Data Type Conversion

  • Binary to ASCII
  • ASCII to Binary

    Arithmetic Using a Stack

    Postfix Expression

    The 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
    image.png ``` .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

  1. LD R1, PUSH_STACK_MAX
  2. NOT R1, R1
  3. ADD R1, R1, #1
  4. ADD R1, R1, R6
  5. BRz OVERFLOW
  6. ADD R6, R6, #-1
  7. STR R0, R6, #0
  8. AND R5, R5, #0
  9. LD R1, PUSH_SAVE1
  10. RET

OVERFLOW LEA R0, OVERFLOW_MSG PUTS AND R5, R5, #0 ADD R5, R5, #1

  1. LD R1, PUSH_SAVE1
  2. RET

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

  1. LDR R0, R6, #0
  2. ADD R6, R6, #1
  3. AND R5, R5, #0
  4. RET

UNDERFLOW LEA R0, UNDERFLOW_MSG PUTS

  1. AND R5, R5, #0
  2. ADD R5, R5, #1
  3. RET

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

  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

  1. JSR POP
  2. ADD R5, R5, #0
  3. BRp OP_DISPAY_DONE
  4. JSR BINARY_TO_ASCII
  5. LD R0, NEWLINE_CHAR
  6. OUT
  7. LD R0, OP_DISPLAY_ASCIIBUFF
  8. PUTS
  9. ADD R6, R6, #-1

OP_DISPAY_DONE LD R0, OP_DISPLAY_SAVE0 LD R5, OP_DISPLAY_SAVE5 LD R7, OP_DISPLAY_SAVE7

  1. 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

  1. LD R1, PUSH_VALUE_ASCIIBUFF
  2. LD R2, MAX_DIGITS

VALUE_LOOP ADD R3, R0, x-0A ; Test for LF BRz INPUT_DONE

  1. ADD R2, R2, #0
  2. BRz DIGIT_OVERFLOW
  3. LD R3, NEG_ASCII_0
  4. ADD R3, R0, R3
  5. BRn NOT_INTEGER
  6. LD R3, NEG_ASCII_9
  7. ADD R3, R0, R3
  8. BRp NOT_INTEGER
  9. ADD R2, R2, #-1
  10. STR R0, R1, #0
  11. ADD R1, R1, #1
  12. GETC
  13. OUT
  14. BRnzp 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

  1. JSR ASCII_TO_BINARY
  2. JSR PUSH
  3. BRnzp 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

  1. LEA R0, NOT_INTEGER_MSG
  2. PUTS
  3. BRnzp PUSH_VALUE_DONE

DIGIT_OVERFLOW GETC OUT ADD R3, R0, x-0A BRnp DIGIT_OVERFLOW

  1. LEA R0, DIGIT_OVERFLOW_MSG
  2. PUTS
  3. BRnzp 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

  1. 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

  1. AND R0, R0, #0
  2. ADD R1, R1, #0 ; Test number of digit
  3. BRz ATOB_DONE ; No digit, i.e 0
  4. LD R2, ATOB_ASCIIBUFF ; R2 is the pointer
  5. ADD R2, R2, R1
  6. ADD R2, R2, #-1
  7. LDR R4, R2, #0 ; R4 <- "ones" digit
  8. AND R4, R4, x000F ; Strip off the ASCII template, i.e. R4 <- R4 - x0030
  9. ADD R0, R0, R4
  10. ADD R1, R1, #-1
  11. BRz ATOB_DONE ; If it is only one digit
  12. ADD R2, R2, #-1
  13. LDR R4, R2, #0 ; R4 <- "tens" digit
  14. AND R4, R4, x000F
  15. LEA R3, LOOK_UP_10
  16. ADD R3, R3, R4
  17. LDR R4, R3, #0
  18. ADD R0, R0, R4
  19. ADD R1, R1, #-1
  20. BRz ATOB_DONE ; If it is only two digits
  21. ADD R2, R2, #-1
  22. LDR R4, R2, #0 ; R4 <- "hundreds" digit
  23. AND R4, R4, x000F
  24. LEA R3, LOOK_UP_100
  25. ADD R3, R3, R4
  26. LDR R4, R3, #0
  27. ADD R0, R0, R4

ATOB_DONE LD R1, ATOB_SAVE1 LD R2, ATOB_SAVE2 LD R3, ATOB_SAVE3 LD R4, ATOB_SAVE4

  1. 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

  1. LD R1, BTOA_ASCIIBUFF
  2. ADD R0, R0, #0
  3. BRn NEG_SIGN
  4. LD R2, ASCII_POS ; Store the positive sign
  5. STR R2, R1, #0
  6. BRnzp 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

  1. LD R0, BTOA_SAVE0
  2. LD R1, BTOA_SAVE1
  3. LD R2, BTOA_SAVE2
  4. LD R3, BTOA_SAVE3
  5. RET

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

  1. RET

RANGE_OVERFLOW ST R0, RANGE_CHECK_SAVE0 LEA R0, RANGE_EROOR_MSG PUTS

  1. AND R5, R5, #0
  2. ADD R5, R5, #1
  3. LD R0, RANGE_CHECK_SAVE0
  4. RET

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

  1. JSR POP
  2. ADD R5, R5, #0
  3. BRp OP_ADD_EXIT
  4. ADD R1, R0, #0
  5. JSR POP
  6. ADD R5, R5, #0
  7. BRp OP_ADD_RESTORE1
  8. ADD R0, R0, R1 ; Addition routine
  9. JSR RANGE_CHECK
  10. ADD R5, R5, #0
  11. BRp OP_ADD_RESTORE2
  12. JSR PUSH
  13. BRnzp 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

  1. 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

  1. JSR POP
  2. ADD R5, R5, #0
  3. BRp OP_MINUS_EXIT
  4. ADD R0, R0, #1
  5. JSR PUSH
  6. JSR OP_ADD

OP_MINUS_EXIT LD R0, OP_MINUS_SAVE0 LD R5, OP_MINUS_SAVE5 LD R7, OP_MINUS_SAVE7

  1. 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

  1. AND R3, R3, #0 ; R3 holds sign of multiplier
  2. JSR POP
  3. ADD R5, R5, #0
  4. BRp OP_MUL_EXIT
  5. ADD R1, R0, #0
  6. JSR POP
  7. ADD R5, R5, #0
  8. BRp OP_MUL_RESTORE1
  9. ADD R2, R0, #0 ; Moves multiplier to test sign
  10. BRzp POS_MULTIPLIER
  11. ADD R3, R3, #1
  12. NOT R2, R2
  13. ADD 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

  1. JSR RANGE_CHECK
  2. ADD R5, R5, #0
  3. BRp OP_MUL_RESTORE2
  4. ADD R3, R3, #0 ; Test for negative multiplier
  5. BRz PUSH_MULT
  6. NOT R0, R0
  7. ADD 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

  1. 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 ```