在MIPS中计算整数数组中所有元素的总和
Calculate the total sum of all elements in an integer array in MIPS
我需要帮助计算整数数组中所有元素的总和。
我似乎无法循环工作。
如果您不提出基于以下更改的解决方案,我将不胜感激“不要更改或使用此行下方的任何内容。”
预期结果:
11个整数之和为217
当前和不正确的结果:
11个整数的和是11
代码片段:
##############################################################################
# DESCRIPTION: Calculates the total sum of all elements in an integer array
#
# INPUT: $a0 - The address of the first number in the array
# $a1 - Number of integers stored in the array
#
# OUTPUT: $v0 - The sum of all numbers in the integer array
##############################################################################
.text
j main
int_array_sum:
## Clues:
## - Do not forget to clear registers that do not have an edge content
## - An integer corresponds to 4 bytes of memory. Each integer is thus 32 bits
## - If you want to multiply the contents of a register with an even two-power,
## a common trick (hint) is to shift bits a few steps left.
## Example (verify with pen and paper. sll = Shift Left Logical):
## sll $t1, $t0, 2 # $t1 = $t0 * 4
## sll $t0, $t1, 4 # $t0 = $t1 * 16
#pseudocode:
# If $t0 (i) is = $a1 skip to end_int # Done if i == N
# Multiply $t0 by 4 and store it in $t1 # Indexadr = i * 4
# Add $t1 with $a0 and save in $t2 # Address = $a0 + Indexadr
# Retrieve the number from memory that $t2 points to and store in $t3 # n = A [i]
# Add $t3 to $v0 (results register) # Sum = Sum + n
# Add 1 to register $t0 # i = i + 1
# Skip to for_every_int
#### WRITE YOUR ASSEMBLY CODE HERE ####
li $v0, 0
li $t0, 0
loopA:
#If $t0 (i) is = $a1 skip to end_int
beq $t0, $a1, end_int # Done if i == N
# Multiply $t0 by 4 and store it in $t1
sll $t1, $t0, 2 # Indexadr = i * 4
#Add $t1 with $a0 and save in $t2
add $t2, $t1, $a0 # Address = $a0 + Indexadr
#Retrieve the number from memory that $t2 points to and store in $t3
lb $t3, 0($t2) # Load the number from array # n = A [i]
#Add $t3 to $v0 (results register)
addu $v0, $v0, $t3 # Sum = Sum + n
#Add 1 to register $t0
add $t0, $t0, 1 # i = i + 1
#Repeat
j loopA
end_int:
jr $ra # Return to calling code
##############################################################################
##############################################################################
##
## *** Don't change or use ANYTHING below this line.
##
##############################################################################
##############################################################################
### Data that is being used as main program
.data
INT_COUNT:
.word 11
INT_ARRAY:
.word 1, 3, 6, 9, 2, 4, 6, 8, 10, 55, 113
INT_1_str:
.asciiz "Sum of the "
INT_2_str:
.asciiz " integer is "
.text
.globl main
##############################################################################
#
# MAIN: Calls subroutine and prints the results
#
##############################################################################
main:
##---
### int_array_sum
##---
li $v0, 4
la $a0, INT_1_str
syscall # print string
lw $a0, INT_COUNT
li $v0, 1
syscall # print integer
li $v0, 4
la $a0, INT_2_str
syscall # print string
li $v0, -1
la $a0, INT_ARRAY
lw $a1, INT_COUNT
jal int_array_sum # run subroutine
# Print sum
add $a0, $v0, $zero
li $v0, 1
syscall # print integer (array sum)
###--- EXIT
li $v0, 10 # MARS / SPIM exit
syscall
#### EOF #####################################################################
如果你打算学习汇编语言,基本的调试技能应该在你的技能组合中。
通过 Whosebug 调试程序是一项挑战 — 调试是一种交互式 activity,而 Whosebug 并不真正符合这种形式!
所以,下面是一些思考过程。
您可以向前调试到错误或意外结果,或者从错误或意外结果向后调试。
当 运行 第一次使用新代码时,我更喜欢继续前进。单步检查每条指令是否符合您的预期。如果任何一条指令做的事情与您的预期不同,那么这就是重点。在寻找与预期的差异时,请同时查看指令的寄存器效应和记忆效应,并遵循预期的控制流。
往回走,我们可能会问:0x00400088处的指令是什么?为什么它访问位置 0x10400000
?要回答这个问题,您必须回过头来看看是什么指令创建了该内存地址,然后确定出错的原因以及需要什么。
前进通常比后退更容易,特别是对于可能有拼写错误的新代码 b/c 如果您有多个错误,处理第一个错误比处理最后一个错误要少 - 最后一个可能不工作 b/c 早期的 errors/typos 正在复合,而向前工作,除非你错过了什么,否则不会有复合的错误。
有时,编写更简单的程序并将这些简单的部分放在一起比编写整个程序并调试它更容易。所以,试着把整体分解成更小的部分,让每个更小的部分发挥作用,然后把这些更小的解决方案组合成一个更大的整体。
如果您正在为循环而苦苦挣扎,您可能会从最简单的循环程序开始,如果您遇到问题,那么您可能会询问有关您遇到问题的指令的技术问题。
好的,所以你已经修复了崩溃并更新了问题来询问你的最新问题,那就是你不尊重参数和 return 值的传递。
这改变了问题的性质,就像我说的,调试是一种交互式 activity 不太适合 Whosebug。通常不赞成完全改变问题的性质 post,以至于之前的答案不再相关。在这种情况下,最好 post 一个新问题而不是编辑现有问题。如果可以使现有问题更加清晰,则可以编辑现有问题。
None 越少,重新阅读作业最顶部的 comment/note ,其中表示输入参数 $a0
和 $a1
并输出return 值在 $v0
:
##############################################################################
# DESCRIPTION: Calculates the total sum of all elements in an integer array
#
# INPUT: $a0 - The address of the first number in the array
# $a1 - Number of integers stored in the array
#
# OUTPUT: $v0 - The sum of all numbers in the integer array
##############################################################################
这样做而不是使用替代寄存器 - 也不要为输入参数提供初始化器 - 这些输入参数由 main
初始化,因为传递输入参数的整个想法是调用者提供值!
此外,让我们继续观察 main
中紧邻函数调用的代码,看看它提供输入参数并查找输出 return 值,如中所述作业的相同初始评论。
li $v0, -1 # clearing answer register, let the sub provide proper value
la $a0, INT_ARRAY # passing first parameter
lw $a1, INT_COUNT # passing second parameter
jal int_array_sum # run subroutine
# Print sum
add $a0, $v0, $zero # expecting return value in $v0
li $v0, 1
syscall # print integer (array sum)
(现在,你认为它为什么认为总和是 -1?)
好的,让我们从上面的main
在做什么开始。首先它清除(好吧,设置为-1)结果寄存器。
然后main
将INT_ARRAY的地址放入$a0
,将值11
放入$a1
——这是你的两个输入参数,等等你应该在你的函数中使用它们。
暂时使用此 main
代码,您会注意到在函数调用 return 时,此代码期望函数的 output/return 值在 $v0
,但由于 $v0
未从 main
清除的 -1 修改,这就是打印的内容(您的代码未能 return $v0
中的正确值。
好吧,现在考虑到 main
是如何工作的(也根据 input/output 的描述)你的函数的设置是 INT_ARRAY 指针在 $a0
register — 已被 main
作为参数传递 — 它在函数的最顶部甚至在函数的第一行函数代码之前都有这个正确的值。
好的,所以只要你需要数组指针,使用$a0
而不是你的$t0
— 并注意它已经预先初始化,因此,只需使用 而无需通过某些 la
指令进行任何进一步启动。
此外,您需要为 output/return 值使用的寄存器是 $v0
,因此 使用 $v0
而不是您的 $t3
每当你需要引用 sum 变量时,当你 return 返回给调用者时,sum 值将在 $v0
调用者所在的位置期待它。
接下来,用寄存器$a1
代替常数值11
;这是保存 main
提供给您的长度参数的寄存器。
我需要帮助计算整数数组中所有元素的总和。 我似乎无法循环工作。 如果您不提出基于以下更改的解决方案,我将不胜感激“不要更改或使用此行下方的任何内容。”
预期结果:
11个整数之和为217
当前和不正确的结果:
11个整数的和是11
代码片段:
##############################################################################
# DESCRIPTION: Calculates the total sum of all elements in an integer array
#
# INPUT: $a0 - The address of the first number in the array
# $a1 - Number of integers stored in the array
#
# OUTPUT: $v0 - The sum of all numbers in the integer array
##############################################################################
.text
j main
int_array_sum:
## Clues:
## - Do not forget to clear registers that do not have an edge content
## - An integer corresponds to 4 bytes of memory. Each integer is thus 32 bits
## - If you want to multiply the contents of a register with an even two-power,
## a common trick (hint) is to shift bits a few steps left.
## Example (verify with pen and paper. sll = Shift Left Logical):
## sll $t1, $t0, 2 # $t1 = $t0 * 4
## sll $t0, $t1, 4 # $t0 = $t1 * 16
#pseudocode:
# If $t0 (i) is = $a1 skip to end_int # Done if i == N
# Multiply $t0 by 4 and store it in $t1 # Indexadr = i * 4
# Add $t1 with $a0 and save in $t2 # Address = $a0 + Indexadr
# Retrieve the number from memory that $t2 points to and store in $t3 # n = A [i]
# Add $t3 to $v0 (results register) # Sum = Sum + n
# Add 1 to register $t0 # i = i + 1
# Skip to for_every_int
#### WRITE YOUR ASSEMBLY CODE HERE ####
li $v0, 0
li $t0, 0
loopA:
#If $t0 (i) is = $a1 skip to end_int
beq $t0, $a1, end_int # Done if i == N
# Multiply $t0 by 4 and store it in $t1
sll $t1, $t0, 2 # Indexadr = i * 4
#Add $t1 with $a0 and save in $t2
add $t2, $t1, $a0 # Address = $a0 + Indexadr
#Retrieve the number from memory that $t2 points to and store in $t3
lb $t3, 0($t2) # Load the number from array # n = A [i]
#Add $t3 to $v0 (results register)
addu $v0, $v0, $t3 # Sum = Sum + n
#Add 1 to register $t0
add $t0, $t0, 1 # i = i + 1
#Repeat
j loopA
end_int:
jr $ra # Return to calling code
##############################################################################
##############################################################################
##
## *** Don't change or use ANYTHING below this line.
##
##############################################################################
##############################################################################
### Data that is being used as main program
.data
INT_COUNT:
.word 11
INT_ARRAY:
.word 1, 3, 6, 9, 2, 4, 6, 8, 10, 55, 113
INT_1_str:
.asciiz "Sum of the "
INT_2_str:
.asciiz " integer is "
.text
.globl main
##############################################################################
#
# MAIN: Calls subroutine and prints the results
#
##############################################################################
main:
##---
### int_array_sum
##---
li $v0, 4
la $a0, INT_1_str
syscall # print string
lw $a0, INT_COUNT
li $v0, 1
syscall # print integer
li $v0, 4
la $a0, INT_2_str
syscall # print string
li $v0, -1
la $a0, INT_ARRAY
lw $a1, INT_COUNT
jal int_array_sum # run subroutine
# Print sum
add $a0, $v0, $zero
li $v0, 1
syscall # print integer (array sum)
###--- EXIT
li $v0, 10 # MARS / SPIM exit
syscall
#### EOF #####################################################################
如果你打算学习汇编语言,基本的调试技能应该在你的技能组合中。
通过 Whosebug 调试程序是一项挑战 — 调试是一种交互式 activity,而 Whosebug 并不真正符合这种形式!
所以,下面是一些思考过程。
您可以向前调试到错误或意外结果,或者从错误或意外结果向后调试。
当 运行 第一次使用新代码时,我更喜欢继续前进。单步检查每条指令是否符合您的预期。如果任何一条指令做的事情与您的预期不同,那么这就是重点。在寻找与预期的差异时,请同时查看指令的寄存器效应和记忆效应,并遵循预期的控制流。
往回走,我们可能会问:0x00400088处的指令是什么?为什么它访问位置 0x10400000
?要回答这个问题,您必须回过头来看看是什么指令创建了该内存地址,然后确定出错的原因以及需要什么。
前进通常比后退更容易,特别是对于可能有拼写错误的新代码 b/c 如果您有多个错误,处理第一个错误比处理最后一个错误要少 - 最后一个可能不工作 b/c 早期的 errors/typos 正在复合,而向前工作,除非你错过了什么,否则不会有复合的错误。
有时,编写更简单的程序并将这些简单的部分放在一起比编写整个程序并调试它更容易。所以,试着把整体分解成更小的部分,让每个更小的部分发挥作用,然后把这些更小的解决方案组合成一个更大的整体。
如果您正在为循环而苦苦挣扎,您可能会从最简单的循环程序开始,如果您遇到问题,那么您可能会询问有关您遇到问题的指令的技术问题。
好的,所以你已经修复了崩溃并更新了问题来询问你的最新问题,那就是你不尊重参数和 return 值的传递。
这改变了问题的性质,就像我说的,调试是一种交互式 activity 不太适合 Whosebug。通常不赞成完全改变问题的性质 post,以至于之前的答案不再相关。在这种情况下,最好 post 一个新问题而不是编辑现有问题。如果可以使现有问题更加清晰,则可以编辑现有问题。
None 越少,重新阅读作业最顶部的 comment/note ,其中表示输入参数 $a0
和 $a1
并输出return 值在 $v0
:
##############################################################################
# DESCRIPTION: Calculates the total sum of all elements in an integer array
#
# INPUT: $a0 - The address of the first number in the array
# $a1 - Number of integers stored in the array
#
# OUTPUT: $v0 - The sum of all numbers in the integer array
##############################################################################
这样做而不是使用替代寄存器 - 也不要为输入参数提供初始化器 - 这些输入参数由 main
初始化,因为传递输入参数的整个想法是调用者提供值!
此外,让我们继续观察 main
中紧邻函数调用的代码,看看它提供输入参数并查找输出 return 值,如中所述作业的相同初始评论。
li $v0, -1 # clearing answer register, let the sub provide proper value
la $a0, INT_ARRAY # passing first parameter
lw $a1, INT_COUNT # passing second parameter
jal int_array_sum # run subroutine
# Print sum
add $a0, $v0, $zero # expecting return value in $v0
li $v0, 1
syscall # print integer (array sum)
(现在,你认为它为什么认为总和是 -1?)
好的,让我们从上面的main
在做什么开始。首先它清除(好吧,设置为-1)结果寄存器。
然后main
将INT_ARRAY的地址放入$a0
,将值11
放入$a1
——这是你的两个输入参数,等等你应该在你的函数中使用它们。
暂时使用此 main
代码,您会注意到在函数调用 return 时,此代码期望函数的 output/return 值在 $v0
,但由于 $v0
未从 main
清除的 -1 修改,这就是打印的内容(您的代码未能 return $v0
中的正确值。
好吧,现在考虑到 main
是如何工作的(也根据 input/output 的描述)你的函数的设置是 INT_ARRAY 指针在 $a0
register — 已被 main
作为参数传递 — 它在函数的最顶部甚至在函数的第一行函数代码之前都有这个正确的值。
好的,所以只要你需要数组指针,使用$a0
而不是你的$t0
— 并注意它已经预先初始化,因此,只需使用 而无需通过某些 la
指令进行任何进一步启动。
此外,您需要为 output/return 值使用的寄存器是 $v0
,因此 使用 $v0
而不是您的 $t3
每当你需要引用 sum 变量时,当你 return 返回给调用者时,sum 值将在 $v0
调用者所在的位置期待它。
接下来,用寄存器$a1
代替常数值11
;这是保存 main
提供给您的长度参数的寄存器。