mirror of
https://github.com/imjasonh/nescript
synced 2026-07-09 09:18:01 +00:00
linker: gate default smiley CHR tile on __default_sprite_used marker
Drop the built-in smiley from CHR tile 0 unless something in the
program actually references it. The marker fires when either:
1. `IrOp::DrawSprite` lowering falls back to tile 0 because the
sprite name doesn't resolve to a user declaration, or
2. The same lowering sees a runtime `frame:` override (which
could index any tile, including 0).
A third source of dependency — a background nametable entry of 0 —
is detected in the linker by scanning `bg.tiles` for zeros. This
preserves the smiley for programs like `examples/friendly_assets`
that use tile 0 as a background placeholder, even though their
draws resolve to user-declared sprites.
Programs whose draws all resolve to explicitly-declared sprites
with static frames AND whose backgrounds reference tiles 1+ now
leave CHR tile 0 as an all-zero blank, freeing 16 CHR bytes that
the user can treat as an always-transparent background tile.
Verified against the current example set: `sprites_and_palettes`
and `auto_chr_background` reclaim tile 0; every other example
keeps it (either they fall back to tile 0 via an undeclared draw
name or their background tilemap references tile 0).
All 33 emulator goldens still pass — removing an unreferenced CHR
tile can't change observable output.
https://claude.ai/code/session_016kM6P7PukktBDqTZexrrAN
This commit is contained in:
parent
7533ac281e
commit
6561daff35
7 changed files with 127 additions and 17 deletions
|
|
@ -1226,11 +1226,15 @@ fn sprite_resolution_uses_tile_index() {
|
|||
"Player sprite CHR bytes should be placed at tile index 1",
|
||||
);
|
||||
|
||||
// The default smiley tile at index 0 should still be non-zero (untouched).
|
||||
// The default smiley tile at index 0 should be blank ($00) —
|
||||
// the program's one `draw Player at: (...)` resolves to the
|
||||
// declared Player sprite at tile 1, so the `__default_sprite_used`
|
||||
// marker never fires and the linker doesn't copy the smiley
|
||||
// into tile 0. That frees the 16 bytes for user graphics.
|
||||
let tile0 = &rom_data[chr_start..chr_start + 16];
|
||||
assert_ne!(
|
||||
assert_eq!(
|
||||
tile0, &[0u8; 16],
|
||||
"tile 0 should still contain the default smiley",
|
||||
"tile 0 should be blank when no draw falls back to the smiley",
|
||||
);
|
||||
|
||||
// In PRG ROM, look for `LDA #$01 ; STA $0201,Y` which writes
|
||||
|
|
@ -1882,12 +1886,16 @@ fn e2e_bank_declarations_dont_affect_nrom_prg_size() {
|
|||
#[test]
|
||||
fn e2e_banked_chr_rom_is_preserved() {
|
||||
// CHR ROM should still contain the default smiley sprite at
|
||||
// tile 0 regardless of how many PRG banks the ROM has.
|
||||
// tile 0 regardless of how many PRG banks the ROM has — but
|
||||
// only when the program actually exercises the fallback. A
|
||||
// `draw` of an undeclared sprite name drops the marker; we
|
||||
// rely on that here rather than declaring a sprite so we keep
|
||||
// testing the "banked ROM still emits the smiley" path.
|
||||
let source = r#"
|
||||
game "CHRCheck" { mapper: MMC1 }
|
||||
bank One: prg
|
||||
bank Two: prg
|
||||
on frame { wait_frame }
|
||||
on frame { draw Unknown at: (0, 0) }
|
||||
start Main
|
||||
"#;
|
||||
let rom = compile_banked(source);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue