# Ch281 closeout — MMI3/PNOR (canonical NOT); next blocker is PAND

**Status:** Closed. **Verdict from re-running qbert.elf:**
`elf_first_unsupported_opcode (pc=0x00112C98 instr=0x70431489)` —
opcode `0x1C` (MMI) + funct `0x09` (MMI2) + sa `0x12` = **PAND**
(Parallel AND). qbert is now deep into the SIMD byte-walker's
mask-and-reduce stage: PSUBB → PNOR → PAND.

## Numbers

| Chapter | Blocker | qbert retire_count |
|---------|---------|---------------------|
| Post-Ch279 (LQ) | PSUBB at 0x00112C90 | 27,020 |
| Post-Ch280 (PSUBB) | PNOR at 0x00112C94 | 27,021 |
| **Post-Ch281 (PNOR)** | **PAND at 0x00112C98** | **27,022** |

1-retire delta — PNOR retired, PAND traps next.

## What landed

### RTL — 5 surgical edits in `ee_core_stub.sv`

1. **Constants**: `FUNC_MMI3 = 6'h29`, `MMI3_PNOR = 5'h13`.
2. **Decode**: `is_pnor = is_mmi && (func == FUNC_MMI3) &&
   (shamt == MMI3_PNOR)`. Same three-way AND as Ch278/Ch280.
3. **`is_rtype_alu` group**: added `is_pnor`.
4. **Writeback (REUSE)**: extended the existing NOR arm to
   `else if (is_nor || is_pnor) rtype_alu_wb = ~(rs_val | rt_val)`.
   Architectural 128-bit PNOR collapses to a regular 32-bit
   bitwise NOR for the low lane.
5. **`is_nop_class` allow**: `!is_pnor` added.

5 LOC of real change. Pure pattern reuse from Ch280 PSUBB
(same MMI narrow-decode shape) plus reuse of the existing
NOR writeback arm.

### Focused TB — `tb_ee_core_pnor.sv`

Three cases:

1. **qbert exact encoding**: `pnor $v1, $zero, $t1`. Encoder
   asserted == `0x70091CE9`. With `$t1 = 0x12345678` → `$v1
   = ~0x12345678 = 0xEDCBA987`.
2. **NOT-of-zero**: `pnor $t2, $0, $0` → `0xFFFFFFFF`. Both
   operands zero; result is all-ones.
3. **General NOR**: `$t3 = 0xF0F0F0F0`, `$t4 = 0x0F0F0F0F`
   → `$t5 = ~(0xF0F0F0F0 | 0x0F0F0F0F) = ~0xFFFFFFFF = 0`.
   Locks in the "general two-operand NOR" path even though
   qbert's specific usage is the NOT-pseudo form.

Result: `retired=22 halt=1 trap=0 pc=0xbfc0014c errors=0 PASS`.

### Makefile + regression

- `tb_ee_core_pnor` target.
- Added to both regression lists.
- Regression: 168 → **169**.

## qbert's SIMD byte-walker — pipeline shape now clear

Six MMI/load chapters (Ch278–Ch281, plus Ch271 SQ and Ch279 LQ)
have surfaced the full byte-walker shape:

```
0x00112C88: lq     $t1, 0($a1)           ; Ch279 — load 128-bit chunk
0x00112C8C: <one  instr we haven't seen the next blocker for>
0x00112C90: psubb  $v0, $t1, $t2         ; Ch280 — per-byte subtract
0x00112C94: pnor   $v1, $zero, $t1       ; Ch281 — ~$t1 (mask gen)
0x00112C98: pand   $v0, $v0, $v1         ; Ch282 — mask the result
... reduction continues ...
```

This is the classic "find a zero byte" or "detect sentinel byte"
SIMD loop — `PSUBB` against a key, `PNOR` to invert the bits,
`PAND` with a mask to isolate the lanes where the condition
holds, then `PMFHL` or similar to reduce to a single GPR for a
branch test.

## Recommendation for Codex's Ch282 — PAND

`0x70431489` at PC `0x00112C98`:
- opcode 0x1C (MMI)
- funct 0x09 (MMI2)
- sa 0x12 (PAND within MMI2)
- rs=$v0, rt=$v1, rd=$v0
- → `pand $v0, $v0, $v1`

Architectural: 128-bit `$rd = $rs & $rt`. For our 32-bit model:
**bit-identical to standard AND** (SPECIAL funct 0x24). Same
shape as PNOR/NOR — different opcode, reused writeback arm.

Implementation outline (mirrors Ch281 PNOR exactly):

1. `localparam MMI2_PAND = 5'h12`.
2. `is_pand = is_mmi && (func == FUNC_MMI2) && (shamt ==
   MMI2_PAND)`. The MMI2 funct constant already exists from
   Ch278.
3. Add to `is_rtype_alu`.
4. **Reuse the existing AND writeback arm**:
   ```sv
   else if (is_and || is_pand) rtype_alu_wb = rs_val & rt_val;
   ```
5. Add `!is_pand` to `is_nop_class`.

~4 LOC.

Focused TB:
- Exact qbert encoding asserted == `0x70431489`.
- General AND case: `pand $rd, 0xFFFFFFFF, 0xAAAAAAAA` →
  `0xAAAAAAAA`.
- All-zero case: `pand $rd, 0xFFFFFFFF, 0x00000000` → 0.

**Likely follow-ons** after PAND: **PMFHL** (move from HI/LO
low halves) for the reduction — the byte-walker needs to fold
the masked vector down to a scalar for branching. Or
**PEXTLW** (parallel extract low word) for a different
reduction shape.

## Pattern review (11 chapters)

| Ch | Blocker | Edits | Pattern |
|----|---------|-------|---------|
| 271 SQ | first | 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) |
| **281 PNOR** | | **5** | **REUSE MMI narrow + reuse NOR arm** |

5 NEW patterns + 6 REUSE chapters. The reuse density continues
to climb — Ch282 PAND will be the most-reused chapter yet (MMI
narrow-decode + standard-AND writeback, both already in place).

## Files changed

- `rtl/ee/ee_core_stub.sv` — 5 surgical edits.
- `sim/tb/integration/tb_ee_core_pnor.sv` — new focused TB.
- `sim/Makefile` — target + both regression lists.

## Regression

In flight; expected **169/169**.
