// spriteProbe.c - Phase 4.2 sprite engine verification probe.
//
// Bare-metal SHR probe: brings up SHR 320 mode via iigsSpriteInit()
// (no startdesk(), no QD), places 8 16x16 sprites at known
// coordinates, renders them, then writes a sentinel byte at a chosen
// scratch DP address so the harness knows we got past the render
// pass.
//
// What we verify under runInMame.sh --check-u8:
//
//   1. SHR enabled marker.  iigsSpriteInit() pokes $C029 = 0xC1.
//      A subsequent readback through $00:C029 verifies the soft
//      switch landed.  (runInMame writes are gated against $C0xx,
//      so the only way that byte reads back as 0xC1 is via our
//      code's store.  Bank 0 $C029 is the actual register.)
//
//   2. After the second render at y=36, scan line 20 (the FIRST
//      position) is back to background.  $E1:2000 + 20*160 = $E1:2C80
//      should be 0x00 -- EraseAll restored the saved background.
//
//   3. Sprite 7's left edge is at byte offset 56 of scan line 36
//      (final position), so $E1:2000 + 36*160 + 56 = $E1:3938 should
//      be 0x77.
//
//   4. A byte BETWEEN sprite rows (scan line 100, offset 0) at
//      $E1:2000 + 100*160 = $E1:5E80 should still be 0x00 (the
//      framebuffer-clear value, untouched by any sprite).
//
//   5. Sentinel marker at $00:0070 = 0x99 confirming the program
//      reached the end of main without halting.

#include <stdint.h>
#include "iigs/sprite.h"


// One 16x16 sprite tile, 4bpp packed: every nibble is 7 (white).
// 128 bytes total.  Stored in .rodata so it sits in bank 0 text-or-
// rodata range (well below $A000) and is reachable as a plain
// pointer.
static const uint8_t kWhiteTile[128] = {
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
    0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
};


int main(void) {
    // 1. Bring up SHR 320 mode.  Clears framebuffer to color 0
    //    (black), installs default palette, resets sprite list.
    iigsSpriteInit();

    // 2. Build the frame's sprite list: 8 copies of the white tile,
    //    laid out across one row at y=20, x stepping by 16.
    iigsSpriteBegin();
    for (uint16_t i = 0; i < 8; i++) {
        IigsSpriteT s;
        s.x      = (uint16_t)(i * 16U);
        s.y      = 20;
        s.pixels = kWhiteTile;
        iigsSpriteAdd(&s);
    }

    // 3. Render: saves background under each sprite, then blits.
    iigsSpriteRenderAll();

    // 4. One frame of update.  EraseAll restores the saved background
    //    (returning row 20 to all-zero), then we shift each sprite
    //    DOWN by 16 lines (y=20 -> y=36) and re-render.  After this:
    //      - row 20 should be all-zero again (background restored).
    //      - row 36 should hold the eight sprites.
    iigsSpriteEraseAll();
    iigsSpriteBegin();
    for (uint16_t i = 0; i < 8; i++) {
        IigsSpriteT s;
        s.x      = (uint16_t)(i * 16U);
        s.y      = 36;
        s.pixels = kWhiteTile;
        iigsSpriteAdd(&s);
    }
    iigsSpriteRenderAll();

    // 5. Drop the sentinel.  $70 is in DP, well outside both libcall
    //    scratch ($E0..$F4) and IMG slots ($C0..$DE), so we don't
    //    collide with any runtime use.
    *(volatile uint8_t *)0x70 = 0x99;

    // Halt — bare metal has no OS to return to.
    for (;;) {
    }
}
