2022-07-23 12:46:27 +00:00
|
|
|
#!/usr/bin/env python
|
2022-05-08 12:14:36 +00:00
|
|
|
from collections import namedtuple
|
|
|
|
|
2022-08-27 16:25:42 +00:00
|
|
|
Opcode = namedtuple('Opcode', ('mnemonic', 'rx', 'ry', 'addr', 'immediate'))
|
2022-05-08 12:14:36 +00:00
|
|
|
|
|
|
|
opcodes = [
|
2022-08-27 16:25:42 +00:00
|
|
|
Opcode('halt', rx=False, ry=False, addr=False, immediate=False),
|
|
|
|
Opcode('ret', rx=False, ry=False, addr=False, immediate=False),
|
|
|
|
|
|
|
|
Opcode('shl', rx=True, ry=False, addr=False, immediate=False),
|
|
|
|
Opcode('shr', rx=True, ry=False, addr=False, immediate=False),
|
|
|
|
Opcode('rol', rx=True, ry=False, addr=False, immediate=False),
|
|
|
|
Opcode('ror', rx=True, ry=False, addr=False, immediate=False),
|
|
|
|
|
|
|
|
Opcode('nand', rx=True, ry=True, addr=False, immediate=False),
|
|
|
|
Opcode('and', rx=True, ry=True, addr=False, immediate=False),
|
|
|
|
Opcode('or', rx=True, ry=True, addr=False, immediate=False),
|
|
|
|
Opcode('xor', rx=True, ry=True, addr=False, immediate=False),
|
|
|
|
|
|
|
|
Opcode('load', rx=True, ry=False, addr=True, immediate=True),
|
|
|
|
Opcode('store', rx=False, ry=True, addr=True, immediate=False),
|
|
|
|
|
|
|
|
Opcode('breq', rx=True, ry=True, addr=True, immediate=False),
|
|
|
|
Opcode('brneq', rx=True, ry=True, addr=True, immediate=False),
|
|
|
|
Opcode('cleq', rx=True, ry=True, addr=True, immediate=False),
|
|
|
|
Opcode('clneq', rx=True, ry=True, addr=True, immediate=False),
|
2022-05-08 12:14:36 +00:00
|
|
|
]
|
|
|
|
|
2022-08-27 16:25:42 +00:00
|
|
|
Instruction = namedtuple('Instruction', ['opcode', 'rx', 'ry', 'addr', 'immediate'])
|
2022-05-08 12:14:36 +00:00
|
|
|
Data = namedtuple('Data', ['byte'])
|
|
|
|
|
2022-07-23 12:51:11 +00:00
|
|
|
Statement = namedtuple('Statement', ['addr', 'raw', 'contents'])
|
2022-05-08 12:14:36 +00:00
|
|
|
|
|
|
|
def segment(binary, origin):
|
|
|
|
statements = []
|
|
|
|
ip = origin
|
|
|
|
while ip < len(binary):
|
|
|
|
byte = binary[ip]
|
|
|
|
|
|
|
|
opcode = byte >> 4
|
|
|
|
|
|
|
|
rx = (byte >> 2) & 3
|
|
|
|
ry = byte & 3
|
|
|
|
|
2022-08-27 16:25:42 +00:00
|
|
|
immediate = opcodes[opcode].immediate and ry == 3
|
|
|
|
|
2022-05-08 12:14:36 +00:00
|
|
|
valid = True
|
|
|
|
if not opcodes[opcode].rx and rx != 0: valid = False
|
2022-08-27 16:25:42 +00:00
|
|
|
if not opcodes[opcode].ry and not immediate and ry != 0: valid = False
|
|
|
|
if opcodes[opcode].addr and not immediate and ip + 2 >= len(binary): valid = False
|
|
|
|
if immediate and ip + 1 >= len(binary): valid = False
|
2022-05-08 12:14:36 +00:00
|
|
|
|
2022-05-10 09:19:22 +00:00
|
|
|
if not valid:
|
2022-07-23 12:51:11 +00:00
|
|
|
raw = binary[ip:ip + 1]
|
|
|
|
statements.append(Statement(ip, raw, Data(byte)))
|
2022-05-10 09:19:22 +00:00
|
|
|
ip += 1
|
2022-08-27 16:25:42 +00:00
|
|
|
elif immediate:
|
|
|
|
raw = binary[ip:ip + 2]
|
|
|
|
instruction = Instruction(opcode, rx, ry, None, binary[ip + 1])
|
|
|
|
statements.append(Statement(ip, raw, instruction))
|
|
|
|
ip += 2
|
2022-05-10 09:19:22 +00:00
|
|
|
elif opcodes[opcode].addr:
|
2022-07-23 12:51:11 +00:00
|
|
|
raw = binary[ip:ip + 3]
|
2022-05-10 09:19:22 +00:00
|
|
|
addr = (binary[ip + 1] << 8) + binary[ip + 2]
|
2022-08-27 16:25:42 +00:00
|
|
|
instruction = Instruction(opcode, rx, ry, addr, None)
|
2022-07-23 12:51:11 +00:00
|
|
|
statements.append(Statement(ip, raw, instruction))
|
2022-05-10 09:19:22 +00:00
|
|
|
ip += 3
|
2022-05-08 12:14:36 +00:00
|
|
|
else:
|
2022-07-23 12:51:11 +00:00
|
|
|
raw = binary[ip:ip + 1]
|
2022-08-27 16:25:42 +00:00
|
|
|
instruction = Instruction(opcode, rx, ry, None, None)
|
2022-07-23 12:51:11 +00:00
|
|
|
statements.append(Statement(ip, raw, instruction))
|
2022-05-10 09:19:22 +00:00
|
|
|
ip += 1
|
2022-05-08 12:14:36 +00:00
|
|
|
|
|
|
|
return statements
|
|
|
|
|
|
|
|
def disasm(binary, origin = 0):
|
2022-07-23 12:51:11 +00:00
|
|
|
for addr, raw, contents in segment(binary, origin):
|
2022-05-08 12:14:36 +00:00
|
|
|
if type(contents) == Data:
|
2022-08-27 16:27:06 +00:00
|
|
|
statement = f'data {contents.byte:02x}'
|
2022-05-08 12:14:36 +00:00
|
|
|
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}')
|
2022-08-27 16:25:42 +00:00
|
|
|
if contents.immediate is not None:
|
2022-08-27 16:27:06 +00:00
|
|
|
fields.append(f'#{contents.immediate:02x}')
|
2022-08-27 16:25:42 +00:00
|
|
|
elif opcodes[contents.opcode].addr:
|
2022-08-27 16:27:06 +00:00
|
|
|
fields.append(f'{contents.addr:04x}')
|
2022-05-08 12:14:36 +00:00
|
|
|
|
|
|
|
if mnemonic == 'store':
|
|
|
|
fields = ', '.join(reversed(fields))
|
|
|
|
else:
|
|
|
|
fields = ', '.join(fields)
|
|
|
|
|
|
|
|
if len(fields) != 0:
|
|
|
|
statement = f'{mnemonic} {fields}'
|
|
|
|
else:
|
|
|
|
statement = mnemonic
|
2022-07-23 12:51:11 +00:00
|
|
|
print(f'{addr:04x} {raw.hex():6} {statement}')
|
2022-05-08 12:14:36 +00:00
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
import sys
|
|
|
|
with open(sys.argv[1], 'rb') as f:
|
|
|
|
binary = f.read()
|
|
|
|
disasm(binary)
|