LC-3 Assembly Code isn't processing user's input correctly

102 Views Asked by At

I have to do a LC-3 code for this question, and i'm having some trouble since I'm new to LC-3:

Write an LC-3 assembly language program that does the following:

  1. Output a message to the screen that prompts the user to type in an LC-3 assembly language instruction (like ADD). The user ends their input by pressing Enter/Return.
  2. If the instruction typed by the user is a legal LC-3 assembly language instruction, your program displays the corresponding 4-bit opcode. For example, if the user types "ADD", the program would print out "0001".
  3. If the instruction typed by the user is not a legal LC-3 assembly language instruction (for example, "ADDD"), your program displays an appropriate error message.
  4. After displaying the output, your program loops back to the top, reinitializes anything that needs to be reinitialized, and goes again.
  5. Your program will exit when the user types the string "QUIT" and presses Enter/Return.

This is my code:

.ORIG x3000

; Constants for comparison
ADD_STR  .STRINGZ "ADD"
AND_STR  .STRINGZ "AND"
JMP_STR  .STRINGZ "JMP"
BR_STR   .STRINGZ "BR"
QUIT_STR .STRINGZ "QUIT"

; Memory locations
MESSAGE  .STRINGZ "Enter an LC-3 assembly language instruction (type QUIT to exit): "
USER_INPUT .BLKW #20

MAIN
    LEA R0, MESSAGE       ; Display the prompt message
    PUTS
    
    ; Read user input
    LEA R0, USER_INPUT    ; Store user input here
    GETC                  ; Read the first character
    OUT                   ; Echo the character

    ; Loop to read input until Enter/Return is pressed
    LOOP
        GETC              ; Read the next character
        OUT               ; Echo the character
        BRZ END_LOOP      ; Exit loop if Enter/Return is pressed
        STR R0, R1, #0    ; Store the character in memory
        ADD R1, R1, #1    ; Move to the next memory location
        BRNZP LOOP        ; Repeat the loop

    END_LOOP

    ; Compare user input to known instructions
    LEA R1, USER_INPUT    ; Load the input string pointer
    LEA R2, ADD_STR      ; Load ADD instruction pointer
    LEA R3, AND_STR      ; Load AND instruction pointer
    LEA R4, JMP_STR      ; Load JMP instruction pointer
    LEA R5, BR_STR       ; Load BR instruction pointer
    LEA R6, QUIT_STR     ; Load QUIT instruction pointer
    
    ; Compare input with ADD
    CMP_ADD
        LDR R7, R1, #0   ; Load a character from input
        LDR R0, R2, #0   ; Load a character from ADD string
        NOT R0, R0       ; Get the 2's complement of ADD character
        ADD R0, R0, #1   ; Add 1 to compare with input character
        ADD R7, R7, #1   ; Prepare to compare next character
        BRnp ADD_CHECK   ; Check condition

    ADD_CHECK
        BRz IS_ADD       ; If both characters match, it's ADD instruction
        BRnzp CMP_AND    ; Else, check for AND instruction

    IS_ADD
        ; Display the opcode for ADD
        LEA R0, ADD_STR  ; Load ADD instruction string
        PUTS             ; Display it
        BRnzp MAIN       ; Go back to the main loop

    CMP_AND
        ; Similar comparison process for AND
        ; ... (Repeat the above process for AND, JMP, BR, QUIT)

    ; Handling for other instructions and errors can be written similarly

    ; Handle QUIT instruction
    QUIT_CHECK
        ; ...

    ; Other instruction checks and error messages go here

    ; Loop back to the beginning
    BRnzp MAIN

.END

the problem is that the program is not processing the user's input correctly, "Enter an LC-3 assembly language instruction (type QUIT to exit): is printed but when i try putting (e.g. ADD) nothing is returned, as well as the QUIT instruction that's not working. Also i'm not sure how to finish up with my code for this project. i hope someone can help me out. thanks.

1

There are 1 best solutions below

0
Erik Eidt On

First, up your debugging skill, and if you don't know debugging yet, now is a good time learn.  Debugging assembly code is much like debugging other languages: single step each line to make sure it is doing what is needed at that point.  One missing or bad instruction will ruin the whole program — any given instruction is depending on the prior ones being useful & correct.

Second, don't wait until you've written dozens of lines of code before you first run the debugger.  Better practice is to write a few lines of code, then run them single step in the debugger.  Observe the effect of the new instructions on CPU registers and data memory.  What you learn from that will help guide the development of rest of the project.

If you start the debugger on this code, you'll probably be confused as to why there are hundreds of NOP instructions before your code, and that is because you have placed your data at the entry point.  The simulator will start the program at x3000 due to the .ORIG statement, however, that's right where your data is.  To remedy is simple and there are two options, either (1) move data to after the code so main is the first actual instruction, -or- (2) don't move the data, but put a BR main right before the data so the simulator/program skips over the data and on to real code.

Jester is right that BRZ is testing for a null character and isn't going to work here, since GETC will never give you a null character.  GETC is a console input function and there is no null key on the keyboard for a user to type.  A better choice is to test for newline character as that is a real character that GETC can give you.  Jester is also right that you have some repeated code re: GETC that seems odd/unwanted — there's no reason to treat the first character of user input as special/different from the rest of them.

Your input loop is storing characters using R1 as a pointer, but have not put any particular value into R1, so that is storing into memory at location 0 and/or whatever is leftover in R1 from prior usage, rather than your buffer.  Your code later uses the buffer, but that's not where the characters went.  This is also observable in single step debugging — R1 doesn't have a value that matches your buffer's addresses, and, the further, store isn't putting characters into your buffer.  You can identify your buffer's addresses, and I call this getting to know your data — you can do this in the debugger before stepping instructions of the program, and when you know the addresses for your data, that will help you recognize bad pointers.

You're doing 2's complement negation properly to compare the characters, but there's no addition of the characters from the two strings, so effectively, the subtraction isn't happening.

Once you get the subtraction working (by adding the two characters together, one from one string and the other the 2's complement from the other string), that sets the condition codes, so you should do that add and a conditional branch (e.g. BRZ) as a sequence.  If you put other instructions in between (such as pointer increment of one, as you have), that will wipe out the condition codes with a new value — and pointer arithmetic does not set the condition codes usefully.  So, you need to either pair together in sequence the final add (that does the subtraction/comparison) with the conditional branch, or, retest the result to recover the condition codes (e.g. using ADD R4, R4, #0, which would retest conditions for R4, while otherwise being harmless).

If you test each possible command in that manner you're suggesting, you'll have a lot of almost pure duplicated code.  There are better approaches, where you'd have only one compare loop, but feed it different starting points to check for the various different strings.  But your approach should work, and may be be easier despite the duplication.