# `bcx` — Branch Conditional > **Category:** [Branch & System](../categories/branch.md) · **Form:** [B](../forms/B.md) · **Opcode:** `0x40000000` · _sync_ ## Assembler Mnemonics | Mnemonic | XML entry | Flags | Description | | --- | --- | --- | --- | | `bc` | `bcx` | — | Branch Conditional | | `bcl` | `bcx` | LK=1 | Branch Conditional | ## Syntax ```asm bc[LK][AA] [BO], [BI], [ADDR] ``` ## Encoding ### `bcx` — form `B` - **Opcode word:** `0x40000000` - **Primary opcode (bits 0–5):** `16` - **Extended opcode:** — - **Synchronising:** yes | Bits | Field | Meaning | | --- | --- | --- | | 0–5 | `OPCD` | primary opcode | | 6–10 | `BO` | branch options | | 11–15 | `BI` | CR bit to test | | 16–29 | `BD` | signed 14-bit word-offset target | | 30 | `AA` | absolute-address flag | | 31 | `LK` | link flag | ## Operands | Field | Role | Description | | --- | --- | --- | | `LK` | bcx: read | Link bit. When 1, LR ← address-of-next-instruction before the branch is taken. | | `AA` | bcx: 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. | | `BO` | bcx: read | 5-bit branch options — selects CTR decrement, CTR test polarity, and CR bit test polarity. See `forms/XL.md`. | | `BI` | bcx: read | CR bit index (0–31) selected by BO's condition test. | | `ADDR` | bcx: read | Encoded branch target displacement (24-bit for I-form, 14-bit for B-form, word-shifted). | | `CR` | bcx: read (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. | | `CTR` | bcx: read (conditional); bcx: write (conditional) | Count register. Decremented and optionally tested by conditional branches when `BO[2]=0`. | | `LR` | bcx: write (conditional) | Link register. Written by `bl`/`bla`/`bcl`/`bclrl`/`bcctrl`; read by `bclr`/`bclrl`. | ## Register Effects ### `bcx` - **Reads (always):** `LK`, `AA`, `BO`, `BI`, `ADDR` - **Reads (conditional):** `CR`, `CTR` - **Writes (always):** _none_ - **Writes (conditional):** `CTR`, `LR` ## Status-Register Effects _No condition-register or status-register effects._ ## Operation (pseudocode) ``` if ¬BO[2] then CTR <- CTR − 1 ctr_ok <- BO[2] | ((CTR ≠ 0) XOR BO[3]) cond_ok <- BO[0] | (CR[BI] ≡ BO[1]) if ctr_ok & cond_ok then NIA <- CIA + EXTS(BD || 0b00) (AA=0) EXTS(BD || 0b00) (AA=1) if LK then LR <- CIA + 4 ``` ## 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 **`bcx`** - xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bcx"`](../../xenia-canary/tools/ppc-instructions.xml) - xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:173`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L173) - 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:340`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L340) - xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:908-938`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L908-L938)
xenia-rs interpreter body (frozen snapshot) ```rust PpcOpcode::bcx => { let bo = instr.bo(); let bi = instr.bi(); // Decrement CTR if needed if bo & 0b00100 == 0 { ctx.ctr = ctx.ctr.wrapping_sub(1); } let ctr_ok = (bo & 0b00100) != 0 || (((ctx.ctr as u32) != 0) ^ ((bo & 0b00010) != 0)); let cond_ok = (bo & 0b10000) != 0 || (ctx.get_cr_bit(bi) == ((bo & 0b01000) != 0)); if ctr_ok && cond_ok { let target = if instr.aa() { instr.bd() as u32 } else { ctx.pc.wrapping_add(instr.bd() as u32) }; if instr.lk() { ctx.lr = (ctx.pc + 4) as u64; } ctx.pc = target; } else { if instr.lk() { ctx.lr = (ctx.pc + 4) as u64; } ctx.pc += 4; } } ```
## Special Cases & Edge Conditions - **14-bit signed displacement.** `BD` is a 14-bit signed word-count, scaled by 4 — yielding a ±32 KiB byte range (`−2^15 … +2^15 − 4`). For longer-range conditional control flow, compilers emit a short `bc` over an unconditional `b`. - **CTR decrement happens before the test.** `BO[2]=0` decrements CTR *first*, then `ctr_ok` evaluates against the new value. The classic `bdnz loop` loops `N` times when CTR is initialised to `N`. - **LR write is unconditional in xenia.** Xenia writes `LR ← CIA + 4` whenever `LK=1`, even on the not-taken path. This matches the PowerISA: `bcl` always sets `LR` regardless of branch outcome — exploited by `bcl 20, 31, $+4` as a self-PC capture (PIC trick). - **`BO` encoding** — see `bclrx.md` for the full 5-bit table. `bcx` supports the full set, including CTR-only branches (`bdnz`, `bdz`). - **Branch hint encoding.** PPC overloads `BO[4]` as a static prediction hint: 0 = "predict not taken", 1 = "predict taken". The Xenon honours it for forward branches; backwards conditional branches are predicted taken regardless. Translators may ignore the hint. - **Synchronisation.** Marked `sync` — like all branches, `bcx` is context-synchronising. Trivial in interpretation; matters for JIT reorder windows. - **No `Rc`.** B-form has no record bit; the apparent `Rc` operand-table entry under "Status-Register Effects" is N/A here. ### BO/BI encoding (compact table) | BO | Effect | Common simplified | | --- | --- | --- | | `0000z` | dec CTR, branch if `CTR≠0` & `¬CR[BI]` | `bdnzf BI, addr` | | `0001z` | dec CTR, branch if `CTR=0` & `¬CR[BI]` | `bdzf BI, addr` | | `0010y` | dec CTR, branch if `CTR≠0` | `bdnz addr` | | `0011y` | dec CTR, branch if `CTR=0` | `bdz addr` | | `0100z` | branch if `¬CR[BI]` | `bf BI, addr` (or `bne`/`bge`/...) | | `0101z` | branch if `CR[BI]` | `bt BI, addr` (or `beq`/`blt`/...) | | `1z1zz` | branch always | `b addr` (prefer plain `b` though) | Bit `z` is the prediction hint (`0` = not taken, `1` = taken). ## Related Instructions - [`bx`](bx.md) — unconditional displacement branch (24-bit range). - [`bclrx`](bclrx.md) — branch conditional to LR (function return). - [`bcctrx`](bcctrx.md) — branch conditional to CTR (indirect call / dispatch). - [`crand`](../control/crand.md), [`cror`](../control/cror.md), … — combine multiple CR bits before a single `bc`. - [`mtctr`](../control/mtspr.md), [`mfctr`](../control/mfspr.md) — set/get loop counter for `bdnz`/`bdz`. - [`sc`](sc.md) — alternative control-flow exit. ### Simplified Mnemonics The `bc` mnemonic is rarely written directly; assemblers fold most uses into form-specific aliases: | Simplified | Expansion | | --- | --- | | `beq crN, addr` | `bc 0b01100, 4·N+2, addr` — branch if `crN.EQ` | | `bne crN, addr` | `bc 0b00100, 4·N+2, addr` — branch if `crN.NE` | | `blt crN, addr` | `bc 0b01100, 4·N+0, addr` — branch if `crN.LT` | | `bge crN, addr` | `bc 0b00100, 4·N+0, addr` — branch if `crN.GE` | | `bgt crN, addr` | `bc 0b01100, 4·N+1, addr` — branch if `crN.GT` | | `ble crN, addr` | `bc 0b00100, 4·N+1, addr` — branch if `crN.LE` | | `bso crN, addr` | `bc 0b01100, 4·N+3, addr` — branch on summary overflow | | `bns crN, addr` | `bc 0b00100, 4·N+3, addr` — branch on no SO | | `bdnz addr` | `bc 0b10000, 0, addr` — decrement CTR, branch if non-zero | | `bdz addr` | `bc 0b10010, 0, addr` — decrement CTR, branch if zero | | `bdnzt BI, addr` | combined CTR + CR test (rare) | When `crN` is omitted in disassembly, `cr0` is implied. ## IBM Reference - [AIX 7.3 — `bc` (Branch Conditional)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-bc-branch-conditional-instruction) - [AIX 7.3 — Branch simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-branch-simplified)