Mips装配中的正方形总和

时间:2018-04-23 08:52:46

标签: assembly 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
#       $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

我不确定这是我如何处理这个乘法的低点和喜好所以我想听听一些建议和提示

2 个答案:

答案 0 :(得分:0)

  

我不确定这是我如何处理这个乘法的喜欢和喜欢

如果您不确定,请准备一小段代码,使用不同的输入值执行您不完全确定的说明,并使用调试程序逐步完成并清除任何混淆。

你在乘法后当前使用lo / hi对我来说是正确的,在MARS模拟器中按预期工作。

经常使用调试器,尝试按照单个指令添加的每一小段代码,都会使您的进度变得更加容易。在大块新代码中搜索某些错误甚至是逻辑问题通常更成问题,然后在编写后立即调试每个新的4-10行代码有点繁琐(您可以将断点放在需要停止的位置)在MARS模拟器中,SPIM系列工具具有类似的功能,对于其他MIPS平台,我不确定工具的外观,对于常规的MIPS linux + GNU工具链,你肯定有gdb可用,但它并不是那么简单学习MARS,虽然它更强大,更完整。)

根据您当前使用分支的方式判断没有分支延迟槽的方式,您可能正在使用MARS / SPIM模拟器,并且“延迟分支”选项关闭(在真正的MIPS CPU之后的第一条指令)跳转仍然执行,即使跳转有条件地进行分支,所以在真正的MIPS上你必须通过在每次跳转后添加nop来中和这种行为,或者为了获得最佳性能以这种方式重新组织代码,您使用分支延迟指令槽进行实际有意义的指令。

我不喜欢你的代码的一件事是不根据需要初始化局部变量......例如t4, t2, t3。这将使您的函数最多只能使用一次,因为在第二次尝试期间,寄存器中已经存在一些意外的值。也许你把这些留给了你的问题简洁,但在我看来,这就像代码的简单错误一样,那些初始化者应该是简化的最小化示例代码的一部分,以表明你确实认为你的代码通过并且你理解它是如何运作的(并且它确实需要这些值)。

更多提示使代码更“优化”和更简单:为什么不将运行总和直接保存在v0,v1中,并将乘法结果存储到临时代码中?你可以在最后一部分避免一次结果移动。

你可以在每次迭代时简化数组地址计算,你可以使用地址+ = 4来更新它,不需要每次都完整(数组+ i * 4)(至少你把我换成* 4,好)。如果要在循环之前计算结束地址,则可以将整个循环条件构建为bne个地址。

你的评论中有很多拼写错误,例如“32字节”而不是“32位”,类似。我会使用更明确的标签,因为“loop”可能会在更大的代码中与任何其他“循环”冲突。

为了好玩,我试图自己跟踪我的提示,并将代码重写为“我的口味”,这是结果(在MARS中尝试,“延迟分支”关闭,以检查结果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

答案 1 :(得分:0)

我为类似的问题编写了一个代码,该代码非常精确并且可以轻松实现。这里我输入一个输入 n,它打印从 1 开始的连续整数的乘积和,即数组大小 n。 相反,可以做的是将长度和数组都作为输入并运行循环“数组长度”次,而不是运行 n 的循环应该读取数组的元素,存储它们然后存储它们的平方,将地址增加 4 以读取每个索引并继续保存总和。

平方和

.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