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>
This commit is contained in:
192
migration/project-root/ppc-manual/branch/bcx.md
Normal file
192
migration/project-root/ppc-manual/branch/bcx.md
Normal file
@@ -0,0 +1,192 @@
|
||||
# `bcx` — Branch Conditional
|
||||
|
||||
> **Category:** [Branch & System](../categories/branch.md) · **Form:** [B](../forms/B.md) · **Opcode:** `0x40000000` · _sync_
|
||||
|
||||
<!-- GENERATED: BEGIN -->
|
||||
|
||||
## 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)
|
||||
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
|
||||
|
||||
```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;
|
||||
}
|
||||
}
|
||||
```
|
||||
</details>
|
||||
|
||||
<!-- GENERATED: END -->
|
||||
|
||||
## 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)
|
||||
Reference in New Issue
Block a user