thingamajig/thingamajig_disasm.py

94 lines
2.4 KiB
Python

from collections import namedtuple
Opcode = namedtuple('Opcode', ('mnemonic', 'rx', 'ry', 'addr'))
opcodes = [
Opcode('halt', rx=False, ry=False, addr=False),
Opcode('ret', rx=False, ry=False, addr=False),
Opcode('shl', rx=True, ry=False, addr=False),
Opcode('shr', rx=True, ry=False, addr=False),
Opcode('rol', rx=True, ry=False, addr=False),
Opcode('ror', rx=True, ry=False, addr=False),
Opcode('nand', rx=True, ry=True, addr=False),
Opcode('and', rx=True, ry=True, addr=False),
Opcode('or', rx=True, ry=True, addr=False),
Opcode('xor', rx=True, ry=True, addr=False),
Opcode('load', rx=True, ry=False, addr=True),
Opcode('store', rx=True, ry=False, addr=True),
Opcode('breq', rx=True, ry=True, addr=True),
Opcode('brneq', rx=True, ry=True, addr=True),
Opcode('cleq', rx=True, ry=True, addr=True),
Opcode('clneq', rx=True, ry=True, addr=True),
]
Instruction = namedtuple('Instruction', ['opcode', 'rx', 'ry', 'addr'])
Data = namedtuple('Data', ['byte'])
Statement = namedtuple('Statement', ['addr', 'contents'])
def segment(binary, origin):
statements = []
ip = origin
while ip < len(binary):
byte = binary[ip]
opcode = byte >> 4
rx = (byte >> 2) & 3
ry = byte & 3
addr = None
if opcodes[opcode].addr:
addr = (binary[ip + 1] << 8) + binary[ip + 2]
valid = True
if not opcodes[opcode].rx and rx != 0: valid = False
if not opcodes[opcode].ry and ry != 0: valid = False
if valid:
instruction = Instruction(opcode, rx, ry, addr)
statements.append(Statement(ip, instruction))
else:
statements.append(Statement(ip, Data(byte)))
ip += 1
if opcodes[opcode].addr:
ip += 2
return statements
def disasm(binary, origin = 0):
for addr, contents in segment(binary, origin):
if type(contents) == Data:
statement = f'db 0x{contents.byte:02x}'
else:
mnemonic = opcodes[contents.opcode].mnemonic
fields = []
if opcodes[contents.opcode].rx:
fields.append(f'r{contents.rx}')
if opcodes[contents.opcode].ry:
fields.append(f'r{contents.ry}')
if opcodes[contents.opcode].addr:
fields.append(f'0x{contents.addr:04x}')
if mnemonic == 'store':
fields = ', '.join(reversed(fields))
else:
fields = ', '.join(fields)
if len(fields) != 0:
statement = f'{mnemonic} {fields}'
else:
statement = mnemonic
print(f'{addr:04x} {statement}')
if __name__ == '__main__':
import sys
with open(sys.argv[1], 'rb') as f:
binary = f.read()
disasm(binary)