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: