mirror of
https://gitlab.com/xCrystal/pokecrystal-board.git
synced 2025-01-23 09:16:20 -08:00
almost complete new disassembler version
This commit is contained in:
parent
0768fead4f
commit
7dd0c86a6b
@ -559,7 +559,6 @@ def load_labels(filename="labels.json"):
|
|||||||
all_labels = json.loads(open(filename, "r").read())
|
all_labels = json.loads(open(filename, "r").read())
|
||||||
else:
|
else:
|
||||||
print "You must run analyze_incbins.scan_for_predefined_labels() to create \"labels.json\"."
|
print "You must run analyze_incbins.scan_for_predefined_labels() to create \"labels.json\"."
|
||||||
load_labels()
|
|
||||||
|
|
||||||
def find_label(local_address, bank_id=0):
|
def find_label(local_address, bank_id=0):
|
||||||
return None
|
return None
|
||||||
@ -827,5 +826,6 @@ def all_outstanding_labels_are_reverse(byte_labels, offset):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
load_labels()
|
||||||
load_rom()
|
load_rom()
|
||||||
print output_bank_opcodes(int(sys.argv[1], 16))[0]
|
print output_bank_opcodes(int(sys.argv[1], 16))[0]
|
||||||
|
178
extras/romstr.py
178
extras/romstr.py
@ -1,17 +1,43 @@
|
|||||||
|
from gbz80disasm import opt_table, end_08_scripts_with, relative_jumps, relative_unconditional_jumps, call_commands
|
||||||
|
|
||||||
class RomStr(str):
|
class RomStr(str):
|
||||||
""" Simple wrapper to prevent a giant rom from being shown on screen
|
""" Simple wrapper to prevent a giant rom from being shown on screen.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def length(self):
|
|
||||||
"""len(self)"""
|
|
||||||
return len(self)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
""" Simplifies this object so that the output doesn't overflow stdout.
|
||||||
|
"""
|
||||||
return "RomStr(too long)"
|
return "RomStr(too long)"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls, crystal=True, red=False):
|
||||||
|
""" Loads a ROM into a RomStr.
|
||||||
|
"""
|
||||||
|
if crystal and not red:
|
||||||
|
file_handler = open("../baserom.gbc", "r")
|
||||||
|
elif red and not crystal:
|
||||||
|
file_handler = open("../pokered-baserom.gbc", "r")
|
||||||
|
else:
|
||||||
|
raise Exception, "not sure which rom to load?"
|
||||||
|
bytes = file_handler.read()
|
||||||
|
file_handler.close()
|
||||||
|
return RomStr(bytes)
|
||||||
|
|
||||||
|
def length(self):
|
||||||
|
""" len(self)
|
||||||
|
"""
|
||||||
|
return len(self)
|
||||||
|
|
||||||
|
def len(self):
|
||||||
|
""" len(self)
|
||||||
|
"""
|
||||||
|
return self.length()
|
||||||
|
|
||||||
def interval(self, offset, length, strings=True, debug=True):
|
def interval(self, offset, length, strings=True, debug=True):
|
||||||
"""returns hex values for the rom starting at offset until offset+length"""
|
""" returns hex values for the rom starting at offset until
|
||||||
returnable = []
|
offset+length
|
||||||
|
"""
|
||||||
|
returnable = []
|
||||||
for byte in self[offset:offset+length]:
|
for byte in self[offset:offset+length]:
|
||||||
if strings:
|
if strings:
|
||||||
returnable.append(hex(ord(byte)))
|
returnable.append(hex(ord(byte)))
|
||||||
@ -20,16 +46,148 @@ class RomStr(str):
|
|||||||
return returnable
|
return returnable
|
||||||
|
|
||||||
def until(self, offset, byte, strings=True, debug=False):
|
def until(self, offset, byte, strings=True, debug=False):
|
||||||
"""returns hex values from rom starting at offset until the given byte"""
|
""" Returns hex values from rom starting at offset until the given
|
||||||
|
byte.
|
||||||
|
"""
|
||||||
return self.interval(offset, self.find(chr(byte), offset) - offset, strings=strings)
|
return self.interval(offset, self.find(chr(byte), offset) - offset, strings=strings)
|
||||||
|
|
||||||
|
def to_asm(self, address, end_address=None, size=None, max_size=0x4000, debug=None):
|
||||||
|
""" Disassembles ASM at some address. This will stop disassembling when
|
||||||
|
either the end_address or size is met. Also, there's a maximum size
|
||||||
|
that will be parsed, so that large patches of data aren't parsed as
|
||||||
|
code.
|
||||||
|
"""
|
||||||
|
start_address = address
|
||||||
|
if start_address == None:
|
||||||
|
raise Exception, "address must be given"
|
||||||
|
|
||||||
|
if debug == None:
|
||||||
|
if not hasattr(self, "debug"):
|
||||||
|
debug = False
|
||||||
|
else:
|
||||||
|
debug = self.debug
|
||||||
|
|
||||||
|
# this is probably a terrible idea.. why am i doing this?
|
||||||
|
if size != None and max_size < size:
|
||||||
|
raise Exception, "max_size must be greater than or equal to size"
|
||||||
|
elif end_address != None and (end_address - start_address) > max_size:
|
||||||
|
raise Exception, "end_address is out of bounds"
|
||||||
|
elif end_address != None and size != None:
|
||||||
|
if (end_address - start_address) >= size:
|
||||||
|
size = end_address - start_address
|
||||||
|
else:
|
||||||
|
end_address = start_address + size
|
||||||
|
elif end_address == None and size != None:
|
||||||
|
end_address = start_address + size
|
||||||
|
elif end_address != None and size == None:
|
||||||
|
size = end_address - start_address
|
||||||
|
|
||||||
|
return Asm(start_address=start_address, end_address=end_address, size=size, max_size=max_size, debug=debug, rom=self)
|
||||||
|
|
||||||
|
class Asm:
|
||||||
|
""" z80 disassembler
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, start_address=None, end_address=None, size=None, max_size=0x4000, debug=True, rom=None):
|
||||||
|
assert start_address != None, "start_address must be given"
|
||||||
|
|
||||||
|
if rom == None:
|
||||||
|
file_handler = open("../baserom.gbc", "r")
|
||||||
|
bytes = file_handler.read()
|
||||||
|
file_handler.close()
|
||||||
|
rom = RomStr(bytes)
|
||||||
|
|
||||||
|
if debug not in [None, True, False]:
|
||||||
|
raise Exception, "debug param is invalid"
|
||||||
|
if debug == None:
|
||||||
|
debug = False
|
||||||
|
|
||||||
|
# get end_address and size in sync with each other
|
||||||
|
if end_address == None and size != None:
|
||||||
|
end_address = start_address + size
|
||||||
|
elif end_address != None and size == None:
|
||||||
|
size = end_address - start_address
|
||||||
|
elif end_address != None and size != None:
|
||||||
|
size = max(end_address - start_address, size)
|
||||||
|
end_address = start_address + size
|
||||||
|
|
||||||
|
# check that the bounds make sense
|
||||||
|
if end_address != None:
|
||||||
|
if end_address <= start_address:
|
||||||
|
raise Exception, "end_address is out of bounds"
|
||||||
|
elif (end_address - start_address) > max_size:
|
||||||
|
raise Exception, "end_address goes beyond max_size"
|
||||||
|
|
||||||
|
# check more edge cases
|
||||||
|
if not start_address >= 0:
|
||||||
|
raise Exception, "start_address must be at least 0"
|
||||||
|
elif not end_address >= 0:
|
||||||
|
raise Exception, "end_address must be at least 0"
|
||||||
|
|
||||||
|
self.rom = rom
|
||||||
|
self.start_address = start_address
|
||||||
|
self.end_address = end_address
|
||||||
|
self.size = size
|
||||||
|
self.max_size = max_size
|
||||||
|
self.debug = debug
|
||||||
|
|
||||||
|
self.parse()
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
""" Disassembles stuff and things.
|
||||||
|
"""
|
||||||
|
|
||||||
|
rom = self.rom
|
||||||
|
start_address = self.start_address
|
||||||
|
end_address = self.end_address
|
||||||
|
max_size = self.max_size
|
||||||
|
debug = self.debug
|
||||||
|
|
||||||
|
bank_id = start_address / 0x4000
|
||||||
|
|
||||||
|
# [{"command": 0x20, "bytes": [0x20, 0x40, 0x50],
|
||||||
|
# "asm": "jp $5040", "label": "Unknown5040"}]
|
||||||
|
asm_commands = []
|
||||||
|
|
||||||
|
offset = start_address
|
||||||
|
|
||||||
|
current_byte_number = 0
|
||||||
|
|
||||||
|
last_hl_address = None
|
||||||
|
last_a_address = None
|
||||||
|
used_3d97 = False
|
||||||
|
|
||||||
|
keep_reading = True
|
||||||
|
|
||||||
|
# for labeling future bytes (like for relative jumps)
|
||||||
|
byte_labels = {}
|
||||||
|
|
||||||
|
while offset <= end_address and keep_reading:
|
||||||
|
current_byte = ord(rom[offset])
|
||||||
|
|
||||||
|
is_data = False
|
||||||
|
|
||||||
|
maybe_byte = current_byte
|
||||||
|
|
||||||
|
# stuff...
|
||||||
|
raise NotImplementedError, "o_______o"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
""" ASM pretty printer.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError, "zzzzzz"
|
||||||
|
|
||||||
class AsmList(list):
|
class AsmList(list):
|
||||||
"""simple wrapper to prevent all asm lines from being shown on screen"""
|
""" Simple wrapper to prevent all asm lines from being shown on screen.
|
||||||
|
"""
|
||||||
|
|
||||||
def length(self):
|
def length(self):
|
||||||
"""len(self)"""
|
""" len(self)
|
||||||
|
"""
|
||||||
return len(self)
|
return len(self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
""" Simplifies this object so that the output doesn't overflow stdout.
|
||||||
|
"""
|
||||||
return "AsmList(too long)"
|
return "AsmList(too long)"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user