Price the transport against the frame, and find dual address cannot fit
FINDINGS 59.7. tools/analysis/15_bus_occupancy.py has always answered "what does each W cost" and never "what can the frame afford", and after 59.2 those are not the same question. It now answers both, and takes an optional --kbps for the auto-request rows -- the only rows whose cost depends on how long the record takes to arrive. On the gate container at 12 fps, decode term MEASURED: decode 68.5%, audio 1.25%, HEADROOM 30.2% = 6.74 clocks per byte at a 37,403 B record. Against that, P4a cut the transport from 391.7% of a frame to 40..95% -- four to ten times, the largest movement in this project's cost model since the decoder was written -- and it still does not fit. A dual-address byte is a 4-clock read of the device plus a 5-clock write to memory, so 9 clk/B is a FLOOR and the frame affords 6.74. No GCR share goes under it and no delivery rate goes under it: a share decides whether the channel sits at the floor or above it. At 460 KB/s max-rate totals 165.1% and LRAR at 50% totals 117.4%, and a 50% share tops out at 543 KB/s, above which the channel is the bottleneck and the rate falls back to exactly that floor. So 59.2's three bounds arrive in the budget as one sentence: the configurations this machine can run are the ones the frame cannot afford, and the one it can afford -- single address, 5 clk/B, 92.2% total, 7.8% spare -- needs the device to ACK the DMAC, which needs a request line MAME does not connect and the slot pinout does have at B36/B37. ROADMAP re-ranks accordingly. B3 stops being a constant to look up and becomes DOES THE CARD DRIVE #EXREQ, ahead of B1: B1 sets how much headroom the player has, B3 decides whether there is any. New E7 carries the other branch -- if the answer is no, the container must reach 27,995 B a frame, 328 KB/s of payload, against 438 now. The dependency diagram is redrawn around that fork. The scope is stated rather than buried: this is the GATE container, deliberately the heaviest thing the encoder emits, and the lighter cpufit family was NOT priced -- 15_bus_occupancy.py refuses it, correctly, because the C68K measurement it cross-checks against belongs to the gate container. E7 therefore begins with a harness re-run, and until then "34% too big" is a statement about the fixture and not about the project. check.sh ALL GREEN before and after. Claude-Session: https://claude.ai/code/session_01194oWYW8DQXK1SZ2DnChW6
This commit is contained in:
@@ -172,6 +172,23 @@ to land, and of the four bus shares the GCR can be programmed for — 50, 25,
|
|||||||
a frame. The GCR is a design lever nothing in this tree had named (FINDINGS
|
a frame. The GCR is a design lever nothing in this tree had named (FINDINGS
|
||||||
59.3).
|
59.3).
|
||||||
|
|
||||||
|
**And what it all costs: the frame affords 6.74 clocks a byte, and a
|
||||||
|
dual-address byte is 9.** Putting the transport on the channel cuts it from
|
||||||
|
**391.7% of a 12 fps frame to 40..95%** — four to ten times, the largest
|
||||||
|
movement in this project's cost model since the decoder was written — and **it
|
||||||
|
still does not fit.** After the measured decode (68.5%) and the audio DMA
|
||||||
|
(1.25%), 30.2% of the frame is left, which at this container's 37,403 B record
|
||||||
|
is 6.74 clocks a byte; a dual-address byte is a 4-clock read of the device plus
|
||||||
|
a 5-clock write to memory, so **9 is a floor no bus share and no delivery rate
|
||||||
|
goes under**. Single address is 5 and fits at 92.2% with room to spare — and it
|
||||||
|
needs the device to ACK the DMAC, which needs a request line MAME does not
|
||||||
|
connect and the slot pinout does have. So the project's live question is now a
|
||||||
|
fact about a board: **does a real CZ-6BS1 drive `#EXREQ`?** If it does, the
|
||||||
|
design fits. If it does not, the container has to come down from 438 KB/s of
|
||||||
|
payload to **328** — which is an encoder target, entirely inside this project,
|
||||||
|
and measured against the heaviest container the encoder emits rather than
|
||||||
|
against a shipping one (FINDINGS 59.7).
|
||||||
|
|
||||||
**A record is not a sector, and the cheapest fix is a re-encode.** 117 of 120
|
**A record is not a sector, and the cheapest fix is a re-encode.** 117 of 120
|
||||||
records start part way into a 512 B block, and reading whole blocks into the
|
records start part way into a 512 B block, and reading whole blocks into the
|
||||||
ring corrupts the neighbouring records rather than merely wasting bytes — the
|
ring corrupts the neighbouring records rather than merely wasting bytes — the
|
||||||
|
|||||||
@@ -5731,3 +5731,75 @@ 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
|
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
|
green after" earned their place; the map is now `$18500`, clear of everything
|
||||||
the streaming rig owns.
|
the streaming rig owns.
|
||||||
|
|
||||||
|
### 59.7 What it all costs: the frame affords 6.74 clocks a byte, and a dual-address byte is 9
|
||||||
|
|
||||||
|
The sweep in `15_bus_occupancy.py` has always answered *"what does each `W`
|
||||||
|
cost"*. It never answered *"what can the frame afford"*, and after 59.2 those
|
||||||
|
stopped being the same question. The tool now answers both; every figure below
|
||||||
|
is it, on the gate container at 12 fps, and the decode term is **measured**
|
||||||
|
(C68K) while the transport terms are datasheet arithmetic — except PIO, which
|
||||||
|
58.2 measured.
|
||||||
|
|
||||||
|
frame slot 833,333 clk
|
||||||
|
decoder, MEASURED 570,958 clk 68.5% (worst frame 110.8%)
|
||||||
|
audio DMA 10,417 clk 1.25%
|
||||||
|
------------------------------------------
|
||||||
|
HEADROOM 251,958 clk 30.2% = 6.74 clk/B at a 37,403 B record
|
||||||
|
|
||||||
|
| transport | clk/B | video | CPU+audio+video |
|
||||||
|
|---|---|---|---|
|
||||||
|
| PIO — **measured**, 58.2 | 87.28 | 391.7% | **461.5%** |
|
||||||
|
| dual address, arbitrated — the IPL ROM's own (52.5) | 16..19 | 71.8..85.3% | 141.6..155.0% |
|
||||||
|
| single address, arbitrated | 12 | 53.9% | 123.6% |
|
||||||
|
| **dual address, held — and the FLOOR of every dual-address configuration** | **9** | 40.4% | **110.2%** |
|
||||||
|
| single address, held | 5 | 22.4% | **92.2%** |
|
||||||
|
|
||||||
|
**WHAT P4a BOUGHT: the transport falls from 391.7% of a frame to 40..95%**, four
|
||||||
|
to ten times. That is the whole of the gain and it is the largest single
|
||||||
|
movement in the project's cost model since the decoder was written.
|
||||||
|
|
||||||
|
**WHAT IT DID NOT BUY IS A FIT, and the reason is one line of arithmetic.** A
|
||||||
|
dual-address byte is a 4-clock read of the device and a 5-clock write to memory
|
||||||
|
— `buscost.DMA_DUAL_BYTE_CLK`, Fig 4-25 — so **9 clocks is a floor, and the
|
||||||
|
frame affords 6.74.** No GCR share goes under it and no delivery rate goes under
|
||||||
|
it: a share decides whether the channel sits *at* the floor or *above* it. So
|
||||||
|
**59.2's three bounds arrive in the budget as one sentence — the configurations
|
||||||
|
this machine can run are exactly the ones the frame cannot afford**, and the one
|
||||||
|
it can afford is single address, which needs the device to ACK, which needs the
|
||||||
|
request line ROADMAP B3 asks about.
|
||||||
|
|
||||||
|
**The rate sweep says the same thing from the other side.** At 460 KB/s
|
||||||
|
max-rate totals **165.1%** and LRAR at 50% totals **117.4%**; the smaller shares
|
||||||
|
total less but cannot carry the rate at all. A faster disc makes auto-request
|
||||||
|
cheaper — which no `W` does, and it is the first cost in this project that
|
||||||
|
improves when the medium does — but it cannot reach the floor: **a 50% share
|
||||||
|
tops out at 543 KB/s**, above which the channel is the bottleneck and the
|
||||||
|
delivered rate falls back to it, at which point the cost is exactly 9 clk/B
|
||||||
|
again.
|
||||||
|
|
||||||
|
**SO THE FIT NOW TURNS ON ONE OF TWO THINGS, AND ONE OF THEM IS OURS.**
|
||||||
|
|
||||||
|
1. **Does a real CZ-6BS1 drive `#EXREQ`/`#EXACK`?** It is the only route to
|
||||||
|
single address, 22.4%, 92.2% total, fitting with 7.8% to spare. MAME cannot
|
||||||
|
answer it — it does not connect the pin (59.2) — and the slot pinout has it
|
||||||
|
at B36/B37. **This is now the sharpest form ROADMAP B3 has ever had**, and it
|
||||||
|
is worth more than the throughput half of B1: B1 sets how much headroom the
|
||||||
|
player has, B3 decides whether there is any.
|
||||||
|
2. **Bytes.** At the 9 clk/B floor this container must come down to **27,995 B a
|
||||||
|
frame — 328 KB/s of payload**, against the 37,403 B and 438 KB/s it is now:
|
||||||
|
**34% too big.** That is an encoder target, it is entirely inside this
|
||||||
|
project, and **it is the pessimistic reading of the lever**, because a
|
||||||
|
lighter container also decodes cheaper and the decode term falls with the
|
||||||
|
byte term.
|
||||||
|
|
||||||
|
**WHAT THIS IS NOT.** It is the **gate container**, which is deliberately the
|
||||||
|
heaviest thing the encoder emits — the span-heavy scsi container encoded to the
|
||||||
|
488 recipe, chosen so that every block mode and the newest span path are
|
||||||
|
exercised (check.sh's own note). The lighter `cpufit` family exists and was NOT
|
||||||
|
measured here: `15_bus_occupancy.py` refuses it, correctly, because the C68K
|
||||||
|
measurement in `tmp/c68k_frames.csv` belongs to the gate container and the
|
||||||
|
cross-check at the top of the tool is what licenses every number under it.
|
||||||
|
**Re-deriving 59.7 against a lighter container needs that harness re-run first**,
|
||||||
|
and until it is, "34% too big" is a statement about the heaviest container and
|
||||||
|
not about the project.
|
||||||
|
|||||||
+70
-13
@@ -11,7 +11,9 @@ Amended end of session 26: P4b done, P4a is the last open item before M2
|
|||||||
Amended end of session 27: P4a done at the transport level; THE RE-ENCODE
|
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
|
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
|
made sector-aligned records a precondition the transport enforces rather than a
|
||||||
preference (FINDINGS 59).
|
preference (FINDINGS 59). **And 59.7 re-ranks what is left: the frame affords
|
||||||
|
6.74 clocks a byte, a dual-address byte costs 9, so B3 stopped being a constant
|
||||||
|
to look up and became the question of whether the design fits at all.**
|
||||||
|
|
||||||
**THE COMPLETION TARGET IS M3, THE VERTICAL SLICE** (USER DECISION): one scene
|
**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
|
tree — a decision point, two outcomes, a death clip — with audio, streaming from
|
||||||
@@ -39,6 +41,7 @@ these units:
|
|||||||
| **Delivery rate** | **no working figure, deliberately** (FINDINGS 50, USER DECISION). Every tool REQUIRES an explicit rate. |
|
| **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. |
|
| **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.** 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). |
|
| **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). |
|
||||||
|
| **The frame's headroom for a transport** | **6.74 clk/B** — 30.2% of a 12 fps frame, after the MEASURED decode (68.5%) and best-case audio (1.25%), at the gate container's 37,403 B record. **New in session 27, 59.7, and it is the number every row above is now read against.** A dual-address byte's floor is 9. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -80,12 +83,34 @@ and settles it in minutes on a real board. FINDINGS 48 shifted the prior toward
|
|||||||
MAME and toward "unusable" — **do not pre-build on 1.0 B/pixel**. Same sitting:
|
MAME and toward "unusable" — **do not pre-build on 1.0 B/pixel**. Same sitting:
|
||||||
the priority register `0xE82500` at `0x0000` (47.3).
|
the priority register `0xE82500` at `0x0000` (47.3).
|
||||||
|
|
||||||
**B3. Single-address vs dual-address DMA.** 242 KB/s and 0.69 dB. Needs
|
**B3. Single-address vs dual-address DMA — and now, first, DOES THE CARD DRIVE
|
||||||
`scsiexrom.bin` (8 KB, CRC `7be488de`) sourced, then its DMAC init disassembled
|
`#EXREQ`?** 242 KB/s and 0.69 dB was the old framing. **Session 27 promoted this
|
||||||
for DCR's DTYP: `10`/`11` = single (5.0 clk/B), `00`/`01` = dual (9.0).
|
to the item that decides whether the design fits at all (59.7).** The frame
|
||||||
|
affords **6.74 clocks a byte**; a dual-address byte is **9** — a 4-clock read of
|
||||||
|
the device plus a 5-clock write to memory — so **no dual-address configuration
|
||||||
|
fits this container at 12 fps, at any delivery rate and any GCR share.** Single
|
||||||
|
address is 5 clk/B and fits at 92.2% of the frame with 7.8% to spare, and it
|
||||||
|
needs the device to ACK the DMAC directly, which needs the request line.
|
||||||
|
|
||||||
|
**MAME cannot answer it**: `x68k_scsiext.cpp`'s `drq_w` only stores a flag and
|
||||||
|
the expansion slot has no request path to the HD63450 at all (59.2). The slot
|
||||||
|
PINOUT has `#EXREQ` at B36 and `#EXACK` at B37, so the provision exists on the
|
||||||
|
real board. **What is wanted from hardware is therefore narrower and sharper
|
||||||
|
than "disassemble the ROM": does a CZ-6BS1 assert `#EXREQ` during a data phase,
|
||||||
|
and will the HD63450 run a single-address channel against it?** A scope or a
|
||||||
|
logic analyser answers the first; the second is a program the player can run.
|
||||||
|
|
||||||
|
Sourcing `scsiexrom.bin` (8 KB, CRC `7be488de`) and disassembling its DMAC init
|
||||||
|
is still the cheapest paper route to the same answer, because whatever Sharp's
|
||||||
|
own driver programs into DCR's DTYP is a statement about what the card supports.
|
||||||
FINDINGS 48.4. Not on this machine (checked, session 18).
|
FINDINGS 48.4. Not on this machine (checked, session 18).
|
||||||
**This is also P4's input** — the handshake the player drives is the same
|
|
||||||
question from the software side.
|
**Ranking, stated because B1 used to outrank this:** B1 (throughput and seek)
|
||||||
|
sets how much headroom the finished player has. **B3 decides whether there is
|
||||||
|
any.** If the card drives `#EXREQ`, the ladder applies and the design fits with
|
||||||
|
room. If it does not, the fallback is limited-rate auto-request at a share the
|
||||||
|
player picks (P4c), and the container has to come down to **328 KB/s of payload**
|
||||||
|
to fit at the 9 clk/B floor — 34% below where the gate container sits (59.7).
|
||||||
|
|
||||||
> **Session 20 moved the prior hard, and it moved the wrong way (FINDINGS 52.5).**
|
> **Session 20 moved the prior hard, and it moved the wrong way (FINDINGS 52.5).**
|
||||||
> The IPL ROM *is* on this machine, and `tools/analysis/21_iplrom_dmac.py` reads
|
> The IPL ROM *is* on this machine, and `tools/analysis/21_iplrom_dmac.py` reads
|
||||||
@@ -382,6 +407,30 @@ interaction to price next, and it is E2's question with a second consumer in it.
|
|||||||
**E6. Container v2** — audio interleave, per-record index, scene table. Depends
|
**E6. Container v2** — audio interleave, per-record index, scene table. Depends
|
||||||
on P6's answer and on P5's index.
|
on P6's answer and on P5's index.
|
||||||
|
|
||||||
|
**E7. A BYTE TARGET, AND IT COMES OUT OF THE BUS BUDGET RATHER THAN OUT OF
|
||||||
|
TASTE (new, session 27, FINDINGS 59.7).** The frame affords **6.74 clocks a
|
||||||
|
byte** after the measured decode and the audio, and a dual-address byte costs
|
||||||
|
**9**. So *if* B3 comes back saying the card cannot drive `#EXREQ`, the container
|
||||||
|
has to reach **27,995 B a frame — 328 KB/s of payload** to fit at 12 fps, where
|
||||||
|
the gate container sits at 37,403 B and 438 KB/s: **34% too big.**
|
||||||
|
|
||||||
|
Three things make this less alarming than the number looks, and one makes it
|
||||||
|
worse:
|
||||||
|
|
||||||
|
- The gate container is **deliberately the heaviest thing the encoder emits**
|
||||||
|
(span-heavy, the 488 recipe, every block mode exercised). It is a test
|
||||||
|
fixture, not a shipping target.
|
||||||
|
- A lighter container **also decodes cheaper**, so the 68.5% decode term falls
|
||||||
|
with the byte term. 328 KB/s is the pessimistic reading of the lever.
|
||||||
|
- `rc_fr_singe_scsi_cpufit.dlx` already exists — the encoder has had a
|
||||||
|
CPU-fitting mode since session 11.
|
||||||
|
- **Worse:** `15_bus_occupancy.py` REFUSES to price the cpufit container,
|
||||||
|
correctly, because the C68K measurement it cross-checks against belongs to
|
||||||
|
the gate container. **So E7 starts with a harness re-run**
|
||||||
|
(`tools/bench/c68k/run.sh`) against whichever container is to be the target,
|
||||||
|
and until that is done "34% too big" is a statement about the fixture rather
|
||||||
|
than about the project.
|
||||||
|
|
||||||
~~**G1. Import the scene graph — early, because it is a measurement input.**~~
|
~~**G1. Import the scene graph — early, because it is a measurement input.**~~
|
||||||
**DONE, session 24 — FINDINGS 56.** It was pulled ahead for exactly the reason
|
**DONE, session 24 — FINDINGS 56.** It was pulled ahead for exactly the reason
|
||||||
given, and it paid: **the worst gap between two consecutive decision points is
|
given, and it paid: **the worst gap between two consecutive decision points is
|
||||||
@@ -435,16 +484,24 @@ Listed for completeness; past M3 these are scope, not risk.
|
|||||||
## Dependency summary
|
## Dependency summary
|
||||||
|
|
||||||
```
|
```
|
||||||
B1 seek+rate ─┐
|
P4a DONE (59): the channel drives the data phase and
|
||||||
B3 DTYP ──────┴─> P4a DMA HOLDS THE BUS ──┐ (P4b DONE, 58: the ring is
|
holds the bus -- 391.7% of a frame becomes 40..95%
|
||||||
│ filled off a real volume, and
|
│
|
||||||
P1 P2(half) P3 P4b P5 P7 ─────────────────┤ PIO costs 87 clk/B)
|
B3 #EXREQ? ──┬─ YES ─> single address, 5 clk/B, 92.2% ── FITS ──┐
|
||||||
├─> M2 ─> M3 (TARGET) ─> M4
|
│ │
|
||||||
P6 (bus cost DONE, 52) ───────────────────┤
|
└─ NO ──> auto-request, 9 clk/B FLOOR, 110.2% ──> E7 byte target
|
||||||
G1 scene graph (DONE, 56) ────────────────┘
|
(the frame affords 6.74; 59.7) 328 KB/s
|
||||||
|
│
|
||||||
|
P2 re-encode bundle (sector alignment is now a PRECONDITION, 59.4) ┤
|
||||||
|
P1 P3 P4b P5 P7, P6 bus cost (52), G1 scene graph (56) ────────────┼─> M2 ─>
|
||||||
|
B1 seek+rate (sets HEADROOM, not fit) ─────────────────────────────┘ M3 ─> M4
|
||||||
B2 blanking ─> (page 1; do not pre-build on it)
|
B2 blanking ─> (page 1; do not pre-build on it)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Read that top-left branch as the project's live question.** Everything else
|
||||||
|
on the diagram is work; `#EXREQ` is a fact about a board nobody here has, and it
|
||||||
|
decides which of the two lower paths the player is on.
|
||||||
|
|
||||||
## Standing rules that apply to all of it
|
## Standing rules that apply to all of it
|
||||||
|
|
||||||
- **Green light first and last.** `./tools/bench/check.sh`, ALL GREEN, before and
|
- **Green light first and last.** `./tools/bench/check.sh`, ALL GREEN, before and
|
||||||
|
|||||||
@@ -57,6 +57,33 @@ writes a contiguous run and cannot drop the 300 B in front of a record, so
|
|||||||
"sector-aligned records should join the bundle" has become "the transport will
|
"sector-aligned records should join the bundle" has become "the transport will
|
||||||
not run without them".
|
not run without them".
|
||||||
|
|
||||||
|
**6. WHAT IT ALL COSTS, and this is the part that re-ranks the roadmap.**
|
||||||
|
`15_bus_occupancy.py` now answers "what can the frame afford" as well as "what
|
||||||
|
does each `W` cost". On the gate container at 12 fps, with the decode term
|
||||||
|
MEASURED: decode 68.5%, audio 1.25%, **headroom 30.2% = 6.74 clocks per byte**
|
||||||
|
at a 37,403 B record.
|
||||||
|
|
||||||
|
| transport | clk/B | video | total |
|
||||||
|
|---|---|---|---|
|
||||||
|
| PIO, measured (58.2) | 87.28 | 391.7% | **461.5%** |
|
||||||
|
| dual address, held — **the floor** | 9 | 40.4% | **110.2%** |
|
||||||
|
| single address, held | 5 | 22.4% | **92.2%** |
|
||||||
|
|
||||||
|
**P4a cut the transport from 391.7% to 40..95%, four to ten times — and it still
|
||||||
|
does not fit.** A dual-address byte is 4 clocks of device read plus 5 of memory
|
||||||
|
write, so **9 is a floor and the frame affords 6.74**; no GCR share and no
|
||||||
|
delivery rate goes under it. At 460 KB/s max-rate totals 165.1% and LRAR at 50%
|
||||||
|
totals 117.4%. So the fit turns on **B3, which has stopped being a constant to
|
||||||
|
look up: does a real CZ-6BS1 drive `#EXREQ`?** If yes, single address fits at
|
||||||
|
92.2% with 7.8% spare. If no, the container must reach **328 KB/s of payload**
|
||||||
|
(new ROADMAP E7), against 438 now.
|
||||||
|
|
||||||
|
**The scope matters and is stated in 59.7:** this is the GATE container, the
|
||||||
|
heaviest thing the encoder emits. The lighter `cpufit` family was NOT priced —
|
||||||
|
the tool refuses it, correctly, because the C68K measurement belongs to the gate
|
||||||
|
container — so E7 begins with a harness re-run, and until then "34% too big" is
|
||||||
|
about the fixture, not about the project.
|
||||||
|
|
||||||
**ONE COLLISION, AND THE BEFORE-HALF OF `check.sh` CAUGHT IT.** `DM_USE` was
|
**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
|
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
|
trace ends at `$182FF` and the next 160 bytes are the ring's. The ring rig's
|
||||||
|
|||||||
@@ -62,6 +62,11 @@ ap.add_argument("container", nargs="?", default="tmp/rc_fr_singe_scsi_cpufit.dlx
|
|||||||
ap.add_argument("--csv", default="tmp/c68k_frames.csv",
|
ap.add_argument("--csv", default="tmp/c68k_frames.csv",
|
||||||
help="per-frame output of tools/bench/c68k/run.sh")
|
help="per-frame output of tools/bench/c68k/run.sh")
|
||||||
ap.add_argument("--nframes", type=int, default=None)
|
ap.add_argument("--nframes", type=int, default=None)
|
||||||
|
ap.add_argument("--kbps", type=float, default=None,
|
||||||
|
help="delivery rate in KB/s. OPTIONAL and there is no default "
|
||||||
|
"(FINDINGS 50): supply it and the AUTO-REQUEST rows are "
|
||||||
|
"added, which are the only rows whose cost depends on how "
|
||||||
|
"long the record takes to arrive (59.3).")
|
||||||
a = ap.parse_args()
|
a = ap.parse_args()
|
||||||
if not os.path.exists(a.container):
|
if not os.path.exists(a.container):
|
||||||
sys.exit(f"missing {a.container}")
|
sys.exit(f"missing {a.container}")
|
||||||
@@ -186,19 +191,102 @@ print(f" {'W (clk/byte)':<16}{'clk/frame':>12}{'% of frame':>12} "
|
|||||||
f"{'CPU+audio+video':>18}")
|
f"{'CPU+audio+video':>18}")
|
||||||
for W, note in ((5.0, "single address, bus held (11_cpu_budget.py default)"),
|
for W, note in ((5.0, "single address, bus held (11_cpu_budget.py default)"),
|
||||||
(8.0, "FINDINGS 5's long-standing per-word ESTIMATE"),
|
(8.0, "FINDINGS 5's long-standing per-word ESTIMATE"),
|
||||||
|
(9.0, "DUAL address, bus held -- and the FLOOR of every "
|
||||||
|
"dual-address\n "
|
||||||
|
" configuration, auto-request included (59.3)"),
|
||||||
(12.0, "single address, arbitrated per byte"),
|
(12.0, "single address, arbitrated per byte"),
|
||||||
(16.0, "what the ROM programs for SASI (best case)"),
|
(16.0, "what the ROM programs for SASI (best case)"),
|
||||||
(19.0, "what the ROM programs for SASI (worst case)")):
|
(19.0, "what the ROM programs for SASI (worst case)"),
|
||||||
|
(87.28, "PIO -- MEASURED, FINDINGS 58.2, the CPU doing it itself")):
|
||||||
v = vid_bpf * W
|
v = vid_bpf * W
|
||||||
tot_clk = (cpu_clk if cyc_t.any() else 0) + a_lo + v
|
tot_clk = (cpu_clk if cyc_t.any() else 0) + a_lo + v
|
||||||
print(f" {W:<16.0f}{v:>12,.0f}{100*v/FRAME_CLK:>11.1f}% "
|
print(f" {W:<16.6g}{v:>12,.0f}{100*v/FRAME_CLK:>11.1f}% "
|
||||||
f"{100*tot_clk/FRAME_CLK:>17.1f}% {note}")
|
f"{100*tot_clk/FRAME_CLK:>17.1f}% {note}")
|
||||||
print(f"\n (the last column adds the MEASURED mean decode and the BEST-CASE "
|
print(f"\n (the last column adds the MEASURED mean decode and the BEST-CASE "
|
||||||
f"audio, so it is\n the optimistic end of every row. 100% is the frame "
|
f"audio, so it is\n the optimistic end of every row. 100% is the frame "
|
||||||
f"deadline at {FPS:g} fps.)")
|
f"deadline at {FPS:g} fps.)")
|
||||||
print(f"""
|
print(f"""
|
||||||
Audio is {100*a_lo/FRAME_CLK:.2f}%..{100*a_hi/FRAME_CLK:.2f}% of the frame and video is {vid_bpf*5/FRAME_CLK*100:.0f}%..{vid_bpf*19/FRAME_CLK*100:.0f}%. The unpriced audio
|
Audio is {100*a_lo/FRAME_CLK:.2f}%..{100*a_hi/FRAME_CLK:.2f}% of the frame and video is {vid_bpf*5/FRAME_CLK*100:.0f}%..{vid_bpf*19/FRAME_CLK*100:.0f}% over the ladder, against
|
||||||
stream was never the risk P6 called it -- ON THE BUS. What the same reading of
|
{vid_bpf*87.28/FRAME_CLK*100:.0f}% for the PIO transport FINDINGS 58.2 measured. The unpriced audio stream
|
||||||
the ROM found is that the DISK's per-byte cost has a worked example on this
|
was never the risk P6 called it -- ON THE BUS.""")
|
||||||
machine, it is 16..19 clocks, and at that price this design does not fit at any
|
|
||||||
container size. W is the number to attack, and it is a PLAYER decision.""")
|
# --- HEADROOM, AND THE FLOOR UNDER THE LADDER -----------------------------
|
||||||
|
# Added session 27. The sweep above answers "what does each W cost"; it never
|
||||||
|
# answered "what can this frame afford", and the two are not the same question.
|
||||||
|
# FINDINGS 59.2 is why it matters now: with no external request line the only
|
||||||
|
# configurations that can be run are dual-address, and a dual-address byte has
|
||||||
|
# a FLOOR -- one 4-clock read of the device plus one 5-clock write to memory,
|
||||||
|
# buscost.DMA_DUAL_BYTE_CLK. No GCR share and no delivery rate goes under it.
|
||||||
|
print("\n" + "=" * 72)
|
||||||
|
print("WHAT THE FRAME CAN AFFORD, AND THE FLOOR UNDER THE LADDER\n")
|
||||||
|
head_clk = FRAME_CLK - (cpu_clk if cyc_t.any() else 0) - a_lo
|
||||||
|
head_wb = head_clk / vid_bpf
|
||||||
|
print(f" headroom after the MEASURED decode and best-case audio: "
|
||||||
|
f"{head_clk:,.0f} clk = {100*head_clk/FRAME_CLK:.1f}%")
|
||||||
|
print(f" at {vid_bpf:,.0f} B a frame that is {head_wb:.2f} CLOCKS PER BYTE, and "
|
||||||
|
f"that is the number\n a transport has to come in under.\n")
|
||||||
|
floor = B.DMA_DUAL_BYTE_CLK
|
||||||
|
print(f" dual-address floor {floor} clk/B ({B.DMA_READ_CLK} read of the "
|
||||||
|
f"device + {B.DMA_WRITE_CLK} write to memory, Fig 4-25)")
|
||||||
|
print(f" single-address held {B.DMA_DISK_CLK_WORD_HELD} clk/B (one memory "
|
||||||
|
f"write; needs the device to ACK, i.e. a REQUEST LINE)")
|
||||||
|
if head_wb < floor:
|
||||||
|
print(f"""
|
||||||
|
SO DUAL ADDRESS DOES NOT FIT THIS CONTAINER AT {FPS:g} fps -- not at any
|
||||||
|
delivery rate and not at any GCR share, because {head_wb:.2f} < {floor}. A share
|
||||||
|
decides whether the channel sits AT the floor or above it; it cannot
|
||||||
|
go under it. That is FINDINGS 59.2's three bounds arriving in the
|
||||||
|
budget: the configurations this machine can run are exactly the ones
|
||||||
|
the frame cannot afford, and the one it can afford -- single address,
|
||||||
|
{B.DMA_DISK_CLK_WORD_HELD} clk/B, {100*vid_bpf*B.DMA_DISK_CLK_WORD_HELD/FRAME_CLK:.1f}% -- needs the request line ROADMAP B3 asks about.""")
|
||||||
|
for w, what in ((floor, "dual address"), (B.DMA_DISK_CLK_WORD_HELD, "single address")):
|
||||||
|
tgt = head_clk / w
|
||||||
|
print(f"\n TO FIT AT {w} clk/B ({what}) THIS CONTAINER MUST COME DOWN TO")
|
||||||
|
print(f" {tgt:,.0f} B a frame = {tgt*FPS/1024:,.0f} KB/s of payload "
|
||||||
|
f"(it is {vid_bpf:,.0f} B, {vid_bpf*FPS/1024:,.0f} KB/s)"
|
||||||
|
+ (" -- already met" if vid_bpf <= tgt else
|
||||||
|
f" -- {100*(vid_bpf/tgt-1):.0f}% too big"))
|
||||||
|
print(f"""
|
||||||
|
AND THAT IS THE PESSIMISTIC READING OF THE ENCODER LEVER: a lighter
|
||||||
|
container also DECODES cheaper, so the decode term above falls with
|
||||||
|
the byte term. The figure to re-derive it against is this tool run on
|
||||||
|
the lighter container -- with its OWN C68K measurement, because the
|
||||||
|
cross-check at the top is what licenses every number below it.""")
|
||||||
|
else:
|
||||||
|
print(f"\n The frame affords {head_wb:.2f} clk/B, which is at or above the "
|
||||||
|
f"{floor} clk/B dual-address floor.")
|
||||||
|
|
||||||
|
# --- AUTO-REQUEST, and only when a rate is supplied ------------------------
|
||||||
|
# These are the rows 59.3 added and they are the only ones here whose cost is
|
||||||
|
# not a property of the transfer: an auto-requested channel spends its share of
|
||||||
|
# the bus whether or not a byte is there, so what a record costs depends on how
|
||||||
|
# long it takes to ARRIVE. No default rate, deliberately (FINDINGS 50).
|
||||||
|
if a.kbps:
|
||||||
|
RATE = a.kbps * 1024.0
|
||||||
|
wire_clk = vid_bpf / RATE * CPUHZ
|
||||||
|
cap = 0.5 * CPUHZ / B.DMA_DUAL_BYTE_CLK # the 50% share's ceiling
|
||||||
|
print("\n" + "=" * 72)
|
||||||
|
print(f"AUTO-REQUEST AT {a.kbps:g} KB/s -- charged by TIME, not by byte "
|
||||||
|
f"(59.3)\n")
|
||||||
|
print(f" the record takes {wire_clk:,.0f} clk to arrive = "
|
||||||
|
f"{100*wire_clk/FRAME_CLK:.1f}% of a frame\n")
|
||||||
|
print(f" {'configuration':<34}{'clk/B':>8}{'% of frame':>12}"
|
||||||
|
f"{'CPU+audio+video':>18}")
|
||||||
|
rows = [("REQG 01, max rate (100% of the bus)", 1.0, None)]
|
||||||
|
for br, share in ((0, .5), (1, .25), (2, .125), (3, .0625)):
|
||||||
|
rows.append((f"REQG 00, LRAR BR={br:02b}, {share*100:g}% share", share,
|
||||||
|
share * CPUHZ / B.DMA_DUAL_BYTE_CLK))
|
||||||
|
for name, share, sustains in rows:
|
||||||
|
v = share * wire_clk
|
||||||
|
tot = (cpu_clk if cyc_t.any() else 0) + a_lo + v
|
||||||
|
flag = ""
|
||||||
|
if sustains is not None and sustains < RATE:
|
||||||
|
flag = f" cannot carry the rate ({sustains/1024:.0f} KB/s max)"
|
||||||
|
print(f" {name:<34}{v/vid_bpf:>8.2f}{100*v/FRAME_CLK:>11.1f}%"
|
||||||
|
f"{100*tot/FRAME_CLK:>17.1f}%{flag}")
|
||||||
|
print(f"""
|
||||||
|
A FASTER DISC MAKES AUTO-REQUEST CHEAPER, which no W does -- the share is
|
||||||
|
spent over a shorter wire time. But it cannot reach the floor: a 50% share
|
||||||
|
tops out at {cap/1024:,.0f} KB/s, above which the CHANNEL is the bottleneck and the
|
||||||
|
delivered rate falls back to it. At that ceiling the cost is exactly the
|
||||||
|
{B.DMA_DUAL_BYTE_CLK} clk/B floor, which is where the section above already put it.""")
|
||||||
|
|||||||
Reference in New Issue
Block a user