# `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`** - Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwz"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) - Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:289`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L289) - Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:162`](../../../crates/sylpheed-ppc/src/opcode.rs#L162) - Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:470`](../../../crates/sylpheed-ppc/src/decoder.rs#L470)
Canary emitter (frozen snapshot @ f21ebd49e9) ```cpp int InstrEmit_lwz(PPCHIRBuilder& f, const InstrData& i) { // if RA = 0 then // b <- 0 // else // b <- (RA) // EA <- b + EXTS(D) // RT <- i32.0 || MEM(EA, 4) Value* b; if (i.D.RA == 0) { b = f.LoadZeroInt64(); } else { b = f.LoadGPR(i.D.RA); } Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); Value* rt = f.ZeroExtend(f.ByteSwap(f.LoadOffset(b, offset, INT32_TYPE)), INT64_TYPE); f.StoreGPR(i.D.RT, rt); return 0; } ```
**`lwzu`** - Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) - Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:310`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L310) - Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:163`](../../../crates/sylpheed-ppc/src/opcode.rs#L163) - Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:471`](../../../crates/sylpheed-ppc/src/decoder.rs#L471)
Canary emitter (frozen snapshot @ f21ebd49e9) ```cpp int InstrEmit_lwzu(PPCHIRBuilder& f, const InstrData& i) { // EA <- (RA) + EXTS(D) // RT <- i32.0 || MEM(EA, 4) // RA <- EA Value* ra = f.LoadGPR(i.D.RA); Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); Value* rt = f.ZeroExtend(f.ByteSwap(f.LoadOffset(ra, offset, INT32_TYPE)), INT64_TYPE); f.StoreGPR(i.D.RT, rt); StoreEA(f, i.D.RA, f.Add(ra, offset)); return 0; } ```
**`lwzux`** - Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) - Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:323`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L323) - Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:164`](../../../crates/sylpheed-ppc/src/opcode.rs#L164) - Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:881`](../../../crates/sylpheed-ppc/src/decoder.rs#L881)
Canary emitter (frozen snapshot @ f21ebd49e9) ```cpp int InstrEmit_lwzux(PPCHIRBuilder& f, const InstrData& i) { // EA <- (RA) + (RB) // RT <- i32.0 || MEM(EA, 4) // RA <- EA Value* ea = CalculateEA(f, i.X.RA, i.X.RB); Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); f.StoreGPR(i.X.RT, rt); StoreEA(f, i.X.RA, ea); return 0; } ```
**`lwzx`** - Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) - Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:334`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L334) - Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:165`](../../../crates/sylpheed-ppc/src/opcode.rs#L165) - Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:871`](../../../crates/sylpheed-ppc/src/decoder.rs#L871)
Canary emitter (frozen snapshot @ f21ebd49e9) ```cpp int InstrEmit_lwzx(PPCHIRBuilder& f, const InstrData& i) { // if RA = 0 then // b <- 0 // else // b <- (RA) // EA <- b + (RB) // RT <- i32.0 || MEM(EA, 4) Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); f.StoreGPR(i.X.RT, rt); return 0; } ```
## 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). Canary does exactly that: `ByteSwap(LoadOffset(…, INT32))`, zero-extended to 64 bits. - **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`](lwa.md) / [`lwaux`](lwa.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). Canary 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`](../alu/sync.md) / [`isync`](../alu/isync.md) / [`lwsync`](../alu/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`](lwa.md), [`lwaux`](lwa.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`](ld.md), [`ldx`](ld.md), [`ldux`](ld.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)