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,135 @@
|
||||
# Ch285 closeout — syscall 0x40 HLE; next blocker is R5900 EI (COP0 funct 0x38)
|
||||
|
||||
**Status:** Closed. **Verdict from re-running qbert.elf:**
|
||||
`elf_first_unsupported_opcode (pc=0x001000FC instr=0x42000038)` —
|
||||
COP0/CO funct 0x38 = R5900 `EI` (Enable Interrupts), an EE-specific
|
||||
extension to the MIPS COP0 CO sub-table. qbert advanced 27,091 →
|
||||
**27,239 retires (+148)** — the biggest single-chapter jump since
|
||||
Ch283. The PC dropped from 0x001113xx (deep into game code) back
|
||||
down to 0x001000FC (early init), which means the syscall 0x40
|
||||
return successfully unstuck qbert's setup phase and it took the next
|
||||
hot block of work.
|
||||
|
||||
## What landed
|
||||
|
||||
A narrow HLE case for syscall `$v1 == 0x40` in `ee_core_stub.sv`'s
|
||||
existing Ch273 dispatcher. Per Codex framing ("accept the
|
||||
registration, return success, continue; don't over-trust the SDK
|
||||
name"), the case returns `$v0 = 0` and resumes at `PC + 4`. Two
|
||||
lines of new RTL surrounded by a comment block:
|
||||
|
||||
```sv
|
||||
32'h0000_0040: begin
|
||||
regfile[2] <= 32'd0;
|
||||
gpr128[2] <= 128'd0;
|
||||
pc <= pc + 32'd4;
|
||||
retire_pulse <= 1'b1;
|
||||
state <= S_IFETCH_REQ;
|
||||
end
|
||||
```
|
||||
|
||||
The standard PS2 kernel syscall table lists names in this slot like
|
||||
`SetVCommonHandler` / `SetVTLBRefillHandler`. The observed call shape
|
||||
(`$a0=0x001DFFC0` heap-ish, `$a1=0x0011C326` code-ptr-ish) is
|
||||
consistent with a kernel-handler-install pattern. Real PS2 ROM
|
||||
implementations of these calls return the previous handler pointer;
|
||||
our stub returns 0 since (a) we don't store handler state, and (b)
|
||||
qbert clearly doesn't use the return value as a function pointer
|
||||
(it advanced 148 instructions past the call without re-trapping in
|
||||
a wild jump).
|
||||
|
||||
If a future ELF needs the previous-handler return, this case can be
|
||||
widened with $a0-keyed handler-pointer storage. Not warranted yet.
|
||||
|
||||
## TB — `tb_ee_core_syscall_hle.sv` extended
|
||||
|
||||
Existing TB extended with a 4th known case slot (`S_ORI_V1_40` /
|
||||
`S_SYS_40` / `S_BNE_40` / `S_DS_40`) plus matching latch
|
||||
(`v0_after_40` / `seen_40_return`) and the corresponding assert.
|
||||
The display summary now reports `$v0_after_40` next to the other
|
||||
three. Pattern identical to the existing 3C/3D/64 cases. The
|
||||
unknown-syscall halt still terminates the test.
|
||||
|
||||
Result: `retired=21 halt=1 trap=0 errors=0 PASS`, with
|
||||
`$v0_after_3C=0x001e0000 $v0_after_3D=0x00000000 $v0_after_64=0x00000000 $v0_after_40=0x00000000 $v1_at_halt=0x00007777`.
|
||||
|
||||
## qbert progression
|
||||
|
||||
| Chapter | Blocker | retire_count |
|
||||
|---|---|---|
|
||||
| Post-Ch283 (PCPYUD + gpr128) | LD at 0x00113378 | 27,067 |
|
||||
| Post-Ch284 (LD) | SYSCALL $v1=0x40 at 0x00111D24 | 27,091 |
|
||||
| **Post-Ch285 (syscall 0x40)** | **`0x42000038` (COP0 EI) at 0x001000FC** | **27,239** |
|
||||
|
||||
The PC walking *backward* from 0x001113xx to 0x001000FC is a
|
||||
positive signal — qbert took the syscall return and looped or
|
||||
called back into earlier code, hit the next blocker there. 148
|
||||
retires is the largest single-chapter jump on the qbert track
|
||||
since Ch283's architectural pivot.
|
||||
|
||||
## Ch286 framing
|
||||
|
||||
Instr `0x42000038`:
|
||||
- bits 31..26: `010000` = opcode 0x10 (COP0)
|
||||
- bits 25..21: `10000` = rs/sub = 0x10 (COP0_CO — "coprocessor
|
||||
command")
|
||||
- bits 5..0: `111000` = funct 0x38
|
||||
|
||||
R5900 `EI` (Enable Interrupts). EE-specific extension to the MIPS
|
||||
COP0 CO sub-table (alongside `DI` at funct 0x39, plus the standard
|
||||
RFE/ERET/TLBP/TLBR/TLBWI/TLBWR/WAIT). Minimal implementation: NOP-
|
||||
class it (no model state mutated), PC += 4. We could optionally set
|
||||
`status[16]` (EIE bit) if a future test depends on the COP0 Status
|
||||
view, but qbert almost certainly doesn't poll Status after EI —
|
||||
it's calling EI as standard init noise.
|
||||
|
||||
Concrete Ch286 scope:
|
||||
1. `localparam FUNC_EI = 6'h38; localparam FUNC_DI = 6'h39;`
|
||||
2. `is_ei = is_cop0 && (rs_idx == COP0_RS_CO) && (func == FUNC_EI)`
|
||||
3. (`is_di` analogous, in case the next chapter trips DI)
|
||||
4. Add `!is_ei` (and `!is_di`) to the `(is_cop0 && !is_mfc0 && !is_mtc0 && !is_rfe)` is_nop_class exclusion.
|
||||
5. Default execute path retires (PC += 4 via normal `retire_advance`).
|
||||
6. Focused TB: encode EI, execute, verify no trap + PC advances + retire fires.
|
||||
|
||||
5-ish RTL edits. Pure NOP-class extension; no register effects in
|
||||
the model.
|
||||
|
||||
## Files changed
|
||||
|
||||
- `rtl/ee/ee_core_stub.sv` — 1 new case in the syscall HLE switch
|
||||
(~10 LOC with comment).
|
||||
- `sim/tb/integration/tb_ee_core_syscall_hle.sv` — 4 new BIOS
|
||||
slots, 1 new latch group, 1 new assertion, 1 expanded display
|
||||
line.
|
||||
|
||||
No new TB, no new Makefile target; regression count unchanged at
|
||||
**172/172**.
|
||||
|
||||
## Pattern review (15 chapters)
|
||||
|
||||
| Ch | Blocker | Edits | Pattern |
|
||||
|-----|--------------|-------|---------|
|
||||
| 271 | SQ | 5 | NEW 4-beat write |
|
||||
| 272 | DADDU | 4 | NEW ALU-low-32 |
|
||||
| 273 | SYSCALL HLE | 2 | NEW gated dispatcher |
|
||||
| 274 | BEQL | 6 | NEW branch+squash |
|
||||
| 275 | SD | 7 | REUSE SQ counter |
|
||||
| 276 | DSLL | 4 | REUSE DADDU |
|
||||
| 277 | BNEL | 6 | REUSE BEQL squash |
|
||||
| 278 | PCPYLD | 4 | NEW MMI narrow-decode |
|
||||
| 279 | LQ | 5 | REUSE LW path |
|
||||
| 280 | PSUBB | 5 | REUSE MMI narrow (byte-SIMD new) |
|
||||
| 281 | PNOR | 5 | REUSE MMI narrow + NOR arm |
|
||||
| 282 | PAND | 5 | REUSE MMI narrow + AND arm |
|
||||
| 283 | PCPYUD + gpr128 | architectural | NEW 128-bit shadow |
|
||||
| 284 | LD | 5 | REUSE Ch283 multi-beat path |
|
||||
| **285** | **syscall 0x40** | **~1** | **REUSE Ch273 dispatcher** |
|
||||
|
||||
Highest-reuse chapter on record. The Ch273 dispatcher was designed
|
||||
to be extended — each new $v1 is one switch case. The +148 retires
|
||||
shows the cost-to-progress ratio remains favorable.
|
||||
|
||||
## Regression
|
||||
|
||||
**172/172 PASS** (unchanged from Ch284; no new TB added in this
|
||||
chapter, the existing tb_ee_core_syscall_hle was extended in place).
|
||||
Reference in New Issue
Block a user