You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2023 lines
35 KiB
2023 lines
35 KiB
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:
|
|
|