c3aeac5df58e3e8d52edfcb58a40df1db41cc5d0
[ned1] / software / 4func_calculator / calc.asm
# (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
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
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
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
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
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.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
LDSP+0
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