# (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
# Get a character/command.
# Check for 'zero stack entry' command.
# Check for 'negate stack entry' command.
# Check for stack navigation commands.
# Check for ASCII digit (append to stack entry) command.
# Check for ASCII 'addition' command.
# Check for ASCII 'subtraction' command.
# Check for ASCII 'multiplication' command.
JSR>evalmathmultiplication
# Check for ASCII 'division' command.
# Dump existing character and get the next character.
##########################################################################################
##########################################################################################
# Initializes stack for calc subroutine.
# Zeros the Data Stack in RAM.
# Data Stack Base Address (=0x40000000)
# Data Stack Offset (=0) <-- TOS
##########################################################################################
# Prepare to generate Data Stack pointers.
LDSP+2 # Data Stack Base Address
LDSP+2 # Data Stack Offset
# Increment Data Stack Offset, store 0 at location.
# Check for loop termination
# Clean up stack and return.
##########################################################################################
##########################################################################################
# Increment the Data Stack Offset, wrapping if approriate.
##########################################################################################
# Increment the Data Stack Offset
IM_4 # Four bytes per word
# See if the new Data Stack Offset should wrap. If so, set it to zero.
IM_12 # Total of four stack entries (offsets: 0, 4, 8, 12).
IM_12 # Address of PSW register.
IM_2 # Negative bit in PSW
BRZ>incrementstackindexreturn
# Negative bit was set, so wrap to start of stack.
incrementstackindexreturn
##########################################################################################
##########################################################################################
# Decrement the Data Stack Offset, wrapping if approriate.
##########################################################################################
# Decrement the Data Stack Offset
# See if new Data Stack Offset should wrap, indicated by value < 0.
# If so, set it to 12 (offsets: 0, 4, 8, 12).
IM_12 # Address of PSW register.
IM_2 # Negative bit in PSW register.
BRZ>decrementstackindexreturn
# Negative bit was set, so wrap to end of stack.
decrementstackindexreturn
##########################################################################################
##########################################################################################
# Prints the data stack index in user readable form.
##########################################################################################
# Put Return PC on bottom of stack.
# Put post-number portion of the string on the stack (colon, space, NUL).
# Divide Data Stack Offset by 4 to generate index since there are 4 bytes per word.
# Convert index to ASCII and print the string.
##########################################################################################
##########################################################################################
# Prints a binary integer to ASCII terminal.
##########################################################################################
# Put Return PC on bottom of stack.
# Put ASCII NUL on stack as end of string.
# Separate Integer into sign and magnitude.
# Sign flag (nonzero for negative result, 0 for positive result)
# First check if the number is zero and print a single zero if true.
BRZ>printbinaryintegerloopend
# Repeatedly divide by ten and push each digit onto the stack in ASCII.
# Verify Integer still has digits to print (i.e. Integer != 0)
BRZ>printbinaryintegerloopend
# Extract the least significant digit.
# Convert to ASCII and add to string on stack.
JMP>printbinaryintegerloop
printbinaryintegerloopend
# Push a leading ASCII zero onto stack.
# Sign flag (nonzero for negative result, 0 for positive result)
# Push sign onto stack as ASCII character.
BRZ>printbinaryintegerpositive
# Add ASCII '-' sign to stack
JMP>printbinaryintegerend
printbinaryintegerpositive
# Add ASCII '+' sign to stack
# Print the string and return
##########################################################################################
##########################################################################################
# Prints the current TOS entry.
# Data Stack Base Address
# Data Stack Base Address
# Data Stack Offset <-- TOS
##########################################################################################
# Prepare the screen and cursor.
JSR>ansiescapeclearscreen
JSR>ansiescapesetcursorcolumnone
# Print the data stack index
# Print the TOS entry from the data stack in human readable form.
##########################################################################################
##########################################################################################
# If character on TOS is ASCII "'", zero the current data stack entry.
# Data Stack Base Address
# Data Stack Base Address
##########################################################################################
BRZ>evalzerostackentrymatch
# No match, return from subroutine
# Matched, zero the stack entry and return.
# Data Stack Base Address
LDSP+4 # Data Stack Base Address
LDSP+4 # Data Stack Offset
##########################################################################################
##########################################################################################
# If character on TOS is ASCII '.' or ',', inc/dec Data Stack Offset to next entry.
# Data Stack Base Address
# Data Stack Base Address
##########################################################################################
BRZ>evalstacknavigationprevmatch
JMP>evalstacknavigationnexttest
evalstacknavigationprevmatch
# Matched, decrement Data Stack Offset.
# Data Stack Base Address
# Decrement the Data Stack Offset
LDSP+3 # Data Stack Offset
# Clean up stack and return.
evalstacknavigationnexttest
BRZ>evalstacknavigationnextmatch
evalstacknavigationnextmatch
# Matched, increment Data Stack Offset
LDSP+2 # Data Stack Offset
##########################################################################################
##########################################################################################
# If character on TOS is ASCII ';', negate the current data stack entry.
# Data Stack Base Address
# Data Stack Base Address
##########################################################################################
BRZ>evalnegatestackentrymatch
# No match, return from subroutine
evalnegatestackentrymatch
# Matched, negate the stack entry and return.
# Data Stack Base Address
LDSP+3 # Data Stack Base Address
LDSP+3 # Data Stack Offset
##########################################################################################
##########################################################################################
# If character on TOS is ASCII '+', perform addition on TOS and NOS.
# Data Stack Base Address
# Data Stack Base Address
##########################################################################################
# Test for ASCII '+' (43).
BRZ>evalmathadditionmatch
# No match, return from subroutine
# Matched. Perform addition.
# Data Stack Base Address
# Fetch the first operand.
LDSP+3 # Data Stack Base Address
LDSP+3 # Data Stack Offset
# Decrement Data Stack Offset.
LDSP+3 # Data Stack Offset
# Fetch the second operand.
LDSP+4 # Data Stack Base Address
LDSP+4 # Data Stack Offset
LDSP+4 # Data Stack Base Address
LDSP+4 # Data Stack Offset
##########################################################################################
##########################################################################################
# If character on TOS is ASCII '-', perform subtraction NOS-TOS.
# Data Stack Base Address
# Data Stack Base Address
##########################################################################################
# Test for ASCII '-' (45).
BRZ>evalmathsubtractionmatch
# No match, return from subroutine
# Matched. Perform subtraction.
# Data Stack Base Address
# Fetch the first operand.
LDSP+3 # Data Stack Base Address
LDSP+3 # Data Stack Offset
# Decrement Data Stack Offset.
LDSP+3 # Data Stack Offset
# Fetch the second operand.
LDSP+4 # Data Stack Base Address
LDSP+4 # Data Stack Offset
# Perform the subtraction.
LDSP+4 # Data Stack Base Address
LDSP+4 # Data Stack Offset
##########################################################################################
##########################################################################################
# If character on TOS is ASCII '*', perform multiplication on TOS and NOS.
# Data Stack Base Address
# Data Stack Base Address
##########################################################################################
# Test for ASCII '*' (42).
BRZ>evalmathmultiplicationmatch
# No match, return from subroutine
evalmathmultiplicationmatch
# Matched. Perform multiplication.
# Data Stack Base Address
# Fetch the first operand.
LDSP+3 # Data Stack Base Address
LDSP+3 # Data Stack Offset
# Decrement Data Stack Offset.
LDSP+3 # Data Stack Offset
# Fetch the second operand.
LDSP+4 # Data Stack Base Address
LDSP+4 # Data Stack Offset
# Perform the multiplication.
LDSP+4 # Data Stack Base Address
LDSP+4 # Data Stack Offset
##########################################################################################
##########################################################################################
# If character on TOS is ASCII '/', perform division NOS/TOS.
# Returns quotient on TOS and remainder on NOS.
# Data Stack Base Address
# Data Stack Base Address
##########################################################################################
# Test for ASCII '/' (47).
BRZ>evalmathdivisionmatch
# No match, return from subroutine
# Matched. Perform division.
# Data Stack Base Address
# Fetch the first operand.
LDSP+3 # Data Stack Base Address
LDSP+3 # Data Stack Offset
# Decrement Data Stack Offset.
LDSP+3 # Data Stack Offset
# Fetch the second operand.
LDSP+4 # Data Stack Base Address
LDSP+4 # Data Stack Offset
LDSP+5 # Data Stack Base Address
LDSP+5 # Data Stack Offset
# Increment the Data Stack Offset
LDSP+3 # Data Stack Offset
LDSP+4 # Data Stack Base Address
LDSP+4 # Data Stack Offset
##########################################################################################
##########################################################################################
# If character on TOS is ASCII digit, append it to current stack entry.
# Data Stack Base Address
# Data Stack Base Address
##########################################################################################
# No match, return from subroutine
# Matched, append result to current stack entry and return.
# Data Stack Base Address
# Load the existing entry from top of data stack.
LDSP+3 # Data Stack Base Address
LDSP+3 # Data Stack Offset
# Multiply existing entry by ten and add new digit to least-significant location.
# Put new entry back on top of data stack and return.
##########################################################################################
##########################################################################################
# Tests if character is ASCII digit (0..9). Returns 0 if true, 1 if false.
# <boolean, 0=true, 1=false>
##########################################################################################
# Subtract ASCII '0' value, translating ASCII digit to integer.
# Copy and test negative result. This would indicate an ASCII character below '0'.
IM_12 # Address of PSW register
BRZ>isasciidigitcontinued
# The result was negative, so clean up stack and return false.
# Subtract another 10 and check for positive result. This indicates ASCII char > '9'.
# The result was true, so clean up stack and return true.
# The result was false, so clean up stack and return false.
##########################################################################################
##########################################################################################
# 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.
##########################################################################################
# Place Return PC at bottom of stack.
##########################################################################################
##########################################################################################
# Returns the additive inverse of a twos-complement operand.
##########################################################################################
##########################################################################################
##########################################################################################
# Returns the absolute value of a twos-complement operand.
##########################################################################################
##########################################################################################
##########################################################################################
# Performs X*Y and returns result on TOS.
##########################################################################################
# Place Return PC at bottom of stack.
# Generate a sign flag and store it behind the operands.
# Sign flag (nonzero for negative result, 0 for positive result)
# Convert both X and Y Operands to absolute value.
# Sign flag (nonzero for negative result, 0 for positive result)
# 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.
# If indicated by a 1 bit, shift and add first operand to result.
# Increment shift magnitude counter.
# Test for completion of multiplication algorithm (31 shifts).
# Clean up the the stack after performing multiplication.
# Sign flag (nonzero for negative result, 0 for positive result)
# Set the sign of the product.
##########################################################################################
##########################################################################################
# Division with remainder.
##########################################################################################
# Move Return PC to bottom of stack.
# Generate a sign flag and store it behind the operands.
# Sign flag (nonzero for negative result, 0 for positive result)
# Convert both Dividend and Divisor to absolute value.
# Sign flag (nonzero for negative result, 0 for positive result)
# Prepare stack for division algorithm.
IM_31 # Cycle Counter - Loop from n-1 -> 0 where n = 32 bits.
# Check Cycle Counter for end-of-loop condition (CC = -1).
# While Cycle Counter >= 0
# Left-shift Remainder by 1 bit.
IM_4 # Address of 0x80000000 register
# Set LSB of Remainder equal to bit (Cycle Counter) of Dividend.
# Check if Remainder >= Divisor
IM_12 # Address of PSW register
IM_2 # Bit for Negative Flag in PSW
# If Remainder >= Divisor
# Set Remainder = Remainder - Divisor
# Set bit (Cycle Counter) of Quotient equal to 1.
# Decrement Cycle Counter
# Loop over next division cycle
# Sign flag (nonzero for negative result, 0 for positive result)
# For now we can only HALT on errors and let the PC inform our debugging.
##########################################################################################
##########################################################################################
# Performs X-Y and returns result on TOS.
##########################################################################################
# Place Return PC at bottom of stack.
##########################################################################################
##########################################################################################
# Converts an ASCII decimal into the corresponding integer value.
# No bounds checks; assumed to already be performed in isasciidigit().
##########################################################################################
##########################################################################################
##########################################################################################
# Converts an integer (0..9) into the corresponding ASCII character.
##########################################################################################
# Verify that operand < 10
TEST # Set PSW according to difference.
# Branch if non-negative:
# Verify that operand > -1
TEST # Set PSW according to operand.
BRZ>itoahalt # Branch if operand was negative.
# Convert the integer to its ASCII representation and return to caller.
##########################################################################################
##########################################################################################
# Writes one character to the terminal.
##########################################################################################
TEST # Drop XCSR from stack
# Wrote the character. Clean up stack and return.
##########################################################################################
##########################################################################################
# Reads one character from the terminal.
##########################################################################################
# Found a character. Clean up stack and return.
##########################################################################################
##########################################################################################
# Prints a null-terminated string located on the stack.
##########################################################################################
##########################################################################################
##########################################################################################
# Clears the entire screen.
##########################################################################################
# Print string and return
##########################################################################################
ansiescapesetcursorcolumnone
##########################################################################################
# Reset cursor to column 1 of screen.
##########################################################################################
# Print string and return