#!/usr/bin/env 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', 'raw', '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 valid = True if not opcodes[opcode].rx and rx != 0: valid = False if not opcodes[opcode].ry and ry != 0: valid = False if opcodes[opcode].addr and ip + 2 >= len(binary): valid = False if not valid: raw = binary[ip:ip + 1] statements.append(Statement(ip, raw, Data(byte))) ip += 1 elif opcodes[opcode].addr: raw = binary[ip:ip + 3] addr = (binary[ip + 1] << 8) + binary[ip + 2] instruction = Instruction(opcode, rx, ry, addr) statements.append(Statement(ip, raw, instruction)) ip += 3 else: raw = binary[ip:ip + 1] instruction = Instruction(opcode, rx, ry, None) statements.append(Statement(ip, raw, instruction)) ip += 1 return statements def disasm(binary, origin = 0): for addr, raw, 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} {raw.hex():6} {statement}') if __name__ == '__main__': import sys with open(sys.argv[1], 'rb') as f: binary = f.read() disasm(binary)