Editing my Easy68k (Assembly) Program to subtract instead of add - algorithm

Ok, here it is guys. Before you, I have a program that performs this algorithm:
"IF X > 12 THEN X = 2*X+4 ELSE X = X + Y, OUTPUT X."
the problem is, I need it to perform this one instead:
"IF X > 12 THEN X = 2*X+4 ELSE X = X - 13, OUTPUT X."
How would I make this subtract rather than add?
ORG $1000
START: LEA PROMPT, A1
MOVE.B #14, D0 ; display string
TRAP #15
MOVE.B #4, D0 ; read from keyboard
TRAP #15
MOVE D1, D3 ; copy X
LEA STTY, A1
MOVE.B #14, D0 ; display string
TRAP #15
CMP #12, D3 ; X > 12 ?
BGT MULTADD ; branch if yes
CMP #12, D3 ; why compare again??
BRA ADDY
MULTADD
LEA XGT, A1
MOVE.B #14, D0 ; display string
TRAP #15
LEA TWOXP4, A1
MOVE.B #14, D0 ; display string
TRAP #15
MULU #2, D3 ; 2*X
ADD #4, D3 ; +4
MOVE D3, D1 ; copy to D1
MOVE.B #3, D0 ; Display decimal signed D1.L in smallest field
TRAP #15
BRA FIN
ADDY LEA XLT, A1
MOVE.B #14, D0 ; display string
TRAP #15
LEA XPY, A1
MOVE.B #14, D0 ; display string
TRAP #15
ADD Y, D3 ; X = X+Y
MOVE D3, D1
MOVE.B #3, D0 ; Display decimal signed D1.L in smallest field
TRAP #15
BRA FIN ; not needed
FIN MOVE.B #9,D0 ; terminate program
TRAP #15
* Variables and Strings
PROMPT DC.B ';Enter X: ';, 0
STTY DC.B ';Y = 4';, CR, LF, 0
XGT DC.B 'X > 12';, CR, LF, 0
XLT DC.B 'X != 12';, CR, LF, 0
TWOXP4 DC.B 2 * X + 4 = ';, CR, LF, 0
XPY DC.B 'X + Y = ';, 0
Y DC.W 4
CR EQU $0D
LF EQU $0A
END START

Tips:
Use MOVEQ to load a small number into a 32 bit register
Don't use MULU to multiply by 2
Use the .B, .W and .L instructions as default normally just 16 bits
ORG $1000
START: LEA PROMPT, A1
MOVEQ #14, D0 ; display string
TRAP #15
MOVEQ #4, D0 ; read number from keyboard
TRAP #15
MOVE.L D1,D3 ; save X
LEA STTY, A1
MOVEQ #14, D0 ; display string
TRAP #15
CMP.L #12, D3 ; X > 12 ?
BGT MULTADD ; branch if yes
ADDY LEA XLT, A1
MOVEQ #14, D0 ; display string
TRAP #15
LEA XPY, A1
MOVEQ #14, D0 ; display string
TRAP #15
ADD.L Y, D3 ; X = X+Y, change to SUB.L Y,D3
MOVE.L D3, D1
MOVEQ #3, D0 ; Display decimal signed D1.L in smallest field
TRAP #15
BRA FIN ; not needed
MULTADD
LEA XGT, A1
MOVEQ #14, D0 ; display string
TRAP #15
LEA TWOXP4, A1
MOVEQ #14, D0 ; display string
TRAP #15
ASL.L #1, D3 ; 2*X by shifting
ADDQ.L #4, D3 ; +4
MOVE.L D3, D1 ; copy to D1
MOVEQ #3, D0 ; Display decimal signed D1.L in smallest field
TRAP #15
FIN MOVEQ #9,D0 ; terminate program
TRAP #15
* Variables and Strings
CR EQU $0D
LF EQU $0A
PROMPT DC.B ';Enter X: ';, 0
STTY DC.B ';Y = 4';, CR, LF, 0
XGT DC.B 'X > 12';, CR, LF, 0
XLT DC.B 'X != 12';, CR, LF, 0
TWOXP4 DC.B 2 * X + 4 = ';, CR, LF, 0
XPY DC.B 'X + Y = ';, 0
Y DC.L 13
END START

Can't test it, but try to replace the
ADD Y, D3
With
SUB Y, D3

Related

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

How can I write a simple LC-3 program

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

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.

Having trouble finding error in my assembly code

I am a beginner when it comes to assembly language. I am using "easy 68k editor/assembler" to write 68k assembly code that asks the user for 2 values, then sum them up together and display it. The problem is that my code keeps getting halted and I am not sure how to troubleshoot/debug this problem.
Can anyone help me figure out how to track down the error? I will be grateful. Thank you in advance.
*-----------------------------------------------------------
* Program : Sum of Two Numbers
* Written by : Me
* Date : July 15, 2012
* Description: This program will read in 2 numbers the user
*inputs and find the sum.
*-----------------------------------------------------------
org $8000
START movea.l #MSG1, A3
trap #3
clr.w D2
JSR Loop
trap #2
move.w d2, d4
movea.l #msg2, a3
trap #3
clr.w d2
jsr loop
trap #2
movea.l #msg3, A3
trap #3
add.w d4, d2
JSR DISP
trap #2
trap #9
LOOP trap #0
trap #1
cmp.b #$0D, D1
BEQ BREAK
and.b #$0F, d1
mulu #10, d2
add.w d1, d2
jmp loop
Break rts
DISP clr.b d3
DISDIV divu #10, D2
move.b #16, d5
ror.l d5, d2
or.b #$30, d2
move.b d2, -(A7)
addq #1, d3
clr.w d2
ror.l d5, d2
bne DISDIV
DISDIG move.b (a7)+, D1
trap #1
subq.b #1, D3
bne DISDIG
rts
org $8100
MSG1 DC.B 'Please enter the first of two numbers (two digits) ', 0
MSG2 DC.B 'Please enter the second of two numbers (two digits) ', 0
MSG3 DC.B 'The sum of the two 2 digit numbers you entered is ', 0
end start
Your code should start with:
LEA MSG1, A1
MOVE.B #14, D0
TRAP #15
This will display the first message to the user. Check out the EASy68K home page for more information on invoking I/O traps.
Most likely the traps you are using are not those used by Easy68K. Look here for the traps used by Easy68K.
The function of the trap instructions is not defined by the 68K assembly language, but rather assigned by the operation system (if the OS makes use of the traps at all, some just ignore them). If you execute a trap instruction the 68000 just executes the code the trap vector points to. There is no "buildin" function assigned to any trap.

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