# `tdi` — Trap Doubleword Immediate > **Category:** [Branch & System](../categories/branch.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x08000000` ## Assembler Mnemonics | Mnemonic | XML entry | Flags | Description | | --- | --- | --- | --- | | `tdi` | `tdi` | — | Trap Doubleword Immediate | ## Syntax ```asm tdi [TO], [RA], [SIMM] ``` ## Encoding ### `tdi` — form `D` - **Opcode word:** `0x08000000` - **Primary opcode (bits 0–5):** `2` - **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` | tdi: read | Trap-on condition mask (5 bits) — LT, GT, EQ, LGT, LLT bits. | | `RA` | tdi: read | Source GPR (`r0`–`r31`). | | `SIMM` | tdi: read | 16-bit signed immediate. Sign-extended to 64 bits before use. | ## Register Effects ### `tdi` - **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 **`tdi`** - xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="tdi"`](../../xenia-canary/tools/ppc-instructions.xml) - xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:568`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L568) - 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:327`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L327) - 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 - **Immediate is sign-extended.** `SIMM` is treated as a 16-bit signed value, then sign-extended to 64 bits before comparison. To trap against a small unsigned constant, the same encoding works because both signed and unsigned interpretations agree for `SIMM ∈ [0, 0x7FFF]`. - **`TO` mask.** Identical bit layout to [`td`](td.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. - **`TO = 31` is unconditional.** `tdi 31, 0, 0` is a debugger / assert trap. Compilers sometimes use it as a "should not reach" marker. - **64-bit comparison only.** Unlike [`twi`](twi.md), `tdi` always compares the full 64-bit GPR — it has no PPC32 analogue. The Xenon's PPC64 mode makes this meaningful. - **No register effects.** Pure side effect on success: Program interrupt → vector `0x700` with `SRR1[TRAP]=1`. - **xenia simplification.** xenia-rs unconditionally treats `tdi` as a fired trap, regardless of `TO`/`RA`/`SIMM` values. This diverges from the spec — real hardware would silently fall through when no `TO` bit's condition holds. Most title code uses only the unconditional `trap` form, so the divergence is normally invisible; non-firing assertion patterns (e.g. `tdi 0, r0, 0`) will mis-fire under xenia. - **Reserved bits.** Bits 6–10 carry the `TO` field; there is no `Rc` / `OE` on D-form trap immediates. ## Related Instructions - [`td`](td.md) — register-register doubleword trap (X-form). - [`twi`](twi.md) / [`tw`](tw.md) — 32-bit-comparison siblings. - [`sc`](sc.md) — kernel-entry counterpart via system call exception. - [`mtmsrd`](mtmsrd.md) (control category) — kernel `rfid`-style return path after handling. ### Simplified Mnemonics | Simplified | Expansion | Triggered when | | --- | --- | --- | | `tdi RA, value` | `tdi 31, RA, value` | unconditional trap | | `tdeqi RA, value` | `tdi 4, RA, value` | `RA == EXTS(value)` | | `tdnei RA, value` | `tdi 24, RA, value` | `RA != EXTS(value)` | | `tdlti RA, value` | `tdi 16, RA, value` | signed less than | | `tdlei RA, value` | `tdi 20, RA, value` | signed less or equal | | `tdgti RA, value` | `tdi 8, RA, value` | signed greater than | | `tdgei RA, value` | `tdi 12, RA, value` | signed greater or equal | | `tdllti RA, value` | `tdi 2, RA, value` | unsigned less than | | `tdlgei RA, value` | `tdi 5, RA, value` | unsigned greater or equal | | `tdlgti RA, value` | `tdi 1, RA, value` | unsigned greater than | | `tdllei RA, value` | `tdi 6, RA, value` | unsigned less or equal | ## IBM Reference - [AIX 7.3 — `tdi` (Trap Doubleword Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-tdi-trap-doubleword-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.