# `bx` — Branch > **Category:** [Branch & System](../categories/branch.md) · **Form:** [I](../forms/I.md) · **Opcode:** `0x48000000` · _sync_ ## Assembler Mnemonics | Mnemonic | XML entry | Flags | Description | | --- | --- | --- | --- | | `b` | `bx` | — | Branch | | `bl` | `bx` | LK=1 | Branch | ## Syntax ```asm b[LK][AA] [ADDR] ``` ## Encoding ### `bx` — form `I` - **Opcode word:** `0x48000000` - **Primary opcode (bits 0–5):** `18` - **Extended opcode:** — - **Synchronising:** yes | Bits | Field | Meaning | | --- | --- | --- | | 0–5 | `OPCD` | primary opcode | | 6–29 | `LI` | signed 24-bit word-offset target | | 30 | `AA` | absolute-address flag | | 31 | `LK` | link flag (bl/ba/bla) | ## Operands | Field | Role | Description | | --- | --- | --- | | `LK` | bx: read | Link bit. When 1, LR ← address-of-next-instruction before the branch is taken. | | `AA` | bx: read | Absolute-address bit. When 1, the branch target is the sign-extended displacement itself; when 0, it is added to the current instruction address. | | `ADDR` | bx: read | Encoded branch target displacement (24-bit for I-form, 14-bit for B-form, word-shifted). | | `LR` | bx: write (conditional) | Link register. Written by `bl`/`bla`/`bcl`/`bclrl`/`bcctrl`; read by `bclr`/`bclrl`. | ## Register Effects ### `bx` - **Reads (always):** `LK`, `AA`, `ADDR` - **Reads (conditional):** _none_ - **Writes (always):** _none_ - **Writes (conditional):** `LR` ## Status-Register Effects _No condition-register or status-register effects._ ## Operation (pseudocode) ``` NIA <- (CIA + EXTS(LI || 0b00)) if AA=0 <- EXTS(LI || 0b00) if AA=1 if LK then LR <- CIA + 4 ``` ## C Translation Example ```c /* b / bl / ba / bla — unconditional branch (I-form, primary 18) */ int32_t li = (int32_t)(insn.LI << 2); /* sign-extended word-offset */ uint32_t target = insn.AA ? (uint32_t)li : (uint32_t)(pc + li); uint32_t next = pc + 4; if (insn.LK) lr = next; /* bl / bla save return addr */ pc = target; ``` ## Implementation References **`bx`** - xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bx"`](../../xenia-canary/tools/ppc-instructions.xml) - xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:154`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L154) - xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:11`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L11) - xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:342`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L342) - xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:897-907`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L897-L907)
xenia-rs interpreter body (frozen snapshot) ```rust PpcOpcode::bx => { let target = if instr.aa() { instr.li() as u32 } else { ctx.pc.wrapping_add(instr.li() as u32) }; if instr.lk() { ctx.lr = (ctx.pc + 4) as u64; } ctx.pc = target; } ```
## Special Cases & Edge Conditions - **24-bit word-aligned target.** `LI` is a 24-bit signed word-count. Hardware concatenates `LI || 0b00` (adds the implicit two low zero bits) and sign-extends to 64 bits before using it as an address. The displacement range is therefore ±32 MiB in bytes (`−2^25 … +2^25 − 4`). - **Four mnemonics, one opcode.** The four runtime variants selected by `AA` and `LK`: - `b` — `AA = 0, LK = 0` — PC-relative, no link. - `bl` — `AA = 0, LK = 1` — PC-relative, `LR = CIA + 4` (the ubiquitous function-call primitive). - `ba` — `AA = 1, LK = 0` — absolute, no link. - `bla` — `AA = 1, LK = 1` — absolute, link. Xbox 360 code almost exclusively uses `b` and `bl`; `ba` / `bla` appear only in kernel / firmware stubs. - **Target alignment.** `LI` is scaled by 4, so all targets are 4-byte aligned by construction. There is no low-bit encoding of ARM-style Thumb — PPC has one instruction width. - **LR write is *before* the branch.** In `bl`, `LR` receives `CIA + 4` (the address of the instruction *after* the branch) before execution transfers to the target. Nested calls naturally overwrite LR; callees must spill it ([`mflr`](../control/mfspr.md) + `std`) before making their own `bl`. - **Indirect tail calls.** A tail call to an indirect target is encoded as `mtctr` + `bctr` (see [`bcctrx`](bcctrx.md)), not `bx` — `bx` has no register-based form. - **No condition test.** Use [`bcx`](bcx.md) for conditional displacement branches or [`bclrx`](bclrx.md) / [`bcctrx`](bcctrx.md) for conditional LR/CTR jumps. - **Speculative execution.** The Xenon fetches past `bx`; translators that mask control flow must treat the target as a single-destination control transfer. ## Related Instructions - [`bcx`](bcx.md) — conditional displacement branch (B-form, ±32 KiB range). - [`bclrx`](bclrx.md), [`bcctrx`](bcctrx.md) — branch to LR / CTR, conditional and unconditional. - [`mtlr`](../control/mtspr.md), [`mflr`](../control/mfspr.md) — LR save/restore for nested `bl` calls. - [`sc`](sc.md) — system call; an alternative control-flow exit to the kernel. ## Simplified Mnemonics Assemblers emit `b`, `bl`, `ba`, `bla` for the four runtime combinations. There is no further simplification. ## IBM Reference - [AIX 7.3 — `b` (Branch)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-b-branch-instruction) - [AIX 7.3 — `bl` (Branch with Link, simplified mnemonic)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-branch-simplified)