Put the palette on the channel, and find one start paints a whole frame
ROADMAP K1, the packed player's one open structural item. A frame is a picture
AND a palette, and no run in this tree had pointed a DMA channel at the palette
registers. dmagate.s runs 7-9, gated by dma_run.sh and check.sh:
7. 512 B off the disc into $E82000, bus held -- byte-exact in 256 register
words, read back OUT OF the registers by the 68000;
8. the SAME transfer aimed at RAM -- byte-exact at $2C000, and 256 of 256
palette words still read the poison the CPU wrote, which is what attributes
run 7 to the channel's MAR rather than to the readback path;
9. ONE array-chained start across two kinds of destination -- the palette and
six picture rows at the 1,024 B line stride, 2,048 B byte-exact.
So a packed frame is one channel start: a 193-entry array, palette first, CPU
halted from the first byte to the last. The array is scene-constant, because
the packed layout spends both 256-colour pages and there is no page to flip.
What is left on the CPU per frame in the video path is the channel start and the
READ(10) -- no per-frame PAINT, which is not the same claim as no per-frame CPU.
The destination is POISONED first (62.1). Runs 4-6 wrote into RAM that was zero
and GVRAM that was stale against a record that is mostly pad; "it matches the
disc" was weaker than it read as. The host counts whether the poison actually
discriminates instead of assuming it: 511 of 512, and the gate refuses under 500.
And it opened a hardware item (62.4, ROADMAP B4). MAME maps the palette to
palette_device over memory_array, whose write16 is a plain COMBINE_DATA -- RAM
that honours mem_mask, with no handler that could refuse a byte write. Unlike
GVRAM's 256-colour arm there is nothing here to be wrong about, so the run
bounds the model and not the board. What a real palette register does with a
byte write is unmeasured. A negative costs 0.28% of a frame and nothing else.
29_packed_player.py now also prints the two rows with the per-frame palette
charged -- 55.7% of a frame on the chain, 582 KB/s -- alongside the picture-only
figures the codec comparison is quoted against.
check.sh ALL GREEN before (tmp/check_s30_start.log) and after
(tmp/check_s30_end.log).
Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
This commit is contained in:
+49
-9
@@ -32,6 +32,16 @@ floor the codec is 110.4% and a decoder-free packed player is **55.2%**. It asks
|
||||
much headroom the player has and started deciding WHICH PLAYER EXISTS**, and B2
|
||||
stopped being a nice-to-have. The codec cannot be packed: 47.6.4 is closed and
|
||||
the answer is no, both ways (61.3).
|
||||
Amended end of session 30: **K1 IS DONE AND THE ANSWER IS THE GOOD ONE
|
||||
(FINDINGS 62).** A channel writes the palette registers at `$E82000` byte-exact,
|
||||
and ONE array-chained start crosses from device registers into GVRAM — so a
|
||||
frame is a palette entry and 192 row entries, started once, with the CPU halted
|
||||
throughout, and the array is scene-constant. **It opened B4**: MAME models the
|
||||
palette as plain `COMBINE_DATA` storage with no handler to be wrong about, so
|
||||
the run bounds the model and not the board, and what a real palette register
|
||||
does with a byte write is UNMEASURED. B4 is the cheapest hardware item in the
|
||||
project and a negative costs 0.28% of a frame. **K2, the packed container, is
|
||||
next.**
|
||||
|
||||
**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
|
||||
@@ -119,6 +129,23 @@ the priority register `0xE82500` at `0x0000` (47.3).
|
||||
> dark one. **B2 and B1 are now the same decision from two sides, and B2 is the
|
||||
> five-minute half.**
|
||||
|
||||
**B4. Does a real palette register take a BYTE write?** (62.4, new session 30.)
|
||||
`$E82000` is 256 16-bit registers. The decoder-free packed player's per-frame
|
||||
palette rides the frame's array chain as a 193rd entry, which means a
|
||||
dual-address channel with an 8-bit device port writes it **one byte at a time**,
|
||||
even bytes into the high half of a register and odd into the low. **MAME cannot
|
||||
be asked**: it maps the palette to `palette_device::read16/write16`, which is
|
||||
`memory_array`'s `COMBINE_DATA` over plain storage — RAM that honours
|
||||
`mem_mask`, with no handler that could refuse. So the run in 62 is a statement
|
||||
about the model and not about the board.
|
||||
|
||||
**It is the cheapest item on this list, cheaper than B2**: write `$A5` to
|
||||
`$E82000` and `$5A` to `$E82001` from the CPU and read the word back. If it
|
||||
comes back `$A55A` the palette rides the chain. **The blast radius of a negative
|
||||
is small and known** — the palette leaves the chain and the CPU writes 256 words
|
||||
a frame at 61.9's derived 0.28% of a frame — which is why this is B4 and not
|
||||
above B2.
|
||||
|
||||
**B3. Single-address vs dual-address DMA — and now, first, DOES THE CARD DRIVE
|
||||
`#EXREQ`?** 242 KB/s and 0.69 dB was the old framing. **Session 27 promoted this
|
||||
to the item that decides whether the design fits at all (59.7).** The frame
|
||||
@@ -197,14 +224,26 @@ codec's 110.4%, and **+4.89 dB** on the shipping container because a literal
|
||||
frame is not tied to a scene palette the codec's codewords index into. It costs
|
||||
**582 KB/s, fixed, with no lever.** Three items, in order.
|
||||
|
||||
- **K1. Can a DMA channel write the palette registers at `$E82000`?** (61.9.)
|
||||
The cheapest item in the project and the one with the largest structural
|
||||
payoff: if the palette takes a byte-wide DMA the way GVRAM does in buffer mode,
|
||||
it becomes a **193rd array-chain entry** and one channel start paints a whole
|
||||
frame — palette included, CPU halted throughout, **no per-frame CPU work in the
|
||||
video path at all**. Same shape as 61.2's three runs: a run in `dmagate.s`, a
|
||||
host comparison in `dma.lua`, an assertion in `dma_run.sh`, **and a negative
|
||||
control.**
|
||||
~~**K1. Can a DMA channel write the palette registers at `$E82000`?**~~
|
||||
**DONE, session 30 — FINDINGS 62. YES, in this model.** `dmagate.s` runs 7–9:
|
||||
512 B off the disc into the whole graphic palette, **byte-exact in 256
|
||||
register words** read back out of `$E82000` by the 68000; the same transfer
|
||||
aimed at RAM leaving the palette as the CPU poisoned it, which is what
|
||||
attributes the first run to the channel's `MAR`; and **ONE array-chained start
|
||||
crossing from device registers into GVRAM**, which is the shape of a whole
|
||||
frame. The destination is POISONED first (62.1) because "it matches" was a
|
||||
weak claim against a record that is mostly pad, and the host counts the
|
||||
poison's discriminating power rather than assuming it: 511 of 512.
|
||||
**And the array is SCENE-constant** (62.3) — the packed layout spends both
|
||||
256-colour pages, so there is no page to flip and the 193 destinations never
|
||||
change; the 1,158 B array is built once at scene setup. What is left on the
|
||||
CPU per frame in the video path is the channel start and the READ(10), and
|
||||
neither is priced — say "no per-frame PAINT work", not "no per-frame CPU work".
|
||||
**It opened B4** (62.4): MAME models the palette as a generic `palette_device`
|
||||
over `memory_array`, whose `write16` is a plain `COMBINE_DATA`, so it has no
|
||||
handler to be wrong about and cannot discriminate. And it filed one open
|
||||
design choice, 62.5: palette FIRST or 193rd is visible on screen and is not
|
||||
decided.
|
||||
- **K2. A packed container.** Quantise to **254** colours (index 0 is the
|
||||
transparency key, black at 255 — 47.2), interleave column *i* with *i+128*,
|
||||
emit a per-frame palette, sector-align the record. Simpler than a coded one:
|
||||
@@ -222,7 +261,8 @@ DMAC-direct packed player has **no ring** — `ring.i`, `xfer.i` and most of
|
||||
simplification that large usually hides something, and 61.7.2 names the specific
|
||||
untested thing: a chained transfer has never run back to back at 12 fps.
|
||||
|
||||
**K1 and K2 survive a bad answer to B2. K3 does not.** Do K1 first.
|
||||
**K1 and K2 survive a bad answer to B2. K3 does not.** ~~Do K1 first.~~ **K1 is
|
||||
done (session 30, FINDINGS 62); K2 is next.**
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user