Skip to content

Instantly share code, notes, and snippets.

@cogwheel
Created September 24, 2023 16:31
Show Gist options
  • Save cogwheel/5e9af99aa0a40bfd9fe136478de91f4d to your computer and use it in GitHub Desktop.
Save cogwheel/5e9af99aa0a40bfd9fe136478de91f4d to your computer and use it in GitHub Desktop.
Read .map file from mos-nes-mmc3 target and summarize RAM/ROM usage
import re
import sys
TOTAL_SYSTEM_RAM = 0x800 # 2kb built into the NES
TOTAL_WORK_RAM = 0x2000 # 8kb of PRG RAM thanks to the mapper TODO: banking?
TOTAL_PRG_BANKS = 64
PRG_BANK_SIZE = 0x2000 # 8KiB banks
TOTAL_CHR_BANKS = 256
CHR_BANK_SIZE = 0x0400 # 1KiB banks
ZP_SIZE = 0x100
ZP_RESERVED = 0x20 # Compiler uses 32 bytes (customizable) for registers.
SRAM_SIZE = TOTAL_SYSTEM_RAM - ZP_SIZE
SWSTACK_SIZE = 0x100
WRAM_SIZE = TOTAL_WORK_RAM - SWSTACK_SIZE
PRG_BANKS_RESERVED = 2 # Fixed banks from 0xC000-0xFFFF
AVAILABLE_PRG_BANKS = TOTAL_PRG_BANKS - PRG_BANKS_RESERVED
with open(sys.argv[1], "r") as file:
zp_left = ZP_SIZE - ZP_RESERVED
sram_left = SRAM_SIZE
wram_left = WRAM_SIZE
fixed_prg_left = PRG_BANK_SIZE * PRG_BANKS_RESERVED
prg_rom_left = [PRG_BANK_SIZE] * AVAILABLE_PRG_BANKS
used_prg_banks = set()
chr_banks_left = TOTAL_CHR_BANKS
for line in file:
try:
vma, lma, size, _, section = line.split()
vma = int(vma, 16)
lma = int(lma, 16)
size = int(size, 16)
section = re.match(r"^(\.[\w.]+)$", section).groups()[0]
except:
continue
# TODO: use memory regions and the values of vma/lma instead of
# hard-coded string names/patterns
if section.startswith(".debug"):
continue
if section in [".comment", ".symtab", ".shstrtab", ".strtab"]:
continue
if section.startswith(".zp"):
zp_left -= size
if (vma != lma):
# Data-like segment; initializer value is in ROM, but program
# accesses it through RAM
fixed_prg_left -= size
elif section in [".bss", ".noinit"]:
wram_left -= size
elif section == ".data":
wram_left -= size
fixed_prg_left -= size
elif section in [".text", ".rodata", ".dpcm", ".reset", ".vectors"]:
fixed_prg_left -= size
elif segment == ".ram":
sram_left -= size
elif section == ".chr_rom":
assert(size % CHR_BANK_SIZE == 0)
chr_banks_left -= size // CHR_BANK_SIZE
elif match := re.match(r".prg_rom_(\d*)", section):
index = int(match.groups()[0])
prg_rom_left[index] -= size
used_prg_banks.add(index)
else:
raise ValueError(f"Unknown section: {section}")
remaining_prg_banks = AVAILABLE_PRG_BANKS - len(used_prg_banks)
print(f"""
Remaining RAM bytes:
ZP: {zp_left:5d}
SRAM: {sram_left:5d}
WRAM: {wram_left:5d}
Remaining PRG ROM bytes:
FIXED: {fixed_prg_left:5d}""")
if used_prg_banks:
for i in range(0, max(used_prg_banks) + 1):
if i in used_prg_banks:
print(f"""\
PRG{i:02d}: {prg_rom_left[i]:5d}""")
else:
print(f"""\
PRG{i:02d}: {PRG_BANK_SIZE:5d} (Unused)""")
print(f"""
Available ROM banks:
PRG: {remaining_prg_banks:5d} ({round(remaining_prg_banks * PRG_BANK_SIZE / 1024)} KiB)
CHR: {chr_banks_left:5d} ({chr_banks_left} KiB)""")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment