First pixels on an actual X68000 screen. Everything up to now was Python-side or a headless -video none run, which cannot snapshot at all. The blocker was not the video controller. The IPL leaves CRTC R20 = 0x0B16, and bit 11 is "G-VRAM set to buffer", which makes MAME's draw_gfx() return early. GVRAM writes still land and read back correctly while the layer is invisible, so six attempts at $E82400/$E82500/$E82600 all rendered black with every register holding the value I intended. Two more facts, both confirmed against MAME 0.277 source rather than assumed: - $E8E001 monitor contrast is left at 14 by the IPL, scaling all output to 93.3%. The player must set it to 15. Contrast 0 blanks the screen, which is a free fade-to-black for scene transitions. - The palette word is GGGGGRRRRRBBBBBI with a shared LSB, expanded as pal6bit((field<<1)|I). With contrast at 15 the render is pixel-exact, not merely close, which also confirms the 1024-byte GVRAM line stride. That exactness gives a new quality ceiling: the 15-bit+I palette alone costs 38.88 dB against the 24-bit palettised source, the same order as the scsi profile's own codec error. scsi is close to display-transparent on hardware, which bounds how much further it is worth raising. Unblocks next step 2, the 68000 decoder skeleton, which now has a known-good reference image to diff against. Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
Dragon's Lair — Sharp X68000 port
Porting Dragon's Lair to a stock X68000 (68000 @ 10MHz, 2MB, SASI/SCSI).
This is fundamentally a video codec problem, not a game-logic problem: the game logic is a scene table with branching input windows; the difficulty is pushing ~22 minutes of Don Bluth animation through a 10MHz 68000.
Read first
docs/FINDINGS.md— measured hardware facts, content statistics, codec decision, and a section on measurement traps that produced three separate false results. Read §4 before trusting any pipeline number.docs/STATUS.md— current state, working setup, blockers, next steps. Start here. It also lists what has been explicitly abandoned, so old ideas do not get re-proposed.docs/BENCHMARK.md— how to measure the storage subsystem, and why a bandwidth figure out of MAME would be meaningless.docs/HARDWARE.md— X68000 GVRAM/CRTC reference.
Layout
docs/ findings, status, hardware reference
tools/analysis/ measurement scripts, numbered in the order they were written
(01/02 marked BROKEN deliberately, kept as regression refs).
Run from the repo root — they import from tools/encoder/.
tools/bench/ MAME Lua injection harness + 68000 benchmark sources
tools/vasm/ vasm m68k assembler (built from source)
tools/encoder/ hybrid VQ encoder + DLX1 container writer (working)
src/player/ 68000 player (not yet written)
assets/ extracted frames/audio (gitignored)
Encoder
python3 tools/encoder/extract.py 00020 /tmp/fr 12 crop
python3 tools/encoder/encode.py /tmp/fr out.dlx --profile sasi --preview p.png
Two quality profiles ship from one codec and one decoder — sasi (110 KB/s) and
scsi (280 KB/s) are two points on the same rate-distortion curve. The codec is
a Cinepak-style hybrid: each 4x4 block is coded as SKIP, one 4x4 codeword, four
2x2 codewords, or RAW literal pixels, chosen per block by rate-distortion.
The RAW escape means lam=0 is pixel-exact against the palettised frame, so the
quality knob spans lossless to heavily-compressed without changing the bitstream.
Profiles are derived from a bandwidth figure, not chosen by eye:
python3 tools/encoder/profile_gen.py --bw-mbps 4 --name scsi
On reading
docs/FINDINGS.md: it is append-only and several later sections overturn earlier ones. Superseded sections carry a blockquote at the top pointing to the correction — heed those, especially 18 (reversed by 21).
Source media (DRAGONS_LAIR.iso) and ROMs are gitignored — supply your own.