The compile benchmark was building each example via an in-memory
pipeline that mirrored the CLI except for one thing — it always
handed the linker empty `PrgBank::empty(...)` slots. That stayed
silently fine until `uxrom_user_banked.ne` started nesting a
function inside a `bank` block: the IR codegen emits
`JSR __tramp_step_animation` at the call site, and with no
trampoline request on the `Extras` bank the assembler's fixup
pass panics with "unresolved label". Local `cargo test` missed
it because the bench is only compiled under `--all-targets`,
which is what CI runs.
Fix: reconstruct the same `banked_streams` + `bank_trampolines`
dance `src/main.rs` already does for the real build path, and
thread the header format through `with_header` for parity.
https://claude.ai/code/session_01MaNVcDmK9gsspRkdxowQAM
Implements three items from docs/future-work.md's
"PNG-sourced palette and nametable assets" section:
- `palette Name @palette("file.png")` — the parser accepts a PNG
shortcut form; the asset resolver decodes the image via the
new `png_to_palette` helper, mapping each pixel's RGB to the
nearest NES master-palette index and building a 32-byte blob
that enforces the universal-first-byte convention (same as
the grouped-form parser). Errors cleanly on missing files or
more than 16 unique colours.
- `background Name @nametable("file.png")` — the parser accepts
a PNG shortcut form; the resolver decodes a 256×240 image into
a 960-byte tile-index table (deduplicating up to 256 unique
8×8 tiles) plus a 64-byte attribute table (bucketed by
average quadrant brightness). CHR data is not yet generated
automatically — callers still need to provide matching CHR
via the existing sprite / `@chr(...)` pipeline; the
limitation is documented on the `png_to_nametable` helper
and can be lifted in a follow-up.
- `--memory-map` now prints a "PRG ROM data blobs" section
listing each palette (32 B) and background (960 + 64 B)
under its linker-assigned label, plus a grand total. The
memory-map code is factored into `write_memory_map` which
takes a writer so unit tests can drive it against a
`Vec<u8>`. Memory-map printing moved to after the link step
so palette/background CPU addresses are available.
Call-site changes: `resolve_palettes` and `resolve_backgrounds`
now take a `source_dir` path and return `Result<_, String>`
because PNG decoding can fail. Updated the CLI driver,
benches/compile.rs, and every integration-test compile helper.
All 23 committed examples rebuild byte-identical; 525 lib
tests + 72 integration tests + 3 bin tests pass; clippy clean.
Adds two items from the "Code quality / tooling" section of
docs/future-work.md. Both make it easier to chase regressions
without touching codegen.
- `nescript build --no-opt` skips the IR optimizer pass so
optimizer-introduced miscompiles can be bisected against the
unoptimized output. Threaded through CompileOptions and gated
at the single optimizer call site in src/main.rs. Covered by a
new integration test that compiles the same program twice
(opt on / opt off) and asserts both outputs are valid iNES
ROMs with matching headers and reset vectors.
- A criterion-based `benches/compile.rs` harness that times the
full parse -> analyze -> lower -> optimize -> codegen -> link
pipeline on every examples/*.ne file. Sources are pre-read
into memory so file I/O stays off the hot loop, and each
example gets its own Criterion group for easy regression
spotting.
Committed ROM bytes under examples/*.nes are unchanged; the
emulator goldens under tests/emulator/goldens/ are untouched.