Require rgbds 0.6.0

This commit is contained in:
Rangi
2022-10-02 22:03:53 -04:00
parent 70a3ec1acc
commit 8e135931a6
85 changed files with 93 additions and 429 deletions

View File

@@ -39,7 +39,7 @@ function register_bank(amount) {
}
}
rom_bank && toupper($0) ~ /^[ \t]*EMPTY/ {
rom_bank && toupper($0) ~ /^[ \t]*EMPTY$/ {
# Empty bank
register_bank(16384)
}

View File

@@ -1,69 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Usage: python3 free_space.py [BANK=none] [pokecrystal.map]
Calculate the free space in the ROM or its individual banks.
The BANK argument allows printing free space in one, all, or none of the ROM's banks.
Valid arguments are numbers (in decimal "42" or hexadecimal "0x2A"), "all" or "none".
If not specified, defaults to "none".
"""
import sys
from mapreader import MapReader
def main():
print_bank = 'none'
filename = 'pokecrystal.map'
for arg in sys.argv[1:]:
if arg.startswith('BANK='):
print_bank = arg.split('=', 1)[-1]
else:
filename = arg
if print_bank not in {'all', 'none'}:
try:
print_bank = (int(print_bank[2:], 16)
if print_bank.startswith(('0x', '0X'))
else int(print_bank))
except ValueError:
error = f'Error: invalid BANK: {print_bank}'
if print_bank.isalnum():
error += f' (did you mean: 0x{print_bank}?)'
print(error, file=sys.stderr)
sys.exit(1)
num_banks = 0x80
bank_size = 0x4000 # bytes
total_size = num_banks * bank_size
reader = MapReader()
with open(filename, 'r', encoding='utf-8') as file:
reader.read_map_data(file.readlines())
free_space = 0
per_bank = []
default_bank_data = {'sections': [], 'used': 0, 'slack': bank_size}
for bank in range(num_banks):
bank_data = reader.bank_data['ROM0 bank' if bank == 0 else 'ROMX bank']
data = bank_data.get(bank, default_bank_data)
used, slack = data['used'], data['slack']
per_bank.append((used, slack))
free_space += slack
free_percent = 100 * free_space / total_size
print(f'Free space: {free_space}/{total_size} ({free_percent:.2f}%)')
if print_bank != 'none':
print()
print('bank, used, free')
for bank in range(num_banks):
used, slack = per_bank[bank]
if print_bank in {'all', bank}:
print(f'${bank:02X}, {used}, {slack}')
if __name__ == '__main__':
main()

View File

@@ -1,173 +0,0 @@
# -*- coding: utf-8 -*-
# A library for parsing the pokecrystal.map file output by rgbds.
import re
class MapReader:
# {'ROM Bank': { 0: { 'sections': [ { 'beg': 1234,
# 'end': 5678,
# 'name': 'Section001',
# 'symbols': [ { 'symbol': 'Function1234',
# 'address: 1234,
# },
# ]
# },
# ],
# 'used': 1234,
# 'slack': 4567,
# },
# },
# 'OAM': { 'sections': [ { 'beg': 1234,
# 'end': 5678,
# 'name': 'Section002',
# 'symbols': [ { 'symbol': 'Data1234',
# 'address: 1234,
# },
# ]
# },
# ],
# 'used': 1234,
# 'slack': 4567,
# },
# }
#
bank_data = {}
bank_types = {
'HRAM' : { 'size': 0x80, 'banked': False, },
'OAM' : { 'size': 0xA0, 'banked': False, },
'ROM0 bank': { 'size': 0x4000, 'banked': True, },
'ROMX bank': { 'size': 0x4000, 'banked': True, },
'SRAM bank': { 'size': 0x2000, 'banked': True, },
'VRAM bank': { 'size': 0x1000, 'banked': True, },
'WRAM bank': { 'size': 0x2000, 'banked': True, },
}
# FSM states
INIT, BANK, SECTION = range(3)
# $506D-$519A ($012E bytes) ["Type Matchups"]
section_header_regex = re.compile('\$([0-9A-Fa-f]{4})-\$([0-9A-Fa-f]{4}) \(.*\) \["(.*)"\]')
# $506D = TypeMatchups
section_data_regex = re.compile('\$([0-9A-Fa-f]{4}) = (.*)')
# $3ED2 bytes
slack_regex = re.compile('\$([0-9A-Fa-f]{4}) bytes?')
def __init__(self, *args, **kwargs):
self.__dict__.update(kwargs)
def _parse_init(self, line):
line = line.split(':', 1)[0]
parts = line.split(' #', 1)
if (parts[0] in self.bank_types):
self._cur_bank_name = parts[0]
self._cur_bank_type = self.bank_types[self._cur_bank_name]
if (self._cur_bank_type['banked'] and len(parts) > 1):
parts[1] = parts[1].split(':', 1)[0]
parts[1] = parts[1].split(' ', 1)[0]
self._cur_bank = int(parts[1], 10)
if self._cur_bank_name not in self.bank_data:
self.bank_data[self._cur_bank_name] = {}
if self._cur_bank_type['banked']:
if self._cur_bank not in self.bank_data[self._cur_bank_name]:
self.bank_data[self._cur_bank_name][self._cur_bank] = {}
self._cur_data = self.bank_data[self._cur_bank_name][self._cur_bank]
else:
self._cur_data = self.bank_data[self._cur_bank_name]
if ({} == self._cur_data):
self._cur_data['sections'] = []
self._cur_data['used'] = 0
self._cur_data['slack'] = self._cur_bank_type['size']
return True
return False
def _parse_section_header(self, header):
section_data = self.section_header_regex.match(header)
if section_data is not None:
beg = int(section_data.group(1), 16)
end = int(section_data.group(2), 16)
name = section_data.group(3)
self._cur_section = {'beg': beg, 'end': end, 'name': name, 'symbols': []}
self._cur_data['sections'].append(self._cur_section)
return True
return False
def _parse_slack(self, data):
slack_data = self.slack_regex.match(data)
slack_bytes = int(slack_data.group(1), 16)
self._cur_data['slack'] = slack_bytes
used_bytes = 0
for s in self._cur_data['sections']:
used_bytes += s['end'] - s['beg'] + 1
self._cur_data['used'] = used_bytes
def read_map_data(self, map):
if type(map) is str:
map = map.split('\n')
self._state = MapReader.INIT
self._cur_bank_name = ''
self._cur_bank_type = {}
self._cur_bank = 0
self._cur_data = {}
for line in map:
line = line.rstrip()
if (MapReader.INIT == self._state):
if (self._parse_init(line)):
self._state = MapReader.BANK
elif (MapReader.BANK == self._state or MapReader.SECTION == self._state):
if ('' == line):
self._state = MapReader.INIT
else:
line = line.lstrip()
parts = line.split(': ', 1)
if (MapReader.SECTION == self._state):
section_data = self.section_data_regex.match(parts[0])
if section_data is not None:
address = int(section_data.group(1), 16)
name = section_data.group(2)
self._cur_section['symbols'].append({'name': name, 'address': address})
continue
if ('SECTION' == parts[0]):
if (self._parse_section_header(parts[1])):
self._state = MapReader.SECTION
elif ('SLACK' == parts[0]):
self._parse_slack(parts[1])
self._state = MapReader.INIT
elif ('EMPTY' == parts[0]):
self._cur_data = {'sections': [], 'used': 0, 'slack': self._cur_bank_type['size']}
self._state = MapReader.INIT
else:
pass
for k, v in self.bank_data.items():
if (self.bank_types[k]['banked']):
for _, vv in v.items():
vv['sections'].sort(key=lambda x: x['beg'])
for vvv in vv['sections']:
vvv['symbols'].sort(key=lambda x: x['address'])
else:
v['sections'].sort(key=lambda x: x['beg'])
for vv in v['sections']:
vv['symbols'].sort(key=lambda x: x['address'])

View File

@@ -1,64 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Usage: python used_space.py [pokecrystal.map] [used_space.png]
Generate a PNG visualizing the space used by each bank in the ROM.
"""
import sys
from colorsys import hls_to_rgb
import png
from mapreader import MapReader
def main():
mapfile = sys.argv[1] if len(sys.argv) >= 2 else 'pokecrystal.map'
outfile = sys.argv[2] if len(sys.argv) >= 3 else 'used_space.png'
num_banks = 0x80
bank_mask = 0x3FFF
bank_size = 0x4000 # bytes
bpp = 8 # bytes per pixel
height = 256 # pixels
assert bank_size % bpp == 0 and (bank_size // bpp) % height == 0
pixels_per_bank = bank_size // bpp # 2048 pixels
bank_width = pixels_per_bank // height # 8 pixels
width = bank_width * num_banks # 1024 pixels
reader = MapReader()
with open(mapfile, 'r', encoding='utf-8') as file:
reader.read_map_data(file.readlines())
hit_data = []
default_bank_data = {'sections': [], 'used': 0, 'slack': bank_size}
for bank in range(num_banks):
hits = [0] * pixels_per_bank
bank_data = reader.bank_data['ROM0 bank' if bank == 0 else 'ROMX bank']
data = bank_data.get(bank, default_bank_data)
for s in data['sections']:
beg = s['beg'] & bank_mask
end = s['end'] & bank_mask
for i in range(beg, end + 1):
hits[i // bpp] += 1
hit_data.append(hits)
pixels = [[(0xFF, 0xFF, 0xFF)] * width for _ in range(height)]
for bank, hits in enumerate(hit_data):
hue = 0 if bank == 0 else 210 if bank % 2 else 270
for i, hit in enumerate(hits):
x, y = i % bank_width + bank * bank_width, i // bank_width
hls = (hue / 360, 1 - (85 * hit / bpp) / 100, 1)
rgb = tuple(int(c * 0xFF) for c in hls_to_rgb(*hls))
pixels[y][x] = rgb
png_data = [tuple(c for pixel in row for c in pixel) for row in pixels]
with open(outfile, 'wb') as file:
writer = png.Writer(width, height, greyscale=False, bitdepth=8, compression=9)
writer.write(file, png_data)
if __name__ == '__main__':
main()