Skip to content

gingerbeardman/snes-memory-maps

Repository files navigation

SNES Memory Maps

Generate zoomable SVG maps of SNES ROM and WRAM from linker map files, with optional machine-readable CSV output.

Supports llvm-mos (ld.lld), vbcc65816 (vlink), cc65 (ca65/ld65), wla-dx, and asar; the input format is auto-detected. Linker maps carry exact sizes; assembler symbol files (wla-dx, asar) carry only addresses, so their sizes are inferred (see below).

The repository provides two command-line scripts:

  • rommap.py creates a physical-bank ROM treemap.
  • rammap.py creates an address-preserving WRAM overview with low-WRAM and direct-page zooms.

Both are thin entry points to snesmap.py, the shared engine that does the map parsing, layout, and rendering; they simply preset ROM or RAM mode. Keeping one engine means the ~95% of logic the two maps share lives in a single place, while you still get the two commands you'd expect. (snesmap.py is not meant to be run directly.)

All three use only the Python 3 standard library. Their SVG output supports light and dark colour schemes, browser zooming, and per-allocation tooltips.

Examples

ROM

Example SNES ROM map

RAM

Example SNES RAM map

Quick start

Run the scripts from the directory containing your linker script:

python3 /path/to/rommap.py build/game.map \
  --linker-script game.ld \
  -o build/rommap

python3 /path/to/rammap.py build/game.map \
  -o build/rammap

Each command writes an SVG by default:

build/rommap.svg
build/rammap.svg

Pass --csv to also write the machine-readable CSV (build/rommap.csv, build/rammap.csv).

The format is auto-detected. Override detection with --format, one of lld, vlink, ca65, wla, or asar.

ROM map

The ROM map displays sixteen physical 32 KiB banks in SNES reading order. Bank headers show allocated bytes and a right-aligned percentage. Symbol rectangles are proportional within each bank; transparent rectangles are free space.

For llvm-mos/ld.lld builds, ROM region names, origins, and capacities come from the linker script's MEMORY block. Regions below $00:8000 and WRAM banks $7E/$7F are excluded.

The RAM script derives its fixed WRAM ranges directly and does not require a linker script.

The existing rom_bank_fixed convention is recognised: its contents are shown in every code_bank_* physical bank. Other linker-region names have no special meaning.

RAM map

The RAM map separates static linker allocation from runtime usage:

  • A true-scale overview displays the full 128 KiB WRAM.
  • A magnified panel displays $7E:0100–1FFF.
  • A second magnified panel displays the default direct page, $7E:0000–00FF with D=$0000.
  • Allocation order and address gaps are preserved.

RAM colours identify initialized .data, zero-filled .bss, .noinit, hardware stack reservation, compiler direct-page registers, and other allocations. Unallocated space is transparent by default.

When present in an ld.lld map, __rcN and __stack linker symbols are used to account for compiler direct-page registers and the page-$01 hardware stack. Dynamic stack and heap high-water usage cannot be inferred from a static linker map.

Display options

Options apply independently to either script:

--checkerboard
--colour-key                 # alias: --color-key
--coloured-percentages       # alias: --colored-percentages
  • --checkerboard uses a Photoshop-style pattern for free space.
  • --colour-key adds the colour legend.
  • --coloured-percentages shows 75–89.9% in amber and 90%+ in red.

All three are off by default.

Use --compiler "toolchain name" to override the compiler/linker label embedded in the SVG footer.

Use --delimiter to change the field separator used throughout the SVG — headers, tooltips, captions, and the footer (e.g. $00 / 31,333 B / 95.6% full). It is space-padded, and the default is a bullet (·), e.g. --delimiter "/".

Supported linker maps

  • llvm-mos/ld.lld map output, with ROM regions read from a GNU-style MEMORY block.
  • vbcc65816/vlink section mappings.
  • vlink LoROM, plus the vlink HiROM address projection used by vlink-hi.
  • cc65 ca65/ld65: the ld65 --mapfile Segment list for exact per-segment sizes. Optionally pass your cc65 linker config (the same .cfg you build with, cl65 -C / ld65 -C) as --linker-script to name the ROM regions; without it the map falls back to physical banks.
  • wla-dx / asar symbol files (wlalink .sym, asar --symbols=wla|nocash): label→address only, so LoROM physical banks are assumed and sizes are inferred from label gaps (the last label in a bank runs to the bank end). Trailing free space inside a bank is therefore invisible; the footer marks these maps (approx sizes).

See docs/linker-map-support.md for assumptions and known limitations.

Development

Run the test suite:

python3 -m unittest discover -s tests -v

The tests invoke both scripts against small checked-in fixtures for each supported format (ld.lld, vlink, ca65/ld65, wla-dx, and asar) and validate their CSV and SVG output.

Acknowledgements

The physical-bank ROM view was inspired by Pin Eight's Homebrew ROM maps and treemaps.

License

MIT. See LICENSE.

About

Generate SNES memory maps as SVG and/or CSV, with lots of options

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Contributors

Languages