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>
5.1 KiB
Ch292 closeout — narrow SYNC accept; next blocker is syscall 0x7A (cache-sync sibling?)
Status: Closed. Verdict from re-running qbert.elf:
elf_first_unhandled_syscall (pc=0x00110994 $v1=0x7A (=122)) —
qbert hit another syscall, this time with $a0 = 0x80000000
(kseg0 base / uncached-pointer base) and the same $a1 = 0x00112AB0 fn_ptr that's been threaded through syscalls
0x12/0x16. PS2 syscall 122 is plausibly SyncDCache /
iSyncDCache — a semantic neighbor to the MIPS SYNC barrier we
just accepted.
qbert advanced 27,954 → 27,968 retires (+14) past the SYNC and through ~13 instructions into a different code region (PC 0x00110994).
What landed
RTL — 3 surgical edits in ee_core_stub.sv
localparam FUNC_SYNC = 6'h0F;next to other SPECIAL func localparams.is_sync = is_special && (func == FUNC_SYNC)decode flag.!is_syncadded to the SPECIAL nop-class exclusion:(is_special && !is_syscall && !is_jr && !is_jalr && !is_rtype_alu && !is_hilo_op && !is_sync) // Ch292
No execute-path arm needed. SYNC falls through every recognized
predicate (is_lw/lq/sw/sq/sd/branch/etc.) and lands in the default
else begin block. None of the writeback predicates match SYNC
(is_rtype_alu / is_lui-family / is_jal / etc. all false), so:
- No GPR write
- No HI/LO write
- No memory side effect
retire_advance()→ PC += 4- Retire pulse fires
Net: side-effect-free retire, exactly what Codex specified.
TB — tb_ee_core_sync.sv
Mirrors tb_ee_core_ei from Ch286 with three correctness
assertions:
- Retire happens — latch keyed on
retired_pc == SYNC slotcapturesseen_sync_retire = 1. - No GPR / HI / LO mutation at retire — $v0/$t0 sentinels + HI/LO snapshot all sampled at the SYNC retire cycle and verified unchanged.
- Decode is narrow — neighbor SPECIAL funct
0x0E(currently unallocated, encoded asinstr 0x0000000E) MUST trap under strict mode. Assertstrap_pc / trap_instrat the 0x0E slot.
Plus the standard "post-SYNC LUI+ORI ran" check ($t1 = SENTINEL_C end-of-sim).
Result: retired=10 halt=0 trap=1 errors=0 PASS. Sentinels intact;
HI/LO both 0; neighbor 0x0E trapped cleanly.
Makefile + regression
tb_ee_core_synctarget.- Added to both PHONY list and
run:master list. - Regression: 175 → 176.
qbert progression
| Chapter | Blocker | retire_count |
|---|---|---|
| Post-Ch290 (syscall 0x12) | syscall 0x16 (identical args) | 27,950 |
| Post-Ch291 (syscall 0x16) | SYNC (0x0000000F) at 0x00112994 | 27,954 |
| Post-Ch292 (SYNC) | syscall $v1=0x7A at 0x00110994 | 27,968 |
PC jumped from 0x00112994 to 0x00110994 — qbert returned to an earlier code region (likely the "main init" function that called the handler-installation helper). The +14 retires include the SYNC retire + the function-return chain + setup for the next syscall.
Ch293 framing — syscall 0x7A
Args at halt:
$v1 = 0x7A(= 122)$a0 = 0x80000000— kseg0 base / uncached pointer. First syscall arg that's a kseg0 address (not heap-ish or fn-ptr).$a1 = 0x00112AB0— same fn_ptr seen in syscalls 0x12 and 0x16$a2 = 0x00000000$a3 = 0x001328C0— same global context pointer
$a0 = 0x80000000 is suggestive: in PS2 SDK code, SyncDCache /
iSyncDCache(start, end) takes a kseg0 address range. The
"semantic neighbor" pattern is striking — Ch292 accepted MIPS
SYNC (memory barrier), and Ch293's syscall might be the
cache-management companion.
Per Codex's established precedent: first-pass return $v0 = 0 ("cache synced OK"), PC += 4, add a runner-side observer with args + count. If the next blocker is a poll for the cache-sync to complete, that's Ch294's problem.
Alternative names for PS2 syscall 122 in various sources:
SyncDCache(start, end)— common nameiSyncDCache— interruptible variant- Could also be a thread or signal-handling call
Empirically: $v0 = 0 and continue. The runner observer pattern makes "wrong return value" easy to detect on the next run.
Pattern review (22 chapters)
| Ch | Blocker | Edits | Pattern |
|---|---|---|---|
| 286 | EI | 3 | NEW narrow exact-32 decode |
| 287 | DMAC ctrl MMIO | ~30 | NEW MMIO stub |
| 288 | DMAC passive | ~30 | REUSE Ch287 internal-stub |
| 289 | syscall 0x78 | ~20 | REUSE Ch273 + NEW observer |
| 290 | syscall 0x12 | ~20 | REUSE Ch289 pattern |
| 291 | syscall 0x16 | ~20 | REUSE Ch289 pattern (paired-call) |
| 292 | SYNC | 3 | REUSE Ch286 narrow-NOP-class |
Two narrow NOP-class accepts (Ch286 EI + Ch292 SYNC) and four syscall HLE extensions (Ch285/289/290/291) since the verdict era flipped at Ch286. The dispatcher accumulates one case per chapter; the runner observer library accumulates one entry per chapter; the TB pattern is mechanical.
Files changed
rtl/ee/ee_core_stub.sv— 3 edits (localparam, decode flag, nop-class exclusion).sim/tb/integration/tb_ee_core_sync.sv— new focused TB.sim/Makefile— target + both regression lists.
Regression
176/176 PASS (was 175/175 in Ch291; +1 for the new tb_ee_core_sync).