Search code examples
assemblyintegermipscalc

Calculate the total sum of all elements in an integer array in MIPS


I need help calculating the total sum of all elements in an integer array. I can't seem the loop to work. I appreciate if you do not propose a solution that is based on changing below "Don't change or use ANYTHING below this line."

Expected result:

Sum of the 11 integer is 217

Current and incorrect result:

Sum of the 11 integer is 11

Code snippet:

##############################################################################
# DESCRIPTION:  Calculates the total sum of all elements in an integer array
#
# INPUT:        $a0 - The address of the first number in the array
#               $a1 - Number of integers stored in the array
#
# OUTPUT:       $v0 - The sum of all numbers in the integer array
##############################################################################
           .text
        j   main

int_array_sum:

##  Clues:
##  - Do not forget to clear registers that do not have an edge content
##  - An integer corresponds to 4 bytes of memory. Each integer is thus 32 bits
##  - If you want to multiply the contents of a register with an even two-power, 
##    a common trick (hint) is to shift bits a few steps left.
##    Example (verify with pen and paper. sll = Shift Left Logical):
##    sll $t1, $t0, 2     #    $t1 = $t0 * 4
##    sll $t0, $t1, 4     #    $t0 = $t1 * 16

#pseudocode:
    # If $t0 (i) is = $a1 skip to end_int       # Done if i == N
    # Multiply $t0 by 4 and store it in $t1     # Indexadr = i * 4
    # Add $t1 with $a0 and save in $t2          # Address = $a0 + Indexadr
    # Retrieve the number from memory that $t2 points to and store in $t3    # n = A [i]
    # Add $t3 to $v0 (results register)         # Sum = Sum + n
    # Add 1 to register $t0                     # i = i + 1
    # Skip to for_every_int

#### WRITE YOUR ASSEMBLY CODE HERE ####
    li  $v0, 0
    li  $t0, 0
loopA:
    #If $t0 (i) is = $a1 skip to end_int
    beq $t0, $a1, end_int   # Done if i == N
    
    # Multiply $t0 by 4 and store it in $t1
    sll $t1, $t0, 2     # Indexadr = i * 4
    
    #Add $t1 with $a0 and save in $t2 
    add $t2, $t1, $a0       # Address = $a0 + Indexadr  
    
    #Retrieve the number from memory that $t2 points to and store in $t3
    lb $t3, 0($t2)          # Load the number from array # n = A [i]
    
    #Add $t3 to $v0 (results register)
    addu $v0, $v0, $t3      # Sum = Sum + n
    
    #Add 1 to register $t0
    add $t0, $t0, 1         # i = i + 1
    
    #Repeat
    j loopA
end_int:
        jr      $ra      # Return to calling code

##############################################################################
##############################################################################
##
##    *** Don't change or use ANYTHING below this line. 
##
##############################################################################
##############################################################################

### Data that is being used as main program

    .data
    
INT_COUNT:
    .word       11
INT_ARRAY:
    .word       1, 3, 6, 9, 2, 4, 6, 8, 10, 55, 113

INT_1_str: 
    .asciiz "Sum of the " 
INT_2_str:
    .asciiz " integer is " 

    .text
    .globl main
##############################################################################
#
# MAIN: Calls subroutine and prints the results
#
##############################################################################  
main:
    ##---
    ### int_array_sum
    ##---
    li      $v0, 4
    la      $a0, INT_1_str
    syscall                            # print string

    lw      $a0, INT_COUNT
    li      $v0, 1
    syscall                            # print integer

    li      $v0, 4
    la      $a0, INT_2_str
    syscall                            # print string
    
    li      $v0, -1
    la      $a0, INT_ARRAY
    lw      $a1, INT_COUNT
    jal     int_array_sum         # run subroutine

    # Print sum
    add     $a0, $v0, $zero
    li      $v0, 1
    syscall                            # print integer (array sum)
    
###--- EXIT
    li      $v0, 10                # MARS / SPIM exit
    syscall
    
#### EOF #####################################################################  

Solution

  • Ok, so you've fixed the crash and updated the question to ask about your newest issues, which is that is that you're not honoring passing of parameters and return value.

    This changes the nature of the question and like I said, debugging is an interactive activity not well suited to StackOverflow.  It is generally frowned upon to completely change the nature of a question post, so much so such that prior answers are no longer relevant.  In such case, it is better to post a new question instead of editing an existing one.  Editing an existing question is fine if it adds clarity to the existing question.

    None the less, re-read the comment/note at the very top of your assignment where it says that input parameters in $a0, and $a1 and output return value is in $v0:

    ##############################################################################
    # DESCRIPTION:  Calculates the total sum of all elements in an integer array
    #
    # INPUT:        $a0 - The address of the first number in the array
    #               $a1 - Number of integers stored in the array
    #
    # OUTPUT:       $v0 - The sum of all numbers in the integer array
    ##############################################################################
    

    Do that instead of using alternative registers — also do not provide initializers for the input parameters — those input parameters are initialized by main as that's the whole idea of passing input parameters is that the caller provides the values!

    Further, let's go on to observe the code in main immediately surrounding the call to your function, and see that it provides the input parameters and looks for the output return value as described in that same initial comment of the assignment.

        li      $v0, -1               # clearing answer register, let the sub provide proper value
        la      $a0, INT_ARRAY        # passing first parameter
        lw      $a1, INT_COUNT        # passing second parameter
        jal     int_array_sum         # run subroutine
    
        # Print sum
        add     $a0, $v0, $zero       # expecting return value in $v0
        li      $v0, 1
        syscall                       # print integer (array sum)
    

    (Now, why do you suppose it thinks the sum is -1?)


    Ok, let's start with what the main is doing in the above.  First it clears (well, sets to -1) the result register.

    Then main puts the address of INT_ARRAY into $a0 and the value 11 into $a1 — these are your two input parameters, and so you should use them in your function.

    Staying with this main code for the moment, you'll note that upon return from the function call, this code expects the function's output/return value in $v0, but since $v0 is unmodified from -1 that main cleared it to, that's what gets printed (your code failed to return a proper value in $v0.

    Alright, now given how main is working (and also according to the input/output description) the setup for your function is that the INT_ARRAY pointer is in the $a0 register — having been passed as a parameter by main — and it has that this proper value in your function at the very top and even before your function's first line of function code.

    Ok, so whenever you need the array pointer, use $a0 instead of your $t0and note that it is already pre-initialized so, just use without any further priming via some la instruction.

    Further, the register you need to use for the output/return value is $v0, so use $v0 instead of your $t3 whenever you need to refer to the sum variable, and when you return back to the caller, the sum value will be in $v0 where the caller expects it to be.

    Next, substitute the register $a1 for the constant value 11; this is the register holding the length parameter that main provided to you.