# `tw` — Trap Word > **Category:** [Branch & System](../categories/branch.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000008` ## Assembler Mnemonics | Mnemonic | XML entry | Flags | Description | | --- | --- | --- | --- | | `tw` | `tw` | — | Trap Word | ## Syntax ```asm tw [TO], [RA], [RB] ``` ## Encoding ### `tw` — form `X` - **Opcode word:** `0x7c000008` - **Primary opcode (bits 0–5):** `31` - **Extended opcode:** `4` - **Synchronising:** no | Bits | Field | Meaning | | --- | --- | --- | | 0–5 | `OPCD` | primary opcode | | 6–10 | `RT/FRT/VRT` | destination | | 11–15 | `RA/FRA/VRA` | source A | | 16–20 | `RB/FRB/VRB` | source B | | 21–30 | `XO` | extended opcode (10 bits) | | 31 | `Rc` | record-form flag | ## Operands | Field | Role | Description | | --- | --- | --- | | `TO` | tw: read | Trap-on condition mask (5 bits) — LT, GT, EQ, LGT, LLT bits. | | `RA` | tw: read | Source GPR (`r0`–`r31`). | | `RB` | tw: read | Source GPR. | ## Register Effects ### `tw` - **Reads (always):** `TO`, `RA`, `RB` - **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 **`tw`** - xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="tw"`](../../xenia-canary/tools/ppc-instructions.xml) - xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:583`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L583) - 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:750`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L750) - 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 only.** `tw` compares the *low 32 bits* of `RA` and `RB`. The high halves of the 64-bit GPRs on the Xenon are ignored. Use [`td`](td.md) for full 64-bit comparisons. - **`TO` mask (5 bits, MSB-first).** Same encoding as the doubleword form: | Bit | Mnemonic | Triggered when | | --- | --- | --- | | `TO[0]` (16) | LT | `(int32) RA < (int32) RB` | | `TO[1]` (8) | GT | `(int32) RA > (int32) RB` | | `TO[2]` (4) | EQ | `(uint32) RA == (uint32) RB` | | `TO[3]` (2) | LGT | `(uint32) RA < (uint32) RB` | | `TO[4]` (1) | LLT | `(uint32) RA > (uint32) RB` | - **`tw 31, 0, 0` is `trap`.** The simplified mnemonic `trap` expands to `tw 31, r0, r0` — all five `TO` bits set ⇒ unconditional trap. Compilers and the kernel use this as the assertion / debugger break primitive; it appears as `0x7FE00008` in raw bytes. - **Conditional asserts.** GCC's `__builtin_trap` and MSVC's `__assert` macros emit `tw` variants like `twge`/`twlt` to fault on bound-check failures. - **No register effects.** Side effect only: Program interrupt (`0x700`) with `SRR1[TRAP]=1`. - **xenia simplification.** xenia-rs collapses `td/tdi/tw/twi` into a single arm that *unconditionally* logs and returns `StepResult::Trap` — the `TO` operand is **not evaluated**. Real hardware would silently fall through when no `TO` bit's condition holds. In practice titles use mostly the unconditional `trap`, so the divergence rarely manifests, but inert-marker patterns like `tw 0, r0, r0` will fire under xenia. - **Inert encoding.** `tw 0, r0, r0` (no `TO` bits set) can never trap on real hardware. It encodes as `0x7C000008` — sometimes used as a structured-NOP marker. Watch for it in xenia traces. ## Related Instructions - [`twi`](twi.md) — same 32-bit comparison against a 16-bit signed immediate. - [`td`](td.md) / [`tdi`](tdi.md) — 64-bit (doubleword) variants. - [`sc`](sc.md) — kernel entry via system-call exception (different vector). - [`mtmsr`](../control/mtmsr.md) — kernel returns from `0x700` via `rfid`. ### Simplified Mnemonics | Simplified | Expansion | Triggered when | | --- | --- | --- | | `trap` | `tw 31, 0, 0` | unconditional | | `tweq RA, RB` | `tw 4, RA, RB` | `RA == RB` | | `twne RA, RB` | `tw 24, RA, RB` | `RA != RB` | | `twlt RA, RB` | `tw 16, RA, RB` | signed less than | | `twle RA, RB` | `tw 20, RA, RB` | signed less or equal | | `twgt RA, RB` | `tw 8, RA, RB` | signed greater than | | `twge RA, RB` | `tw 12, RA, RB` | signed greater or equal | | `twllt RA, RB` | `tw 2, RA, RB` | unsigned less than | | `twlge RA, RB` | `tw 5, RA, RB` | unsigned greater or equal | | `twlgt RA, RB` | `tw 1, RA, RB` | unsigned greater than | | `twlle RA, RB` | `tw 6, RA, RB` | unsigned less or equal | ## IBM Reference - [AIX 7.3 — `tw` (Trap Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-tw-trap-word-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.