How to make this LC3 program multiply instead? - loops

Was trying to learn how to multiply in LC3 but having trouble modifying my old program that was just meant for adding sums. How would I go about modifying this program to multiply by the 2 given inputs?
Code:
.ORIG x3000 ; begin at x3000
; input two numbers
IN ;input an integer character (ascii) {TRAP 23}
LD R3, HEXN30 ;subtract x30 to get integer
ADD R0, R0, R3
ADD R1, R0, x0 ;move the first integer to register 1
IN ;input another integer {TRAP 23}
ADD R0, R0, R3 ;convert it to an integer
; add the numbers
ADD R2, R0, R1 ;add the two integers
; print the results
LEA R0, MESG ;load the address of the message string
PUTS ;"PUTS" outputs a string {TRAP 22}
ADD R0, R2, x0 ;move the sum to R0, to be output
LD R3, HEX30 ;add 30 to integer to get integer character
ADD R0, R0, R3
OUT ;display the sum {TRAP 21}
; stop
HALT ;{TRAP 25}
; data
MESG .STRINGZ "The sum of those two numbers is: "
HEXN30 .FILL xFFD0 ; -30 HEX
HEX30 .FILL x0030 ; 30 HEX
.END```

The simplest approach to multiply on LC-3 is repetitive addition. So keep summing the multiplicand and decrement the multiplier; the iteration stops when the multiplier is consumed (i.e. zero).
There are lot's of caveats: if the multiplier is negative, then we would either negate it to use with count down, or count up instead — either way, the final result would be negated.
Since multiplication is commutative, we might consider using the lessor (absolute) value for the multiplier so that fewer iterations are done. But for more optimal multiplication, we would switch to a whole 'nother algorithm, the shift and add. Note that this algorithm is usually presented for hardware implementation, in which saving precious register bits is important, whereas for software this is not a really significant concern.

Related

How can I use arm adcs in loop?

In arm assembly language, the instruction ADCS will add with condition flags C and set condition flags.
And the CMP instruction do the same things, so the condition flags will be recovered.
How can I solve it ?
This is my code, it is doing BCD adder with r0 and r1 :
ldr r8, =#0
ldr r9, =#15
adds r7, r8, #0
ADDLOOP:
and r4, r0, r9
and r5, r1, r9
adcs r6, r4, r5
orr r7, r6, r7
add r8, r8, #1
mov r9, r9, lsl #4
cmp r8, #3
bgt ADDEND
bl ADDLOOP
ADDEND:
mov r0, r7
I tried to save the state of condition flags, but I don't know how to do.
To save/restore the Carry flag, you could create a 0/1 integer in a register (perhaps with adc reg, zeroed_reg, #0?), then next iteration cmp reg, #1 or rsbs reg, reg, #1 to set the carry flag from it.
ARM can't materialize C as an integer 0/1 with a single instruction without any setup; compilers normally use movcs r0, #1 / movcc r0, #0 when not in a loop (Godbolt), but in a loop you'd probably want to zero a register once outside the loop instead of using two instructions predicated on carry-set / carry-clear.
Loop without modifying C
Use teq r8, #4 / bne ADDLOOP as the loop branch, like the bottom of a do{}while(r8 != 4).
Or count down from 4 with tst r8,r8 / bne ADDLOOP, using sub r8, #1 instead of add.
TEQ updates N and Z but not C or V flags. (Unless you use a shifted source operand, then it can update C). docs - unlike cmp, it sets flags like eors. The eq / ne conditions work the same: subtraction and XOR both produce zero when the inputs are equal, and non-zero in every other case. But teq doesn't even set C or V flags, and greater / less wouldn't be meaningful anyway.
This is what optimized BigInt code like GMP does, for example in its mpn_add_n function (source) which adds two bigint inputs (arrays of 32-bit chunks).
IDK why you were jumping forwards over a bl (branch-and-link) which sets lr as a return address. Don't do that, structure your asm loops like a do{}while() because it's more efficient, especially when the trip-count is known to be non-zero so you don't have to worry about running the loop zero times in some cases.
There are cbz/cbnz instructions (docs) that jump on a register being zero or non-zero without affecting flags, but they can only jump forwards (out of the loop, past an unconditional branch). They're also only available in Thumb mode, unlike teq which was probably specifically designed to give ARM an efficient way to write BigInt loops.
BCD adding
Your algorithm has bugs; you need base-10 carry, like 0x05 + 0x06 = 0x11 not 0x0b in packed BCD.
And even the binary Carry flag isn't set by something like 0x0005000 + 0x0007000; there's no carry-out from the high bit, only into the next nibble. Also, adc adds the carry-in at the bottom of the register, not at nibble your mask isolated.
So maybe you need to do something like subtract 0x000a000 from the sum (for that example shift position), because that will carry-out. (ARM sets C as a !borrow on subtraction, so maybe rsb reverse-subtract or swap the operands.)
NEON should make it possible to unpack to 8-bit elements (mask odd/even and interleave) and do all nibbles in parallel, but carry propagation is a problem; ARM doesn't have an efficient way to branch on SIMD vector conditions (unlike x86 pmovmskb). Just byte-shifting the vector and adding could generate further carries, as with 999999 + 1.
IDK if this can be cut down effectively with the same techniques hardware uses, like carry-select or carry-lookahead, but for 4-bit BCD digits with SIMD elements instead of single bits with hardware full-adders.
It's not worth doing for binary bigint because you can work in 32 or 64-bit chunks with the carry flag to help, but maybe there's something to gain when primitive hardware operations only do 4 bits at a time.

How to print the binary version of a value in an LC3(using Assembly language) using a loop and a string? [duplicate]

I'm trying to print a binary number to the console using LC-3 assembly.
What I've tried so far includes (but isn't limited to):
binary .fill b10000110
lea r0, binary
puts ; prints garbage
ld r0, binary
out ; prints 0 (I know it only prints one character but I don't know why it chooses to print 0)
lea r1, binary
and r2, r2, #0
loop ldr r0, r1, r2
out
add r2, r2, #1
and r3, r3, #0
not r3, r2
add r3, r3, #1
add r3, r3, #8 ; I know all the binary numbers will be exactly 8 bits long
brz end
add r3, r3, #0 ; to be safe
brnzp loop
end
; more code...
None of this works particularly well. I'm pulling my hair out trying to figure out the proper way to do this, but everything I'm thinking of relies on binary being a string, which I can't do.
In LC-3, the OUT trap subroutine takes the value currently stored in register R0, finds the corresponding ASCII value and outputs it to the console, while the PUT trap subroutine takes the value stored in R0 as a memory, and iterates through all the data stored at that address, outputting each byte as ASCII to the console, until it finds a NULL character.
In the example you gave, PUTS will print out the ASCII representation of b10000110, followed by garbage until it happens to hit a NULL character whereas OUT will simply print the ASCII representation of b10000110.
Subsequently, to actually print a 0 or a 1, we must print the ASCII representation of those numbers, not the numbers themselves. So, we define two words, one for the ASCII character 0, and the other for 1.
ascii0 .fill x30
ascii1 .fill x31
So, for any 1-bit number, we can print it to the console with a simple if-else branch and the OUT subroutine.
binary .fill b1
LD R1, binary
AND R0, R1, #1
BRnz else
LD R0, ascii1
BRnzp done
else LD R0, ascii0
done OUT
Now, we must extend this to n-bits. That is to say that we must break our n-bit number into a series of 1-bit numbers that we can easily print. To achieve this, all we need is a simple AND and a mask for the ith bit (e.g. given the 8-bit number b10000110, to determine the 3rd least significant bit, we would use the mask b00000100). So, for an 8-bit number, we will need the sequence of masks b10000000, b01000000, ..., b00000001. There are several ways to do this, such as starting with b10000000 and left-shifting/multiplying by 2 for each bit, however for the sake of simplicity we will use a lookup table.
masks .fill b10000000
.fill b01000000
.fill b00100000
.fill b00010000
.fill b00001000
.fill b00000100
.fill b00000010
.fill b00000001
To choose the mask before we print out each bit, we can use a simple for-loop branch.
AND R4, R4, #0 ;clears the register we will count with
LD R1, binary
LEA R2, masks ;finds the address in memory of the first mask
loop LDR R3, R2, #0 ;load the mask from the address stored in R2
ADD R2, R2, #1 ;next mask address
AND R0, R1, R3
;print out 1-bit number
ADD R4, R4, #1
ADD R0, R4, #-8 ;sets condition bit zero when R4 = 8
BRn loop ;loops if R4 < 8
Finally, we have our completed program.
.ORIG x3000
AND R4, R4, #0 ;clears the register we will count with
LD R1, binary
LEA R2, masks ;finds the address in memory of the first mask
loop LDR R3, R2, #0 ;load the mask from the address stored in R2
ADD R2, R2, #1 ;next mask address
AND R0, R1, R3
BRnz else
LD R0, ascii1
BRnzp done
else LD R0, ascii0
done OUT
ADD R4, R4, #1
ADD R0, R4, #-8 ;sets condition bit zero when R4 = 8
BRn loop ;loops if R4 < 8
HALT
masks .fill b10000000
.fill b01000000
.fill b00100000
.fill b00010000
.fill b00001000
.fill b00000100
.fill b00000010
.fill b00000001
ascii0 .fill x30
ascii1 .fill x31
binary .fill b10000110
.END

ARM Assembly, Keil Microvision 4; Working with non-zero registry values

Hoping for just a bit of help with something.
I have a college assignment which involves making what is basically a calculator that takes values entered in by the user as a string of ASCII characters and stores and displays the entered value, as well as making various computations such as sum, min, etc. and stores them all as well. The code only executes after a value is entered.
My code itself is working how I need it to so far, and I think I know how to write in all the computations, but my issue is that most of the registers hold non-zero values from the start, and so if I start adding in values to a register right away -- for the sum, for instance -- the end value will be incorrect. I can't just use LDR and set them to zero beforehand, though, since that will happen every time the code is run, and I need to keep the added values around to make the computations each time.
I don't know if I'm overthinking this or if there's something really simple that I'm missing, but I can't think of a way to do what I need to with non-zero registry values.
This is my working code so far:
AREA ConsoleInput, CODE, READONLY
IMPORT main
IMPORT getkey
IMPORT sendchar
EXPORT start
PRESERVE8
start
read
LDR R7, =0
BL getkey ; read key from console
CMP R0, #0x0D ; while (key != CR)
BEQ endRead ; {
BL sendchar ; echo key back to console
;R4 is used to store the hex value of whatever is entered (as a full number)
;R5 stored the entered input safely (as R0 can change)
;R6 holds the constant 10, for increasing successive entries by a base of ten
;R10 is where successive values are multiplied by 10
;R11 is used to hold the count (+1 each time the code is run)
LDR R6, =10
MUL R10, R6, R10
MOV R5, R0
AND R5, R5, #&F
ADD R10, R10, R5
MOV R4, R10 ;NUMBER ENTERED SENT TO R4
ADD R11, R11, #1 ;COUNT
B read ; }
endRead
stop B stop
END

LC-3 Decimal to Binary Converter

I have to create a program that converts the given user input (decimal) into its binary match when the user presses enter or exit when they press X. Can anyone give a pointer on how to start this assignment. We are required to use masks and loops, but I do not know where to start with this.
I wrote this because there aren't a whole lot of examples of binary masks.
A binary mask is useful in assembly because it gives us the power to examine a single bit in a decimal or hex value.
Example:
If we look at the decimal number 5 we know its binary value is 0101, when we AND R4, R4, R5 on our first loop we compare 1000 with 0101. Since bit[3] is a zero in 0101 we then tell the LC3 simulator to print out an ASCII char "0". We then repeat the process with the next binary mask 0100.
This can be a tricky concept to get at first so I would first look at a few examples of loops and bit masks.
LC3 Bit Counter
How do I write a program that prints out “Hello World”, 5 times using a loop in LC3?
.ORIG x3000
LEA R0, PROMPT
PUTs ; TRAP x22
LD R0, ENTER
OUT ; TRAP x21
IN ; TRAP x23
AND R5, R5, #0 ; clear R5
ADD R5, R5, R0 ; Store the user input into R5
AND R1, R1, #0 ; clear R1, R1 is our loop count
LD R2, MASK_COUNT ; load our mask limit into R2
NOT R2, R2 ; Invert the bits in R2
ADD R2, R2, #1 ; because of 2's compliment we have
; to add 1 to R2 to get -4
WHILE_LOOP
ADD R3, R1, R2 ; Adding R1, and R2 to see if they'll
; will equal zero
BRz LOOP_END ; If R1+R2=0 then we've looped 4
; times and need to exit
LEA R3, BINARY ; load the first memory location
; in our binary mask array
ADD R3, R3, R1 ; use R1 as our array index and
; add that to the first array location
LDR R4, R3, #0 ; load the next binary mask into R4
AND R4, R4, R5 ; AND the user input with the
; binary mask
BRz NO_BIT
LD R0, ASCII_ONE
OUT ; TRAP x21
ADD R1, R1, #1 ; add one to our loop counter
BRnzp WHILE_LOOP ; loop again
NO_BIT
LD R0, ASCII_ZERO
OUT ; TRAP x21
ADD R1, R1, #1 ; add one to our loop counter
BRnzp WHILE_LOOP ; loop again
LOOP_END
LD R0, ENTER
OUT ; TRAP x21
HALT ; TRAP x25
; Binary Maps
BINARY .FILL b0000000000001000
.FILL b0000000000000100
.FILL b0000000000000010
.FILL b0000000000000001
.FILL b0000000000000000
; Stored Values
ENTER .FILL x000A
ASCII_ZERO .FILL x0030
ASCII_ONE .FILL x0031
MASK_COUNT .FILL x04 ; loop limit = 4
PROMPT .STRINGZ "Enter a number from 0-9"
.END

ARM Division by 10 Save remainder and quotient

This is a question on homework from CS2400 MSU Denver
Hello,
I have a program that reads keys from the user until they have either entered a non HEX character or entered a max of 8 HEX characters. As keys are entered I maintain a sum of hex values being entered by the user by multiplying the sum register by 16 and adding the new hex value.
This part is all fine and dandy, no help needed. I am having trouble taking this final result, in HEX, and converting it to DEC. I know I need to divide by 10 only I don't know how I can accomplish this.
Please help me determine how to divide by 10 and save the quotient and remainder. Thanks.
AREA HW6, CODE
ENTRY
Divsor EQU 10
MAIN
MOV R1, #0 ; Clear register to be used as symbols received counter
MOV R2, #0 ; Clear register to be used as temp result
LDR R4, =DecStr ; Load address of DecStr
LDR R5, =TwosComp ; Load address of TwosComp
LDR R6, =RvsDecStr
BL READ_CHARS ; Read characters from the keyboard
BL TO_DECIMAL ; Is R2 negative ?
SWI 0x11
READ_CHARS
CMP R1, #8 ; Check if necessary to read another key
BEQ DONE_READ_CHAR ; User has entered 8 hex symbols
SWI 4 ; [R0] <--- Key from keyboard (ASCII)
CMP R0, #'0' ; Verify digit is valid
BLO DONE_READ_CHARS
CMP R0, #'9' ; Verify digit is valid
BHI CHECK_HEX
SUB R0, R0, #'0' ; Obtain Hex equivalent of ASCII char 0-9
B STORE_INPUT
CHECK_HEX
CMP R0, #'A'
BLO DONE_READ_CHARS ; Invalid Hex symbol
CMP R0, #'F'
BHI DONE_READ_CHARS ; Invalid Hex symbol
SUB R0, R0, #'A'
ADD R0, R0, #0xA ; Adding ten to receive Hex equivalent of ASCII A-F
STORE_INPUT
MOV R3, R2, LSL#4 ; *16
ADD R2, R3, R0 ; Add valid Hex symbol to temp result
ADD R1, R1, #1 ; Increase symbol's recieved counter
B READ_CHARS ; Get next key
DONE_READ_CHARS
MOV PC, LR ; Return to BL READ_CHARS ( MAIN )
TO_DECIMAL
TST R2, #2, 2
BEQ POSITIVE
STRB #'-', [R4], #1 ; Store - as first byte in DecStr
MVN R2, R2 ; [R2] <- 1's complement of R2
ADD R2, R2, #1 ; [R2] <- 2's complement of R2
POSITVE
STR R2, [R5] ; Store all entered hex values in memory at TwosComp
LDR R7, [R5] ; Initial quotient
udiv10
LDRB R7, [R5], #1 ; Load a byte of TwosComp
CMP R7, #0
BEQ DONE_TO_DECIMAL
DONE_TO_DECIMAL
MOV PC, LR
AREA data1, DATA
TwosComp
DCD 0
DecStr % 12
RvsDecStr
% 11
ALLIGN
END
You can do it by subtracting-and-shift like elementary division easily. There are also many division algorithms on this site and Google
How does one do integer (signed or unsigned) division on ARM?
Assembly mod algorithm on processor with no division operator
But if you only want to convert from hexadecimal to decimal then double dabble may fit your need. It converts number to packed BCD without any division

Resources