assemblylc3

why program not reaching 'RET' or HALT' in LC3?


When the user presses ENTER(ASCII 10), the code should subtract 10 then branch to GSEND and go to halt but instead it is doing some weird loop. code follows:

.orig x3000
MAIN
    LEA R0, STR1 ;R0 points to STR1, which is the memory where we store the string.
    JSR GETSTR ;Get a string from the user
    PUTS ;Print the string
    HALT

    ;Data – Change these for testing
    .blkw 50 ;Change this value when testing between 50 and 150.

;Save space for string storage. Note that this effectively limits your string
;size to 50 which is the number of zs below.
STR1 .stringz "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"

GETSTR

    ;save registers
    ST R2, GS_SR2
    ST R3, GS_SR3
    ST R4, GS_SR4

    LD R4, GS_LR4

    ADD R2, R0, #0

GSTOP

    GETC ;get character

    ADD R3, R0, R4 ;if newline skip to end
    BRZ GSEND

    STR R0, R2, #0 ;store letter in STR1
    OUT

    ADD R2, R2, #1 ;increment R2
    BRNZP GSTOP


GSEND


    ADD R0, R2, #0
    ;reset registers
    LD R2, GS_SR2
    LD R3, GS_SR3


    RET


GS_SR0  .fill 0
GS_SR2  .fill 0
GS_SR3  .fill 0
GS_SR4  .fill 0

GS_LR4  .fill -10


    .end

code should reprint the entire string and halt. i can't tell if it just never reaches RET or is getting sent somewhere else.


Solution

  • The JSR instruction performs a call.  A call does two things: transfers control to the designated label, and also, puts the place (here in main, a code address) to return to in R7.  In order for GETSTR to successfully return to main, it must have that same return address that main put into R7 via the JSR instruction.

    However, it does not, because the trap invoking instruction (here GETC) repurposes R7 for the return address from the trap.  So, in some sense, use of GETC wipes out one R7 value so that GETC can use R7 to return back to GETSTR.  So, when GETSTR tries to use R7 via RET, it returns not to where should go, but to the return address in R7, which is within GETSTR right after the GETC since that is how R7 was last used — hence the weird loop.

    Just need to save & restore R7 the same way as some of the other registers already being done.