shithub: pokecrystal

Download patch

ref: 7dd0c86a6b6ebe03ed00dc7bd75d54d7b33db374
parent: 0768fead4fc4c0ff5b88637b02b5fb46484153df
author: Bryan Bishop <[email protected]>
date: Wed Jun 6 21:07:48 EDT 2012

almost complete new disassembler version

--- a/extras/gbz80disasm.py
+++ b/extras/gbz80disasm.py
@@ -559,7 +559,6 @@
         all_labels = json.loads(open(filename, "r").read())
     else:
         print "You must run analyze_incbins.scan_for_predefined_labels() to create \"labels.json\"."
-load_labels()
 
 def find_label(local_address, bank_id=0):
     return None
@@ -827,5 +826,6 @@
     return True
 
 if __name__ == "__main__":
+    load_labels()
     load_rom()
     print output_bank_opcodes(int(sys.argv[1], 16))[0]
--- a/extras/romstr.py
+++ b/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):
-    """ 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 __repr__(self):
+        """ Simplifies this object so that the output doesn't overflow stdout.
+        """
+        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)"""
+        """ len(self)
+        """
         return len(self)
 
-    def __repr__(self):
-        return "RomStr(too long)"
+    def len(self):
+        """ len(self)
+        """
+        return self.length()
 
     def interval(self, offset, length, strings=True, debug=True):
-        """returns hex values for the rom starting at offset until offset+length"""
-        returnable = [] 
+        """ returns hex values for the rom starting at offset until
+            offset+length
+        """
+        returnable = []
         for byte in self[offset:offset+length]:
             if strings:
                 returnable.append(hex(ord(byte)))
@@ -20,16 +46,148 @@
         return returnable
 
     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)
 
+    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):
-    """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):
-        """len(self)"""
+        """ len(self)
+        """
         return len(self)
 
     def __repr__(self):
+        """ Simplifies this object so that the output doesn't overflow stdout.
+        """
         return "AsmList(too long)"