# Ch301 closeout — syscall 0x17 HLE; second paired-call pattern surfaces at 0x13

**Status:** Closed. **Verdict from re-running qbert.elf:**
`elf_first_unhandled_syscall (pc=0x00112A64 $v1=0x13 (=19))` with
arguments **identical to the just-HLE'd 0x17 call**. qbert advanced
28,708 → **28,726 retires (+18)** through the syscall 0x17 and
into a companion call.

## The second paired-call pattern

| Field | Syscall 0x17 (Ch301) | Syscall 0x13 (Ch302 blocker) |
|-------|---------------------|------------------------------|
| PC    | 0x00112A84          | 0x00112A64                   |
| $a0   | 0x00000005          | **0x00000005**               |
| $a1   | 0x00000000          | **0x00000000**               |
| $a2   | 0xFFFFFFFF          | **0xFFFFFFFF**               |
| $a3   | 0x00137568          | **0x00137568**               |

**All four args identical.** This mirrors the Ch290/291 0x12/0x16
discovery — `Add*Handler` + `Enable*Handler` style paired calls.
PS2 syscall 19 (0x13) and syscall 23 (0x17) are adjacent in the
standard kernel table; plausibly a "set" + "register" pair for the
same per-channel resource.

The two paired-call discoveries on the syscall track:
- Ch290/291: 0x12 + 0x16 with `(5, fn_ptr, 0, global_ctx)`
- Ch301/Ch302: 0x17 + 0x13 with `(5, 0, -1, new_ctx_0x00137568)`

Both involve `$a0 = 5` (channel id). Different `$a3` context
pointers though — the second pair uses a different kernel-state
region (0x00137568 vs 0x001328C0).

## What landed

### Dispatcher case — `rtl/ee/ee_core_stub.sv`

9th narrow $v0=0 case in the Ch273 dispatcher:

```sv
32'h0000_0017: begin
    regfile[2]   <= 32'd0;
    gpr128[2]    <= 128'd0;
    pc           <= pc + 32'd4;
    retire_pulse <= 1'b1;
    state        <= S_IFETCH_REQ;
end
```

### TB extension — `tb_ee_core_syscall_hle.sv`

Standard 4-slot subcase + latch + assertion + display. The TB
now covers ten known syscall numbers (3C / 3D / 40 / 64 / 78 / 12 /
16 / 7A with $a0=0 and $a0=4 / 79 / 77 / 17) plus the unknown-halt
path.

### Runner observer — `tb_ee_core_elf_runner.sv`

6th observer in the library, second to use the richer
distinct-tuple tracking (after Ch297 0x77). From qbert's run:

```
syscall_0x17 = count=1 distinct_tuples=1 first_pc=0x00112a84
  $a0=0x00000005 $a1=0x00000000 $a2=0xffffffff $a3=0x00137568 → $v0=0
  0x17 tuple[0] = (...same...) count=1
```

Single call with the args Codex flagged. count=1 means no
iteration, no spin — qbert called 0x17 once and moved on. The
$a3 context-shift Codex worried about is captured cleanly in the
SUMMARY for downstream analysis.

## qbert progression

| Chapter | Blocker | retire_count |
|---|---|---|
| Post-Ch300 (PCPYH) | syscall $v1=0x17 at 0x00112A84 | 28,708 |
| **Post-Ch301 (syscall 0x17)** | **syscall $v1=0x13 at 0x00112A64 (identical args)** | **28,726 (+18)** |

The +18 retires include the 0x17 retire + 17 instructions of
glue code + the 0x13 syscall trap. PC walks backward (0x00112A84
→ 0x00112A64), same pattern as Ch290/291's paired-call discovery.

## Ch302 framing — syscall 0x13

Args identical to the 0x17 call we just HLE'd. High-confidence
mechanical recipe:

1. 10th narrow $v0=0 case in the dispatcher.
2. Runner observer with distinct-tuple tracking (will likely
   confirm count=1 with the same args — confirmation surface).
3. Standard 4-slot TB subcase.

If qbert then progresses normally, the paired-call pattern is
fully unblocked. If it misbranches or spins, the symmetric arg
shape suggests we'd need to model the actual per-channel state
mutation — but that's Ch303+ if needed.

## Pattern review (31 chapters)

| Era | Effect |
|-----|--------|
| Opcode-blocker (Ch271..286) | exhausted |
| MMIO stubs (Ch287..288) | exhausted |
| Syscall HLE narrow (~10 cases now) | active |
| Narrow NOP-class (Ch286/292) | exhausted |
| Investigation/unblock cycles (Ch293-295, Ch297-299) | reusable pattern |
| MMI op extensions (Ch300+) | ride Ch283 gpr128 seam |
| **Paired-call discoveries** | **2 instances now** (0x12/0x16, 0x17/0x13) |

The "paired-call" pattern is now the second observed structural
discovery (after the "$a0-aware HLE" of Ch295). Both came out of
the runner observer instrumentation Codex pushed for. Each one
shortens the next chapter's framing time because the args are
predictable.

## Files changed

- `rtl/ee/ee_core_stub.sv` — 1 new HLE case (~25 LOC with comment).
- `sim/tb/integration/tb_ee_core_syscall_hle.sv` — 4 new slots +
  1 latch + 1 assertion + 1 display field.
- `sim/tb/integration/tb_ee_core_elf_runner.sv` — 1 new observer
  block (with distinct-tuple tracking) + SUMMARY display.

No new TB, no new Makefile target; regression count unchanged at
**177/177**.

## Regression

**177/177 PASS** (unchanged from Ch300; no new TB).
