Search code examples
assemblymipsqtspim

Why does using $v0 register in a loop return wrong output?


The following program

  1. Given a lower and upper bound input by user, determines the min and min index within that range

For the test case (lower bound: 2 upper bound: 4), I tried two different codes, with the difference marked below.

The following code does not return the expected output

findMin:

      addi $t0, $a0, 0        # initialise $t0 (current pointer) to lower bound 
      addi $t1, $a0, 0        # initialise minimum pointer to upper bound 
      lw   $t2, 0($t1)        # initialise min (value) to the lower bound  


Loop: slt $t4, $a1, $t0
      bne $t4, $zero, End     # branch to end if upper < lower

      lw, $t3, 0($t0)         # store the content of the current pointer
      slt $t4, $t3, $t2       # if current ($t3) < min ($t2), store 1 in $t4
      beq $t4, $zero, LoopEnd # if it is 0, go to LoopEnd

      addi $t2, $t3, 0        # store content ($t3) as minimum ($t2)
      addi $v0, $t0, 0        # store the address of min (DIFFERENCE)

LoopEnd: addi $t0, $t0, 4     # increments current pointer lower bound 
         j Loop               # Jump to loop 

End:     jr $ra               # return from this function

However, the following code does return the expected value:

findMin:
    addi $t0, $a0, 0  # $t0 is the pointer to the current item
    addi $t1, $a0, 0  # $t1 is the pointer to the minimum item
    lw   $t2, 0($t1)  # $t2 stores the value of minimum item

loop:
    slt $t4, $a1, $t0  # check if last pointer < current pointer
    bne $t4, $zero, exit # if current pointer > last pointer, exit
    lw  $t3, 0($t0)    # $t3 stores the value of current item
    slt $t4, $t3, $t2  # if the current value is lesser than minimum value
    beq $t4, $zero, skip # if current value is not lesser, then skip

    addi $t1, $t0, 0   # minimum pointer = current pointer (DIFFERENCE)
    lw   $t2, 0($t1)   # $t2 stores the value of minimum item

skip:
    addi $t0, $t0, 4   # move to the next item
    j loop
exit:   
    addi $v0, $t1, 0   # $v0 stores the address of the minimum item (DIFFERENCE)
    jr $ra          # return from this function

What is the rationale behind this?

The following is the code in its entirety (optional)


# arrayFunction.asm
       .data 
array: .word 8, 2, 1, 6, 9, 7, 3, 5, 0, 4
newl:  .asciiz "\n"

       .text
main:
    # Print the original content of array
    # setup the parameter(s)
    # call the printArray function
    la $a0, array            # base address of array
    la $a1, 10               # number of elements in array
    jal printArray           # call function 


    # Ask the user for two indices
    li   $v0, 5             # System call code for read_int
    syscall 
    add  $t0, $v0, $zero    # store input in $t0          

    li   $v0, 5             # System call code for read_int
    syscall           
    add  $t1, $v0, $zero    # store input in $t1          

    # Call the findMin function
    # setup the parameter(s) 
    la $a0, array       # load address of array into $a0
    la $a1, array       # load address of array into $a1
    sll $t0, $t0, 2         # calculate offset of lower bound
    sll $t1, $t1, 2         # calculate offset of upper bound
    add $a0, $a0, $t0       # set $a0 to the lower bound
    add $a1, $a1, $t1       # set $a1 to the upper bound 

    # call the function
    jal findMin             # call function 


    # Print the min item
    # place the min item in $t3 for printing
    addi $t3, $t2, 0        # placing min item in $t3 
    addi $t4, $v0, 0        # saving the pointer to the min element

    # Print an integer followed by a newline
    li   $v0, 1             # system call code for print_int
    addi $a0, $t3, 0        # print $t3
    syscall                 # make system call

    li   $v0, 4             # system call code for print_string
    la   $a0, newl      
    syscall                 # print newline

    #Calculate and print the index of min item
    la  $a0, array
    sub $t3, $t4, $a0   
    srl $t3, $t3, 2 

    # Place the min index in $t3 for printing   

    # Print the min index
    # Print an integer followed by a newline
    li   $v0, 1         # system call code for print_int
    addi $a0, $t3, 0    # print $t3
    syscall             # make system call

    li   $v0, 4         # system call code for print_string
    la   $a0, newl      
    syscall             # print newline

    # End of main, make a syscall to "exit"
    li   $v0, 10        # system call code for exit
    syscall             # terminate program


#######################################################################
###   Function printArray   ### 
#Input: Array Address in $a0, Number of elements in $a1
#Output: None
#Purpose: Print array elements
#Registers used: $t0, $t1, $t2, $t3
#Assumption: Array element is word size (4-byte)
printArray:
    addi $t1, $a0, 0    #$t1 is the pointer to the item
    sll  $t2, $a1, 2    #$t2 is the offset beyond the last item
    add  $t2, $a0, $t2  #$t2 is pointing beyond the last item
l1: 
    beq  $t1, $t2, e1
    lw   $t3, 0($t1)    # $t3 is the current item
    li   $v0, 1         # system call code for print_int
    addi $a0, $t3, 0    # integer to print
    syscall             # print it
    addi $t1, $t1, 4
    j l1            # Another iteration
e1:
    li   $v0, 4         # system call code for print_string
    la   $a0, newl      # 
    syscall             # print newline
    jr $ra          # return from this function


#######################################################################
###   Student Function findMin   ### 
#Input: Lower Array Pointer in $a0, Higher Array Pointer in $a1
#Output: $v0 contains the address of min item 
#Purpose: Find and return the minimum item 
#              between $a0 and $a1 (inclusive)
#Registers used: $t0 (counter), $t1 (max add), $t2 (min), $v0 (min pos), $t3 (current item)
#Assumption: Array element is word size (4-byte), $a0 <= $a1
findMin:

      addi $t0, $a0, 0        # initialise $t0 (current pointer) to lower bound 
      addi $t1, $a0, 0        # initialise minimum pointer to upper bound 
      lw   $t2, 0($t1)        # initialise min (value) to the lower bound  


Loop: slt $t4, $a1, $t0
      bne $t4, $zero, End     # branch to end if upper < lower

      lw, $t3, 0($t0)         # store the content of the current pointer
      slt $t4, $t3, $t2       # if current ($t3) < min ($t2), store 1 in $t4
      beq $t4, $zero, LoopEnd # if it is 0, go to LoopEnd

      addi $t2, $t3, 0        # store content ($t3) as minimum ($t2)
      addi $t1, $t0, 0        # store the address of min

LoopEnd: addi $t0, $t0, 4     # increments current pointer lower bound 
         j Loop               # Jump to loop 

End:    addi $v0, $t1, 0       
    jr $ra                # return from this function


Solution

  • In the first case the problem is that you save the min pointer to the t1 register initially, but on return you expect it to be on v0. Now on cases where the min value is not exactly on the lowerbound index this will not come up as an issue, because in the loop you save the new found min values pointer to v0, so uppon return everything will be as expected. But in case like 2,4 the min value at the lowerbound here so in index 2, therefore in the loop since no new min points is found, thus nothing will be written in v0, so on return it will have some garbage value.

    Change the begining part to this and will work fine:

          addi $v0, $a0, 0        # initialise minimum pointer to upper bound 
          lw   $t2, 0($v0)        # initialise min (value) to the lower bound