Initial commit: retroDE_ps2 — first-of-its-kind PS2 GS FPGA core (DE25-Nano / Agilex 5)
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>
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
# Ch261 closeout — synthetic IOP responder skeleton + arbitration fix
|
||||
|
||||
**Status:** Closed. All Codex Ch261 acceptance criteria met. Regression
|
||||
green at **157 / 157** (was 155 pre-Ch261, +1 for the collision TB,
|
||||
+1 for the SIF-landing TB).
|
||||
|
||||
## Codex Ch261 acceptance — line-by-line
|
||||
|
||||
| Codex requirement | Status | Where |
|
||||
|--------------------------------------------------------------|--------|------------------------------------------------|
|
||||
| Focused collision check: CPU + DMA different addresses same cycle; DMA gets its word first, CPU later gets its own word | ✅ | `sim/tb/iop/tb_iop_memory_map_collision.sv` |
|
||||
| Ch261 SIF landing TB passes with intended payload | ✅ | `sim/tb/integration/tb_iop_responder_ee_ram_landing.sv` |
|
||||
| Full regression green | ✅ | `make run` → 157 PASS |
|
||||
| Noisy per-beat diagnostics stripped after collision test exists | ✅ | `tb_iop_responder_ee_ram_landing.sv` (removed `[diag-beat]`, `[diag] iop_ram`, `[diag] DMAC regs`) |
|
||||
|
||||
## What landed
|
||||
|
||||
### RTL fix — `rtl/iop/iop_memory_map_stub.sv`
|
||||
|
||||
Replaced the silent-corruption arbitration with a **one-entry
|
||||
deferred-CPU-RAM-read slot** exactly per Codex's spec:
|
||||
|
||||
- **DMA wins** the RAM port on any CPU+DMA collision (immediate).
|
||||
- **CPU's read address latches** into `cpu_pend_addr` / `cpu_pend_valid`.
|
||||
- On the next non-DMA cycle, the deferred read services from the
|
||||
pending slot.
|
||||
- `iop_rd_valid` stays LOW for the deferred CPU read until the
|
||||
slot actually fires; then pulses normally — CPU sees its own
|
||||
data on the right cycle, just one cycle later than it would
|
||||
without contention.
|
||||
- **Single-entry safe** because every existing CPU client of the
|
||||
map (`iop_exec_stub`, `iop_core_stub`, `iop_fetch_stub`) is
|
||||
request-then-wait-for-valid; no second outstanding read can be
|
||||
in flight from the same client.
|
||||
- **Sim-only overflow detector** (`$error` under
|
||||
``ifndef SYNTHESIS``) catches any future client that breaks the
|
||||
single-outstanding-read assumption.
|
||||
- The pre-Ch261 comment that called the collision "documented, not
|
||||
guarded" was removed.
|
||||
|
||||
### New focused TB — `sim/tb/iop/tb_iop_memory_map_collision.sv`
|
||||
|
||||
Directly drives the map's CPU- and DMA-read ports (no exec stub, no
|
||||
DMAC core), so no future change to clients can mask this regression.
|
||||
Three scenarios:
|
||||
|
||||
1. **Collision** — both reads on the same cycle, different addresses.
|
||||
Asserts DMA gets `DMA_SENTINEL` next cycle, CPU gets `CPU_SENTINEL`
|
||||
the cycle after, `iop_rd_valid` stays low during the deferral.
|
||||
2. **Solo CPU read** — no DMA contention. CPU sentinel arrives next
|
||||
cycle, no deferral.
|
||||
3. **Solo DMA read** — no CPU contention. DMA sentinel arrives next
|
||||
cycle, no spurious CPU activity.
|
||||
|
||||
### Ch261 SIF landing TB — `sim/tb/integration/tb_iop_responder_ee_ram_landing.sv`
|
||||
|
||||
Restored to its natural shape — full `WRITE INTC_MASK / MADR / BCR /
|
||||
CHCR=start / WAIT_IRQ / W1C INTC_STAT / READ DONE_COUNT / HALT`
|
||||
script. The arbitration fix makes the previously-fatal CPU/DMA
|
||||
collision (exec stub fetching WAIT_IRQ at the same cycle as DMA's
|
||||
beat 0) resolve correctly: DMA gets its real first-beat data, CPU's
|
||||
fetch services one cycle later.
|
||||
|
||||
Result: landed qword = `0xCAFEF00D12345678C0FFEE00DEADBEEF` —
|
||||
exactly the expected pattern, all four payload sentinels in place,
|
||||
1 DMA_DONE event, 1 halt event, `eebr_last_seen` latched. Clean
|
||||
PASS in ~1.5 ms sim time, well under the 5 ms watchdog.
|
||||
|
||||
Diagnostic prints (`[diag-beat]`, `[diag] iop_ram words`,
|
||||
`[diag] DMAC regs`) all stripped per Codex's framing — the
|
||||
collision TB is now the standing arbitration regression, this TB
|
||||
is the standing IOP-responder-architecture regression.
|
||||
|
||||
### Makefile
|
||||
|
||||
Both new TBs added to:
|
||||
- Per-target rules: `tb_iop_memory_map_collision`,
|
||||
`tb_iop_responder_ee_ram_landing`.
|
||||
- `.PHONY` list.
|
||||
- `run:` master list.
|
||||
|
||||
(Matches `[feedback-makefile-two-lists]` — the run-list addition
|
||||
that's easy to miss otherwise.)
|
||||
|
||||
## What we proved (Codex's Ch261 goal in one paragraph)
|
||||
|
||||
The existing IOP-side stubs (`iop_exec_stub` + `iop_memory_map_stub`
|
||||
+ `iop_ram_stub` + `iop_dmac_reg_stub` + `intc_stub`) can be
|
||||
composed with the SIF egress chain (`sif_dma_ee_ram_bridge_stub` +
|
||||
`ee_ram_stub`) to produce ONE explicit EE-visible side effect — a
|
||||
known 128-bit qword landing in EE RAM at a fixed offset —
|
||||
autonomously from a single `go_i` pulse, with no BIOS image, no
|
||||
long watchdog, deterministic ~1.5 ms runtime. The IOP responder
|
||||
architecture is real and works.
|
||||
|
||||
## Unexpected bonus: a real bug, found and fixed
|
||||
|
||||
The Ch261 SIF-landing TB surfaced what the previous TBs in the IOP
|
||||
chain (`tb_iop_self_driven`, `tb_iop_autonomous_two_xfers`) never
|
||||
could because they only verified event counts, not DMA payload
|
||||
data. The map's pre-Ch261 arbitration silently routed CPU's data
|
||||
to the DMA path on collision — a latent silent-corruption bug.
|
||||
Ch261 ends with that bug fixed, locked down by the focused
|
||||
collision TB, and the comment in the map updated so the next
|
||||
reader knows the path is now guarded.
|
||||
|
||||
## Files changed
|
||||
|
||||
- `rtl/iop/iop_memory_map_stub.sv` — deferred-CPU-slot arbitration.
|
||||
- `sim/tb/iop/tb_iop_memory_map_collision.sv` — NEW focused TB.
|
||||
- `sim/tb/integration/tb_iop_responder_ee_ram_landing.sv` — NEW
|
||||
composition TB (restored to natural script + diagnostics
|
||||
stripped).
|
||||
- `sim/Makefile` — new per-target rules + `.PHONY` + `run:`
|
||||
entries for both TBs.
|
||||
- `docs/ch261_arbitration_bug_brief.md` — finding writeup (kept for
|
||||
archaeology; Codex's pick from it became the implementation).
|
||||
- `docs/ch261_closeout.md` — this file.
|
||||
|
||||
## What's next (for Codex's Ch262 call)
|
||||
|
||||
Per Codex's Ch261 framing, Ch262 should "wire that responder into
|
||||
the BIOS-long setup and ask one question." Candidates that fall
|
||||
out of the Ch261 result:
|
||||
|
||||
1. **Plug the synthetic IOP responder into the BIOS-long TB** as
|
||||
a peer that writes a sentinel into a kernel-data region BIOS
|
||||
polls (`0x80030000`+ per Ch218 v5 capture). Question: does
|
||||
BIOS escape the Ch215 treadmill when the polled region
|
||||
actually mutates between syscall #8 cycles?
|
||||
2. **Asserted-source-from-the-responder INTC**: hook the
|
||||
responder's DMA-done pulse into the EE-side INTC view (via
|
||||
the Ch259 `iop_intc_inject_src_i` port, now actually driven by
|
||||
a real responder rather than a constant plusarg). Question: is
|
||||
the BIOS dispatch path satisfied by a real source pulse + a
|
||||
responder that ack-clears, vs Ch259's static-bit experiment?
|
||||
3. **Keep responder isolated, add the second side effect (SIF
|
||||
mailbox flag)** — proves the responder can produce *two*
|
||||
different EE-visible side effects on its own. Lighter than
|
||||
wiring into BIOS-long.
|
||||
|
||||
I think (1) is the natural Ch262 — the BIOS-long arc is paused
|
||||
waiting for exactly this kind of producer. (2) is the chapter
|
||||
after, layering the INTC signaling on top of the RAM-write
|
||||
producer. (3) is a smaller hold-pattern if Codex wants more
|
||||
isolated proof before opening BIOS-long again.
|
||||
|
||||
Standing by for Codex's call.
|
||||
Reference in New Issue
Block a user