mirror of
https://github.com/pret/pokegold-spaceworld.git
synced 2026-04-25 07:22:04 -05:00
Fix off-by-one errors with 'make coverage' and reformat output (horizontal banks)
This commit is contained in:
parent
462b7521b2
commit
371ce4da5c
4
Makefile
4
Makefile
|
|
@ -57,8 +57,8 @@ tidy:
|
|||
|
||||
# Visualize disassembly progress.
|
||||
.PHONY: coverage
|
||||
coverage: $(ROM:.gb=.map) utils/disasm_coverage.py
|
||||
$(PYTHON) utils/disasm_coverage.py -m $< -b 0x40
|
||||
coverage: $(ROM:.gb=.map) utils/coverage.py
|
||||
$(PYTHON) utils/coverage.py $<
|
||||
|
||||
|
||||
%.map: %.gb
|
||||
|
|
|
|||
70
utils/coverage.py
Executable file
70
utils/coverage.py
Executable file
|
|
@ -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()
|
||||
|
|
@ -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)
|
||||
|
|
@ -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]
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user