Data Type Conversion
- Binary to ASCII
- ASCII to Binary
Arithmetic Using a Stack
Postfix ExpressionThe Calculator
It allows a user to enter positive integers consisting of not more than 3 decimal digits, perform basic arithmetic ( addition, subtraction and multiplication ) on these integers, and display the decimal result
```
.ORIG x3000
; Main Routine
LEA R6, STACK_BASE
ADD R6, R6, #1
NEW_COMMAND LEA R0, PROMPT_MSG PUTS GETC OUT
; Check the command
; X for exit TEST_X LD R1, NEG_X ADD R1, R1, R0 BRnp TEST_C HALT ; C for clearing the stack TEST_C LD R1, NEG_C ADD R1, R1, R0 BRnp TEST_ADD JSR OP_CLEAR BRnzp NEW_COMMAND ; + for addition TEST_ADD LD R1, NEG_PLUS ADD R1, R1, R0 BRnp TEST_MINUS JSR OP_ADD BRnzp NEW_COMMAND ; - for subtraction TEST_MINUS LD R1, NEG_MINUS ADD R1, R1, R0 Brnp TEST_MUL JSR OP_MINUS BRnzp NEW_COMMAND ; * for multiplication TEST_MUL LD R1, NEG_MUL ADD R1, R1, R0 BRnp TEST_D JSR OP_MUL BRnzp NEW_COMMAND ; D for Display the value at the top of the stack TEST_D LD R1, NEG_D ADD R1, R1, R0 BRnp ENTER_NUMBER JSR OP_DISPLAY BRnzp NEW_COMMAND ; Input a number, LF for end ENTER_NUMBER JSR PUSH_VALUE BRnzp NEW_COMMAND
PROMPT_MSG .FILL x000A .STRINGZ “Enter a command: “ NEG_X .FILL xFFA8 NEG_C .FILL xFFBD NEG_PLUS .FILL xFFD5 NEG_MINUS .FILL xFFD3 NEG_MUL .FILL xFFD6 NEG_D .FILL xFFBC
; Globals STACK_MAX .BLKW #9 STACK_BASE .BLKW #1 ASCIIBUFF .BLKW #4 .FILL x0000 ; ASCIIBUFF sentinel
; Stack Operations
; Push the value in R0 on the stack ; R5 is used to indicate success (R5 = 0) or failure (R5 = 1) PUSH ST R1, PUSH_SAVE1
LD R1, PUSH_STACK_MAXNOT R1, R1ADD R1, R1, #1ADD R1, R1, R6BRz OVERFLOWADD R6, R6, #-1STR R0, R6, #0AND R5, R5, #0LD R1, PUSH_SAVE1RET
OVERFLOW LEA R0, OVERFLOW_MSG PUTS AND R5, R5, #0 ADD R5, R5, #1
LD R1, PUSH_SAVE1RET
PUSH_SAVE1 .BLKW #1 OVERFLOW_MSG .FILL x000A .STRINGZ “Error: Stack is Full.” PUSH_STACK_MAX .FILL STACK_MAX
; Pop a value from the stack into R0 ; R5 is used to indicate success (R5 = 0) or failure (R5 = 1) POP LD R0, POP_STACK_BASE NOT R0, R0 ADD R0, R0, R6 BRz UNDERFLOW
LDR R0, R6, #0ADD R6, R6, #1AND R5, R5, #0RET
UNDERFLOW LEA R0, UNDERFLOW_MSG PUTS
AND R5, R5, #0ADD R5, R5, #1RET
UNDERFLOW_MSG .FILL x000A .STRINGZ “Error: Too Few Values on the Stack.” POP_STACK_BASE .FILL STACK_BASE
; Clear the stack by resetting the stack pointer R6 OP_CLEAR LD R6, OP_CLEAR_STACK_BASE ADD R6, R6, #1
RET
OP_CLEAR_STACK_BASE .FILL STACK_BASE
; Display the value on the screen OP_DISPLAY ST R0, OP_DISPLAY_SAVE0 ST R5, OP_DISPLAY_SAVE5 ST R7, OP_DISPLAY_SAVE7
JSR POPADD R5, R5, #0BRp OP_DISPAY_DONEJSR BINARY_TO_ASCIILD R0, NEWLINE_CHAROUTLD R0, OP_DISPLAY_ASCIIBUFFPUTSADD R6, R6, #-1
OP_DISPAY_DONE LD R0, OP_DISPLAY_SAVE0 LD R5, OP_DISPLAY_SAVE5 LD R7, OP_DISPLAY_SAVE7
RET
NEWLINE_CHAR .FILL x000A OP_DISPLAY_ASCIIBUFF .FILL ASCIIBUFF OP_DISPLAY_SAVE0 .BLKW #1 OP_DISPLAY_SAVE5 .BLKW #1 OP_DISPLAY_SAVE7 .BLKW #1
; Push the value into stack ; R0 is each input char ; R1 points to the string PUSH_VALUE ST R0, PUSH_VALUE_SAVE0 ST R1, PUSH_VALUE_SAVE1 ST R2, PUSH_VALUE_SAVE2 ST R7, PUSH_VALUE_SAVE7
LD R1, PUSH_VALUE_ASCIIBUFFLD R2, MAX_DIGITS
VALUE_LOOP ADD R3, R0, x-0A ; Test for LF BRz INPUT_DONE
ADD R2, R2, #0BRz DIGIT_OVERFLOWLD R3, NEG_ASCII_0ADD R3, R0, R3BRn NOT_INTEGERLD R3, NEG_ASCII_9ADD R3, R0, R3BRp NOT_INTEGERADD R2, R2, #-1STR R0, R1, #0ADD R1, R1, #1GETCOUTBRnzp VALUE_LOOP
INPUT_DONE LD R2, PUSH_VALUE_ASCIIBUFF ; Test whether no input NOT R2, R2 ADD R2, R2, #1 ADD R1, R1, R2 BRz NO_DIGIT
JSR ASCII_TO_BINARYJSR PUSHBRnzp PUSH_VALUE_DONE
NO_DIGIT LEA R0, NO_DIGIT_MSG PUTS BRnzp PUSH_VALUE_DONE
NOT_INTEGER GETC OUT ADD R3, R0, x-0A BRnp NOT_INTEGER
LEA R0, NOT_INTEGER_MSGPUTSBRnzp PUSH_VALUE_DONE
DIGIT_OVERFLOW GETC OUT ADD R3, R0, x-0A BRnp DIGIT_OVERFLOW
LEA R0, DIGIT_OVERFLOW_MSGPUTSBRnzp PUSH_VALUE_DONE
PUSH_VALUE_DONE LD R0, PUSH_VALUE_SAVE0 LD R1, PUSH_VALUE_SAVE1 LD R2, PUSH_VALUE_SAVE2 LD R7, PUSH_VALUE_SAVE7
RET
DIGIT_OVERFLOW_MSG .FILL x000A .STRINGZ “Too many digits” NO_DIGIT_MSG .FILL x000A .STRINGZ “No number entered” NOT_INTEGER_MSG .FILL x000A .STRINGZ “Not an integer”
MAX_DIGITS .FILL x0003 NEG_ASCII_0 .FILL x-30 NEG_ASCII_9 .FILL x-39 PUSH_VALUE_ASCIIBUFF .FILL ASCIIBUFF
PUSH_VALUE_SAVE0 .BLKW #1 PUSH_VALUE_SAVE1 .BLKW #1 PUSH_VALUE_SAVE2 .BLKW #1 PUSH_VALUE_SAVE7 .BLKW #1
; Convertion
; ASCII to Binary convertion ; R0 is used to collect the result. ; R1 keeps track of how many digits are left to process ASCII_TO_BINARY ST R1, ATOB_SAVE1 ST R2, ATOB_SAVE2 ST R3, ATOB_SAVE3 ST R4, ATOB_SAVE4
AND R0, R0, #0ADD R1, R1, #0 ; Test number of digitBRz ATOB_DONE ; No digit, i.e 0LD R2, ATOB_ASCIIBUFF ; R2 is the pointerADD R2, R2, R1ADD R2, R2, #-1LDR R4, R2, #0 ; R4 <- "ones" digitAND R4, R4, x000F ; Strip off the ASCII template, i.e. R4 <- R4 - x0030ADD R0, R0, R4ADD R1, R1, #-1BRz ATOB_DONE ; If it is only one digitADD R2, R2, #-1LDR R4, R2, #0 ; R4 <- "tens" digitAND R4, R4, x000FLEA R3, LOOK_UP_10ADD R3, R3, R4LDR R4, R3, #0ADD R0, R0, R4ADD R1, R1, #-1BRz ATOB_DONE ; If it is only two digitsADD R2, R2, #-1LDR R4, R2, #0 ; R4 <- "hundreds" digitAND R4, R4, x000FLEA R3, LOOK_UP_100ADD R3, R3, R4LDR R4, R3, #0ADD R0, R0, R4
ATOB_DONE LD R1, ATOB_SAVE1 LD R2, ATOB_SAVE2 LD R3, ATOB_SAVE3 LD R4, ATOB_SAVE4
RET
ATOB_ASCIIBUFF .FILL ASCIIBUFF ATOB_SAVE1 .BLKW #1 ATOB_SAVE2 .BLKW #1 ATOB_SAVE3 .BLKW #1 ATOB_SAVE4 .BLKW #1 LOOK_UP_10 .FILL #0 .FILL #10 .FILL #20 .FILL #30 .FILL #40 .FILL #50 .FILL #60 .FILL #70 .FILL #80 .FILL #90 LOOK_UP_100 .FILL #0 .FILL #100 .FILL #200 .FILL #300 .FILL #400 .FILL #500 .FILL #600 .FILL #700 .FILL #800 .FILL #900
; Binary to ASCII convertion ; R0 contains the binary value ; R1 keeps track of the output string BINARY_TO_ASCII ST R0, BTOA_SAVE0 ST R1, BTOA_SAVE1 ST R2, BTOA_SAVE2 ST R3, BTOA_SAVE3
LD R1, BTOA_ASCIIBUFFADD R0, R0, #0BRn NEG_SIGNLD R2, ASCII_POS ; Store the positive signSTR R2, R1, #0BRnzp SKIP
NEG_SIGN LD R2, ASCII_NEG ; Store the negtive sign STR R2, R1, #0 NOT R0, R0 ADD R0, R0, #1
; Process the “hundreds” digit SKIP LD R2, ASCII_OFFSET LD R3, NEG_100 ; Since 100 > 2^5, immediate mode can’t be used LOOP_100 ADD R0, R0, R3 BRn END_100 ADD R2, R2, #1 BRnzp LOOP_100
END_100 STR R2, R1, #1 LD R3, POS_100 ADD R0, R0, R3 ; R0 <- R0 + 100
; Process the “tens” digit LD R2, ASCII_OFFSET LOOP_10 ADD R0, R0, #-10 BRn END_10 ADD R2, R2, #1 BRnzp LOOP_10
END_10 STR R2, R1, #2 ADD R0, R0, #10
; Process the “ones” digit LD R2, ASCII_OFFSET ADD R2, R2, R0 STR R2, R1, #3
LD R0, BTOA_SAVE0LD R1, BTOA_SAVE1LD R2, BTOA_SAVE2LD R3, BTOA_SAVE3RET
ASCII_POS .FILL x002B ASCII_NEG .FILL x002D ASCII_OFFSET .FILL x0030 NEG_100 .FILL #-100 POS_100 .FILL #100 BTOA_ASCIIBUFF .FILL ASCIIBUFF BTOA_SAVE0 .BLKW #1 BTOA_SAVE1 .BLKW #1 BTOA_SAVE2 .BLKW #1 BTOA_SAVE3 .BLKW #1
; Check
RANGE_CHECK LD R5, NEG_999 ADD R5, R0, R5 BRp RANGE_OVERFLOW LD R5, POS_999 ADD R5, R0, R5 BRn RANGE_OVERFLOW AND R5, R5, #0
RET
RANGE_OVERFLOW ST R0, RANGE_CHECK_SAVE0 LEA R0, RANGE_EROOR_MSG PUTS
AND R5, R5, #0ADD R5, R5, #1LD R0, RANGE_CHECK_SAVE0RET
NEG_999 .FILL #-999 POS_999 .FILL #999 RANGE_EROOR_MSG .FILL x000A .STRINGZ “Error: Number is out of range.” RANGE_CHECK_SAVE0 .BLKW #1
; Arithmetic Operations
OP_ADD ST R0, OP_ADD_SAVE0 ST R5, OP_ADD_SAVE5 ST R7, OP_ADD_SAVE7
JSR POPADD R5, R5, #0BRp OP_ADD_EXITADD R1, R0, #0JSR POPADD R5, R5, #0BRp OP_ADD_RESTORE1ADD R0, R0, R1 ; Addition routineJSR RANGE_CHECKADD R5, R5, #0BRp OP_ADD_RESTORE2JSR PUSHBRnzp OP_ADD_EXIT
OP_ADD_RESTORE2 ADD R6, R6, #-1 OP_ADD_RESTORE1 ADD R6, R6, #-1 OP_ADD_EXIT LD R0, OP_ADD_SAVE0 LD R1, OP_ADD_SAVE1 LD R7, OP_ADD_SAVE7
RET
OP_ADD_SAVE0 .BLKW #1 OP_ADD_SAVE1 .BLKW #1 OP_ADD_SAVE5 .BLKW #1 OP_ADD_SAVE7 .BLKW #1
OP_MINUS ST R0, OP_MINUS_SAVE0 ST R5, OP_MINUS_SAVE5 ST R7, OP_MINUS_SAVE7
JSR POPADD R5, R5, #0BRp OP_MINUS_EXITADD R0, R0, #1JSR PUSHJSR OP_ADD
OP_MINUS_EXIT LD R0, OP_MINUS_SAVE0 LD R5, OP_MINUS_SAVE5 LD R7, OP_MINUS_SAVE7
RET
OP_MINUS_SAVE0 .BLKW #1 OP_MINUS_SAVE5 .BLKW #1 OP_MINUS_SAVE7 .BLKW #1
OP_MUL ST R0, OP_MUL_SAVE0 ST R1, OP_MUL_SAVE1 ST R2, OP_MUL_SAVE2 ST R3, OP_MUL_SAVE3 ST R5, OP_MUL_SAVE5 ST R7, OP_MUL_SAVE7
AND R3, R3, #0 ; R3 holds sign of multiplierJSR POPADD R5, R5, #0BRp OP_MUL_EXITADD R1, R0, #0JSR POPADD R5, R5, #0BRp OP_MUL_RESTORE1ADD R2, R0, #0 ; Moves multiplier to test signBRzp POS_MULTIPLIERADD R3, R3, #1NOT R2, R2ADD R2, R2, #1
POS_MULTIPLIER AND R0, R0, #0 ADD R2, R2, #0 BRz PUSH_MULT ; If multiplier = 0, then DONE
MUL_LOOP ADD R0, R0, R1 ; Multiply routine ADD R2, R2, #-1 BRp MUL_LOOP
JSR RANGE_CHECKADD R5, R5, #0BRp OP_MUL_RESTORE2ADD R3, R3, #0 ; Test for negative multiplierBRz PUSH_MULTNOT R0, R0ADD R0, R0, #1
PUSH_MULT JSR PUSH BRnzp OP_MUL_EXIT
OP_MUL_RESTORE2 ADD R6, R6, #-1
OP_MUL_RESTORE1 ADD R6, R6, #-1
OP_MUL_EXIT LD R0, OP_MUL_SAVE0
LD R1, OP_MUL_SAVE1
LD R3, OP_MUL_SAVE3
LD R5, OP_MUL_SAVE5
LD R7, OP_MUL_SAVE7
RET
OP_MUL_SAVE0 .BLKW #1 OP_MUL_SAVE1 .BLKW #1 OP_MUL_SAVE2 .BLKW #1 OP_MUL_SAVE3 .BLKW #1 OP_MUL_SAVE5 .BLKW #1 OP_MUL_SAVE7 .BLKW #1
.END ```
