diff options
Diffstat (limited to 'utils')
-rwxr-xr-x | utils/coverage.py | 70 | ||||
-rw-r--r-- | utils/disasm_coverage.py | 102 | ||||
-rw-r--r-- | utils/mapreader.py | 33 |
3 files changed, 92 insertions, 113 deletions
diff --git a/utils/coverage.py b/utils/coverage.py new file mode 100755 index 0000000..3a3fca0 --- /dev/null +++ b/utils/coverage.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +Usage: python3 coverage.py [pokegold-spaceworld.map] [coverage.png] + +Generate a PNG visualizing the space used by each bank in the ROM. +""" + +import sys +import png +from colorsys import hls_to_rgb + +from mapreader import MapReader + +def main(): + mapfile = sys.argv[1] if len(sys.argv) >= 2 else 'pokegold-spaceworld.map' + filename = sys.argv[2] if len(sys.argv) >= 3 else 'coverage.png' + + num_banks = 0x40 + 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 + + r = MapReader() + with open(mapfile, 'r', encoding='utf-8') as f: + l = f.readlines() + r.read_map_data(l) + + hit_data = [] + default_bank_data = {'sections': [], 'used': 0, 'slack': bank_size} + for bank in range(num_banks): + hits = [0] * pixels_per_bank + data = r.bank_data['rom bank'].get(bank, default_bank_data) + for s in data['sections']: + if s['beg'] > s['end']: + continue + if s['beg'] == 0x0000 and s['end'] > 0xFFFF: + # https://github.com/rednex/rgbds/issues/515 + continue + 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 not bank else 210 if bank % 2 else 270 + for i, h in enumerate(hits): + y = i // bank_width + x = i % bank_width + bank * bank_width + hls = (hue / 360.0, 1.0 - (h / bpp * (100 - 15)) / 100.0, 1.0) + rgb = tuple(int(c * 255) 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(filename, 'wb') as f: + w = png.Writer(width, height) + w.write(f, png_data) + +if __name__ == '__main__': + main() diff --git a/utils/disasm_coverage.py b/utils/disasm_coverage.py deleted file mode 100644 index 6a68730..0000000 --- a/utils/disasm_coverage.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -from __future__ import division - -import os -import sys -import argparse -import png -from mapreader import MapReader -from colorsys import hls_to_rgb - -if __name__ == '__main__': - # argument parser - ap = argparse.ArgumentParser() - ap.add_argument('-r', dest='romname') - ap.add_argument('-o', dest='filename', default='coverage.png') - ap.add_argument('-m', dest='mapfile', required=True) - ap.add_argument('-b', dest='num_banks', required=True, type=lambda x: int(x, 0)) - args = ap.parse_args() - - bank_mask = 0x3FFF - bank_size = 0x4000 # bytes - width = 256 # pixels per row - bpp = 8 # bytes per pixel - - romname = args.romname - rom_size = args.num_banks * bank_size # bytes - height = (args.num_banks * bank_size + (width * bpp - 1)) // (width * bpp) # pixels - rows_per_bank = bank_size // (width * bpp) - - r = MapReader() - try: - with open(args.mapfile, 'r') as f: - l = f.readlines() - except UnicodeDecodeError: - # Python 3 seems to choke on the file's encoding, but the `encoding` keyword only works on Py3 - with open(args.mapfile, 'r', encoding= 'utf-8') as f: - l = f.readlines() - r.read_map_data(l) - - default_bank_data = {'sections': [], 'used': 0, 'slack': bank_size} - filler = [0x00, 0xFF] - - if (romname is not None): - with open(romname, 'rb') as f: - for rb in range(0, args.num_banks): - bank_data = r.bank_data['ROM0 bank' if rb == 0 else 'ROMX bank'] - data = bank_data.get(rb, default_bank_data) - bank = f.read(bank_size) - if (bank[bank_size - 1] in filler): - fill = bank[bank_size - 1] - for i in reversed(range(-1, bank_size - 1)): - if (i < 0 or bank[i] != fill): - break - # i is now pointing to first different byte - beg = i + 1 + (0 if rb == 0 else bank_size) - end = bank_size + (0 if rb == 0 else bank_size) - data['sections'].append({'beg': beg, 'end': end, 'name': 'Section_Trailing_Fill', 'symbols': []}) - - hit_data = [[0] * width for _ in range(height)] - for bank in range(args.num_banks): - bank_data = r.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) + bank * bank_size - end = ((s['end'] -1) & bank_mask) + bank * bank_size # end is exclusive - # skip zero-sized entries - if (s['beg'] == s['end']): - continue - y_beg = beg // (width * bpp) - x_beg = (beg % (width * bpp)) // bpp - y_end = end // (width * bpp) - x_end = (end % (width * bpp)) // bpp - #print('beg {0} end {1}: {2}/{3} -- {4}/{5}'.format(beg, end, y_beg, x_beg, y_end, x_end)) - # special case y_beg/x_beg and y_end/x_end - if (y_beg == y_end and x_beg == x_end): - hit_data[y_beg][x_beg] += end - beg + 1 - else: - hit_data[y_beg][x_beg] += bpp - ((beg % (width * bpp)) - x_beg * bpp) - hit_data[y_end][x_end] += ((end % (width * bpp)) - x_end * bpp + 1) - # regular case - for y in range(y_beg, y_end + 1): - x_line_beg = 0 if y_beg != y else x_beg + 1 - x_line_end = width - 1 if y_end != y else x_end - 1 - for x in range(x_line_beg, x_line_end + 1): - hit_data[y][x] += bpp - - png_data = [] - for i, row in enumerate(hit_data): - bank = i // rows_per_bank - hue = 0 if bank % 2 else 120 - row_png_data = () - for col in row: - hls = (hue/360.0, 1.0 - (col/bpp * (100 - 15))/100.0, 1.0) - rgb = tuple(255 * x for x in hls_to_rgb(*hls)) - row_png_data += rgb - png_data.append(row_png_data) - - with open(args.filename, 'wb') as f: - w = png.Writer(width, height) - w.write(f, png_data) diff --git a/utils/mapreader.py b/utils/mapreader.py index 1164cc4..0538d99 100644 --- a/utils/mapreader.py +++ b/utils/mapreader.py @@ -6,7 +6,7 @@ import re class MapReader: - # {'ROM Bank': { 0: { 'sections': [ { 'beg': 1234, + # {'rom bank': { 0: { 'sections': [ { 'beg': 1234, # 'end': 5678, # 'name': 'Section001', # 'symbols': [ { 'symbol': 'Function1234', @@ -19,7 +19,7 @@ class MapReader: # 'slack': 4567, # }, # }, - # 'OAM': { 'sections': [ { 'beg': 1234, + # 'oam': { 'sections': [ { 'beg': 1234, # 'end': 5678, # 'name': 'Section002', # 'symbols': [ { 'symbol': 'Data1234', @@ -36,13 +36,21 @@ class MapReader: 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, }, + 'hram bank': { 'size': 0x80, 'banked': False, }, + 'oam bank' : { 'size': 0xA0, 'banked': False, }, + 'rom bank' : { 'size': 0x4000, 'banked': True, }, + 'sram bank': { 'size': 0x2000, 'banked': True, }, + 'vram bank': { 'size': 0x1000, 'banked': True, }, + 'wram bank': { 'size': 0x2000, 'banked': True, }, + } + + bank_aliases = { + 'hram': 'hram bank', + 'oam': 'oam bank', + 'rom0 bank': 'rom bank', + 'romx bank': 'rom bank', + 'wram0 bank': 'wram bank', + 'wramx bank': 'wram bank', } # FSM states @@ -63,8 +71,11 @@ class MapReader: line = line.split(':', 1)[0] parts = line.split(' #', 1) - if (parts[0] in self.bank_types): - self._cur_bank_name = parts[0] + bank_type = parts[0].lower() + bank_type = self.bank_aliases.get(bank_type, bank_type) + + if (bank_type in self.bank_types): + self._cur_bank_name = bank_type 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] |