# `lwz` — Load Word and Zero > **Category:** [Memory](../categories/memory.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x80000000` ## Assembler Mnemonics | Mnemonic | XML entry | Flags | Description | | --- | --- | --- | --- | | `lwz` | `lwz` | — | Load Word and Zero | | `lwzu` | `lwzu` | — | Load Word and Zero with Update | | `lwzux` | `lwzux` | — | Load Word and Zero with Update Indexed | | `lwzx` | `lwzx` | — | Load Word and Zero Indexed | ## Syntax ```asm lwz [RD], [d]([RA0]) lwzu [RD], [d]([RA]) lwzux [RD], [RA], [RB] lwzx [RD], [RA0], [RB] ``` ## Encoding ### `lwz` — form `D` - **Opcode word:** `0x80000000` - **Primary opcode (bits 0–5):** `32` - **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 | ### `lwzu` — form `D` - **Opcode word:** `0x84000000` - **Primary opcode (bits 0–5):** `33` - **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 | ### `lwzux` — form `X` - **Opcode word:** `0x7c00006e` - **Primary opcode (bits 0–5):** `31` - **Extended opcode:** `55` - **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 | ### `lwzx` — form `X` - **Opcode word:** `0x7c00002e` - **Primary opcode (bits 0–5):** `31` - **Extended opcode:** `23` - **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 | | --- | --- | --- | | `RA0` | lwz: read; lwzx: read | Source GPR; when the encoded register number is 0 the operand is the literal 64-bit zero, **not** `r0`. | | `d` | lwz: read; lwzu: read | 16-bit signed displacement (`d`) added to the base address register. | | `RD` | lwz: write; lwzu: write; lwzux: write; lwzx: write | Destination GPR. | | `RA` | lwzu: read; lwzu: write; lwzux: read; lwzux: write | Source GPR (`r0`–`r31`). | | `RB` | lwzux: read; lwzx: read | Source GPR. | ## Register Effects ### `lwz` - **Reads (always):** `RA0`, `d` - **Reads (conditional):** _none_ - **Writes (always):** `RD` - **Writes (conditional):** _none_ ### `lwzu` - **Reads (always):** `RA`, `d` - **Reads (conditional):** _none_ - **Writes (always):** `RD`, `RA` - **Writes (conditional):** _none_ ### `lwzux` - **Reads (always):** `RA`, `RB` - **Reads (conditional):** _none_ - **Writes (always):** `RD`, `RA` - **Writes (conditional):** _none_ ### `lwzx` - **Reads (always):** `RA0`, `RB` - **Reads (conditional):** _none_ - **Writes (always):** `RD` - **Writes (conditional):** _none_ ## Status-Register Effects _No condition-register or status-register effects._ ## Operation (pseudocode) ``` EA <- (RA|0) + EXTS(d) RT <- ZEXT32_to_64(MEM(EA, 4)) ``` ## C Translation Example ```c /* lwz RT, d(RA) */ uint64_t base = (insn.RA == 0) ? 0 : r[insn.RA]; uint32_t ea = (uint32_t)(base + (int64_t)(int16_t)insn.D); r[insn.RT] = (uint64_t)mem_read_u32_be(ea); /* zero-extend */ ``` ## Implementation References **`lwz`** - xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwz"`](../../xenia-canary/tools/ppc-instructions.xml) - xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:289`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L289) - xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) - xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:355`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L355) - xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1000-1005`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1000-L1005)
xenia-rs interpreter body (frozen snapshot) ```rust PpcOpcode::lwz => { let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; ctx.pc += 4; } ```
**`lwzu`** - xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzu"`](../../xenia-canary/tools/ppc-instructions.xml) - xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:310`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L310) - xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) - xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:356`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L356) - xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1006-1011`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1006-L1011)
xenia-rs interpreter body (frozen snapshot) ```rust PpcOpcode::lwzu => { let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; ctx.gpr[instr.ra()] = ea as u64; ctx.pc += 4; } ```
**`lwzux`** - xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzux"`](../../xenia-canary/tools/ppc-instructions.xml) - xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:323`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L323) - xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) - xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:766`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L766) - xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1018-1023`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1018-L1023)
xenia-rs interpreter body (frozen snapshot) ```rust PpcOpcode::lwzux => { let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; ctx.gpr[instr.ra()] = ea as u64; ctx.pc += 4; } ```
**`lwzx`** - xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzx"`](../../xenia-canary/tools/ppc-instructions.xml) - xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:334`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L334) - xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) - xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:756`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L756) - xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1012-1017`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1012-L1017)
xenia-rs interpreter body (frozen snapshot) ```rust PpcOpcode::lwzx => { let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; ctx.pc += 4; } ```
## Extended Pseudocode ``` ; lwz — D-form plain EA <- (RA|0) + EXTS(d) RT <- 0x0000_0000 || MEM(EA, 4) ; zero-extend 32→64 ; lwzu — D-form with update (base-register post-write) EA <- (RA) + EXTS(d) ; RA ≠ 0 required RT <- 0x0000_0000 || MEM(EA, 4) RA <- EA ; lwzx — X-form indexed EA <- (RA|0) + (RB) RT <- 0x0000_0000 || MEM(EA, 4) ; lwzux — X-form indexed with update EA <- (RA) + (RB) ; RA ≠ 0 required RT <- 0x0000_0000 || MEM(EA, 4) RA <- EA ``` ## Special Cases & Edge Conditions - **Big-endian memory.** The Xenon reads memory big-endian. Translating to little-endian hosts requires a byte-swap on the 32-bit read (or calling a `mem_read_u32_be` helper as in the C example). Matching byte-order helpers in xenia: `mem.read_u32(...)` already returns a host-native `u32` of the big-endian word. - **Zero-extension to 64 bits.** The result occupies the full 64-bit GPR; the high 32 bits are zero. This is semantically distinct from [`lwa`](lwa.md) / [`lwax`](lwax.md) / [`lwaux`](lwaux.md), which sign-extend. Most Xbox 360 code uses `lwz` for unsigned word loads and for pointer loads (addresses are 32-bit and fit in the low half). - **`RA0` (non-update forms).** In `lwz` and `lwzx`, when the encoded `RA = 0` the base is the literal zero, **not** `r0`. This enables absolute-address loads `lwz RT, 0x8000(0)` and is heavily used to read from statically-linked data near the TOC base. - **Update forms require `RA ≠ 0`.** `lwzu` / `lwzux` invoke "RA = 0" as an invalid form; AIX docs say the result is undefined and assemblers will refuse to assemble `lwzu RT, d(0)`. Further, `RA = RT` is also invalid (the "effective address" write and the "loaded value" write would race). Xenia implements update forms without these checks; rely on incoming code being well-formed. - **No alignment requirement.** Xenon executes unaligned word loads without a fault (unlike some POWER cores). `MEM(EA, 4)` reads four bytes starting at `EA`, whatever alignment. - **No ordering guarantee.** These are ordinary cached loads; use [`sync`](sync.md) / [`isync`](isync.md) / [`lwsync`](sync.md) for explicit ordering, or [`lwarx`](lwarx.md) for load-reserve semantics. - **Indexed variant operand order.** `lwzx RT, RA, RB` — `RA` is the base (with `RA0` semantics), `RB` is the offset. The variant without `RA0` is `lwzux`. ## Related Instructions - [`lwa`](lwa.md), [`lwax`](lwax.md), [`lwaux`](lwaux.md) — load word, sign-extend to 64. - [`lwbrx`](lwbrx.md) — load word byte-reversed (little-endian word). - [`lwarx`](lwarx.md) — load word and reserve (pair with [`stwcx`](stwcx.md)). - [`ld`](ld.md), [`ldu`](ldu.md), [`ldx`](ldx.md), [`ldux`](ldux.md) — 64-bit loads. - [`lhz`](lhz.md), [`lbz`](lbz.md) — half-word / byte zero-extending loads (same family structure). - [`stw`](stw.md) family — the corresponding stores. ## IBM Reference - [AIX 7.3 — `lwz` (Load Word and Zero)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-lwz-load-word-zero-instruction) - [AIX 7.3 — `lwzu` / `lwzx` / `lwzux`](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-lwzu-load-word-zero-update-instruction)