Put the data phase on the DMAC, and find auto-request is charged by time
ROADMAP P4a. src/player/dma.i programs HD63450 channel 1 and takes the SCSI DATA IN phase off the CPU; src/player/dmagate.s reads the same 2,048 B at LBA 1000 three ways -- PIO, the channel with the bus held, the channel stealing cycles -- and all three are byte-exact against the host's copy of the volume. The evidence never reads $EA0015, because 57.3 established that it cannot: with the DMAC's OWN asserted MAME cannot tell a CPU-driven byte there from a DMAC-driven one. The discriminator is the CPU's own progress. MTC is sampled by the INSTRUCTION AFTER the one that starts the channel, and held it reads 0 of 2,048 -- the whole transfer happened between two instructions, because the 68000 did not execute in between -- against the full count and 426 loop trips for the stealing configuration. Put the stealing registers in the held slot and every byte still arrives and tools/bench/dma_run.sh goes RED, which is what says the counter can come out different; 58.3's vacuous "UNDERRUNS: 0/120" is the trap being avoided. tools/analysis/27_dmac_config.py decodes the four register bytes out of the player's own source, with the MC68450 field tables now in one copy (tools/analysis/mc68450.py) shared with 21_iplrom_dmac.py, so the player's configuration and the IPL ROM's 16..19 clk/B one are the same decoding. Three bounds on the apparatus, read out of MAME 0.277 rather than inferred: the CZ-6BS1 has NO request line to the DMAC (its flow control is DTACK), so external request cannot be run; single address cannot be run either, because only channel 0 has device callbacks; and only burst is modelled as held. Of the four rows of the W ladder exactly one -- dual address held -- has a code path here, and it is the one demonstrated. W did not move by one clock, for the third session running. What outlives the emulator is the currency. Every W in this project is clocks per DELIVERED byte, which presumes the device asks; an auto-requested channel spends its share of the bus whether or not a byte is there, so a record costs what it costs to ARRIVE -- halve the delivery rate and the CPU cost of the same record doubles. tools/analysis/28_autorequest_cost.py prices it from MC68450 3.8 and 5.2.3.3.2, gating its formulas against Table 5-3's sixteen rows first. At 37,405 B and an explicit 460 KB/s: max rate costs the whole 95.3% of a frame the record takes to land, and of the GCR's four bus shares only BR=00, 50%, carries the rate -- 10.61 clk/B, 47.6% of a frame, against 40.4% for the W=9 row and 391.8% measured for PIO. The GCR is a design lever nothing in this tree had named. 59.4 changes what is left. sc_in_data now REFUSES a windowed read when the data phase is the channel's (SCE_WINDOW), because a channel writes a contiguous run and cannot drop the 300 B in front of a record. 117 of 120 records need one, so sector-aligned records have gone from a preference in ROADMAP's re-encode bundle to the precondition the transport enforces -- and that bundle is now the only thing between this tree and M2. One collision, recorded because the procedure is the finding: DM_USE first sat at $18300, which is ring.i's XF_SLOT mailbox, and the P4b stage -- untouched by this work -- went red on a run that never reached its snapshot. check.sh was ALL GREEN before any of this, which is what made that red unambiguous. ALL GREEN after too, with one new stage. decode.bin is unchanged at 1,296 B and the same MD5. Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
This commit is contained in:
@@ -5539,3 +5539,195 @@ now worth 87 against either.
|
||||
**Does put a real number on the layer below every previous delivery result.**
|
||||
Everything in FINDINGS 49, 51 and 55 was measured with the bytes arriving free.
|
||||
They are not free, and 58.2 is the first measurement of what they cost.
|
||||
|
||||
---
|
||||
|
||||
## FINDINGS 59 — the DMAC drives the data phase, and auto-request is charged by time (session 27)
|
||||
|
||||
**Emulated.** MAME 0.277, `x68000 -exp1 cz6bs1 -ramsize 2M`, a blank
|
||||
`scsiexrom.bin` on a private rompath (57.1's substitution, unchanged). No real
|
||||
hardware ran. `./tools/bench/check.sh` was ALL GREEN before this and ALL GREEN
|
||||
after, with one new stage.
|
||||
|
||||
**ROADMAP P4a is DONE at the transport level.** What is left before M2 is not a
|
||||
DMAC question any more; it is the re-encode bundle, because 59.4 makes
|
||||
sector-aligned records a precondition the transport now enforces rather than a
|
||||
preference the roadmap recorded.
|
||||
|
||||
### 59.1 The channel drives the data phase, and the evidence is the CPU's own progress
|
||||
|
||||
`src/player/dma.i` programs HD63450 channel 1 and hands it the DATA IN phase;
|
||||
`src/player/dmagate.s` reads **the same 2,048 B at LBA 1000 three ways** and the
|
||||
host compares all three against its own copy of the image:
|
||||
|
||||
| | bytes | MTC one instruction after START | CPU trips round its wait loop |
|
||||
|---|---|---|---|
|
||||
| PIO, the path 58.2 measured | byte-exact | — | — |
|
||||
| **DMA, bus HELD** (DCR `$00`, OCR `$81`) | **byte-exact** | **0 of 2048** | **1** |
|
||||
| **DMA, cycle STEALING** (DCR `$80`, OCR `$80`) | **byte-exact** | 2048 of 2048 | 426 |
|
||||
|
||||
Both channels reported `CSR = $E0` (COC, BTC, NDT), `CER = $00`, `MTC = 0` and a
|
||||
memory address exactly `+2048` from where it started.
|
||||
|
||||
**THE DISCRIMINATOR NEVER READS `$EA0015`, and that is the whole design.** 57.3
|
||||
established that watching the data register cannot answer this question: with
|
||||
the DMAC's `OWN` asserted — which it is at idle on this machine — MAME cannot
|
||||
tell a CPU-driven byte there from a DMAC-driven one. So what separates the two
|
||||
configurations is **whether the 68000 executed anything while the bytes were
|
||||
arriving**:
|
||||
|
||||
move.b #CCR_START,DM_CCR ; the channel is told to go
|
||||
move.w DM_MTC,d0 ; <- sampled by the VERY NEXT instruction
|
||||
|
||||
Held, `d0` is **zero**: the entire 2,048-byte transfer happened between two
|
||||
instructions, because the CPU did not run in between. Stealing, `d0` is the full
|
||||
count and the CPU then goes round its own loop 426 times while the bytes
|
||||
trickle in. That is what "holds the bus" means, and it is a fact about the CPU
|
||||
rather than about the data register.
|
||||
|
||||
**The mechanism, named so the claim is not over-read.** MAME models a held bus
|
||||
by asserting `INPUT_LINE_HALT` for burst + max-rate and clearing it at
|
||||
end-of-transfer (`hd63450.cpp`). It is not inventing that semantic: MC68450
|
||||
§5.2.3.3.1 says of maximum-rate auto-request that "all operands in the data
|
||||
block will be transferred in one burst, so that the DMAC will use **100% of the
|
||||
available bus bandwidth**". The model and the datasheet agree about what this
|
||||
configuration does to the CPU. **They do not agree about anything per-operand,
|
||||
and no `W` is claimed here** (42.5: MAME's DMAC runs on wall-clock attotimes).
|
||||
|
||||
**The gate was checked against its own negative.** With the *stealing* register
|
||||
pair put in the *held* slot, the run still delivers all 2,048 bytes byte-exact
|
||||
— and `tools/bench/dma_run.sh` goes **red**, on the trip count and on the MTC
|
||||
sample. A counter that cannot come out different is 58.3's vacuous
|
||||
"UNDERRUNS: 0/120" again; this one can, and was made to.
|
||||
|
||||
`tools/analysis/27_dmac_config.py` decodes the four register bytes out of
|
||||
`src/player/dma.i` itself, with the same MC68450 field tables
|
||||
`21_iplrom_dmac.py` reads the IPL ROM with (now one copy, `mc68450.py`). So
|
||||
"dual address, 8-bit port, burst, auto-request at max rate" is a decode of the
|
||||
bytes the player programs, not a comment next to them — and it is directly
|
||||
comparable with Sharp's own disk channel, which 52.5 read as `DCR $80 / OCR $B2`
|
||||
and priced at 16..19 clk/B.
|
||||
|
||||
### 59.2 Three things this model cannot be asked, and they bound the result
|
||||
|
||||
Read out of MAME 0.277's source rather than inferred from behaviour:
|
||||
|
||||
1. **The card has no request line to the DMAC.** `x68k_scsiext.cpp`'s `drq_w`
|
||||
only stores a flag; the expansion slot carries no request to the HD63450 at
|
||||
all (`x68k.cpp` wires `drq0` from the FDC and `drq3` from ADPCM, and nothing
|
||||
else). The card's flow control is **DTACK**: on a DMAC cycle with DRQ low it
|
||||
negates DTACK and the channel discards that operand and retries. So **REQG =
|
||||
10, external request — the mode the ladder's `W`=5 and `W`=12 rows assume —
|
||||
cannot be run here at all.**
|
||||
2. **Single address cannot be run either.** `hd63450.cpp` takes the implicit
|
||||
path only for a channel with a device callback, and on this machine only
|
||||
channel 0 (the FDC) has one. `DTYP` = 10/11 on channels 1..3 falls through to
|
||||
the dual-address code.
|
||||
3. **Only burst is modelled as held.** The device tests `(dcr & 0xc0) == 0`, so
|
||||
XRM = 10 (cycle steal *without* hold) and XRM = 11 (cycle steal **with**
|
||||
hold) are one code path.
|
||||
|
||||
**So of the four rows of the per-byte ladder, exactly one — dual address, bus
|
||||
held, 9 clk/B — has a code path in this model, and it is the one demonstrated.**
|
||||
That is a bound on the apparatus, not a result about the board. The slot's own
|
||||
pinout has `#EXREQ` at B36, so a real CZ-6BS1 plausibly drives it; whether it
|
||||
does is ROADMAP B3, and it is now a sharper question than "which DTYP".
|
||||
|
||||
### 59.3 Auto-request is charged by TIME, not by byte — and the GCR is the lever
|
||||
|
||||
This is the finding that outlives the emulator. Every `W` in this project is
|
||||
**clocks per delivered byte**, which presumes the device asks for each one. An
|
||||
auto-requested channel does not know whether the device is ready: it takes the
|
||||
share of the bus it was told to take and spends it either way. So the cost of a
|
||||
record scales with **how long the record takes to arrive** — halve the delivery
|
||||
rate and the CPU cost of the same record **doubles**. No `W` does that.
|
||||
|
||||
`tools/analysis/28_autorequest_cost.py` prices it from MC68450 §3.8 and
|
||||
§5.2.3.3.2, and gates its formulas against Table 5-3's sixteen printed rows
|
||||
before printing anything. At the gate container's 37,405 B mean record and
|
||||
**460 KB/s, an explicit rate and not a measurement** (FINDINGS 50):
|
||||
|
||||
| configuration | sustains | charged to the 68000 | % of a 12 fps frame |
|
||||
|---|---|---|---|
|
||||
| REQG 01, max rate — what 59.1 demonstrated | the wire | 21.23 clk/B | **95.3%** |
|
||||
| REQG 00, LRAR, BR = 00, 50% of the bus | 534 KB/s | 10.61 clk/B | **47.6%** |
|
||||
| REQG 00, LRAR, BR = 01, 25% | 267 KB/s | 5.31 | 23.8% — **does not carry the rate** |
|
||||
| REQG 00, LRAR, BR = 10, 12.5% | 133 KB/s | 2.65 | 11.9% — **does not carry the rate** |
|
||||
| *(ladder, for comparison)* `W`=9 dual held | — | 9 | 40.4% |
|
||||
| *(measured, 58.2)* PIO | — | 87.28 | 391.8% |
|
||||
|
||||
**The held configuration is the cheapest per byte MOVED and the dearest per byte
|
||||
DELIVERED**, and the gap between those two is the device's own slowness: 9
|
||||
clocks of DMAC work inside 21.2 clocks of waiting means **42.4% of the held bus
|
||||
does anything at all**. Holding the bus is only cheap when the hold is ended by
|
||||
the device, which is what external request is for.
|
||||
|
||||
**BT and BR are two bits each and they set what fraction of the bus the player
|
||||
gives away** (burst time `2^(BT+4)` clocks, sample period `2^(BT+BR+5)`, share
|
||||
`2^-(BR+1)`). Nothing in this tree had named the GCR as a design choice; it is
|
||||
the same kind of lever as `aligned` vs `split` and it belongs in the same list.
|
||||
**At 460 KB/s only BR = 00 carries the rate**, so the fallback plan — if a real
|
||||
card turns out not to drive `#EXREQ` — is 50% of the bus for the duration of
|
||||
every record, or 47.6% of a frame slot per record. That is affordable and it is
|
||||
not free, and it is the first cost model in this project that gets *worse* when
|
||||
the disc gets slower.
|
||||
|
||||
**59.3's one load-bearing assumption**, stated because the whole table rests on
|
||||
it: that the channel *spends* its allotted share whether or not the device has a
|
||||
byte. Under auto-request a request is pending until MTC is exhausted, so the
|
||||
DMAC takes the bus during every window it is entitled to; when the device is not
|
||||
ready the cycle is stretched by wait states (a real card negating DTACK) or
|
||||
retried later (MAME's model discards the operand), and either way the window is
|
||||
gone from the CPU's point of view. **If a real CZ-6BS1 instead lets the DMAC off
|
||||
the bus early when no byte is there, 59.3's figures are upper bounds.** That is
|
||||
a board question, and it is B3's.
|
||||
|
||||
### 59.4 The window is refused, and that makes the re-encode a precondition
|
||||
|
||||
58.3 found that 117 of 120 records start part way into a sector, and that PIO
|
||||
absorbs it for free because the CPU is already touching every byte. A channel
|
||||
cannot: it writes a contiguous run and cannot be told to drop the 300 bytes in
|
||||
front of the record. `sc_in_data` now **refuses** a windowed read when the data
|
||||
phase is the DMAC's — a new error, `SCE_WINDOW` — rather than quietly delivering
|
||||
the neighbouring records' bytes into the ring, where the block loop has no
|
||||
bounds check to catch them (49.2). The gate asserts the refusal.
|
||||
|
||||
**So "sector-aligned records" has stopped being a preference in ROADMAP's
|
||||
re-encode bundle and become the thing standing between P4a and the ring.** The
|
||||
transport states its own precondition; the container does not meet it yet.
|
||||
|
||||
### 59.5 What this does and does not move
|
||||
|
||||
**Does not move `W`.** Not by one clock, for the third session running, and for
|
||||
the reason 57.6 and 58.4 give.
|
||||
|
||||
**Does not put the DMAC behind `ring.i`'s mailbox.** 59.4 is why: `xfer.i` asks
|
||||
for records, and every record but three needs a window. That work is now
|
||||
downstream of the re-encode bundle rather than of a DMAC question.
|
||||
|
||||
**Does close the question ROADMAP called P4's first job.** A configuration that
|
||||
holds the bus exists, runs, delivers the disc's bytes byte-exact, and is
|
||||
demonstrated by evidence that does not come from watching `$EA0015` — which is
|
||||
exactly what 57.3 said would be needed.
|
||||
|
||||
**Does change what the fallback looks like.** Before this session the fallback
|
||||
below a held bus was `W` = 16..19, the IPL ROM's own arbitrated configuration.
|
||||
It is now limited-rate auto-request at a share the player chooses, priced in a
|
||||
currency the project did not have, and the arithmetic says a 50% share carries
|
||||
this container at 460 KB/s.
|
||||
|
||||
### 59.6 One collision, and it was caught by the half of `check.sh` that runs first
|
||||
|
||||
`DM_USE` — the word that tells `sc_in_data` whether the data phase is the
|
||||
DMAC's — was first placed at `$18300`. `scsi.i`'s trace ends at `$182FF` and the
|
||||
next 160 bytes are the **ring's**: `$18300` is `ring.i`'s `XF_SLOT` mailbox, and
|
||||
`tools/bench/stream.lua` reads the same addresses from outside the machine. So
|
||||
the ring rig's first record request wrote a non-zero word into what the
|
||||
transport now read as "use the DMAC", and **the P4b stage — a stage this session
|
||||
did not otherwise touch — went red on a run that never reached its snapshot.**
|
||||
|
||||
Recorded because the procedure is the finding: `check.sh` was ALL GREEN before
|
||||
any of this work, so the red was unambiguously new, and the failure was in a
|
||||
stage nobody would have re-run on suspicion. Both halves of "green before and
|
||||
green after" earned their place; the map is now `$18500`, clear of everything
|
||||
the streaming rig owns.
|
||||
|
||||
+54
-13
@@ -8,6 +8,10 @@ Amended end of session 24: G1 done (FINDINGS 56).
|
||||
Amended end of session 25: P4 HALF done (FINDINGS 57).
|
||||
Amended end of session 26: P4b done, P4a is the last open item before M2
|
||||
(FINDINGS 58).
|
||||
Amended end of session 27: P4a done at the transport level; THE RE-ENCODE
|
||||
BUNDLE under P2 is now the only thing between this tree and M2, because 59.4
|
||||
made sector-aligned records a precondition the transport enforces rather than a
|
||||
preference (FINDINGS 59).
|
||||
|
||||
**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
|
||||
@@ -34,7 +38,7 @@ these units:
|
||||
| **68000 clocks** | measured, and the rate controller binds on them. |
|
||||
| **Delivery rate** | **no working figure, deliberately** (FINDINGS 50, USER DECISION). Every tool REQUIRES an explicit rate. |
|
||||
| **Seek time** | **no figure at all, and never had one.** 51.3/51.4 made it matter. |
|
||||
| **W, clocks stolen per delivered byte** | 5 single-address held, 9 dual held, 12 single arbitrated; the IPL ROM's own disk channel is **16..19** (52.5). **The largest open number in the project.** |
|
||||
| **W, clocks stolen per delivered byte** | 5 single-address held, 9 dual held, 12 single arbitrated; the IPL ROM's own disk channel is **16..19** (52.5). **The largest open number in the project.** Session 27 added the row underneath it: with **no external request line** on the card (59.2) the channel is auto-requested and is charged **by time rather than by byte**, so at 460 KB/s a 50% bus share costs **10.61 clk/B** and a smaller share cannot carry the rate at all (59.3). |
|
||||
|
||||
---
|
||||
|
||||
@@ -135,7 +139,9 @@ own; together they are one:
|
||||
2. `--spans all` as the default (E2, and it is the loaded lever on the byte
|
||||
side);
|
||||
3. re-derive span selection jointly with `lam` (E3);
|
||||
4. **sector-align every record (58.3, new in session 26)** — +0.43% on the
|
||||
4. **sector-align every record (58.3; PROMOTED TO A PRECONDITION in session
|
||||
27, 59.4 — `sc_in_data` refuses a windowed read under the DMAC, so this is
|
||||
what the channel is waiting for)** — +0.43% on the
|
||||
wire, zero clocks, and it is what lets P4a's DMA channel write straight
|
||||
into the ring with no window and no bounce copy. Until then the letterbox gets the palette's
|
||||
closest thing to black (index 255 on the gate container); `load.i` reports
|
||||
@@ -173,8 +179,10 @@ period from `htotal - 8`), so the tree's "1/55.46 s granularity" was 1/56.69 s
|
||||
throughout. No 68000 cycle figure moves — the CPU clock is unrelated to the
|
||||
screen — but anything paced by the raster does. 54.5.
|
||||
|
||||
**P4. Real transport. P4b DONE, session 26 — FINDINGS 58. P4a OPEN, and it is
|
||||
now the ONLY thing between this tree and M2.**
|
||||
**P4. Real transport. P4b DONE, session 26 — FINDINGS 58. P4a DONE at the
|
||||
transport level, session 27 — FINDINGS 59. What is now between this tree and M2
|
||||
is THE RE-ENCODE BUNDLE under P2, because the channel refuses a windowed read
|
||||
(59.4) and 117 of 120 records need one.**
|
||||
~~Drive the MB89352 instead of a host file.~~ `src/player/scsi.i` selects a SCSI
|
||||
target and issues READ(10) on the 68000, with no IOCS and no host in the
|
||||
transfer path: **4,096 B from LBA 0 and 2,048 B from LBA 1000, both byte-exact**
|
||||
@@ -189,14 +197,45 @@ wants the real ROM's bytes** and is untouched by this.
|
||||
|
||||
**What is left is the half that decides the project**, and it is now two pieces:
|
||||
|
||||
**P4a. A DMAC configuration that HOLDS THE BUS.** Unchanged as the first job,
|
||||
but 57.3 changes how it can be shown: `x68k_scsiext.cpp` glues `$EA0015` so that
|
||||
a write is discarded when `exown()` is asserted and DRQ is low, and on this
|
||||
machine `exown()` is asserted at idle. Every transfer therefore runs the SPC in
|
||||
DMA mode with the CPU moving the bytes through the DMAC's own door — and **MAME
|
||||
cannot then distinguish a CPU-driven byte from a DMAC-driven one at that
|
||||
address**. "The DMAC held the bus" needs evidence that does not come from
|
||||
watching `$EA0015`.
|
||||
~~**P4a. A DMAC configuration that HOLDS THE BUS.**~~ **DONE at the transport
|
||||
level, session 27 — FINDINGS 59.** `src/player/dma.i` programs HD63450 channel 1
|
||||
and takes the DATA IN phase: **the same 2,048 B off the disc three ways — PIO,
|
||||
held, stealing — all three byte-exact.** 57.3's warning was met rather than
|
||||
worked around: the evidence never reads `$EA0015`. **MTC is sampled by the
|
||||
instruction after the one that starts the channel, and held it reads zero of
|
||||
2,048** — the whole transfer happened between two instructions, because the
|
||||
68000 did not execute in between — against the full count and 426 CPU loop trips
|
||||
for the stealing configuration. Put the stealing registers in the held slot and
|
||||
every byte still arrives and the gate goes **red**, which is what says the
|
||||
counter can come out different (58.3's vacuous-counter trap, avoided
|
||||
deliberately).
|
||||
|
||||
**Three bounds on the apparatus, read out of MAME's source and not inferred**
|
||||
(59.2): the card has **no request line to the DMAC** (its flow control is
|
||||
DTACK), so external request — the mode the `W`=5 and `W`=12 rows assume —
|
||||
cannot be run; **single address** cannot be run either (only channel 0 has
|
||||
device callbacks); and **only burst is modelled as held**. Of the four rows of
|
||||
the ladder exactly one, dual address held, has a code path here, and it is the
|
||||
one demonstrated. The slot pinout has `#EXREQ` at B36, so a real card plausibly
|
||||
drives it — **that is now B3's sharpest form**.
|
||||
|
||||
**What is left of P4a is downstream of the container, not of the DMAC** (59.4):
|
||||
`sc_in_data` **refuses** a windowed read when the data phase is the channel's,
|
||||
because a channel writes a contiguous run and cannot drop the 300 B in front of
|
||||
a record. So putting the channel behind `ring.i`'s mailbox waits on the
|
||||
re-encode bundle.
|
||||
|
||||
**P4c (new, and it is a DESIGN CHOICE the tree had not named).** Auto-request is
|
||||
charged **by time, not by byte** — the channel spends its share of the bus
|
||||
whether or not a byte is there, so halving the delivery rate DOUBLES the CPU
|
||||
cost of the same record. The MC68450's GCR sets that share: `BT`/`BR`, four
|
||||
values, 50/25/12.5/6.25%. `tools/analysis/28_autorequest_cost.py` prices it
|
||||
against an explicit rate; at 460 KB/s **only the 50% share carries this
|
||||
container**, at 10.61 clk/B and 47.6% of a frame per record, against 40.4% for
|
||||
the `W`=9 row and 391.8% measured for PIO. **If B3 comes back saying the real
|
||||
card drives `#EXREQ`, the ladder applies and this is the fallback; if it does
|
||||
not, this IS the cost model** and the GCR pair is a number the player has to
|
||||
choose.
|
||||
|
||||
~~**P4b. `scsi.i` behind `ring.i`'s `XF_*` mailbox.**~~ **DONE, session 26 —
|
||||
FINDINGS 58.** `src/player/xfer.i` answers the mailbox with a real READ(10) per
|
||||
@@ -239,7 +278,9 @@ writes a contiguous run and cannot drop bytes. The three ways out price as
|
||||
avoid), or **+0.43% wire and zero clocks** (sector-aligned records in the
|
||||
container). The last one wins on both axes and is a **re-encode**; see the
|
||||
bundle under P2. **P4a should be attempted against a sector-aligned container,
|
||||
not against this one.**
|
||||
not against this one.** *(Session 27: it was, in the only sense that mattered —
|
||||
the transport now REFUSES the windowed case rather than being trusted not to
|
||||
reach it, so the bundle is a precondition rather than a plan. 59.4.)*
|
||||
|
||||
*(original item, still the standing description of the `W` question:)*
|
||||
Drive the MB89352 instead of a host file. **Session 23
|
||||
|
||||
@@ -1,3 +1,89 @@
|
||||
# Status & next-session handoff — end of session 27 (2026-08-24)
|
||||
|
||||
## Session 27: the DMAC drives the data phase, and auto-request is charged by time
|
||||
|
||||
**Green light first and last: `./tools/bench/check.sh` was ALL GREEN before any
|
||||
of this and ALL GREEN after**, plus one new stage.
|
||||
|
||||
**ROADMAP P4a is DONE at the transport level. FINDINGS 59.** **Emulated** —
|
||||
MAME 0.277, `x68000 -exp1 cz6bs1 -ramsize 2M`. No real hardware ran.
|
||||
|
||||
**1. THE CHANNEL DRIVES THE DATA PHASE.** `src/player/dma.i` programs HD63450
|
||||
channel 1 and `src/player/dmagate.s` reads the same 2,048 B at LBA 1000 three
|
||||
ways, with the host comparing all three against its own copy of the image:
|
||||
|
||||
| | bytes | MTC one instruction after START | CPU trips round its wait loop |
|
||||
|---|---|---|---|
|
||||
| PIO, the path 58.2 measured | byte-exact | — | — |
|
||||
| **DMA, bus HELD** (DCR `$00`, OCR `$81`) | **byte-exact** | **0 of 2048** | **1** |
|
||||
| **DMA, cycle STEALING** (DCR `$80`, OCR `$80`) | **byte-exact** | 2048 of 2048 | 426 |
|
||||
|
||||
Both channels reported `CSR = $E0`, `CER = $00`, `MTC = 0`, `MAR` exactly
|
||||
`+2048`.
|
||||
|
||||
**2. THE EVIDENCE NEVER READS `$EA0015`, which is the whole design.** 57.3 said
|
||||
it could not: with the DMAC's OWN asserted, MAME cannot tell a CPU-driven byte
|
||||
at that address from a DMAC-driven one. So the discriminator is **the CPU's own
|
||||
progress** — MTC sampled by the instruction *after* the one that starts the
|
||||
channel. Held, the whole transfer happened between two instructions. **The gate
|
||||
was checked against its own negative**: with the stealing register pair in the
|
||||
held slot, every byte still arrives and `dma_run.sh` goes RED. A counter that
|
||||
cannot come out different is 58.3's vacuous "UNDERRUNS: 0/120" again.
|
||||
|
||||
**3. THREE THINGS THIS MODEL CANNOT BE ASKED**, read out of MAME's source: the
|
||||
card has **no request line to the DMAC** (its flow control is DTACK, so external
|
||||
request cannot be run); **single address** cannot be run either (only channel 0
|
||||
has device callbacks); and **only burst is modelled as held** (`(dcr & 0xc0) ==
|
||||
0`, so cycle-steal-with-hold shares the not-held path). Of the four rows of the
|
||||
`W` ladder, exactly one — dual address, held, 9 clk/B — has a code path here,
|
||||
and it is the one demonstrated. The slot pinout has `#EXREQ` at B36, so a real
|
||||
card plausibly drives it; that is ROADMAP B3, sharpened.
|
||||
|
||||
**4. AUTO-REQUEST IS CHARGED BY TIME, NOT BY BYTE — and this outlives the
|
||||
emulator.** Every `W` in this project presumes the device asks for each byte. An
|
||||
auto-requested channel spends its share of the bus whether or not a byte is
|
||||
there, so a record's cost scales with **how long it takes to arrive**: halve the
|
||||
rate and the CPU cost of the same record doubles. `tools/analysis/
|
||||
28_autorequest_cost.py` prices it from MC68450 §3.8/§5.2.3.3.2, gating its
|
||||
formulas against Table 5-3's sixteen rows first. At 37,405 B and **460 KB/s, an
|
||||
explicit rate**: max rate costs the whole **95.3% of a frame**; of the GCR's
|
||||
four bus shares only **BR = 00, 50%, carries the rate**, at 10.61 clk/B and
|
||||
47.6% of a frame. **The GCR is a design lever nothing in this tree had named.**
|
||||
|
||||
**5. THE WINDOW IS REFUSED, so the re-encode is now a precondition.** A channel
|
||||
writes a contiguous run and cannot drop the 300 B in front of a record, so
|
||||
`sc_in_data` refuses a windowed read when the data phase is the DMAC's
|
||||
(`SCE_WINDOW`) rather than writing the neighbours into the ring (49.2). 58.3's
|
||||
"sector-aligned records should join the bundle" has become "the transport will
|
||||
not run without them".
|
||||
|
||||
**ONE COLLISION, AND THE BEFORE-HALF OF `check.sh` CAUGHT IT.** `DM_USE` was
|
||||
first placed at `$18300`, which is `ring.i`'s `XF_SLOT` mailbox — `scsi.i`'s
|
||||
trace ends at `$182FF` and the next 160 bytes are the ring's. The ring rig's
|
||||
first record request therefore wrote a non-zero word into what the transport
|
||||
read as "use the DMAC", and **the P4b stage, which this session did not touch,
|
||||
went red**. The map is now `$18500`. Green-before is not a formality: it is what
|
||||
made a red in an untouched stage unambiguous. 59.6.
|
||||
|
||||
**New in the tree:** `src/player/dma.i`, `src/player/dmagate.s`,
|
||||
`tools/bench/dma.lua`, `tools/bench/dma_run.sh`,
|
||||
`tools/analysis/27_dmac_config.py` (decodes what the player programs, out of the
|
||||
player's own source), `tools/analysis/28_autorequest_cost.py`,
|
||||
`tools/analysis/mc68450.py` (the MC68450 field tables, now ONE copy, shared with
|
||||
`21_iplrom_dmac.py`), and one `check.sh` stage. `src/player/scsi.i` gained the
|
||||
`DM_USE` dispatch and `SCE_WINDOW`.
|
||||
|
||||
**No decoder code changed.** `decode.bin` is still 1,296 B at the same MD5.
|
||||
|
||||
**Next: THE RE-ENCODE BUNDLE, and it is now the only thing between this tree and
|
||||
M2.** Four items sharing one re-measurement (ROADMAP P2): index-0 black,
|
||||
`--spans all` as default, joint `lam`, and **sector-aligned records**, which
|
||||
59.4 promoted from preference to precondition. After it, P4a's channel goes
|
||||
behind `ring.i`'s mailbox and the 120-frame pixel-exact pass runs with the CPU
|
||||
free — which is the shape of M2.
|
||||
|
||||
---
|
||||
|
||||
# Status & next-session handoff — end of session 26 (2026-08-24)
|
||||
|
||||
## Session 26: the player runs off the disc, and PIO costs 87 clocks a byte
|
||||
|
||||
Reference in New Issue
Block a user