Files
retroDE_ps2/docs/ch290_closeout.md
thejayman77 ec82764bef 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>
2026-06-29 20:10:50 -04:00

148 lines
5.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ch290 closeout — syscall 0x12 HLE; paired syscall 0x16 surfaces with identical args
**Status:** Closed. **Verdict from re-running qbert.elf:**
`elf_first_unhandled_syscall (pc=0x00112A74 $v1=0x16 (=22))` with
arguments **identical to the syscall 0x12 call we just HLE'd**.
qbert advanced 27,930 → **27,950 retires (+20)** through the
handler-install syscall and into a companion call that takes the
exact same args. The strongest signal of the run.
## Codex's framing confirmed
Codex predicted "$v1=0x12 is a registration call, plausibly
AddDmacHandler(5, fn, 0, ctx)". The runner-side observer
captured the first occurrence:
```
syscall_0x12 = seen=1 count=1 first_pc=0x00112a54
$a0=0x05 $a1=0x00112ab0 $a2=0x00000000 $a3=0x001328c0 → $v0=0
```
This is the classic 4-arg handler-install ABI: small slot index +
function pointer + null ctx0 + context pointer.
## The paired-syscall signal
The next blocker after 0x12 is `$v1=0x16 (=22)` at PC 0x00112A74,
**32 bytes (8 instructions) past the 0x12 call site**. Args:
| Reg | After syscall 0x12 | At syscall 0x16 blocker |
|-----|--------------------|-------------------------|
| $a0 | 0x00000005 | **0x00000005** |
| $a1 | 0x00112AB0 | **0x00112AB0** |
| $a2 | 0x00000000 | **0x00000000** |
| $a3 | 0x001328C0 | **0x001328C0** |
**Identical.** qbert is calling syscall 0x16 with the literally
same arguments it just passed to 0x12. The PS2 syscall table cites
`EnableIntcHandler` / `EnableDmacHandler` (or similar
"enable-just-registered" calls) in the 0x14-0x18 range. The
pattern: `Add*Handler` registers, `Enable*Handler` activates.
This is a Ch291 candidate with very high confidence:
- Same Ch285 precedent: accept ($v0 = 0, PC += 4).
- Parallel observer in the runner.
- One more switch case in the dispatcher.
## What landed in Ch290
### Dispatcher case — `rtl/ee/ee_core_stub.sv`
One new case (the 6th overall) in the Ch273 HLE switch:
```sv
32'h0000_0012: begin
regfile[2] <= 32'd0;
gpr128[2] <= 128'd0;
pc <= pc + 32'd4;
retire_pulse <= 1'b1;
state <= S_IFETCH_REQ;
end
```
Per Codex: do NOT invoke the handler function, do NOT mutate
DMAC/INTC state. Just accept the registration and observe what
qbert demands next.
### TB extension — `tb_ee_core_syscall_hle.sv`
Same mechanical pattern (slots / latch / assertion / display) used
for the Ch285 0x40 and Ch289 0x78 extensions. The TB now covers
six known syscall numbers (3C / 3D / 40 / 64 / 78 / 12). Result:
```
$v0_after_3C=0x001e0000 $v0_after_3D=0x00000000 $v0_after_64=0x00000000
$v0_after_40=0x00000000 $v0_after_78=0x00000000 $v0_after_12=0x00000000
$v1_at_halt=0x00007777
```
### Runner-side observer — `tb_ee_core_elf_runner.sv`
Parallel to the Ch289 0x78 observer. Same shape: detect retire of
SYSCALL with $v1 = 0x12, snapshot PC + $a0..$a3 on first occurrence,
emit a SUMMARY line. Worked first try — `syscall_0x12 seen=1
count=1 ...`.
The two observers (0x78 and 0x12) form a small library of "this
HLE'd syscall is worth surfacing." The pattern is mechanical and
the SUMMARY block now self-documents what qbert is calling the
kernel for. As more syscalls accumulate, the SUMMARY becomes a
running ledger of qbert's init sequence.
## qbert progression
| Chapter | Blocker | retire_count |
|---|---|---|
| Post-Ch287 (DMAC ctrl) | unmapped 0x1000C000 | 27,912 |
| Post-Ch288 (DMAC passive) | syscall 0x78 | 27,920 |
| Post-Ch289 (syscall 0x78) | syscall 0x12 | 27,930 |
| **Post-Ch290 (syscall 0x12)** | **syscall 0x16 at PC 0x00112A74 (identical args)** | **27,950 (+20)** |
The +20 retires include the 0x12 syscall return + 8 instructions
of setup (likely loading the same args back into $a0/$a1/$a3 from
some register holding pattern, or just executing the second call
that already had them in place) + the 0x16 syscall trap.
## Ch291 framing — syscall 0x16
Args identical to syscall 0x12 — the pattern Codex predicted at
Ch290 (registration accepted; next demand will tell us if the
handler needs to actually fire). The simplest hypothesis: 0x16 is
`Enable*Handler` for the registration that just landed.
First-pass scope:
1. Add `$v1 == 0x16` case to dispatcher: $v0 = 0, PC += 4.
2. Parallel observer in the runner (same template as 0x78/0x12).
3. TB extension (7th case).
If qbert then goes on to *poll* for the handler to fire — e.g.,
read DMAC D_STAT looking for a channel-5 interrupt bit — then
Ch292 has to model the handler-invocation path (real interrupt
delivery, COP0 Cause/Status, the registered fn_ptr being called).
But based on the identical args + Ch285 precedent, $v0=0 is the
right shape for the first pass. Let qbert's next demand tell us
what's needed.
## Pattern review (20 chapters)
20 chapters in: Ch271 + Ch290 = 12 retires → 27,950 retires
(2,329× advance). The syscall HLE dispatcher now handles SIX
distinct $v1 values, each added in one chapter. The runner-side
observer pattern (Ch289/Ch290) makes the diagnostic free.
## Files changed
- `rtl/ee/ee_core_stub.sv` — one new HLE case (~10 LOC).
- `sim/tb/integration/tb_ee_core_syscall_hle.sv` — extended with
syscall 0x12 case.
- `sim/tb/integration/tb_ee_core_elf_runner.sv` — syscall_0x12
observer + SUMMARY line.
No new TB, no new Makefile target; regression count unchanged at
**175/175**.
## Regression
**175/175 PASS** (unchanged from Ch289; no new TB).