pokecrystal-board/extras/gbz80disasm.py
Bryan Bishop 381d3e76b7 include_last_address for disassembler
This is an extra option that is on by default for gbz80disasm, which is
useful in situations where you may not want the last address to be
included (like if the output of the disassembler is going to be sent to
to_asm anyway).
2013-02-27 20:03:18 -06:00

853 lines
26 KiB
Python

# -*- coding: utf-8 -*-
import os
import sys
from copy import copy, deepcopy
from ctypes import c_int8
import random
import json
# New versions of json don't have read anymore.
if not hasattr(json, "read"):
json.read = json.loads
from romstr import RomStr
def load_rom(filename="../baserom.gbc"):
global rom
rom = RomStr.load(filename=filename)
return rom
spacing = "\t"
temp_opt_table = [
[ "ADC A", 0x8f, 0 ],
[ "ADC B", 0x88, 0 ],
[ "ADC C", 0x89, 0 ],
[ "ADC D", 0x8a, 0 ],
[ "ADC E", 0x8b, 0 ],
[ "ADC H", 0x8c, 0 ],
[ "ADC [HL]", 0x8e, 0 ],
[ "ADC L", 0x8d, 0 ],
[ "ADC x", 0xce, 1 ],
[ "ADD A", 0x87, 0 ],
[ "ADD B", 0x80, 0 ],
[ "ADD C", 0x81, 0 ],
[ "ADD D", 0x82, 0 ],
[ "ADD E", 0x83, 0 ],
[ "ADD H", 0x84, 0 ],
[ "ADD [HL]", 0x86, 0 ],
[ "ADD HL, BC", 0x9, 0 ],
[ "ADD HL, DE", 0x19, 0 ],
[ "ADD HL, HL", 0x29, 0 ],
[ "ADD HL, SP", 0x39, 0 ],
[ "ADD L", 0x85, 0 ],
[ "ADD SP, x", 0xe8, 1 ],
[ "ADD x", 0xc6, 1 ],
[ "AND A", 0xa7, 0 ],
[ "AND B", 0xa0, 0 ],
[ "AND C", 0xa1, 0 ],
[ "AND D", 0xa2, 0 ],
[ "AND E", 0xa3, 0 ],
[ "AND H", 0xa4, 0 ],
[ "AND [HL]", 0xa6, 0 ],
[ "AND L", 0xa5, 0 ],
[ "AND x", 0xe6, 1 ],
[ "BIT 0, A", 0x47cb, 3 ],
[ "BIT 0, B", 0x40cb, 3 ],
[ "BIT 0, C", 0x41cb, 3 ],
[ "BIT 0, D", 0x42cb, 3 ],
[ "BIT 0, E", 0x43cb, 3 ],
[ "BIT 0, H", 0x44cb, 3 ],
[ "BIT 0, [HL]", 0x46cb, 3 ],
[ "BIT 0, L", 0x45cb, 3 ],
[ "BIT 1, A", 0x4fcb, 3 ],
[ "BIT 1, B", 0x48cb, 3 ],
[ "BIT 1, C", 0x49cb, 3 ],
[ "BIT 1, D", 0x4acb, 3 ],
[ "BIT 1, E", 0x4bcb, 3 ],
[ "BIT 1, H", 0x4ccb, 3 ],
[ "BIT 1, [HL]", 0x4ecb, 3 ],
[ "BIT 1, L", 0x4dcb, 3 ],
[ "BIT 2, A", 0x57cb, 3 ],
[ "BIT 2, B", 0x50cb, 3 ],
[ "BIT 2, C", 0x51cb, 3 ],
[ "BIT 2, D", 0x52cb, 3 ],
[ "BIT 2, E", 0x53cb, 3 ],
[ "BIT 2, H", 0x54cb, 3 ],
[ "BIT 2, [HL]", 0x56cb, 3 ],
[ "BIT 2, L", 0x55cb, 3 ],
[ "BIT 3, A", 0x5fcb, 3 ],
[ "BIT 3, B", 0x58cb, 3 ],
[ "BIT 3, C", 0x59cb, 3 ],
[ "BIT 3, D", 0x5acb, 3 ],
[ "BIT 3, E", 0x5bcb, 3 ],
[ "BIT 3, H", 0x5ccb, 3 ],
[ "BIT 3, [HL]", 0x5ecb, 3 ],
[ "BIT 3, L", 0x5dcb, 3 ],
[ "BIT 4, A", 0x67cb, 3 ],
[ "BIT 4, B", 0x60cb, 3 ],
[ "BIT 4, C", 0x61cb, 3 ],
[ "BIT 4, D", 0x62cb, 3 ],
[ "BIT 4, E", 0x63cb, 3 ],
[ "BIT 4, H", 0x64cb, 3 ],
[ "BIT 4, [HL]", 0x66cb, 3 ],
[ "BIT 4, L", 0x65cb, 3 ],
[ "BIT 5, A", 0x6fcb, 3 ],
[ "BIT 5, B", 0x68cb, 3 ],
[ "BIT 5, C", 0x69cb, 3 ],
[ "BIT 5, D", 0x6acb, 3 ],
[ "BIT 5, E", 0x6bcb, 3 ],
[ "BIT 5, H", 0x6ccb, 3 ],
[ "BIT 5, [HL]", 0x6ecb, 3 ],
[ "BIT 5, L", 0x6dcb, 3 ],
[ "BIT 6, A", 0x77cb, 3 ],
[ "BIT 6, B", 0x70cb, 3 ],
[ "BIT 6, C", 0x71cb, 3 ],
[ "BIT 6, D", 0x72cb, 3 ],
[ "BIT 6, E", 0x73cb, 3 ],
[ "BIT 6, H", 0x74cb, 3 ],
[ "BIT 6, [HL]", 0x76cb, 3 ],
[ "BIT 6, L", 0x75cb, 3 ],
[ "BIT 7, A", 0x7fcb, 3 ],
[ "BIT 7, B", 0x78cb, 3 ],
[ "BIT 7, C", 0x79cb, 3 ],
[ "BIT 7, D", 0x7acb, 3 ],
[ "BIT 7, E", 0x7bcb, 3 ],
[ "BIT 7, H", 0x7ccb, 3 ],
[ "BIT 7, [HL]", 0x7ecb, 3 ],
[ "BIT 7, L", 0x7dcb, 3 ],
[ "CALL C, ?", 0xdc, 2 ],
[ "CALL NC, ?", 0xd4, 2 ],
[ "CALL NZ, ?", 0xc4, 2 ],
[ "CALL Z, ?", 0xcc, 2 ],
[ "CALL ?", 0xcd, 2 ],
[ "CCF", 0x3f, 0 ],
[ "CP A", 0xbf, 0 ],
[ "CP B", 0xb8, 0 ],
[ "CP C", 0xb9, 0 ],
[ "CP D", 0xba, 0 ],
[ "CP E", 0xbb, 0 ],
[ "CP H", 0xbc, 0 ],
[ "CP [HL]", 0xbe, 0 ],
[ "CPL", 0x2f, 0 ],
[ "CP L", 0xbd, 0 ],
[ "CP x", 0xfe, 1 ],
[ "DAA", 0x27, 0 ],
[ "DEBUG", 0xed, 0 ],
[ "DEC A", 0x3d, 0 ],
[ "DEC B", 0x5, 0 ],
[ "DEC BC", 0xb, 0 ],
[ "DEC C", 0xd, 0 ],
[ "DEC D", 0x15, 0 ],
[ "DEC DE", 0x1b, 0 ],
[ "DEC E", 0x1d, 0 ],
[ "DEC H", 0x25, 0 ],
[ "DEC HL", 0x2b, 0 ],
[ "DEC [HL]", 0x35, 0 ],
[ "DEC L", 0x2d, 0 ],
[ "DEC SP", 0x3b, 0 ],
[ "DI", 0xf3, 0 ],
[ "EI", 0xfb, 0 ],
[ "HALT", 0x76, 0 ],
[ "INC A", 0x3c, 0 ],
[ "INC B", 0x4, 0 ],
[ "INC BC", 0x3, 0 ],
[ "INC C", 0xc, 0 ],
[ "INC D", 0x14, 0 ],
[ "INC DE", 0x13, 0 ],
[ "INC E", 0x1c, 0 ],
[ "INC H", 0x24, 0 ],
[ "INC HL", 0x23, 0 ],
[ "INC [HL]", 0x34, 0 ],
[ "INC L", 0x2c, 0 ],
[ "INC SP", 0x33, 0 ],
[ "JP C, ?", 0xda, 2 ],
[ "JP [HL]", 0xe9, 0 ],
[ "JP NC, ?", 0xd2, 2 ],
[ "JP NZ, ?", 0xc2, 2 ],
[ "JP Z, ?", 0xca, 2 ],
[ "JP ?", 0xc3, 2 ],
[ "JR C, x", 0x38, 1 ],
[ "JR NC, x", 0x30, 1 ],
[ "JR NZ, x", 0x20, 1 ],
[ "JR Z, x", 0x28, 1 ],
[ "JR x", 0x18, 1 ],
[ "LD A, A", 0x7f, 0 ],
[ "LD A, B", 0x78, 0 ],
[ "LD A, C", 0x79, 0 ],
[ "LD A, D", 0x7a, 0 ],
[ "LD A, E", 0x7b, 0 ],
[ "LD A, H", 0x7c, 0 ],
[ "LD A, L", 0x7d, 0 ],
[ "LD A, [$FF00+C]", 0xf2, 0 ],
[ "LD A, [$FF00+x]", 0xf0, 1 ],
# [ "LDH A, [x]", 0xf0, 1 ], # rgbds has trouble with this one?
[ "LD A, [BC]", 0xa, 0 ],
[ "LD A, [DE]", 0x1a, 0 ],
# [ "LD A, [HL+]", 0x2a, 0 ],
# [ "LD A, [HL-]", 0x3a, 0 ],
[ "LD A, [HL]", 0x7e, 0 ],
[ "LD A, [HLD]", 0x3a, 0 ],
[ "LD A, [HLI]", 0x2a, 0 ],
[ "LD A, [?]", 0xfa, 2 ],
[ "LD A, x", 0x3e, 1 ],
[ "LD B, A", 0x47, 0 ],
[ "LD B, B", 0x40, 0 ],
[ "LD B, C", 0x41, 0 ],
[ "LD [BC], A", 0x2, 0 ],
[ "LD B, D", 0x42, 0 ],
[ "LD B, E", 0x43, 0 ],
[ "LD B, H", 0x44, 0 ],
[ "LD B, [HL]", 0x46, 0 ],
[ "LD B, L", 0x45, 0 ],
[ "LD B, x", 0x6, 1 ],
[ "LD C, A", 0x4f, 0 ],
[ "LD C, B", 0x48, 0 ],
[ "LD C, C", 0x49, 0 ],
[ "LD C, D", 0x4a, 0 ],
[ "LD C, E", 0x4b, 0 ],
[ "LD C, H", 0x4c, 0 ],
[ "LD C, [HL]", 0x4e, 0 ],
[ "LD C, L", 0x4d, 0 ],
[ "LD C, x", 0xe, 1 ],
[ "LD D, A", 0x57, 0 ],
# [ "LDD A, [HL]", 0x3a, 0 ],
[ "LD D, B", 0x50, 0 ],
[ "LD D, C", 0x51, 0 ],
[ "LD D, D", 0x52, 0 ],
[ "LD D, E", 0x53, 0 ],
[ "LD [DE], A", 0x12, 0 ],
[ "LD D, H", 0x54, 0 ],
[ "LD D, [HL]", 0x56, 0 ],
# [ "LDD [HL], A", 0x32, 0 ],
[ "LD D, L", 0x55, 0 ],
[ "LD D, x", 0x16, 1 ],
[ "LD E, A", 0x5f, 0 ],
[ "LD E, B", 0x58, 0 ],
[ "LD E, C", 0x59, 0 ],
[ "LD E, D", 0x5a, 0 ],
[ "LD E, E", 0x5b, 0 ],
[ "LD E, H", 0x5c, 0 ],
[ "LD E, [HL]", 0x5e, 0 ],
[ "LD E, L", 0x5d, 0 ],
[ "LD E, x", 0x1e, 1 ],
[ "LD [$FF00+C], A", 0xe2, 0 ],
[ "LD [$FF00+x], A", 0xe0, 1 ],
# [ "LDH [x], A", 0xe0, 1 ],
[ "LD H, A", 0x67, 0 ],
[ "LD H, B", 0x60, 0 ],
[ "LD H, C", 0x61, 0 ],
[ "LD H, D", 0x62, 0 ],
[ "LD H, E", 0x63, 0 ],
[ "LD H, H", 0x64, 0 ],
[ "LD H, [HL]", 0x66, 0 ],
[ "LD H, L", 0x65, 0 ],
# [ "LD [HL+], A", 0x22, 0 ],
# [ "LD [HL-], A", 0x32, 0 ],
[ "LD [HL], A", 0x77, 0 ],
[ "LD [HL], B", 0x70, 0 ],
[ "LD [HL], C", 0x71, 0 ],
[ "LD [HL], D", 0x72, 0 ],
[ "LD [HLD], A", 0x32, 0 ],
[ "LD [HL], E", 0x73, 0 ],
[ "LD [HL], H", 0x74, 0 ],
[ "LD [HLI], A", 0x22, 0 ],
[ "LD [HL], L", 0x75, 0 ],
[ "LD HL, SP+x", 0xf8, 1 ],
[ "LD [HL], x", 0x36, 1 ],
[ "LD H, x", 0x26, 1 ],
# [ "LDI A, [HL]", 0x2a, 0 ],
# [ "LDI [HL], A", 0x22, 0 ],
[ "LD L, A", 0x6f, 0 ],
[ "LD L, B", 0x68, 0 ],
[ "LD L, C", 0x69, 0 ],
[ "LD L, D", 0x6a, 0 ],
[ "LD L, E", 0x6b, 0 ],
[ "LD L, H", 0x6c, 0 ],
[ "LD L, [HL]", 0x6e, 0 ],
[ "LD L, L", 0x6d, 0 ],
[ "LD L, x", 0x2e, 1 ],
# [ "LD PC, HL", 0xe9, 0 ], #prefer jp [hl]
[ "LD SP, HL", 0xf9, 0 ],
[ "LD BC, ?", 0x1, 2 ],
[ "LD DE, ?", 0x11, 2 ],
[ "LD HL, ?", 0x21, 2 ],
[ "LD SP, ?", 0x31, 2 ],
[ "LD [?], SP", 0x8, 2 ],
[ "LD [?], A", 0xea, 2 ],
[ "NOP", 0x0, 0 ],
[ "OR A", 0xb7, 0 ],
[ "OR B", 0xb0, 0 ],
[ "OR C", 0xb1, 0 ],
[ "OR D", 0xb2, 0 ],
[ "OR E", 0xb3, 0 ],
[ "OR H", 0xb4, 0 ],
[ "OR [HL]", 0xb6, 0 ],
[ "OR L", 0xb5, 0 ],
[ "OR x", 0xf6, 1 ],
[ "POP AF", 0xf1, 0 ],
[ "POP BC", 0xc1, 0 ],
[ "POP DE", 0xd1, 0 ],
[ "POP HL", 0xe1, 0 ],
[ "PUSH AF", 0xf5, 0 ],
[ "PUSH BC", 0xc5, 0 ],
[ "PUSH DE", 0xd5, 0 ],
[ "PUSH HL", 0xe5, 0 ],
[ "RES 0, A", 0x87cb, 3 ],
[ "RES 0, B", 0x80cb, 3 ],
[ "RES 0, C", 0x81cb, 3 ],
[ "RES 0, D", 0x82cb, 3 ],
[ "RES 0, E", 0x83cb, 3 ],
[ "RES 0, H", 0x84cb, 3 ],
[ "RES 0, [HL]", 0x86cb, 3 ],
[ "RES 0, L", 0x85cb, 3 ],
[ "RES 1, A", 0x8fcb, 3 ],
[ "RES 1, B", 0x88cb, 3 ],
[ "RES 1, C", 0x89cb, 3 ],
[ "RES 1, D", 0x8acb, 3 ],
[ "RES 1, E", 0x8bcb, 3 ],
[ "RES 1, H", 0x8ccb, 3 ],
[ "RES 1, [HL]", 0x8ecb, 3 ],
[ "RES 1, L", 0x8dcb, 3 ],
[ "RES 2, A", 0x97cb, 3 ],
[ "RES 2, B", 0x90cb, 3 ],
[ "RES 2, C", 0x91cb, 3 ],
[ "RES 2, D", 0x92cb, 3 ],
[ "RES 2, E", 0x93cb, 3 ],
[ "RES 2, H", 0x94cb, 3 ],
[ "RES 2, [HL]", 0x96cb, 3 ],
[ "RES 2, L", 0x95cb, 3 ],
[ "RES 3, A", 0x9fcb, 3 ],
[ "RES 3, B", 0x98cb, 3 ],
[ "RES 3, C", 0x99cb, 3 ],
[ "RES 3, D", 0x9acb, 3 ],
[ "RES 3, E", 0x9bcb, 3 ],
[ "RES 3, H", 0x9ccb, 3 ],
[ "RES 3, [HL]", 0x9ecb, 3 ],
[ "RES 3, L", 0x9dcb, 3 ],
[ "RES 4, A", 0xa7cb, 3 ],
[ "RES 4, B", 0xa0cb, 3 ],
[ "RES 4, C", 0xa1cb, 3 ],
[ "RES 4, D", 0xa2cb, 3 ],
[ "RES 4, E", 0xa3cb, 3 ],
[ "RES 4, H", 0xa4cb, 3 ],
[ "RES 4, [HL]", 0xa6cb, 3 ],
[ "RES 4, L", 0xa5cb, 3 ],
[ "RES 5, A", 0xafcb, 3 ],
[ "RES 5, B", 0xa8cb, 3 ],
[ "RES 5, C", 0xa9cb, 3 ],
[ "RES 5, D", 0xaacb, 3 ],
[ "RES 5, E", 0xabcb, 3 ],
[ "RES 5, H", 0xaccb, 3 ],
[ "RES 5, [HL]", 0xaecb, 3 ],
[ "RES 5, L", 0xadcb, 3 ],
[ "RES 6, A", 0xb7cb, 3 ],
[ "RES 6, B", 0xb0cb, 3 ],
[ "RES 6, C", 0xb1cb, 3 ],
[ "RES 6, D", 0xb2cb, 3 ],
[ "RES 6, E", 0xb3cb, 3 ],
[ "RES 6, H", 0xb4cb, 3 ],
[ "RES 6, [HL]", 0xb6cb, 3 ],
[ "RES 6, L", 0xb5cb, 3 ],
[ "RES 7, A", 0xbfcb, 3 ],
[ "RES 7, B", 0xb8cb, 3 ],
[ "RES 7, C", 0xb9cb, 3 ],
[ "RES 7, D", 0xbacb, 3 ],
[ "RES 7, E", 0xbbcb, 3 ],
[ "RES 7, H", 0xbccb, 3 ],
[ "RES 7, [HL]", 0xbecb, 3 ],
[ "RES 7, L", 0xbdcb, 3 ],
[ "RETI", 0xd9, 0 ],
[ "RET C", 0xd8, 0 ],
[ "RET NC", 0xd0, 0 ],
[ "RET NZ", 0xc0, 0 ],
[ "RET Z", 0xc8, 0 ],
[ "RET", 0xc9, 0 ],
[ "RLA", 0x17, 0 ],
[ "RL A", 0x17cb, 3 ],
[ "RL B", 0x10cb, 3 ],
[ "RL C", 0x11cb, 3 ],
[ "RLCA", 0x7, 0 ],
[ "RLC A", 0x7cb, 3 ],
[ "RLC B", 0xcb, 3 ],
[ "RLC C", 0x1cb, 3 ],
[ "RLC D", 0x2cb, 3 ],
[ "RLC E", 0x3cb, 3 ],
[ "RLC H", 0x4cb, 3 ],
[ "RLC [HL]", 0x6cb, 3 ],
[ "RLC L", 0x5cb, 3 ],
[ "RL D", 0x12cb, 3 ],
[ "RL E", 0x13cb, 3 ],
[ "RL H", 0x14cb, 3 ],
[ "RL [HL]", 0x16cb, 3 ],
[ "RL L", 0x15cb, 3 ],
[ "RRA", 0x1f, 0 ],
[ "RR A", 0x1fcb, 3 ],
[ "RR B", 0x18cb, 3 ],
[ "RR C", 0x19cb, 3 ],
[ "RRCA", 0xf, 0 ],
[ "RRC A", 0xfcb, 3 ],
[ "RRC B", 0x8cb, 3 ],
[ "RRC C", 0x9cb, 3 ],
[ "RRC D", 0xacb, 3 ],
[ "RRC E", 0xbcb, 3 ],
[ "RRC H", 0xccb, 3 ],
[ "RRC [HL]", 0xecb, 3 ],
[ "RRC L", 0xdcb, 3 ],
[ "RR D", 0x1acb, 3 ],
[ "RR E", 0x1bcb, 3 ],
[ "RR H", 0x1ccb, 3 ],
[ "RR [HL]", 0x1ecb, 3 ],
[ "RR L", 0x1dcb, 3 ],
[ "RST $0", 0xc7, 0 ],
[ "RST $10", 0xd7, 0 ],
[ "RST $18", 0xdf, 0 ],
[ "RST $20", 0xe7, 0 ],
[ "RST $28", 0xef, 0 ],
[ "RST $30", 0xf7, 0 ],
[ "RST $38", 0xff, 0 ],
[ "RST $8", 0xcf, 0 ],
[ "SBC A", 0x9f, 0 ],
[ "SBC B", 0x98, 0 ],
[ "SBC C", 0x99, 0 ],
[ "SBC D", 0x9a, 0 ],
[ "SBC E", 0x9b, 0 ],
[ "SBC H", 0x9c, 0 ],
[ "SBC [HL]", 0x9e, 0 ],
[ "SBC L", 0x9d, 0 ],
[ "SBC x", 0xde, 1 ],
[ "SCF", 0x37, 0 ],
[ "SET 0, A", 0xc7cb, 3 ],
[ "SET 0, B", 0xc0cb, 3 ],
[ "SET 0, C", 0xc1cb, 3 ],
[ "SET 0, D", 0xc2cb, 3 ],
[ "SET 0, E", 0xc3cb, 3 ],
[ "SET 0, H", 0xc4cb, 3 ],
[ "SET 0, [HL]", 0xc6cb, 3 ],
[ "SET 0, L", 0xc5cb, 3 ],
[ "SET 1, A", 0xcfcb, 3 ],
[ "SET 1, B", 0xc8cb, 3 ],
[ "SET 1, C", 0xc9cb, 3 ],
[ "SET 1, D", 0xcacb, 3 ],
[ "SET 1, E", 0xcbcb, 3 ],
[ "SET 1, H", 0xcccb, 3 ],
[ "SET 1, [HL]", 0xcecb, 3 ],
[ "SET 1, L", 0xcdcb, 3 ],
[ "SET 2, A", 0xd7cb, 3 ],
[ "SET 2, B", 0xd0cb, 3 ],
[ "SET 2, C", 0xd1cb, 3 ],
[ "SET 2, D", 0xd2cb, 3 ],
[ "SET 2, E", 0xd3cb, 3 ],
[ "SET 2, H", 0xd4cb, 3 ],
[ "SET 2, [HL]", 0xd6cb, 3 ],
[ "SET 2, L", 0xd5cb, 3 ],
[ "SET 3, A", 0xdfcb, 3 ],
[ "SET 3, B", 0xd8cb, 3 ],
[ "SET 3, C", 0xd9cb, 3 ],
[ "SET 3, D", 0xdacb, 3 ],
[ "SET 3, E", 0xdbcb, 3 ],
[ "SET 3, H", 0xdccb, 3 ],
[ "SET 3, [HL]", 0xdecb, 3 ],
[ "SET 3, L", 0xddcb, 3 ],
[ "SET 4, A", 0xe7cb, 3 ],
[ "SET 4, B", 0xe0cb, 3 ],
[ "SET 4, C", 0xe1cb, 3 ],
[ "SET 4, D", 0xe2cb, 3 ],
[ "SET 4, E", 0xe3cb, 3 ],
[ "SET 4, H", 0xe4cb, 3 ],
[ "SET 4, [HL]", 0xe6cb, 3 ],
[ "SET 4, L", 0xe5cb, 3 ],
[ "SET 5, A", 0xefcb, 3 ],
[ "SET 5, B", 0xe8cb, 3 ],
[ "SET 5, C", 0xe9cb, 3 ],
[ "SET 5, D", 0xeacb, 3 ],
[ "SET 5, E", 0xebcb, 3 ],
[ "SET 5, H", 0xeccb, 3 ],
[ "SET 5, [HL]", 0xeecb, 3 ],
[ "SET 5, L", 0xedcb, 3 ],
[ "SET 6, A", 0xf7cb, 3 ],
[ "SET 6, B", 0xf0cb, 3 ],
[ "SET 6, C", 0xf1cb, 3 ],
[ "SET 6, D", 0xf2cb, 3 ],
[ "SET 6, E", 0xf3cb, 3 ],
[ "SET 6, H", 0xf4cb, 3 ],
[ "SET 6, [HL]", 0xf6cb, 3 ],
[ "SET 6, L", 0xf5cb, 3 ],
[ "SET 7, A", 0xffcb, 3 ],
[ "SET 7, B", 0xf8cb, 3 ],
[ "SET 7, C", 0xf9cb, 3 ],
[ "SET 7, D", 0xfacb, 3 ],
[ "SET 7, E", 0xfbcb, 3 ],
[ "SET 7, H", 0xfccb, 3 ],
[ "SET 7, [HL]", 0xfecb, 3 ],
[ "SET 7, L", 0xfdcb, 3 ],
[ "SLA A", 0x27cb, 3 ],
[ "SLA B", 0x20cb, 3 ],
[ "SLA C", 0x21cb, 3 ],
[ "SLA D", 0x22cb, 3 ],
[ "SLA E", 0x23cb, 3 ],
[ "SLA H", 0x24cb, 3 ],
[ "SLA [HL]", 0x26cb, 3 ],
[ "SLA L", 0x25cb, 3 ],
[ "SRA A", 0x2fcb, 3 ],
[ "SRA B", 0x28cb, 3 ],
[ "SRA C", 0x29cb, 3 ],
[ "SRA D", 0x2acb, 3 ],
[ "SRA E", 0x2bcb, 3 ],
[ "SRA H", 0x2ccb, 3 ],
[ "SRA [HL]", 0x2ecb, 3 ],
[ "SRA L", 0x2dcb, 3 ],
[ "SRL A", 0x3fcb, 3 ],
[ "SRL B", 0x38cb, 3 ],
[ "SRL C", 0x39cb, 3 ],
[ "SRL D", 0x3acb, 3 ],
[ "SRL E", 0x3bcb, 3 ],
[ "SRL H", 0x3ccb, 3 ],
[ "SRL [HL]", 0x3ecb, 3 ],
[ "SRL L", 0x3dcb, 3 ],
[ "STOP", 0x10, 0 ],
[ "SUB A", 0x97, 0 ],
[ "SUB B", 0x90, 0 ],
[ "SUB C", 0x91, 0 ],
[ "SUB D", 0x92, 0 ],
[ "SUB E", 0x93, 0 ],
[ "SUB H", 0x94, 0 ],
[ "SUB [HL]", 0x96, 0 ],
[ "SUB L", 0x95, 0 ],
[ "SUB x", 0xd6, 1 ],
[ "SWAP A", 0x37cb, 3 ],
[ "SWAP B", 0x30cb, 3 ],
[ "SWAP C", 0x31cb, 3 ],
[ "SWAP D", 0x32cb, 3 ],
[ "SWAP E", 0x33cb, 3 ],
[ "SWAP H", 0x34cb, 3 ],
[ "SWAP [HL]", 0x36cb, 3 ],
[ "SWAP L", 0x35cb, 3 ],
[ "XOR A", 0xaf, 0 ],
[ "XOR B", 0xa8, 0 ],
[ "XOR C", 0xa9, 0 ],
[ "XOR D", 0xaa, 0 ],
[ "XOR E", 0xab, 0 ],
[ "XOR H", 0xac, 0 ],
[ "XOR [HL]", 0xae, 0 ],
[ "XOR L", 0xad, 0 ],
[ "XOR x", 0xee, 1 ],
[ "E", 0x100, -1 ],
]
# construct a more useful version of opt_table
opt_table = {}
for line in temp_opt_table:
opt_table[line[1]] = [line[0], line[2]]
del line
end_08_scripts_with = [
0xe9, #jp hl
#0xc3, #jp
##0x18, #jr
0xc9, #ret
###0xda, 0xe9, 0xd2, 0xc2, 0xca, 0xc3, 0x38, 0x30, 0x20, 0x28, 0x18, 0xd8, 0xd0, 0xc0, 0xc8, 0xc9
]
relative_jumps = [0x38, 0x30, 0x20, 0x28, 0x18, 0xc3, 0xda, 0xc2]
relative_unconditional_jumps = [0xc3, 0x18]
call_commands = [0xdc, 0xd4, 0xc4, 0xcc, 0xcd]
all_labels = {}
def load_labels(filename="labels.json"):
global all_labels
if os.path.exists(filename):
all_labels = json.read(open(filename, "r").read())
else:
print "You must run crystal.scan_for_predefined_labels() to create \"labels.json\". Trying..."
import crystal
crystal.scan_for_predefined_labels()
def find_label(local_address, bank_id=0):
global all_labels
# keep an integer
if type(local_address) == str:
local_address1 = int(local_address.replace("$", "0x"), 16)
else: local_address1 = local_address
# turn local_address into an integer
if type(local_address) == str:
if "0x" in local_address:
local_address = local_address.replace("0x", "$")
elif "$" in local_address:
local_address = local_address.replace("$", "")
if type(local_address) == str:
local_address = int(local_address, 16)
for label_entry in all_labels:
if label_entry["address"] == local_address:
if label_entry["bank"] == bank_id or (local_address1 < 0x8000 and (label_entry["bank"] == 0 or label_entry["bank"] == 1)):
return label_entry["label"]
return None
def asm_label(address):
# why using a random value when you can use the address?
return ".ASM_" + hex(address)[2:]
def output_bank_opcodes(original_offset, max_byte_count=0x4000, include_last_address=True, debug = False):
#fs = current_address
#b = bank_byte
#in = input_data -- rom
#bank_size = byte_count
#i = offset
#ad = end_address
#a, oa = current_byte_number
load_labels()
load_rom()
bank_id = 0
if original_offset > 0x8000:
bank_id = original_offset / 0x4000
if debug: print "bank id is: " + str(bank_id)
last_hl_address = None #for when we're scanning the main map script
last_a_address = None
used_3d97 = False
global rom
offset = original_offset
current_byte_number = 0 #start from the beginning
#we don't actually have an end address, but we'll just say $4000
end_address = original_offset + max_byte_count
byte_labels = {}
output = ""
keep_reading = True
while offset <= end_address and keep_reading:
current_byte = ord(rom[offset])
is_data = False
maybe_byte = current_byte
#first check if this byte already has a label
#if it does, use the label
#if not, generate a new label
if offset in byte_labels.keys():
line_label = byte_labels[offset]["name"]
byte_labels[offset]["usage"] += 1
else:
line_label = asm_label(offset)
byte_labels[offset] = {}
byte_labels[offset]["name"] = line_label
byte_labels[offset]["usage"] = 0
byte_labels[offset]["definition"] = True
output += line_label.lower() + "\n" #" ; " + hex(offset) + "\n"
#find out if there's a two byte key like this
temp_maybe = maybe_byte
temp_maybe += ( ord(rom[offset+1]) << 8)
if temp_maybe in opt_table.keys() and ord(rom[offset+1])!=0:
opstr = opt_table[temp_maybe][0].lower()
if "x" in opstr:
for x in range(0, opstr.count("x")):
insertion = ord(rom[offset + 1])
insertion = "$" + hex(insertion)[2:]
opstr = opstr[:opstr.find("x")].lower() + insertion + opstr[opstr.find("x")+1:].lower()
current_byte += 1
offset += 1
if "?" in opstr:
for y in range(0, opstr.count("?")):
byte1 = ord(rom[offset + 1])
byte2 = ord(rom[offset + 2])
number = byte1
number += byte2 << 8;
insertion = "$%.4x" % (number)
opstr = opstr[:opstr.find("?")].lower() + insertion + opstr[opstr.find("?")+1:].lower()
current_byte_number += 2
offset += 2
output += spacing + opstr #+ " ; " + hex(offset)
output += "\n"
current_byte_number += 2
offset += 2
elif maybe_byte in opt_table.keys():
op_code = opt_table[maybe_byte]
op_code_type = op_code[1]
op_code_byte = maybe_byte
#type = -1 when it's the E op
#if op_code_type != -1:
if op_code_type == 0 and ord(rom[offset]) == op_code_byte:
op_str = op_code[0].lower()
output += spacing + op_code[0].lower() #+ " ; " + hex(offset)
output += "\n"
offset += 1
current_byte_number += 1
elif op_code_type == 1 and ord(rom[offset]) == op_code_byte:
oplen = len(op_code[0])
opstr = copy(op_code[0])
xes = op_code[0].count("x")
include_comment = False
for x in range(0, xes):
insertion = ord(rom[offset + 1])
insertion = "$" + hex(insertion)[2:]
if current_byte == 0x18 or current_byte==0x20 or current_byte in relative_jumps: #jr or jr nz
#generate a label for the byte we're jumping to
target_address = offset + 2 + c_int8(ord(rom[offset + 1])).value
if target_address in byte_labels.keys():
byte_labels[target_address]["usage"] = 1 + byte_labels[target_address]["usage"]
line_label2 = byte_labels[target_address]["name"]
else:
line_label2 = asm_label(target_address)
byte_labels[target_address] = {}
byte_labels[target_address]["name"] = line_label2
byte_labels[target_address]["usage"] = 1
byte_labels[target_address]["definition"] = False
insertion = line_label2.lower()
include_comment = True
elif current_byte == 0x3e:
last_a_address = ord(rom[offset + 1])
opstr = opstr[:opstr.find("x")].lower() + insertion + opstr[opstr.find("x")+1:].lower()
# because the $ff00+$ff syntax is silly
if opstr.count("$") > 0 and "+" in opstr:
first_orig = opstr.split("$")[1].split("+")[0]
first_num = "0x"+first_orig
first_val = int(first_num, 16)
second_orig = opstr.split("+$")[1].split("]")[0]
second_num = "0x"+second_orig
second_val = int(second_num, 16)
combined_val = "$" + hex(first_val + second_val)[2:]
replacetron = "[$"+first_orig+"+$"+second_orig+"]"
opstr = opstr.replace(replacetron, "["+combined_val+"]")
output += spacing + opstr
if include_comment:
output += " ; " + hex(offset)
if current_byte in relative_jumps:
output += " $" + hex(ord(rom[offset + 1]))[2:]
output += "\n"
current_byte_number += 1
offset += 1
insertion = ""
current_byte_number += 1
offset += 1
include_comment = False
elif op_code_type == 2 and ord(rom[offset]) == op_code_byte:
oplen = len(op_code[0])
opstr = copy(op_code[0])
qes = op_code[0].count("?")
for x in range(0, qes):
byte1 = ord(rom[offset + 1])
byte2 = ord(rom[offset + 2])
number = byte1
number += byte2 << 8;
insertion = "$%.4x" % (number)
if maybe_byte in call_commands or current_byte in relative_unconditional_jumps or current_byte in relative_jumps:
result = find_label(insertion, bank_id)
if result != None:
insertion = result
opstr = opstr[:opstr.find("?")].lower() + insertion + opstr[opstr.find("?")+1:].lower()
output += spacing + opstr #+ " ; " + hex(offset)
output += "\n"
current_byte_number += 2
offset += 2
current_byte_number += 1
offset += 1
if current_byte == 0x21:
last_hl_address = byte1 + (byte2 << 8)
if current_byte == 0xcd:
if number == 0x3d97: used_3d97 = True
#duck out if this is jp $24d7
if current_byte == 0xc3 or current_byte in relative_unconditional_jumps:
if current_byte == 0xc3:
if number == 0x3d97: used_3d97 = True
#if number == 0x24d7: #jp
if not has_outstanding_labels(byte_labels) or all_outstanding_labels_are_reverse(byte_labels, offset):
keep_reading = False
is_data = False
break
else:
is_data = True
#stop reading at a jump, relative jump or return
if current_byte in end_08_scripts_with:
if not has_outstanding_labels(byte_labels) and all_outstanding_labels_are_reverse(byte_labels, offset):
keep_reading = False
is_data = False #cleanup
break
else:
is_data = False
keep_reading = True
else:
is_data = False
keep_reading = True
else:
#if is_data and keep_reading:
output += spacing + "db $" + hex(ord(rom[offset]))[2:] #+ " ; " + hex(offset)
output += "\n"
offset += 1
current_byte_number += 1
#else the while loop would have spit out the opcode
#these two are done prior
#offset += 1
#current_byte_number += 1
#clean up unused labels
for label_line in byte_labels.keys():
address = label_line
label_line = byte_labels[label_line]
if label_line["usage"] == 0:
output = output.replace((label_line["name"] + "\n").lower(), "")
#add the offset of the final location
if include_last_address:
output += "; " + hex(offset)
return (output, offset, last_hl_address, last_a_address, used_3d97)
def has_outstanding_labels(byte_labels):
"""
If a label is used once in the asm output, then that means it has to be
called or specified later.
"""
for label_line in byte_labels.keys():
real_line = byte_labels[label_line]
if real_line["definition"] == False: return True
return False
def all_outstanding_labels_are_reverse(byte_labels, offset):
for label_id in byte_labels.keys():
line = byte_labels[label_id] # label_id is also the address
if line["definition"] == False:
if not label_id < offset: return False
return True
if __name__ == "__main__":
print output_bank_opcodes(int(sys.argv[1], 16))[0]