2018-01-03 20:00:53 +00:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
2018-01-03 20:25:40 +00:00
|
|
|
"""
|
|
|
|
Convert an rgbds .map file into a sorted .sym file
|
|
|
|
with bank and section data in comments.
|
|
|
|
"""
|
2018-01-03 19:41:17 +00:00
|
|
|
|
|
|
|
import sys
|
|
|
|
import re
|
|
|
|
|
|
|
|
def total_bank_size(type):
|
|
|
|
# used to output the size of EMPTY banks
|
|
|
|
sizes = {
|
2018-01-03 20:00:53 +00:00
|
|
|
'ROM0': 0x4000, # 0000-3FFF
|
|
|
|
'ROMX': 0x4000, # 4000-7FFF
|
|
|
|
'VRAM': 0x2000, # 8000-9FFF
|
2018-01-03 19:41:17 +00:00
|
|
|
'SRAM': 0x2000, # A000-BFFF
|
|
|
|
'WRAM0': 0x1000, # C000-CFFF
|
|
|
|
'WRAMX': 0x1000, # D000-DFFF
|
|
|
|
# E000-FDFF: echo RAM
|
|
|
|
'OAM': 0xA0, # FE00-FE9F
|
|
|
|
# FEA0-FEFF: unusable
|
|
|
|
# FF00-FF7F: hardware I/O registers
|
|
|
|
'HRAM': 0x80, # FF80-FFFF
|
|
|
|
}
|
|
|
|
return sizes[type]
|
|
|
|
|
|
|
|
def sorted_mapfile(input):
|
2018-01-03 20:31:03 +00:00
|
|
|
# analogous to ";File generated by rgblink"
|
|
|
|
yield ';File generated by sort_map.py\n'
|
|
|
|
|
2018-01-03 19:57:10 +00:00
|
|
|
# ex: OAM:
|
2018-01-03 19:52:32 +00:00
|
|
|
unused_rx = re.compile(r'^([A-Z]+):$')
|
2018-01-03 19:57:10 +00:00
|
|
|
# ex: ROM Bank #1:
|
2018-01-03 19:41:17 +00:00
|
|
|
bank_rx = re.compile(r'^([A-Z]+) Bank #([0-9]+)')
|
2018-01-03 19:57:10 +00:00
|
|
|
# ex: SECTION: $4000-$747A ($347B bytes) ["bank1"]
|
2018-01-03 19:41:17 +00:00
|
|
|
section_rx = re.compile(r' +SECTION: \$([0-9A-F]+)(?:-\$([0-9A-F]+))? \(\$([0-9A-F]+) bytes\) \["(.+)"\]')
|
2018-01-03 19:57:10 +00:00
|
|
|
# ex: $4025 = PlaceWaitingText.Waiting
|
2018-01-03 19:41:17 +00:00
|
|
|
label_rx = re.compile(r' +\$([0-9A-F]+) = (.+)')
|
2018-01-03 19:57:10 +00:00
|
|
|
# ex: SLACK: $0B85 bytes
|
2018-01-03 19:41:17 +00:00
|
|
|
slack_rx = re.compile(r' +SLACK: \$([0-9A-F]+) bytes')
|
|
|
|
|
|
|
|
bank_type = None
|
|
|
|
bank_number = None
|
|
|
|
bank_size = 0
|
|
|
|
bank_queue = []
|
|
|
|
section_queue = []
|
|
|
|
|
|
|
|
for line in input:
|
|
|
|
|
|
|
|
if line.startswith(' EMPTY'):
|
|
|
|
# empty banks have their entire capacity as slack
|
|
|
|
line = ' SLACK: $%04X bytes\n' % total_bank_size(bank_type)
|
|
|
|
|
2018-01-03 19:52:32 +00:00
|
|
|
x = re.match(unused_rx, line)
|
|
|
|
if x:
|
|
|
|
# start an unused bank
|
|
|
|
bank_type = x.group(1)
|
|
|
|
bank_number = '00'
|
|
|
|
bank_size = 0
|
2018-01-03 20:00:53 +00:00
|
|
|
del bank_queue[:]
|
|
|
|
del section_queue[:]
|
2018-01-03 19:52:32 +00:00
|
|
|
continue
|
|
|
|
|
2018-01-03 19:41:17 +00:00
|
|
|
x = re.match(bank_rx, line)
|
|
|
|
if x:
|
|
|
|
# start a new bank
|
|
|
|
bank_type = x.group(1)
|
|
|
|
bank_number = '%02X' % int(x.group(2))
|
|
|
|
if bank_type == 'ROM':
|
|
|
|
bank_type = 'ROM0' if bank_number == '00' else 'ROMX'
|
|
|
|
if bank_type == 'WRAM':
|
|
|
|
bank_type = 'WRAM0' if bank_number == '00' else 'WRAMX'
|
|
|
|
bank_size = 0
|
2018-01-03 20:00:53 +00:00
|
|
|
del bank_queue[:]
|
|
|
|
del section_queue[:]
|
2018-01-03 19:41:17 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
x = re.match(section_rx, line)
|
|
|
|
if x:
|
|
|
|
# finish current section
|
|
|
|
bank_queue.extend(sorted(section_queue))
|
|
|
|
# start a new section
|
|
|
|
start = x.group(1)
|
|
|
|
end = x.group(2) or start
|
|
|
|
size = x.group(3).zfill(4)
|
|
|
|
name = x.group(4)
|
|
|
|
bank_size += int(size, 16)
|
|
|
|
bank_queue.append('; %s:%s-%s ($%s) %s\n' % (bank_number, start, end, size, name))
|
2018-01-03 20:00:53 +00:00
|
|
|
del section_queue[:]
|
2018-01-03 19:41:17 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
x = re.match(label_rx, line)
|
|
|
|
if x:
|
|
|
|
# add label to section
|
|
|
|
address = x.group(1)
|
|
|
|
label = x.group(2)
|
|
|
|
section_queue.append('%s:%s %s\n' % (bank_number, address, label))
|
|
|
|
continue
|
|
|
|
|
|
|
|
x = re.match(slack_rx, line)
|
|
|
|
if x:
|
|
|
|
# finish current section
|
|
|
|
bank_queue.extend(sorted(section_queue))
|
|
|
|
# finish current bank
|
|
|
|
slack = int(x.group(1), 16)
|
2018-01-03 19:46:37 +00:00
|
|
|
yield '; %s $%s ($%04X) ($%04X free)\n' % (bank_type, bank_number, bank_size, slack)
|
2018-01-03 20:00:53 +00:00
|
|
|
for line in bank_queue:
|
|
|
|
yield line
|
2018-01-03 19:41:17 +00:00
|
|
|
continue
|
|
|
|
|
|
|
|
def main():
|
|
|
|
if len(sys.argv) < 3:
|
2018-01-03 20:25:40 +00:00
|
|
|
sys.stderr.write('Usage: %s pokecrystal.map sorted.sym\n' % sys.argv[0])
|
2018-01-03 19:41:17 +00:00
|
|
|
sys.exit(1)
|
|
|
|
input_filename = sys.argv[1]
|
|
|
|
output_filename = sys.argv[2]
|
2018-01-03 20:00:53 +00:00
|
|
|
with open(input_filename, 'r') as infile:
|
2018-01-03 19:41:17 +00:00
|
|
|
input = infile.readlines()
|
|
|
|
output = sorted_mapfile(input)
|
2018-01-03 20:00:53 +00:00
|
|
|
with open(output_filename, 'w') as outfile:
|
2018-01-03 19:41:17 +00:00
|
|
|
for line in output:
|
|
|
|
outfile.write(line)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
main()
|