问题
I'm tackling an assignment which asks us to:
Write a program in MIPS assembly which, given a memory address in $a0 to the first element of an array of n 32-bit unsigned numbers (n is stored in $a1), it should square each one of them and sum the squares. The 32 most significant bits should be returned on $v1, while the least significant ones on $v0.
Special returns (on v0):
- Zero if the array has no elements (n = 0)
- DEADBEEF (hex) = 3735928559 (dec) if the result can't fit in 64 bits.
What I've done so far: (the input is handled by separate, given to us code)
squaredSum:
beq $t5, $zero, getRetAddr # if $t5 (caller's ret. addr.) is zero (ie. first time the function is called, then get the caller's ret. addr.)
move $t0, $a1 # $t0: array size (we want to turn it into bytes)
sll $t0, $t0, 2 # multiply array size by 4, so we get the total number of bytes (2 left bitwise shifts)
beq $t1, $t0, sumExit # if offset ($t1) = bytes, then end of array, so we terminate (jump to "exit" label)
add $t2, $t1, $a0 # $t2: address from which we start reading (base + offset)
lw $t3, 0($t2) # $t3: the number to be squared is loaded here
mult $t3, $t3 # multiply $t3 with itself (square), result of multiplication goes to internal registers Hi and Lo
mfhi $t8 # load HI's contents into $t8
mflo $t9 # load LO's contents into $t9
addi $t1, $t1, 4 # add 4 to offset (move to next element, since numbers are 32bit)
jal adduover # call adduover to sum the newly found square
b squaredSum # go back to the beginning of the loop
adduover:
add $t7, $t7, $t9 # add Lo to $t7
add $t6, $t6, $t8 # add Hi to $t6
blt $t7, $t9, correction # if total sum of Lo is lower than Lo before summation (32bit overflow) then jump to label "correction"
blt $t6, $t8, overflow # if total sum of Hi is lower than before summation (64bit overflow) then jump to label "overflow"s
jr $ra
correction:
addi $t8, $t8, 1 # add 1 to the most significant bits (we made a full circle)
jr $ra # continue with adduover
overflow:
li $v0, 3735928559 # return as result (0x00000000DEADBEEF) in case of 64-bit overflow
jr $ra # continue with adduover
getRetAddr:
move $t5, $ra # get the return addr. of squareSum's caller, because it gets overwritten during execution
j squaredSum # continue with squaredSum
sumExit:
move $v0, $t9 # send least significant 32 bits to $v0 (exercise output)
move $v1, $t8 # same as above for most significant
jr $t5 # return to squaredsum's caller's address
For input of small numbers (even in large arrays) the program works as intended. My problem is that when I input a large number (ie. 2000000000), during the multiplication the lo register overflows and flips to minus, which implies that everything stored in lo gets signed, while I want it to be unsigned in order to return to 0 and count upwards. Is there any workaround for this?
Thanks for your time.
PS: FYI, I'm using MARS for interpreting the code.
来源:https://stackoverflow.com/questions/49965565/overflow-problems-with-summing-squares