Advertisement
PikalaxALT

pikaz80disasm.py

May 22nd, 2016
241
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 11.43 KB | None | 0 0
  1. #!/usr/bin/python3
  2.  
  3. import re, sys, argparse, random
  4.  
  5. z80table = [
  6. # $00
  7. ("nop", 0), ("ld bc, ${:04x}", 2), ("ld [bc], a", 0), ("inc bc", 0), ("inc b", 0), ("dec b", 0), ("ld b, ${:02x}", 1), ("rlca", 0),
  8. # $08
  9. ("ld [${:04x}], sp", 2), ("add hl, bc", 0), ("ld a, [bc]", 0), ("dec bc", 0), ("inc c", 0), ("dec c", 0), ("ld c, ${:02x}", 1), ("rrca", 0),
  10. # $10
  11. ("stop", 0), ("ld de, ${:04x}", 2), ("ld [de], a", 0), ("inc de", 0), ("inc d", 0), ("dec d", 0), ("ld d, ${:02x}", 1), ("rla", 0),
  12. # $18
  13. ("jr ${:02x}", 1), ("add hl, de", 0), ("ld a, [de]", 0), ("dec de", 0), ("inc e", 0), ("dec e", 0), ("ld e, ${:02x}", 1), ("rra", 0),
  14. # $20
  15. ("jr nz, ${:02x}", 1), ("ld hl, ${:04x}", 2), ("ld [hli], a", 0), ("inc hl", 0), ("inc h", 0), ("dec h", 0), ("ld h, ${:02x}", 1), ("daa", 0),
  16. # $28
  17. ("jr z, ${:02x}", 1), ("add hl, hl", 0), ("ld a, [hli]", 0), ("dec hl", 0), ("inc l", 0), ("dec l", 0), ("ld l, ${:02x}", 1), ("cpl", 0),
  18. # $30
  19. ("jr nc, ${:02x}", 1), ("ld sp, ${:04x}", 2), ("ld [hld], a", 0), ("inc sp", 0), ("inc [hl]", 0), ("dec [hl]", 0), ("ld [hl], ${:02x}", 1), ("scf", 0),
  20. # $38
  21. ("jr c, ${:02x}", 1), ("add hl, sp", 0), ("ld a, [hld]", 0), ("dec sp", 0), ("inc a", 0), ("dec a", 0), ("ld a, ${:02x}", 1), ("ccf", 0),
  22. # $40
  23. ("ld b, b", 0), ("ld b, c", 0), ("ld b, d", 0), ("ld b, e", 0), ("ld b, h", 0), ("ld b, l", 0), ("ld b, [hl]", 0), ("ld b, a", 0),
  24. # $48
  25. ("ld c, b", 0), ("ld c, c", 0), ("ld c, d", 0), ("ld c, e", 0), ("ld c, h", 0), ("ld c, l", 0), ("ld c, [hl]", 0), ("ld c, a", 0),
  26. # $50
  27. ("ld d, b", 0), ("ld d, c", 0), ("ld d, d", 0), ("ld d, e", 0), ("ld d, h", 0), ("ld d, l", 0), ("ld d, [hl]", 0), ("ld d, a", 0),
  28. # $58
  29. ("ld e, b", 0), ("ld e, c", 0), ("ld e, d", 0), ("ld e, e", 0), ("ld e, h", 0), ("ld e, l", 0), ("ld e, [hl]", 0), ("ld e, a", 0),
  30. # $60
  31. ("ld h, b", 0), ("ld h, c", 0), ("ld h, d", 0), ("ld h, e", 0), ("ld h, h", 0), ("ld h, l", 0), ("ld h, [hl]", 0), ("ld h, a", 0),
  32. # $68
  33. ("ld l, b", 0), ("ld l, c", 0), ("ld l, d", 0), ("ld l, e", 0), ("ld l, h", 0), ("ld l, l", 0), ("ld l, [hl]", 0), ("ld l, a", 0),
  34. # $70
  35. ("ld [hl], b", 0), ("ld [hl], c", 0), ("ld [hl], d", 0), ("ld [hl], e", 0), ("ld [hl], h", 0), ("ld [hl], l", 0), ("halt", 0), ("ld [hl], a", 0),
  36. # $78
  37. ("ld a, b", 0), ("ld a, c", 0), ("ld a, d", 0), ("ld a, e", 0), ("ld a, h", 0), ("ld a, l", 0), ("ld a, [hl]", 0), ("ld a, a", 0),
  38. # $80
  39. ("add b", 0), ("add c", 0), ("add d", 0), ("add e", 0), ("add h", 0), ("add l", 0), ("add [hl]", 0), ("add a", 0),
  40. # $88
  41. ("adc b", 0), ("adc c", 0), ("adc d", 0), ("adc e", 0), ("adc h", 0), ("adc l", 0), ("adc [hl]", 0), ("adc a", 0),
  42. # $90
  43. ("sub b", 0), ("sub c", 0), ("sub d", 0), ("sub e", 0), ("sub h", 0), ("sub l", 0), ("sub [hl]", 0), ("sub a", 0),
  44. # $98
  45. ("sbc b", 0), ("sbc c", 0), ("sbc d", 0), ("sbc e", 0), ("sbc h", 0), ("sbc l", 0), ("sbc [hl]", 0), ("sbc a", 0),
  46. # $a0
  47. ("and b", 0), ("and c", 0), ("and d", 0), ("and e", 0), ("and h", 0), ("and l", 0), ("and [hl]", 0), ("and a", 0),
  48. # $a8
  49. ("xor b", 0), ("xor c", 0), ("xor d", 0), ("xor e", 0), ("xor h", 0), ("xor l", 0), ("xor [hl]", 0), ("xor a", 0),
  50. # $b0
  51. ("or b", 0), ("or c", 0), ("or d", 0), ("or e", 0), ("or h", 0), ("or l", 0), ("or [hl]", 0), ("or a", 0),
  52. # $b8
  53. ("cp b", 0), ("cp c", 0), ("cp d", 0), ("cp e", 0), ("cp h", 0), ("cp l", 0), ("cp [hl]", 0), ("cp a", 0),
  54. # $c0
  55. ("ret nz", 0), ("pop bc", 0), ("jp nz, ${:04x}", 2), ("jp ${:04x}", 2), ("call nz, ${:04x}", 2), ("push bc", 0), ("add ${:02x}", 1), ("rst $0", 0),
  56. # $c8
  57. ("ret z", 0), ("ret", 0), ("jp z, ${:04x}", 2), ("extd", 0), ("call z, ${:04x}", 2), ("call ${:04x}", 2), ("adc ${:02x}", 1), ("rst $8", 0),
  58. # $d0
  59. ("ret nc", 0), ("pop de", 0), ("jp nc, ${:04x}", 2), ("db $d3", 0), ("call nc, ${:04x}", 2), ("push de", 0), ("sub ${:02x}", 1), ("rst $10", 0),
  60. # $d8
  61. ("ret c", 0), ("reti", 0), ("jp c, ${:04x}", 2), ("db $db", 0), ("call c, ${:04x}", 2), ("db $dd", 2), ("sbc ${:02x}", 1), ("rst $18", 0),
  62. # $e0
  63. ("ld [$ff{:02x}], a", 1), ("pop hl", 0), ("ld [$ff00+c], a", 0), ("db $e3", 0), ("db $e4", 0), ("push hl", 0), ("and ${:02x}", 1), ("rst $20", 0),
  64. # $e8
  65. ("add sp, ${:02x}", 1), ("jp [hl]", 0), ("ld [${:04x}], a", 2), ("db $eb", 0), ("db $ec", 2), ("db $ed", 2), ("xor ${:02x}", 1), ("rst $28", 0),
  66. # $f0
  67. ("ld a, [$ff{:02x}]", 1), ("pop af", 0), ("db $f2", 0), ("di", 0), ("db $f4", 0), ("push af", 0), ("or ${:02x}", 1), ("rst $30", 0),
  68. # $f8
  69. ("ld hl, sp+${:02x}", 1), ("ld sp, [hl]", 0), ("ld a, [${:04x}]", 2), ("ei", 0), ("db $fc", 2), ("db $fd", 2), ("cp ${:02x}", 1), ("rst $38", 0)
  70. ]
  71.  
  72. extdtable = [
  73. # $00
  74. "rlc b", "rlc c", "rlc d", "rlc e", "rlc h", "rlc l", "rlc [hl]", "rlc a",
  75. # $08
  76. "rrc b", "rrc c", "rrc d", "rrc e", "rrc h", "rrc l", "rrc [hl]", "rrc a",
  77. # $10
  78. "rl b", "rl c", "rl d", "rl e", "rl h", "rl l", "rl [hl]", "rl a",
  79. # $18
  80. "rr b", "rr c", "rr d", "rr e", "rr h", "rr l", "rr [hl]", "rr a",
  81. # $20
  82. "sla b", "sla c", "sla d", "sla e", "sla h", "sla l", "sla [hl]", "sla a",
  83. # $28
  84. "sra b", "sra c", "sra d", "sra e", "sra h", "sra l", "sra [hl]", "sra a",
  85. # $30
  86. "swap b", "swap c", "swap d", "swap e", "swap h", "swap l", "swap [hl]", "swap a",
  87. # $38
  88. "srl b", "srl c", "srl d", "srl e", "srl h", "srl l", "srl [hl]", "srl a",
  89. # $40
  90. "bit 0, b", "bit 0, c", "bit 0, d", "bit 0, e", "bit 0, h", "bit 0, l", "bit 0, [hl]", "bit 0, a",
  91. # $48
  92. "bit 1, b", "bit 1, c", "bit 1, d", "bit 1, e", "bit 1, h", "bit 1, l", "bit 1, [hl]", "bit 1, a",
  93. # $50
  94. "bit 2, b", "bit 2, c", "bit 2, d", "bit 2, e", "bit 2, h", "bit 2, l", "bit 2, [hl]", "bit 2, a",
  95. # $58
  96. "bit 3, b", "bit 3, c", "bit 3, d", "bit 3, e", "bit 3, h", "bit 3, l", "bit 3, [hl]", "bit 3, a",
  97. # $60
  98. "bit 4, b", "bit 4, c", "bit 4, d", "bit 4, e", "bit 4, h", "bit 4, l", "bit 4, [hl]", "bit 4, a",
  99. # $68
  100. "bit 5, b", "bit 5, c", "bit 5, d", "bit 5, e", "bit 5, h", "bit 5, l", "bit 5, [hl]", "bit 5, a",
  101. # $70
  102. "bit 6, b", "bit 6, c", "bit 6, d", "bit 6, e", "bit 6, h", "bit 6, l", "bit 6, [hl]", "bit 6, a",
  103. # $78
  104. "bit 7, b", "bit 7, c", "bit 7, d", "bit 7, e", "bit 7, h", "bit 7, l", "bit 7, [hl]", "bit 7, a",
  105. # $80
  106. "res 0, b", "res 0, c", "res 0, d", "res 0, e", "res 0, h", "res 0, l", "res 0, [hl]", "res 0, a",
  107. # $88
  108. "res 1, b", "res 1, c", "res 1, d", "res 1, e", "res 1, h", "res 1, l", "res 1, [hl]", "res 1, a",
  109. # $90
  110. "res 2, b", "res 2, c", "res 2, d", "res 2, e", "res 2, h", "res 2, l", "res 2, [hl]", "res 2, a",
  111. # $98
  112. "res 3, b", "res 3, c", "res 3, d", "res 3, e", "res 3, h", "res 3, l", "res 3, [hl]", "res 3, a",
  113. # $a0
  114. "res 4, b", "res 4, c", "res 4, d", "res 4, e", "res 4, h", "res 4, l", "res 4, [hl]", "res 4, a",
  115. # $a8
  116. "res 5, b", "res 5, c", "res 5, d", "res 5, e", "res 5, h", "res 5, l", "res 5, [hl]", "res 5, a",
  117. # $b0
  118. "res 6, b", "res 6, c", "res 6, d", "res 6, e", "res 6, h", "res 6, l", "res 6, [hl]", "res 6, a",
  119. # $b8
  120. "res 7, b", "res 7, c", "res 7, d", "res 7, e", "res 7, h", "res 7, l", "res 7, [hl]", "res 7, a",
  121. # $c0
  122. "set 0, b", "set 0, c", "set 0, d", "set 0, e", "set 0, h", "set 0, l", "set 0, [hl]", "set 0, a",
  123. # $c8
  124. "set 1, b", "set 1, c", "set 1, d", "set 1, e", "set 1, h", "set 1, l", "set 1, [hl]", "set 1, a",
  125. # $d0
  126. "set 2, b", "set 2, c", "set 2, d", "set 2, e", "set 2, h", "set 2, l", "set 2, [hl]", "set 2, a",
  127. # $d8
  128. "set 3, b", "set 3, c", "set 3, d", "set 3, e", "set 3, h", "set 3, l", "set 3, [hl]", "set 3, a",
  129. # $e0
  130. "set 4, b", "set 4, c", "set 4, d", "set 4, e", "set 4, h", "set 4, l", "set 4, [hl]", "set 4, a",
  131. # $e8
  132. "set 5, b", "set 5, c", "set 5, d", "set 5, e", "set 5, h", "set 5, l", "set 5, [hl]", "set 5, a",
  133. # $f0
  134. "set 6, b", "set 6, c", "set 6, d", "set 6, e", "set 6, h", "set 6, l", "set 6, [hl]", "set 6, a",
  135. # $f8
  136. "set 7, b", "set 7, c", "set 7, d", "set 7, e", "set 7, h", "set 7, l", "set 7, [hl]", "set 7, a"
  137. ]
  138.  
  139. def parse_sym_file(symfile):
  140.     pat = re.compile("(?P<bank>[0-9A-F]{2}):(?P<addr>[0-9A-F]{4}) (?P<label>\S+)$")
  141.     symbols = {}
  142.     for line in symfile.readlines():
  143.         M = pat.match(line)
  144.         if M is not None:
  145.             bank, addr, label = M.groups()
  146.             key = (int(bank,16), int(addr,16))
  147.             if key in symbols:
  148.                 symbols[key].append(label)
  149.             else:
  150.                 symbols[key] = [label]
  151.     symbols[None] = [None]
  152.     return symbols
  153.  
  154. def get_symbol(bank, addr, symbols):
  155.     if addr < 0x4000:
  156.         key = (0, addr)
  157.     elif addr < 0x8000:
  158.         key = (bank, addr)
  159.     elif addr >= 0xc000 and addr < 0xd000:
  160.         key = (0, addr)
  161.     elif addr >= 0xd000 and addr < 0xe000:
  162.         key = (1, addr)
  163.     else:
  164.         key = None
  165.     if key not in symbols:
  166.         return None
  167.     return random.choice(symbols[key])
  168.  
  169. def disassemble_chunk(filename, start, end, outfile, symbols):
  170.     try:
  171.         start = int(start)
  172.         end = int(end)
  173.     except ValueError:
  174.         start = int(start, 16)
  175.         end = int(end, 16)
  176.     labels = {}
  177.     lines = []
  178.     with open(filename, 'rb') as F:
  179.         F.seek(start)
  180.         while F.tell() < end:
  181.             pos = F.tell()
  182.             bank, addr = divmod(pos, 0x4000)
  183.             if bank:addr += 0x4000
  184.             instr, param_pos = get_next_instruction(F, symbols, bank, addr)
  185.             labels[pos] = "\t" + instr + "\n"
  186.             if param_pos:
  187.                 _bank, _addr, _label = param_pos
  188.                 if (_bank, _addr) not in symbols:
  189.                     symbols[(_bank, _addr)] = [_label]
  190.     for pos in range(start, end):
  191.         bank, addr = divmod(pos, 0x4000)
  192.         if bank:addr += 0x4000
  193.         cur_sym = get_symbol(bank, addr, symbols)
  194.         if cur_sym:
  195.             if cur_sym.startswith("."):
  196.                 lines.append(cur_sym + "\n")
  197.             else:
  198.                 lines.append(cur_sym + ":\n")
  199.         if pos in labels:
  200.             lines.append(labels[pos])
  201.     with open(outfile, 'w+') as O:
  202.         O.write("".join(lines))
  203.  
  204. def get_next_instruction(open_file, symbols, bank, addr):
  205.     instr, size = z80table[int.from_bytes(open_file.read(1), 'little')]
  206.     param_pos = None
  207.     if instr == "extd":
  208.         instr = extdtable[int.from_bytes(open_file.read(1), 'little')]
  209.     elif size:
  210.         param = int.from_bytes(open_file.read(size), 'little')
  211.         if "jr" in instr:
  212.             if param & 0x80:
  213.                 param = -(0x100 - param)
  214.             param += addr + 2
  215.             param_pos = (bank, param, ".asm_{:x}".format((bank * 0x4000) + (param & 0x3fff)))
  216.             param = ".asm_{:x}".format((bank * 0x4000) + (param & 0x3fff))
  217.         elif size == 2:
  218.             param = get_symbol(bank, param, symbols) or param
  219.             if type(param) == int and param < 0x8000:
  220.                 param_pos = (bank, param, "Func_{:x}".format((bank * 0x4000) + (param & 0x3fff)))
  221.         if type(param) == str:
  222.             instr = re.sub("\${.*?}", param, instr)
  223.         else:
  224.             instr = instr.format(param)
  225.     return instr, param_pos
  226.  
  227. if __name__ == "__main__":
  228.     parser = argparse.ArgumentParser()
  229.     parser.add_argument("start")
  230.     parser.add_argument("end")
  231.     parser.add_argument("-r", dest="romfile")
  232.     parser.add_argument("-o", dest="outfile")
  233.     parser.add_argument("-s", dest="symfile", default=None)
  234.     args = parser.parse_args()
  235.  
  236.     try:
  237.         start = int(args.start)
  238.     except ValueError:
  239.         start = int(args.start, 16)
  240.     try:
  241.         end = int(args.end)
  242.     except ValueError:
  243.         end = int(args.end, 16)
  244.  
  245.     if args.symfile:
  246.         with open(args.symfile, 'r') as SYM:
  247.             symbols = parse_sym_file(SYM)
  248.     else:
  249.         symbols = {}
  250.     disassemble_chunk(args.romfile, start, end, args.outfile, symbols)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement