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:
+163
-3
@@ -37,13 +37,21 @@
|
||||
; burst modelled as held.
|
||||
|
||||
DGFLAG = $18600 ; 0 idle / 1 done
|
||||
DGREC = $18610 ; 6 x 32 B: rc, err, mtc0, spin, csr, cer, mtc, mar
|
||||
DGREC = $18800 ; 9 x 32 B: rc, err, mtc0, spin, csr, cer, mtc, mar
|
||||
; $18800 AND NOT $18610, WHERE THIS LIVED: nine
|
||||
; records of 32 B run to $188FF, and from $18610
|
||||
; they would have run over DGWIN at $18700 --
|
||||
; the window run's own result, which run 10 then
|
||||
; writes back. A silent overlap between two
|
||||
; runs' evidence is the kind of thing that makes
|
||||
; a gate report the wrong run's numbers.
|
||||
DGREC_SZ = 32
|
||||
DGWIN = $18700 ; u32 return of the WINDOWED dma read (want -1)
|
||||
DGWERR = $18704 ; u32 SC_ERR after it (want SCE_WINDOW)
|
||||
DGR20 = $18708 ; u32 R20 as it stood during run 4
|
||||
DGR20N = $1870C ; u32 R20 as it stood during run 5 (the control)
|
||||
DGR20C = $18710 ; u32 R20 as it stood during run 6 (chained)
|
||||
DGR20P = $18714 ; u32 R20 as it stood during run 9 (palette+rows)
|
||||
R20_BUF = $0916 ; 256-colour, 31.5 kHz, G-VRAM SET TO BUFFER
|
||||
R20_MSK = $0116 ; the SAME, bit 11 CLEAR -- the negative control
|
||||
DGDST4 = $C0C000 ; where the control writes
|
||||
@@ -60,6 +68,25 @@ DGDST0 = $20000 ; PIO
|
||||
DGDST1 = $24000 ; DMA, bus held
|
||||
DGDST2 = $28000 ; DMA, cycle stealing
|
||||
|
||||
; ---- runs 7-9: THE PALETTE (ROADMAP K1, FINDINGS 61.9's first open item).
|
||||
DGPAL = $E82000 ; the GRAPHIC palette: 256 words, GGGGGRRRRRBBBBBI
|
||||
DGPALN = 256 ; words in it -- and 512 B is exactly ONE sector
|
||||
DGPBLK = 1 ; so the whole palette is one block off the disc
|
||||
DGPOIS = $A500 ; the poison: word i = DGPOIS|i. A palette that
|
||||
; still reads this was not written by anything.
|
||||
DGDST6 = $2C000 ; run 8's destination: RAM, so the palette is
|
||||
; left alone and must still read poison
|
||||
DGDST7 = $C14000 ; run 9's six GVRAM rows, at the 1024 B stride
|
||||
DGCHA2 = $19100 ; run 9's array: 7 x {u32 MAR, u16 MTC}
|
||||
DGCHN2 = 7 ; palette 512 B + 6 rows x 256 B = 2,048 B
|
||||
DGCROW2 = 256
|
||||
DGPS7 = $1A000 ; the palette as it stood after run 7 ...
|
||||
DGPS8 = $1A200 ; ... after run 8 (the control: poison) ...
|
||||
DGPS9 = $1A400 ; ... and after run 9 (chained). SNAPSHOTS, not
|
||||
; a late read: each run overwrites the previous
|
||||
; run's palette, so a host that looks once at
|
||||
; the end sees only the last of the three.
|
||||
|
||||
org $10000
|
||||
start:
|
||||
clr.l DGFLAG.l
|
||||
@@ -167,7 +194,7 @@ start:
|
||||
; 256 B of a 1024 B line stride, so a frame is 192 destinations and not one.
|
||||
; 46.6 said "no stride for a DMAC to skip" about the bytes WITHIN a row and left
|
||||
; the rows themselves unexamined; a channel cannot skip 768 B any more than it
|
||||
; could skip the 300 B in front of a record (run 7 below).
|
||||
; could skip the 300 B in front of a record (run 10 below).
|
||||
;
|
||||
; The MC68450 answers this with SEQUENTIAL ARRAY CHAINING -- an array of 6-byte
|
||||
; {u32 MAR, u16 MTC} entries it walks by itself -- and MAME implements it. So
|
||||
@@ -199,7 +226,109 @@ dg_mkch:
|
||||
bsr dg_save
|
||||
clr.l DM_BARV.l ; and OFF again, so run 7 is unchained
|
||||
|
||||
; ---- 7. and a WINDOWED read through the channel, which must be REFUSED. This
|
||||
; ---- 7. THE PALETTE. Can a channel write $E82000? (FINDINGS 61.9, ROADMAP
|
||||
; K1.) Runs 4-6 put the PICTURE on the channel; a packed frame is a picture AND
|
||||
; a palette, and if the palette registers take a byte-wide DMA the way GVRAM
|
||||
; does in buffer mode then the palette is a 193rd array-chain entry and ONE
|
||||
; channel start paints a whole frame -- no per-frame CPU work in the video path
|
||||
; at all. If they do not, the CPU writes 256 words a frame (61.9 derives that
|
||||
; at ~2,370 clocks, 0.28% of a frame) and the architecture still stands; this is
|
||||
; the difference between cheap and free, and it is worth one run to know which.
|
||||
;
|
||||
; 512 B IS THE WHOLE PALETTE AND EXACTLY ONE SECTOR, which is why this run reads
|
||||
; one block where the others read four: a transfer that ran long would write
|
||||
; $E82200 (the TEXT palette) and then $E82400 (the video controller's own
|
||||
; registers, priority included), and a probe that reconfigures the video
|
||||
; controller as a side effect is not a probe.
|
||||
;
|
||||
; THE PALETTE IS POISONED FIRST, and that is what stops this being run 4's trap
|
||||
; a second time. A destination that already holds the right bytes cannot tell a
|
||||
; channel that wrote them from a channel that did nothing; RAM at $20000 was
|
||||
; zero and the record is mostly pad, so "it matches" has been a weak claim all
|
||||
; session. Word i is set to $A500|i, which no 512 B of container matches by
|
||||
; accident, and the host reports how many of the 512 positions the poison and
|
||||
; the disc actually differ in rather than assuming all of them.
|
||||
bsr scsi_init
|
||||
bsr dg_poison
|
||||
move.l #DM_HELD_DCR,DM_DCRV.l
|
||||
move.l #DM_HELD_OCR,DM_OCRV.l
|
||||
move.l #1,DM_USE.l
|
||||
move.l #DGLBA,d3
|
||||
moveq #DGPBLK,d4
|
||||
lea DGPAL,a1
|
||||
bsr scsi_read
|
||||
lea DGPS7,a1
|
||||
bsr dg_palsnap ; before run 8 overwrites it
|
||||
lea DGREC+6*DGREC_SZ,a0
|
||||
bsr dg_save
|
||||
|
||||
; ---- 8. THE NEGATIVE CONTROL, and it is an ATTRIBUTION control rather than a
|
||||
; mechanism one. Run 5's control could point at a mode bit; there is no mode
|
||||
; bit here, so what has to be excluded is that run 7's palette held the disc's
|
||||
; bytes for some reason OTHER than the channel having written them there --
|
||||
; a readback that aliases somewhere else, the SPC's own path touching the
|
||||
; registers, the poison never having landed.
|
||||
;
|
||||
; Same transfer, same channel, same bytes; ONE thing different, the destination
|
||||
; address. The disc's bytes must appear at $2C000, and the palette must still
|
||||
; read poison in all 256 words. Two claims from one run, and the second is the
|
||||
; one that makes run 7 mean anything: it also proves the CPU's poison writes
|
||||
; reach the registers the host reads back, which is the positive half.
|
||||
bsr scsi_init
|
||||
bsr dg_poison
|
||||
move.l #DM_HELD_DCR,DM_DCRV.l
|
||||
move.l #DM_HELD_OCR,DM_OCRV.l
|
||||
move.l #1,DM_USE.l
|
||||
move.l #DGLBA,d3
|
||||
moveq #DGPBLK,d4
|
||||
lea DGDST6,a1
|
||||
bsr scsi_read
|
||||
lea DGPS8,a1
|
||||
bsr dg_palsnap ; must be poison, word for word
|
||||
lea DGREC+7*DGREC_SZ,a0
|
||||
bsr dg_save
|
||||
|
||||
; ---- 9. THE 193rd ENTRY: one start, the palette AND the picture rows. This is
|
||||
; the run K1 exists for. Runs 7 and 8 only show that a channel can write the
|
||||
; palette registers; what the architecture needs is that ONE array chain can
|
||||
; cross from a hardware register area into GVRAM without the CPU between them,
|
||||
; because a frame is a palette entry followed by 192 row entries and the whole
|
||||
; claim is that the CPU starts the channel once.
|
||||
;
|
||||
; Seven entries, 2,048 B, out of the same LBA as everything else: 512 B into the
|
||||
; palette and then six rows of 256 B at the 1024 B line stride. The destination
|
||||
; regions are of two different KINDS -- device registers and video RAM in buffer
|
||||
; mode -- which is exactly the crossing that has never been run.
|
||||
bsr scsi_init
|
||||
bsr dg_poison
|
||||
move.w #R20_BUF,CRTC20.l
|
||||
move.l #R20_BUF,DGR20P.l
|
||||
lea DGCHA2,a0
|
||||
move.l #DGPAL,(a0)+ ; entry 0: the palette, a whole sector
|
||||
move.w #DGPALN*2,(a0)+
|
||||
lea DGDST7,a1
|
||||
moveq #DGCHN2-2,d5 ; the remaining six are picture rows
|
||||
dg_mkch2:
|
||||
move.l a1,(a0)+
|
||||
move.w #DGCROW2,(a0)+
|
||||
lea 1024(a1),a1
|
||||
dbra d5,dg_mkch2
|
||||
move.l #DM_HELD_DCR,DM_DCRV.l
|
||||
move.l #DM_HELD_OCR|$08,DM_OCRV.l ; OCR CHAIN = %10, array chain
|
||||
move.l #DGCHA2,DM_BARV.l
|
||||
move.l #DGCHN2,DM_BTCV.l
|
||||
move.l #1,DM_USE.l
|
||||
move.l #DGLBA,d3
|
||||
moveq #DGBLK,d4
|
||||
lea DGDST7,a1 ; ignored under chaining, as in run 6
|
||||
bsr scsi_read
|
||||
lea DGPS9,a1
|
||||
bsr dg_palsnap
|
||||
lea DGREC+8*DGREC_SZ,a0
|
||||
bsr dg_save
|
||||
clr.l DM_BARV.l ; and OFF again, so run 10 is unchained
|
||||
|
||||
; ---- 10. and a WINDOWED read through the channel, which must be REFUSED. This
|
||||
; is the one test here that is expected to fail, and it has to fail LOUDLY: the
|
||||
; alternative is a channel writing a whole sector into a ring that has room for
|
||||
; a record, over the top of records the decoder has not finished with.
|
||||
@@ -240,4 +369,35 @@ dg_save:
|
||||
clr.l DM_MARF.l
|
||||
rts
|
||||
|
||||
; ---- the poison. Word i of the graphic palette <- $A500|i, written by the
|
||||
; 68000 itself. Two jobs: a destination that cannot hold the right answer by
|
||||
; accident, and a known pattern the control run reads back out of the registers
|
||||
; to show the readback path shows what is actually in them.
|
||||
dg_poison:
|
||||
movem.l d0-d2/a0,-(sp)
|
||||
lea DGPAL,a0
|
||||
moveq #0,d1 ; i
|
||||
move.w #DGPALN-1,d0
|
||||
.p: move.w d1,d2
|
||||
ori.w #DGPOIS,d2 ; $A500|i, and i never exceeds 255
|
||||
move.w d2,(a0)+
|
||||
addq.w #1,d1
|
||||
dbra d0,.p
|
||||
movem.l (sp)+,d0-d2/a0
|
||||
rts
|
||||
|
||||
; ---- the palette as it stands, copied to (a1) by the 68000 READING THE
|
||||
; REGISTERS. A snapshot and not a late host read: each palette run overwrites
|
||||
; the last one's result, so all three have to be kept while they are true. It
|
||||
; is also the same shape of evidence 53.3 used for pal_pack -- the words come
|
||||
; back out of $E82000 rather than out of the buffer they were built in.
|
||||
dg_palsnap:
|
||||
movem.l d0/a0-a1,-(sp)
|
||||
lea DGPAL,a0
|
||||
move.w #DGPALN-1,d0
|
||||
.s: move.w (a0)+,(a1)+
|
||||
dbra d0,.s
|
||||
movem.l (sp)+,d0/a0-a1
|
||||
rts
|
||||
|
||||
include "src/player/scsi.i"
|
||||
|
||||
Reference in New Issue
Block a user