# `bcctrx` — Branch Conditional to Count Register > **Category:** [Branch & System](../categories/branch.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000420` · _sync_ ## Assembler Mnemonics | Mnemonic | XML entry | Flags | Description | | --- | --- | --- | --- | | `bcctr` | `bcctrx` | — | Branch Conditional to Count Register | | `bcctrl` | `bcctrx` | LK=1 | Branch Conditional to Count Register | ## Syntax ```asm bcctr[LK] [BO], [BI] ``` ## Encoding ### `bcctrx` — form `XL` - **Opcode word:** `0x4c000420` - **Primary opcode (bits 0–5):** `19` - **Extended opcode:** `528` - **Synchronising:** yes | Bits | Field | Meaning | | --- | --- | --- | | 0–5 | `OPCD` | primary opcode (19) | | 6–10 | `BT/BO` | target / branch options | | 11–15 | `BA/BI` | source A / CR bit to test | | 16–20 | `BB` | source B | | 21–30 | `XO` | extended opcode (10 bits) | | 31 | `LK` | link flag | ## Operands | Field | Role | Description | | --- | --- | --- | | `LK` | bcctrx: read | Link bit. When 1, LR ← address-of-next-instruction before the branch is taken. | | `BO` | bcctrx: read | 5-bit branch options — selects CTR decrement, CTR test polarity, and CR bit test polarity. See `forms/XL.md`. | | `BI` | bcctrx: read | CR bit index (0–31) selected by BO's condition test. | | `CR` | bcctrx: read | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. | | `CTR` | bcctrx: read | Count register. Decremented and optionally tested by conditional branches when `BO[2]=0`. | | `LR` | bcctrx: write (conditional) | Link register. Written by `bl`/`bla`/`bcl`/`bclrl`/`bcctrl`; read by `bclr`/`bclrl`. | ## Register Effects ### `bcctrx` - **Reads (always):** `LK`, `BO`, `BI`, `CR`, `CTR` - **Reads (conditional):** _none_ - **Writes (always):** _none_ - **Writes (conditional):** `LR` ## Status-Register Effects _No condition-register or status-register effects._ ## Operation (pseudocode) ``` cond_ok <- BO[0] | (CR[BI] ≡ BO[1]) if cond_ok then NIA <- CTR[0:61] || 0b00 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 **`bcctrx`** - xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bcctrx"`](../../xenia-canary/tools/ppc-instructions.xml) - xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:250`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L250) - 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:721`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L721) - xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:962-981`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L962-L981)
xenia-rs interpreter body (frozen snapshot) ```rust PpcOpcode::bcctrx => { let bo = instr.bo(); let bi = instr.bi(); let cond_ok = (bo & 0b10000) != 0 || (ctx.get_cr_bit(bi) == ((bo & 0b01000) != 0)); if cond_ok { let next_pc = ctx.pc + 4; ctx.pc = (ctx.ctr as u32) & !3; if instr.lk() { ctx.lr = next_pc as u64; } } else { if instr.lk() { ctx.lr = (ctx.pc + 4) as u64; } ctx.pc += 4; } } ```
## Special Cases & Edge Conditions - **No CTR decrement.** Unlike [`bcx`](bcx.md) and [`bclrx`](bclrx.md), `bcctr` cannot decrement CTR (the CTR is the *target*). The PowerISA reserves `BO[2] = 0` encodings — they are *invalid* on `bcctrx`. xenia silently ignores `BO[2]`/`BO[3]` and treats every `bcctr` as a pure CR-conditional branch, which matches both the canary emit and real Xenon hardware behaviour. - **CTR alignment mask.** The target is `CTR & ~3`. Like `bclr`, the low two bits are stripped — a misaligned CTR is silently rounded down rather than trapping. - **BO encoding (CR-only subset).** Because CTR-test bits are unused, only four `BO` patterns are meaningful: | BO (binary) | Meaning | | --- | --- | | `0100z` | branch if `CR[BI]` false | | `0101z` | branch if `CR[BI]` true | | `1z1zz` | branch always (`bctr`) | | `0000z`/`001at`/etc. | reserved — implementation-defined | - **Indirect call/dispatch idiom.** `mtctr rN; bctrl` is the canonical PPC indirect call: load function pointer into CTR, call. The xenia interpreter writes `LR ← CIA + 4` only when the branch is taken — this matches the PowerISA, but contrast with `bcx` where `LK` always writes LR (even if the branch is not taken). The C-translation reference handles this asymmetry explicitly. - **`bctr` for switch tables.** Compilers emit `bctr` (not `bctrl`) for jump-table dispatch, with CTR loaded from a base + (index*4) lookup. Xenia honours this by simply jumping to `CTR & ~3`. - **Synchronisation.** Marked `sync` in xenia's XML — context-synchronising. JIT backends must ensure prior side effects have committed before the indirect transfer. - **No prediction hint sensitivity.** Xenon predicts indirect branches via a separate target cache; the `BO[4]` hint is mostly cosmetic for `bcctr`. ## Related Instructions - [`bclrx`](bclrx.md) — branch conditional to **LR** (function returns). - [`bcx`](bcx.md) — branch conditional to displacement (B-form). - [`bx`](bx.md) — unconditional displacement branch (I-form). - [`mtctr`](../control/mtspr.md), [`mfctr`](../control/mfspr.md) — load/read CTR via `mtspr 9` / `mfspr 9`. - [`sc`](sc.md) — alternative control-flow exit (system call). ### Simplified Mnemonics | Simplified | Expansion | | --- | --- | | `bctr` | `bcctr BO=0b10100, BI=0` — unconditional indirect branch | | `bctrl` | `bcctrl BO=0b10100, BI=0` — unconditional indirect call | | `beqctr crN` | `bcctr BO=0b01100, BI=4·N+2` — call CTR if `crN.EQ` | | `bnectr crN` | `bcctr BO=0b00100, BI=4·N+2` — call CTR if `crN.NE` | | `bltctr crN` | `bcctr BO=0b01100, BI=4·N+0` — call CTR if `crN.LT` | | `bgectr crN` | `bcctr BO=0b00100, BI=4·N+0` — call CTR if `crN.GE` | | `bgtctr crN` | `bcctr BO=0b01100, BI=4·N+1` — call CTR if `crN.GT` | | `blectr crN` | `bcctr BO=0b00100, BI=4·N+1` — call CTR if `crN.LE` | The unconditional `bctr`/`bctrl` are by far the most common in Xbox 360 disassembly (compiler-emitted indirect calls and switch dispatch). ## IBM Reference - [AIX 7.3 — `bcctr` (Branch Conditional to Count Register)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-bcctr-bcctrl-branch-conditional-count-register-instruction) - [AIX 7.3 — Branch simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-branch-simplified)