# `twi` — Trap Word Immediate > **Category:** [Branch & System](../categories/branch.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x0c000000` ## Assembler Mnemonics | Mnemonic | XML entry | Flags | Description | | --- | --- | --- | --- | | `twi` | `twi` | — | Trap Word Immediate | ## Syntax ```asm tw [TO], [RA], [SIMM] ``` ## Encoding ### `twi` — form `D` - **Opcode word:** `0x0c000000` - **Primary opcode (bits 0–5):** `3` - **Extended opcode:** — - **Synchronising:** no | Bits | Field | Meaning | | --- | --- | --- | | 0–5 | `OPCD` | primary opcode | | 6–10 | `RT` | destination GPR (or RS when storing) | | 11–15 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) | | 16–31 | `D/SI/UI` | 16-bit signed or unsigned immediate | ## Operands | Field | Role | Description | | --- | --- | --- | | `TO` | twi: read | Trap-on condition mask (5 bits) — LT, GT, EQ, LGT, LLT bits. | | `RA` | twi: read | Source GPR (`r0`–`r31`). | | `SIMM` | twi: read | 16-bit signed immediate. Sign-extended to 64 bits before use. | ## Register Effects ### `twi` - **Reads (always):** `TO`, `RA`, `SIMM` - **Reads (conditional):** _none_ - **Writes (always):** _none_ - **Writes (conditional):** _none_ ## Status-Register Effects _No condition-register or status-register effects._ ## Operation (pseudocode) ``` ; Pseudocode derives directly from the xenia-rs interpreter ; arm (see Implementation References). Operation semantics: ; - Read source operands from the fields listed under Operands. ; - Apply the arithmetic / logical / memory action described ; in the Description field above. ; - Write results to the destination register(s); update any ; status bits enumerated under Status-Register Effects. ; Consult the IBM AIX reference link under IBM Reference for ; canonical PPC-style pseudocode where xenia's expression is ; terse. ``` ## C Translation Example ```c /* C translation: the xenia-rs interpreter arm below in */ /* Implementation References is the authoritative semantic */ /* snapshot. Translate it line-by-line: */ /* - ctx.gpr[N] -> r[N] (or f[]/v[] for FPRs/VRs) */ /* - mem.read_u*/write_u* -> mem_read_u*_be / mem_write_u*_be */ /* - ctx.update_cr_signed(fld, v) -> update_cr_signed(fld, v) */ /* - ctx.xer_ca / xer_ov / xer_so -> xer.CA / xer.OV / xer.SO */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` ## Implementation References **`twi`** - xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="twi"`](../../xenia-canary/tools/ppc-instructions.xml) - xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:601`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L601) - xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:87`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L87) - xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:328`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L328) - xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1762-1796`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1762-L1796)
xenia-rs interpreter body (frozen snapshot) ```rust PpcOpcode::tw | PpcOpcode::twi | PpcOpcode::td | PpcOpcode::tdi => { // PPCBUG-063: save CIA before incrementing so a trap handler reads // the faulting instruction address, not CIA+4. // PPCBUG-065: log the SIMM type code on `twi 31, r0, IMM` (Xbox 360 // typed-trap convention used by the CRT/kernel for C++ exception // class dispatch). The audit notes this is relevant to the Sylpheed // throw investigation; routing the type code via a payload requires // a StepResult enum extension that's deferred for now. let trap_pc = ctx.pc; let a = ctx.gpr[instr.ra()]; let b = match instr.opcode { PpcOpcode::twi | PpcOpcode::tdi => instr.simm16() as i64 as u64, _ => ctx.gpr[instr.rb()], }; let width = match instr.opcode { PpcOpcode::tw | PpcOpcode::twi => trap::TrapWidth::Word, _ => trap::TrapWidth::Doubleword, }; let fired = trap::evaluate(instr.to(), a, b, width); if fired { let typed_trap_simm = if matches!(instr.opcode, PpcOpcode::twi) && instr.to() == 31 && instr.ra() == 0 { Some(instr.simm16() as u16) } else { None }; tracing::warn!( "Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}{}", trap_pc, instr.opcode, instr.to(), a, b, typed_trap_simm.map_or(String::new(), |t| format!(" typed_trap_simm={:#06x}", t)) ); // Leave ctx.pc at CIA (NOT NIA) so trap handlers / SEH delivery // can read the faulting instruction address from ctx.pc. return StepResult::Trap; } ctx.pc += 4; } ```
## Special Cases & Edge Conditions - **32-bit comparison against sign-extended immediate.** `SIMM` is a 16-bit signed value, sign-extended to 32 bits, then compared against the low 32 bits of `RA`. The high half of `RA` is *ignored*. - **`TO` mask.** Identical to [`tw`](tw.md): bit 0 = signed LT, 1 = signed GT, 2 = EQ, 3 = unsigned LT (LGT), 4 = unsigned GT (LLT). Trap fires if any selected bit's condition is true. - **`twi 31, 0, 0` is unconditional trap.** All `TO` bits set ⇒ guaranteed trap. The simplified mnemonic family (`twnei`, `twgei`, …) is much more common in real code: bound checks, null checks, integer-divide-by-zero pre-checks. - **Compiler usage.** Xbox 360 GCC emits `twnei rN, -1` and similar to validate handle-style return values; the kernel handler turns the trap into an exception delivered to the title. - **No register effects.** Side effect: Program interrupt → vector `0x700` with `SRR1[TRAP]=1`. - **xenia simplification.** Same as the other three trap forms — xenia-rs unconditionally returns `StepResult::Trap` whenever it decodes any of `tdi`/`twi`/`td`/`tw`, regardless of the `TO` mask or operands. This means `twi 0, r0, 0` (architecturally a guaranteed-no-trap encoding) will spuriously fire under xenia. Keep this in mind when triaging unexpected trap signals. - **No `Rc` / `OE`.** D-form trap immediates have neither. ## Related Instructions - [`tw`](tw.md) — register-register 32-bit trap (X-form). - [`tdi`](tdi.md) / [`td`](td.md) — 64-bit (doubleword) siblings. - [`sc`](sc.md) — alternative synchronous kernel entry. - [`cmpi`](../alu/cmpi.md), [`cmpli`](../alu/cmpli.md) — set CR for a subsequent [`bcx`](bcx.md) when you want a regular branch instead of a trap. ### Simplified Mnemonics | Simplified | Expansion | Triggered when | | --- | --- | --- | | `tweqi RA, value` | `twi 4, RA, value` | `RA == EXTS(value)` | | `twnei RA, value` | `twi 24, RA, value` | `RA != EXTS(value)` | | `twlti RA, value` | `twi 16, RA, value` | signed less than | | `twlei RA, value` | `twi 20, RA, value` | signed less or equal | | `twgti RA, value` | `twi 8, RA, value` | signed greater than | | `twgei RA, value` | `twi 12, RA, value` | signed greater or equal | | `twllti RA, value` | `twi 2, RA, value` | unsigned less than | | `twlgei RA, value` | `twi 5, RA, value` | unsigned greater or equal | | `twlgti RA, value` | `twi 1, RA, value` | unsigned greater than | | `twllei RA, value` | `twi 6, RA, value` | unsigned less or equal | ## IBM Reference - [AIX 7.3 — `twi` (Trap Word Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-twi-trap-word-immediate-instruction) - [AIX 7.3 — Trap simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-trap-simplified) - PowerISA v2.07B, Book I §3.3.11 — fixed-point trap instructions.