# Ch300 closeout — MMI3 PCPYH; another adjacent-syscall surfaces

**Status:** Closed. Codex's PCPYH semantics (sa=0x1B, $rs-ignored,
broadcast low halfword of each $rt doubleword) implemented and
tested. **Verdict from re-running qbert.elf:**
`elf_first_unhandled_syscall (pc=0x00112A84 $v1=0x17 (=23))`. qbert
advanced 28,655 → **28,708 retires (+53)** through PCPYH and into
another syscall.

## What landed — `rtl/ee/ee_core_stub.sv`

Five surgical edits via the Ch278/281/283 MMI narrow-decode
pattern:

1. `localparam MMI3_PCPYH = 5'h1B` alongside MMI3_PCPYUD (0x0E).
2. `is_pcpyh` decode flag.
3. `is_pcpyh` added to `is_rtype_alu` and `is_mmi_wb`; `!is_pcpyh`
   added to MMI nop_class exclusion.
4. **Low-32 mirror arm:** `rtype_alu_wb = {rt128_val[15:0],
   rt128_val[15:0]}` — broadcasts h0 across the low 32 (the
   regfile mirror sees `{h0,h0}`).
5. **Full-128 writeback:** `rtype_alu128_wb = {{4{rt128_val[79:64]}},
   {4{rt128_val[15:0]}}}` — broadcasts h0 across low 64 lanes and
   h4 across high 64 lanes. Exactly Codex's spec.

`$rs` is architecturally ignored — the decode uses opcode+funct+sa
only, no rs check. The TB's Case 2 verifies this.

## Focused TB — `tb_ee_core_pcpyh.sv`

Three cases:

1. **Exact qbert encoding asserted** == `0x70081EE9`. Seeds
   gpr128[$t0] via PCPYLD($t0, $t1, $t2) where $t1 low 16 = 0xABCD
   (→ h4) and $t2 low 16 = 0x1234 (→ h0). Then PCPYH $v1, $t0.
   Verified:
   - `regfile[$v1] = 0x12341234`
   - `gpr128[$v1][63:0] = 0x1234_1234_1234_1234`
   - `gpr128[$v1][127:64] = 0xABCD_ABCD_ABCD_ABCD`
2. **$rs-ignored check:** PCPYH $t3, $t0 with rs=$v1 (non-zero).
   Asserts gpr128[$t3] == gpr128[$v1] (same full 128-bit result;
   $rs change has no effect).
3. **Narrow decode:** neighbor MMI3 sa=0x1C (unallocated) still
   traps under strict mode.

Result: `retired=16 halt=0 trap=1 errors=0 PASS`. The TB also
verifies the full SUMMARY line shows the broadcast pattern in
hex.

## Makefile + regression

- `tb_ee_core_pcpyh` target.
- Added to both PHONY list and `run:` master list.
- Regression: 176 → **177**.

## qbert progression

| Chapter | Blocker | retire_count |
|---|---|---|
| Post-Ch299 (gate poke) | MMI3 PCPYH at 0x00110BB4 | 28,655 |
| **Post-Ch300 (PCPYH)** | **syscall $v1=0x17 at 0x00112A84** | **28,708 (+53)** |

Small advance (+53) because qbert went immediately from the PCPYH
into the next syscall. The new blocker is in a different code
region (PC 0x00112A84 is near earlier syscall sites — close to
the Ch289 0x78 area at 0x00112AA4).

## Ch301 framing — syscall 0x17

```
$v1 = 0x17 (= 23)
$a0 = 0x00000005  (channel id 5, same as Ch290/291)
$a1 = 0x00000000
$a2 = 0xFFFFFFFF  (-1, sentinel?)
$a3 = 0x00137568  (NEW context pointer, NOT the global ctx 0x001328C0)
```

Notable shifts from earlier syscalls:
- `$a3` has CHANGED again: previously 0x001328C0 (global ctx),
  then 0x00137568 (different region — looks like a per-channel
  state buffer? same low byte as the Ch299 halt's $a0=0x00137540).
- `$a0 = 5` matches the channel id used in Ch290/291 (the DMAC
  handler-install pair). So qbert is doing channel-5-specific
  cleanup or query.
- `$a2 = -1` is unusual — often a "no filter" or "all" sentinel.

PS2 syscall 0x17 (= 23) in standard tables is commonly cited as
`SetVTLBRefillHandler` or `iWakeupThread` or similar. The
$a0=channel pattern fits a per-channel kernel call.

Mechanical recipe: 9th narrow $v0=0 case in the dispatcher +
runner observer with full arg snapshot. Standard Ch289-pattern
extension.

## Pattern review (30 chapters)

| Era | Chapters | Effect |
|-----|----------|--------|
| Opcode-blocker | Ch271..Ch286 | R5900 opcodes |
| MMIO stubs | Ch287..Ch288 | DMAC ctrl + per-channel |
| Syscall HLE narrow | Ch273/285/289/290/291/293/296/297 | $v0=0 narrow cases |
| Narrow NOP-class | Ch286/292 | side-effect-free accepts |
| Inflection #1 | Ch293 | first wait loop |
| Investigation #1 | Ch294 | bit-17 syscall poll |
| Experimental unblock #1 | Ch295 | $a0-aware HLE |
| Inflection #2 | Ch297 | second wait loop |
| Investigation #2 | Ch298 | memory poll at 0x001329C0 |
| Experimental unblock #2 | Ch299 | TB-side gate poke |
| **MMI op** | **Ch300 (PCPYH)** | **mechanical MMI extension** |

The chapter cadence is now well-mixed: opcode chapters, MMIO
chapters, syscall HLE chapters, narrow NOP-class chapters, and
investigation/unblock 3-chapter cycles. All productive.

## Files changed

- `rtl/ee/ee_core_stub.sv` — 5 surgical edits (localparam, decode
  flag, is_rtype_alu/is_mmi_wb/nop_class wiring, two writeback
  arms).
- `sim/tb/integration/tb_ee_core_pcpyh.sv` — new focused TB.
- `sim/Makefile` — target + both regression lists.

## Regression

**177/177 PASS** (was 176 in Ch299; +1 for the new
tb_ee_core_pcpyh).
