2023 lines
35 KiB
NASM
2023 lines
35 KiB
NASM
org 0
|
||
|
||
load r0, fResultPtr+0
|
||
load r1, fResultPtr+1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, dumpFloat
|
||
|
||
cleq r0, r0, normalize
|
||
|
||
load r0, fResultPtr+0
|
||
load r1, fResultPtr+1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, dumpFloat
|
||
|
||
load r0, fResultPtr+0
|
||
load r1, fResultPtr+1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, fPack
|
||
|
||
cleq r0, r0, fPrint
|
||
cleq r0, r0, newline
|
||
|
||
halt
|
||
|
||
cleq r0, r0, readline
|
||
|
||
load r0, linelen+0
|
||
load r1, linelen+1
|
||
cleq r0, r0, pushWord
|
||
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, stPrinthex
|
||
|
||
xor r0, r0
|
||
xor r1, r1
|
||
cleq r0, r0, pushWord
|
||
|
||
printloop:
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stGtEq
|
||
brneq r0, r1, printend
|
||
|
||
cleq r0, r0, stDup
|
||
load r0, linebufStart+0
|
||
load r1, linebufStart+1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stAdd
|
||
|
||
cleq r0, r0, stLoadByte
|
||
cleq r0, r0, stEmit
|
||
|
||
cleq r0, r0, stInc
|
||
|
||
breq r0, r0, printloop
|
||
|
||
printend:
|
||
cleq r0, r0, newline
|
||
halt
|
||
|
||
dumpFloat:
|
||
xor r0, r0
|
||
load r1, #12
|
||
cleq r0, r0, pushWord
|
||
dumpFloatLoop:
|
||
cleq r0, r0, peekWord
|
||
or r0, r1
|
||
xor r2, r2
|
||
breq r0, r2, dumpFloatEnd
|
||
cleq r0, r0, stDec
|
||
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, stLoadByte
|
||
cleq r0, r0, popWord
|
||
xor r0, r0
|
||
or r0, r1
|
||
cleq r0, r0, writehexByte
|
||
load r0, #20
|
||
store ffff, r0
|
||
cleq r0, r0, stInc
|
||
cleq r0, r0, stSwap
|
||
breq r0, r0, dumpFloatLoop
|
||
|
||
dumpFloatEnd:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, popWord
|
||
breq r0, r0, newline
|
||
|
||
|
||
debug:
|
||
store debugr0, r0
|
||
store debugr1, r1
|
||
store debugr2, r2
|
||
store debugr3, r3
|
||
|
||
debugRegs:
|
||
load r0, debugr0
|
||
cleq r0, r0, writehexByte
|
||
load r0, #20
|
||
store ffff, r0
|
||
|
||
load r0, debugr1
|
||
cleq r0, r0, writehexByte
|
||
load r0, #20
|
||
store ffff, r0
|
||
|
||
load r0, debugr2
|
||
cleq r0, r0, writehexByte
|
||
load r0, #20
|
||
store ffff, r0
|
||
|
||
load r0, debugr3
|
||
cleq r0, r0, writehexByte
|
||
load r0, #20
|
||
store ffff, r0
|
||
|
||
debugTmpWords:
|
||
load r0, tmpWordHigh
|
||
load r1, tmpWordLow
|
||
cleq r0, r0, writeHexWord
|
||
load r0, #20
|
||
store ffff, r0
|
||
|
||
load r0, tmpWord2High
|
||
load r1, tmpWord2Low
|
||
cleq r0, r0, writeHexWord
|
||
load r0, #20
|
||
store ffff, r0
|
||
|
||
load r0, tmpWord3High
|
||
load r1, tmpWord3Low
|
||
cleq r0, r0, writeHexWord
|
||
load r0, #7c
|
||
store ffff, r0
|
||
|
||
load r0, SPStart+0
|
||
load r1, SPStart+1
|
||
store debugPtr+0, r0
|
||
store debugPtr+1, r1
|
||
|
||
debugLoop:
|
||
load r0, debugPtr+0
|
||
load r1, debugPtr+1
|
||
load r2, SP+0
|
||
load r3, SP+1
|
||
|
||
brneq r0, r2, debugDumpword
|
||
breq r1, r3, debugEnd
|
||
|
||
debugDumpword:
|
||
load r0, debugPtr+0
|
||
load r1, debugPtr+1
|
||
store loadByteHigh, r0
|
||
store loadByteLow, r1
|
||
cleq r0, r0, loadByte
|
||
cleq r0, r0, writehexByte
|
||
|
||
load r0, debugPtr+0
|
||
load r1, debugPtr+1
|
||
cleq r0, r0, incWord
|
||
store debugPtr+0, r0
|
||
store debugPtr+1, r1
|
||
|
||
load r0, debugPtr+0
|
||
load r1, debugPtr+1
|
||
store loadByteHigh, r0
|
||
store loadByteLow, r1
|
||
cleq r0, r0, loadByte
|
||
cleq r0, r0, writehexByte
|
||
|
||
load r0, debugPtr+0
|
||
load r1, debugPtr+1
|
||
cleq r0, r0, incWord
|
||
store debugPtr+0, r0
|
||
store debugPtr+1, r1
|
||
|
||
load r0, #20
|
||
store ffff, r0
|
||
|
||
breq r0, r0, debugLoop
|
||
|
||
debugEnd:
|
||
cleq r0, r0, newline
|
||
|
||
load r0, debugr0
|
||
load r1, debugr1
|
||
load r2, debugr2
|
||
load r3, debugr3
|
||
|
||
ret
|
||
|
||
debugPtr: addr debugPtr
|
||
debugr0: data 0
|
||
debugr1: data 0
|
||
debugr2: data 0
|
||
debugr3: data 0
|
||
|
||
; --
|
||
readline:
|
||
; Current index starts at 0
|
||
xor r0, r0
|
||
xor r1, r1
|
||
cleq r0, r0, pushWord
|
||
|
||
readlineLoop:
|
||
; Read a byte of input
|
||
cleq r0, r0, stKey
|
||
|
||
; Is it enter?
|
||
cleq r0, r0, peekWord
|
||
load r0, #0d
|
||
breq r0, r1, readlineEnter
|
||
|
||
; Is it backspace?
|
||
load r0, #08
|
||
breq r0, r1, readlineBackspace
|
||
|
||
; Is the buffer full?
|
||
cleq r0, r0, stOver
|
||
load r0, linebufSize+0
|
||
load r1, linebufSize+1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stGtEq
|
||
brneq r0, r1, readlineBufFull
|
||
|
||
; Calculate address
|
||
cleq r0, r0, stOver
|
||
load r0, linebufStart+0
|
||
load r1, linebufStart+1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stAdd
|
||
|
||
; Store the read byte
|
||
cleq r0, r0, stStoreByte
|
||
|
||
; Increase index
|
||
cleq r0, r0, stInc
|
||
|
||
breq r0, r0, readlineLoop
|
||
|
||
readlineEnter:
|
||
; Remove the CR byte off the stack, as it's not needed
|
||
cleq r0, r0, popWord
|
||
|
||
cleq r0, r0, popWord
|
||
store linelen+0, r0
|
||
store linelen+1, r1
|
||
|
||
breq r0, r0, newline
|
||
|
||
readlineBackspace:
|
||
; Remove the BS byte off the stack
|
||
cleq r0, r0, popWord
|
||
|
||
; Are we at the beginning of the line?
|
||
cleq r0, r0, stDup
|
||
xor r0, r0
|
||
xor r1, r1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stGtEq
|
||
brneq r0, r1, readlineLoop
|
||
|
||
; Decrease the index and erase the echoed character
|
||
; TODO: utf-8
|
||
cleq r0, r0, stDec
|
||
load r3, #20
|
||
store ffff, r3
|
||
load r3, #08
|
||
store ffff, r3
|
||
|
||
breq r0, r0, readlineLoop
|
||
|
||
readlineBufFull:
|
||
; Drop the input byte and erase the echoed character
|
||
; TODO: utf-8
|
||
cleq r0, r0, popWord
|
||
load r3, #08
|
||
store ffff, r3
|
||
load r3, #20
|
||
store ffff, r3
|
||
load r3, #08
|
||
store ffff, r3
|
||
breq r0, r0, readlineLoop
|
||
|
||
; ==================================================================
|
||
; Floating point
|
||
; ==================================================================
|
||
|
||
; ------------------------------------------------------------------
|
||
; Format conversion
|
||
; ------------------------------------------------------------------
|
||
|
||
; When on-stack, a floating point number uses an 8-byte packed BCD format
|
||
; 0 1 2 3 4 5 6 7
|
||
; seee mmmm mmmm mmmm
|
||
; |\_/ \____________/
|
||
; | | |
|
||
; | | mantissa, first digit being before and rest after the point
|
||
; | exponent, with a bias of 500 (i.e. value of 0 means ×10⁻⁵⁰⁰)
|
||
; sign, 00 for non-negative, 01 for negative, 02 for overflow
|
||
|
||
; For operation, the format is instead an 18-byte unpacked BCD format
|
||
; 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11
|
||
; 0s 0e 0e 0e 0o 0m 0m 0m 0m 0m 0m 0m 0m 0m 0m 0m 0m 0r
|
||
; | \______/ | \_________________________________/ |
|
||
; | | | | extra digit for rounding
|
||
; | | | mantissa
|
||
; | | extra digit for overflow
|
||
; | exponent
|
||
; sign
|
||
|
||
; f ptr --
|
||
fUnpack:
|
||
; Start from the end
|
||
xor r0, r0
|
||
load r1, #11
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stAdd
|
||
|
||
; Zero out rounding digit
|
||
xor r0, r0
|
||
xor r1, r1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stStoreByte
|
||
cleq r0, r0, stDec
|
||
|
||
; Mantissa
|
||
cleq r0, r0, fUnpackWord
|
||
cleq r0, r0, fUnpackWord
|
||
cleq r0, r0, fUnpackWord
|
||
|
||
; Zero out overflow digit
|
||
xor r0, r0
|
||
xor r1, r1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stStoreByte
|
||
cleq r0, r0, stDec
|
||
|
||
; Sign and exponent
|
||
cleq r0, r0, fUnpackWord
|
||
|
||
; Clear off the pointer from the stack
|
||
breq r0, r0, popWord
|
||
|
||
; w ptr -- ptr-4
|
||
fUnpackWord:
|
||
; Low nybble of low byte
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stLowNybble
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stStoreByte
|
||
cleq r0, r0, stDec
|
||
|
||
; High nybble of low byte
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stShr4
|
||
cleq r0, r0, stLowNybble
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stStoreByte
|
||
cleq r0, r0, stDec
|
||
|
||
; Low nybble of high byte
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stShr8
|
||
cleq r0, r0, stLowNybble
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stStoreByte
|
||
cleq r0, r0, stDec
|
||
|
||
; High nybble of high byte
|
||
cleq r0, r0, stSwap ; Clear off the word from the stack
|
||
cleq r0, r0, stShr8
|
||
cleq r0, r0, stShr4
|
||
cleq r0, r0, stLowNybble
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stStoreByte
|
||
breq r0, r0, stDec
|
||
|
||
; ptr -- f
|
||
fPack:
|
||
; Sign and exponent
|
||
cleq r0, r0, fPackWord
|
||
|
||
; Skip over the overflow digit
|
||
cleq r0, r0, stInc
|
||
|
||
; Mantissa
|
||
cleq r0, r0, fPackWord
|
||
cleq r0, r0, fPackWord
|
||
cleq r0, r0, fPackWord
|
||
|
||
; Clean off the pointer from stack
|
||
breq r0, r0, popWord
|
||
|
||
; ptr -- w ptr+4
|
||
fPackWord:
|
||
; High nybble of high byte
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, stLoadByte
|
||
cleq r0, r0, stShl8
|
||
cleq r0, r0, stShl4
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stInc
|
||
cleq r0, r0, stSwap
|
||
|
||
; Low nybble of high byte
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stLoadByte
|
||
cleq r0, r0, stShl8
|
||
cleq r0, r0, stOr
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stInc
|
||
cleq r0, r0, stSwap
|
||
|
||
; High nybble of low byte
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stLoadByte
|
||
cleq r0, r0, stShl4
|
||
cleq r0, r0, stOr
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stInc
|
||
cleq r0, r0, stSwap
|
||
|
||
; Low nybble of low byte
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stLoadByte
|
||
cleq r0, r0, stOr
|
||
cleq r0, r0, stSwap
|
||
breq r0, r0, stInc
|
||
|
||
; ------------------------------------------------------------------
|
||
; Unpacked floating point variables
|
||
; ------------------------------------------------------------------
|
||
|
||
fArg1Ptr: addr fArg1
|
||
fArg1:
|
||
data 00 ; sign
|
||
data 00 ; exponent
|
||
data 00
|
||
data 00
|
||
data 00 ; overflow
|
||
data 00 ; mantissa
|
||
data 00
|
||
data 00
|
||
data 00
|
||
data 00
|
||
data 00
|
||
data 00
|
||
data 00
|
||
data 00
|
||
data 00
|
||
data 00
|
||
data 00
|
||
data 00 ; rounding
|
||
|
||
fResultPtr: addr fResult
|
||
fResult:
|
||
data 00 ; sign
|
||
data 05 ; exponent
|
||
data 00
|
||
data 00
|
||
data 09 ; overflow
|
||
data 09 ; mantissa
|
||
data 09
|
||
data 09
|
||
data 09
|
||
data 09
|
||
data 09
|
||
data 09
|
||
data 09
|
||
data 09
|
||
data 09
|
||
data 09
|
||
data 09
|
||
data 04 ; rounding
|
||
|
||
; ------------------------------------------------------------------
|
||
; Arithmetic
|
||
; ------------------------------------------------------------------
|
||
|
||
; x y z -- tens(x+y+z) ones(x+y+z)
|
||
bcdDigitAdd3:
|
||
cleq r0, r0, stAdd
|
||
|
||
cleq r0, r0, stDup
|
||
xor r0, r0
|
||
load r1, #a
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stGtEq
|
||
breq r0, r1, bcdDigitAdd
|
||
|
||
; Adjust so that carry is in the high 3 bits
|
||
; Basically we want 9+1=a₁₆ to become 20₁₆
|
||
xor r0, r0
|
||
load r1, #16
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stAdd
|
||
|
||
; x y -- tens(x+y) ones(x+y)
|
||
bcdDigitAdd:
|
||
cleq r0, r0, stAdd
|
||
|
||
cleq r0, r0, stDup
|
||
; Only look at the bottom 5 bits, since high 3 bits may already
|
||
; contain carry
|
||
cleq r0, r0, popWord
|
||
load r2, #1f
|
||
and r1, r2
|
||
cleq r0, r0, pushWord
|
||
xor r0, r0
|
||
load r1, #a
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stGtEq
|
||
breq r0, r1, bcdDigitAddNoAdjust
|
||
|
||
; Adjust so that carry is in the high 3 bits
|
||
; Basically we want 9+1=a₁₆ to become 20₁₆
|
||
xor r0, r0
|
||
load r1, #16
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stAdd
|
||
|
||
bcdDigitAddNoAdjust:
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, stShr4
|
||
cleq r0, r0, stShr1
|
||
cleq r0, r0, stSwap
|
||
breq r0, r0, stLowNybble
|
||
|
||
; x -- 9-x
|
||
bcdDigit9sComplement:
|
||
xor r0, r0
|
||
load r1, #9
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stSwap
|
||
breq r0, r0, stSub
|
||
|
||
; ptr --
|
||
incExponent:
|
||
; Ones
|
||
xor r0, r0
|
||
load r1, #3
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stAdd
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, stLoadByte
|
||
xor r0, r0
|
||
load r1, #1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, bcdDigitAdd
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stStoreByte
|
||
|
||
; Tens
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stDec
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stLoadByte
|
||
cleq r0, r0, bcdDigitAdd
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stStoreByte
|
||
|
||
; Hundreds
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stDec
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stLoadByte
|
||
cleq r0, r0, bcdDigitAdd
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, popWord
|
||
brneq r0, r1, incExponentOverflow
|
||
cleq r0, r0, stSwap
|
||
breq r0, r0, stStoreByte
|
||
|
||
incExponentOverflow:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, stDec
|
||
xor r0, r0
|
||
load r1, #2
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stSwap
|
||
breq r0, r0, stStoreByte
|
||
|
||
; ptr --
|
||
decExponent:
|
||
; Ones
|
||
xor r0, r0
|
||
load r1, #3
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stAdd
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, stLoadByte
|
||
xor r0, r0
|
||
load r1, #9
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, bcdDigitAdd
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stStoreByte
|
||
|
||
; Tens
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stDec
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stLoadByte
|
||
xor r0, r0
|
||
load r1, #9
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, bcdDigitAdd3
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stStoreByte
|
||
|
||
; Ones
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stDec
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stLoadByte
|
||
xor r0, r0
|
||
load r1, #9
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, bcdDigitAdd3
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, popWord
|
||
breq r0, r1, error ; Should never underflow
|
||
cleq r0, r0, stSwap
|
||
breq r0, r0, stStoreByte
|
||
|
||
; ptr --
|
||
shiftMantissaLeft:
|
||
; Shift-in a zero to zero-out the rightmost mantissa digit
|
||
xor r0, r0
|
||
xor r1, r1
|
||
cleq r0, r0, pushWord
|
||
|
||
; Starting at the end of the extended mantissa
|
||
cleq r0, r0, stSwap
|
||
xor r0, r0
|
||
load r1, #11
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stAdd
|
||
|
||
; We run the loop 14 times
|
||
xor r0, r0
|
||
load r1, #e
|
||
cleq r0, r0, pushWord
|
||
|
||
shiftMantissaLeftLoop:
|
||
; See if loop counter hit zero and decrement if not
|
||
cleq r0, r0, peekWord
|
||
or r0, r1
|
||
xor r2, r2
|
||
breq r0, r2, shiftMantissaLeftEnd
|
||
cleq r0, r0, stDec
|
||
|
||
; Load ("shift-out") the current value at pointer
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, stLoadByte
|
||
|
||
; Store ("shift-in") the previous value
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stStoreByte
|
||
|
||
; Decrememnt pointer and put stack back in order
|
||
cleq r0, r0, stDec
|
||
cleq r0, r0, stRot
|
||
|
||
breq r0, r0, shiftMantissaLeftLoop
|
||
|
||
shiftMantissaLeftEnd:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, popWord
|
||
breq r0, r0, popWord
|
||
|
||
; ptr --
|
||
shiftMantissaRight:
|
||
; Shift-in a zero to zero-out the leftmost mantissa digit
|
||
xor r0, r0
|
||
xor r1, r1
|
||
cleq r0, r0, pushWord
|
||
|
||
; Starting at the beginning of the extended mantissa
|
||
cleq r0, r0, stSwap
|
||
xor r0, r0
|
||
load r1, #4
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stAdd
|
||
|
||
; We run the loop 14 times
|
||
xor r0, r0
|
||
load r1, #e
|
||
cleq r0, r0, pushWord
|
||
|
||
shiftMantissaRightLoop:
|
||
; See if loop counter hit zero and decrement if not
|
||
cleq r0, r0, peekWord
|
||
or r0, r1
|
||
xor r2, r2
|
||
breq r0, r2, shiftMantissaRightEnd
|
||
cleq r0, r0, stDec
|
||
|
||
; Load ("shift-out") the current value at pointer
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, stLoadByte
|
||
|
||
; Store ("shift-in") the previous value
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stStoreByte
|
||
|
||
; Increment pointer and put stack back in order
|
||
cleq r0, r0, stInc
|
||
cleq r0, r0, stRot
|
||
|
||
breq r0, r0, shiftMantissaRightLoop
|
||
|
||
shiftMantissaRightEnd:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, popWord
|
||
breq r0, r0, popWord
|
||
|
||
; --
|
||
normalize:
|
||
; Do we have a digit in overflow?
|
||
load r0, fResult+4
|
||
xor r1, r1
|
||
breq r0, r1, normalizeNoOverflow
|
||
|
||
load r0, fResultPtr+0
|
||
load r1, fResultPtr+1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, shiftMantissaRight
|
||
cleq r0, r0, incExponent
|
||
|
||
; Did we overflow the exponent?
|
||
load r0, fResult+0
|
||
load r1, #2
|
||
breq r0, r1, normalizeEnd
|
||
|
||
normalizeNoOverflow:
|
||
; Is extended mantissa all zeroes?
|
||
load r0, fResult+4
|
||
load r1, fResult+5
|
||
or r0, r1
|
||
load r1, fResult+6
|
||
or r0, r1
|
||
load r1, fResult+7
|
||
or r0, r1
|
||
load r1, fResult+8
|
||
or r0, r1
|
||
load r1, fResult+9
|
||
or r0, r1
|
||
load r1, fResult+a
|
||
or r0, r1
|
||
load r1, fResult+b
|
||
or r0, r1
|
||
load r1, fResult+c
|
||
or r0, r1
|
||
load r1, fResult+d
|
||
or r0, r1
|
||
load r1, fResult+e
|
||
or r0, r1
|
||
load r1, fResult+f
|
||
or r0, r1
|
||
load r1, fResult+10
|
||
or r0, r1
|
||
load r1, fResult+11
|
||
or r0, r1
|
||
|
||
xor r1, r1
|
||
brneq r0, r1, normalizeNonZero
|
||
|
||
; Zero out the entire number
|
||
; This causes sign to be 0 (non-negative), exponent -500, and
|
||
; extended mantissa 00.000000000000
|
||
load r0, fResultPtr+0
|
||
load r1, fResultPtr+1
|
||
cleq r0, r0, pushWord
|
||
xor r0, r0
|
||
load r1, #12
|
||
cleq r0, r0, pushWord
|
||
breq r0, r0, stZeroMem ; returns
|
||
|
||
normalizeNonZero:
|
||
normalizeTooSmallMantissa:
|
||
; Do we have a zero as the digit before the point?
|
||
load r0, fResult+5
|
||
xor r1, r1
|
||
brneq r0, r1, normalizeMantissaNormalized
|
||
|
||
; Can we decrement the exponent?
|
||
load r0, fResult+1
|
||
load r1, fResult+2
|
||
or r0, r1
|
||
load r2, fResult+3
|
||
or r0, r1
|
||
|
||
xor r1, r1
|
||
breq r0, r1, normalizeMantissaNormalized
|
||
|
||
load r0, fResultPtr+0
|
||
load r1, fResultPtr+1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stDup
|
||
cleq r0, r0, shiftMantissaLeft
|
||
cleq r0, r0, decExponent
|
||
|
||
breq r0, r0, normalizeTooSmallMantissa
|
||
|
||
normalizeMantissaNormalized:
|
||
; Is the rounding digit at least 5?
|
||
load r0, fResult+11
|
||
xor r1, r1
|
||
breq r0, r1, normalizeRoundDown
|
||
load r1, #1
|
||
breq r0, r1, normalizeRoundDown
|
||
load r1, #2
|
||
breq r0, r1, normalizeRoundDown
|
||
load r1, #3
|
||
breq r0, r1, normalizeRoundDown
|
||
load r1, #4
|
||
breq r0, r1, normalizeRoundDown
|
||
|
||
normalizeRoundUp:
|
||
; Pointer to last digit of non-extended mantissa
|
||
load r0, fResultPtr+0
|
||
load r1, fResultPtr+1
|
||
cleq r0, r0, pushWord
|
||
xor r0, r0
|
||
load r1, #10
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stAdd
|
||
|
||
; Carry-in is 1 since we are rounding up
|
||
xor r0, r0
|
||
load r1, #1
|
||
cleq r0, r0, pushWord
|
||
|
||
; Number of times to run the loop
|
||
xor r0, r0
|
||
load r1, #d ; 12 normal mantissa + 1 overflow
|
||
cleq r0, r0, pushWord
|
||
|
||
normalizeRoundUpLoop:
|
||
cleq r0, r0, peekWord
|
||
or r0, r1
|
||
xor r2, r2
|
||
breq r0, r2, normalizeRoundUpEnd
|
||
cleq r0, r0, stDec
|
||
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stLoadByte
|
||
cleq r0, r0, bcdDigitAdd
|
||
cleq r0, r0, stRot
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stOver
|
||
cleq r0, r0, stStoreByte
|
||
cleq r0, r0, stDec
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stRot
|
||
|
||
breq r0, r0, normalizeRoundUpLoop
|
||
|
||
normalizeRoundUpEnd:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, popWord
|
||
|
||
; Zero out the rounding digit
|
||
xor r0, r0
|
||
store fResult+11, r0
|
||
|
||
; We might have ended up with a digit in the overflow
|
||
breq r0, r0, normalize
|
||
|
||
normalizeRoundDown:
|
||
; Zero out the rounding digit
|
||
xor r0, r0
|
||
store fResult+11, r0
|
||
|
||
normalizeEnd:
|
||
ret
|
||
|
||
; ------------------------------------------------------------------
|
||
; Output
|
||
; ------------------------------------------------------------------
|
||
|
||
fPrint:
|
||
load r0, fArg1Ptr+0
|
||
load r1, fArg1Ptr+1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, fUnpack
|
||
|
||
; Overflow?
|
||
load r0, fArg1+0
|
||
load r1, #2
|
||
breq r0, r1, fPrintOverflow
|
||
|
||
; Negative?
|
||
load r1, #1
|
||
brneq r0, r1, fPrintMantissa
|
||
|
||
load r0, #2d ; -
|
||
store ffff, r0
|
||
|
||
fPrintMantissa:
|
||
load r0, fArg1+5
|
||
cleq r0, r0, writehexNybble
|
||
|
||
load r0, #2e ; .
|
||
store ffff, r0
|
||
|
||
load r0, fArg1+6
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+7
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+8
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+9
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+a
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+b
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+c
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+d
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+e
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+f
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+10
|
||
cleq r0, r0, writehexNybble
|
||
|
||
fPrintExponent:
|
||
load r0, #65 ; e
|
||
store ffff, r0
|
||
|
||
; Adjust the hundreds digit for the bias
|
||
xor r0, r0,
|
||
load r1, fArg1+1
|
||
cleq r0, r0, pushWord
|
||
xor r0, r0
|
||
load r1, #5
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, bcdDigitAdd
|
||
|
||
; Is the exponent negative?
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, popWord
|
||
breq r0, r1, fPrintNegativeExponent
|
||
|
||
cleq r0, r0, popWord
|
||
xor r0, r0
|
||
or r0, r1
|
||
cleq r0, r0, writehexNybble
|
||
|
||
load r0, fArg1+2
|
||
cleq r0, r0, writehexNybble
|
||
load r0, fArg1+3
|
||
breq r0, r0, writehexNybble
|
||
|
||
fPrintNegativeExponent:
|
||
cleq r0, r0, popWord ; Remove result we don't need
|
||
load r0, #2d ; -
|
||
store ffff, r0
|
||
|
||
; The exponent is stored with a bias of 500
|
||
; unbiased + 500 = biased
|
||
; By this point we know unbiased < 0 and have printed the minus
|
||
; sign, so we want to print the negative of unbiased
|
||
; unbiased + 500 = biased
|
||
; unbiased = -500 + biased
|
||
; -unbiased = 500 - biased
|
||
|
||
; We implement subtraction using 9's complement, where each
|
||
; digit of the subtrahend is subtracted from 9 before being
|
||
; added to the corresponding minuend. This by itself gives a
|
||
; result that is one too small, so we add one to it (c.f. binary
|
||
; subtraction, where we negate the subtrahend and then add one).
|
||
; 500 + 1 + 999 - biased
|
||
; = 500 + 1000 - biased (1000 = 0 mod 1000)
|
||
; = 500 - biased
|
||
|
||
; Ones
|
||
xor r0, r0
|
||
load r1, #1
|
||
cleq r0, r0, pushWord
|
||
xor r0, r0
|
||
load r1, fArg1+3
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, bcdDigit9sComplement
|
||
cleq r0, r0, bcdDigitAdd
|
||
cleq r0, r0, stSwap
|
||
|
||
; Tens
|
||
xor r0, r0
|
||
load r1, fArg1+2
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, bcdDigit9sComplement
|
||
cleq r0, r0, bcdDigitAdd
|
||
cleq r0, r0, stSwap
|
||
|
||
; Hundreds
|
||
xor r0, r0
|
||
load r1, #5
|
||
cleq r0, r0, pushWord
|
||
xor r0, r0
|
||
load r1, fArg1+1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, bcdDigit9sComplement
|
||
cleq r0, r0, bcdDigitAdd3
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, popWord
|
||
|
||
; Print
|
||
cleq r0, r0, popWord
|
||
xor r0, r0
|
||
or r0, r1
|
||
cleq r0, r0, writehexNybble
|
||
cleq r0, r0, popWord
|
||
xor r0, r0
|
||
or r0, r1
|
||
cleq r0, r0, writehexNybble
|
||
cleq r0, r0, popWord
|
||
xor r0, r0
|
||
or r0, r1
|
||
breq r0, r0, writehexNybble
|
||
|
||
fPrintOverflow:
|
||
load r0, #4f ; O
|
||
store ffff, r0
|
||
load r0, #76 ; v
|
||
store ffff, r0
|
||
load r0, #65 ; e
|
||
store ffff, r0
|
||
load r0, #72 ; r
|
||
store ffff, r0
|
||
load r0, #66 ; f
|
||
store ffff, r0
|
||
load r0, #6c ; l
|
||
store ffff, r0
|
||
load r0, #6f ; o
|
||
store ffff, r0
|
||
load r0, #77 ; w
|
||
store ffff, r0
|
||
ret
|
||
|
||
; ==================================================================
|
||
; Stack-based functions
|
||
; ==================================================================
|
||
|
||
; ------------------------------------------------------------------
|
||
; Arithmetic
|
||
; ------------------------------------------------------------------
|
||
|
||
; a b -- a+b
|
||
stAdd:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpStoreWord01
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpLoadWord23
|
||
cleq r0, r0, addWord
|
||
breq r0, r0, pushWord
|
||
|
||
; a b -- a-b
|
||
stSub:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpStoreWord01
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpLoadWord23
|
||
cleq r0, r0, subWord
|
||
breq r0, r0, pushWord
|
||
|
||
; a -- a+1
|
||
stInc:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, incWord
|
||
breq r0, r0, pushWord
|
||
|
||
; a -- a-1
|
||
stDec:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, decWord
|
||
breq r0, r0, pushWord
|
||
|
||
; a b -- a|b
|
||
stOr:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpStoreWord01
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpLoadWord23
|
||
or r0, r2
|
||
or r1, r3
|
||
breq r0, r0, pushWord
|
||
|
||
; a -- a<<8
|
||
stShl8:
|
||
cleq r0, r0, popWord
|
||
xor r0, r0
|
||
or r0, r1
|
||
xor r1, r1
|
||
breq r0, r0, pushWord
|
||
|
||
; a -- a>>8
|
||
stShr8:
|
||
cleq r0, r0, popWord
|
||
xor r1, r1
|
||
or r1, r0
|
||
xor r0, r0
|
||
breq r0, r0, pushWord
|
||
|
||
; a -- a<<4
|
||
stShl4:
|
||
cleq r0, r0, popWord
|
||
shl r0, 4
|
||
xor r2, r2
|
||
or r2, r1
|
||
shr r2, 4
|
||
or r0, r2
|
||
shl r1, 4
|
||
breq r0, r0, pushWord
|
||
|
||
; a -- a>>4
|
||
stShr4:
|
||
cleq r0, r0, popWord
|
||
shr r1, 4
|
||
xor r2, r2
|
||
or r2, r0
|
||
shl r2, 4
|
||
or r1, r2
|
||
shr r0, 4
|
||
breq r0, r0, pushWord
|
||
|
||
; a -- a>>1
|
||
stShr1:
|
||
cleq r0, r0, popWord
|
||
shr r1, 1
|
||
xor r2, r2
|
||
or r2, r0
|
||
shl r2, 4
|
||
shl r2, 3
|
||
or r1, r2
|
||
shr r0, 1
|
||
breq r0, r0, pushWord
|
||
|
||
; a -- a&f
|
||
stLowNybble:
|
||
cleq r0, r0, popWord
|
||
xor r0, r0
|
||
load r2, #f
|
||
and r1, r2
|
||
breq r0, r0, pushWord
|
||
|
||
; a b --
|
||
; if a >= b then r0:r1 = 0001
|
||
; else r0:r1 = 0000
|
||
stGtEq:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpStoreWord01
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpLoadWord23
|
||
cleq r0, r0, subWord
|
||
xor r0, r0
|
||
xor r1, r1
|
||
or r1, r2
|
||
ret
|
||
|
||
; ------------------------------------------------------------------
|
||
; I/O
|
||
; ------------------------------------------------------------------
|
||
|
||
; n -- n
|
||
stPrinthex:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, writehexWord
|
||
breq r0, r0, newline
|
||
|
||
; -- c
|
||
stKey:
|
||
xor r0, r0
|
||
load r1, ffff
|
||
breq r0, r0, pushWord
|
||
|
||
; c --
|
||
stEmit:
|
||
cleq r0, r0, popWord
|
||
store ffff, r1
|
||
ret
|
||
|
||
; ------------------------------------------------------------------
|
||
; Stack manipulation
|
||
; ------------------------------------------------------------------
|
||
|
||
; a - a a
|
||
stDup:
|
||
cleq r0, r0, peekWord
|
||
breq r0, r0, pushWord
|
||
|
||
; a b -- a b a
|
||
stOver:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpStoreWord01
|
||
cleq r0, r0, peekWord
|
||
cleq r0, r0, tmp2StoreWord01
|
||
cleq r0, r0, tmpLoadWord01
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, tmp2LoadWord01
|
||
breq r0, r0, pushWord
|
||
|
||
; a b -- b a
|
||
stSwap:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpStoreWord01
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmp2StoreWord01
|
||
cleq r0, r0, tmpLoadWord01
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, tmp2LoadWord01
|
||
breq r0, r0, pushWord
|
||
|
||
; a b c -- b c a
|
||
stRot:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpStoreWord01
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmp2StoreWord01
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmp3StoreWord01
|
||
cleq r0, r0, tmp2LoadWord01
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, tmpLoadWord01
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, tmp3LoadWord01
|
||
breq r0, r0, pushWord
|
||
|
||
; ------------------------------------------------------------------
|
||
; Memory
|
||
; ------------------------------------------------------------------
|
||
|
||
; b ptr --
|
||
stStoreByte:
|
||
cleq r0, r0, popWord
|
||
store storeByteHigh, r0
|
||
store storeByteLow, r1
|
||
cleq r0, r0, popWord
|
||
xor r0, r0
|
||
or r0, r1
|
||
breq r0, r0, storeByte
|
||
|
||
; ptr -- b
|
||
stLoadByte:
|
||
cleq r0, r0, popWord
|
||
store loadByteHigh, r0
|
||
store loadByteLow, r1
|
||
cleq r0, r0, loadByte
|
||
xor r1, r1
|
||
or r1, r0
|
||
xor r0, r0
|
||
breq r0, r0, pushWord
|
||
|
||
; n ptr --
|
||
stStoreWord:
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, tmpStoreWord01
|
||
store storeByteHigh, r0
|
||
store storeByteLow, r1
|
||
cleq r0, r0, peekWord
|
||
cleq r0, r0, storeByte
|
||
cleq r0, r0, tmpLoadWord01
|
||
cleq r0, r0, incWord
|
||
store storeByteHigh, r0
|
||
store storeByteLow, r1
|
||
cleq r0, r0, popWord
|
||
xor r0, r0
|
||
or r0, r1
|
||
breq r0, r0, storeByte
|
||
|
||
; ptr -- n
|
||
stLoadWord:
|
||
cleq r0, r0, peekWord
|
||
store loadByteHigh, r0
|
||
store loadByteLow, r1
|
||
cleq r0, r0, loadByte
|
||
cleq r0, r0, tmpStoreWord01
|
||
cleq r0, r0, popWord
|
||
cleq r0, r0, incWord
|
||
store loadByteHigh, r0
|
||
store loadByteLow, r1
|
||
cleq r0, r0, loadByte
|
||
xor r2, r2
|
||
or r2, r0
|
||
cleq r0, r0, tmpLoadWord01
|
||
xor r1, r1
|
||
or r1, r2
|
||
breq r0, r0, pushWord
|
||
|
||
; ptr n --
|
||
stZeroMem:
|
||
cleq r0, r0, peekWord
|
||
or r0, r1
|
||
xor r2, r2
|
||
breq r0, r2, stZeroMemDone
|
||
|
||
cleq r0, r0, stDec
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stDup
|
||
xor r0, r0
|
||
xor r1, r1
|
||
cleq r0, r0, pushWord
|
||
cleq r0, r0, stSwap
|
||
cleq r0, r0, stStoreByte
|
||
cleq r0, r0, stInc
|
||
cleq r0, r0, stSwap
|
||
breq r0, r0, stZeroMem
|
||
|
||
stZeroMemDone:
|
||
ret
|
||
|
||
; ==================================================================
|
||
; Low-level functions
|
||
; ==================================================================
|
||
|
||
; ------------------------------------------------------------------
|
||
; Memory
|
||
; ------------------------------------------------------------------
|
||
|
||
tmpWordHigh: data 0
|
||
tmpWordLow: data 0
|
||
tmpWord2High: data 0
|
||
tmpWord2Low: data 0
|
||
tmpWord3High: data 0
|
||
tmpWord3Low: data 0
|
||
|
||
; in:
|
||
; r0:r1 = word
|
||
tmpStoreWord01:
|
||
store tmpWordHigh, r0
|
||
store tmpWordLow, r1
|
||
ret
|
||
|
||
; out:
|
||
; r0:r1 = word
|
||
tmpLoadWord01:
|
||
load r0, tmpWordHigh
|
||
load r1, tmpWordLow
|
||
ret
|
||
|
||
; out:
|
||
; r2:r3 = word
|
||
tmpLoadWord23:
|
||
load r2, tmpWordHigh
|
||
load r3, tmpWordLow
|
||
ret
|
||
|
||
; in:
|
||
; r0:r1 = word
|
||
tmp2StoreWord01:
|
||
store tmpWord2High, r0
|
||
store tmpWord2Low, r1
|
||
ret
|
||
|
||
; out:
|
||
; r0:r1 = word
|
||
tmp2LoadWord01:
|
||
load r0, tmpWord2High
|
||
load r1, tmpWord2Low
|
||
ret
|
||
|
||
; in:
|
||
; r0:r1 = word
|
||
tmp3StoreWord01:
|
||
store tmpWord3High, r0
|
||
store tmpWord3Low, r1
|
||
ret
|
||
|
||
; out:
|
||
; r0:r1 = word
|
||
tmp3LoadWord01:
|
||
load r0, tmpWord3High
|
||
load r1, tmpWord3Low
|
||
ret
|
||
|
||
; out:
|
||
; r0:r1 = word
|
||
; clobbers:
|
||
; r2, r3
|
||
peekWord:
|
||
cleq r0, r0, popWord
|
||
store peekWordHigh, r0
|
||
store peekWordLow, r1
|
||
|
||
; Return SP back to where it was
|
||
load r0, SP+0
|
||
load r1, SP+1
|
||
xor r2, r2
|
||
load r3, #02
|
||
cleq r0, r0, addWord
|
||
store SP+0, r0
|
||
store SP+1, r1
|
||
|
||
load r0, peekWordHigh
|
||
load r1, peekWordLow
|
||
ret
|
||
|
||
peekWordHigh: data 0
|
||
peekWordLow: data 0
|
||
|
||
; in:
|
||
; r0:r1 = word
|
||
; clobbers:
|
||
; r0, r1, r2, r3
|
||
pushWord:
|
||
store pushWordLow, r1
|
||
cleq r0, r0, pushByte
|
||
load r0, pushWordLow
|
||
breq r0, r0, pushByte
|
||
|
||
pushWordLow: data 0
|
||
|
||
; out:
|
||
; r0:r1
|
||
; clobbers:
|
||
; r2, r3
|
||
popWord:
|
||
cleq r0, r0, popByte
|
||
store popWordLow, r0
|
||
|
||
cleq r0, r0, popByte
|
||
|
||
load r1, popWordLow
|
||
|
||
ret
|
||
|
||
popWordLow: data 0
|
||
|
||
; in:
|
||
; r0 = byte
|
||
; clobbers:
|
||
; r0, r1, r2, r3
|
||
pushByte:
|
||
load r2, SP+0
|
||
store storeByteHigh, r2
|
||
load r3, SP+1
|
||
store storeByteLow, r3
|
||
cleq r0, r0, storeByte
|
||
|
||
load r0, SP+0
|
||
load r1, SP+1
|
||
cleq r0, r0, incWord
|
||
store SP+0, r0
|
||
store SP+1, r1
|
||
|
||
ret
|
||
|
||
; out:
|
||
; r0 = byte
|
||
; clobbers:
|
||
; r1, r2, r3
|
||
popByte:
|
||
load r0, SP+0
|
||
load r1, SP+1
|
||
|
||
load r2, SPStart+0
|
||
load r3, SPStart+1
|
||
brneq r0, r2, popByteNoUnderflow
|
||
breq r1, r3, underflow
|
||
|
||
popByteNoUnderflow:
|
||
cleq r0, r0, decWord
|
||
store SP+0, r0
|
||
store SP+1, r1
|
||
|
||
store loadByteHigh, r0
|
||
store loadByteLow, r1
|
||
breq r0, r0, loadByte
|
||
|
||
; in:
|
||
; storeByteHigh:storeByteLow = address
|
||
; r0 = byte
|
||
storeByte:
|
||
data b0 ; store addr, r0
|
||
storeByteHigh: data 0
|
||
storeByteLow: data 0
|
||
ret
|
||
|
||
; in:
|
||
; loadByteHigh:loadByteLow = address
|
||
; out:
|
||
; r0 = byte
|
||
loadByte:
|
||
data a0 ; load r0, addr
|
||
loadByteHigh: data 0
|
||
loadByteLow: data 0
|
||
ret
|
||
|
||
; ------------------------------------------------------------------
|
||
; Arithmetic
|
||
; ------------------------------------------------------------------
|
||
|
||
; in:
|
||
; r0:r1 = first addend
|
||
; r2:r3 = second addend
|
||
; out:
|
||
; r0:r1 = result
|
||
; r2 = carryout
|
||
; clobbers:
|
||
; r3
|
||
addWord:
|
||
store addWordFirstHigh, r0
|
||
store addWordSecondHigh, r2
|
||
|
||
; Add low bytes
|
||
xor r0, r0
|
||
or r0, r3
|
||
cleq r0, r0, addByte
|
||
store addWordResultLow, r0
|
||
|
||
; Add high bytes and carry (in r1)
|
||
load r0, addWordFirstHigh
|
||
load r2, addWordSecondHigh
|
||
cleq r0, r0, addByte3
|
||
|
||
; Move carryout to r2
|
||
xor r2, r2
|
||
or r2, r1
|
||
|
||
load r1, addWordResultLow
|
||
|
||
ret
|
||
|
||
addWordFirstHigh: data 0
|
||
addWordSecondHigh: data 0
|
||
addWordResultLow: data 0
|
||
|
||
; in:
|
||
; r0:r1 = minuend
|
||
; r2:r3 = subtrahend
|
||
; out:
|
||
; r0:r1 = result
|
||
; r2 = carryout
|
||
; clobbers:
|
||
; r3
|
||
subWord:
|
||
store subWordMinuendHigh, r0
|
||
store subWordSubtrahendHigh, r2
|
||
|
||
; Subtract low bytes
|
||
; a - b = a + (-b) = a + ~b + 1
|
||
xor r0, r0
|
||
or r0, r3
|
||
nand r0, r0
|
||
load r2, #01
|
||
cleq r0, r0, addByte3
|
||
store subWordResultLow, r0
|
||
|
||
; Subtract high bytes with carry-in in r1
|
||
load r0, subWordMinuendHigh
|
||
load r2, subWordSubtrahendHigh
|
||
nand r2, r2
|
||
cleq r0, r0, addByte3
|
||
|
||
; Move carryout to r2
|
||
xor r2, r2
|
||
or r2, r1
|
||
|
||
load r1, subWordResultLow
|
||
|
||
ret
|
||
|
||
subWordMinuendHigh: data 0
|
||
subWordSubtrahendHigh: data 0
|
||
subWordResultLow: data 0
|
||
|
||
; in/out:
|
||
; r0:r1 = word
|
||
; clobbers:
|
||
; r2, r3
|
||
incWord:
|
||
store incWordHigh, r0
|
||
|
||
; Add 1 to low byte
|
||
load r0, #01
|
||
cleq r0, r0, addByte
|
||
store incWordLow, r0
|
||
|
||
; Add carry to high byte
|
||
load r0, incWordHigh
|
||
cleq r0, r0, addByte
|
||
|
||
load r1, incWordLow
|
||
|
||
ret
|
||
|
||
incWordHigh: data 0
|
||
incWordLow: data 0
|
||
|
||
; in/out:
|
||
; r0:r1 = word
|
||
; clobbers:
|
||
; r2, r3
|
||
decWord:
|
||
store decWordHigh, r0
|
||
|
||
; Add ff to low byte
|
||
load r0, #ff
|
||
cleq r0, r0, addByte
|
||
store decWordLow, r0
|
||
|
||
; Add ff and carry to high byte
|
||
load r0, #ff
|
||
load r2, decWordHigh
|
||
cleq r0, r0, addByte3
|
||
|
||
load r1, decWordLow
|
||
|
||
ret
|
||
|
||
decWordHigh: data 0
|
||
decWordLow: data 0
|
||
|
||
; in:
|
||
; r0 = first addend
|
||
; r1 = second addend
|
||
; r2 = third addend
|
||
; out:
|
||
; r0 = result
|
||
; r1 = carryout
|
||
; clobbers:
|
||
; r2, r3
|
||
addByte3:
|
||
store addByte3ThirdAddend, r2
|
||
|
||
cleq r0, r0, addByte
|
||
store addByte3Carryout, r1
|
||
|
||
load r1, addByte3ThirdAddend
|
||
cleq r0, r0, addByte
|
||
|
||
load r3, addByte3Carryout
|
||
or r1, r3
|
||
|
||
ret
|
||
|
||
addByte3ThirdAddend: data 0
|
||
addByte3Carryout: data 0
|
||
|
||
; in:
|
||
; r0 = first addend
|
||
; r1 = second addend
|
||
; out:
|
||
; r0 = result
|
||
; r1 = carryout
|
||
; clobbers:
|
||
; r2, r3
|
||
addByte:
|
||
; Initiliaze carryout to 0
|
||
xor r2, r2
|
||
|
||
addByteLoop:
|
||
; Copy second addend to r3
|
||
xor r3, r3
|
||
or r3, r1
|
||
; Calculate carries in r3
|
||
and r3, r0
|
||
or r2, r3 ; Accumulate carry into carryout
|
||
shl r3, 1
|
||
; Calculate sums in r0
|
||
xor r0, r1
|
||
; Copy carries into second addend
|
||
xor r1, r1
|
||
or r1, r3
|
||
|
||
; Loop until second addend is 0
|
||
xor r3, r3
|
||
brneq r1, r3, addByteLoop
|
||
|
||
; Shift carryout, as we want carry from highest place = 1
|
||
shr r2, 4
|
||
shr r2, 3
|
||
|
||
; Move carryout to r1
|
||
; (We know r1 is already 0 since it's the loop condition)
|
||
or r1, r2
|
||
|
||
ret
|
||
|
||
; ------------------------------------------------------------------
|
||
; Hex conversion routines
|
||
; ------------------------------------------------------------------
|
||
|
||
; in:
|
||
; r0 = number in range [0, 0xf]
|
||
; out:
|
||
; r0 = ascii character corresponding to input
|
||
; clobbers:
|
||
; r3
|
||
nybble2hex:
|
||
xor r3, r3
|
||
breq r0, r3, nybble2hex0
|
||
load r3, #01
|
||
breq r0, r3, nybble2hex1
|
||
load r3, #02
|
||
breq r0, r3, nybble2hex2
|
||
load r3, #03
|
||
breq r0, r3, nybble2hex3
|
||
load r3, #04
|
||
breq r0, r3, nybble2hex4
|
||
load r3, #05
|
||
breq r0, r3, nybble2hex5
|
||
load r3, #06
|
||
breq r0, r3, nybble2hex6
|
||
load r3, #07
|
||
breq r0, r3, nybble2hex7
|
||
load r3, #08
|
||
breq r0, r3, nybble2hex8
|
||
load r3, #09
|
||
breq r0, r3, nybble2hex9
|
||
load r3, #0a
|
||
breq r0, r3, nybble2hexa
|
||
load r3, #0b
|
||
breq r0, r3, nybble2hexb
|
||
load r3, #0c
|
||
breq r0, r3, nybble2hexc
|
||
load r3, #0d
|
||
breq r0, r3, nybble2hexd
|
||
load r3, #0e
|
||
breq r0, r3, nybble2hexe
|
||
load r3, #0f
|
||
breq r0, r3, nybble2hexf
|
||
|
||
breq r0, r0, error
|
||
|
||
nybble2hex0:
|
||
load r0, #30
|
||
ret
|
||
nybble2hex1:
|
||
load r0, #31
|
||
ret
|
||
nybble2hex2:
|
||
load r0, #32
|
||
ret
|
||
nybble2hex3:
|
||
load r0, #33
|
||
ret
|
||
nybble2hex4:
|
||
load r0, #34
|
||
ret
|
||
nybble2hex5:
|
||
load r0, #35
|
||
ret
|
||
nybble2hex6:
|
||
load r0, #36
|
||
ret
|
||
nybble2hex7:
|
||
load r0, #37
|
||
ret
|
||
nybble2hex8:
|
||
load r0, #38
|
||
ret
|
||
nybble2hex9:
|
||
load r0, #39
|
||
ret
|
||
nybble2hexa:
|
||
load r0, #61
|
||
ret
|
||
nybble2hexb:
|
||
load r0, #62
|
||
ret
|
||
nybble2hexc:
|
||
load r0, #63
|
||
ret
|
||
nybble2hexd:
|
||
load r0, #64
|
||
ret
|
||
nybble2hexe:
|
||
load r0, #65
|
||
ret
|
||
nybble2hexf:
|
||
load r0, #66
|
||
ret
|
||
|
||
; in:
|
||
; r0 = ascii hex digit
|
||
; out:
|
||
; r0 = corresponding nybble
|
||
; clobbers:
|
||
; r3
|
||
hex2nybble:
|
||
load r3, #30
|
||
breq r0, r3, hex2nybble0
|
||
load r3, #31
|
||
breq r0, r3, hex2nybble1
|
||
load r3, #32
|
||
breq r0, r3, hex2nybble2
|
||
load r3, #33
|
||
breq r0, r3, hex2nybble3
|
||
load r3, #34
|
||
breq r0, r3, hex2nybble4
|
||
load r3, #35
|
||
breq r0, r3, hex2nybble5
|
||
load r3, #36
|
||
breq r0, r3, hex2nybble6
|
||
load r3, #37
|
||
breq r0, r3, hex2nybble7
|
||
load r3, #38
|
||
breq r0, r3, hex2nybble8
|
||
load r3, #39
|
||
breq r0, r3, hex2nybble9
|
||
load r3, #61
|
||
breq r0, r3, hex2nybblea
|
||
load r3, #62
|
||
breq r0, r3, hex2nybbleb
|
||
load r3, #63
|
||
breq r0, r3, hex2nybblec
|
||
load r3, #64
|
||
breq r0, r3, hex2nybbled
|
||
load r3, #65
|
||
breq r0, r3, hex2nybblee
|
||
load r3, #66
|
||
breq r0, r3, hex2nybblef
|
||
load r3, #41
|
||
breq r0, r3, hex2nybblea
|
||
load r3, #42
|
||
breq r0, r3, hex2nybbleb
|
||
load r3, #43
|
||
breq r0, r3, hex2nybblec
|
||
load r3, #44
|
||
breq r0, r3, hex2nybbled
|
||
load r3, #45
|
||
breq r0, r3, hex2nybblee
|
||
load r3, #46
|
||
breq r0, r3, hex2nybblef
|
||
|
||
breq r0, r0, error
|
||
|
||
hex2nybble0:
|
||
xor r0, r0
|
||
ret
|
||
hex2nybble1:
|
||
load r0, #01
|
||
ret
|
||
hex2nybble2:
|
||
load r0, #02
|
||
ret
|
||
hex2nybble3:
|
||
load r0, #03
|
||
ret
|
||
hex2nybble4:
|
||
load r0, #04
|
||
ret
|
||
hex2nybble5:
|
||
load r0, #05
|
||
ret
|
||
hex2nybble6:
|
||
load r0, #06
|
||
ret
|
||
hex2nybble7:
|
||
load r0, #07
|
||
ret
|
||
hex2nybble8:
|
||
load r0, #08
|
||
ret
|
||
hex2nybble9:
|
||
load r0, #09
|
||
ret
|
||
hex2nybblea:
|
||
load r0, #0a
|
||
ret
|
||
hex2nybbleb:
|
||
load r0, #0b
|
||
ret
|
||
hex2nybblec:
|
||
load r0, #0c
|
||
ret
|
||
hex2nybbled:
|
||
load r0, #0d
|
||
ret
|
||
hex2nybblee:
|
||
load r0, #0e
|
||
ret
|
||
hex2nybblef:
|
||
load r0, #0f
|
||
ret
|
||
|
||
; ------------------------------------------------------------------
|
||
; Hex output
|
||
; ------------------------------------------------------------------
|
||
|
||
; in:
|
||
; r1:r0 = word
|
||
; clobbers:
|
||
; r0, r2, r3
|
||
writehexWord:
|
||
cleq r0, r0, writehexByte
|
||
|
||
; Move low byte to r0
|
||
xor r0, r0
|
||
or r0, r1
|
||
breq r0, r0, writehexByte
|
||
|
||
; in:
|
||
; r0 = byte
|
||
; clobbers:
|
||
; r0, r2, r3
|
||
writehexByte:
|
||
; Store copy of the byte (as r0 is modified by nybble2hex)
|
||
xor r2, r2
|
||
or r2, r0
|
||
|
||
; High nybble
|
||
shr r0, 4
|
||
cleq r0, r0, nybble2hex
|
||
store ffff, r0
|
||
|
||
; Low nybble
|
||
load r0, #0f
|
||
and r0, r2
|
||
cleq r0, r0, nybble2hex
|
||
store ffff, r0
|
||
|
||
ret
|
||
|
||
; in:
|
||
; r0 = nybble
|
||
; clobbers:
|
||
; r3
|
||
writehexNybble:
|
||
cleq r0, r0, nybble2hex
|
||
store ffff, r0
|
||
ret
|
||
|
||
; ------------------------------------------------------------------
|
||
; Common output routines
|
||
; ------------------------------------------------------------------
|
||
|
||
; clobbers:
|
||
; r3
|
||
newline:
|
||
load r3, #0d
|
||
store ffff, r3
|
||
load r3, #0a
|
||
store ffff, r3
|
||
ret
|
||
|
||
; noreturn
|
||
underflow:
|
||
load r0, #55 ; U
|
||
store ffff, r0
|
||
load r0, #6e ; n
|
||
store ffff, r0
|
||
load r0, #64 ; d
|
||
store ffff, r0
|
||
load r0, #65 ; e
|
||
store ffff, r0
|
||
load r0, #72 ; r
|
||
store ffff, r0
|
||
load r0, #66 ; f
|
||
store ffff, r0
|
||
load r0, #6c ; l
|
||
store ffff, r0
|
||
load r0, #6f ; o
|
||
store ffff, r0
|
||
load r0, #77 ; w
|
||
store ffff, r0
|
||
load r0, #20
|
||
store ffff, r0
|
||
|
||
; noreturn
|
||
error:
|
||
load r0, #65 ; e
|
||
store ffff, r0
|
||
load r0, #72 ; r
|
||
store ffff, r0
|
||
store ffff, r0
|
||
load r1, #6f ; o
|
||
store ffff, r1
|
||
store ffff, r0
|
||
cleq r0, r0, newline
|
||
halt
|
||
|
||
; ==================================================================
|
||
; Data
|
||
; ==================================================================
|
||
|
||
linelen:
|
||
data 0
|
||
data 0
|
||
|
||
linebufStart: addr end
|
||
linebufSize:
|
||
data 00
|
||
data 80
|
||
SP: addr end + 80
|
||
SPStart: addr end + 80
|
||
|
||
end:
|