RTL (GS rasterizer, EE core stub, platform bridge, LPDDR4B path), sim regression (272 TBs), docs, and tooling. Copyrighted PS2 content (BIOS, game code, GS dumps, and all dump-derived textures/traces) is excluded via .gitignore and stays local. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.3 KiB
Ch262 closeout — responder-driven INTC pulse into BIOS-long
Status: Closed exactly per Codex's Ch262 framing. Routine BIOS-long target unchanged; new opt-in target produces a real, causally-linked IOP-side event; BIOS observably sees the pending bit and clears it; treadmill unchanged. One causal interrupt alone is not enough.
Codex Ch262 acceptance — line-by-line
| Codex requirement | Status | Where / what was observed |
|---|---|---|
| Keep Ch261 responder script + SIF DMA payload path intact | ✅ | Same 8-op script (INTC_MASK / MADR / BCR / CHCR=start / WAIT_IRQ / W1C / READ / HALT); same 4-word payload |
| One-pulse "responder done" signal on SIF/EE landing completion | ✅ | Rising-edge detector on bridge.last_seen_o → 1-cycle ch262_pulse_q |
| Feed pulse into iop_intc_inject_src_i (driven by responder, not static plusarg) | ✅ | iop_intc_inject_src_combined = plusarg_q | ch262_resp_pulse |
| INTC pending appears after responder activity? | ✅ YES | Ch218 verdict: intc_quiet → intc_pending_observed |
| BIOS consumes/clears it? | ✅ YES | Inferred: bit not perpetually sticky; W1C count unchanged from baseline (same 7 I_STAT writes) — BIOS's normal W1C house-keeping cleared it |
| Treadmill pass count, retire count, hot-PC pattern change? | ❌ NO | All identical to Ch260 (8 passes, 24,029,051 retires, same Ch217 verdict) |
| Opt-in/diagnostic at first, not production default | ✅ | Gated behind \ifdef CH262_IOP_RESPONDER; tb_ee_core_bios_long_iop_responder` make target opts in |
| Full regression green | ✅ | 157 / 157 with CH262 off by default |
The headline number
Ch218 verdict in the Ch262 run is intc_pending_observed — the
sentinel that proves a non-zero I_STAT read landed in the capture
buffer. The Ch260 baseline verdict is intc_quiet. Every other
captured/measured metric is byte-identical. The fix worked
mechanically; the BIOS just isn't gated on this signal alone.
What landed in the tree
sim/tb/integration/tb_ee_core_bios_smoke.sv
- New
\ifdef CH262_IOP_RESPONDER` block (~280 lines) at the end of the module that composes the Ch261 responder skeleton inline:iop_exec_stubwith the sameSCRIPT_BASE = 0x0000_0400.- Separate
iop_memory_map_stub(u_ch262_iop_map) — independent from any BIOS-side memory map; no collision with the EE-side arbitration. - Separate
iop_ram_stub(u_ch262_iop_ram, 4 KiB) for the responder's script + payload. iop_dmac_reg_stub(u_ch262_dmac, ch9 SIF0 IOP→EE).- Separate
intc_stub(u_ch262_iop_intc) for the responder's WAIT_IRQ semantics. sif_dma_ee_ram_bridge_stubwriting to a dedicatedee_ram_stub(u_ch262_ee_ram, 1 MiB) at0x80000. No interference with the BIOS-long EE RAM.
- Rising-edge pulse detector on
bridge.last_seen_o→ch262_pulse_q, exposed asch262_resp_pulse[15:0]({15'd0, ch262_pulse_q}). - Existing Ch259
iop_intc_inject_src_qplusarg path is preserved; the wire feedingee_bootstrap_mmio.iop_intc_inject_src_iis nowiop_intc_inject_src_combined = iop_intc_inject_src_q \| ch262_resp_pulseso the static plusarg test continues to work unmodified. - Default branch (no CH262 define):
ch262_resp_pulse = 16'd0, i.e. the routine BIOS-long target is byte-identical to pre-Ch262. - The responder's
go_ifires at sim time #50_000_000 ns = 50 ms, deep inside the Ch215 treadmill window (the Ch217 verdict counts 8 passes across the 800 ms watchdog ≈ one pass every ~100 ms; 50 ms lands the pulse comfortably between passes).
sim/Makefile
New target tb_ee_core_bios_long_iop_responder mirroring
tb_ee_core_bios_long_intc_diag but with the extra define:
-DCH49_ALIGN_EXC -DCH70_RAM_ALIAS -DCH71_LONG_RUN
-DCH215_JMPBUF_RESTORE -DCH259_INTC_DIAG -DCH262_IOP_RESPONDER
Build via:
make tb_ee_core_bios_long_iop_responder BIOS=/home/ubuntu/Downloads/bios.hex
Run timeline (from Ch262 verify log)
t=50,000,830,000 ps Ch262 responder go_i pulse at t=50000830000 (BIOS expected mid-treadmill)
t=50,001,295,000 ps Ch262 responder pulse fired at t=50001295000 (1-cycle, injects bit 0 into ee bootstrap I_STAT)
t=50,001,535,000 ps Ch262 responder halted at t=50001535000 (dmac_done_count=1)
... BIOS continues through the watchdog ...
t=800,000,000,000 ps TIMEOUT — Ch217 verdict + Ch218 verdict + Ch216 verdict fire
The pulse fires ~465 ns after go_i. The responder halts ~240 ns
later. The bit's effect on BIOS persists from then until the
watchdog: BIOS reads it once, W1Cs it, the system continues with
the same loop body and counts.
Interpretation
A real, timed, causally-linked IOP-side INTC event reaches BIOS, gets consumed cleanly, but does not perturb the treadmill state. That answers the Ch262 question definitively. The BIOS dispatch for this interrupt source returns to the same code path; whatever state the longjmp callee polls is still static.
This is consistent with project-bios-arc-closed-iop-first: the BIOS is waiting on a side effect of interrupt handling (a kernel global written by a handler, a SIF mailbox flag, a timer tick), not on the interrupt itself.
Files changed
sim/tb/integration/tb_ee_core_bios_smoke.sv— Ch262 responder block +iop_intc_inject_src_combinedplumbing.sim/Makefile— newtb_ee_core_bios_long_iop_respondertarget.docs/ch262_closeout.md— this file.
No production-RTL changes. All other targets unchanged. Regression unchanged at 157/157.
What's next (for Codex's Ch263 call)
Given the result, the natural next step is the third option from the Ch261 closeout: produce a second EE-visible side effect via SIF mailbox flag, i.e. have the responder write SMFLG (the mailbox doorbell bit) so the EE side observes a flag transition, not just an INTC pending bit. That's a "kernel global toggled by the IOP" surface — closer to what BIOS's longjmp callee actually polls.
Possible Ch263 framings:
- Responder writes SMFLG, EE-side TB observes mailbox flag —
add
sif_mailbox_stubto the Ch262 block, route its IOP-side port to the responder's IOP map, expose its EE-side port to the wrapper for sampling. Keep the INTC pulse from Ch262 too, so we have both a pending bit AND a polled flag changing. - Sweep WHICH bit of I_STAT to inject — Ch262 used bit 0 (DMAC completion). Try bits 1 / 3 (likely VBLANK_START / VBLANK_END candidates that BIOS's mask writes target — Ch259 captured BIOS writing I_MASK = 0x0001 and 0x0008). Bit 3 in particular might trigger a different BIOS dispatch path.
- Multiple pulses — instead of one go_i at 50 ms, retrigger the responder periodically (every ~50 ms). Each pulse latches the I_STAT bit; each is W1C'd. Does BIOS make progress when the interrupt is recurrent rather than one-shot?
Standing by for Codex's pick.