How do I deal with three or more values being stored in stack pointer for MIPS Assembly?

This program is meant to allow the user to put dashes ('-' and '|') to form boxes, connecting vertices of a 3x3 grid.

So call this a beginner Assembly programmer question if you will, but I am having issues with storing three or more values on the stack pointer. I would like to return to main from loop1 by popping the return address off of the stack pointer; however, in checkMove the stack pointer is added to twice.

How can I solve my issue so that I can return to main from loop1?

    .data #Data declaration segment
board: .ascii   "\n\n   . . .          . 0 . 1 ."
       .ascii     "\n                  2   3   4"
       .ascii     "\n   . . .          . 5 . 6 ."
       .ascii     "\n                  7   8   9"
       .asciiz    "\n   . . .          . a . b .\n"
offset: .byte     6,   8,  33,  35,  37,  62,  64,  89,  91,  93,  118, 120
marker: .byte    '-', '-', '|', '|', '|', '-', '-', '|', '|', '|', '-', '-'

    .text #Text declaration statement

main:
    li $t0, 6 #Number of loops/moves to make
    jal loop1
    
    #Print game board
    li $v0, 4
    la $a0, board
    syscall
    
    #Exit Program
    li $v0, 10
    syscall
    
loop1:
    #Load return address onto stack pointer
    subu $sp, $sp, 4 
    sw $ra, ($sp) #Store $ra into $sp
    
    #Read integer for marking excluding a and b
    li $v0, 5
    syscall
    
    move $a0, $v0 #Set $v0 to $a0
    jal markMove #Jump to markMove; return address is set in $ra
    sub $t0, $t0, 1 #Decrement counter by 1
    bnez $t0, loop1 #Return to L1 if counter not 0
    
    #Once counter is 0, pop return address off stack pointer
    lw $ra, ($sp)
    addu $sp, $sp, 4
    
    jr $ra
    
#Mark a move on the game board
#Input : $a0 (Integer move 0-9)
markMove:
    ##Prepare to pass necessary variables ($v0, $ra) into function.
    
    #Push return address ($ra) onto stack pointer
    subu $sp, $sp, 4 
    sw $ra, ($sp) #Store $ra into $sp
    #Push $t0 onto stack pointer
    subu $sp, $sp, 4

    sw $t0, ($sp) #Store $t0 into $sp
    
    lb $t0, offset($a0)
    
    #Actually mark now
    lb $t1, marker($a0) #Find the marker
    sb $t1, board($t0) #Place the marker at spot in board

#Clear stack pointer ($sp) and return to $ra
loop2:
    ##Prepare to take the variables ($v0, $ra) from above.
    lw $t0, ($sp) #Pop $t0 off of stack pointer
    addu $sp, $sp, 4
    lw $ra, ($sp) #Pop $t0 off of stack pointer
    addu $sp, $sp, 4
    
    jr $ra #Return to return address; jump register

Upvotes: 0

Views: 351

Answers (1)

gusbro
gusbro

Reputation: 22585

Your problem is that you are pushing $ra on each iteration that reads a number from user (6 loops/moves according to your commented code).

You should only store the return address once every time you enter a new function/procedure, and restore it prior to returning from it.

So you would add another label after you save context and use it in your control loop. In this example I used inner_loop:

...
loop1:
    #Load return address onto stack pointer
    subu $sp, $sp, 4 
    sw $ra, ($sp) #Store $ra into $sp
    
inner_loop:
    #Read integer for marking excluding a and b
    li $v0, 5
    syscall
    
    move $a0, $v0 #Set $v0 to $a0
    jal markMove #Jump to markMove; return address is set in $ra
    sub $t0, $t0, 1 #Decrement counter by 1
    bnez $t0, inner_loop #Return to L1 if counter not 0
    
    #Once counter is 0, pop return address off stack pointer
...

Upvotes: 2

Related Questions