Put the player on a real volume, and find the write window is the frame

ROADMAP K3. src/player/packed.s (2,898 B) brings up its own display, builds
its own 193-entry DMA chain, keeps its own frame clock off V-DISP and fetches
every record itself with READ(10) off a CZ-6BS1. The rig writes no picture
byte, no palette entry and no CRTC register.

120 of 120 frames pixel-exact, every one compared, in both palette orders --
the gate had to grow to do it, because a packed frame is a LITERAL and the
codec's recursion was what made one comparison audit 120.

And the write window turns out to be the frame. A packed write requires R20
bit 11, buffer mode blanks the layer, and a DMAC-direct player holds the
window open for the whole data phase, so

    dark fraction of a slot = record bytes / (DATA-PHASE rate x slot)

which is 1.0 at the container's own 582.0 KB/s: every frame delivered, on
time, pixel-exact, and none of them displayed. The rate in that expression is
the BURST rate, a third hardware number B1 has no test for. It reverses 61.5's
ranking -- a packed player that DMAs to RAM and paints with the measured 27.3%
blit is on screen 72.7% of every slot at any rate, and the two are equal only
at 2,131 KB/s = 3.7x the wire.

And a held channel costs the frame clock half its ticks without the clock
being able to tell: 487 of 1,038 V-DISP edges lost, zero late frames reported,
the player believing 12 fps while the screen ran at 6.37.

FINDINGS 64. ROADMAP K4 opened and fenced behind B2.
check.sh ALL GREEN before and after.

Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
This commit is contained in:
prosolis
2026-08-25 09:10:48 -07:00
parent f1007a0dbc
commit 6f698ca226
14 changed files with 2091 additions and 23 deletions
+76 -12
View File
@@ -56,6 +56,24 @@ pairing. **B2 now decides which packed CONTAINER exists, not only which player**
(63.4). The fallback is a flag: `--scene-palette --no-palette` is 30.79 dB, zero
churn, 576.0 KB/s and still +2.07 dB on the shipping codec. **K3 is next.**
Amended end of session 32: **K3 IS DONE, AND IT FOUND THE THING THAT DECIDES
THE BRANCH (FINDINGS 64).** `src/player/packed.s` brings up its own display,
builds its own 193-entry chain, keeps its own clock off V-DISP and fetches every
record itself off a CZ-6BS1: **120 of 120 frames pixel-exact, every one
compared, in both palette orders.** Two things came with it. **(1) The write
window is the frame.** A packed write needs R20 bit 11, buffer mode blanks the
layer, and a DMAC-direct player holds the window open for the whole data phase
— so the dark fraction of a slot is `record / (DATA-PHASE rate x slot)` and a
medium that exactly meets the 582.0 KB/s sustained requirement **displays none
of the frames it delivers on time**. The rate that matters here is the BURST
rate, which is a third hardware number **B1 has no test for**. It also
**reverses 61.5's ranking**: a packed player that DMAs to RAM and paints with
the CPU opens the window only for the measured 27.3% blit, so it is on screen
72.7% of every slot at any rate, and the two are equal only at **2,131 KB/s =
3.7x the wire**. **(2) A held channel costs the frame clock half its ticks and
the clock cannot tell** — 46.9% of V-DISP edges lost, zero late frames reported,
the player believing 12 fps while the screen ran at 6.37. **The open item is now
K4.**
**THE COMPLETION TARGET IS M3, THE VERTICAL SLICE** (USER DECISION): one scene
tree — a decision point, two outcomes, a death clip — with audio, streaming from
a real SCSI volume on a stock 2 MB machine, playable. That is the point at which
@@ -108,7 +126,16 @@ None of these block M2 or M3 software work, because session 18 forced every rate
to be an explicit argument. They set constants, and two of them decide how much
headroom the finished player has.
**B1. Measure the BlueSCSI — throughput AND seek time.** **Session 29 gave this
**B1. Measure the BlueSCSI — throughput, seek time AND the DATA-PHASE BURST
RATE.** The third one is session 32's (FINDINGS 64.2) and it is not a refinement
of the first: sustained throughput decides whether record *i* arrives before
slot *i*, and the **burst rate during the data phase** decides how much of the
slot the picture is on screen, because a DMAC-direct packed player holds the
GVRAM write window open for exactly as long as the transfer takes and buffer
mode blanks the layer. A drive with a read-ahead cache can pass the first and
fail the second. The acceptance test is **`record / (burst x slot)` = the dark
fraction**; at the container's own 582.0 KB/s it is 1.0, and the picture is never
displayed. **Session 29 gave this
a second acceptance test that is not a codec figure at all: 576 KB/s SUSTAINED,
which is what a decoder-free packed literal frame costs and cannot be talked down
from (FINDINGS 61.5).** A codec's bitrate is a lever; a literal frame's is
@@ -286,9 +313,37 @@ frame is not tied to a scene palette the codec's codewords index into. It costs
codec's ceiling, so the whole +2.31 dB is the per-frame palette; 90% of that
palette changes every frame; and a mismatched paint is 12.8 dB worse, for
roughly half of every frame slot, if buffer mode does not blank.
- **K3. End to end, off the disc.** Palette, page-1 X-scroll 384, priority
`vc1 = 0x0002`, R20 bit 11; one chained DMA a frame. Gated pixel-exact over the
same 120-frame window the decoder is gated on.
- ~~**K3. End to end, off the disc.**~~ **DONE, session 32 — FINDINGS 64.**
`src/player/packed.s`, `tools/bench/packed.lua`, `tools/bench/packed_run.sh`,
`tools/bench/verify_packed.py`, `tools/analysis/31_display_duty.py`. Palette,
page-1 X-scroll 384, priority `vc1 = 0x0002`, R20 bit 11, one chained DMA a
frame, **120 of 120 pixel-exact in both palette orders** — and the gate checks
every frame rather than the last, because a packed frame is a literal and the
codec's recursion was what made one comparison audit 120.
**What it found is K4's whole content**, and it is in the amendment above: the
window is the frame, the burst rate decides visibility, and a held channel
eats the clock.
- **K4. THE PACKED PLAYER THAT IS ON SCREEN.** 64.2's option B: DMA the record
into one of two RAM buffers with the window SHUT, then paint it with the
packed `movem` blit (`blit.s` V8, **measured** at 227,553 clocks = 27.3% of a
slot). **82.2% of a frame at the 9 clk/B dual-address floor** against A's
54.9%, **99,328 B of RAM**, and a picture on screen **72.7% of every slot at
any delivery rate** instead of 0% at the container's own wire.
It is not a rewrite of K3: `packed.s` keeps its display bring-up, its clock,
its transport and its record arithmetic, and what changes is the chain's
destination and the addition of a paint. **The one thing in it that has never
been run is the overlap** — a channel filling buffer *i+1* while the CPU
paints buffer *i*, which is the first time in this project that the DMAC and
the 68000 have had to want the bus at the same time for a whole scene.
**K4 is conditional on B2 the same way K3's ranking was**, and the condition
now cuts the other way: if buffer mode does NOT blank, A is on screen the whole
slot and K4 is 27.3% of a frame spent on nothing. **Do not build K4 before B2
is answered** — that is the same rule 61.7 wrote for the codec, applied to the
branch that replaced it.
**What K3 deletes, and why that is a risk and not a win to be banked:** a
DMAC-direct packed player has **no ring**`ring.i`, `xfer.i` and most of
@@ -719,17 +774,26 @@ P2 re-encode bundle DONE (60): DLX5, records ARE sectors ───────
E7/E4/C1 PARKED session 29: encoder work waits on B2 ───────────┤
K1 palette-register DMA? ─> K2 packed container ─> K3 end to end ──┤
(61.9; K1/K2 survive a bad B2, K3 does not)
K1 DONE s30 (62), K2 DONE s31 (63) ── K3 is the open one
K1 DONE s30 (62), K2 DONE s31 (63), K3 DONE s32 (64):
120/120 pixel-exact, both palette orders, off a real volume
└─> and K3 found that the WRITE WINDOW IS THE FRAME, so: │
K4 (DMA to RAM + the measured 27.3% paint) is the player │
that is ON SCREEN below a 2,131 KB/s BURST rate -- which │
is 3.7x the wire, so below every rate anyone has proposed │
P4a WIRING (the channel behind ring.i's mailbox) <- THE LAST ITEM ─┤
P1 P2 P3 P4b P5 P7, P6 bus cost (52), G1 scene graph (56) ────────┼─> M2 ─>
B1 seek+rate (sets HEADROOM, not fit) ─────────────────────────────┘ M3 ─> M4
B2 blanking ─┬─ NOT blanked ─> the DECODER-FREE PACKED player is live (61):
55.2% of a frame at the 9 clk/B FLOOR, against
the codec's 110.4% -- and then B1 decides it,
because it wants 576 KB/s FIXED (61.4, 61.5)
└─ blanked ──────> a 27..113% duty strobe; there is no version of
it that is merely expensive (48.3, 61.6)
B2 blanking ─┬─ NOT blanked ─> K3's DMAC-DIRECT player is the one: 54.9% of a
│ frame at the 9 clk/B floor against the codec's
110.4%, on screen the whole slot, and K4's paint
would be 27.3% spent on nothing (61.4, 61.5)
└─ blanked ──────> K3's player is on screen for
1 - record/(BURST x slot) of every slot, which is
ZERO at the container's own wire -- so K4 is the
player, at 82.2% of a frame and 99,328 B of RAM
(64.2). Neither answer kills the branch and each
picks a different player.
B1 BURST rate (NEW, 64.2) ──> which of the two K3/K4 wins, if B2 blanks
```
**Read that top-left branch as the project's live question.** Everything else