Search code examples
assemblymipsadditioninteger-overflowmars-simulator

Detecting for Overflow using addu in MIPS


I am struggling with the implementation in MIPS of detecting for overflow and throwing an error using addu.

This is for a school assignment. We were given code that was a very basic bank ledger. The ledger asks the user for input then if it is positive it adds to the balance and if it is negative it subtracts from the balance. I have already improved it to detect for non-integer inputs as per the assignment, and now I need to be able to detect for overflow and throw an error message and not change the balance if overflow is detected (then re-prompt for a transaction). I figured here since this is only addition, if the signs are the same and result in the opposite sign, then there is overflow. I also figure that if the signs are opposite then no overflow should happen.

Currently it seems to skip right over my overflow detection, so it works, but is not detecting overflow as I need for the assignment. Any advice on what I am doing wrong?

Here is the relevant part of my code:

loopB:
    li  $s1, 0          #### reset $s1
    add $s1, $zero, $t3     #### load integer value into $s1
    beqz    $s1, done       # If $s1 equals zero, branch to done
    li  $s2, 0          #### initialize $s2 for temporary balance
    addu    $s2, $s0, $t6       #### set temporary balance to initial balance
    addu    $s2, $s0, $s1       # add transaction amount to the temporary Balance

oTest:
    sltiu   $t6, $s0, 0     #### if $t6 == 1 then number is negative
    sltiu   $t7, $s1, 0     #### if $t7 == 1 then number is negative
    
    bne $t6, $t7, LoopC     #### if opposite signs then no overflow
    
    sltiu   $t8, $s2, 0     #### if $t8 == 1 then the number is negative
    
    and $t9, $t6, $t7       #### if $t9 == 1 then $t6 and $t7 are both negative
    
    bne     $t9, $t8, over      #### if $t9 and $t8 are not both negative, then overflow has occured
    
    sgtu    $t6, $s0, $zero     #### if $t6 == 1 then number is positive
    sgtu    $t7, $s0, $zero     #### if $t7 == 1 then number is positive
    sgtu    $t8, $s0, $zero     #### if $t8 == 1 then number is positive
    
    and $t9, $t6, $t7       #### if $t9 == 1 then $t6 and $t7 are both positive
    
    bne $t9, $t8, over      #### if $t8 and $t9 are not equal then overflow has occured

LoopC:
    addu    $s0, $s0, $s1       #### add transaction to balance
    li  $v0, 4          # system call code for print_string
    la  $a0, tabs       # load address of tabs into $a0
    syscall             # used to space over to the Balance column
    
    li  $v0, 1          # system call code for print_integer
    move    $a0, $s0        # move Bank Balance value to $a0 
    syscall             # print Bank Balance
    
    b   loop            # branch to loop
    
over:
    li  $v0, 4          #### system call code for print_string
    la  $a0, oMsg       #### load address of msg. into $a0
    syscall             #### print the string
    
    li  $s2, 0          #### reset $s2
    
    li  $v0, 1          #### system call code for print_integer
    move    $a0, $s0        #### move Bank Balance value to $a0 
    syscall             #### print Bank Balance
    
    b   loop            # branch to loop

Solution

  • Can you explain what you're trying to do here:

        addu    $s2, $s0, $t6       #### set temporary balance to initial balance
        addu    $s2, $s0, $s1       # add transaction amount to the temporary Balance
    

    ?

    Those two instructions don't make sense together.  The second wipes out / resets $s2 without using the result of the first.


    You're using unsigned compare for less than with an immediate of 0 — that will always produce false, as no unsigned number is less than zero, by definition of unsigned numbers.  In other words, negative is not a property that is possible for unsigned numbers.

    If you want to know if the number is negative, use a signed compare instead.

    FYI, you can also use shifting to extract or replicate the sign bit, so by using arithmetic shift of 31, getting either a -1 or a 0, and by using logical shift of 31 getting either a 1 or a 0.


    Fundamentally, you're dealing with signed integers, so all your compare operations should be signed unless you really know something different somewhere there.

    However, you are right that you need to do unsigned addition and/or subtraction in order to avoid the processor's automatic signed overflow detection, because if you hit that it will terminate your program.  When there is no overflow, the unsigned addition will produce the same number, same numeric value, same bit pattern as the signed addition, so, this works. — and if there is overflow, you can detected it as you're thinking, e.g. after the addition.

    But the comparisons need to be done with signed arithmetic in order to make sense, and, these signed compares (unlike signed addition/subtraction) don't risk hitting the processor's overflow trap.