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:
@@ -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",
|
||||
help="per-frame output of tools/bench/c68k/run.sh")
|
||||
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()
|
||||
if not os.path.exists(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}")
|
||||
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"),
|
||||
(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"),
|
||||
(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
|
||||
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}")
|
||||
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"deadline at {FPS:g} fps.)")
|
||||
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
|
||||
stream was never the risk P6 called it -- ON THE BUS. What the same reading of
|
||||
the ROM found is that the DISK's per-byte cost has a worked example on this
|
||||
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.""")
|
||||
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
|
||||
{vid_bpf*87.28/FRAME_CLK*100:.0f}% for the PIO transport FINDINGS 58.2 measured. The unpriced audio stream
|
||||
was never the risk P6 called it -- ON THE BUS.""")
|
||||
|
||||
# --- 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