Session 1: hardware research, content measurement, codec decision, MAME harness

Verified GVRAM is one word-access per pixel in ALL color modes; chose 256-color
256x192 with movem.l bursts (page 1 sacrificed as double-buffer).

Measured 8 scenes from the Blu-ray source: blit costs under 8% of the 12fps
cycle budget, so I/O is the bottleneck, not CPU. Naive delta+RLE reaches only
3.2:1 (365 KB/s, 470MB) -> decision to use 4x4 vector quantization (~30 KB/s).

"Shot on twos" assumption failed: the transfer has zero duplicate frames, so
12fps requires explicit decimation.

Documents three false measurement results and their root causes (per-frame
Floyd-Steinberg dithering, temporal denoise, exact-match dedupe on noisy source).

MAME Lua injection harness works and is reusable for cycle-cost measurement;
the IOCS _B_READ disk benchmark is blocked returning -1.

Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
This commit is contained in:
reala-misaki
2026-08-23 11:23:49 -07:00
commit 65112b9305
19 changed files with 842 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
# Status & next-session handoff — end of session 1 (2026-08-23)
## Decisions locked
| decision | value | why |
|---|---|---|
| Target CPU | 68000 @ 10MHz (stock) | hardest honest constraint |
| Display mode | 256 colors, 256x192 in 256x256 CRTC mode | every mode is 1 word-access/pixel, so 256c is free vs 16c |
| Double buffer | **none** — page 1 sacrificed | enables `movem.l` 24px bursts; delta coding needs a RAM reference frame anyway |
| Codec | 4x4 vector quantization, per-scene codebook + block delta | CPU is idle, I/O is the ceiling — spend cycles to buy bandwidth |
| Framerate | 12 fps, **explicit decimation** | source has zero duplicate frames; no free "twos" win |
| Medium | SCSI HDD image (.hds) | but see SASI/SCSI split below |
| Emulator | MAME 0.277 x68000 | accurate enough that measured cycles mean something |
**OPEN QUESTION for the user:** stock 10MHz machines are **SASI**, not SCSI.
Three options, not yet chosen:
1. Stock 10MHz + SASI (purist) — VQ becomes mandatory
2. Stock 10MHz + CZ-6BS1 SCSI board — relieves I/O, keeps CPU honest
3. Super/XVI baseline — built-in SCSI, still a 10MHz 68000
Recommendation: make the codec's bitrate ceiling a **build parameter**, so one
encoder serves all three and the target is chosen at package time.
---
## Working setup
**MAME ROMs**`~/mame/roms/x68000.zip` (present, working).
Must pass **`-bios ipl10`**; the default BIOS is `cz600ce`, whose split
even/odd IPL halves (`rh-ix0897cezz.ic12` / `rh-ix0898cezz.ic11`) are absent.
`-verifyroms` will still report those two as missing — this is expected and harmless.
Boots headless at ~430-480% speed:
```
mame x68000 -bios ipl10 -video none -sound none -nothrottle -seconds_to_run 3
```
**Assembler** — vasm built from source, binary at `tools/vasm/vasmm68k_mot`
(source tarball alongside it). Verified correct 68000 output.
```
tools/vasm/vasmm68k_mot -Fbin -o out.bin in.s
```
**Blu-ray** — mount with:
```
udisksctl loop-setup -r -f DRAGONS_LAIR.iso # -> /media/reala-misaki/BDROM
```
NOTE: this loop mount is still active from session 1. Re-mount if the machine rebooted.
---
## MAME Lua harness — WORKING, reusable
`tools/bench/*.lua` inject 68000 machine code straight into emulated RAM and time
it against the emulated clock. No bootable disk or OS required. This is the
measurement rig for all future cycle-cost work (blit timing, decoder benchmarks).
Pattern:
```
mame x68000 -bios ipl10 -video none -sound none -nothrottle \
-seconds_to_run 30 -plugins -autoboot_script yourscript.lua
```
### Three MAME Lua gotchas — all cost real time, all now solved
1. **Retain the notifier subscription.** `emu.add_machine_frame_notifier()` returns
a token; if you drop it into a chunk-local it is garbage-collected and the
callback **silently stops firing**. Assign it to a **global** (`SUB = ...`).
2. **The stack pointer is `SP`, not `A7`** in `cpu.state[...]`.
Full list: A0-A6, D0-D7, PC, SP, SR, USP, CURPC, CURFLAGS, IR.
3. **`autoboot_script` fires at time=0, before boot** (PC=0). Wait until
`machine.time` >= ~5s before injecting, or IOCS is not yet initialised.
Also: piping MAME through `grep` block-buffers output — write raw to a file when
backgrounding, or you will see an empty log and assume a hang.
And never `pkill -f 'mame x68000'` — the pattern matches your own shell and kills it
(exit 144). Use `pkill -x mame`.
---
## BLOCKED: disk throughput benchmark
**Goal:** measure real SASI/SCSI KB/s to replace the folklore figures in FINDINGS.md §5.
**Status:** harness fully working; the IOCS call itself fails.
`IOCS _B_READ` ($46 via `TRAP #15`; d1.hb=PDA, d2.l=position, d3.l=bytes, a1=buffer)
returns **`FFFFFFFF` (-1), zero reads**, uniformly across:
- all 16 PDA values $80-$8F
- both d1 encodings (PDA in bits 31-24 and bits 15-8)
- image sizes 10MB / 20MB / 40MB
The uniformity is the diagnostic: calls are **dispatched and cleanly rejected**,
so `TRAP #15` and IOCS are reachable. MAME does mount the image
(`:x68k_hdc: opened image file bench.hdf`).
**Untested hypotheses, in rough order of likelihood:**
1. The raw image has no X68000 SASI format, so the IPL's boot scan never registered
a usable drive and IOCS refuses. Would need Human68k to format one — **we have
no Human68k image on this system.**
2. MAME's `x68k_hdc` SASI implementation may be too partial for IOCS-level reads.
3. `SP=$8000` may put the injected stack on top of the IOCS work area in low RAM.
Try a much higher stack.
4. The **SCSI path was never tried** — this is the obvious next move and is more
relevant to the target anyway:
`-exp1 cz6bs1 -hard disk.chd` with `exp1:cz6bs1:scsi:0 harddisk`
(`-listmedia` gains a `harddisk` slot accepting .chd/.hd/.hdv/.2mg/.hdi).
**Honest assessment: this benchmark is NOT on the critical path.** The VQ codec
(~30 KB/s) is correct whether SASI does 300 or 600 KB/s. Do not let it block the
encoder. Its real value is deciding whether the *simpler* row-span codec could
have sufficed.
Caveat if resumed: MAME idealizes drive seek latency. That's acceptable because the
realistic deployment is BlueSCSI/SCSI2SD (SD-backed, no mechanical seek), so what
gets measured is the bus/DMAC/controller path — the genuine ceiling. The caveat
only bites for a real period spinning drive.
---
## Next steps, in priority order
1. **Build the VQ encoder** (`tools/encoder/`) — 4x4 blocks, per-scene codebook,
block delta. Emit sample PNGs for visual evaluation. **The open question is
whether VQ softens Bluth's ink linework unacceptably — decide by eye before
committing to the architecture.**
2. **Full-disc survey** — all 224 streams, not 5s samples, to firm up bitrate
(current numbers are +/-30%) and map streams onto the arcade scene graph.
3. **Check the SNES project's license**, then evaluate reusing `data/events/`
(516 chapters / 29 scenes) as the scene-graph and input-timing layer.
4. Resolve the SASI/SCSI target question with the user.
5. Optionally unblock the disk benchmark via the SCSI path.
6. 68000 player skeleton: CRTC init for 256x192x256c, `movem.l` blitter,
ADPCM via HD63450 DMA.
## Not yet started
- Any 68000 player code
- ADPCM audio extraction/encoding (MSM6258, 15.6kHz mono, ~7.8 KB/s, ~10MB for 22min)
- Disk image packaging / container format
- Game logic (scene branching, input windows, death clips)