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:
@@ -330,10 +330,14 @@ print(f""" PSNR against the 24-bit source, 18_text_plane_16col.py over the same
|
||||
one entry. The tree has already measured a reserved entry at
|
||||
0.04 dB (60.3), so this is noise against {PSNR_FRAME_256-PSNR_SHIPPED:+.2f}.
|
||||
|
||||
NOT SETTLED, and it is the obvious next probe: whether a DMA CHANNEL can write
|
||||
the palette registers at $E82000, which would make the palette a 193rd chain
|
||||
entry and cost the CPU nothing at all. Untested; 61.2 only ever pointed a
|
||||
channel at GVRAM.
|
||||
SETTLED IN SESSION 30, AND THE ANSWER IS YES (FINDINGS 62): a channel writes
|
||||
the palette registers at $E82000 byte-exact, and ONE array-chained start
|
||||
crosses from those registers into GVRAM -- so the palette IS a 193rd chain
|
||||
entry and the clocks row above is what the CPU pays only if it does the write
|
||||
itself. dmagate.s runs 7-9. What that does NOT settle is the board: MAME maps
|
||||
the palette to palette_device over memory_array, whose write16 is a plain
|
||||
COMBINE_DATA, so there is no handler that could refuse a byte write and the
|
||||
model cannot discriminate. ROADMAP B4.
|
||||
|
||||
AND THE PSNR FIGURES ARE PIL's MEDIANCUT, not this project's own palette
|
||||
builder (vq.scene_palette / H.build). The DIRECTION is measured and the
|
||||
@@ -344,6 +348,14 @@ print(f""" PSNR against the 24-bit source, 18_text_plane_16col.py over the same
|
||||
w9 = 9.0
|
||||
free_packed_dma = PACKED_BPF * w9 + CHAIN_CLK + AUD_CLK
|
||||
free_packed_cpu = PACKED_BPF * w9 + blit[8] + AUD_CLK
|
||||
# ... and the same two rows with the PER-FRAME PALETTE actually charged, which
|
||||
# is what a player ships. The picture rows above are the comparison against the
|
||||
# codec and are left alone so the published 55.2% / 81.6% do not drift; these
|
||||
# are the shipping figures. Session 30 (FINDINGS 62) made the DMAC row's
|
||||
# version legal: the palette is a 193rd chain ENTRY, so it costs 512 more
|
||||
# delivered bytes and one more entry rather than 256 CPU word writes.
|
||||
pal_dma = (PACKED_BPF + PAL_BYTES) * w9 + CHAIN_CLK + B.DMA_CHAIN_CLK + AUD_CLK
|
||||
pal_cpu = (PACKED_BPF + PAL_BYTES) * w9 + blit[8] + pal_clk + AUD_CLK
|
||||
codec_9 = codec_bpf * w9 + codec_decode + AUD_CLK
|
||||
print("\n" + "=" * 78)
|
||||
print(f"""THE ANSWER, AT THE ONE RUNG THIS MACHINE CAN BE SHOWN TO RUN (W=9)
|
||||
@@ -352,6 +364,22 @@ print(f"""THE ANSWER, AT THE ONE RUNG THIS MACHINE CAN BE SHOWN TO RUN (W=9)
|
||||
free / DMAC->GVRAM / PACKED {100*free_packed_dma/FRAME_CLK:6.1f}% -- FITS, with {100-100*free_packed_dma/FRAME_CLK:.0f}% to spare
|
||||
free / CPU-painted / PACKED {100*free_packed_cpu/FRAME_CLK:6.1f}% -- FITS, with {100-100*free_packed_cpu/FRAME_CLK:.0f}% to spare
|
||||
|
||||
WITH THE PER-FRAME PALETTE CHARGED, which is what would ship:
|
||||
|
||||
DMAC-direct, palette on the CHAIN (62) {100*pal_dma/FRAME_CLK:6.1f}% of the frame, {(PACKED_BPF+PAL_BYTES)*FPS/1024:.0f} KB/s
|
||||
CPU-painted, palette written by the CPU {100*pal_cpu/FRAME_CLK:6.1f}% of the frame, {(PACKED_BPF+PAL_BYTES)*FPS/1024:.0f} KB/s
|
||||
|
||||
The palette costs the same on the WIRE either way -- {PAL_BYTES} B a frame,
|
||||
+{100*PAL_BYTES/PACKED_BPF:.1f}% -- and the wire is where this design is expensive. The gap
|
||||
between the two rows is the PAINT, not the palette.
|
||||
|
||||
What session 30 bought is smaller than either and is worth stating exactly:
|
||||
{pal_clk:,.0f} CPU clocks of palette writing replaced by one more chain entry at
|
||||
{B.DMA_CHAIN_CLK} clocks, a net {100*(pal_clk-B.DMA_CHAIN_CLK)/FRAME_CLK:.2f}% of a frame -- plus the structural half,
|
||||
which is that the video path then contains no per-frame PAINT at all. The
|
||||
CPU still issues the READ(10) and starts the channel, and neither of those
|
||||
is priced anywhere in this tree.
|
||||
|
||||
THE DECODER-FREE PACKED PLAYER FITS THE CLOCK BUDGET THAT THE CODEC MISSES.
|
||||
That is not a small correction to 47.5, it is the reverse of the reason the
|
||||
codec exists. 44.7 said it in advance and on a different cost model: "the
|
||||
|
||||
Reference in New Issue
Block a user