+# (c) 2018 Aaron Taylor <ataylor at subgeniuskitty dot com>
+# See LICENSE.txt file for copyright and license details.
+
+# Simple 4-function calculator in NED assembly.
+# 20181128 - Aaron Taylor
+
+calc
+ JSR>calcinit
+
+ calcloop
+ # Refresh the display.
+ JSR>printtopstackentry
+
+ # Get a character/command.
+ JSR>getchar
+
+ # Check for 'zero stack entry' command.
+ LDSP+0
+ JSR>evalzerostackentry
+
+ # Check for 'negate stack entry' command.
+ LDSP+0
+ JSR>evalnegatestackentry
+
+ # Check for stack navigation commands.
+ LDSP+0
+ JSR>evalstacknavigation
+
+ # Check for ASCII digit (append to stack entry) command.
+ LDSP+0
+ JSR>evalasciidigit
+
+ # Check for ASCII 'addition' command.
+ LDSP+0
+ JSR>evalmathaddition
+
+ # Check for ASCII 'subtraction' command.
+ LDSP+0
+ JSR>evalmathsubtraction
+
+ # Check for ASCII 'multiplication' command.
+ LDSP+0
+ JSR>evalmathmultiplication
+
+ # Check for ASCII 'division' command.
+ LDSP+0
+ JSR>evalmathdivision
+
+ # Dump existing character and get the next character.
+ TEST
+ JMP>calcloop
+
+# Should be unreachable.
+HALT
+
+##########################################################################################
+calcinit
+##########################################################################################
+# Description:
+# Initializes stack for calc subroutine.
+# Zeros the Data Stack in RAM.
+# Call Stack:
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Base Address (=0x40000000)
+# Data Stack Offset (=0) <-- TOS
+##########################################################################################
+ # Setup program stack.
+ WORD_1073741824
+ SWAP
+ IM_0
+ SWAP
+
+ # Prepare to generate Data Stack pointers.
+ LDSP+2 # Data Stack Base Address
+ LDSP+2 # Data Stack Offset
+
+ # Zero the Data Stack.
+ calcinitzeroloop
+
+ # Increment Data Stack Offset, store 0 at location.
+ JSR>incrementstackindex
+ IM_0
+ LDSP+2
+ LDSP+2
+ ADD
+ STORE
+
+ # Check for loop termination
+ LDSP+0
+ TEST
+ BRZ>calcinitzeroloopend
+ JMP>calcinitzeroloop
+
+ calcinitzeroloopend
+
+ # Clean up stack and return.
+ TEST
+ TEST
+ RTS
+
+##########################################################################################
+incrementstackindex
+##########################################################################################
+# Description:
+# Increment the Data Stack Offset, wrapping if approriate.
+# Call Stack:
+# Data Stack Offset
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Offset
+##########################################################################################
+ # Increment the Data Stack Offset
+ SWAP
+ IM_4 # Four bytes per word
+ ADD
+
+ # See if the new Data Stack Offset should wrap. If so, set it to zero.
+ LDSP+0
+ IM_12 # Total of four stack entries (offsets: 0, 4, 8, 12).
+ JSR>subtract
+ TEST
+ IM_12 # Address of PSW register.
+ LOAD
+ IM_2 # Negative bit in PSW
+ AND
+ TEST
+ BRZ>incrementstackindexreturn
+ # Negative bit was set, so wrap to start of stack.
+ TEST
+ IM_0
+ incrementstackindexreturn
+ SWAP
+ RTS
+
+##########################################################################################
+decrementstackindex
+##########################################################################################
+# Description:
+# Decrement the Data Stack Offset, wrapping if approriate.
+# Call Stack:
+# Data Stack Offset
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Offset
+##########################################################################################
+ # Decrement the Data Stack Offset
+ SWAP
+ IM_4
+ SWAP
+ JSR>subtract
+
+ # See if new Data Stack Offset should wrap, indicated by value < 0.
+ # If so, set it to 12 (offsets: 0, 4, 8, 12).
+ LDSP+0
+ TEST
+ IM_12 # Address of PSW register.
+ LOAD
+ IM_2 # Negative bit in PSW register.
+ AND
+ TEST
+ BRZ>decrementstackindexreturn
+ # Negative bit was set, so wrap to end of stack.
+ TEST
+ IM_12
+ decrementstackindexreturn
+ SWAP
+ RTS
+
+##########################################################################################
+printstackindex
+##########################################################################################
+# Description:
+# Prints the data stack index in user readable form.
+# Call Stack:
+# Data Stack Offset
+# Return PC <-- TOS
+# Return Stack:
+# <empty>
+##########################################################################################
+ # Put Return PC on bottom of stack.
+ SWAP
+
+ # Put post-number portion of the string on the stack (colon, space, NUL).
+ IM_0 # ASCII NUL
+ SWAP
+ WORD_32 # ASCII ' '
+ SWAP
+ WORD_58 # ASCII ':'
+ SWAP
+
+ # Stack now looks like:
+ # Return PC
+ # ASCII NUL
+ # ASCII ' '
+ # ASCII ':'
+ # Data Stack Offset
+
+ # Divide Data Stack Offset by 4 to generate index since there are 4 bytes per word.
+ IM_4
+ JSR>divide
+ TEST # DROP Remainder
+
+ # Convert index to ASCII and print the string.
+ JSR>itoa
+ JSR>printstring
+ RTS
+
+##########################################################################################
+printbinaryinteger
+##########################################################################################
+# Description:
+# Prints a binary integer to ASCII terminal.
+# Call Stack:
+# Integer
+# Return PC <-- TOS
+# Return Stack:
+# <empty>
+##########################################################################################
+ # Put Return PC on bottom of stack.
+ SWAP
+
+ # Put ASCII NUL on stack as end of string.
+ IM_0
+ SWAP
+
+ # Separate Integer into sign and magnitude.
+ LDSP+0
+ IM_4
+ LOAD
+ AND
+ SWAP
+ JSR>absolutevalue
+
+ # Stack now looks like:
+ # Return PC
+ # ASCII NUL
+ # Sign flag (nonzero for negative result, 0 for positive result)
+ # ABS(Integer)
+
+ # First check if the number is zero and print a single zero if true.
+ LDSP+0
+ TEST
+ BRZ>printbinaryintegerloopend
+
+ # Repeatedly divide by ten and push each digit onto the stack in ASCII.
+ printbinaryintegerloop
+
+ # Verify Integer still has digits to print (i.e. Integer != 0)
+ LDSP+0
+ TEST
+ BRZ>printbinaryintegerloopend
+
+ # Extract the least significant digit.
+ IM_10
+ JSR>divide
+
+ # Convert to ASCII and add to string on stack.
+ JSR>itoa
+ LDSP+2 # Sign flag
+ SWAP
+ STSP+2
+ SWAP
+
+ # Loop
+ JMP>printbinaryintegerloop
+
+ printbinaryintegerloopend
+ TEST # DROP ABS(Integer)
+
+ # Push a leading ASCII zero onto stack.
+ IM_0
+ JSR>itoa
+ SWAP
+
+ # Stack now looks like:
+ # Return PC
+ # ASCII NUL
+ # ASCII digit
+ # ...
+ # ASCII digit
+ # Sign flag (nonzero for negative result, 0 for positive result)
+
+ # Push sign onto stack as ASCII character.
+ TEST
+ BRZ>printbinaryintegerpositive
+
+ # Add ASCII '-' sign to stack
+ WORD_44
+ IM_1
+ ADD
+ JMP>printbinaryintegerend
+
+ printbinaryintegerpositive
+
+ # Add ASCII '+' sign to stack
+ WORD_42
+ IM_1
+ ADD
+
+ printbinaryintegerend
+
+ # Print the string and return
+ JSR>printstring
+ RTS
+
+##########################################################################################
+printtopstackentry
+##########################################################################################
+# Description:
+# Prints the current TOS entry.
+# Call Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Base Address
+# Data Stack Offset <-- TOS
+##########################################################################################
+ # Prepare the screen and cursor.
+ JSR>ansiescapeclearscreen
+ JSR>ansiescapesetcursorcolumnone
+
+ # Print the data stack index
+ LDSP+1
+ JSR>printstackindex
+
+ # Print the TOS entry from the data stack in human readable form.
+ LDSP+2
+ LDSP+2
+ ADD
+ LOAD
+ JSR>printbinaryinteger
+ RTS
+
+##########################################################################################
+evalzerostackentry
+##########################################################################################
+# Description:
+# If character on TOS is ASCII "'", zero the current data stack entry.
+# Call Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+# ASCII character
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+##########################################################################################
+ SWAP
+
+ # Test for ASCII "'".
+ WORD_38 # ASCII "'"
+ IM_1
+ ADD
+ JSR>subtract
+ TEST
+ BRZ>evalzerostackentrymatch
+
+ # No match, return from subroutine
+ RTS
+
+ evalzerostackentrymatch
+
+ # Matched, zero the stack entry and return.
+
+ # Stack now looks like:
+ # Data Stack Base Address
+ # Data Stack Offset
+ # ASCII character
+ # Return PC <-- TOS
+
+ IM_0
+ LDSP+4 # Data Stack Base Address
+ LDSP+4 # Data Stack Offset
+ ADD
+ STORE
+ RTS
+
+##########################################################################################
+evalstacknavigation
+##########################################################################################
+# Description:
+# If character on TOS is ASCII '.' or ',', inc/dec Data Stack Offset to next entry.
+# Call Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+# ASCII character
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+##########################################################################################
+ SWAP
+ LDSP+0
+
+ # Test for ASCII ','
+ WORD_44 # ASCII ','
+ JSR>subtract
+ TEST
+ BRZ>evalstacknavigationprevmatch
+
+ # No match.
+ JMP>evalstacknavigationnexttest
+
+ evalstacknavigationprevmatch
+
+ # Matched, decrement Data Stack Offset.
+
+ # Stack now looks like:
+ # Data Stack Base Address
+ # Data Stack Offset
+ # ASCII character
+ # Return PC <-- TOS
+ # ASCII character
+
+ # Decrement the Data Stack Offset
+ LDSP+3 # Data Stack Offset
+ JSR>decrementstackindex
+ STSP+3
+
+ # Clean up stack and return.
+ TEST
+ RTS
+
+ evalstacknavigationnexttest
+ # Test for ASCII '.'
+ WORD_46 # ASCII '.'
+ JSR>subtract
+ TEST
+ BRZ>evalstacknavigationnextmatch
+
+ # No match.
+ RTS
+
+ evalstacknavigationnextmatch
+
+ # Matched, increment Data Stack Offset
+
+ # Increment and return.
+ LDSP+2 # Data Stack Offset
+ JSR>incrementstackindex
+ STSP+2
+ RTS
+
+##########################################################################################
+evalnegatestackentry
+##########################################################################################
+# Description:
+# If character on TOS is ASCII ';', negate the current data stack entry.
+# Call Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+# ASCII character
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+##########################################################################################
+ SWAP
+
+ # Test for ASCII ';'
+ WORD_58 # ASCII ';'
+ IM_1
+ ADD
+ JSR>subtract
+ TEST
+ BRZ>evalnegatestackentrymatch
+
+ # No match, return from subroutine
+ RTS
+
+ evalnegatestackentrymatch
+
+ # Matched, negate the stack entry and return.
+
+ # Stack now looks like:
+ # Data Stack Base Address
+ # Data Stack Offset
+ # ASCII character
+ # Return PC <-- TOS
+
+ LDSP+3 # Data Stack Base Address
+ LDSP+3 # Data Stack Offset
+ ADD
+ LDSP+0
+ LOAD
+ JSR>negate
+ SWAP
+ STORE
+ RTS
+
+##########################################################################################
+evalmathaddition
+##########################################################################################
+# Description:
+# If character on TOS is ASCII '+', perform addition on TOS and NOS.
+# Call Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+# ASCII character
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+##########################################################################################
+ SWAP
+
+ # Test for ASCII '+' (43).
+ IM_30
+ IM_13
+ ADD
+ JSR>subtract
+ TEST
+ BRZ>evalmathadditionmatch
+
+ # No match, return from subroutine
+ RTS
+
+ evalmathadditionmatch
+
+ # Matched. Perform addition.
+
+ # Stack now looks like:
+ # Data Stack Base Address
+ # Data Stack Offset
+ # ASCII character
+ # Return PC <-- TOS
+
+ # Fetch the first operand.
+ LDSP+3 # Data Stack Base Address
+ LDSP+3 # Data Stack Offset
+ ADD
+ LOAD
+
+ # Decrement Data Stack Offset.
+ LDSP+3 # Data Stack Offset
+ JSR>decrementstackindex
+ STSP+3
+
+ # Fetch the second operand.
+ LDSP+4 # Data Stack Base Address
+ LDSP+4 # Data Stack Offset
+ ADD
+ LOAD
+
+ # Perform the addition.
+ ADD
+
+ # Store the result.
+ LDSP+4 # Data Stack Base Address
+ LDSP+4 # Data Stack Offset
+ ADD
+ STORE
+
+ # Return
+ RTS
+
+##########################################################################################
+evalmathsubtraction
+##########################################################################################
+# Description:
+# If character on TOS is ASCII '-', perform subtraction NOS-TOS.
+# Call Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+# ASCII character
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+##########################################################################################
+ SWAP
+
+ # Test for ASCII '-' (45).
+ IM_30
+ IM_15
+ ADD
+ JSR>subtract
+ TEST
+ BRZ>evalmathsubtractionmatch
+
+ # No match, return from subroutine
+ RTS
+
+ evalmathsubtractionmatch
+
+ # Matched. Perform subtraction.
+
+ # Stack now looks like:
+ # Data Stack Base Address
+ # Data Stack Offset
+ # ASCII character
+ # Return PC <-- TOS
+
+ # Fetch the first operand.
+ LDSP+3 # Data Stack Base Address
+ LDSP+3 # Data Stack Offset
+ ADD
+ LOAD
+
+ # Decrement Data Stack Offset.
+ LDSP+3 # Data Stack Offset
+ JSR>decrementstackindex
+ STSP+3
+
+ # Fetch the second operand.
+ LDSP+4 # Data Stack Base Address
+ LDSP+4 # Data Stack Offset
+ ADD
+ LOAD
+
+ # Perform the subtraction.
+ JSR>subtract
+
+ # Store the result.
+ LDSP+4 # Data Stack Base Address
+ LDSP+4 # Data Stack Offset
+ ADD
+ STORE
+
+ # Return
+ RTS
+
+##########################################################################################
+evalmathmultiplication
+##########################################################################################
+# Description:
+# If character on TOS is ASCII '*', perform multiplication on TOS and NOS.
+# Call Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+# ASCII character
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+##########################################################################################
+ SWAP
+
+ # Test for ASCII '*' (42).
+ IM_30
+ IM_12
+ ADD
+ JSR>subtract
+ TEST
+ BRZ>evalmathmultiplicationmatch
+
+ # No match, return from subroutine
+ RTS
+
+ evalmathmultiplicationmatch
+
+ # Matched. Perform multiplication.
+
+ # Stack now looks like:
+ # Data Stack Base Address
+ # Data Stack Offset
+ # ASCII character
+ # Return PC <-- TOS
+
+ # Fetch the first operand.
+ LDSP+3 # Data Stack Base Address
+ LDSP+3 # Data Stack Offset
+ ADD
+ LOAD
+
+ # Decrement Data Stack Offset.
+ LDSP+3 # Data Stack Offset
+ JSR>decrementstackindex
+ STSP+3
+
+ # Fetch the second operand.
+ LDSP+4 # Data Stack Base Address
+ LDSP+4 # Data Stack Offset
+ ADD
+ LOAD
+
+ # Perform the multiplication.
+ JSR>multiply
+
+ # Store the result.
+ LDSP+4 # Data Stack Base Address
+ LDSP+4 # Data Stack Offset
+ ADD
+ STORE
+
+ # Return
+ RTS
+
+##########################################################################################
+evalmathdivision
+##########################################################################################
+# Description:
+# If character on TOS is ASCII '/', perform division NOS/TOS.
+# Returns quotient on TOS and remainder on NOS.
+# Call Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+# ASCII character
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+##########################################################################################
+ SWAP
+
+ # Test for ASCII '/' (47).
+ IM_30
+ IM_17
+ ADD
+ JSR>subtract
+ TEST
+ BRZ>evalmathdivisionmatch
+
+ # No match, return from subroutine
+ RTS
+
+ evalmathdivisionmatch
+
+ # Matched. Perform division.
+
+ # Stack now looks like:
+ # Data Stack Base Address
+ # Data Stack Offset
+ # ASCII character
+ # Return PC <-- TOS
+
+ # Fetch the first operand.
+ LDSP+3 # Data Stack Base Address
+ LDSP+3 # Data Stack Offset
+ ADD
+ LOAD
+
+ # Decrement Data Stack Offset.
+ LDSP+3 # Data Stack Offset
+ JSR>decrementstackindex
+ STSP+3
+
+ # Fetch the second operand.
+ LDSP+4 # Data Stack Base Address
+ LDSP+4 # Data Stack Offset
+ ADD
+ LOAD
+
+ # Perform the division.
+ SWAP
+ JSR>divide
+
+ # Store the remainder.
+ LDSP+5 # Data Stack Base Address
+ LDSP+5 # Data Stack Offset
+ ADD
+ STORE
+
+ # Increment the Data Stack Offset
+ LDSP+3 # Data Stack Offset
+ JSR>incrementstackindex
+ STSP+3
+
+ # Store the quotient.
+ LDSP+4 # Data Stack Base Address
+ LDSP+4 # Data Stack Offset
+ ADD
+ STORE
+
+ # Return
+ RTS
+
+##########################################################################################
+evalasciidigit
+##########################################################################################
+# Description:
+# If character on TOS is ASCII digit, append it to current stack entry.
+# Call Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+# ASCII character
+# Return PC <-- TOS
+# Return Stack:
+# Data Stack Base Address
+# Data Stack Offset
+# ASCII character
+##########################################################################################
+ SWAP
+
+ # Test for ASCII digit.
+ JSR>isasciidigit
+ TEST
+ BRZ>evalasciidigitmatch
+
+ # No match, return from subroutine
+ RTS
+
+ evalasciidigitmatch
+
+ # Matched, append result to current stack entry and return.
+
+ # Stack now looks like:
+ # Data Stack Base Address
+ # Data Stack Offset
+ # ASCII digit
+ # Return PC <-- TOS
+
+ # Load the existing entry from top of data stack.
+ LDSP+3 # Data Stack Base Address
+ LDSP+3 # Data Stack Offset
+ ADD
+ LDSP+0
+ LOAD
+
+ # Multiply existing entry by ten and add new digit to least-significant location.
+ IM_10
+ JSR>multiply
+ LDSP+3 # ASCII digit
+ JSR>atoi
+ ADD
+
+ # Put new entry back on top of data stack and return.
+ SWAP
+ STORE
+ RTS
+
+##########################################################################################
+isasciidigit
+##########################################################################################
+# Description:
+# Tests if character is ASCII digit (0..9). Returns 0 if true, 1 if false.
+# Call Stack:
+# ASCII character
+# Return PC <-- TOS
+# Return Stack:
+# <boolean, 0=true, 1=false>
+##########################################################################################
+ # Subtract ASCII '0' value, translating ASCII digit to integer.
+ SWAP
+ WORD_48
+ SWAP
+ JSR>subtract
+ # Copy and test negative result. This would indicate an ASCII character below '0'.
+ LDSP+0
+ TEST
+ IM_12 # Address of PSW register
+ LOAD
+ IM_2
+ AND
+ TEST
+ BRZ>isasciidigitcontinued
+ # The result was negative, so clean up stack and return false.
+ IM_1
+ STSP+0
+ SWAP
+ RTS
+ isasciidigitcontinued
+ # Subtract another 10 and check for positive result. This indicates ASCII char > '9'.
+ IM_10
+ SWAP
+ JSR>subtract
+ TEST
+ IM_12
+ LOAD
+ IM_2
+ AND
+ TEST
+ BRZ>isasciidigitfalse
+ # The result was true, so clean up stack and return true.
+ IM_0
+ SWAP
+ RTS
+ isasciidigitfalse
+ # The result was false, so clean up stack and return false.
+ IM_1
+ SWAP
+ RTS
+
+##########################################################################################
+generatesignflag
+##########################################################################################
+# Description:
+# Given a pair of twos-complement signed integers X and Y, generates a sign flag.
+# Flag is non-zero if the product of X and Y would be negative, otherwise flag is zero.
+# Call Stack:
+# Y Operand
+# X Operand
+# Return PC <-- TOS
+# Return Stack:
+# Sign Flag <-- TOS
+##########################################################################################
+ # Place Return PC at bottom of stack.
+ LDSP+2
+ LDSP+1
+ STSP+3
+ STSP+0
+
+ # Stack now looks like:
+ # Return PC
+ # X Operand
+ # Y Operand <-- TOS
+
+ IM_4
+ LOAD
+ AND
+ SWAP
+ IM_4
+ LOAD
+ AND
+ XOR
+ SWAP
+ RTS
+
+##########################################################################################
+negate
+##########################################################################################
+# Description:
+# Returns the additive inverse of a twos-complement operand.
+# Call Stack:
+# Operand
+# Return PC <-- TOS
+# Return Stack:
+# Result <-- TOS
+##########################################################################################
+ SWAP
+ NOT
+ IM_1
+ ADD
+ SWAP
+ RTS
+
+##########################################################################################
+absolutevalue
+##########################################################################################
+# Description:
+# Returns the absolute value of a twos-complement operand.
+# Call Stack:
+# Operand
+# Return PC <-- TOS
+# Return Stack:
+# Result <-- TOS
+##########################################################################################
+ SWAP
+ LDSP+0
+ IM_4
+ LOAD
+ AND
+ TEST
+ BRZ>absolutevaluereturn
+ JSR>negate
+
+ absolutevaluereturn
+ SWAP
+ RTS
+
+##########################################################################################
+multiply
+##########################################################################################
+# Description:
+# Performs X*Y and returns result on TOS.
+# Call Stack:
+# Y Operand
+# X Operand
+# Return PC <-- TOS
+# Return Stack:
+# Result <-- TOS
+##########################################################################################
+ # Place Return PC at bottom of stack.
+ LDSP+2
+ LDSP+1
+ STSP+3
+ STSP+0
+
+ # Stack now looks like:
+ # Return PC
+ # X Operand
+ # Y Operand <-- TOS
+
+ # Generate a sign flag and store it behind the operands.
+ LDSP+1
+ LDSP+1
+ JSR>generatesignflag
+ LDSP+2
+ SWAP
+ STSP+2
+
+ # Stack now looks like:
+ # Return PC
+ # Sign flag (nonzero for negative result, 0 for positive result)
+ # Y Operand
+ # X Operand <-- TOS
+
+ # Convert both X and Y Operands to absolute value.
+ JSR>absolutevalue
+ SWAP
+ JSR>absolutevalue
+
+ # Stack now looks like:
+ # Return PC
+ # Sign flag (nonzero for negative result, 0 for positive result)
+ # ABS(X Operand)
+ # ABS(Y Operand) <-- TOS
+
+ # Prepare the stack for multiplication algorithm
+ IM_0 # For magnitude of left/right shifts.
+ LDSP+0 # Sets up stack location to build/store result.
+
+ # Check Nth bit of second operand.
+ testbit
+ LDSP+2 # Y Operand
+ LDSP+2 # Shift magnitude
+ SHIFT
+ IM_1
+ AND
+ TEST
+ BRZ>skipadd
+ # If indicated by a 1 bit, shift and add first operand to result.
+ LDSP+3 # X Operand
+ IM_4 # 0x80000000
+ LOAD
+ LDSP+3 # Shift magnitude
+ OR
+ SHIFT
+ ADD
+ skipadd
+
+ # Increment shift magnitude counter.
+ LDSP+1 # Shift magnitude
+ IM_1
+ ADD
+ STSP+1
+
+ # Test for completion of multiplication algorithm (31 shifts).
+ LDSP+1 # Shift magnitude
+ IM_30
+ JSR>subtract
+ TEST
+ BRZ>multiplycleanup
+ JMP>testbit
+
+ # Clean up the the stack after performing multiplication.
+ multiplycleanup
+ STSP+0
+ STSP+0
+ STSP+0
+
+ # Stack now looks like:
+ # Return PC
+ # Sign flag (nonzero for negative result, 0 for positive result)
+ # ABS(X*Y) <-- TOS
+
+ # Set the sign of the product.
+ applysign
+ SWAP
+ TEST
+ BRZ>multiplyreturn
+ JSR>negate
+
+ # Clean up and return.
+ multiplyreturn
+ SWAP
+ RTS
+
+##########################################################################################
+divide
+##########################################################################################
+# Description:
+# Division with remainder.
+# Halts on zero divisor.
+# Call Stack:
+# Dividend
+# Divisor
+# Return PC <-- TOS
+# Return Stack:
+# Quotient
+# Remainder <-- TOS
+##########################################################################################
+ # Move Return PC to bottom of stack.
+ LDSP+2
+ SWAP
+ STSP+2
+ SWAP
+
+ # Stack now looks like:
+ # Return PC
+ # Dividend
+ # Divisor <-- TOS
+
+ # Check for zero divisor
+ LDSP+0
+ TEST
+ BRZ>divideexception
+
+ # Generate a sign flag and store it behind the operands.
+ LDSP+1
+ LDSP+1
+ JSR>generatesignflag
+ LDSP+2
+ SWAP
+ STSP+2
+
+ # Stack now looks like:
+ # Return PC
+ # Sign flag (nonzero for negative result, 0 for positive result)
+ # Divisor
+ # Dividend <-- TOS
+
+ # Convert both Dividend and Divisor to absolute value.
+ JSR>absolutevalue
+ SWAP
+ JSR>absolutevalue
+
+ # Stack now looks like:
+ # Return PC
+ # Sign flag (nonzero for negative result, 0 for positive result)
+ # ABS(Dividend)
+ # ABS(Divisor) <-- TOS
+
+ # Prepare stack for division algorithm.
+ IM_31 # Cycle Counter - Loop from n-1 -> 0 where n = 32 bits.
+ IM_0 # Quotient
+ IM_0 # Remainder
+
+ # Binary long division
+ divisionloop
+ # Check Cycle Counter for end-of-loop condition (CC = -1).
+ LDSP+2 # Cycle Counter
+ IM_1
+ ADD
+ TEST
+ BRZ>divisionloopend
+
+ # While Cycle Counter >= 0
+
+ # Left-shift Remainder by 1 bit.
+ IM_1
+ IM_4 # Address of 0x80000000 register
+ LOAD
+ OR
+ SHIFT
+
+ # Set LSB of Remainder equal to bit (Cycle Counter) of Dividend.
+ LDSP+4 # Dividend
+ LDSP+3 # Cycle Counter
+ SHIFT
+ IM_1
+ AND
+ OR
+
+ # Check if Remainder >= Divisor
+ LDSP+3 # Divisor
+ LDSP+1 # Remainder
+ JSR>subtract
+ TEST
+ IM_12 # Address of PSW register
+ LOAD
+ IM_2 # Bit for Negative Flag in PSW
+ AND
+ IM_2
+ XOR
+ TEST
+ BRZ>divisionsubloopend
+
+ # If Remainder >= Divisor
+
+ # Set Remainder = Remainder - Divisor
+ LDSP+3 # Divisor
+ SWAP
+ JSR>subtract
+
+ # Set bit (Cycle Counter) of Quotient equal to 1.
+ SWAP
+ IM_1
+ LDSP+3 # Cycle Counter
+ IM_4
+ LOAD
+ OR
+ SHIFT
+ OR
+ SWAP
+
+ divisionsubloopend
+
+ # Decrement Cycle Counter
+ IM_1
+ LDSP+3 # Cycle Counter
+ JSR>subtract
+ STSP+2
+
+ # Loop over next division cycle
+ JMP>divisionloop
+
+ divisionloopend
+
+ # Stack cleanup
+ STSP+1
+ STSP+1
+ STSP+1
+
+ # Stack now looks like:
+ # Return PC
+ # Sign flag (nonzero for negative result, 0 for positive result)
+ # Remainder
+ # Quotient <-- TOS
+
+ # Set sign of results.
+ LDSP+2 # Sign flag
+ TEST
+ BRZ>divisioncleanup
+ JSR>negate
+ SWAP
+ JSR>negate
+ SWAP
+
+ divisioncleanup
+
+ # Clean up and return
+ SWAP
+ LDSP+3 # Return PC
+ SWAP
+ STSP+2
+ SWAP
+ STSP+2
+ RTS
+
+ # For now we can only HALT on errors and let the PC inform our debugging.
+ divideexception
+ HALT
+
+##########################################################################################
+subtract
+##########################################################################################
+# Description:
+# Performs X-Y and returns result on TOS.
+# Call Stack:
+# Y Operand
+# X Operand
+# Return PC <-- TOS
+# Return Stack:
+# Result <-- TOS
+##########################################################################################
+ # Place Return PC at bottom of stack.
+ LDSP+2
+ LDSP+1
+ STSP+3
+ STSP+0
+ # Stack now looks like:
+ # Return PC
+ # X Operand
+ # Y Operand <-- TOS
+
+ JSR>negate
+ ADD
+ SWAP
+ RTS
+
+##########################################################################################
+atoi
+##########################################################################################
+# Description:
+# Converts an ASCII decimal into the corresponding integer value.
+# No bounds checks; assumed to already be performed in isasciidigit().
+# Call Stack:
+# Operand
+# Return PC <-- TOS
+# Return Stack:
+# Result <-- TOS
+##########################################################################################
+ SWAP
+ WORD_48
+ SWAP
+ JSR>subtract
+ SWAP
+ RTS
+
+##########################################################################################
+itoa
+##########################################################################################
+# Description:
+# Converts an integer (0..9) into the corresponding ASCII character.
+# Call Stack:
+# Operand
+# Return PC <-- TOS
+# Return Stack:
+# Result <-- TOS
+##########################################################################################
+ # Copy operand to TOS
+ LDSP+1
+ # Verify that operand < 10
+ IM_10
+ LDSP+1
+ JSR>subtract
+ TEST # Set PSW according to difference.
+ # Branch if non-negative:
+ IM_12 # Address of PSW
+ LOAD
+ IM_2
+ AND
+ TEST
+ BRZ>itoahalt
+ # Verify that operand > -1
+ LDSP+0
+ TEST # Set PSW according to operand.
+ # Branch if negative:
+ IM_12
+ LOAD
+ IM_2
+ AND
+ IM_2
+ XOR
+ TEST
+ BRZ>itoahalt # Branch if operand was negative.
+ # Convert the integer to its ASCII representation and return to caller.
+ WORD_48
+ ADD
+ STSP+1
+ RTS
+ # Halt on error
+ itoahalt
+ HALT
+
+##########################################################################################
+putchar
+##########################################################################################
+# Description:
+# Writes one character to the terminal.
+# Call Stack:
+# Character to write
+# Return PC <-- TOS
+# Return Stack:
+# <empty>
+##########################################################################################
+ WORD_134217728 # XBUF
+ WORD_134217732 # XCSR
+ LDSP+3
+ SWAP
+ putcharloop
+ LDSP+0
+ LOAD
+ TEST
+ BRZ>putcharloop
+ TEST # Drop XCSR from stack
+ SWAP
+ STORE
+ # Wrote the character. Clean up stack and return.
+ STSP+0
+ RTS
+
+##########################################################################################
+getchar
+##########################################################################################
+# Description:
+# Reads one character from the terminal.
+# Call Stack:
+# Return PC <-- TOS
+# Return Stack:
+# Character <-- TOS
+##########################################################################################
+ WORD_134217736 # RBUF
+ WORD_134217740 # RCSR
+ getcharloop
+ LDSP+0
+ LOAD
+ TEST
+ BRZ>getcharloop
+ LDSP+1
+ LOAD
+ # Found a character. Clean up stack and return.
+ STSP+0
+ STSP+0
+ SWAP
+ RTS
+
+##########################################################################################
+printstring
+##########################################################################################
+# Description:
+# Prints a null-terminated string located on the stack.
+# Call Stack:
+# ASCII NUL
+# ASCII character
+# ...
+# ASCII character
+# Return PC <-- TOS
+##########################################################################################
+ SWAP
+ BRZ>printstringreturn
+ JSR>putchar
+ JMP>printstring
+
+ printstringreturn
+ TEST
+ RTS
+
+##########################################################################################
+ansiescapeclearscreen
+##########################################################################################
+# Description:
+# Clears the entire screen.
+# Call Stack:
+# Return PC <-- TOS
+# Return Stack:
+# <empty>
+##########################################################################################
+ # ASCII NUL
+ WORD_0
+ # ASCII 'J'
+ WORD_74
+ # ASCII '2'
+ WORD_50
+ # ASCII '['
+ WORD_90
+ IM_1
+ ADD
+ # ASCII ESC
+ WORD_26
+ IM_1
+ ADD
+ # Print string and return
+ JSR>printstring
+ RTS
+
+##########################################################################################
+ansiescapesetcursorcolumnone
+##########################################################################################
+# Description:
+# Reset cursor to column 1 of screen.
+# Call Stack:
+# Return PC <-- TOS
+# Return Stack:
+# <empty>
+##########################################################################################
+ # ASCII NUL
+ WORD_0
+ # ASCII 'G'
+ WORD_70
+ IM_1
+ ADD
+ # ASCII '1'
+ WORD_48
+ IM_1
+ ADD
+ # ASCII '['
+ WORD_90
+ IM_1
+ ADD
+ # ASCII ESC
+ WORD_26
+ IM_1
+ ADD
+ # Print string and return
+ JSR>printstring
+ RTS