summaryrefslogtreecommitdiff
path: root/disasm.py
diff options
context:
space:
mode:
Diffstat (limited to 'disasm.py')
-rwxr-xr-xdisasm.py100
1 files changed, 100 insertions, 0 deletions
diff --git a/disasm.py b/disasm.py
new file mode 100755
index 0000000..3ba5c2f
--- /dev/null
+++ b/disasm.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+import sys
+
+mnems = """
+nop
+rot
+nrt
+dup
+swp
+ovr
+drp
+tck
+nip
+equ
+neq
+add
+sub
+mul
+div
+neg
+slt
+ult
+sle
+ule
+lod
+sto
+psh
+pop
+""".split()
+mnems.extend(['???']*(64-len(mnems)))
+def opws(kw):
+ for k in range(16):
+ mnems.append(kw + str(k))
+opws("mark") # who is mark
+opws("loc")
+opws("ret")
+opws("lit")
+
+def dpc(addr):
+ print(f"{addr:04x} | ",end='')
+
+def uuu(b):
+ u=bin(b)[2:].zfill(16)
+ for x in range(0,len(u),4):
+ yield u[x:x+4]
+
+def fbin(b):
+ return '_'.join(uuu(b))
+
+pc = 0
+
+MASK_CALL = 0b1000_0000_0000_0000
+MASK_LIT = 0b0110_0000_0000_0000
+MASK_JMP = 0b0100_0000_0000_0000
+def maskeq(x, m):
+ # must be called in the right order
+ return (x&m)==m
+
+def main():
+ while True:
+ global pc
+ bys = sys.stdin.buffer.read(2)
+ if len(bys) < 2: break
+ word = int.from_bytes(bys, 'big')
+ dpc(pc)
+ dpc(word)
+ if maskeq(word, MASK_CALL):
+ disasm_call(word)
+ elif maskeq(word, MASK_LIT):
+ disasm_lit(word)
+ elif maskeq(word, MASK_JMP):
+ disasm_br(word, pc)
+ else:
+ disasm_i(word)
+ pc += 2
+
+def disasm_call(word):
+ addr = word & 0b0111_1111_1111_1111
+ addr = addr << 1
+ print(f"c {addr:04x}")
+def disasm_lit(word):
+ val = word & 0b0001_1111_1111_1111
+ print(f"l {val:04x}")
+def disasm_br(word, pc):
+ is_cond = (word & 0b0001_0000_0000_0000) != 0
+ char = 'b' if is_cond else 'j'
+ rel = (word & 0b0000_1111_1111_1111) - 2048
+ target = rel + pc
+ print(f"{char} {rel:+05x} ={target:04x}")
+def disasm_i(word):
+ opc1 = (word&0b0011_1111_1000_0000)>>7
+ opc2 = (word&0b0000_0000_0111_1111)
+ mnem1 = mnems[opc1]
+ mnem2 = mnems[opc2]
+ if mnem2 == "nop": mnem2 = ""
+ print(f"i {mnem1} {mnem2}")
+
+
+if __name__ == "__main__":
+ main()