Files
Sylpheed/tools/ppc-manual/branch/bcctrx.md
MechaCat02 6bdbf89ebc
All checks were successful
CI / Native — linux (pull_request) Successful in 37m56s
CI / WASM — Web (pull_request) Successful in 28m5s
CI / Formatting (pull_request) Successful in 59s
chore(tools): adopt the PPC manual and a canary launcher that works anywhere
CONSOLIDATION.md Phase 6. Both lived untracked in the project root -- on one
disk, backed up by nothing.

  tools/ppc-manual/   393 files, 3.7 MB. 455 instructions, 350 family pages,
                      598 mnemonics resolvable through index.json, plus the
                      generator that produced them.
  tools/run-canary.sh the oracle launcher.

🔴 THE LAUNCHER WAS BROKEN IN TWO WAYS AND IS REWRITTEN, not copied:

  * it pointed at `xenia-rs/sylpheed.iso`, a SYMLINK. Wine cannot resolve one
    and says "path invalid", which reads as a corrupt image rather than a path
    problem -- it has cost a session before. It now points at the real file and
    warns if handed a symlink.
  * it hardcoded one machine's absolute paths, and named `xenia-rs`, which this
    consolidation retires. Now derived from the script's own location, with
    SYLPH_CANARY_BIN / SYLPH_ISO overrides and a check that each exists.

The standing constraints are in its header where someone will read them: one
emulator at a time, Canary runs MUTED, and never judge a crash or a hang from
a Bash-launched run -- a SIGKILL that looked like the binary was the editor's
process supervisor.

⚠️ The manual's GENERATOR reads the xenia-rs source tree, which is going away.
Its decoder now lives here as crates/sylpheed-ppc, so the generator must be
repointed before it is run again. Recorded in the README rather than left for
someone to discover; the manual's content is checked in and regenerates from
nothing implicitly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 21:18:00 +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