ec82764bef
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>
144 lines
7.3 KiB
Markdown
144 lines
7.3 KiB
Markdown
# 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_stub` with the same `SCRIPT_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_stub` writing to a dedicated
|
|
`ee_ram_stub` (`u_ch262_ee_ram`, 1 MiB) at `0x80000`. **No
|
|
interference with the BIOS-long EE RAM.**
|
|
- Rising-edge pulse detector on `bridge.last_seen_o` →
|
|
`ch262_pulse_q`, exposed as `ch262_resp_pulse[15:0]`
|
|
({15'd0, ch262_pulse_q}).
|
|
- Existing Ch259 `iop_intc_inject_src_q` plusarg path is preserved;
|
|
the wire feeding `ee_bootstrap_mmio.iop_intc_inject_src_i` is now
|
|
`iop_intc_inject_src_combined = iop_intc_inject_src_q \|
|
|
ch262_resp_pulse` so 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_i` fires 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_combined` plumbing.
|
|
- `sim/Makefile` — new `tb_ee_core_bios_long_iop_responder` target.
|
|
- `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:
|
|
|
|
1. **Responder writes SMFLG, EE-side TB observes mailbox flag** —
|
|
add `sif_mailbox_stub` to 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.
|
|
2. **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.
|
|
3. **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.
|