Files
xenia-rs/migration/project-root/ppc-manual/branch/bcctrx.md
MechaCat02 e6d43a23ac chore: add migration/ bundle for cross-machine setup
Bundles state that lives OUTSIDE the xenia-rs repo so a fresh clone on
another machine can be brought up to identical configuration via
migration/setup.sh:

  - claude-memory/             ~/.claude/projects/-home-fabi-RE-Project-Sylpheed/memory/
                               (103 files, 1.1 MB - MEMORY.md + every
                                project_xenia_rs_*.md from audits
                                addis_signext through audit-058)
  - project-root/dot-claude/   <project-root>/.claude/settings.json
                               (Stop hook + permissions)
  - project-root/ppc-manual/   <project-root>/ppc-manual/
                               (PowerPC reference docs, 397 files, 3.7 MB)
  - project-root/run-canary.sh <project-root>/run-canary.sh
  - README.md                  Human-readable setup checklist
  - setup.sh                   Idempotent installer (also reclones
                               xenia-canary at pinned HEAD 6de80dffe)
  - MANIFEST.md                Per-file mapping + per-file-not-bundled
                               restoration recipe

Excluded from bundle (not shippable via git):
  - Sylpheed ISO (7.8 GB; copyright; manual copy required)
  - sylpheed.db (395 MB; regenerable from XEX via analysis tooling)
  - target/ build artifacts (rebuild on target)
  - audit-runs probe firehoses (.log/.stdout/.stderr ~11 GB; rerun if needed)
  - audit-runs memory dumps (.bin ~4.5 GB; rerun audit-026/027/029 if needed)
  - xenia-canary checkout (setup.sh reclones from
    git.mc02.dev/fabi/Xenia-Canary.git at HEAD 6de80dffe)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 21:38:38 +02:00

7.3 KiB
Raw Blame History

bcctrx — Branch Conditional to Count Register

Category: Branch & System · Form: XL · 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

bcctr[LK] [BO], [BI]

Encoding

bcctrx — form XL

  • Opcode word: 0x4c000420
  • Primary opcode (bits 05): 19
  • Extended opcode: 528
  • Synchronising: yes
Bits Field Meaning
05 OPCD primary opcode (19)
610 BT/BO target / branch options
1115 BA/BI source A / CR bit to test
1620 BB source B
2130 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 (031) 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 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-rs interpreter body (frozen snapshot)
        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 and bclrx, 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.

  • bclrx — branch conditional to LR (function returns).
  • bcx — branch conditional to displacement (B-form).
  • bx — unconditional displacement branch (I-form).
  • mtctr, mfctr — load/read CTR via mtspr 9 / mfspr 9.
  • sc — 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