Added semantic names to 4 major data tables in Wild Gunman (JU): - SpriteAttributeTable at : Sprite attribute data (Y/tile/attr/X groups) - NoteVolumeTable at : APU note period/volume lookup table (32 bytes) - VolumeEnvelopeTable at : APU volume envelope lookup table (96 bytes) - SpritePositionTable at : Sprite position/attribute table (2168 bytes) Build verified byte-identical. verify_pass1.py passes. Updated TODO.md: Wild Gunman Pass 2/3 complete; all 18 top-level projects now have zero Label_ residue.
74 lines
2.9 KiB
Python
74 lines
2.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Pass 3 for Wild Gunman (JU): Add semantic names to data tables.
|
|
|
|
Pass 3 names data tables and structures based on their usage patterns
|
|
and the header documentation which identifies:
|
|
- Inline dispatch tables ($C6AC-$C802)
|
|
- Sound/music pattern data ($DEED-$F371)
|
|
- Note/volume tables ($F3EF/$F48F)
|
|
- Sprite/attribute tables ($F77C-$FFF3)
|
|
"""
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
# ============================================================================
|
|
# DATA TABLE NAME MAP
|
|
# Address -> (name, description)
|
|
# Only include regions that are pure data (not mixed code/data)
|
|
# ============================================================================
|
|
|
|
DATA_TABLES = {
|
|
0xC6AC: ("SpriteAttributeTable", "Sprite attribute data: Y/tile/attr/X groups for object sprites"),
|
|
0xF3EF: ("NoteVolumeTable", "APU note period/volume lookup table (32 bytes)"),
|
|
0xF48F: ("VolumeEnvelopeTable", "APU volume envelope lookup table (96 bytes)"),
|
|
0xF77C: ("SpritePositionTable", "Sprite position/attribute table (2168 bytes)"),
|
|
}
|
|
|
|
def process_file(input_path, output_path):
|
|
text = Path(input_path).read_text()
|
|
lines = text.split('\n')
|
|
|
|
# Build a map of PRG offset -> line index for data regions
|
|
# Find where each data address appears in the file
|
|
addr_to_line = {}
|
|
for i, line in enumerate(lines):
|
|
m = re.search(r'; CPU:\$([0-9A-F]{4}) PRG:([0-9A-F]{4})', line)
|
|
if m:
|
|
cpu_addr = int(m.group(1), 16)
|
|
addr_to_line[cpu_addr] = i
|
|
|
|
print(f"Found {len(addr_to_line)} address annotations")
|
|
|
|
# Find insertion points for each data table
|
|
insertions = [] # (line_index, label_text)
|
|
|
|
for addr, (name, desc) in DATA_TABLES.items():
|
|
if addr in addr_to_line:
|
|
line_idx = addr_to_line[addr]
|
|
# Verify this line is a .byte or .word line (data, not code)
|
|
if '.byte' in lines[line_idx] or '.word' in lines[line_idx]:
|
|
insertions.append((line_idx, f"{name}:"))
|
|
print(f" {name} at CPU:${addr:04X} -> line {line_idx+1}")
|
|
else:
|
|
print(f" SKIP {name} at CPU:${addr:04X} -> line {line_idx+1} is not a data line: {lines[line_idx][:60]}")
|
|
else:
|
|
print(f" WARNING: CPU:${addr:04X} not found in file")
|
|
|
|
# Sort insertions by line index (descending) so we can insert without shifting
|
|
insertions.sort(key=lambda x: x[0], reverse=True)
|
|
|
|
# Apply insertions
|
|
for line_idx, label_text in insertions:
|
|
lines.insert(line_idx, label_text)
|
|
|
|
new_text = '\n'.join(lines)
|
|
Path(output_path).write_text(new_text)
|
|
print(f"\nWritten to {output_path}")
|
|
print(f"Added {len(insertions)} data table labels")
|
|
|
|
if __name__ == '__main__':
|
|
input_file = "Wild Gunman (U)/copilot/prg.s"
|
|
output_file = "Wild Gunman (U)/copilot/prg.s"
|
|
process_file(input_file, output_file) |