# coding: utf-8 # hacky mods to extras.gbz80disasm import sys import re from gbaddr import * sys.path.insert(0, 'extras/pokemontools') import configuration from gbz80disasm import * from preprocessor import separate_comment conf = configuration.Config() dis = Disassembler(conf) dis.initialize() find_label = dis.find_label find_address_from_label = dis.find_address_from_label def output_bank_opcodes_plus_wram(address): label = dis.find_label(get_local_address(address), address/0x4000) output = '' output += '; %x\n' % address asm, offset = dis.output_bank_opcodes(address)[:2] output += asm # replace rst $8 with callab/callba macros if the functions exist. output = label_farcalls(output) # label rst vectors output = output.replace('rst $10', 'rst Bankswitch\n').replace('rst $8', 'rst FarCall').replace('rst $28', 'rst JumpTable').replace('0x','') # replace top labels top_label = '.asm_%x' % address if top_label in output and label: output = output.replace('\n' + top_label, '').replace(top_label, label) return output, offset def label_farcalls(output): output = output.decode('utf8') hl = '\tld hl, (\\$*.+)\n' a = '\tld a, (\\$*.+)\n' ba = a+hl+'\trst \\$8' ab = hl+a+'\trst \\$8' for pattern in [ba, ab]: for m in re.finditer(pattern, output): mbank = m.expand('\\1').replace('$', '0x') maddress = m.expand('\\2').replace('$', '0x') if pattern == ab: mbank, maddress = maddress, mbank try: bank = eval(mbank) except: continue if find_address_from_label(maddress): mlabel = maddress addr = get_local_address(find_address_from_label(mlabel)) else: try: addr = int(maddress, 16) except: continue mlabel = find_label(addr, bank) if mlabel: if pattern == ab: output = output.replace('\tld hl, %s\n\tld a, %s\n\trst $8' % (m.expand('\\1'), m.expand('\\2')), '\tcallab %s' % mlabel) else: output = output.replace('\tld a, %s\n\tld hl, %s\n\trst $8' % (m.expand('\\1'), m.expand('\\2')), '\tcallba %s' % mlabel) elif addr != maddress: if pattern == ab: output = output.replace('\tld hl, %s\n\tld a, %s\n\trst $8' % (m.expand('\\1'), m.expand('\\2')), '\tld hl, %s\n\tld a, %s\n\trst $8' % ('$%x' % addr, m.expand('\\2'))) else: output = output.replace('\tld a, %s\n\tld hl, %s\n\trst $8' % (m.expand('\\1'), m.expand('\\2')), '\tld a, %s\n\tld hl, %s\n\trst $8' % (m.expand('\\1'), '$%x' % addr)) output = output.encode('utf8') return output def find_rom_label(address, bank_id=0): """ Was going to be just rom, but this is handy for ram too. Avoids interpreting common numbers or instructions as addresses. """ if address > 0x100 and address != 0xff00 and address != 0xffff: return find_label(address, bank_id) return None def label_known_addresses(output, bank_id = 0): for m in re.finditer(r'(\$[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]??\b)', output): addr = eval(m.expand('\\1').replace('$','0x')) label = find_rom_label(addr, bank_id) if label: output = re.sub('\\'+address+r'\b', label, output) return output def label_known_section_addresses(output): """ Run through each bank replacing any local addresses. """ load_labels() output = output.decode('utf8') banks = output.split('SECTION "bank') for i, bank in enumerate(banks): if i == 0: # skip anything before the first bank continue bank_id = int(bank[:bank.find('"')],16) addresses = [] for m in re.finditer(r'(\$[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]??\b)', bank): address = m.expand('\\1') addr = eval(address.replace('$','0x')) if addr in [0xd000, 0xd040, 0xd080, 0xd0c0]: # no "Pals" wram addresses continue label = find_rom_label(addr, bank_id) if label: addresses += [[address, label]] bank = bank.split('\n') for address, label in addresses: # figure out a better way to handle local labels if '.' in label: continue # dont replace parameters if eval(address.replace('$','0x')) < 0x0a00: continue for j, line in enumerate(bank): # dont replace addresses in incbins if 'INCBIN' in line or 'SECTION' in line: continue # dont replace farcalls if j > 0 and 'ld hl' in line and ('FarCall' in bank[j-1] or 'FarCall' in bank[j+1] or 'rst $8' in bank[j-1] or 'rst $8' in bank[j+1]): continue # dont touch pointers if 'dbw' in line or 'dwb' in line: continue addr = address if addr[1] == '0': alt_addr = addr[0] + addr[2:] else: alt_addr = addr[0] + '0' + addr[1:] for a in [addr, alt_addr]: if a in line: line = re.sub('\\' + a + r'\b', label, line) bank[j] = line bank = u'\n'.join(bank) banks[i] = bank output = 'SECTION "bank'.join(banks) output = output.encode('utf8') return output def label_pointers(output): load_labels() output = output.decode('utf8') output = output.split('\n') for i, line in enumerate(output): asm = line.split(';')[0] if ',' not in asm: continue if 'dbw' in asm: bank, address = [x.strip() for x in asm.split('dbw')[1].split(',')] elif 'dwb' in asm: address, bank = [x.strip() for x in asm.split('dwb')[1].split(',')] else: continue try: a = eval(address.replace('$','0x')) b = eval(bank.replace('$','0x')) except: continue label = find_label(a, b) if label: line = line.replace(address, label) line = line.replace(bank, 'BANK(%s)' % label) else: continue output[i] = line output = '\n'.join(output) output = output.encode('utf8') return output def better_scan_for_predefined_labels(filename='main.asm'): """ Not actually used, just generate labels from a mapfile using sym.py instead. """ labels = [] lines = open(filename, 'r').readlines() for line in lines: line, comment = separate_comment(line) if 'INCLUDE' in line: labels += better_scan_for_predefined_labels('../' + line.split('"')[1]) #labels.update(better_scan_for_predefined_labels('../' + line.split('"')[1])) if ':' in line: try: label = line[:line.find(':')-1] address = int(comment, 16) labels += [{ 'label': label, 'address': get_local_address(address), 'bank': address / 0x4000, }] except: pass return labels #all_labels = {} #def better_load_labels(filename="labels.json"): # global all_labels # # don't re-load labels each time # if all_labels != {}: return # all_labels = better_scan_for_predefined_labels() #better_load_labels() if __name__ == "__main__": output = open('main.asm', 'r').read() output = label_known_section_addresses(output) output = label_farcalls(output) output = label_pointers(output) with open('main.asm', 'w') as out: out.write(output) #print output #print output_bank_opcodes_plus_wram(gbaddr_int(sys.argv[1]))[0]