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>
165 lines
6.4 KiB
Markdown
165 lines
6.4 KiB
Markdown
# Ch288 closeout — DMAC passive per-channel surface; MMIO clear, syscall 0x78 surfaces
|
|
|
|
**Status:** Closed. **Verdict from re-running qbert.elf:**
|
|
`elf_first_unhandled_syscall (pc=0x00112AA4 $v1=0x78 (=120))`.
|
|
qbert advanced 27,912 → **27,920 retires (+8)** — past the
|
|
per-channel clear loop and on to another kernel syscall.
|
|
|
|
The standout signal: **`saw_unmapped_mmio = 0`** for the first time
|
|
since Ch286. The Ch287 + Ch288 combination now covers every
|
|
EE DMAC MMIO surface qbert touches during its init sweep — the
|
|
verdict shape flipped back to "unhandled syscall," which means
|
|
qbert is back in normal control flow and the MMIO era closes (for
|
|
now).
|
|
|
|
## What landed
|
|
|
|
Per Codex's "lightweight per-channel register surface, no transfer
|
|
FSM" framing, Ch288 delivers:
|
|
|
|
### New module — `rtl/dmac/ee_dmac_passive_chan_stub.sv`
|
|
|
|
A single channel-multiplexed register stub covering five DMAC
|
|
channels (the unmodeled ones):
|
|
|
|
| Channel | Base | Endpoint | Internal idx |
|
|
|---------|------------|-----------|--------------|
|
|
| ch0 | 0x10008000 | VIF0 | 0 |
|
|
| ch1 | 0x10009000 | VIF1 | 1 |
|
|
| (ch2) | (0x1000A000) | (GIF) | (skip — dedicated `dmac_reg_stub` on `ee_dmac_ch2_*` ports) |
|
|
| ch3 | 0x1000B000 | IPU_FROM | 2 |
|
|
| ch4 | 0x1000C000 | IPU_TO | 3 ← qbert blocker |
|
|
| ch5 | 0x1000D000 | SIF0 | 4 |
|
|
|
|
Per channel: CHCR / MADR / QWC / TADR (4 latched 32-bit registers
|
|
at offsets 0x00/0x10/0x20/0x30). Writes latch. Reads return last
|
|
latched value. Reset = 0. **No transfer FSM. No start-bit side
|
|
effects. No D_STAT interaction.**
|
|
|
|
The module decodes the channel index from `chan_addr[15:12]`:
|
|
- 0x8 → idx 0 (ch0)
|
|
- 0x9 → idx 1 (ch1)
|
|
- 0xB → idx 2 (ch3)
|
|
- 0xC → idx 3 (ch4)
|
|
- 0xD → idx 4 (ch5)
|
|
- 0xA (= ch2) → silently dropped (chan_valid=0): the real GIF
|
|
stub lives elsewhere; this module must not shadow it.
|
|
|
|
Unknown register offsets within a valid channel: write dropped,
|
|
read returns 0.
|
|
|
|
### Memory-map integration — `rtl/memory/ee_memory_map_stub.sv`
|
|
|
|
Five mechanical edits (the now-standard new-region recipe):
|
|
|
|
1. `REGION_EE_DMAC_PASSIVE = 64'd14` localparam.
|
|
2. `ee_rd_is_dmac_passive` / `ee_wr_is_dmac_passive` predicates:
|
|
```
|
|
(phys[28:16] == 13'h1000) &&
|
|
((phys[15:12] == 8) || (== 9) || (== B) || (== C) || (== D))
|
|
```
|
|
The `!= 0xA` exclusion keeps ch2 GIF on its dedicated port.
|
|
3. Internal instantiation of `ee_dmac_passive_chan_stub`.
|
|
4. New `ee_rd_was_dmac_passive` latch + response-mux arm.
|
|
5. New trace branches (read AND write) emitting
|
|
`REGION_EE_DMAC_PASSIVE`. **The Ch287 footgun avoided** —
|
|
trace branches added at the same time as the predicate, not as
|
|
a follow-up.
|
|
|
|
## TB — `tb_ee_dmac_passive_chan_stub.sv`
|
|
|
|
18 named assertions covering:
|
|
|
|
1. **ch4 reset reads zero** for all four registers.
|
|
2. **ch4 round-trip** writes/readbacks of CHCR/MADR/QWC/TADR with
|
|
distinct values.
|
|
3. **Channel independence:** write to ch5; verify ch4 values
|
|
unchanged; verify ch5 readback.
|
|
4. **ch2 filter:** write to chan_nibble=0xA returns 0 on read (this
|
|
stub does NOT shadow ch2 — that's `dmac_reg_stub`'s territory).
|
|
5. **ch0 / ch1 / ch3 reset** verifies multi-channel initialization.
|
|
6. **Unknown register offset** on a valid channel: read returns 0,
|
|
write doesn't damage the channel; the next valid read still
|
|
works.
|
|
|
|
Result: `errors=0 PASS` (18/18 sub-checks).
|
|
|
|
## Makefile + regression
|
|
|
|
- `tb_ee_dmac_passive_chan_stub` target.
|
|
- `rtl/dmac/ee_dmac_passive_chan_stub.sv` added to RTL_SRCS.
|
|
- TB added to both PHONY list and `run:` master list.
|
|
- Regression: 174 → **175**.
|
|
|
|
## qbert progression
|
|
|
|
| Chapter | Blocker | retire_count | unmapped_mmio? |
|
|
|---|---|---|:---:|
|
|
| Post-Ch286 (EI) | 0x1000E010 D_STAT (unmapped MMIO) | 27,907 | YES |
|
|
| Post-Ch287 (DMAC ctrl stub) | 0x1000C000 ch4 base (unmapped MMIO) | 27,912 | YES |
|
|
| **Post-Ch288 (DMAC passive)** | **syscall $v1=0x78 at PC 0x00112AA4** | **27,920** | **NO** |
|
|
|
|
The MMIO era (Ch287..Ch288) ran for just two chapters and added
|
|
~+13 retires worth of init-sweep coverage. With the per-channel
|
|
clear loop satisfied, qbert advanced to a SECOND kernel syscall
|
|
beyond the Ch285 $v1=0x40 — namely $v1=0x78 (120). Argument
|
|
snapshot at halt:
|
|
|
|
- `$a0 = 0x00000000` (zero / null)
|
|
- `$a1 = 0x00130000` (heap-ish or code-ish)
|
|
- `$a2 = 0x20000000` (high bit set; kseg0+0 = "uncached pointer"
|
|
base in PS2 convention)
|
|
- `$a3 = 0x001328c0` (code/data pointer-looking)
|
|
|
|
Per the Ch285 framing principle ("don't over-trust the SDK name;
|
|
model the observed behavior"), the right Ch289 move is probably
|
|
another narrow case: `$v0 = 0; PC += 4` and see what happens. If
|
|
qbert misbranches, return the `$a2` arg pattern instead. PS2
|
|
syscall 120 in the standard table is commonly cited as one of the
|
|
GS-control or threading-related calls; Codex can pick the right
|
|
stub-return semantics.
|
|
|
|
## Ch289 framing
|
|
|
|
Two narrow options for Codex:
|
|
- (a) **Add `$v1 == 0x78` to the existing HLE dispatcher** with
|
|
`$v0 = 0, PC += 4`. Trivial; one switch case.
|
|
- (b) **Identify the exact PS2 kernel service for syscall 120** and
|
|
pick a context-aware return value (e.g. echo $a2 if it's a
|
|
"register and return previous" pattern).
|
|
|
|
I lean (a) for the first pass — matches the Ch285 precedent. If
|
|
qbert misbranches downstream, revisit and try $a2 or $a1 as the
|
|
return.
|
|
|
|
## Files changed
|
|
|
|
- `rtl/dmac/ee_dmac_passive_chan_stub.sv` — new module (~160 LOC).
|
|
- `rtl/memory/ee_memory_map_stub.sv` — predicate, internal
|
|
instance, mux arm, trace branches.
|
|
- `sim/tb/dmac/tb_ee_dmac_passive_chan_stub.sv` — new focused TB.
|
|
- `sim/Makefile` — RTL_SRCS entry, new tb target, both regression
|
|
lists.
|
|
|
|
## Pattern review (18 chapters)
|
|
|
|
| Ch | Blocker | Edits | Pattern |
|
|
|-----|--------------|-------|---------|
|
|
| 271..286 | opcodes | various | opcode-era |
|
|
| 287 | DMAC ctrl MMIO | ~30 | NEW MMIO stub + map routing |
|
|
| **288** | **DMAC passive per-channel** | **~30** | **REUSE Ch287 internal-stub pattern** |
|
|
|
|
The internal-stub pattern from Ch287 paid off in Ch288: the same
|
|
predicate-instance-mux-trace mechanical sequence dropped a second
|
|
MMIO region into place without disturbing the 88 TBs that use
|
|
ee_memory_map_stub. The chapter cost stayed flat at ~30 edits
|
|
across one new RTL file + one map extension + one TB.
|
|
|
|
The trace-branch addition was done correctly at the same time as
|
|
the predicate (the Ch287 footgun avoided).
|
|
|
|
## Regression
|
|
|
|
**175/175 PASS** (was 174/174 in Ch287; +1 for the new
|
|
tb_ee_dmac_passive_chan_stub).
|