I'm very new to LC-3 assembly language, Currently doing an assignment, One of the questions I am asked is to output a user input string, for example:
Please enter a text: Hello world123
The text you have entered is: Hello world123
Here is the Code that I have been using:
.orig x3000
Lea r0, Name
Puts
Lea r0, inputstring
Puts
lea r2, outputstring
loop
getc
add r1,r0, -10
brz outside
out
str r0,r2, #0
add r2, r2, #1
brnzp loop
outside
lea r0, output_text
puts
Halt
Name .stringz "Francois Van Zyl"
inputstring .stringz "\nPlease enter a text: "
output_text .stringz "\nThe text you have typed is: "
outputstring .blkw 99
.end
I expect that after the user inputted a string, the program would show the result. How can I fix this?
I finally found it! by experimenting a lot.
here is the code I have done:
.orig x3000
Lea r1, storeString
Lea r0, Student
puts
Lea r0, Userinput
puts
LOOP
getc
out
str r0, r1, 0
add r1, r1, 1
add r0, r0, -10
brz OUTSIDE
brnzp LOOP
OUTSIDE
Lea r0, Outputtext
puts
Lea r0, storeString
puts
Halt
Student .stringz "Francois Van Zyl"
Userinput .stringz "\n\nPlease enter a text: "
Outputtext .stringz "The text you have typed is: "
storeString .blkw 99
.end
Related
This may seem rather silly, but there actually are hardly any resources to learn LC-3. I can't manage to seem to find a proper in depth analysis of the subject and explain how things work, I mean sure, you can find simple definitions and what certain op/pseudo-op codes do, but nothing written in full and fully explained.
If someone could do a full analysis of the following:
; Hello name in LC-3 assembler
.orig x3000
lea r0, what
puts
lea r1, name
; typical assembly language hack coming up
add r1, r1, #-1
char getc
putc
add r2, r0, #-10
brz completed; was a newline
str r0, r1, #0
add r1, r1, #1
brnzp char
completed lea r0, hello
puts
halt
That would probably extremely lengthy, but also very appreciated. (Maybe this is the first stack post for a full analysis of LC-3 code resource?)
p.s I don't expect the person who answers to explain what each op/pseudo op code does but at least be very specific about how the operator performs and does its work
I mostly learned how LC3 worked from plugging in code and stepping through it. Though I would reference Appendix A in the book a LOT.
; Hello name in LC-3 assembler
.orig x3000 ; Starting place in memory for our code
lea r0, what ; Load the memory address of variable what
puts ; Print the string who's memory address is stored in R0
lea r1, name ; Load the memory address of the variable name into R1
; typical assembly language hack coming up
add r1, r1, #-1 ; Subtract 1 from R1, then store into R1
char getc ; Get a single char from the user, store into R0
putc ; Print that same char to the console
add r2, r0, #-10 ; R2 = R0 - 10
brz completed ; If the user presses ENTER (Ascii 10)
; and we've subtracted 10 then we'll get a 0, exit program
str r0, r1, #0 ; Store the value of R0 into memory[R1 + 0]
add r1, r1, #1 ; R1 = R1 + 1
brnzp char ; Jump to Clear no matter what
completed lea r0, hello ; Load the memory address of variable hello into R0
puts ; Print the string stored in hello
halt ; Stop the program
I wrote a program for LC-3 to take in a number under 10 until 0 is reached, and then output the largest number entered.
Everything seems to work but I keep getting an incorrect, or nonexistent result. For example, if I input 1, 2, 3, then 0, it should say:
Zero entered, ending program. The largest integer entered was 3
but I'm getting nothing back.
The method I'm attempting to use to output the largest integer is to use the two's complement system to determine the larger number of two, and loop back if 0 is not entered, but I think my logic has a major issue.
Sorry, the formatting might be a bit wonky, and if you need any more information or if I've done something wrong (in terms of the post - I know my code is wrong) please let me know.
Thank you in advance! (Also I have a sample output at the bottom of the code.)
.ORIG x3000
AND R0,R0,#0 ;clear R0
AND R0,R0,#0 ;clear R1
LEA R0, MSG1 ;load address of message 1
PUTS ;display message
GETC ;read in character from keyboard
OUT ;echo input
ST R0, NUM1 ;store the number in num1
LD R2, NUM1
LD R1, POS48
ADD R2,R2, R1 ;adds 48 to make the character a number
BRz ZERO ;checks if the number is zero
LD R0, NEWLINE ;load newline
OUT ;execute newline
LOOP LEA R0, MSG1 ;load address of message 1
PUTS ;display message
GETC ;read in character from keyboard
OUT ;echo input
ST R0, NUM2 ;store character in num2
LD R2, POS48
LD R3, NUM2
ADD R0, R3, R2 ;adds 48 to make the character a number
BRz ZERO ;checks if the number is zero
LD R0, NEWLINE ;load newline
OUT ;execute newline
LD R1, NUM1 ;load the first number
LD R2, NUM2 ;load the second number
NOT R2, R2 ;two's complement of R2
ADD R2, R2, #1 ;getting negative of num 2
ADD R0, R1, R2 ;adding the two values
ST R0, MAX ;storing larger number in NUM5
BRnz LOOP ;Branch if R0 is positive
ZERO LEA R0, MSG2 ;load message if number entred is zero
PUTS ;display message
LD R0, NEWLINE ;load newline
OUT ;execute newline
LEA R0, MSG3 ;load largest int message
PUTS ;display
LD R2, MAX
LD R1, POS48
ADD R1, R2, R1 ;adds 48 to make the character a number
LD R0, MAX ;load largest int
OUT ;display largest int
HALT ;end program
;*** Data ***
MSG1 .STRINGZ "Enter a single-digit integer: "
MSG2 .STRINGZ "Zero entered, ending program."
MSG3 .STRINGZ "The largest integer is: "
POS48 .FILL #48
NEWLINE .FILL #10
NUM1 .BLKW 1
NUM2 .BLKW 1
MAX .BLKW 1
.END
Sample output -
Enter a single-digit integer: 1
Enter a single-digit integer: 2
Enter a single-digit integer: 3
Enter a single-digit integer: 0
Zero entered, ending program.
After debugging your program I was able to find two logical bugs in your code. The first is when you were trying to convert between integer value and ascii value. The second is when you are comparing two numbers to find which is larger. I have re-created a working version of your program and commented it very thoroughly so it should be easy to follow along with.
First problem was with your ascii integer conversion code. You were trying to convert to an integer value from an ascii digit using POS48 which was equal to 48; however, in order to convert from ascii to integer you must subract 48, or in the case of assembly add -48. Then to convert back from an integer value to an ascii value you would add positive 48.
For Example:
NEG48 .FILL xFFD0 ;create constant NEG48 which = xFFD0 = -48
LD R6, NEG48 ;load NEG48 into register 6
GETC ;get user input
ADD R0, R0, R6 ;add -48 to the user input to get integer value
The second problem was with the code comparing two integer values to find which is larger. In your code you were getting the two's compliment, getting the negative of the second value, and then adding it to the first value. This is correct except that you need to use a BRn and BRp to evaluate whether the result is positive or negative. If the value is positive this means that the first number is larger, and if it's negative the second number is larger. BRn will branch is negative, and BRp will branch if positive.
For Example the following code will compare a new number inputted by the user earlier in your program to the current maximum value entered by the user then saves the larger value into the CURRENTMAX variable:
LD R2, CURRENTMAX ;load CURRENTMAX
LD R3, NEWNUM ;load NEWNUM
NOT R4, R3 ;two's complement of NEWNUM
ADD R4, R4, #1 ;getting negative of NEWNUM
ADD R1, R4, R2 ;adding the negative of NEWNUM to CURRENTMAX
BRn LrgR3 ;if the result in R1 is negative NEWNUM is larger so branch to LrgR3
BRp LrgR2 ;if the result in R1 is positive CURRENTMAX is larger so branch to LrgR2
;**************** LrgR3 ****************
LrgR3 ;begin LrgR3
ST R3, CURRENTMAX ;store the larger result in CURRENTMAX
BR LOOP ;branch to LOOP
;**************** LrgR2 ****************
LrgR2 ;begin LrgR2
ST R2, CURRENTMAX ;store the larger result in CURRENTMAX
BR LOOP ;branch to LOOP
Finally here is the working re-written version that I made to help you better solve this problem.
.ORIG x3000
;**************** POLL INITIAL USER INPUT ****************
LD R5, POS48 ;load num to char conversion value
LD R6, NEG48 ;load char to num conversion value
LEA R0, MSG1 ;load MSG1
PUTS ;display MSG1
GETC ;get user input
OUT ;display users input
ADD R0, R0, R6 ;convert input char into a number value
ST R0, CURRENTMAX ;store numer value into MAX since the only number entered is obviously the MAX value entered
BRz ZERO ;if zero branch to ZERO
LD R0, NEWLINE ;load newline
OUT ;display newline
;**************** LOOP ****************
LOOP ;begin LOOP
LEA R0, MSG1 ;load MSG1
PUTS ;display MSG1
GETC ;get under input
OUT ;display user input
ADD R0, R0, R6 ;convert user input char into a number value
ST R0, NEWNUM ;store number value into NEWNUM
BRz ZERO ;if zero branch to ZERO
LD R0, NEWLINE ;load newline
OUT ;display newline
LD R2, CURRENTMAX ;load CURRENTMAX
LD R3, NEWNUM ;load NEWNUM
NOT R4, R3 ;two's complement of NEWNUM
ADD R4, R4, #1 ;getting negative of NEWNUM
ADD R1, R4, R2 ;adding the negative of NEWNUM to CURRENTMAX
BRn LrgR3 ;if the result in R1 is negative NEWNUM is larger so branch to LrgR3
BRp LrgR2 ;if the result in R1 is positive CURRENTMAX is larger so branch to LrgR2
;**************** LrgR3 ****************
LrgR3 ;begin LrgR3
ST R3, CURRENTMAX ;store the larger result in CURRENTMAX
BR LOOP ;branch to LOOP
;**************** LrgR2 ****************
LrgR2 ;begin LrgR2
ST R2, CURRENTMAX ;store the larger result in CURRENTMAX
BR LOOP ;branch to LOOP
;**************** ZERO ****************
ZERO ;begin ZERO
LD R0, NEWLINE ;load newline
OUT ;display newline
LEA R0, MSG2 ;load MSG2
PUTS ;display MSG2
LD R0, NEWLINE ;load newline
OUT ;display newline
LEA R0, MSG3 ;load MSG3
PUTS ;display MSG3
LD R0, CURRENTMAX ;load CURRENTMAXvalue
ADD R0, R0, R5 ;convert CURRENTMAX num into char
OUT ;display CURRENTMAX's char value
HALT ;end program
;**************** Variables and Constants ****************
MSG1 .STRINGZ "Enter a single-digit integer: "
MSG2 .STRINGZ "Zero entered, ending program."
MSG3 .STRINGZ "The largest integer is: "
POS48 .FILL x30
NEG48 .FILL xFFD0
NEWLINE .FILL #10
NEWNUM .BLKW 1
CURRENTMAX .BLKW 1
.END
How can I write a simple LC-3 program that compares the two numbers in R1 and R2 and puts the value 0 in R0 if R1 = R2, 1 if R1 > R2 and -1 if R1 < R2.
The comparison is done using simple arithmetic.
In my example we compare 2 and 6, you know what the result is.
LD R1, NUMBER1 ;load NUMBER1 into R1
LD R2, NUMBER2 ;load NUMBER1 into R2
AND R6,R6,#0 ;initialize R0 with 0
NOT R3, R2 ;R3 = -R2 (we negate NUMBER2)
ADD R4, R3, R1 ;R4 = R1 - R2
BRz Equals ;we jump to Equals if NUMBER1 = NUMBER2 (we can just jump directly to END)
BRn GreaterR2 ;we jump to GreaterR2 if NUMBER1 < NUMBER2
BRp GreaterR1 ;we jump to GreaterR2 if NUMBER1 > NUMBER2
Equals BRnzp End ;nothing to do, because R0=0 (THIS IS NOT NECCESARY)
GreaterR2 ADD R0, R0, #-1 ;R0 = -1
BRnzp End
GreaterR1 ADD R0, R0, #1 ;R0 = 1
BRnzp End
Done HALT ;THE END
NUMBER1 .FILL #2 ;/ Here we declare the numbers we want to compare
NUMBER1 .FILL #6 ;\
.ORIG x3000
AND R1, R1, x0
AND R2, R2, x0
LD R6, RESET
LEA R0, LINE1
PUTS
GETC
OUT
ADD R1, R6, R0
LEA R0, LINE2
PUTS
GETC
OUT
ADD R2, R6, R0
JSR COMPARE
HALT
;////////// COMPARE FUNCTION BEGINS /////////////
COMPARE
AND R3, R3, x0
NOT R2, R2
ADD R2, R2, x1
ADD R3, R1, R2
BRn NEG
ADD R3, R3, x0
BRp POS
ADD R3, R3, x0
BRz EQ
AND R5, R5, x0
ADD R5, R5, R1
RET
NEG LEA R0, N ; triggers when R3 IS NEGATIVE
PUTS
RET
POS LEA R0, P ; triggers when R3 IS POSITIVE
PUTS
RET
EQ LEA R0, E ; triggers when R3 IS ZERO
PUTS
RET
N .STRINGZ "\nX IS LESS THAN Y"
P .STRINGZ "\nX IS GREATER THAN Y"
E .STRINGZ "\nX IS EQUAL TO Y"
RESET .FILL xFFD0; RESET = -48 AS THIS IS ASCII RESETER FOR OUR PROGRAM
LINE1 .STRINGZ "ENTER X : "
LINE2 .STRINGZ "\nENTER Y : "
.END
Can anyone run this program, or try to help me understand why my counter isnt updating?
I am supposed to read in text from a prompt and find the length of the text and output it with a colon before printing out the actual text entered.
If the first time I type in "test" the length is 4, but then when it loops back to start it asks me to input again, it outputs the correct text, but the counter doesnt change unless the text is longer.
So, if i type "I", it will output length of 4, since test is longer and is 4. But if I type "Control" which is 7 letters, it will update the counter to 7.
OUTPUT:
Enter: Hey
3:Hey
Enter: Test
4:Test
Enter: Control
7:Control
Enter: Hey
7:Hey <---- Length should be 3!
Thank you!
.orig x3000 ; Starting point of the program.
BR start ; Branch to the start routine.
newln: .stringz "\n"
msg1: .stringz "Enter: "
; Prints out the instructions to the user and reads some user input.
start:
lea r0, newln ; Load address of newline into R0.
puts ; Print newline.
lea r0, msg1 ; Load address of message3 into R0.
puts
lea r2, MESSAGE ; Load starting point address of MESSAGE.
and r1, r1, #0 ; Initialize R1 to zero.
input:
getc ; Read in a single character to R0.
out
add r5, r0, #-10 ; Subtract 10 because enter key is 10.
BRz printint ; If zero, branch to checkChar routine.
; Else continue the loop.
str r0, r2, #0 ; Store char in MESSAGE.
add r2, r2, #1 ; Increment index of MESSAGE.
add r1, r1, #1 ; Increment input counter.
BR input ; Unconditional branch to input.
checkChar:
lea r5, inv81 ; Load address of inv68 into R6.
ldr r5, r5, #0 ; Load contents of inv68 into R6 (R6 now holds -68).
add r0, r3, r5 ; Add -68 to the value in R3, to check if it's 'q'.
BRz quit ; If zero, branch to decrypt.
;
;print integer starts here
;
printint:
ld r3,psign
jsr STRLEN
ADD r7, r0, #0 ; get the integer to print
brzp nonneg
ld r3,nsign
not r7,r7
add r7,r7,1
nonneg:
lea r6,buffer ; get the address of o/p area
add r6,r6,#7 ; compute address of end of o/p
ld r5,char0 ; get '0' to add to int digits
loop1:
and r0,r0,#0 ; init quotient for each divide
loop2:
add r7,r7,#-10 ; add -10
brn remdr ; until negative
add r0,r0,#1 ; incr to compute quotient
br loop2 ; repeat
remdr:
add r7,r7,#10 ; add 10 to get remainder
add r7,r7,r5 ; convert to ascii
str r7,r6,0 ; place ascii in o/p
add r7,r0,#0 ; move quot for next divide
brz end ; if done then print
add r6,r6,#-1 ; move to prev o/p position
br loop1 ; repeat
end:
add r6,r6,#-1 ; move to prev o/p position
str r3,r6,0 ; place sign
add r0,r6,#0 ; move address of 1st char
puts ; into r0 and print
output:
ld r5, colon
and r3,r3, 0;
add r0, r3, r5;
out
lea r2, MESSAGE ; Load (starting) address of MESSAGE.
outputLoop:
ldr r0, r2, #0 ; Load contents of address at MESSAGE index into R0.
out ; Print character.
add r2, r2, #1 ; Increment MESSAGE index.
add r1, r1, #-1 ; Decrease counter.
BRp outputLoop ; If positive, loop.
br start
quit:
halt ; Halt execution.
STRLEN:
LEA R2, MESSAGE ;R1 is pointer to characters
AND R0, R0, #0 ;R0 is counter, initially 0
LD R5, char0
LOOP: ADD R2, R2, #1 ;POINT TO NEXT CHARACTER
LDR R4, R2, #0 ;R4 gets character input
BRz FINISH
ADD R0, R0, #1
BR LOOP
FINISH:
ADD R0, R0, #1
ret
MESSAGE: .blkw 99 ; MESSAGE of size 20.
inv48: .fill #-48 ; Constant for converting numbers from ASCII to decimal.
inv81: .fill #-81 ; Constant for the inverse of 'Q'.
buffer: .blkw 8 ; o/p area
null: .fill 0 ; null to end o/p area
char0: .fill x30
colon .fill x3A
nsign .fill x2d
psign .fill x20
.end
At the end of your example, the contents in memory starting at message are:
Heytrol0000000
It looks to me like the problem is that in STRLEN we compute the length of the string by counting until we reach the first character that is 0. There are 7 characters in "Heytrol".
However, when we are storing the message, we count the number of characters that we have read in (kept in r1). When we print the string later on, we use the value in r1, so we don't end up printing any of the "extra" characters.
To fix this, I'd either output the value in r1 that was computed while reading the string as its length (get rid of the STRLEN code completely) or make sure that when we read the enter in the input loop, we write a zero into the string before going and printing:
input:
getc ; Read in a single character to R0.
out
add r5, r0, #-10 ; Subtract 10 because enter key is 10.
BRz finishString ; If zero, branch to finishString routine.
; Else continue the loop.
str r0, r2, #0 ; Store char in MESSAGE.
add r2, r2, #1 ; Increment index of MESSAGE.
add r1, r1, #1 ; Increment input counter.
BR input ; Unconditional branch to input.
finishString:
and r0, r0, #0 ; set r0 to zero so we can store it
str r0, r2, #0 ; write zero (from r0) into the end of the string
BR printint ; Now, branch to checkChar routine.
I am trying to write a LC3 assembly language program that takes two input numbers and prints out x * y = z.
I can get it to work for numbers 0-9 however any numbers above that I get weird letters or symbols.
Also how can I make it so that it can not only take only 1 inputs per GETC but two numbers eg. 10 * 12= 120?
Any help would be appreciated! :)
Here's what I have done so far
.ORIG x3000
AND R3, R3, #0 ;r3 stores the sum, set r3 to zero
AND R4, R4, #0 ;r4 is the counter
LD R5, INVERSE_ASCII_OFFSET ;inverse ascii offset
LD R6, DECIMAL_OFFSET ;decimal offset
;---------------------
;storing first input digits
LEA R0, display1 ;load the address of the 'display1' message string
PUTS ;Prints the message string
GETC ;get the first number
OUT ;print the first number
ADD R1, R0, #0 ;store input value(ascii) to r1
ADD R1, R1, R5 ;get real value of r1
;storing second input digits
LEA R0, display2 ;load the address of the 'display2' message string
PUTS ;Prints the message string
GETC ;get the first number
OUT ;print the first number
ADD R2, R0, #0 ;store input value(ascii) to r2
ADD R2, R2, R5 ;get real value of r2
;----------------------
ADD R4, R2, #0 ;fill counter with multiplier
MULTIPLICATION:
ADD R3, R3, R1 ;add to sum
ADD R4, R4, #-1 ;decrease counter by one
BRp MULTIPLICATION ;continue loop until multiplier is 0
LEA R0, stringResult
PUTS
ADD R0, R3, R6 ;move result to r0
OUT ;print result
HALT
display1 .STRINGZ "\nenter the 1st no.: "
display2 .STRINGZ "\nenter the 2nd no.: "
stringResult .STRINGZ "\nResult: "
INVERSE_ASCII_OFFSET .fill xFFD0 ; Negative of x0030.
DECIMAL_OFFSET .fill #48
.END
Your display function works by adding a number to the base ascii value of '0'. This works because the ascii table was arranged in a way to be convenient. For instance, '0' + 1 = '1', which is equivalent to 0x30 + 1 = 0x31. However, if you are probably finding that '0' + 12 = '<'. This is because '0' = 0x30, so 0x30 + 12 (0xC) = 0x3C. Looking at the ascii chart we see that 0x3C = '<'. That is, this is an effective method only to print out a single digit.
The answer to both your questions lie in writing a routine that iteratively deals with digits and forms a number with them. In other words, you will need a loop that determines which character to print out next and prints it.