1

I want to calculate the average value of a list on MIPS. I've tried isolation and it works perfectly fine if I want to print out sum or a prompt to test but when I put the average calculation back in, it somehow gives me size * 4 as an answer. My assembly code is as below:

                .data

size_prompt:    .asciiz "Enter number of elements: "    
element_prompt: .asciiz "Enter an element: "
size:           .word 0 
to_store:       .word 0
sum:            .word 0
avg:            .word 0

                .text
                #Prints prompt
                la $a0, size_prompt
                addi $v0, $0, 4
                syscall

                #Gets input from user
                addi $v0, $0, 5
                syscall
                sw $v0, size

                addi $t0, $0, 0 #Initialise i = 0

                #Creates the list
                lw $s0, size
                addi $t1, $0, 4
                mult $s0, $t1
                mflo $t2
                add $a0, $t1, $t2
                addi $v0, $0, 9
                syscall

stack:          beq $t0, $s0, list_sum
                la $a0, element_prompt
                addi $v0, $0, 4
                syscall

                addi $v0, $0, 5
                syscall
                sw $v0, to_store
                lw $t5, to_store

                addi $sp, $sp, -4
                sw $t5, 0($sp)

                addi $t0, $t0, 1
                j stack

list_sum:       beq $s0, 0, average
                lw $t6, sum
                lw $t7, 0($sp)
                addi $sp, $sp, 4
                add $t6, $t7, $t6
                sw $t6, sum
                addi $s0, $s0, -1
                j list_sum

average:        lw $t0, sum
                div $t0, $s0
                mflo $t0
                sw $t0, avg
                lw $a0, avg
                addi $v0, $0, 1
                syscall
  • What's your entry-point? I don't see a `main:`, and the first bit of code in `.text` doesn't have a label at all. – EOF Aug 08 '16 at 15:07
  • @EOF my uni somehow doesn't require us to do that and it works just fine. – Kimberley Nikolaevna Aug 08 '16 at 15:28
  • @EOF: The GNU linker defaults to setting the entry point to the beginning of the `.text` section if there's no `_start` label. e.g. on x86-64 `ld: warning: cannot find entry symbol _start; defaulting to 0000000008048060`. So I assume it's the same on MIPS. Still, `.globl _start` / `_start:` would be good practice to make this explicit, Kimberley. – Peter Cordes Aug 08 '16 at 17:17
  • 1
    What do you see when you single-step through your loop in a debugger? Does it go through the loop the right number of times? This would be a better question if you comment your code to explain at a higher level what's going on in each section. (Still, at least it's readably indented and has useful label names, so it's not too bad.) Adding info about what you can find out with a debugger would narrow things down a lot for people that might answer this. – Peter Cordes Aug 08 '16 at 17:23

1 Answers1

1

Okay, you had only one bug and it was a one-liner so you were doing pretty well.

However, there weren't too many comments in the code, so as I was reading/analyzing it, I added some.

I should mention that as I did this, I was able to spot the bug with just visual inspection and review. That is, I was able to find the bug and annotate it along with the fix with this alone.

So, I'd didn't actually need to step the code with the debugger. After applying the fix, it ran correctly the first time.

I recently answered a very similar question here: MIPS questions about writing assembly to call functions on an array that does sum/product on an array

Also, please see my answer here: MIPS linked list Amongst other things, it has a howto on writing clean mips/asm code, based on my own personal experience.

I created two versions of your code. One with minimal changes and just the bug fix. And, another, where I tightened it up and simplified it a bit. Please pardon the gratuitous style cleanups.


Here's the code with the bug/fix annotation:

    .data

    # NOTE/BUG: due to alignment issues put the .word directives _before_
    # the [variable length] .asciiz directives
size:       .word       0
to_store:   .word       0
sum:        .word       0
avg:        .word       0

size_prompt:    .asciiz "Enter number of elements: "
element_prompt: .asciiz "Enter an element: "
msg_space:      .asciiz " "

    .text
    .globl  main
main:

    # Prints prompt
    la      $a0,size_prompt
    addi    $v0,$0,4
    syscall

    # Gets input from user
    addi    $v0,$0,5
    syscall
    sw      $v0,size

    addi    $t0,$0,0                # Initialise i = 0

    # Creates the list
    lw      $s0,size                # get array count
    addi    $t1,$0,4                # get 4
    mult    $s0,$t1                 # get count * 4
    mflo    $t2                     # get offset
    add     $a0,$t1,$t2
    addi    $v0,$0,9
    syscall

stack:
    beq     $t0,$s0,list_sum        # done with number input? if yes, fly

    # prompt user for list element
    la      $a0,element_prompt
    addi    $v0,$0,4
    syscall

    # read in element value
    addi    $v0,$0,5
    syscall
    sw      $v0,to_store
    lw      $t5,to_store

    # push element to stack
    addi    $sp,$sp,-4
    sw      $t5,0($sp)

    addi    $t0,$t0,1           # advance array index
    j       stack

    # get sum of array elements
list_sum:
    beq     $s0,0,average       # at end? if yes, fly
    lw      $t6,sum             # get previous sum
    lw      $t7,0($sp)          # get next array element value
    addi    $sp,$sp,4           # advance array pointer
    add     $t6,$t7,$t6         # sum += array[i]
    sw      $t6,sum             # store it
    addi    $s0,$s0,-1          # bump down the _count_
    j       list_sum

    # NOTE/BUG: in the list_sum loop above, s0 is being decremented, so when we
    # get here it is _always_ zero
average:
    lw      $t0,sum             # get the sum

    # print the sum
    li      $v0,1
    move    $a0,$t0
    syscall

    # NOTE/FIX: restore the count value
    lw      $s0,size

    div     $t0,$s0             # divide by count
    mflo    $t0
    sw      $t0,avg             # store average

    li      $v0,4
    la      $a0,msg_space
    syscall

    # print average
    lw      $a0,avg
    addi    $v0,$0,1
    syscall

exit:
    li      $v0,10              # exit program
    syscall

Here's my take on cleanup.

mips has many registers, so when they can be used, intermediate results can be preserved.

For example, note that in the summation loop, a different register is used for the decrement, so $s0 remains. Also, I was able to use registers to hold all values that previously used memory locations [except for the stack usage]

    .data

size_prompt:    .asciiz "Enter number of elements: "
element_prompt: .asciiz "Enter an element: "
msg_space:      .asciiz " "

    .text
    .globl  main
main:

    # prompt user for number of elements
    la      $a0,size_prompt
    li      $v0,4
    syscall

    # get array count from user
    li      $v0,5
    syscall
    move    $s0,$v0                 # save array count

    li      $t0,0                   # i = 0

stack:
    beq     $t0,$s0,sumlist         # input done (i.e. i >= count)? if yes, fly

    # prompt user for list element
    la      $a0,element_prompt
    li      $v0,4
    syscall

    # read in element value
    li      $v0,5
    syscall

    # push element to stack
    addi    $sp,$sp,-4
    sw      $v0,0($sp)

    addi    $t0,$t0,1               # i += 1
    j       stack

    # get sum of array elements
    #   t6 -- sum value
sumlist:
    li      $t6,0                   # sum = 0
    move    $t4,$s0                 # get the count

sumlist_loop:
    beqz    $t4,average             # at end? if yes, fly

    # pop element off stack
    lw      $t7,0($sp)              # get next array element value
    addi    $sp,$sp,4               # advance array pointer

    add     $t6,$t6,$t7             # sum += array[i]
    addi    $t4,$t4,-1              # bump down the count
    j       sumlist_loop

    # get average
    #   t6 -- sum value
    #   t5 -- average value
average:
    # print the sum
    li      $v0,1
    move    $a0,$t6             # get the sum
    syscall

    div     $t6,$s0             # compute sum / count
    mflo    $t5                 # retrieve it

    # output a space
    li      $v0,4
    la      $a0,msg_space
    syscall

    # print average
    move    $a0,$t5
    li      $v0,1
    syscall

exit:
    li      $v0,10              # exit program
    syscall
Community
  • 1
  • 1
Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • Nice. I didn't even try to really follow the OP's code, since I wasn't in the mood for debugging beginner code from someone who pretty clearly hadn't even used a debugger. Lucky for the OP that someone else was feeling more generous with their time. :) – Peter Cordes Aug 09 '16 at 03:23
  • @PeterCordes I got into (i.e. learned) mips by answering questions on SO [leveraging my experience with a plethora of other asm/arches]. I've got several `perl` scripts that automate this process. For example, one of the first editors I used had an "asmfix" sub-command to reindent (IBM/370) assembly language. Out of nostalgia, I created an "asmfix" command, so it eliminates a bit of the drudge. mips is elegant in its simplicity. Although I like x86 [and almost any arch], mips doesn't have the complexities. Thus, it's like a vacation. – Craig Estey Aug 09 '16 at 03:44