diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93080a2..76387bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,3 +49,31 @@ jobs: - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - run: cargo test --all-targets + + examples: + name: Build Examples + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - run: cargo build --release + - name: Compile all .ne examples + run: | + for f in examples/*.ne; do + echo "==> Compiling $f" + cargo run --release -- build "$f" + done + - name: Verify ROMs are valid iNES + run: | + for f in examples/*.nes; do + echo "==> Checking $f" + # iNES magic: first 4 bytes must be "NES\x1a" + header=$(od -A n -t x1 -N 4 "$f" | tr -d ' ') + if [ "$header" != "4e45531a" ]; then + echo "FAIL: $f is not a valid iNES ROM (header: $header)" + exit 1 + fi + size=$(stat -c%s "$f") + echo " OK: $size bytes" + done diff --git a/examples/README.md b/examples/README.md index 05a5f17..6663d9e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -35,10 +35,18 @@ Use the d-pad (arrow keys in most emulators) to move the sprite. ## What you'll see -The ROM displays a small smiley-face sprite (an 8x8 tile built into the -compiler's default CHR data). In `hello_sprite`, you control it with the d-pad. +The ROM displays a small 8x8 smiley-face sprite. This is a default tile built +into the compiler's CHR data. In `hello_sprite`, you control it with the d-pad. In `bouncing_ball`, it moves on its own and bounces off the screen edges. +### About sprite names + +In Milestone 1, the name in `draw Smiley at: (x, y)` is parsed but not +resolved to a specific tile — all draws use CHR tile 0 (the built-in smiley). +The `draw` syntax is forward-compatible: when `sprite` declarations and the +asset pipeline arrive in M3, names like `Smiley` will reference actual +sprite definitions with custom tile data from PNGs. + ## Emulator controls | NES Button | Typical Key | diff --git a/examples/bouncing_ball.ne b/examples/bouncing_ball.ne index 911e949..7ba75ac 100644 --- a/examples/bouncing_ball.ne +++ b/examples/bouncing_ball.ne @@ -2,6 +2,10 @@ // // Build: cargo run -- build examples/bouncing_ball.ne // Output: examples/bouncing_ball.nes +// +// Note: In M1 the sprite name in `draw` is parsed but not resolved. +// All sprites use tile 0 from the built-in CHR data (a smiley face). +// Custom sprite declarations come in M3. game "Bouncing Ball" { mapper: NROM diff --git a/examples/hello_sprite.ne b/examples/hello_sprite.ne index b809a65..9b602de 100644 --- a/examples/hello_sprite.ne +++ b/examples/hello_sprite.ne @@ -1,8 +1,12 @@ // Hello Sprite — the simplest NEScript program. // -// Displays a smiley-face sprite on screen and moves it with the d-pad. +// Displays a sprite on screen and moves it with the d-pad. // Build: cargo run -- build examples/hello_sprite.ne // Output: examples/hello_sprite.nes (open in any NES emulator) +// +// Note: In M1 the sprite name in `draw` is parsed but not resolved. +// All sprites use tile 0 from the built-in CHR data (a smiley face). +// Sprite declarations with custom tile data come in M3. game "Hello Sprite" { mapper: NROM diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index a756957..4cd02f9 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -540,7 +540,10 @@ impl CodeGen { fn gen_draw(&mut self, draw: &DrawStmt) { // OAM buffer is at $0200-$02FF // Each sprite entry: Y, tile, attributes, X - // For M1: use OAM slot 0 (bytes $0200-$0203) + // For M1: sprite name (draw.sprite_name) is parsed but ignored — + // all draws use OAM slot 0 with tile index 0 (the built-in CHR tile). + // Sprite name resolution and multiple OAM slots come in M2/M3. + let _ = &draw.sprite_name; // Y position (stored at $0200) self.gen_expr(&draw.y); self.emit(STA, AM::Absolute(0x0200));