Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

I have the following LC3 Calculator. I need it to be able to use division as wel

ID: 3773053 • Letter: I

Question

I have the following LC3 Calculator. I need it to be able to use division as well, and show the remainder in the result.

.ORIG   x3000
;
; The Calculator, Main Algorithm
;
LEA R6,StackBase ; Initialize the Stack.
ADD R6,R6,#-1 ; R6 is stack pointer
LEA R0,PromptMsg
PUTS
GETC
OUT
;
; Check the command
;
Test LD R1,NegX ; Check for X entered   
ADD R1,R1,R0
BRz Exit
;
LD R1,NegC ; Check for C entered
ADD R1,R1,R0
BRz OpClear ; See Figure 10.27 page 283
;
LD R1,NegPlus ; Check for + entered
ADD R1,R1,R0
BRz OpAdd ; See Figure 10.9 page 267
;
LD R1,NegMult ; Check for *   
ADD R1,R1,R0
BRz OpMult ; See Figure 10.14 page 271
;
LD R1,NegMinus ; Check for - entered
ADD R1,R1,R0
BRz OpNeg ; See Figure 10.15 page 272
;
LD R1,NegD ; Check for D entered
ADD R1,R1,R0
BRz OpDisplay ;
;
; Then we must be entering an integer
;
BRnzp PushValue ; See Figure 10.25 page 282
;
NewCommand LEA R0,PromptMsg
PUTS
GETC
OUT
BRnzp Test
Exit HALT
PromptMsg .FILL x000A
.STRINGZ "Enter a command:"
NegX .FILL xFFA8
NegC .FILL xFFBD
NegPlus .FILL xFFD5
NegMinus .FILL xFFD3
NegMult .FILL xFFD6
NegD .FILL xFFBC

; This algorithm takes a sequence of ASCII digits typed by the user,
; converts it into a binary value by calling the ASCIItoBinary
; subroutine and pushes the binary value onto the stack.
;
PushValue LEA R1,ASCIIBUFF ; R1 points to string being
LD R2,MaxDigits ; generated
;
ValueLoop ADD R3,R0,xFFF6 ; Test for carriage return
BRz GoodInput
ADD R2,R2,#0
BRz TooLargeInput
ADD R2,R2,#-1 ; Still room for more digits
STR R0,R1,#0 ; Store last character read
ADD R1,R1,#1   
GETC
OUT ; Echo it
BRnzp ValueLoop
;
GoodInput LEA R2,ASCIIBUFF
NOT R2,R2
ADD R2,R2,#1
ADD R1,R1,R2 ; R1 now contains no. of char.
JSR ASCIItoBinary
JSR PUSH
BRnzp NewCommand
;
TooLargeInput GETC ; Spin until carriage return
OUT
ADD R3,R0,xFFF6
BRnp TooLargeInput
LEA R0,TooManyDigits
PUTS
BRnzp NewCommand
TooManyDigits .FILL x000A
.STRINGZ "Too many digits"
MaxDigits .FILL x0003

;
; This routine clears the stack by resetting the stack pointer (R6).
;
OpClear LEA R6,StackBase ; Initialize the Stack.
ADD R6,R6,#1 ; R6 is stack pointer
BRnzp NewCommand
;
; Routine to pop the top two elements from the stack,
; add them, and push the sum onto the stack. R6 is
; the stack pointer.
;

OpAdd JSR POP ; Get first source operand.
ADD R5,R5,#0 ; Test if POP was successful.
BRp ExitOA ; Branch if not successful.
ADD R1,R0,#0 ; Make room for second operand
JSR POP ; Get second source operand.
ADD R5,R5,#0 ; Test if POP was successful.
BRp Restore1 ; Not successful, put back first.
ADD R0,R0,R1 ; THE Add.
JSR RangeCheck ; Check size of result.
BRp Restore2 ; Out of range, restore both.
JSR PUSH ; Push sum on the stack.
BRnzp NewCommand ; On to the next task...
Restore2 ADD R6,R6,#-1 ; Decrement stack pointer.
Restore1 ADD R6,R6,#-1 ; Decrement stack pointer.
ExitOA BRnzp NewCommand
;   
; Algorithm to pop two values from the stack, multiply them
; and if their product is within the acceptable range, push
; the result on the stack. R6 is stack pointer.
;
OpMult AND R3,R3,#0 ; R3 holds sign of multiplier.
JSR POP ; Get first source from stack.
ADD R5,R5,#0 ; Test for successful POP
BRp ExitOM ; Failure
ADD R1,R0,#0 ; Make room for next POP
JSR POP ; Get second source operand
ADD R5,R5,#0 ; Test for successful POP
BRp Restore1OM ; Failure; restore first POP
ADD R2,R0,#0 ; Moves multiplier, tests sign
BRzp PosMultiplier
ADD R3,R3,#1 ; Sets FLAG: Multiplier is neg
NOT R2,R2
ADD R2,R2,#1 ; R2 contains -(multiplier)
PosMultiplier AND R0,R0,#0 ; Clear product register
ADD R2,R2,#0
BRz PushMult ; Multiplier = 0, Done.
;
MultLoop ADD R0,R0,R1 ; THE actual "multiply"
ADD R2,R2,#-1 ; Iteration Control
BRp MultLoop
;
JSR RangeCheck
ADD R5,R5,#0 ; R5 contains success/failure
BRp Restore2OM
;
ADD R3,R3,#0 ; Test for negative multiplier
BRz PushMult
NOT R0,R0 ; Adjust for
ADD R0,R0,#1 ; sign of result
PushMult JSR PUSH ; Push product on the stack.
BRnzp NewCommand
Restore2OM ADD R6,R6,#-1 ; Adjust stack pointer.
Restore1OM ADD R6,R6,#-1 ; Adjust stack pointer.
ExitOM BRnzp NewCommand   

; Algorithm to pop the top of the stack, form its negative,
; and push the result on the stack.
;
OpNeg JSR POP ; Get the source operand
ADD R5,R5,#0 ; test for successful pop
BRp ExitON ; Branch if failure
NOT R0,R0
ADD R0,R0,#1 ; Form the negative of the source.
JSR PUSH ; Push the result on the stack.
ExitON BRnzp NewCommand
;
; Routine to check that the magnitude of a value is
; between -999 and +999.
;
RangeCheck LD R5,Neg999
ADD R4,R0,R5 ; Recall that R0 contains the
BRp BadRange ; result being checked.
LD R5,Pos999
ADD R4,R0,R5
BRn BadRange
AND R5,R5,#0 ; R5 <-- success
RET
BadRange ST R7,Save ; R7 is needed by TRAP/RET
LEA R0,RangeErrorMsg
TRAP x22 ; Output character string
LD R7,Save
AND R5,R5,#0 ;
ADD R5,R5,#1 ; R5 <-- failure
RET
Neg999 .FILL #-999
Pos999 .FILL #999
Save .FILL x0000
RangeErrorMsg .FILL x000A
.STRINGZ "Error: Number is out of range."
;
; This algorithm calls BinarytoASCII to convert the 2's complement
; number on the top of the stack into an ASCII character string, and
; then calls PUTS to display that number on the screen.
OpDisplay JSR POP ; R0 gets the value to be displayed
ADD R5,R5,#0
BRp NewCommand ; POP failed, nothing on the stack.
JSR BinarytoASCII
LD R0,NewlineChar
OUT
LEA R0,ASCIIBUFF
PUTS
ADD R6,R6,#-1 ; Push displayed number back on stack
BRnzp NewCommand
NewlineChar .FILL x000A

ASCIIBUFF .BLKW 4
BUFFEREND .FILL x0000   ; needed to force x0000 at end of ASCIIBUFF

;
; This algorithm POPs a value from the stack and puts it in
; R0 before returning to the calling program. R5 is used to
; report success (R5=0) or failure (R5=1) of the POP operation.
POP LEA R0,StackBase
NOT R0,R0
ADD R0,R0,#2 ; R0 = -(addr.ofStackBase -1)
ADD R0,R0,R6 ; R6 = StackPointer
BRz Underflow
LDR R0,R6,#0 ; The actual POP
ADD R6,R6,#1 ; Adjust StackPointer
AND R5,R5,#0 ; R5 <-- success
RET
Underflow ST R7,SaveR7 ; TRAP/RET needs R7
LEA R0,UnderflowMsg
PUTS ; Print error message.
LD R7,SaveR7 ; Restore R7
AND R5,R5,#0
ADD R5,R5,#1 ; R5 <-- failure
RET
SaveR7 .FILL x0000
StackMax .BLKW 9
StackBase .FILL x0000
UnderflowMsg .FILL x000A
.STRINGZ "Error: Too Few Values on the Stack."

; This algorithm PUSHes on the stack the value stored in R0.
; R5 is used to report success (R5=0) or failure (R5=1) of
; the PUSH operation.
;
PUSH ST R1,Save1 ; R1 is needed by this routine
LEA R1,StackMax
NOT R1,R1
ADD R1,R1,#1 ; R1 = - addr. of StackMax
ADD R1,R1,R6 ; R6 = StackPointer
BRz Overflow
ADD R6,R6,#-1 ; Adjust StackPointer for PUSH
STR R0,R6,#0 ; The actual PUSH
BRnzp Success_exit
Overflow ST R7,Save7PUSH
LEA R0,OverflowMsg
PUTS
LD R7,Save7PUSH
LD R1, Save1 ; Restore R1
AND R5,R5,#0
ADD R5,R5,#1 ; R5 <-- failure
RET
Success_exit LD R1,Save1 ; Restore R1
AND R5,R5,#0 ; R5 <-- success
RET
Save7PUSH .FILL x0000
Save1 .FILL x0000
OverflowMsg .STRINGZ "Error: Stack is Full."

;
; This algorithm takes an ASCII string of three decimal digits and
; converts it into a binary number. R0 is used to collect the result.
; R1 keeps track of how many digits are left to process. ASCIIBUFF
; contains the most significant digit in the ASCII string.
;
ASCIItoBinary AND R0,R0,#0 ; R0 will be used for our result
ADD R1,R1,#0 ; Test number of digits.
BRz DoneAtoB ; There are no digits
;
LD R3,NegASCIIOffset ; R3 gets xFFD0, i.e., -x0030
LEA R2,ASCIIBUFF
ADD R2,R2,R1
ADD R2,R2,#-1 ; R2 now points to "ones" digit
;
LDR R4,R2,#0 ; R4 <-- "ones" digit
ADD R4,R4,R3 ; Strip off the ASCII template
ADD R0,R0,R4 ; Add ones contribution
;
ADD R1,R1,#-1
BRz DoneAtoB ; The original number had one digit
ADD R2,R2,#-1 ; R2 now points to "tens" digit
;
LDR R4,R2,#0 ; R4 <-- "tens" digit
ADD R4,R4,R3 ; Strip off ASCII template
LEA R5,LookUp10 ; LookUp10 is BASE of tens values
ADD R5,R5,R4 ; R5 points to the right tens value
LDR R4,R5,#0
ADD R0,R0,R4 ; Add tens contribution to total
;
ADD R1,R1,#-1
BRz DoneAtoB ; The original number had two digits
ADD R2,R2,#-1 ; R2 now points to "hundreds" digit
;
LDR R4,R2,#0 ; R4 <-- "hundreds" digit
ADD R4,R4,R3 ; Strip off ASCII template
LEA R5,LookUp100 ; LookUp100 is hundreds BASE
ADD R5,R5,R4 ; R5 points to hundreds value
LDR R4,R5,#0
ADD R0,R0,R4 ; Add hundreds contribution to total
;   
DoneAtoB RET
NegASCIIOffset .FILL xFFD0

LookUp10 .FILL #0
.FILL #10
.FILL #20
.FILL #30
.FILL #40
.FILL #50
.FILL #60
.FILL #70
.FILL #80
.FILL #90
;
LookUp100 .FILL #0
.FILL #100
.FILL #200
.FILL #300
.FILL #400
.FILL #500
.FILL #600
.FILL #700
.FILL #800
.FILL #900
;
; This algorithm takes the 2's complement representation of a signed
; integer, within the range -999 to +999, and converts it into an ASCII
; string consisting of a sign digit, followed by three decimal digits.
; R0 contains the initial value being converted.
;
BinarytoASCII LEA R1,ASCIIBUFF ; R1 points to string being generated
ADD R0,R0,#0 ; R0 contains the binary value
BRn NegSign ;
LD R2,ASCIIplus ; First store the ASCII plus sign
STR R2,R1,#0
BRnzp Begin100
NegSign LD R2,ASCIIminus ; First store ASCII minus sign
STR R2,R1,#0
NOT R0,R0 ; Convert the number to absolute
ADD R0,R0,#1 ; value; it is easier to work with.
;
Begin100 LD R2,ASCIIoffset ; Prepare for "hundreds" digit
;
LD R3,Neg100 ; Determine the hundreds digit
Loop100 ADD R0,R0,R3
BRn End100
ADD R2,R2,#1
BRnzp Loop100
;
End100 STR R2,R1,#1 ; Store ASCII code for hundreds digit
LD R3,Pos100
ADD R0,R0,R3 ; Correct R0 for one-too-many subtracts
;
LD R2,ASCIIoffset ; Prepare for "tens" digit
;
Begin10 LD R3,Neg10 ; Determine the tens digit
Loop10 ADD R0,R0,R3
BRn End10
ADD R2,R2,#1
BRnzp Loop10
;
End10 STR R2,R1,#2 ; Store ASCII code for tens digit
ADD R0,R0,#10 ; Correct R0 for one-too-many subtracts
Begin1 LD R2,ASCIIoffset ; Prepare for "ones" digit
ADD R2,R2,R0
STR R2,R1,#3
RET
;
ASCIIplus .FILL x002B
ASCIIminus .FILL x002D
ASCIIoffset .FILL x0030
Neg100 .FILL xFF9C
Pos100 .FILL x0064
Neg10 .FILL xFFF6

.END   ; end of assembly listing

Explanation / Answer


.ORIG x3000
; initialize stack:
LD R6, STACKBASE
BRnzp GET_INPUT

; get user input routine:
GET_INPUT:
;ADD R3, R7, #0 ; save current return address (in R3)
LEA R0, USER_PROMPT ; show prompt
PUTS
; initialize the R4 register, which is where we're going
; to keep the number of digits entered
AND R4, R4, #0
INPUT: ; loop to here while getting numbers
GETC

BRnzp CHECK_SPECIAL

CONT_INPUT:
; check if we have more than 5 digits
ADD R3, R0, #0 ; save current input char - need R0 for subtract
ADD R1, R4, #0
LD R0, MAX_DIGITS
JSR SUBTRACT
BRnz INPUT ; if we reached max digits (5) already, go back to input, wait for "enter"
ADD R4, R4, #1
; check if it's a number:
; first, >="0"
ADD R0, R3, #0 ; copy char back to register R0
LD R1, ASCII_0 ; copy 48 (ascii "0") to R1
JSR SUBTRACT
; check if it's negative (i.e., <0)
BRn NOT_NUM
; second, <="9"
ADD R1, R0, #0 ; copy char to register R1
LD R0, ASCII_9 ; copy 48 (ascii "0") to R0
JSR SUBTRACT
; check if it's negative (i.e., >9)
BRn NOT_NUM
ADD R0, R3, #0 ; copy char back to register R0
OUT ; display the typed char
; add to stack:
JSR PUSH

BRnzp INPUT

USER_PROMPT .stringz "ENTER NUMBER/OPERATOR: "
ASCII_INVERSE_OFFSET .fill #-48
ASCII_9 .fill #57
ZERO .fill #0
MAX_DIGITS .fill #5
ASCII_R .fill #82
ASCII_C .fill #67
ASCII_P .fill #80
PC_RET .fill x2fff

CHECK_SPECIAL:
; check for special cases: return, backspace
LD R1, ASCII_CR
JSR SUBTRACT
BRz ENTER_PRESSED
LD R1, ASCII_BS
JSR SUBTRACT
BRz BS_PRESSED
BRnzp CONT_INPUT

; non-numeric input; check for operators/special char's
NOT_NUM:
;LEA R0, USER_PROMPT_NN
;PUTS
; need to copy from R3, since the check against 9 will mess up "letter" characters
ADD R0, R3, #0 ; copy char back to register R0

; plus?
LD R1, ASCII_PLUS
JSR SUBTRACT
BRz PLUS_OP

; minus?
LD R1, ASCII_MINUS
JSR SUBTRACT
BRz MINUS_OP

; multiply?
LD R1, ASCII_STAR
JSR SUBTRACT
BRz MULT_OP

; divide?
LD R1, ASCII_SLASH
JSR SUBTRACT
BRz DIVIDE_OP

; root?
LD R1, ASCII_R
JSR SUBTRACT
BRz ROOT_OP

; prime?
LD R1, ASCII_P
JSR SUBTRACT
BRz PRIME_OP

BRnzp INPUT

; user pressed "enter" - use current number
ENTER_PRESSED:
;LEA R0, USER_PROMPT_CR
;PUTS
OUT
; did user enter a number?
AND R4, R4, xFFFF
BRz GET_INPUT:
; calculate the number entered:
AND R3, R3, #0 ; initialize value to zero
AND R2, R2, #0 ; initialize multiplier to zero
ADD R2, R2, #1 ; and adjust to the value 1
LOOP_GETNUM:
JSR POP ; get last entered digit (in R0)
LD R1, ASCII_INVERSE_OFFSET ; subtract the ASCII offset
ADD R0, R0, R1 ; remove ASCII offset
; multiply by correct value depending on place:
ADD R1, R2, #0 ; multiplier
JSR MULTIPLY ; R5 now contains the multiplied/adjusted value
ADD R3, R3, R5 ; add result to R3
; adjust multiplier one ten's place to the left (by multiplying by 10)
AND R1, R1, #0
ADD R1, R1, #10
ADD R0, R2, #0
JSR MULTIPLY ; R5 has new multiplier
ADD R2, R5, #0
; decrement counter & continue loop if more digits
ADD R4, R4, #-1
BRp LOOP_GETNUM
ADD R0, R3, #0
JSR PUSH ; add value to stack
BRnzp EXIT_INPUT

; user pressed "backspace"
BS_PRESSED:
; NOTE: backspace is NOT working, just ignore for now...
BRnzp INPUT

;LEA R0, USER_PROMPT_BS
;PUTS
; if we don't have any current character(s), just go back to the input...
;not-implemented;ADD R2, R4, #0
;not-implemented;BRnz INPUT
; pop the last char and update the char count
;not-implemented;OUT ; "display" the backspace to remove the last typed character
;not-implemented;ADD R4, R4, #-1
;not-implemented;JSR POP
;not-implemented;BRnzp INPUT

; note: the following is just for an intermediate step to overcome the
; 9-bit PC jump limitation
INTERMEDIATE_GET_INPUT:
BRnzp GET_INPUT

; handle a "plus" operation:
PLUS_OP:
JSR POP ; get last entered value
ADD R2, R0, #0 ; copy to R1 register
JSR POP ; get previous entered value
ADD R1, R0, #0 ; copy to R2 register
ADD R0, R1, R2 ; perform "add" operation
JSR PUSH ; store result
; now: store the operands (reg's will be used during display)
ADD R0, R2, #0
JSR PUSH
ADD R0, R1, #0
; display the first operand, operation, second operand, "=", and result
JSR DISPLAY_R0
LD R0, ASCII_SPACE
OUT
LD R0, ASCII_PLUS
OUT
LD R0, ASCII_SPACE
OUT
JSR POP
JSR DISPLAY_R0
LD R0, ASCII_SPACE
OUT
LD R0, ASCII_EQUALS
OUT
LD R0, ASCII_SPACE
OUT
JSR POP
JSR PUSH
JSR DISPLAY_R0
LD R0, ASCII_CR
OUT
BRnzp EXIT_INPUT

MINUS_OP:
JSR POP ; get last entered value
ADD R1, R0, #0 ; copy to R1 register
ADD R4, R0, #0 ; save copy to R4 register
JSR POP ; get previous entered value
ADD R3, R0, #0 ; save copy to R3 register
JSR SUBTRACT ; perform "subtract" operation
ADD R0, R5, #0 ; put result in R0 register (for push)
JSR PUSH ; store result
; now: store the operands (reg's will be used during display)
ADD R0, R4, #0
JSR PUSH
ADD R0, R3, #0
; display the first operand, operation, second operand, "=", and result
JSR DISPLAY_R0
LD R0, ASCII_SPACE
OUT
LD R0, ASCII_MINUS
OUT
LD R0, ASCII_SPACE
OUT
JSR POP
JSR DISPLAY_R0
LD R0, ASCII_SPACE
OUT
LD R0, ASCII_EQUALS
OUT
LD R0, ASCII_SPACE
OUT
JSR POP
JSR PUSH
JSR DISPLAY_R0
LD R0, ASCII_CR
OUT
BRnzp EXIT_INPUT

STACKBASE .FILL x2F00

MULT_OP:
JSR POP ; get last entered value
ADD R1, R0, #0 ; copy to R1 register
ADD R4, R0, #0 ; save copy to R4 register
JSR POP ; get previous entered value
ADD R3, R0, #0 ; save copy to R3 register
JSR MULTIPLY ; perform "multiply" operation
ADD R0, R5, #0 ; put result in R0 register (for push)
JSR PUSH ; store result
; now: store the operands (reg's will be used during display)
ADD R0, R4, #0
JSR PUSH
ADD R0, R3, #0
; display the first operand, operation, second operand, "=", and result
JSR DISPLAY_R0
LD R0, ASCII_SPACE
OUT
LD R0, ASCII_STAR
OUT
LD R0, ASCII_SPACE
OUT
JSR POP
JSR DISPLAY_R0
LD R0, ASCII_SPACE
OUT
LD R0, ASCII_EQUALS
OUT
LD R0, ASCII_SPACE
OUT
JSR POP
JSR PUSH
JSR DISPLAY_R0
LD R0, ASCII_CR
OUT
BRnzp EXIT_INPUT

DIVIDE_OP:
JSR POP ; get last entered value
ADD R1, R0, #0 ; copy to R1 register
ADD R4, R0, #0 ; save copy to R4 register
JSR POP ; get previous entered value
JSR PUSH ; restore it
ADD R3, R0, #0 ; save copy to R3 register
ADD R0, R4, #0 ; store this one, too
JSR PUSH
ADD R0, R3, #0
JSR DIVIDE ; perform "DIVIDE" operation
ADD R2, R5, #0 ; R5 used by PUSH and POP, so we need to copy it
JSR POP ; get for R4
ADD R4, R0, #0
JSR POP ; get for R3
ADD R3, R0, #0
ADD R0, R2, #0 ; put result in R0 register (for push)
JSR PUSH ; store result
; now: store the operands (reg's will be used during display)
ADD R0, R4, #0
JSR PUSH
ADD R0, R3, #0
; display the first operand, operation, second operand, "=", and result
JSR DISPLAY_R0
LD R0, ASCII_SPACE
OUT
LD R0, ASCII_SLASH
OUT
LD R0, ASCII_SPACE
OUT
JSR POP
JSR DISPLAY_R0
LD R0, ASCII_SPACE
OUT
LD R0, ASCII_EQUALS
OUT
LD R0, ASCII_SPACE
OUT
JSR POP
JSR PUSH
JSR DISPLAY_R0
LD R0, ASCII_CR
OUT
BRnzp EXIT_INPUT

ASCII_0 .fill #48
ASCII_BS .fill #8

ROOT_OP:
JSR POP ; get last value
ADD R2, R0, #0 ; save copy (divide messes with it)
AND R1, R1, #0 ; clear R1
RLOOP:
ADD R0, R2, #0 ; restore copy (messed up after first iteration)
ADD R1, R1, #1 ; increment
JSR DIVIDE ; divide
; negate the result
NOT R5, R5
ADD R5, R5, #1
; and see if it's the same as the divisor
ADD R3, R1, R5
BRn RLOOP
; at this point, R1 has the nearest SQRT answer, so store & display it
ADD R0, R1, #0
JSR PUSH
LEA R0, SQRT_TEXT
SQRT_TEXT .stringz "Square Root of "
PUTS
ADD R0, R2, #0; operand
JSR DISPLAY_R0
LD R0, ASCII_SPACE
OUT
LD R0, ASCII_EQUALS
OUT
LD R0, ASCII_SPACE
OUT
JSR POP
JSR PUSH
JSR DISPLAY_R0
LD R0, ASCII_CR
OUT
BRnzp EXIT_INPUT

ASCII_CR .fill #10

ASCII_EQUALS .fill #61
ASCII_SPACE .fill #32
ASCII_PLUS .fill #43
ASCII_MINUS .fill #45
ASCII_STAR .fill #42
ASCII_SLASH .fill #47

PRIME_OP:
JSR POP ; get last operand (to R0)
JSR PUSH ; re-store last operand
ADD R2, R0, #0 ; save
AND R0, R0, #0
ADD R0, R0, #1
JSR PUSH ; save "1" as fake prime
ADD R0, R2, #0 ; restore operand
AND R1, R1, #0
ADD R1, R1, #2
DIV_PRIME:
ADD R2, R0, #0 ; save copy
JSR DIVIDE
ADD R3, R0, #0 ; test for remainder
BRz GOOD_PRIME
BRnzp NEXT_DIV
GOOD_PRIME:
ADD R3, R5, #0 ; save current val
JSR POP ; fetch (discard) current prime candidate
ADD R0, R1, #0 ; move cur candidate to R0
JSR PUSH ; save current divisor as candidate
ADD R0, R3, #0 ; restore current val
BRnzp DIV_PRIME ; even division, go do it again
NEXT_DIV:
; increment divisor; by 1 if 2, by 2 otherwise
ADD R0, R1, #0
AND R1, R1, #0
ADD R1, R1, #2
JSR SUBTRACT
BRz P_IS_TWO
ADD R1, R0, #2 ; increment by two
BRnzp P_CONT
P_IS_TWO:
ADD R1, R0, #1 ; increment by one
P_CONT:
ADD R0, R2, #0 ; restore previous value
; check whether we've hit the original number
ADD R3, R0, #0 ; save cur val
ADD R4, R1, #0 ; save cur candidate
JSR POP ; prime candidate
ADD R2, R0, #0 ; save
JSR POP ; original number (to R0)
JSR PUSH ; re-save it
JSR SUBTRACT
BRn FOUND_PRIME
ADD R0, R2, #0
JSR PUSH ; re-save prime candidate
ADD R0, R3, #0 ; restore cur val
ADD R1, R4, #0 ; restore cur candidate
BRnzp DIV_PRIME
EXIT_INPUT:
;ADD R7, R3, #0 ; restore current return address (from R3)
BRnzp INTERMEDIATE_GET_INPUT ; need intermediate step because of 9-bit limitation on PC jump

; display a value as a string
DISPLAY_R0:
ADD R2, R7, #0 ; save return PC (we're going to JSR in here)
; check for NEGATIVE result:
ADD R0, R0, #0
BRn SHOW_NEG
BRnzp SHOW_NUM
SHOW_NEG:
; display a minus sign, then negate the number (to show "pos" value after the "-")
JSR PUSH
LD R0, ASCII_MINUS
OUT
JSR POP
NOT R0, R0
ADD R0, R0, #1
SHOW_NUM:
LD R1, BY_10000
JSR DIVIDE ; divide by 10000 to get an answer
ADD R4, R5, #0
JSR PUSH
ADD R5, R4, #0
LD R1, ASCII_0
ADD R0, R5, R1
OUT
ADD R4, R5, #0
JSR POP
ADD R5, R4, #0
LD R1, BY_1000
JSR DIVIDE ; divide by 1000 to get an answer
ADD R4, R5, #0
JSR PUSH
ADD R5, R4, #0
LD R1, ASCII_0
ADD R0, R5, R1
OUT
ADD R4, R5, #0
JSR POP
ADD R5, R4, #0
LD R1, BY_100
JSR DIVIDE ; divide by 100 to get an answer
ADD R4, R5, #0
JSR PUSH
ADD R5, R4, #0
LD R1, ASCII_0
ADD R0, R5, R1
OUT
ADD R4, R5, #0
JSR POP
ADD R5, R4, #0
LD R1, BY_10
JSR DIVIDE ; divide by 10 to get an answer
ADD R4, R5, #0
JSR PUSH
ADD R5, R4, #0
LD R1, ASCII_0
ADD R0, R5, R1
OUT
ADD R4, R5, #0
JSR POP
ADD R5, R4, #0
LD R1, ASCII_0
ADD R0, R0, R1
OUT
; ADD R0, R5, ASCII_INVERSE_OFFSET
ADD R7, R2, #0 ; restore return PC
RET

; This algorithm POPs a value from the stack and puts it in
; R0 before returning to the calling program. R5 is used to
; report success (R5=0) or failure (R5=1) of the POP operation.
POP LEA R0,STACKBASE
NOT R0,R0
ADD R0,R0,#1 ; R0 = -addr.ofSTACKBASE
ADD R0,R0,R6 ; R6 = StackPointer
BRz Underflow
LDR R0,R6,#0 ; The actual POP
ADD R6,R6,#1 ; Adjust StackPointer
AND R5,R5,#0 ; R5 <-- success
RET
Underflow ST R7,Save ; TRAP/RET needs R7
LEA R0,UnderflowMsg
PUTS ; Print error message.
LD R7,Save ; Restore R7
AND R5,R5,#0
ADD R5,R5,#1 ; R5 <-- failure
RET
Save3 .FILL x0000
StackMax .BLKW 9
UnderflowMsg .FILL x000A
.STRINGZ "Error: Too Few Values on the Stack."
; This algorithm PUSHes on the stack the value stored in R0.
; R5 is used to report success (R5=0) or failure (R5=1) of
; the PUSH operation.
;
PUSH ST R1,Save1 ; R1 is needed by this routine
LEA R1,StackMax
NOT R1,R1
ADD R1,R1,#1 ; R1 = - addr. of StackMax
ADD R1,R1,R6 ; R6 = StackPointer
BRz Overflow
ADD R6,R6,#-1 ; Adjust StackPointer for PUSH
STR R0,R6,#0 ; The actual PUSH
BRnzp Success_exit
Overflow ST R7,Save
LEA R0,OverflowMsg
PUTS
LD R7,Save
LD R1, Save1 ; Restore R1
AND R5,R5,#0
ADD R5,R5,#1 ; R5 <-- failure
RET
Success_exit LD R1,Save1 ; Restore R1
AND R5,R5,#0 ; R5 <-- success
RET
Save2 .FILL x0000
Save1 .FILL x0000
Save .FILL x0000
OverflowMsg .STRINGZ "Error: Stack is Full."

FOUND_PRIME:
ADD R3, R0, #0
ADD R0, R2, #0
JSR PUSH
LEA R0, USER_MESSAGE_PRIME
PUTS
ADD R0, R3, #0
JSR DISPLAY_R0
LD R0, ASCII_SPACE
OUT
LD R0, ASCII_EQUALS
OUT
LD R0, ASCII_SPACE
OUT
JSR POP
JSR PUSH
JSR DISPLAY_R0
LD R0, ASCII_CR
OUT
BRnzp EXIT_INPUT

BY_10000 .fill #10000
BY_1000 .fill #1000
BY_100 .fill #100
BY_10 .fill #10

; division routine: R0 / R1 = R5
; note: R0 will have remainder
; note: division uses R0, R1, R3, R4, R5
DIVIDE:
AND R5, R5, #0 ; zero out the total
; let's do division on POSITIVE values; if only one is negative,
; we'll negate the result; finally, once we're done, assign the
; remainder its original sign; use R4 as bitmap for which are negated
AND R4, R4, #0
ADD R0, R0, #0 ; check numerator
BRp NUM_POS
NOT R0, R0
ADD R0, R0, #1
ADD R4, R4, #1 ; mark numerator as negative
NUM_POS:
ADD R1, R1, #0 ; check denominator
BRp DEN_POS
NOT R1, R1
ADD R1, R1, #1
ADD R4, R4, #2 ; mark denominator as negative
DEN_POS:
; finally, we need to negate the denominator for the subtractions
NOT R1, R1
ADD R1, R1, #1
DLOOP ADD R0, R0, R1
BRn EXIT_DIV ; when we get a negative value, we've finished
ADD R5, R5, #1 ; increment counter
BRnzp DLOOP
EXIT_DIV:
NOT R1, R1
ADD R1, R1, #1
ADD R0, R0, #0
BRz EVEN_DIV
ADD R0, R0, R1 ; add divisor to adjust R0 to remainder value
EVEN_DIV
; finally, apply the appropriate sign to the result & remainder
AND R3, R4, #1
BRz NUM_NOT_NEG
; need to negate the numerator
NOT R0, R0
ADD R0, R0, #1
NUM_NOT_NEG:
AND R3, R4, #2
BRz DEN_NOT_NEG
; need to negate the denominator
NOT R1, R1
ADD R1, R1, #1
DEN_NOT_NEG:
; finally, need to negate the result if signs of num & denom differ
AND R3, R4, #1
BRz NUM_NOT_NEG_FIN
; numerator is negative, negate result if denom is positive
AND R3, R4, #2
BRp EXIT_DIV_FIN
; denom pos, num neg, negate answer
NOT R5, R5
ADD R5, R5, #1
BRnzp EXIT_DIV_FIN

NUM_NOT_NEG_FIN
; numerator is positive, negate result if denom is negative
AND R3, R4, #2
BRz EXIT_DIV_FIN
; denom neg, num pos, negate answer
NOT R5, R5
ADD R5, R5, #1
BRnzp EXIT_DIV_FIN

EXIT_DIV_FIN:
RET

USER_MESSAGE_PRIME .stringz "Largest prime factor of "

; multiplication routine: R0 * R1 = R5
MULTIPLY:
AND R5, R5, #0 ; zero out the total
; loop R2 times, adding R1 each time
MLOOP ADD R5, R5, R0 ; adds to the ongoing sum
ADD R1, R1, #-1 ; decrements counter by 1
BRp MLOOP ; this will jump back to the LOOP label above until R1 is nonpositive
RET

; subtraction routine: R0 - R1 = R5
; NOTE: R1 will be NEGATED on return!
SUBTRACT:
; create the negative of R1
NOT R1, R1
ADD R1, R1, #1

; subtract - R5 now holds answer
ADD R5, R0, R1
RET

HALT

.END