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,121 @@
|
||||
# Ch302 closeout — syscall 0x13 HLE; channel-5 syscall sequence emerging
|
||||
|
||||
**Status:** Closed. **Verdict from re-running qbert.elf:**
|
||||
`elf_first_unhandled_syscall (pc=0x00111D64 $v1=0x6B (=107))` —
|
||||
qbert advanced 28,726 → **28,813 retires (+87)** through the paired
|
||||
0x13 and into a THIRD syscall sharing the same channel-5 args.
|
||||
|
||||
## What landed
|
||||
|
||||
10th narrow $v0=0 case in the Ch273 dispatcher + 7th runner
|
||||
observer (distinct-tuple tracking, paralleling 0x17). All
|
||||
mechanical. Regression 177/177 (no new TB).
|
||||
|
||||
## The channel-5 syscall sequence (NEW structural finding)
|
||||
|
||||
The runner observers now show qbert running a **repeating
|
||||
per-channel sequence**, not just isolated paired calls:
|
||||
|
||||
```
|
||||
syscall_0x17 = count=2 args=(5, 0, -1, 0x00137568) distinct_tuples=1
|
||||
syscall_0x13 = count=2 args=(5, 0, -1, 0x00137568) distinct_tuples=1
|
||||
(next blocker) $v1=0x6B args=(5, 0, -1, 0x00137568)
|
||||
```
|
||||
|
||||
Three observations:
|
||||
|
||||
1. **0x17 and 0x13 are each now called TWICE** (count=2, up from
|
||||
count=1 in Ch301). When Ch301 HLE'd 0x17, qbert was blocked
|
||||
before its second 0x17 call. With 0x13 now HLE'd too, qbert
|
||||
loops back and makes both calls a second time — then hits 0x6B.
|
||||
|
||||
2. **All three syscalls (0x17, 0x13, 0x6B) share identical args**:
|
||||
`$a0=5` (channel id), `$a1=0`, `$a2=0xFFFFFFFF` (-1 sentinel),
|
||||
`$a3=0x00137568` (the per-channel ctx).
|
||||
|
||||
3. **This is a per-channel-resource sequence**, not a one-shot
|
||||
pair. qbert appears to be iterating: for each channel resource,
|
||||
it calls a sequence of kernel functions (0x17, 0x13, 0x6B, …)
|
||||
with the same channel id and context.
|
||||
|
||||
## Codex's pause-for-autopsy condition — assessment
|
||||
|
||||
Codex said: "if this clears and the next thing is a wait loop or
|
||||
channel-5 event, pause for autopsy rather than adding more blind
|
||||
success cases."
|
||||
|
||||
**The next blocker IS a channel-5 event** (0x6B with $a0=5). But
|
||||
it is **not a wait loop** — it's a concrete unhandled syscall
|
||||
(`elf_first_unhandled_syscall`, not `elf_timeout_with_hot_pc`).
|
||||
qbert is making forward progress (+87 retires), not spinning.
|
||||
|
||||
**My read:** this is the boundary Codex flagged. The pattern has
|
||||
shifted from "isolated syscall blockers" to "a repeating
|
||||
channel-init sequence." Two paths for Ch303:
|
||||
|
||||
### Path A — continue mechanical (one more $v0=0 for 0x6B)
|
||||
|
||||
If 0x6B is just the third call in a finite per-channel init
|
||||
sequence (e.g., the SDK does `SetX(ch); RegisterY(ch); EnableZ(ch)`
|
||||
for each channel), then a few more mechanical $v0=0 cases will
|
||||
clear the whole sequence and qbert moves on. Cheap to try; the
|
||||
runner observers will show whether the sequence is finite.
|
||||
|
||||
### Path B — autopsy the sequence now
|
||||
|
||||
Disassemble the code region around PC 0x00111D64..0x00111DA0 (the
|
||||
caller of these syscall wrappers) to understand the loop
|
||||
structure. If it's `for (ch = 0..N) { syscall_0x17(ch); ... }`,
|
||||
we learn N and the full syscall set up front, instead of
|
||||
discovering them one trap at a time.
|
||||
|
||||
**Recommendation: Path B (brief autopsy) before Ch303.** The
|
||||
triplet + count=2 pattern is strong evidence of a bounded loop.
|
||||
A 20-minute disassembly of the caller would reveal:
|
||||
- the loop bound (how many channels),
|
||||
- the full syscall sequence per channel,
|
||||
- whether any of these syscalls' return values are checked
|
||||
(which would make a blind $v0=0 wrong).
|
||||
|
||||
This matches Codex's instinct: stop adding blind success cases
|
||||
once a *structured sequence* (not isolated calls) emerges. The
|
||||
autopsy is cheap and prevents a string of one-trap-at-a-time
|
||||
chapters.
|
||||
|
||||
## qbert progression
|
||||
|
||||
| Chapter | Blocker | retire_count |
|
||||
|---|---|---|
|
||||
| Post-Ch301 (0x17) | syscall $v1=0x13 | 28,726 |
|
||||
| **Post-Ch302 (0x13)** | **syscall $v1=0x6B at 0x00111D64 (channel-5 args)** | **28,813 (+87)** |
|
||||
|
||||
## Files changed
|
||||
|
||||
- `rtl/ee/ee_core_stub.sv` — 1 new HLE case.
|
||||
- `sim/tb/integration/tb_ee_core_syscall_hle.sv` — 0x13 subcase.
|
||||
- `sim/tb/integration/tb_ee_core_elf_runner.sv` — 0x13 observer
|
||||
(distinct-tuple) + SUMMARY.
|
||||
|
||||
No new TB; regression unchanged at **177/177**.
|
||||
|
||||
## Ch303 framing — autopsy the channel-init sequence
|
||||
|
||||
Concrete first step for Codex/next chapter:
|
||||
|
||||
1. Disassemble 0x00111D40..0x00111DC0 (the wrappers + their
|
||||
caller). The syscall wrappers are likely 4-instruction stubs
|
||||
like 0x00110990 (the 0x7A wrapper from Ch294); the *caller* is
|
||||
what loops.
|
||||
2. Identify the loop: is it `for each channel` or `for each
|
||||
resource`? What's the bound?
|
||||
3. Enumerate the full syscall sequence per iteration (0x17, 0x13,
|
||||
0x6B, and whatever follows).
|
||||
4. Decide: mechanical batch (add all the sequence's syscalls as
|
||||
$v0=0 at once) vs. modeling actual per-channel state.
|
||||
|
||||
The runner observer infrastructure (distinct-tuple tracking) is
|
||||
already in place to validate whatever Ch303 decides.
|
||||
|
||||
## Regression
|
||||
|
||||
**177/177 PASS** (unchanged from Ch301; no new TB).
|
||||
Reference in New Issue
Block a user