loopslc3

Is there a reason this LC-3 subroutine keeps looping?


    AND R3, R3, #0    ; Initialize step count to 0
    ADD R4, R7, #0
    LOOP              ; Loop until X becomes 1
    ADD R0, R0, #-1   ; Checks if X = 1
    BRnz QUIT
    ADD R0, R0, #1    ; Restores value of X
    ADD R2, R0, #0    ; Copy X into R2
    AND R2, R2, #1    ; Check if X is odd
    BRz EVEN          ; Branch to EVEN if X is even
    JSR MUL3ADD1      ; Run the MUL3ADD1 subroutine if odd
    ADD R0, R1, #0    ; Copy the result into X
    ADD R3, R3, #1    ; Increment the step count
    BRnzp LOOP        ; Loop again
    EVEN
    JSR DIVIDEBY2     ; Run the DIVIDEBY2 subroutine if even
    ADD R0, R1, #0    ; Copy the result into X
    ADD R3, R3, #1    ; Increment the step count
    BRnzp LOOP        ; Loop again
    QUIT
    ADD R7, R4, #0    ; resets R7 value
    RET

I need the loop to terminate at quit by returning to the user when R0 = 1, but it doesn't stop. MUL3ADD1 and DIVIDEBY2 work independently so it's not a problem with those.


Solution

  • Yes, the problem is that the return address is being overwritten.  It is stored in R7, and wiped out / repurposed by JSR.

    As a result RET will retun to within its self instead of the caller.

    So, that code needs to manage R7.  Save it upon entry and restore it just prior to ret.  Should ba able to find examples doing that.

    The registers do not stack themselves, they are globally accessible storage locations that can only hold one value at a time.

    While it is relatively efficient to pass the return address location in a register, if the function repurposes R7, and intends to later return to its caller, it will have to manage the return addresses.

    It is too bad, IMHO, that LC-3 simulators do not set up a stack by default, as popular MIPS and RISC V simulators (MARS,RARS) do.  That means that if you want to use the stack for such temporary storage purposes, you have to establish one yourself.

    The other common approach on LC-3 is to simply use a global variable to store the old/incoming R7 value so that R7 can be repurposed and still the function can find its way back to its caller.  Use of global variables for these purposes precludes recursion and reentrancy, but is still a common approach on LC-3.