diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5533399 --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +BIN=calculator.bin +.SUFFIXES: +.SUFFIXES: .asm .bin + +.PHONY: all +all: $(BIN) + +.asm.bin: + thingamajig_assembler $@ < $< + +.PHONY: clean distclean +clean: + rm -f $(BIN) +distclean: clean + +.PHONY: run +run: $(BIN) + thingamajig_emulator $(BIN) diff --git a/calculator.asm b/calculator.asm new file mode 100644 index 0000000..15a2842 --- /dev/null +++ b/calculator.asm @@ -0,0 +1,712 @@ +org 0 + +start: + cleq r0, r0, initStack + + load r0, lit01 + load r1, litff + cleq r0, r0, pushWord + cleq r0, r0, stPrinthex + + xor r0, r0 + load r1, lit41 + cleq r0, r0, pushWord + cleq r0, r0, stPrinthex + + cleq r0, r0, stSub + cleq r0, r0, stPrinthex + + halt + +; ================================================================== +; 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, stNeg + breq r0, r0, stAdd + +; n -- -n +stNeg: + cleq r0, r0, popWord + nand r0, r0 + nand r1, r1 + cleq r0, r0, incWord + breq r0, r0, pushWord + +; ------------------------------------------------------------------ +; I/O +; ------------------------------------------------------------------ + +; n -- n +stPrinthex: + cleq r0, r0, peekWord + 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 + +; ================================================================== +; Low-level functions +; ================================================================== + +; ------------------------------------------------------------------ +; Memory +; ------------------------------------------------------------------ + +tmpWordHigh: data 0 +tmpWordLow: data 0 + +; out: +; r0:r1 = word +peekWord: + cleq r0, r0, popWord + cleq r0, r0, tmpStoreWord01 + cleq r0, r0, pushWord + breq r0, r0, tmpLoadWord01 + +; 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 +; trashes: +; 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 +; trashes: +; r2, r3 +popWord: + cleq r0, r0, popByte + store popWordLow, r0 + + cleq r0, r0, popByte + + load r1, popWordLow + + ret + + popWordLow: data 0 + +; in: +; r0 = byte +; trashes: +; r0, r1, r2, r3 +pushByte: + load r2, SPHigh + store storeByteHigh, r2 + load r3, SPLow + store storeByteLow, r3 + cleq r0, r0, storeByte + + load r0, SPHigh + load r1, SPLow + cleq r0, r0, incWord + store SPHigh, r0 + store SPLow, r1 + + ret + +; out: +; r0 = byte +; trashes: +; r1, r2, r3 +popByte: + load r0, SPHigh + load r1, SPLow + cleq r0, r0, decWord + store SPHigh, r0 + store SPLow, 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 +; trashes: +; 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/out: +; r0:r1 = word +; trashes: +; 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 +; trashes: +; 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 +; trashes: +; 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 +; trashes: +; 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 +; trashes: +; 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 +; trashes: +; 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 +; trashes: +; 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 +; trashes: +; 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 +; ------------------------------------------------------------------ + +; trashes: +; 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 + +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 + +; ================================================================== +; Stack +; ================================================================== + +SPHigh: data 0 +SPLow: data 0 + +; trashes: +; r3 +initStack: + load r3, initStackDummyLoad+1 + store SPHigh, r3 + load r3, initStackDummyLoad+2 + store SPLow, r3 + ret + + initStackDummyLoad: load r0, stackBase + +stackBase: