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>
132 lines
5.0 KiB
Markdown
132 lines
5.0 KiB
Markdown
# Ch304 closeout — syscall 0x6B HLE; +604 retires; next blocker is DSUBU (not a wrapper syscall)
|
|
|
|
**Status:** Closed. **Verdict from re-running qbert.elf:**
|
|
`elf_first_unsupported_opcode (pc=0x00110A60 instr=0x0062102F)` —
|
|
SPECIAL funct 0x2F = **DSUBU** (`dsubu $v0, $v1, $v0`). qbert
|
|
advanced 28,813 → **29,417 retires (+604)**.
|
|
|
|
## Ch303's prediction — partially confirmed, with a twist
|
|
|
|
Ch303 predicted the next blocker would be one of the remaining
|
|
Table1 wrappers (0x76, 0x44, or 0xFFFF_FFBD). Instead, clearing
|
|
0x6B let qbert run **604 more retires** into code that hits a
|
|
**new opcode** (DSUBU), NOT the next wrapper syscall.
|
|
|
|
This is consistent with Ch303's autopsy — it doesn't contradict
|
|
it. The wrapper table is real and bounded; qbert just doesn't
|
|
walk straight down it. After the 0x6B call returns (its caller at
|
|
0x00111B00 ignoring the return, exactly as Ch303 found), qbert's
|
|
control flow proceeds into a different code path that needs DSUBU
|
|
before it would reach 0x76/0x44/-67.
|
|
|
|
**Implication for Ch305:** the "batch the remaining wrappers"
|
|
plan is **deferred, not cancelled**. Those wrappers (0x76, 0x44,
|
|
-67) will surface only when qbert's path actually reaches them.
|
|
Ch305 is now a DSUBU opcode chapter, not a wrapper batch.
|
|
|
|
The Ch303 autopsy still paid off: when 0x76/0x44/-67 do surface,
|
|
we already know they're return-ignored wrappers and can clear
|
|
them instantly. We just don't pre-add them speculatively.
|
|
|
|
## What landed — `rtl/ee/ee_core_stub.sv`
|
|
|
|
11th narrow $v0=0 case in the Ch273 dispatcher:
|
|
|
|
```sv
|
|
32'h0000_006B: begin
|
|
regfile[2] <= 32'd0;
|
|
gpr128[2] <= 128'd0;
|
|
pc <= pc + 32'd4;
|
|
retire_pulse <= 1'b1;
|
|
state <= S_IFETCH_REQ;
|
|
end
|
|
```
|
|
|
|
Ch303 proved the caller at 0x00111B00 ignores the return ($v0=0
|
|
is safe).
|
|
|
|
## TB + observer
|
|
|
|
- `tb_ee_core_syscall_hle.sv`: 0x6B subcase (now 11 known syscalls
|
|
+ unknown-halt).
|
|
- `tb_ee_core_elf_runner.sv`: 0x6B observer (count + first/last
|
|
args). qbert run shows:
|
|
```
|
|
syscall_0x6B = seen=1 count=1 first_pc=0x00111d64
|
|
first_args=(0x00000005, 0, 0xffffffff, 0x00137568) → $v0=0
|
|
```
|
|
count=1, exactly the channel-5 args Ch303's autopsy predicted.
|
|
Single call, return ignored, qbert moved on.
|
|
|
|
## qbert progression
|
|
|
|
| Chapter | Blocker | retire_count |
|
|
|---|---|---|
|
|
| Post-Ch302 (0x13) | syscall $v1=0x6B at 0x00111D64 | 28,813 |
|
|
| **Post-Ch304 (0x6B)** | **DSUBU (0x0062102F) at 0x00110A60** | **29,417 (+604)** |
|
|
|
|
The +604 jump is the largest syscall-HLE-driven advance since the
|
|
Ch293/Ch297 inflections — clearing the channel-5 init sequence
|
|
let qbert run a substantial stretch of follow-on code.
|
|
|
|
## Ch305 framing — DSUBU (SPECIAL funct 0x2F)
|
|
|
|
Instr `0x0062102F` decodes:
|
|
- opcode 0x00 (SPECIAL)
|
|
- rs = 3 ($v1), rt = 2 ($v0), rd = 2 ($v0), sa = 0
|
|
- funct = 0x2F = DSUBU (Doubleword Subtract Unsigned)
|
|
|
|
DSUBU is the 64-bit subtract — exact sibling of Ch272's DADDU
|
|
(funct 0x2D). Our 32-bit-scalar model treats it as SUBU on the
|
|
low 32 bits (the same approximation DADDU uses). With the gpr128
|
|
shadow, we could optionally do a full 64-bit subtract into the
|
|
low doubleword, but the established DADDU precedent is low-32
|
|
SUBU + zero-extend mirror.
|
|
|
|
Mechanical recipe (mirror Ch272 DADDU, ~4 edits):
|
|
1. `localparam FUNC_DSUBU = 6'h2F`.
|
|
2. `is_dsubu` decode flag.
|
|
3. Add to `is_rtype_alu` (and nop_class exclusion via that).
|
|
4. Writeback arm: `is_sub || is_subu || is_dsubu` → `rs_val -
|
|
rt_val` (extend the existing SUBU arm).
|
|
5. Focused TB: exact qbert encoding 0x0062102F asserted + normal
|
|
subtract + wraparound.
|
|
|
|
Regression 177 → 178.
|
|
|
|
## Files changed
|
|
|
|
- `rtl/ee/ee_core_stub.sv` — 1 new HLE case (~20 LOC with comment).
|
|
- `sim/tb/integration/tb_ee_core_syscall_hle.sv` — 0x6B subcase.
|
|
- `sim/tb/integration/tb_ee_core_elf_runner.sv` — 0x6B observer +
|
|
SUMMARY.
|
|
|
|
No new TB; regression unchanged at **177/177**.
|
|
|
|
## Pattern note
|
|
|
|
The Ch303 autopsy's value is now clear in retrospect: it told us
|
|
0x6B's return is ignored (so $v0=0 was safe to add immediately,
|
|
no risk), AND it pre-identified the remaining wrappers so we
|
|
won't be surprised when they appear. The fact that DSUBU came
|
|
first instead just means the autopsy's "bounded set" is a
|
|
*future* certainty, not an *immediate* sequence.
|
|
|
|
## Regression
|
|
|
|
**177/177 PASS.** (Honest note: I briefly misread this regression
|
|
as "interrupted" because it was still running when I spot-checked
|
|
its partial log at 135 lines and saw no live `make` process in
|
|
that instant — it then completed cleanly at 177/177. The Ch304
|
|
0x6B change is also independently validated by the focused
|
|
tb_ee_core_syscall_hle and the qbert run.)
|
|
|
|
**Process note for the playbook (still valid):** I started Ch305's
|
|
`ee_core_stub.sv` edits while this Ch304 `make run` was still in
|
|
its per-TB build phase. It happened to be harmless here only
|
|
because the DSUBU additions were syntactically valid SystemVerilog
|
|
— a half-finished edit (e.g. mid-`always_comb`) would have made
|
|
the regression's later iverilog builds fail spuriously. Rule:
|
|
wait for the regression-complete notification before editing
|
|
shared RTL for the next chapter.
|