SHARE
TWEET

Very hacky job to make gbz80disasm.py to work

luckytyphlosion Oct 25th, 2015 84 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # coding: utf-8
  2. """
  3. RGBDS BSS section and constant parsing.
  4. """
  5.  
  6. import os
  7.  
  8.  
  9. def separate_comment(line):
  10.         if ';' in line:
  11.                 i = line.find(';')
  12.                 return line[:i], line[i:]
  13.         return line, None
  14.  
  15.  
  16. def rgbasm_to_py(text):
  17.         return text.replace('$', '0x').replace('%', '0b').replace('@', '0xd8a3')
  18.  
  19. def rgbasm_to_py2(text):
  20.         return text.replace('$', '0x').replace('%', '%').replace('@', '0xd8a3')
  21.        
  22. def make_wram_labels(wram_sections):
  23.         wram_labels = {}
  24.         for section in wram_sections:
  25.                 for label in section['labels']:
  26.                         if label['address'] not in wram_labels.keys():
  27.                                 wram_labels[label['address']] = []
  28.                         wram_labels[label['address']] += [label['label']]
  29.         return wram_labels
  30.  
  31. def bracket_value(string, i=0):
  32.         return string.split('[')[1 + i*2].split(']')[0]
  33.  
  34. saved_value = ""
  35. class BSSReader:
  36.         """
  37.         Read rgbasm BSS/WRAM sections and associate labels with addresses.
  38.         Also reads constants/variables, even in macros.
  39.         """
  40.         sections  = []
  41.         section   = None
  42.         address   = None
  43.         macros  = {}
  44.         constants = {}
  45.  
  46.         section_types = {
  47.                 'VRAM':  0x8000,
  48.                 'SRAM':  0xa000,
  49.                 'WRAM0': 0xc000,
  50.                 'WRAMX': 0xd000,
  51.                 'HRAM':  0xff80,
  52.         }
  53.  
  54.         def __init__(self, *args, **kwargs):
  55.                 self.__dict__.update(kwargs)
  56.  
  57.         def read_bss_line(self, l):
  58.                 parts = l.strip().split(' ')
  59.                 token = parts[0].strip()
  60.                 params = ' '.join(parts[1:]).split(',')
  61.                 if token in ['ds', 'db', 'dw']:
  62.                         if any(params):
  63.                                 length = eval(rgbasm_to_py(params[0]), self.constants.copy())
  64.                         else:
  65.                                 length = {'ds': 1, 'db': 1, 'dw': 2}[token]
  66.                         self.address += length
  67.                         # assume adjacent labels to use the same space
  68.                         for label in self.section['labels'][::-1]:
  69.                                 if label['length'] == 0:
  70.                                         label['length'] = length
  71.                                 else:
  72.                                         break
  73.  
  74.                 elif token in self.macros.keys():
  75.                         macro_text = '\n'.join(self.macros[token]) + '\n'
  76.                         for i, p in enumerate(params):
  77.                                 macro_text = macro_text.replace('\\'+str(i+1),p)
  78.                         macro_text = macro_text.split('\n')
  79.                         macro_reader = BSSReader(
  80.                                 sections  = list(self.sections),
  81.                                 section   = dict(self.section),
  82.                                 address   = self.address,
  83.                                 constants = self.constants,
  84.                         )
  85.                         macro_sections = macro_reader.read_bss_sections(macro_text)
  86.                         self.section = macro_sections[-1]
  87.                         if self.section['labels']:
  88.                                 self.address = self.section['labels'][-1]['address'] + self.section['labels'][-1]['length']
  89.  
  90.  
  91.         def read_bss_sections(self, bss):
  92.  
  93.                 if self.section is None:
  94.                         self.section = {
  95.                                 "labels": [],
  96.                         }
  97.  
  98.                 if type(bss) is str:
  99.                         bss = bss.split('\n')
  100.  
  101.                 macro = False
  102.                 macro_name = None
  103.                 for line in bss:
  104.                         line = line.lstrip()
  105.                         line, comment = separate_comment(line)
  106.                         line = line.strip()
  107.                         split_line = line.split()
  108.                         split_line_upper = map(str.upper, split_line)
  109.  
  110.                         if not line:
  111.                                 pass
  112.  
  113.                         elif line[-4:].upper() == 'ENDM':
  114.                                 macro = False
  115.                                 macro_name = None
  116.  
  117.                         elif macro:
  118.                                 self.macros[macro_name] += [line]
  119.  
  120.                         elif line[-5:].upper() == 'MACRO':
  121.                                 macro_name = line.split(':')[0]
  122.                                 macro = True
  123.                                 self.macros[macro_name] = []
  124.  
  125.                         elif 'INCLUDE' == line[:7].upper():
  126.                                 filename = line.split('"')[1]
  127.                                 self.read_bss_sections(open(filename).readlines())
  128.  
  129.                         elif 'SECTION' == line[:7].upper():
  130.                                 if self.section: # previous
  131.                                         self.sections += [self.section]
  132.  
  133.                                 section_def = line.split(',')
  134.                                 name  = section_def[0].split('"')[1]
  135.                                 type_ = section_def[1].strip()
  136.                                 if len(section_def) > 2:
  137.                                         bank = bracket_value(section_def[2])
  138.                                 else:
  139.                                         bank = None
  140.  
  141.                                 if '[' in type_:
  142.                                         self.address = int(rgbasm_to_py(bracket_value(type_)), 16)
  143.                                 else:
  144.                                         if self.address == None or bank != self.section['bank'] or self.section['type'] != type_:
  145.                                                 self.address = self.section_types.get(type_, self.address)
  146.                                         # else: keep going from this address
  147.  
  148.                                 self.section = {
  149.                                         'name': name,
  150.                                         'type': type_,
  151.                                         'bank': bank,
  152.                                         'start': self.address,
  153.                                         'labels': [],
  154.                                 }
  155.  
  156.                         elif ':' in line:
  157.                                 # rgbasm allows labels without :, but prefer convention
  158.                                 label = line[:line.find(':')]
  159.                                 if '\\' in label:
  160.                                         raise Exception, line + ' ' + label
  161.                                 if ';' not in label:
  162.                                         section_label = {
  163.                                                 'label': label,
  164.                                                 'address': self.address,
  165.                                                 'length': 0,
  166.                                         }
  167.                                         self.section['labels'] += [section_label]
  168.                                         self.read_bss_line(line.split(':')[-1])
  169.                         elif any(x in split_line_upper for x in ['EQU', '=', 'SET']): # TODO: refactor
  170.                                 for x in ['EQU', '=', 'SET']:
  171.                                         if x in split_line_upper:
  172.                                                 index = split_line_upper.index(x)
  173.                                                 real = split_line[index]
  174.                                                 name, value = map(' '.join, [split_line[:index], split_line[index+1:]])
  175.                                                 saved_value = value
  176.                                                 try:
  177.                                                         value = rgbasm_to_py(value)
  178.                                                         self.constants[name] = eval(value, self.constants.copy())
  179.                                                 except SyntaxError:
  180.                                                         value = saved_value
  181.                                                         value = rgbasm_to_py2(value)
  182.                                                         self.constants[name] = eval(value, self.constants.copy())
  183.                         else:
  184.                                 try:
  185.                                         self.read_bss_line(line)
  186.                                 except NameError:
  187.                                         pass
  188.                 self.sections += [self.section]
  189.                 return self.sections
  190.  
  191. def read_bss_sections(bss):
  192.         reader = BSSReader()
  193.         return reader.read_bss_sections(bss)
  194.  
  195.  
  196. def constants_to_dict(constants):
  197.         """Deprecated. Use BSSReader."""
  198.         return dict((eval(rgbasm_to_py(constant[constant.find('EQU')+3:constant.find(';')])), constant[:constant.find('EQU')].strip()) for constant in constants)
  199.  
  200. def scrape_constants(text):
  201.         if type(text) is not list:
  202.                 text = text.split('\n')
  203.         bss = BSSReader()
  204.         bss.read_bss_sections(text)
  205.         constants = bss.constants
  206.         return {v: k for k, v in constants.items()}
  207.  
  208. def read_constants(filepath):
  209.         """
  210.         Load lines from a file and grab any constants using BSSReader.
  211.         """
  212.         lines = []
  213.         if os.path.exists(filepath):
  214.                 with open(filepath, "r") as file_handler:
  215.                         lines = file_handler.readlines()
  216.         return scrape_constants(lines)
  217.  
  218. class WRAMProcessor(object):
  219.         """
  220.         RGBDS BSS section and constant parsing.
  221.         """
  222.  
  223.         def __init__(self, config):
  224.                 """
  225.                 Setup for WRAM parsing.
  226.                 """
  227.                 self.config = config
  228.  
  229.                 self.paths = {}
  230.  
  231.                 if hasattr(self.config, "wram"):
  232.                         self.paths["wram"] = self.config.wram
  233.                 else:
  234.                         self.paths["wram"] = os.path.join(self.config.path, "wram.asm")
  235.  
  236.                 if hasattr(self.config, "hram"):
  237.                         self.paths["hram"] = self.config.hram
  238.                 else:
  239.                         self.paths["hram"] = os.path.join(self.config.path, "hram.asm")
  240.  
  241.                 if hasattr(self.config, "gbhw"):
  242.                         self.paths["gbhw"] = self.config.gbhw
  243.                 else:
  244.                         self.paths["gbhw"] = os.path.join(self.config.path, "gbhw.asm")
  245.  
  246.         def initialize(self):
  247.                 """
  248.                 Read constants.
  249.                 """
  250.                 self.setup_wram_sections()
  251.                 self.setup_wram_labels()
  252.                 self.setup_hram_constants()
  253.                 self.setup_gbhw_constants()
  254.  
  255.                 self.reformat_wram_labels()
  256.  
  257.         def read_wram_sections(self):
  258.                 """
  259.                 Opens the wram file and calls read_bss_sections.
  260.                 """
  261.                 wram_content = None
  262.                 wram_file_path = self.paths["wram"]
  263.  
  264.                 with open(wram_file_path, "r") as wram:
  265.                         wram_content = wram.readlines()
  266.  
  267.                 wram_sections = read_bss_sections(wram_content)
  268.                 return wram_sections
  269.  
  270.         def setup_wram_sections(self):
  271.                 """
  272.                 Call read_wram_sections and set a variable.
  273.                 """
  274.                 self.wram_sections = self.read_wram_sections()
  275.                 return self.wram_sections
  276.  
  277.         def setup_wram_labels(self):
  278.                 """
  279.                 Make wram labels based on self.wram_sections as input.
  280.                 """
  281.                 self.wram_labels = make_wram_labels(self.wram_sections)
  282.                 return self.wram_labels
  283.  
  284.         def read_hram_constants(self):
  285.                 """
  286.                 Read constants from hram.asm using read_constants.
  287.                 """
  288.                 hram_constants = read_constants(self.paths["hram"])
  289.                 return hram_constants
  290.  
  291.         def setup_hram_constants(self):
  292.                 """
  293.                 Call read_hram_constants and set a variable.
  294.                 """
  295.                 self.hram_constants = self.read_hram_constants()
  296.                 return self.hram_constants
  297.  
  298.         def read_gbhw_constants(self):
  299.                 """
  300.                 Read constants from gbhw.asm using read_constants.
  301.                 """
  302.                 gbhw_constants = read_constants(self.paths["gbhw"])
  303.                 return gbhw_constants
  304.  
  305.         def setup_gbhw_constants(self):
  306.                 """
  307.                 Call read_gbhw_constants and set a variable.
  308.                 """
  309.                 self.gbhw_constants = self.read_gbhw_constants()
  310.                 return self.gbhw_constants
  311.  
  312.         def reformat_wram_labels(self):
  313.                 """
  314.                 Flips the wram_labels dictionary the other way around to access
  315.                 addresses by label.
  316.                 """
  317.                 self.wram = {}
  318.  
  319.                 for (address, labels) in self.wram_labels.iteritems():
  320.                         for label in labels:
  321.                                 self.wram[label] = address
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top