org 0 start: cleq r0, r0, stReadline cleq r0, r0, dumpstack halt dumpstack: load r0, SPStart+0 load r1, SPStart+1 store dumpstackPtr+0, r0 store dumpstackPtr+1, r1 dumpstackLoop: load r0, dumpstackPtr+0 load r1, dumpstackPtr+1 load r2, SP+0 load r3, SP+1 brneq r0, r2, dumpstackDumpword breq r1, r3, dumpstackEnd dumpstackDumpword: load r0, dumpstackPtr+0 load r1, dumpstackPtr+1 store loadByteHigh, r0 store loadByteLow, r1 cleq r0, r0, loadByte cleq r0, r0, writehexByte load r0, dumpstackPtr+0 load r1, dumpstackPtr+1 cleq r0, r0, incWord store dumpstackPtr+0, r0 store dumpstackPtr+1, r1 load r0, dumpstackPtr+0 load r1, dumpstackPtr+1 store loadByteHigh, r0 store loadByteLow, r1 cleq r0, r0, loadByte cleq r0, r0, writehexByte load r0, dumpstackPtr+0 load r1, dumpstackPtr+1 cleq r0, r0, incWord store dumpstackPtr+0, r0 store dumpstackPtr+1, r1 load r0, litcharSpace store ffff, r0 breq r0, r0, dumpstackLoop dumpstackEnd: breq r0, r0, newline dumpstackPtr: addr dumpstackPtr stReadline: ; 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, litcharCR breq r0, r1, readlineEnter ; Is it backspace? load r0, litcharBS 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 we only want to return the length cleq r0, r0, popWord 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 cleq r0, r0, stDec load r3, litcharSpace store ffff, r3 load r3, litcharBS store ffff, r3 breq r0, r0, readlineLoop readlineBufFull: ; Drop the input byte and erase the echoed character cleq r0, r0, popWord load r3, litcharBS store ffff, r3 load r3, litcharSpace store ffff, r3 load r3, litcharBS store ffff, r3 breq r0, r0, readlineLoop ; ================================================================== ; 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 -- ; 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 ; ------------------------------------------------------------------ ; 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 ; ================================================================== ; Low-level functions ; ================================================================== ; ------------------------------------------------------------------ ; Memory ; ------------------------------------------------------------------ tmpWordHigh: data 0 tmpWordLow: data 0 tmpWord2High: data 0 tmpWord2Low: 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 ; 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, lit02 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 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, lit01 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, lit01 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, litff cleq r0, r0, addByte store decWordLow, r0 ; Add ff and carry to high byte load r0, litff 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 ; 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 shr r2 shr r2 shr r2 shr r2 shr r2 shr r2 ; 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, lit01 breq r0, r3, nybble2hex1 load r3, lit02 breq r0, r3, nybble2hex2 load r3, lit03 breq r0, r3, nybble2hex3 load r3, lit04 breq r0, r3, nybble2hex4 load r3, lit05 breq r0, r3, nybble2hex5 load r3, lit06 breq r0, r3, nybble2hex6 load r3, lit07 breq r0, r3, nybble2hex7 load r3, lit08 breq r0, r3, nybble2hex8 load r3, lit09 breq r0, r3, nybble2hex9 load r3, lit0a breq r0, r3, nybble2hexa load r3, lit0b breq r0, r3, nybble2hexb load r3, lit0c breq r0, r3, nybble2hexc load r3, lit0d breq r0, r3, nybble2hexd load r3, lit0e breq r0, r3, nybble2hexe load r3, lit0f breq r0, r3, nybble2hexf breq r0, r0, error nybble2hex0: load r0, litchar0 ret nybble2hex1: load r0, litchar1 ret nybble2hex2: load r0, litchar2 ret nybble2hex3: load r0, litchar3 ret nybble2hex4: load r0, litchar4 ret nybble2hex5: load r0, litchar5 ret nybble2hex6: load r0, litchar6 ret nybble2hex7: load r0, litchar7 ret nybble2hex8: load r0, litchar8 ret nybble2hex9: load r0, litchar9 ret nybble2hexa: load r0, litchara ret nybble2hexb: load r0, litcharb ret nybble2hexc: load r0, litcharc ret nybble2hexd: load r0, litchard ret nybble2hexe: load r0, litchare ret nybble2hexf: load r0, litcharf ret ; in: ; r0 = ascii hex digit ; out: ; r0 = corresponding nybble ; clobbers: ; r3 hex2nybble: load r3, litchar0 breq r0, r3, hex2nybble0 load r3, litchar1 breq r0, r3, hex2nybble1 load r3, litchar2 breq r0, r3, hex2nybble2 load r3, litchar3 breq r0, r3, hex2nybble3 load r3, litchar4 breq r0, r3, hex2nybble4 load r3, litchar5 breq r0, r3, hex2nybble5 load r3, litchar6 breq r0, r3, hex2nybble6 load r3, litchar7 breq r0, r3, hex2nybble7 load r3, litchar8 breq r0, r3, hex2nybble8 load r3, litchar9 breq r0, r3, hex2nybble9 load r3, litchara breq r0, r3, hex2nybblea load r3, litcharb breq r0, r3, hex2nybbleb load r3, litcharc breq r0, r3, hex2nybblec load r3, litchard breq r0, r3, hex2nybbled load r3, litchare breq r0, r3, hex2nybblee load r3, litcharf breq r0, r3, hex2nybblef load r3, litcharUppera breq r0, r3, hex2nybblea load r3, litcharUpperb breq r0, r3, hex2nybbleb load r3, litcharUpperC breq r0, r3, hex2nybblec load r3, litcharUpperD breq r0, r3, hex2nybbled load r3, litcharUpperE breq r0, r3, hex2nybblee load r3, litcharUpperF breq r0, r3, hex2nybblef breq r0, r0, error hex2nybble0: xor r0, r0 ret hex2nybble1: load r0, lit01 ret hex2nybble2: load r0, lit02 ret hex2nybble3: load r0, lit03 ret hex2nybble4: load r0, lit04 ret hex2nybble5: load r0, lit05 ret hex2nybble6: load r0, lit06 ret hex2nybble7: load r0, lit07 ret hex2nybble8: load r0, lit08 ret hex2nybble9: load r0, lit09 ret hex2nybblea: load r0, lit0a ret hex2nybbleb: load r0, lit0b ret hex2nybblec: load r0, lit0c ret hex2nybbled: load r0, lit0d ret hex2nybblee: load r0, lit0e ret hex2nybblef: load r0, lit0f 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 shr r0 shr r0 shr r0 cleq r0, r0, nybble2hex store ffff, r0 ; Low nybble load r0, lit0f and r0, r2 cleq r0, r0, nybble2hex store ffff, r0 ret ; ------------------------------------------------------------------ ; Common output routines ; ------------------------------------------------------------------ ; clobbers: ; r3 newline: load r3, litcharCR store ffff, r3 load r3, litcharLF store ffff, r3 ret ; noreturn error: load r0, litchare store ffff, r0 load r0, litcharr store ffff, r0 store ffff, r0 load r1, litcharo store ffff, r1 store ffff, r0 cleq r0, r0, newline halt ; ================================================================== ; Literals pool ; ================================================================== lit01: data 01 lit02: data 02 lit03: data 03 lit04: data 04 lit05: data 05 lit06: data 06 lit07: data 07 litcharBS: lit08: data 08 lit09: data 09 litcharLF: lit0a: data 0a lit0b: data 0b lit0c: data 0c litcharCR: lit0d: data 0d lit0e: data 0e lit0f: data 0f litcharSpace: lit20: data 20 litchar0: lit30: data 30 litchar1: lit31: data 31 litchar2: lit32: data 32 litchar3: lit33: data 33 litchar4: lit34: data 34 litchar5: lit35: data 35 litchar6: lit36: data 36 litchar7: lit37: data 37 litchar8: lit38: data 38 litchar9: lit39: data 39 litcharUppera: lit41: data 41 litcharUpperb: lit42: data 42 litcharUpperc: lit43: data 43 litcharUpperd: lit44: data 44 litcharUppere: lit45: data 45 litcharUpperf: lit46: data 46 litchara: lit61: data 61 litcharb: lit62: data 62 litcharc: lit63: data 63 litchard: lit64: data 64 litchare: lit65: data 65 litcharf: lit66: data 66 litcharo: lit6f: data 6f litcharr: lit72: data 72 litff: data ff ; ================================================================== ; Data ; ================================================================== linebufStart: addr end linebufSize: data 00 data 80 SP: addr end + 80 SPStart: addr end + 80 end: