How to store a value on an address line? - lc3

I need help with figuring out how do I store the value of a register (e.g. R0) on an address line that can be found on yet another register (e.g. R1):
AddressLine[R1] <- M[R0]
if R1 = x3400
then x3400 <- M[R0]

You're looking for the STR instruction
STR <source register> <base register> <immediate offset>
i.e.
AND r0,r0,#0 ; clear r0
ADD r0,r0,#10 ; r0 = 10
LEA r1,MEMSPACE ; address of MEMSPACE
STR r0,r1,#0 ; M[R1 + 0] = R0
MEMSPACE .word 0 ; will become 10

Related

ARM legV8 Program received signal SIGSEGV, Segmentation fault

I have recently wrote this code in assembly (ARM legV8) which uses recursion to calculate gcd between 64 bit random numbers. In the first place i generate 2 random numbers using random() and then i check if the are relatively prime ( gcd(num1,num2) == 1). If not then generate new numbers. Repeat until relatively prime numbers are found. The random() and gcd() functions are working fine (checked). I have an issue with the stack (Segmentation fault) when i try to store on it an updated value. I get error on the third time i call the loop on that line str x22,[x29,24] Here is my code :
.data //Start of the datasegment
q_initialState: .string "Please enter the intial state : "
scanner_hex: .string "%p"
output_num: .string "%llu\n"
gcd_result: .string "GCD is : %d\n"
message: .string "They are prime numbers \n"
.text //Start of the .text segment
.global main
main:
stp x29,x30,[sp,-32]!
add x29,sp,0
adr x0,q_initialState
bl printf
add x1,x29,28
adr x0,scanner_hex
bl scanf
ldr x19,[x29,28] //this is the initial state
loop:
mov x2,x19
bl random
mov x22,x5
mov x1,x22
adr x0,output_num
bl printf
mov x2,x19
bl random
mov x23,x5
mov x1,x23
adr x0,output_num
bl printf
str x22,[x29,24] // <----------- ERROR HERE ---------
str x23,[x29,28]
bl gcd
cmp x24,1
bne loop
ldp x29,x30,[sp],32
ret
random:
stp x29,x30,[sp,-32]!
add x29,sp,0
eor x2,x2,x2,lsr 12
eor x2,x2,x2,lsl 25
eor x2,x2,x2,lsr 27
ldr x4,=0x2545f4914f6cdd1d
mul x5,x2,x4
mov x19,x2
ldp x29,x30,[sp],32
ret
gcd:
stp x29,x30,[sp,-32]!
add x29,sp,0
ldr x9,[x29,56] //Value for variable m
ldr x10,[x29,60] //Value for variable n
udiv x11,x9,x10
mul x11,x11,x10
sub x1,x9,x11
cbz x1,return_n
str x10,[x29,24]
str x1,[x29,28]
bl gcd
ldp x29,x30,[sp],32
ret
return_n:
ldr x1,[x29,60]
mov x24,x1
ldp x29,x30,[sp],32
ret

How do I implement a division algorithm in ARM Assembly?

I am trying to implement the following algorithm in ARM assembly, but when I run my code in ARMSim 1.9.1, it prints out the quotient and remainder completely unchanged (0 and 5 in this case). Can someone tell me what I am doing wrong? I think it is probably where I'm trying to set the rightmost bits of the register.
Given: Two positive integers: a Divisor X, and a Dividend Y
Use three General Purpose Registers (R, Q, X)
where R stores the Remainder, Q stores the Quotient, and X stores the Divisor.
Steps:
1. Copy Y into the Remainder register (R)
Register Q will be initialized as 0
2. update: R = R - X
3. If R >= 0 then
Shift the Quotient Register (Q) to the left (1 bit)
and set the new rightmost bit to 1
Else
Restore the original value by of R: R = R + X
Also, Shift the Quotient Register (Q) to the left (1 bit)
and set the new least significant bit to 0
4. Shift the Divisor Register (X) to the right (1 bit)
5. Repeat 31 more times
And here is my code:
.equ X, 12 # the divisor - change to whatever number you wish
.equ Y, 5 # the dividend - change to whatever number you wish
.global main
main:
LDR R6, =Y # R6 = R = Y
MOV R7, #0 # R7 = Q = 0
MOV R8, #0 # R8 = count = 0
LDR R9, =X # R9 = X
loop: SUB R6, R6, R9 # R -= X
CMP R6, #0 # if R >= 0
BGE _if # goto _if
CMP R6, #0 # else if R < 0
BLT _else # else goto _else
ADD R8, R8, #01 # count++
MOV R9, R9, LSR #01 # shift X right 1 bit
CMP R8, #32 # if count <= 32
BLE loop # continue looping
_if:
MOV R7, R7, LSL #01 # shift Q left 1 bit
ORR R7, R7, #01 # set rightmost bit to 1
_else:
ADD R6, R6, R9 # R += X
MOV R7, R7, LSL #01 # shift Q left 1 bit
AND R7, R7, #2147483646 # set rightmost bit to 0
exit:
MOV R1, R7 # R1 = Q
SWI 0x6B # cout << R1
MOV R1, R6 # R1 = R
SWI 0x6B # cout << R1
SWI 0x11 # exit

Where to learn LC3 with proper full explanations?

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

LC-3 How do I reset my counter?

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.

LC3 Assembly Language

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.

Resources