@@ -36,11 +36,18 @@ zig build nes-megablast
3636zig build nes-gg-demo
3737zig build nes-mappers
3838zig build nes-cnrom-hello
39+ zig build nes-cnrom-sprites
3940zig build nes-unrom-hello
41+ zig build nes-unrom-color-cycle
4042zig build nes-mmc1-hello
43+ zig build nes-mmc1-sprites
4144zig build nes-mmc3-hello
45+ zig build nes-mmc3-pads
4246zig build nes-gtrom-hello
47+ zig build nes-gtrom-color-cycle
4348zig build nes-unrom-512-hello
49+ zig build nes-action53-hello
50+ zig build fds-hello
4451
4552# Commodore 64
4653zig build c64-hello
@@ -50,6 +57,7 @@ zig build c64-plasma
5057# Commander X16
5158zig build cx16-hello
5259zig build cx16-k-console-test
60+ zig build vic20-hello
5361
5462# Atari Lynx
5563zig build lynx-hello
@@ -76,7 +84,6 @@ zig build snes-zig-logo
7684zig build snes-pi-test
7785zig build snes-pi-fastrom
7886zig build snes-hirom-hello
79- zig build snes-megablast
8087zig build snes-pads
8188
8289# mos-sim (6502 simulator)
@@ -118,11 +125,18 @@ Output files land in `zig-out/bin/`.
118125| ` nes-pads ` — controller input with two 16×16 metasprites | ![ ] ( .github/mmc3-pads.gif ) |
119126| ` nes-mappers ` — CNROM 4-bank CHR demo, press Start to cycle banks | ![ ] ( .github/mappers.gif ) |
120127| ` nes-cnrom-hello ` — CNROM banked CHR ROM | |
128+ | ` nes-cnrom-sprites ` — CNROM sprites example | |
121129| ` nes-unrom-hello ` — UNROM banked PRG ROM | |
130+ | ` nes-unrom-color-cycle ` — UNROM colour-cycle across PRG banks | |
122131| ` nes-mmc1-hello ` — MMC1 mapper | |
132+ | ` nes-mmc1-sprites ` — MMC1 sprites with CHR RAM upload | |
123133| ` nes-mmc3-hello ` — MMC3 mapper | |
134+ | ` nes-mmc3-pads ` — MMC3 controller + collision example | ![ ] ( .github/mmc3-pads.gif ) |
124135| ` nes-gtrom-hello ` — GTROM mapper | |
136+ | ` nes-gtrom-color-cycle ` — GTROM colour-cycle with LED | |
125137| ` nes-unrom-512-hello ` — UNROM-512 mapper (mapper 30) | |
138+ | ` nes-action53-hello ` — Action53 multicart (mapper 28) | |
139+ | ` fds-hello ` — Famicom Disk System backdrop hello | |
126140
127141### SNES
128142
@@ -134,7 +148,6 @@ Output files land in `zig-out/bin/`.
134148| ` snes-pi-test ` — ~ 900 digits of π via Spigot algorithm, BG1 text (port of pi_snes by Sirmacho) | |
135149| ` snes-pi-fastrom ` — same π demo built as FastROM (map mode $30, MEMSEL=1) | |
136150| ` snes-hirom-hello ` — HiROM backdrop hello (map mode $21) | |
137- | ` snes-megablast ` — full-game port [ no sound] of NES Megablast (CH13), Mode 1 BG+OBJ | |
138151| ` snes-pads ` — joypad demo: LEFT/RIGHT cycles backdrop color, A+B resets; exercises ` buttonMask ` , ` held ` , ` pressed ` | |
139152
140153### Other platforms
@@ -162,10 +175,15 @@ Output files land in `zig-out/bin/`.
162175| ` nes-gg-demo ` | NES NROM | mos6502 | ` .nes ` |
163176| ` nes-mappers ` | NES CNROM (4-bank) | mos6502 | ` .nes ` |
164177| ` nes-cnrom-hello ` | NES CNROM | mos6502 | ` .nes ` |
178+ | ` nes-cnrom-sprites ` | NES CNROM sprites | mos6502 | ` .nes ` |
165179| ` nes-unrom-hello ` | NES UNROM | mos6502 | ` .nes ` |
180+ | ` nes-unrom-color-cycle ` | NES UNROM colour-cycle | mos6502 | ` .nes ` |
166181| ` nes-mmc1-hello ` | NES MMC1 | mos6502 | ` .nes ` |
182+ | ` nes-mmc1-sprites ` | NES MMC1 sprites (CHR RAM) | mos6502 | ` .nes ` |
167183| ` nes-mmc3-hello ` | NES MMC3 | mos6502 | ` .nes ` |
184+ | ` nes-mmc3-pads ` | NES MMC3 controller + collision | mos6502 | ` .nes ` |
168185| ` nes-gtrom-hello ` | NES GTROM | mos6502 | ` .nes ` |
186+ | ` nes-gtrom-color-cycle ` | NES GTROM colour-cycle + LED | mos6502 | ` .nes ` |
169187| ` nes-unrom-512-hello ` | NES UNROM-512 | mos6502 | ` .nes ` |
170188| ` nes-action53-hello ` | NES Action53 (mapper 28) | mos6502 | ` .nes ` |
171189| ` fds-hello ` | Famicom Disk System | mos6502 | ` .fds ` |
@@ -188,7 +206,6 @@ Output files land in `zig-out/bin/`.
188206| ` snes-pi-test ` | SNES LoROM | mosw65816 | ` .sfc ` |
189207| ` snes-pi-fastrom ` | SNES FastROM | mosw65816 | ` .sfc ` |
190208| ` snes-hirom-hello ` | SNES HiROM | mosw65816 | ` .sfc ` |
191- | ` snes-megablast ` | SNES LoROM | mosw65816 | ` .sfc ` |
192209| ` snes-pads ` | SNES LoROM | mosw65816 | ` .sfc ` |
193210| ` sim-hello ` | mos-sim (6502 simulator) | mos6502 | binary |
194211| ` mega65-hello ` , ` mega65-plasma ` | MEGA65 | mos45gs02 | ` .prg ` |
@@ -219,21 +236,127 @@ fib(20) = 6765 ( 4 cycles)
219236sieve<127>: 31 primes (6905 cycles)
220237```
221238
239+ ## Host tools
240+
241+ Built automatically alongside the examples (` zig build --summary all ` ).
242+
243+ ### ` bininfo ` — binary inspector
244+
245+ Identifies and inspects any MOS-platform output binary.
246+
247+ ``` sh
248+ zig-out/bin/bininfo < file> [files…] [flags]
249+ ```
250+
251+ | Flag | Short | Description |
252+ | ------| -------| -------------|
253+ | ` --sections ` | ` -S ` | List ELF sections |
254+ | ` --symbols ` | ` -n ` | List ELF symbols |
255+ | ` --dwarf ` | ` -d ` | Dump DWARF section inventory |
256+ | ` --xxd ` | ` -x ` | Hex+ASCII dump (xxd style) |
257+ | ` --xxd-limit N ` | | Cap xxd output at N bytes |
258+ | ` --disasm ` | ` -D ` | 6502 disassembly of file payload |
259+
260+ Flags may appear before or after filenames.
261+
262+ Detected formats: iNES 1.0/2.0 (` .nes ` ), SNES SFC/SMC (` .sfc ` /` .smc ` — SMC 512-byte copier header auto-stripped), FDS raw (` .fds ` ), GEOS CVT (` .cvt ` ), CBM PRG (` .prg ` ), Atari 2600 (` .a26 ` ), Atari 8-bit cart (` .rom ` ), Atari XEX (` .xex ` ), Lynx BLL (` .bll ` ), PC Engine (` .pce ` ), Neo6502 (` .neo ` ), Apple IIe ProDOS (` .sys ` ), mos-sim binary, ELF. HiROM vs LoROM is auto-detected from map-mode byte.
263+
264+ ``` sh
265+ # Inspect a built NES ROM
266+ bininfo zig-out/bin/hello1.nes --sections
267+
268+ # Dump first 64 bytes of an FDS binary
269+ bininfo zig-out/bin/fds-hello.fds -x --xxd-limit 64
270+
271+ # Disassemble a PRG (auto-skips 2-byte load-address header)
272+ bininfo zig-out/bin/c64-hello.prg -D
273+ ```
274+
275+ ### ` romtool ` — NES / SNES ROM analyser
276+
277+ ``` sh
278+ zig-out/bin/romtool < subcommand> [options] < file>
279+ ```
280+
281+ | Subcommand | Description |
282+ | ------------| -------------|
283+ | ` disasm ` | 6502 / 65816 disassembly |
284+ | ` unpack ` | Extract PRG/CHR banks + ` header.txt ` |
285+ | ` pack nes ` | Assemble PRG+CHR banks back into an iNES ROM |
286+ | ` pack snes ` | Assemble bank binaries into an SFC ROM with correct checksum |
287+
288+ ** ` disasm ` options:**
289+
290+ | Flag | Description |
291+ | ------| -------------|
292+ | ` --bank N ` | NES: PRG bank N (16 KB, 0-based); SNES: 32 KB bank N (0-based) |
293+ | ` --base 0xNNNN ` | Override load address displayed |
294+ | ` --offset N ` | Skip N bytes before disassembling (address adjusts automatically) |
295+ | ` --length N ` | Disassemble at most N bytes |
296+ | ` --m8 ` / ` --x8 ` | SNES: start with M/X flags set (8-bit accumulator/index) |
297+
298+ ``` sh
299+ # Disassemble NES PRG bank 1 from offset $1234
300+ romtool disasm game.nes --bank 1 --base 0xC000 --offset 0x1234 --length 128
301+
302+ # Disassemble SNES RESET vector (HiROM, bank 1, offset $7F98)
303+ romtool disasm game.smc --bank 1 --base 0x8000 --offset 0x7F98 --m8 --x8 --length 40
304+
305+ # Unpack all banks to a directory
306+ romtool unpack game.nes /path/to/game-banks/
307+
308+ # Reassemble NES ROM from PRG + CHR binaries
309+ romtool pack nes -o repacked.nes prg-bank-00.bin chr-bank-00.bin
310+
311+ # Assemble SNES ROM from 32KB bank binaries (checksum auto-computed)
312+ romtool pack snes -o out.sfc --map lorom bank-00.bin [bank-01.bin ...]
313+
314+ # Same with SMC copier header and custom title
315+ romtool pack snes -o out.smc --map hirom --title " MY GAME" --smc bank-00.bin
316+ ```
317+
318+ ### ` chr2svg ` / ` svg2chr ` — NES CHR tile converter
319+
320+ ``` sh
321+ # CHR ROM → SVG (view/edit tiles in any SVG editor)
322+ chr2svg zig-out/bin/chr-bank-00.bin tiles.svg --scale 3 --cols 16
323+
324+ # SVG → CHR ROM (after editing)
325+ svg2chr tiles.svg chr-bank-00.bin
326+ ```
327+
328+ ### ` elf2mlb ` — Mesen label file generator
329+
330+ Converts a MOS ELF debug binary to a Mesen ` .mlb ` label file for source-level symbol display in the Mesen emulator debugger.
331+
332+ ``` sh
333+ elf2mlb zig-out/bin/hello1.nes.elf hello1.mlb
334+ ```
335+
336+ The ` gen-labels ` build step runs this automatically for all NES examples.
337+
222338## Platform notes
223339
224340- ** NES mappers** — CNROM 4-bank CHR demo; press Start to cycle through 4 CHR banks with distinct palettes. ROM: 32 KB PRG + 32 KB CHR ROM (4×8 KB banks).
225341- ** NES CNROM hello** — uses translated ` mapper.h ` via ` b.addTranslateC ` ; calls ` set_chr_bank(0) ` to initialise the CNROM CHR bank. ROM: 32 KB PRG + 8 KB CHR ROM.
342+ - ** NES CNROM sprites** — CNROM OAM sprite rendering with banked CHR. ROM: 32 KB PRG + 8 KB CHR ROM.
226343- ** NES UNROM hello** — uses translated ` mapper.h ` ; calls ` set_prg_bank(0) ` to initialise the UNROM PRG bank. ROM: 256 KB PRG + 8 KB CHR RAM.
344+ - ** NES UNROM colour-cycle** — cycles backdrop colour across multiple UNROM PRG banks. ROM: 256 KB PRG + CHR RAM.
227345- ** NES MMC1 hello** — uses translated ` mapper.h ` ; calls ` set_prg_bank(0) ` and ` set_mirroring(MIRROR_VERTICAL) ` to initialise MMC1 registers. ROM: 256 KB PRG + 8 KB CHR RAM.
228- - ** NES MMC3 hello** — uses translated ` mapper.h ` ; calls ` set_prg_bank(0) ` to initialise MMC3 PRG bank. ROM: 512 KB PRG + 256 KB CHR ROM.
346+ - ** NES MMC1 sprites** — MMC1 OAM sprites with 8 KB CHR uploaded to CHR RAM via ` vram_write ` ; calls ` set_mmc1_ctrl(0x0E) ` first to set 8 KB CHR mode.
347+ - ** NES MMC3 hello** — uses translated ` mapper.h ` ; calls ` set_prg_bank(0) ` to initialise MMC3 PRG bank. ROM: 512 KB PRG + CHR RAM.
348+ - ** NES MMC3 pads** — MMC3 controller input + sprite-background collision; uploads CHR tiles to CHR RAM.
229349- ** NES GTROM hello** — uses translated ` mapper.h ` ; GTROM (Codemasters) flash mapper. ROM: 512 KB PRG flash.
350+ - ** NES GTROM colour-cycle** — GTROM PRG bank cycling with LED toggle via ` $5000 ` write.
230351- ** NES UNROM-512 hello** — uses translated ` mapper.h ` ; calls ` set_prg_bank(0) ` and ` set_chr_bank(0) ` to initialise mapper 30 registers. ROM: 512 KB PRG + 32 KB CHR RAM.
231- - ** NES Action53 hello** — uses translated ` mapper.h ` ; mapper 28 (Action53 multicart). ROM: 128 KB PRG + 8 KB CHR RAM.
352+ - ** NES Action53 hello** — uses translated ` mapper.h ` ; mapper 28 (Action53 multicart). ROM: 64 KB PRG + 8 KB CHR RAM.
232353- ** FDS hello** — Famicom Disk System; uses raw PPU register writes via ` nes/hardware.zig ` (no neslib — FDS has no CHR ROM, raw PPU only). Writes dark-green backdrop (` $1A ` ) to palette ` $3F00 ` .
233354- ** VIC-20 hello** — uses CBM KERNAL ` cbm_k_chrout ` to print "HELLO VIC20!", then cycles VIC chip background/border colour register (` $900F ` ). Targets 24K memory expansion, loads at ` $1201 ` .
234355- ** C64 hello** — uses translated ` c64.h ` (VIC-II typed struct) via ` b.addTranslateC ` ; cycles VIC-II border colour register.
235356- ** CX16 hello** — uses CBM KERNAL ` cbm_k_chrout ` to print "HELLO X16!", then cycles the border colour register.
236357- ** Lynx hello** — uses translated ` _mikey.h ` (MIKEY typed struct) via ` b.addTranslateC ` ; animates all 32 palette entries.
358+ - ** SNES FastROM** — same π demo as ` snes-pi-test ` built with map mode ` $30 ` (FastROM) and MEMSEL=1; ROM mirrored at ` $80:8000 ` , runs at full 3.58 MHz.
359+ - ** SNES HiROM** — 64 KB bank layout with header at ` $FFC0 ` ; data bank register forced to ` $00 ` via ` lda #$00; pha; plb ` in crt0 (safe for both LoROM and HiROM).
237360- ** Atari 8-bit DOS hello** — uses ` std.c.printf ` via CIO-backed libc (E: screen editor device).
238361- ** Atari 8-bit cart hello** — uses translated ` _gtia.h ` (GTIA write struct) via ` b.addTranslateC ` ; cycles COLBK background colour, synced to ANTIC VCOUNT.
239362- ** sim-hello** — uses translated ` sim-io.h ` (typed MMIO struct) via ` b.addTranslateC ` ; benchmarks fib(10), fib(20), and sieve of Eratosthenes for primes < 128.
0 commit comments