diff options
Diffstat (limited to 'extras')
| m--------- | extras | 0 | ||||
| -rwxr-xr-x | extras/configuration.py | 57 | ||||
| -rwxr-xr-x | extras/gbz80disasm.py | 998 | ||||
| -rwxr-xr-x | extras/gfx.py | 668 | ||||
| -rwxr-xr-x | extras/labels.py | 81 | ||||
| -rwxr-xr-x | extras/scan_includes.py | 36 | ||||
| -rwxr-xr-x | extras/wram.py | 299 | 
7 files changed, 0 insertions, 2139 deletions
| diff --git a/extras b/extras new file mode 160000 +Subproject dfe657177453423987544798d9763b2938874b4 diff --git a/extras/configuration.py b/extras/configuration.py deleted file mode 100755 index 1592fe6..0000000 --- a/extras/configuration.py +++ /dev/null @@ -1,57 +0,0 @@ -""" -Configuration -""" - -import os - -class ConfigException(Exception): -    """ -    Configuration error. Maybe a missing config variable. -    """ - -class Config(object): -    """ -    The Config class handles all configuration for pokemontools. Other classes -    and functions use a Config object to determine where expected files can be -    located. -    """ - -    def __init__(self, **kwargs): -        """ -        Store all parameters. -        """ -        self._config = {} - -        for (key, value) in kwargs.items(): -            if key not in self.__dict__: -                self._config[key] = value -            else: -                raise ConfigException( -                    "Can't store \"{0}\" in configuration because the key conflicts with an existing property." -                    .format(key) -                ) - -        if "path" not in self._config: -            self._config["path"] = os.getcwd() - -        # vba save states go into ./save-states/ -        if "save_state_path" not in self._config: -            self._config["save_state_path"] = os.path.join(self._config["path"], "save-states/") - -        # assume rom is at ./baserom.gbc -        if "rom" not in self._config: -            self._config["rom_path"] = os.path.join(self._config["path"], "baserom.gbc") - -    def __getattr__(self, key): -        """ -        Grab the value from the class properties, then check the configuration, -        and raise an exception if nothing works. -        """ -        if key in self.__dict__: -            return self.__dict__[key] -        elif key in self._config: -            return self._config[key] -        else: -            raise ConfigException( -                "no config found for \"{0}\"".format(key) -            ) diff --git a/extras/gbz80disasm.py b/extras/gbz80disasm.py deleted file mode 100755 index 2e9e8b3..0000000 --- a/extras/gbz80disasm.py +++ /dev/null @@ -1,998 +0,0 @@ -# -*- coding: utf-8 -*- -""" -GBC disassembler, specialized for TCG macros -""" - -import os -import sys -from copy import copy, deepcopy -from ctypes import c_int8 -import random -import json - -import configuration -import labels -import wram - -# New versions of json don't have read anymore. -if not hasattr(json, "read"): -    json.read = json.loads - -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 ], # rgbds uses [sp+x] -  [ "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 ], -  [ "BANK1CALL ?", 0xdf, 4 ], -  [ "RST $20", 0xe7, 0 ], -  [ "FARCALL x, ?", 0xef, 4 ], -  [ "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 = [ -0xc9, #ret -0xd9, #reti -0xe9, #jp hl -#0xc3, #jp -##0x18, #jr -###0xda, 0xe9, 0xd2, 0xc2, 0xca, 0xc3, 0x38, 0x30, 0x20, 0x28, 0x18, 0xd8, 0xd0, 0xc0, 0xc8, 0xc9 -] - -discrete_jumps = [0xda, 0xe9, 0xd2, 0xc2, 0xca, 0xc3] -relative_jumps = [0x38, 0x30, 0x20, 0x28, 0x18, 0xc3, 0xda, 0xc2] -relative_unconditional_jumps = [0xc3, 0x18] - -call_commands = [0xdc, 0xd4, 0xc4, 0xcc, 0xcd] - -def asm_label(address): -    """ -    Return the ASM label using the address. -    """ -    # why using a random value when you can use the address? -    return '.asm_%x' % address - -def data_label(address): -    return '.data_%x' % address - -def get_local_address(address): -    bank = address / 0x4000 -    return (address & 0x3fff) + 0x4000 * bool(bank) - -def get_global_address(address, bank): -    if address < 0x8000: -        return (address & 0x3fff) + 0x4000 * bank -    return None - -    return ".ASM_" + hex(address)[2:] - -def has_outstanding_labels(byte_labels): -    """ -    Check whether a label is used once in the asm output. - -    If so, 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 - -class Disassembler(object): -    """ -    GBC disassembler -    """ - -    def __init__(self, config): -        """ -        Setup the class instance. -        """ -        self.config = config - -        self.wram = wram.WRAMProcessor(self.config) -        self.labels = labels.Labels(self.config) - -    def initialize(self): -        """ -        Setup the disassembler. -        """ -        self.wram.initialize() -        self.labels.initialize() - -        # TODO: fix how ROM is handled throughout the project. -        rom_path = os.path.join(self.config.path, "baserom.gbc") -        self.rom = bytearray(open(rom_path, "rb").read()) - -    def find_label(self, local_address, bank_id=0): -        # keep an integer -        if type(local_address) == str: -            local_address = int(local_address.replace("$", "0x"), 16) - -        if local_address < 0x8000: -            for label_entry in self.labels.labels: -                if get_local_address(label_entry["address"]) == local_address: -                    if "bank" in label_entry and (label_entry["bank"] == bank_id or label_entry["bank"] == 0): -                        return label_entry["label"] -        if local_address in self.wram.wram_labels.keys(): -            return self.wram.wram_labels[local_address][-1] -        for constants in [self.wram.gbhw_constants, self.wram.hram_constants]: -            if local_address in constants.keys() and local_address >= 0xff00: -                return constants[local_address] -        return None - -    def find_address_from_label(self, label): -        for label_entry in self.labels.labels: -            if label == label_entry["label"]: -                return label_entry["address"] -        return None - -    def output_bank_opcodes(self, original_offset, max_byte_count=0x4000, include_last_address=True, stop_at=[], debug=False): -        """ -        Output bank opcodes. - -        fs = current_address -        b = bank_byte -        in = input_data  -- rom -        bank_size = byte_count -        i = offset -        ad = end_address -        a, oa = current_byte_number - -        stop_at can be used to supply a list of addresses to not disassemble -        over. This is useful if you know in advance that there are a lot of -        fall-throughs. -        """ - -        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 - -        rom = self.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 = {} -        data_tables = {} - -        first_loop = True -        output = "" -        keep_reading = True -        is_data = False -        while offset <= end_address and keep_reading: -            current_byte = rom[offset] -            maybe_byte = current_byte - -            # stop at any address -            if not first_loop and offset in stop_at: -                keep_reading = False -                break - -            #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 -                output += "\n" -            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 + "\n" #" ; " + hex(offset) + "\n" - -            #find out if there's a two byte key like this -            temp_maybe = maybe_byte -            temp_maybe += ( rom[offset+1] << 8) -            if not is_data and temp_maybe in opt_table.keys() and rom[offset+1]!=0: -                opstr = opt_table[temp_maybe][0].lower() - -                if "x" in opstr: -                    for x in range(0, opstr.count("x")): -                        insertion = 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 = rom[offset + 1] -                        byte2 = 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 not is_data and 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 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 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 = 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(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 -                            if has_outstanding_labels(byte_labels) and all_outstanding_labels_are_reverse(byte_labels, offset): -                                include_comment = True -                        elif current_byte == 0x3e: -                            last_a_address = 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("$") > 1 and "+" in opstr: -                            first_orig = opstr[opstr.find("$"):opstr.find("+")] -                            first_val = eval(first_orig.replace("$","0x")) - -                            second_orig = opstr[opstr.find("+$")+1:opstr.find("]")] -                            second_val = eval(second_orig.replace("$","0x")) - -                            combined_val = "$%.4x" % (first_val + second_val) -                            result = self.find_label(combined_val, bank_id) -                            if result != None: -                                combined_val = result - -                            replacetron = "[%s+%s]" % (first_orig, second_orig) -                            opstr = opstr.replace(replacetron, "[%s]" % combined_val) - -                        output += spacing + opstr -                        if include_comment: -                            output += " ; " + hex(offset) -                            if current_byte in relative_jumps: -                                output += " $" + hex(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 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 = rom[offset + 1] -                        byte2 = rom[offset + 2] - -                        number = byte1 -                        number += byte2 << 8 - -                        if current_byte not in call_commands + discrete_jumps + relative_jumps: -                            pointer = get_global_address(number, bank_id) -                            if pointer not in data_tables.keys(): -                                data_tables[pointer] = {} -                                data_tables[pointer]['usage'] = 0 -                            else: -                                data_tables[pointer]['usage'] += 1 - -                        insertion = "$%.4x" % (number) -                        result = self.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 -                elif op_code_type == 4 and rom[offset] == op_code_byte: -                    oplen = len(op_code[0]) -                    opstr = copy(op_code[0]) -                    if op_code_byte == 0xef: -                        xes = op_code[0].count("x") -                        for x in range(0, xes): -                            temp_bank = rom[offset + 1] -                            insertion = "$" + hex(temp_bank)[2:] -                            temp_opstr = opstr[:opstr.find("x")].lower() + insertion + opstr[opstr.find("x")+1:].lower() - -                            current_byte_number += 1 -                            offset += 1 -                    else: -                        temp_bank = 1 - -                    qes = op_code[0].count("?") -                    for x in range(0, qes): -                        byte1 = rom[offset + 1] -                        byte2 = rom[offset + 2] - -                        number = byte1 -                        number += byte2 << 8 - -                        insertion = "$%.4x" % (number) -                        result = self.find_label(insertion, temp_bank) -                        if op_code_byte == 0xef: -                            if result != None: -                                insertion = result -                                opstr = opstr[:opstr.find("x, ?")].lower() + insertion + opstr[opstr.find("x, ?")+4:].lower() -                            else: -                                opstr = temp_opstr[:temp_opstr.find("?")].lower() + insertion + temp_opstr[temp_opstr.find("?")+1:].lower() -                                opstr = "farcallx" + opstr[7:] -                        else: -                            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 -                else: -                    is_data = True -            else: -            #if is_data and keep_reading: -                output += spacing + "db $" + hex(rom[offset])[2:] #+ " ; " + hex(offset) -                output += "\n" -                offset += 1 -                current_byte_number += 1 -                if offset in byte_labels.keys(): -                    is_data = False -                    keep_reading = True -            #else the while loop would have spit out the opcode - -            #these two are done prior -            #offset += 1 -            #current_byte_number += 1 - -            if not is_data and current_byte in relative_unconditional_jumps + end_08_scripts_with: -                #stop reading at a jump, relative jump or return -                if not has_outstanding_labels(byte_labels) or all_outstanding_labels_are_reverse(byte_labels, offset): -                    keep_reading = False -                    is_data = False #cleanup -                    break -                elif offset not in byte_labels.keys() and offset in data_tables.keys(): -                    is_data = True -                    keep_reading = True -                else: -                    is_data = False -                    keep_reading = True -                output += "\n" -            elif is_data and offset not in byte_labels.keys(): -                is_data = True -                keep_reading = True -            else: -                is_data = False -                keep_reading = True - -            if offset in data_tables.keys(): -                output = output.replace('$%x' % (get_local_address(offset)), data_label(offset)) -                output += data_label(offset) + '\n' -                is_data = True -                keep_reading = True - -            first_loop = False - -        #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"), "") - -        #tone down excessive spacing -        output = output.replace("\n\n\n","\n\n") - -        #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) - -if __name__ == "__main__": -    conf = configuration.Config() -    disasm = Disassembler(conf) -    disasm.initialize() - -    addr = sys.argv[1] -    if ":" in addr: -        addr = addr.split(":") -        addr = int(addr[0], 16)*0x4000+(int(addr[1], 16)%0x4000) -    else: -        label_addr = disasm.find_address_from_label(addr) -        if label_addr: -            addr = label_addr -        else: -            addr = int(addr, 16) -    if addr / 0x4000 == 0: -        if addr < 0x1000: -            output = "Func_0{:02x}: ; 0{:02x} ({:0x}:0{:02x})\n".format(addr, addr, addr / 0x4000, addr) -        else: -            output = "Func_{:02x}: ; {:02x} ({:0x}:{:02x})\n".format(addr, addr, addr / 0x4000, addr % 0x4000) -    else: -        output = "Func_{:02x}: ; {:02x} ({:0x}:{:02x})\n".format(addr, addr, addr / 0x4000, addr % 0x4000 + 0x4000) -    output += disasm.output_bank_opcodes(addr)[0] -    print output diff --git a/extras/gfx.py b/extras/gfx.py deleted file mode 100755 index 38f6f5f..0000000 --- a/extras/gfx.py +++ /dev/null @@ -1,668 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import sys -import png -from math import sqrt, floor, ceil -import argparse - -def split(list_, interval): -    """ -    Split a list by length. -    """ -    for i in xrange(0, len(list_), interval): -        j = min(i + interval, len(list_)) -        yield list_[i:j] - -def get_tiles(image): -    """ -    Split a 2bpp image into 8x8 tiles. -    """ -    return list(split(image, 0x10)) - -def connect(tiles): -    """ -    Combine 8x8 tiles into a 2bpp image. -    """ -    return [byte for tile in tiles for byte in tile] - -def transpose(tiles, width=None): -    """ -    Transpose a tile arrangement along line y=-x. - -      00 01 02 03 04 05     00 06 0c 12 18 1e -      06 07 08 09 0a 0b     01 07 0d 13 19 1f -      0c 0d 0e 0f 10 11 <-> 02 08 0e 14 1a 20 -      12 13 14 15 16 17     03 09 0f 15 1b 21 -      18 19 1a 1b 1c 1d     04 0a 10 16 1c 22 -      1e 1f 20 21 22 23     05 0b 11 17 1d 23 - -      00 01 02 03     00 04 08 -      04 05 06 07 <-> 01 05 09 -      08 09 0a 0b     02 06 0a -                      03 07 0b -    """ -    if width == None: -        width = int(sqrt(len(tiles))) # assume square image -    tiles = sorted(enumerate(tiles), key= lambda (i, tile): i % width) -    return [tile for i, tile in tiles] - -def transpose_tiles(image, width=None): -    return connect(transpose(get_tiles(image), width)) - -def interleave(tiles, width): -    """ -      00 01 02 03 04 05     00 02 04 06 08 0a -      06 07 08 09 0a 0b     01 03 05 07 09 0b -      0c 0d 0e 0f 10 11 --> 0c 0e 10 12 14 16 -      12 13 14 15 16 17     0d 0f 11 13 15 17 -      18 19 1a 1b 1c 1d     18 1a 1c 1e 20 22 -      1e 1f 20 21 22 23     19 1b 1d 1f 21 23 -    """ -    interleaved = [] -    left, right = split(tiles[::2], width), split(tiles[1::2], width) -    for l, r in zip(left, right): -        interleaved += l + r -    return interleaved - -def deinterleave(tiles, width): -    """ -      00 02 04 06 08 0a     00 01 02 03 04 05  -      01 03 05 07 09 0b     06 07 08 09 0a 0b -      0c 0e 10 12 14 16 --> 0c 0d 0e 0f 10 11 -      0d 0f 11 13 15 17     12 13 14 15 16 17 -      18 1a 1c 1e 20 22     18 19 1a 1b 1c 1d -      19 1b 1d 1f 21 23     1e 1f 20 21 22 23 -    """ -    deinterleaved = [] -    rows = list(split(tiles, width)) -    for left, right in zip(rows[::2], rows[1::2]): -        for l, r in zip(left, right): -            deinterleaved += [l, r] -    return deinterleaved - -def interleave_tiles(image, width): -    return connect(interleave(get_tiles(image), width)) - -def deinterleave_tiles(image, width): -    return connect(deinterleave(get_tiles(image), width)) - -def condense_tiles_to_map(image): -    tiles = get_tiles(image) -    new_tiles = [] -    tilemap = [] -    for tile in tiles: -        if tile not in new_tiles: -            new_tiles += [tile] -        tilemap += [new_tiles.index(tile)] -    new_image = connect(new_tiles) -    return new_image, tilemap - -def to_file(filename, data): -    file = open(filename, 'wb') -    for byte in data: -        file.write('%c' % byte) -    file.close() - -def bin_to_rgb(word): -    red   = word & 0b11111 -    word >>= 5 -    green = word & 0b11111 -    word >>= 5 -    blue  = word & 0b11111 -    return (red, green, blue) - -def convert_binary_pal_to_text_by_filename(filename): -    pal = bytearray(open(filename).read()) -    return convert_binary_pal_to_text(pal) - -def convert_binary_pal_to_text(pal): -    output = '' -    words = [hi * 0x100 + lo for lo, hi in zip(pal[::2], pal[1::2])] -    for word in words: -        red, green, blue = ['%.2d' % c for c in bin_to_rgb(word)] -        output += '\tRGB ' + ', '.join((red, green, blue)) -        output += '\n' -    return output - -def read_rgb_macros(lines): -    colors = [] -    for line in lines: -        macro = line.split(" ")[0].strip() -        if macro == 'RGB': -            params = ' '.join(line.split(" ")[1:]).split(',') -            red, green, blue = [int(v) for v in params] -            colors += [[red, green, blue]] -    return colors - -def flatten(planar): -    """ -    Flatten planar 2bpp image data into a quaternary pixel map. -    """ -    strips = [] -    for bottom, top in split(planar, 2): -        bottom = bottom -        top = top -        strip = [] -        for i in xrange(7,-1,-1): -            color = ( -                (bottom >> i & 1) + -                (top *2 >> i & 2) -            ) -            strip += [color] -        strips += strip -    return strips - -def to_lines(image, width): -    """ -    Convert a tiled quaternary pixel map to lines of quaternary pixels. -    """ -    tile_width = 8 -    tile_height = 8 -    num_columns = width / tile_width -    height = len(image) / width - -    lines = [] -    for cur_line in xrange(height): -        tile_row = cur_line / tile_height -        line = [] -        for column in xrange(num_columns): -            anchor = ( -                num_columns * tile_row * tile_width * tile_height + -                column * tile_width * tile_height + -                cur_line % tile_height * tile_width -            ) -            line += image[anchor : anchor + tile_width] -        lines += [line] -    return lines - -def pal_to_png(filename): -    """ -    Interpret a .pal file as a png palette. -    """ -    with open(filename) as rgbs: -        colors = read_rgb_macros(rgbs.readlines()) -    a = 255 -    palette = [] -    for color in colors: -        # even distribution over 000-255 -        r, g, b = [int(hue * 8.25) for hue in color] -        palette += [(r, g, b, a)] -    white = (255,255,255,255) -    black = (000,000,000,255) -    if white not in palette and len(palette) < 4: -        palette = [white] + palette -    if black not in palette and len(palette) < 4: -        palette = palette + [black] -    return palette - -def png_to_rgb(palette): -    """ -    Convert a png palette to rgb macros. -    """ -    output = '' -    for color in palette: -        r, g, b = [color[c] / 8 for c in 'rgb'] -        output += '\tRGB ' + ', '.join(['%.2d' % hue for hue in (r, g, b)]) -        output += '\n' -    return output - -def read_filename_arguments(filename): -    int_args = { -        'w': 'width', -        'h': 'height', -        't': 'tile_padding', -    } -    parsed_arguments = {} -    arguments = os.path.splitext(filename)[0].split('.')[1:] -    for argument in arguments: -        arg   = argument[0] -        param = argument[1:] -        if param.isdigit(): -            arg = int_args.get(arg, False) -            if arg: -                parsed_arguments[arg] = int(param) -        elif len(argument) == 3: -            w, x, h = argument[:3] -            if w.isdigit() and h.isdigit() and x == 'x': -                parsed_arguments['pic_dimensions'] = (int(w), int(h)) -        elif argument == 'interleave': -            parsed_arguments['interleave'] = True -        elif argument == 'norepeat': -            parsed_arguments['norepeat'] = True -        elif argument == 'arrange': -            parsed_arguments['norepeat'] = True -            parsed_arguments['tilemap']  = True -    return parsed_arguments - -def export_2bpp_to_png(filein, fileout=None, pal_file=None, height=0, width=0, tile_padding=0, pic_dimensions=None): - -    if fileout == None: -        fileout = os.path.splitext(filein)[0] + '.png' - -    image = open(filein, 'rb').read() - -    arguments = { -        'width': width, -        'height': height, -        'pal_file': pal_file, -        'tile_padding': tile_padding, -        'pic_dimensions': pic_dimensions, -    } -    arguments.update(read_filename_arguments(filein)) - -    if pal_file == None: -        if os.path.exists(os.path.splitext(fileout)[0]+'.pal'): -            arguments['pal_file'] = os.path.splitext(fileout)[0]+'.pal' - -    result = convert_2bpp_to_png(image, **arguments) -    width, height, palette, greyscale, bitdepth, px_map = result - -    w = png.Writer( -        width, -        height, -        palette=palette, -        compression=9, -        greyscale=greyscale, -        bitdepth=bitdepth -    ) -    with open(fileout, 'wb') as f: -        w.write(f, px_map) - -def convert_2bpp_to_png(image, **kwargs): -    """ -    Convert a planar 2bpp graphic to png. -    """ - -    image = bytearray(image) - -    pad_color = bytearray([0]) - -    width          = kwargs.get('width', 0) -    height         = kwargs.get('height', 0) -    tile_padding   = kwargs.get('tile_padding', 0) -    pic_dimensions = kwargs.get('pic_dimensions', None) -    pal_file       = kwargs.get('pal_file', None) -    interleave     = kwargs.get('interleave', False) - -    # Width must be specified to interleave. -    if interleave and width: -        image = interleave_tiles(image, width / 8) - -    # Pad the image by a given number of tiles if asked. -    image += pad_color * 0x10 * tile_padding - -    # Some images are transposed in blocks. -    if pic_dimensions: -        w, h  = pic_dimensions -        if not width: width = w * 8 - -        pic_length = w * h * 0x10 - -        trailing = len(image) % pic_length - -        pic = [] -        for i in xrange(0, len(image) - trailing, pic_length): -            pic += transpose_tiles(image[i:i+pic_length], h) -        image = bytearray(pic) + image[len(image) - trailing:] - -        # Pad out trailing lines. -        image += pad_color * 0x10 * ((w - (len(image) / 0x10) % h) % w) - -    def px_length(img): -        return len(img) * 4 -    def tile_length(img): -        return len(img) * 4 / (8*8) - -    if width and height: -        tile_width = width / 8 -        more_tile_padding = (tile_width - (tile_length(image) % tile_width or tile_width)) -        image += pad_color * 0x10 * more_tile_padding - -    elif width and not height: -        tile_width = width / 8 -        more_tile_padding = (tile_width - (tile_length(image) % tile_width or tile_width)) -        image += pad_color * 0x10 * more_tile_padding -        height = px_length(image) / width - -    elif height and not width: -        tile_height = height / 8 -        more_tile_padding = (tile_height - (tile_length(image) % tile_height or tile_height)) -        image += pad_color * 0x10 * more_tile_padding -        width = px_length(image) / height - -    # at least one dimension should be given -    if width * height != px_length(image): -        # look for possible combos of width/height that would form a rectangle -        matches = [] -        # Height need not be divisible by 8, but width must. -        # See pokered gfx/minimize_pic.1bpp. -        for w in range(8, px_length(image) / 2 + 1, 8): -            h = px_length(image) / w -            if w * h == px_length(image): -                matches += [(w, h)] -        # go for the most square image -        if len(matches): -            width, height = sorted(matches, key= lambda (w, h): (h % 8 != 0, w + h))[0] # favor height -        else: -            raise Exception, 'Image can\'t be divided into tiles (%d px)!' % (px_length(image)) - -    # convert tiles to lines -    lines = to_lines(flatten(image), width) - -    if pal_file == None: -        palette   = None -        greyscale = True -        bitdepth  = 2 -        px_map    = [[3 - pixel for pixel in line] for line in lines] - -    else: # gbc color -        palette   = pal_to_png(pal_file) -        greyscale = False -        bitdepth  = 8 -        px_map    = [[pixel for pixel in line] for line in lines] - -    return width, height, palette, greyscale, bitdepth, px_map - -def export_png_to_2bpp(filein, fileout=None, palout=None, tile_padding=0, pic_dimensions=None): - -    arguments = { -        'tile_padding': tile_padding, -        'pic_dimensions': pic_dimensions, -    } -    arguments.update(read_filename_arguments(filein)) - -    image, palette, tmap = png_to_2bpp(filein, **arguments) - -    if fileout == None: -        fileout = os.path.splitext(filein)[0] + '.2bpp' -    to_file(fileout, image) - -    if tmap != None: -        mapout = os.path.splitext(fileout)[0] + '.tilemap' -        to_file(mapout, tmap) - -    if palout == None: -        palout = os.path.splitext(fileout)[0] + '.pal' -    export_palette(palette, palout) - -def get_image_padding(width, height, wstep=8, hstep=8): - -    padding = { -        'left':   0, -        'right':  0, -        'top':    0, -        'bottom': 0, -    } - -    if width % wstep and width >= wstep: -       pad = float(width % wstep) / 2 -       padding['left']   = int(ceil(pad)) -       padding['right']  = int(floor(pad)) - -    if height % hstep and height >= hstep: -       pad = float(height % hstep) / 2 -       padding['top']    = int(ceil(pad)) -       padding['bottom'] = int(floor(pad)) - -    return padding - -def png_to_2bpp(filein, **kwargs): -    """ -    Convert a png image to planar 2bpp. -    """ - -    tile_padding   = kwargs.get('tile_padding', 0) -    pic_dimensions = kwargs.get('pic_dimensions', None) -    interleave     = kwargs.get('interleave', False) -    norepeat       = kwargs.get('norepeat', False) -    tilemap        = kwargs.get('tilemap', False) - -    with open(filein, 'rb') as data: -        width, height, rgba, info = png.Reader(data).asRGBA8() -        rgba = list(rgba) -        greyscale = info['greyscale'] - -    # png.Reader returns flat pixel data. Nested is easier to work with -    len_px  = 4 # rgba -    image   = [] -    palette = [] -    for line in rgba: -        newline = [] -        for px in xrange(0, len(line), len_px): -            color = { 'r': line[px  ], -                      'g': line[px+1], -                      'b': line[px+2], -                      'a': line[px+3], } -            newline += [color] -            if color not in palette: -                palette += [color] -        image += [newline] - -    assert len(palette) <= 4, 'Palette should be 4 colors, is really %d' % len(palette) - -    # Pad out smaller palettes with greyscale colors -    hues = { -        'white': { 'r': 0xff, 'g': 0xff, 'b': 0xff, 'a': 0xff }, -        'black': { 'r': 0x00, 'g': 0x00, 'b': 0x00, 'a': 0xff }, -        'grey':  { 'r': 0x55, 'g': 0x55, 'b': 0x55, 'a': 0xff }, -        'gray':  { 'r': 0xaa, 'g': 0xaa, 'b': 0xaa, 'a': 0xff }, -    } -    for hue in hues.values(): -        if len(palette) >= 4: -            break -        if hue not in palette: -            palette += [hue] - -    # Sort palettes by luminance -    def luminance(color): -        rough = { 'r':  4.7, -                  'g':  1.4, -                  'b': 13.8, } -        return sum(color[key] * rough[key] for key in rough.keys()) -    palette.sort(key=luminance) - -    # Game Boy palette order -    palette.reverse() - -    # Map pixels to quaternary color ids -    padding = get_image_padding(width, height) -    width += padding['left'] + padding['right'] -    height += padding['top'] + padding['bottom'] -    pad = bytearray([0]) - -    qmap = [] -    qmap += pad * width * padding['top'] -    for line in image: -        qmap += pad * padding['left'] -        for color in line: -            qmap += [palette.index(color)] -        qmap += pad * padding['right'] -    qmap += pad * width * padding['bottom'] - -    # Graphics are stored in tiles instead of lines -    tile_width  = 8 -    tile_height = 8 -    num_columns = max(width, tile_width) / tile_width -    num_rows = max(height, tile_height) / tile_height -    image = [] - -    for row in xrange(num_rows): -        for column in xrange(num_columns): - -            # Split it up into strips to convert to planar data -            for strip in xrange(min(tile_height, height)): -                anchor = ( -                    row * num_columns * tile_width * tile_height + -                    column * tile_width + -                    strip * width -                ) -                line = qmap[anchor : anchor + tile_width] -                bottom, top = 0, 0 -                for bit, quad in enumerate(line): -                    bottom += (quad & 1) << (7 - bit) -                    top += (quad /2 & 1) << (7 - bit) -                image += [bottom, top] - -    if pic_dimensions: -        w, h = pic_dimensions - -        tiles = get_tiles(image) -        pic_length = w * h -        tile_width = width / 8 -        trailing = len(tiles) % pic_length -        new_image = [] -        for block in xrange(len(tiles) / pic_length): -            offset = (h * tile_width) * ((block * w) / tile_width) + ((block * w) % tile_width) -            pic = [] -            for row in xrange(h): -                index = offset + (row * tile_width) -                pic += tiles[index:index + w] -            new_image += transpose(pic, w) -        new_image += tiles[len(tiles) - trailing:] -        image = connect(new_image) - -    # Remove any tile padding used to make the png rectangular. -    image = image[:len(image) - tile_padding * 0x10] - -    if interleave: -        image = deinterleave_tiles(image, num_columns) - -    if norepeat: -        image, tmap = condense_tiles_to_map(image) -    if not tilemap: -        tmap = None - -    return image, palette, tmap - -def export_palette(palette, filename): -    """ -    Export a palette from png to rgb macros in a .pal file. -    """ - -    if os.path.exists(filename): - -        # Pic palettes are 2 colors (black/white are added later). -        with open(filename) as rgbs: -            colors = read_rgb_macros(rgbs.readlines()) - -        if len(colors) == 2: -            palette = palette[1:3] - -        text = png_to_rgb(palette) -        with open(filename, 'w') as out: -            out.write(text) - -def convert_2bpp_to_1bpp(data): -    """ -    Convert planar 2bpp image data to 1bpp. Assume images are two colors. -    """ -    return data[::2] - -def convert_1bpp_to_2bpp(data): -    """ -    Convert 1bpp image data to planar 2bpp (black/white). -    """ -    output = [] -    for i in data: -        output += [i, i] -    return output - -def export_2bpp_to_1bpp(filename): -    name, extension = os.path.splitext(filename) -    image = open(filename, 'rb').read() -    image = convert_2bpp_to_1bpp(image) -    to_file(name + '.1bpp', image) - -def export_1bpp_to_2bpp(filename): -    name, extension = os.path.splitext(filename) -    image = open(filename, 'rb').read() -    image = convert_1bpp_to_2bpp(image) -    to_file(name + '.2bpp', image) - -def export_1bpp_to_png(filename, fileout=None): - -    if fileout == None: -        fileout = os.path.splitext(filename)[0] + '.png' - -    arguments = read_filename_arguments(filename) - -    image = open(filename, 'rb').read() -    image = convert_1bpp_to_2bpp(image) - -    result = convert_2bpp_to_png(image, **arguments) -    width, height, palette, greyscale, bitdepth, px_map = result - -    w = png.Writer(width, height, palette=palette, compression=9, greyscale=greyscale, bitdepth=bitdepth) -    with open(fileout, 'wb') as f: -        w.write(f, px_map) - -def export_png_to_1bpp(filename, fileout=None): - -    if fileout == None: -        fileout = os.path.splitext(filename)[0] + '.1bpp' - -    arguments = read_filename_arguments(filename) -    image = png_to_1bpp(filename, **arguments) - -    to_file(fileout, image) - -def png_to_1bpp(filename, **kwargs): -    image, palette, tmap = png_to_2bpp(filename, **kwargs) -    return convert_2bpp_to_1bpp(image) - -def convert_to_2bpp(filenames=[]): -    for filename in filenames: -        name, extension = os.path.splitext(filename) -        if extension == '.1bpp': -            export_1bpp_to_2bpp(filename) -        elif extension == '.2bpp': -            pass -        elif extension == '.png': -            export_png_to_2bpp(filename) -        else: -            raise Exception, "Don't know how to convert {} to 2bpp!".format(filename) - -def convert_to_1bpp(filenames=[]): -    for filename in filenames: -        name, extension = os.path.splitext(filename) -        if extension == '.1bpp': -            pass -        elif extension == '.2bpp': -            export_2bpp_to_1bpp(filename) -        elif extension == '.png': -            export_png_to_1bpp(filename) -        else: -            raise Exception, "Don't know how to convert {} to 1bpp!".format(filename) - -def convert_to_png(filenames=[]): -    for filename in filenames: -        name, extension = os.path.splitext(filename) -        if extension == '.1bpp': -            export_1bpp_to_png(filename) -        elif extension == '.2bpp': -            export_2bpp_to_png(filename) -        elif extension == '.png': -            pass -        else: -            raise Exception, "Don't know how to convert {} to png!".format(filename) - -def main(): -    ap = argparse.ArgumentParser() -    ap.add_argument('mode') -    ap.add_argument('filenames', nargs='*') -    args = ap.parse_args() - -    method = { -        '2bpp': convert_to_2bpp, -        '1bpp': convert_to_1bpp, -        'png':  convert_to_png, -    }.get(args.mode, None) - -    if method == None: -        raise Exception, "Unknown conversion method!" - -    method(args.filenames) - -if __name__ == "__main__": -    main() diff --git a/extras/labels.py b/extras/labels.py deleted file mode 100755 index bbd0079..0000000 --- a/extras/labels.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- -""" -Various label/line-related functions. -""" - -import os - -class Labels(object): -    """ -    Store all labels. -    """ - -    def __init__(self, config, filename="tcg.map"): -        """ -        Setup the instance. -        """ -        self.config = config -        self.filename = filename -        self.path = os.path.join(self.config.path, self.filename) - -    def initialize(self): -        """ -        Handle anything requiring file-loading and such. -        """ -        # Look for a mapfile if it's not given -        if not os.path.exists(self.path): -            self.filename = find_mapfile_in_dir(self.config.path) -            if self.filename == None: -                raise Exception, "Couldn't find any mapfiles. Run rgblink -m to create a mapfile." -            self.path = os.path.join(self.config.path, self.filename) - -        self.labels = read_mapfile(self.path) - -def find_mapfile_in_dir(path): -    for filename in os.listdir(path): -        if os.path.splitext(filename)[1] == '.map': -            return filename -    return None - -def read_mapfile(filename='tcg.map'): -    """ -    Scrape label addresses from an rgbds mapfile. -    """ - -    labels = [] - -    with open(filename, 'r') as mapfile: -        lines = mapfile.readlines() - -    for line in lines: -        if line[0].strip(): # section type def -            section_type = line.split(' ')[0] -            if section_type == 'Bank': # ROM -                cur_bank = int(line.split(' ')[1].split(':')[0][1:]) -            elif section_type in ['WRAM0', 'HRAM']: -                cur_bank = 0 -            elif section_type in ['WRAM, VRAM']: -                cur_bank = int(line.split(' ')[2].split(':')[0][1:]) -                cur_bank = int(line.split(' ')[2].split(':')[0][1:]) - -        # label definition -        elif '=' in line: -            address, label = line.split('=') -            address = int(address.lstrip().replace('$', '0x'), 16) -            label = label.strip() - -            bank = cur_bank -            offset = address -            if address < 0x8000 and bank: # ROM -                offset += (bank - 1) * 0x4000 - -            labels += [{ -                'label': label, -                'bank': bank, -                'address': offset, -                'offset': offset, -                'local_address': address, -            }] - -    return labels - diff --git a/extras/scan_includes.py b/extras/scan_includes.py deleted file mode 100755 index 466402c..0000000 --- a/extras/scan_includes.py +++ /dev/null @@ -1,36 +0,0 @@ -# coding: utf-8 - -""" -Recursively scan an asm file for rgbasm INCLUDEs and INCBINs. -Used to generate dependencies for each rgbasm object. -""" - -import os -import sys - -import configuration -conf = configuration.Config() - -def recursive_scan(filename, includes = []): -	if (filename[-4:] == '.asm') and os.path.exists(filename): -		lines = open(filename).readlines() -		for line in lines: -			for directive in ('INCLUDE', 'INCBIN'): -				if directive in line: -					line = line[:line.find(';')] -					if directive in line: -						include = "src/" + line.split('"')[1] -						if include not in includes and include != "src/baserom.gbc": -							includes += [include] -							includes = recursive_scan(os.path.join(conf.path, include), includes) -						break -	return includes - -if __name__ == '__main__': -	filenames = sys.argv[1:] -	dependencies = [] -	for filename in filenames: -		dependencies += recursive_scan(os.path.join(conf.path, filename)) -	dependencies = list(set(dependencies)) -	sys.stdout.write(' '.join(dependencies)) - diff --git a/extras/wram.py b/extras/wram.py deleted file mode 100755 index a095cc0..0000000 --- a/extras/wram.py +++ /dev/null @@ -1,299 +0,0 @@ -# coding: utf-8 -""" -RGBDS BSS section and constant parsing. -""" - -import os - - -def separate_comment(line): -    if ';' in line: -        i = line.find(';') -        return line[:i], line[i:] -    return line, None - - -def rgbasm_to_py(text): -    return text.replace('$', '0x').replace('%', '0b') - - -def make_wram_labels(wram_sections): -    wram_labels = {} -    for section in wram_sections: -        for label in section['labels']: -            if label['address'] not in wram_labels.keys(): -                wram_labels[label['address']] = [] -            wram_labels[label['address']] += [label['label']] -    return wram_labels - -def bracket_value(string, i=0): -    return string.split('[')[1 + i*2].split(']')[0] - -class BSSReader: -    """Really?""" -    sections  = [] -    section   = None -    address   = None -    macros    = {} -    constants = { -        # TODO: parse these constants from constants.asm -        'NUM_OBJECTS': 0x10, -        'OBJECT_LENGTH': 0x10, -    } - -    section_types = { -        'VRAM':  0x8000, -        'SRAM':  0xa000, -        'WRAM0': 0xc000, -        'WRAMX': 0xd000, -        'HRAM':  0xff80, -    } - -    def __init__(self, *args, **kwargs): -        self.__dict__.update(kwargs) - -    def read_bss_line(self, l): -        parts = l.strip().split(' ') -        token = parts[0].strip() -        params = ' '.join(parts[1:]).split(',') - -        if token in ['ds', 'db', 'dw']: -            if any(params): -                length = eval(rgbasm_to_py(params[0]), self.constants) -            else: -                length = {'ds': 1, 'db': 1, 'dw': 2}[token] -            self.address += length -            # assume adjacent labels to use the same space -            for label in self.section['labels'][::-1]: -                if label['length'] == 0: -                    label['length'] = length -                else: -                    break - -        elif token in self.macros.keys(): -            macro_text = '\n'.join(self.macros[token]) + '\n' -            for i, p in enumerate(params): -                macro_text = macro_text.replace('\\'+str(i+1),p) -            macro_text = macro_text.split('\n') -            macro_reader = BSSReader( -                sections  = list(self.sections), -                section   = dict(self.section), -                address   = self.address, -                constants = self.constants, -            ) -            macro_sections = macro_reader.read_bss_sections(macro_text) -            self.section = macro_sections[-1] -            self.address = self.section['labels'][-1]['address'] + self.section['labels'][-1]['length'] - - -    def read_bss_sections(self, bss): - -        if self.section is None: -            self.section = { -                "labels": [], -            } - -        if type(bss) is str: -            bss = bss.split('\n') - -        macro = False -        macro_name = None -        for line in bss: -            line = line.lstrip() -            line, comment = separate_comment(line) -            line = line.strip() - -            if line[-4:].upper() == 'ENDM': -                macro = False -                macro_name = None - -            elif macro: -                self.macros[macro_name] += [line] - -            elif line[-5:].upper() == 'MACRO': -                macro_name = line.split(':')[0] -                macro = True -                self.macros[macro_name] = [] - -            elif 'SECTION' == line[:7]: -                if self.section: # previous -                    self.sections += [self.section] - -                section_def = line.split(',') -                name  = section_def[0].split('"')[1] -                type_ = section_def[1].strip() -                if len(section_def) > 2: -                    bank = bracket_value(section_def[2]) -                else: -                    bank = None - -                if '[' in type_: -                    self.address = int(rgbasm_to_py(bracket_value(type_)), 16) -                else: -                    if self.address == None or bank != self.section['bank'] or self.section['type'] != type_: -                        self.address = self.section_types.get(type_, self.address) -                    # else: keep going from this address - -                self.section = { -                    'name': name, -                    'type': type_, -                    'bank': bank, -                    'start': self.address, -                    'labels': [], -                } - -            elif ':' in line: -                # rgbasm allows labels without :, but prefer convention -                label = line[:line.find(':')] -                if '\\' in label: -                    raise Exception, line + ' ' + label -                if ';' not in label: -                    section_label = { -                        'label': label, -                        'address': self.address, -                        'length': 0, -                    } -                    self.section['labels'] += [section_label] -                    self.read_bss_line(line.split(':')[-1]) - -            elif 'EQU' in line.split(): -                # some space is defined using constants -                name, value = line.split('EQU') -                name, value = name.strip(), value.strip().replace('$','0x').replace('%','0b') -                self.constants[name] = eval(value, self.constants) - -            elif line: -                self.read_bss_line(line) - -        self.sections += [self.section] -        return self.sections - -def read_bss_sections(bss): -    reader = BSSReader() -    return reader.read_bss_sections(bss) - - -def constants_to_dict(constants): -    return dict((eval(rgbasm_to_py(constant[constant.find('EQU')+3:constant.find(';')])), constant[:constant.find('EQU')].strip()) for constant in constants) - -def scrape_constants(text): -    if type(text) is not list: -        text = text.split('\n') -    return constants_to_dict([line for line in text if 'EQU' in line[:line.find(';')]]) - -def read_constants(filepath): -    """ -    Load lines from a file and call scrape_constants. -    """ -    lines = [] -    if os.path.exists(filepath): -        with open(filepath, "r") as file_handler: -            lines = file_handler.readlines() - -    constants = scrape_constants(lines) -    return constants - -class WRAMProcessor(object): -    """ -    RGBDS BSS section and constant parsing. -    """ - -    def __init__(self, config): -        """ -        Setup for WRAM parsing. -        """ -        self.config = config - -        self.paths = {} - -        if hasattr(self.config, "wram"): -            self.paths["wram"] = self.config.wram -        else: -            self.paths["wram"] = os.path.join(self.config.path, "wram.asm") - -        if hasattr(self.config, "hram"): -            self.paths["hram"] = self.config.hram -        else: -            self.paths["hram"] = os.path.join(self.config.path, "hram.asm") - -        if hasattr(self.config, "gbhw"): -            self.paths["gbhw"] = self.config.gbhw -        else: -            self.paths["gbhw"] = os.path.join(self.config.path, "gbhw.asm") - -    def initialize(self): -        """ -        Read constants. -        """ -        self.setup_wram_sections() -        self.setup_wram_labels() -        self.setup_hram_constants() -        self.setup_gbhw_constants() - -        self.reformat_wram_labels() - -    def read_wram_sections(self): -        """ -        Opens the wram file and calls read_bss_sections. -        """ -        wram_content = None -        wram_file_path = self.paths["wram"] - -        with open(wram_file_path, "r") as wram: -            wram_content = wram.readlines() - -        wram_sections = read_bss_sections(wram_content) -        return wram_sections - -    def setup_wram_sections(self): -        """ -        Call read_wram_sections and set a variable. -        """ -        self.wram_sections = self.read_wram_sections() -        return self.wram_sections - -    def setup_wram_labels(self): -        """ -        Make wram labels based on self.wram_sections as input. -        """ -        self.wram_labels = make_wram_labels(self.wram_sections) -        return self.wram_labels - -    def read_hram_constants(self): -        """ -        Read constants from hram.asm using read_constants. -        """ -        hram_constants = read_constants(self.paths["hram"]) -        return hram_constants - -    def setup_hram_constants(self): -        """ -        Call read_hram_constants and set a variable. -        """ -        self.hram_constants = self.read_hram_constants() -        return self.hram_constants - -    def read_gbhw_constants(self): -        """ -        Read constants from gbhw.asm using read_constants. -        """ -        gbhw_constants = read_constants(self.paths["gbhw"]) -        return gbhw_constants - -    def setup_gbhw_constants(self): -        """ -        Call read_gbhw_constants and set a variable. -        """ -        self.gbhw_constants = self.read_gbhw_constants() -        return self.gbhw_constants - -    def reformat_wram_labels(self): -        """ -        Flips the wram_labels dictionary the other way around to access -        addresses by label. -        """ -        self.wram = {} - -        for (address, labels) in self.wram_labels.iteritems(): -            for label in labels: -                self.wram[label] = address | 
