Assembly MIPS32上32位整数数组的64位平方和
我必须在Mips汇编中计算数组的平方和。我在寻找代码的反馈。下面发布的代码只是一个开始,没有考虑可能的溢出情况。但是,我只想确保,这段基本代码按预期工作Assembly MIPS32上32位整数数组的64位平方和,assembly,mips,mips32,Assembly,Mips,Mips32,我必须在Mips汇编中计算数组的平方和。我在寻找代码的反馈。下面发布的代码只是一个开始,没有考虑可能的溢出情况。但是,我只想确保,这段基本代码按预期工作 # Function to calculate squared sum # # Inputs: # $a0: address of array in memory (*a) # $a1: array size (n) # # Outputs: # $v0: low 32 bytes of result #
# Function to calculate squared sum
#
# Inputs:
# $a0: address of array in memory (*a)
# $a1: array size (n)
#
# Outputs:
# $v0: low 32 bytes of result
# $v1: high 32 bytes of result
#
# If the array is empty, then the function returns zero.
#
squareSum:
Loop:
sltu $t5,$t4,$a1 # if(i<n)
beq $t5,$zero,Exit # if ($t5 == 0)
sll $t0,$t4,2 # προσωρινος καταχωρητης 4 * i
addu $t0,$t0,$a0 # ο καταχωρητης $t0 δειχνει στη διευθυνση μνημης του array προστιθεμενο με το 4 * i, αρα εχουμε παρει το array[i]
lw $t1,0($t0) # φορτωση στον καταχωρητη $t1 της τιμη του πινακα που θελουμε καθε στιγμη
multu $t1,$t1 # array[i] * array[i]
mflo $v0 # 32 least significant bits of multiplication to $v0
mfhi $v1 # 32 most significant bits of multiplication to $v1
addu $t2,$t2,$v0
addu $t3,$t3,$v1
addiu $v0,$zero,0
addiu $v1,$zero,0
addiu $t4,$t4,1 # i += 1
j Loop
Exit:
add $v0,$zero,$t2
add $v1,$zero,$t3
jr $ra
计算平方和的函数
#
#投入:
#$a0:内存中数组的地址(*a)
#$a1:阵列大小(n)
#
#产出:
#$v0:结果的低32字节
#$v1:结果的高32字节
#
#如果数组为空,则函数返回零。
#
平方和:
循环:
sltu$t5、$t4、$a1#如果(i)
我不确定这是我处理这个乘法的lo和hi的方式
当您不确定时,准备一段简短的代码,使用不同的输入值来练习您不完全确定的指令,并使用调试器逐步完成这些指令并消除任何混淆
您当前在乘法后使用的lo/hi在我看来是正确的,在MARS模拟器中工作正常
经常使用调试器,尝试每一条指令添加的每一小段新代码,将使您的进度更容易。在大块新代码中搜索某些bug甚至逻辑问题通常更麻烦,然后在编写新代码后立即调试每4-10行新代码会有点繁琐(您可以在MARS simulator中需要停止的地方放置断点,SPIM系列工具也有类似的功能,对于其他MIPS平台,我不确定这些工具的外观如何,对于常规的MIPS linux+GNU工具链,您当然有可用的gdb
,但它不像MARS那样简单易学,尽管它更强大、更完整)
从您当前的源代码以一种没有分支延迟槽的方式使用分支判断,您可能正在使用MARS/SPIM模拟器,并且您已经关闭了“延迟分支”选项(在真正的MIPS CPU上,任何跳转后的第一条指令仍在执行,即使跳转确实有条件地进行分支,因此在真正的MIPS上,您必须通过在每次跳转后添加nop
来消除此行为,或者为了获得最佳性能,以这样的方式重新组织代码,使用分支延迟指令实际有意义指令的插槽
我不喜欢你的代码的一点是没有根据需要初始化局部变量…例如,
t4,t2,t3
。这将使你的函数最多只能使用一次,因为在第二次尝试时,寄存器中已经有一些意想不到的值。也许你为了问题的简洁而忽略了这些值,但在我看来,这就像plai在代码的bug中,这些初始值设定项甚至应该是简化的最小化示例代码的一部分,以表明您确实仔细思考了代码,并且理解了它是如何运行的(并且它确实需要这些值)
还有一些让代码更“优化”和更简单的提示:为什么不将运行的和直接保存在v0、v1中,并将乘法结果存储到临时值中呢?可以避免在最后一部分移动一次结果
你可以简化每次迭代的数组地址计算,你可以使用address+=4来更新它,不需要每次都做full(array+i*4)(至少你把i移到了*4,很好)。如果你想在循环之前计算结束地址,那么你可以将整个循环条件构建为地址的bne
您的注释中有许多拼写错误,例如“32字节”而不是“32位”,以及类似的错误。我会使用更明确的标签,因为在更大的代码中,“循环”可能会与任何其他“循环”冲突
为了好玩,我自己尝试按照我的提示,将代码改写成“我的口味”,这就是结果(在火星上尝试,“延迟分支”关闭,以检查结果v0:v1
值在每个jal
之后放置一个断点),还修复了溢出情况:
main: # test the subroutine
la $a0, testArr
li $a1, 4
jal squareSum
# v0:v1 = 14 (0*0 + 1*1 + 2*2 + 3*3)
# more complex input, testing 64 bit results and overflow
la $a0, testArr
li $a1, 7
jal squareSum
# terminate app
li $v0, 10
syscall
# Function to calculate squared sum
#
# Inputs:
# $a0: address of word array in memory (*a)
# $a1: array size (n)
#
# Outputs:
# $v0: low 32 bits of result
# $v1: high 32 bits of result
#
# If the array is empty, then the function returns zero.
#
squareSum:
# result = 0
addiu $v0, $zero,0
addiu $v1, $zero,0
# calculate end() pointer of array (for loop condition)
sll $a1, $a1, 2 # n * 4
addu $a1, $a1, $a0 # a1 = array.end() address (a0 = array.begin())
beq $a0, $a1, squareSum_exit # begin() == end() => empty array
squareSum_summing:
# load next array element and calculate it's square
lw $t0, 0($a0) # t0 = array[i]
addiu $a0, $a0, 4 # advance the array pointer
multu $t0, $t0 # array[i] * array[i]
mflo $t0 # t0 = 32 least significant bits of multiplication
mfhi $t1 # t1 = 32 most significant bits of multiplication
# add square value to the result
addu $v0, $v0, $t0
addu $v1, $v1, $t1
# handle unsigned addition overflow
sltu $t1, $v0, $t0 # t1 = 0/1 correction ((x+y) < y)
addu $v1, $v1, $t1 # add correction to the result
# loop while array_ptr != array.end()
bne $a0, $a1, squareSum_summing
squareSum_exit:
jr $ra
.data
testArr: .word 0, 1, 2, 3, 65535, 1024, 1048576
main:#测试子例程
洛杉矶a0,Testar
李:1美元,4美元
日航平方和
#v0:v1=14(0*0+1*1+2*2+3*3)
#更复杂的输入,测试64位结果和溢出
洛杉矶$a0,testArr
李:1美元,7美元
日航平方和
#终止应用程序
李$v0,10
系统调用
#函数来计算平方和
#
#投入:
#$a0:内存中字数组的地址(*a)
#$a1:阵列大小(n)
#
#产出:
#$v0:结果的低32位
#$v1:结果的高32位
#
#如果数组为空,则函数返回零。
#
平方和:
#结果=0
加总$v0,$0,0
加上$v1,$0,0
#计算数组的end()指针(用于循环条件)
sll$a1,$a1,2#n*4
addu$a1,$a1,$a0#a1=array.end()地址(a0=array.begin())
beq$a0,$a1,平方和退出#begin()==end()=>空数组
平方和求和:
#加载下一个数组元素并计算其平方
lw$t0,0$a0)#t0=数组[i]
addiu$a0,$a0,4#推进数组指针
multu$t0,$t0#数组[i]*数组[i]
mflo$t0#t0=乘法的32个最低有效位
mfhi$t1#t1=32乘法的最高有效位
#将平方值添加到结果中
加成$v0,$v0,$t0
添加$v1、$v1、$t1
#处理无符号加法溢出
sltu$t1,$v0,$t0#t1=0/1校正((x+y)
我为一个类似的问题编写了一个代码,该代码非常精确,并且可以轻松实现。这里,我获取一个输入n,它打印了
.data
#initilisation prompt to ask the user for their input
n: .asciiz "enter n: "
.text
.globl main
main:
#declaring i and initiating its value to 0
li $t0, 0
#printing prompt to ask from user
li $v0,4
la $a0, n
syscall
#inputing value from console
li $v0,5
syscall
#moving to temporary variable t1
move $t1, $v0
#initialising sum as 0, stored as t3
li $t3 0
#Function acting as a loop
function:
#condition to end the loop and jump to print function
#while(t0!=t1)
beq $t0 $t1 print
#incrementation of loop variable (t0)
addi $t0 $t0 1
#calculating square of t0 and storing it in t4
mul $t4 $t0 $t0
#adding the current squared to previous sum and again storing it in sum(t3)
add $t3 $t3 $t4
#loop to this function again
j function
#procedure to print the sum(t3)
print:
move $a0 $t3
li $v0 1
syscall
#exit procedure
end:
li $v0 10
syscall