Assembly MIPS32上32位整数数组的64位平方和

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 #

我必须在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
#       $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