assemblymipsqtspim

MIPS Double Recursion Problem " Can't expand stack segment by 16 bytes to 524288 bytes"


I'm trying to implement a double recursion program using MIPS that follows this pseudocode:

procedure DRAGON(order, sign)
    if order = 0 then
        Move forward
    else
        DRAGON(order-1; 1)
        Turn 90sign
        DRAGON(order-1; -1)

This is what I have until now, but when I run it, I get this error:

Can't expand stack segment by 16 bytes to 524288 bytes.
Use -lstack # with # > 524288

I'm new to MIPS so it's really difficult for me to debug this. I suspect that it's probably because I'm making infinite recursive calls, but I'm not sure how to fix this. Could anyone be able to help point out what the problem is?

        .data
# SVG path segment commands
up:     .asciiz "v-5"
right:  .asciiz "h5"
down:   .asciiz "v5"
left:   .asciiz "h-5"

# Print one of the path segment strings by readings its address
# from this array of pointers
        .align 2
dirs:   .word up, right, down, left

# Keep the current direction (0-3) in this single byte value
direction:
        .byte 3

        .text
        # $a0 = order (an unsigned integer)
        # $a1 = sign (either 1 or -1)

        .globl dragon

dragon:
        addiu   $sp, $sp, -16           # allocate space on stack (multiple of 8)
        la      $t0, dirs               # t0: dirs array address
        lbu     $t1, direction          # t1: load current direction byte
        move    $t6, $t1                # t6: copy of current direction byte
        li      $t2, 1                  # t2: load constant 1
        li      $t3, -1                 # t3: load constant -1

        sw      $ra, 0($sp)
        sw      $a0, 4($sp)
        sw      $a1, 8($sp)
        beq     $a0, $0, base

        move    $t4, $a1                # t4: keep current sign (1 or -1)
        addiu   $a0, $a0, -1            # order = order - 1
        move    $a1, $t2                # sign = 1
        jal     dragon                  # dragon(order-1, 1)

        li      $v0, print_int
        move    $a0, $a1
        syscall

        addu    $t5, $t6, $t4
        addiu   $t5, $t5, 4
        div     $t5, $t5, 4
        mfhi    $t6                     # t1: (direction + sign + 4) % 4 -> new direction
        sb      $t6, direction

        move    $a1, $t3
        jal     dragon                  # dragon(order-1, -1)
        j       done

base:                                   # when order = 0
        addu    $t1, $t1, $t1
        addu    $t1, $t1, $t1           # direction * 4
        addu    $t5, $t1, $t0           # base address + offset
        lw      $t5, 0($t5)             # t5: direction from array dirs

        li      $v0, print_string
        move    $a0, $t5
        syscall                         # print direction

done:
        lw      $ra, 0($sp)
        lw      $a0, 4($sp)
        lw      $a1, 8($sp)
        addiu   $sp, $sp, 16
        jr      $ra
#
# Main program
#
        .data
svg_header:
        .asciiz "<svg xmlns=\"http://www.w3.org/2000/svg\">\n"
svg_footer:
        .asciiz "</svg>\n"
path_header:
        .asciiz "<path stroke=\"black\" fill=\"none\" d=\"M225 225"
path_footer:
        .asciiz "\" />\n"

        .text

        .globl main
main:
        move    $s0, $ra

        la      $a0, svg_header
        li      $v0, print_string
        syscall

        la      $a0, path_header
        syscall

        li      $a0, 3   # Order
        li      $a1, 1   # Sign
        jal     dragon

        la      $a0, path_footer
        li      $v0, print_string
        syscall

        la      $a0, svg_footer
        syscall

        li      $v0, 10
        syscall


Solution

  • In your recursive fragment, you don't return before the base bits. So after the second jal dragon, your code falls through to the base scenario, which is wrong by any account. By that time, t1 no longer contains the direction variable - it's been multiplied by four. In the base, the code tries to resolve t1 as if it still was the direction and faults.