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:
MechaCat02
2026-05-10 21:38:38 +02:00
parent 8e709b0a24
commit e6d43a23ac
505 changed files with 86028 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
# PowerPC Instruction Manual (Xenia Xbox 360 Subset)
A reference for the **Xenon** PowerPC dialect used by the Xbox 360. Its
primary audience is an AI agent translating PPC assembly functions into
equivalent C. The content is derived from the two authoritative sources in
this repository — **xenia-canary** (C++ emulator) and **xenia-rs** (Rust
rewrite) — and may be deepened with the IBM AIX PowerPC reference.
- **455** distinct XML-level instructions (one page each).
- **350** instruction family pages (VMX128 siblings folded).
- **598** assembly mnemonics once runtime `Rc`/`OE`/`LK` variants are expanded — all resolvable through `index.json`.
## How to use this manual (translation agent)
1. Parse the 32-bit instruction word and identify the mnemonic. Resolve it
through [`index.json`](index.json): every assembly form (including
`add.`, `addo.`, `bclrl`, …) is a top-level key pointing at a page.
2. Open the page referenced by `index.json[mnem].page`. The page is in a
fixed format — see the "Page anatomy" section below.
3. Emit a C translation consistent with the page's pseudocode, the
registers-affected list, and the status-register effects.
## Page anatomy
Every instruction page has the same sections, in this order:
| Section | Purpose |
| --- | --- |
| **Assembler Mnemonics** | Table of every runtime variant (Rc/OE/LK) the base XML entry covers, plus VMX128 siblings. |
| **Syntax** | Canonical assembly template with `[OE]`/`[Rc]`/`[LK]` bracketed-modifier notation. |
| **Encoding** | Form name, opcode word, primary/extended opcodes, and bit-layout table. |
| **Operands** | Every bit-field operand, its role per variant, and its meaning. |
| **Register Effects** | Unconditional vs. conditional reads and writes, per variant. |
| **Status-Register Effects** | CR0/CR1/CR6, XER[CA/OV/SO], FPSCR, VSCR updates. |
| **Operation** | PPC-style pseudocode (`RT <- …`, `EXTS(…)`, `MEM(EA, n)`). |
| **C Translation Example** | Minimal idiomatic C rendering a translator could emit. |
| **Implementation References** | Direct links into `xenia-canary/` and `xenia-rs/` with line numbers. |
| **Special Cases & Edge Conditions** | RA=0, alignment, endian byte-reverse, reservation, SPR remapping, VMX128 fusion. |
| **Related Instructions** | Sibling cross-links. |
| **IBM Reference** | Optional link to IBM AIX PPC reference for canonical pseudocode. |
Sections between the `<!-- GENERATED: BEGIN -->` and `<!-- GENERATED: END -->`
sentinels are produced by [`generator/generate_manual.py`](generator/generate_manual.py)
and re-generated on every run. Sections outside the sentinels are
hand-written and preserved across re-runs.
## Conventions
- **Bit numbering** follows PowerPC (big-endian, bit 0 = MSB).
- **GPRs** are 64-bit. 32-bit operations operate on bits `[32:63]` and
conventionally write the low 32 bits with zero- or sign-extension into
the high 32 bits. Page pseudocode makes this explicit when it matters.
- **Vector registers** are 128-bit with **lane 0 at the most-significant
byte** (big-endian lane indexing). On x86 hosts byte-swap is applied at
load/store to preserve this invariant.
- **CR** is 8 × 4-bit fields `CR0..CR7`, each `{LT, GT, EQ, SO}`. The record
form of arithmetic instructions writes CR0 (integer) or CR1 (FPU); the
record form of vector compare writes CR6 = `{all-true, 0, all-false, 0}`.
- **XER** holds `SO`, `OV`, and `CA` at bits 32, 33, 34 respectively
(PPC bit numbering), plus a 7-bit string length used by `lswi`/`stswi`.
## Categories
| Category | Families | XML entries | Description |
| --- | --- | --- | --- |
| [Integer ALU](categories/alu.md) | 70 | 70 | Fixed-point add/sub/multiply/divide, logical, rotate, shift, compare, count-leading-zeros, sign-extension, trap-on-condition. |
| [Branch & System](categories/branch.md) | 9 | 9 | Unconditional / conditional branches, branch to LR/CTR, traps, system call. |
| [Control / CR / SPR](categories/control.md) | 26 | 26 | Condition-register logical ops, CR field moves, mfspr/mtspr/mtcrf, time-base reads, synchronisation (sync, isync, eieio). |
| [Floating-Point](categories/fpu.md) | 33 | 33 | IEEE-754 add/sub/mul/div/sqrt, fused multiply-add, conversions, compares, FPSCR moves. |
| [Memory](categories/memory.md) | 56 | 112 | Loads/stores for byte, half, word, doubleword, float, multiple and string; cache management (dcbt, dcbf, dcbz); reservation pair lwarx/stwcx. |
| [VMX (Altivec)](categories/vmx.md) | 144 | 193 | 128-bit SIMD over 32 registers V0V31. Integer/float arithmetic, logical, compare, permute/merge, pack/unpack, saturation helpers. |
| [VMX128](categories/vmx128.md) | 12 | 12 | Xbox-360-specific Altivec extension that widens the vector register file to 128 registers (V0V127). Register IDs are encoded with bit-fusion across non-contiguous fields. |
## Forms
| Form | Count | Page |
| --- | --- | --- |
| `A` | 21 | [forms/A.md](forms/A.md) |
| `B` | 1 | [forms/B.md](forms/B.md) |
| `D` | 40 | [forms/D.md](forms/D.md) |
| `DCBZ` | 2 | [forms/DCBZ.md](forms/DCBZ.md) |
| `DS` | 5 | [forms/DS.md](forms/DS.md) |
| `I` | 1 | [forms/I.md](forms/I.md) |
| `M` | 3 | [forms/M.md](forms/M.md) |
| `MD` | 4 | [forms/MD.md](forms/MD.md) |
| `MDS` | 2 | [forms/MDS.md](forms/MDS.md) |
| `SC` | 1 | [forms/SC.md](forms/SC.md) |
| `VA` | 14 | [forms/VA.md](forms/VA.md) |
| `VC` | 13 | [forms/VC.md](forms/VC.md) |
| `VX` | 117 | [forms/VX.md](forms/VX.md) |
| `VX128` | 34 | [forms/VX128.md](forms/VX128.md) |
| `VX128_1` | 16 | [forms/VX128_1.md](forms/VX128_1.md) |
| `VX128_2` | 1 | [forms/VX128_2.md](forms/VX128_2.md) |
| `VX128_3` | 15 | [forms/VX128_3.md](forms/VX128_3.md) |
| `VX128_4` | 2 | [forms/VX128_4.md](forms/VX128_4.md) |
| `VX128_5` | 1 | [forms/VX128_5.md](forms/VX128_5.md) |
| `VX128_P` | 1 | [forms/VX128_P.md](forms/VX128_P.md) |
| `VX128_R` | 5 | [forms/VX128_R.md](forms/VX128_R.md) |
| `X` | 117 | [forms/X.md](forms/X.md) |
| `XFL` | 1 | [forms/XFL.md](forms/XFL.md) |
| `XFX` | 4 | [forms/XFX.md](forms/XFX.md) |
| `XL` | 12 | [forms/XL.md](forms/XL.md) |
| `XO` | 21 | [forms/XO.md](forms/XO.md) |
| `XS` | 1 | [forms/XS.md](forms/XS.md) |
## Regenerating this manual
```bash
python3 generator/generate_manual.py
```
Re-running the generator is safe — it only rewrites sections between
`<!-- GENERATED: BEGIN -->` / `<!-- GENERATED: END -->` sentinels. Add
your hand-written content below the `END` marker and it will be
preserved.

View File

@@ -0,0 +1,159 @@
# Page Template — Canonical Structure
This file is the **reference for every instruction page** in the manual.
It documents the section order, what each section is for, and the
formatting conventions that the Phase 1 generator emits and Phase 2
reviewers enhance.
Do **not** copy this file to create a new page. Instruction pages are
produced by `generator/generate_manual.py` and should stay under the
generator's control.
---
## Page anatomy (section order)
Every page follows this skeleton:
```markdown
# `<base-mnem>` — <Short description>
> **Category:** [<Group label>](../categories/<group>.md) · **Form:** [<FORM>](../forms/<FORM>.md) · **Opcode:** `0x........`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
<table — runtime Rc/OE/LK variants + VMX128 siblings + memory u/x/ux siblings>
## Syntax
<fenced `asm` block with bracketed-modifier notation, one template per variant>
## Encoding
<per XML-entry subsection: opcode word, primary/extended, sync flag, bit-layout table>
## Operands
<field table — name, role per mnemonic, IBM-style description>
## Register Effects
<per-mnemonic: unconditional / conditional reads + writes>
## Status-Register Effects
<CR0/CR1/CR6, XER[CA/OV/SO], FPSCR, VSCR updates — only ones that apply>
## Operation (pseudocode)
<fenced PPC-style pseudocode block — IBM convention>
## C Translation Example
<fenced `c` block — minimal, idiomatic rendering a translator could emit>
## Implementation References
<xenia-canary XML / emit line, xenia-rs opcode / decoder / interpreter line range,
plus a <details> block with the frozen interpreter body snapshot>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
<hand-written. RA0 / alignment / endian / reservation / SPR-remap / VMX128 fusion>
## Related Instructions
<hand-written. Cross-links to siblings that didn't land on the same page>
## IBM Reference
<optional. Link to IBM AIX PowerPC reference when it adds value>
```
### Sentinel markers
The `<!-- GENERATED: BEGIN -->` / `<!-- GENERATED: END -->` pair
separates machine-generated content from hand-written enhancement.
- **Inside the sentinels:** rewritten on every generator run. Do not
edit — your changes will be overwritten.
- **Outside the sentinels:** preserved across regenerations. Put all
Phase 2 enhancements there.
If a page's generated section is missing the `END` sentinel the
generator assumes a human has fully taken over and leaves the file
untouched.
---
## Writing conventions
### Pseudocode
Follow IBM's AIX reference style:
```
EA <- (RA|0) + EXTS(d)
RT <- ZEXT32_to_64(MEM(EA, 4))
```
- `<-` for assignment, `(X)` for "value of register X".
- `(RA|0)` for RA0 fields — literal 0 when the encoded register is 0.
- `EXTS(x)` = sign-extend, `ZEXT/SEXT<n>_to_<m>(x)` explicit when helpful.
- `||` for bit concatenation.
- `MEM(EA, n)` for an n-byte big-endian memory read.
- `CR[BF] <- ...` for CR field updates.
- Register bit numbering in pseudocode is **PowerPC big-endian** (bit 0
is the MSB). `(RS)[56:63]` is the low byte of RS.
### C translation
- Use a pseudo-context of `r[]` (GPRs), `f[]` (FPRs), `v[]` (128-bit
vectors), `cr[]` (CR fields), and scalars `xer`, `lr`, `ctr`, `pc`.
- Prefer `int64_t`/`uint64_t` for 64-bit ops; cast to `int32_t` for
32-bit sub-word ops and explicitly sign/zero-extend.
- Use `mem_read_u32_be` / `mem_write_vec128_be` style helpers to make
the big-endian memory model explicit.
- Show the base form always; add one annotated variant (e.g. `if
(insn.Rc) ...`) only when it genuinely changes the translation.
### Bit ordering
PowerPC big-endian bit numbering is used throughout the manual (bit 0
is MSB). The same convention is used by IBM's reference and by the XML
source. Do not switch to Intel-style LSB-first numbering.
### Vector lane indexing
Altivec / VMX uses **big-endian lane indexing**: lane 0 is the
most-significant 16 bytes (or 4 words / 2 doublewords) of the vector.
On little-endian hosts (x86-64) byte-swap is applied at load/store to
preserve this invariant — call that out in the "Special Cases" section
when relevant.
---
## Example: fully-reviewed page
See `alu/addx.md` after Phase 2 review for the canonical look. It
demonstrates:
- Complete operand descriptions (not TODO stubs).
- Pseudocode with explicit CR/XER updates.
- C translation covering the base form plus Rc and OE variants.
- "Special Cases" calling out 32-bit vs 64-bit overflow tracking.
- Cross-links to `addcx`, `addex`, `subfx`.
---
## Golden-path spot-check list (Phase 2 review order)
These pages are reviewed first; they anchor the expected quality bar:
| Page | Reason |
| --- | --- |
| `alu/addx.md` | XO form with Rc+OE — representative ALU |
| `alu/addi.md` | D form with RA0 semantics — representative immediate |
| `memory/lwz.md` | D form load family (lwz/lwzu/lwzx/lwzux) |
| `memory/stvx.md` | Vector store with alignment mask |
| `memory/lvsl.md` | Permute-control generator |
| `branch/bclrx.md` | BO/BI conditional with LK |
| `branch/bx.md` | Absolute/relative branch |
| `control/mfspr.md` | SPR halves-swap encoding |
| `control/mtcrf.md` | CR field-mask update |
| `fpu/faddx.md` | Double-precision FPU + CR1 via Rc |
| `vmx/vaddfp.md` | VMX + VMX128 sibling on one page |
| `vmx/vperm.md` | Byte permute — lane-indexing discipline |
| `vmx128/vpkd3d128.md` | VMX128 orphan (no non-128 sibling) |

View File

@@ -0,0 +1,138 @@
# `addcx` — Add Carrying
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000014`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `addc` | `addcx` | — | Add Carrying |
| `addco` | `addcx` | OE=1 | Add Carrying |
| `addc.` | `addcx` | Rc=1 | Add Carrying |
| `addco.` | `addcx` | OE=1, Rc=1 | Add Carrying |
## Syntax
```asm
addc[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `addcx` — form `XO`
- **Opcode word:** `0x7c000014`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `10`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | addcx: read | Source GPR (`r0``r31`). |
| `RB` | addcx: read | Source GPR. |
| `RD` | addcx: write | Destination GPR. |
| `CA` | addcx: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
| `OE` | addcx: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
| `CR` | addcx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `addcx`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`, `CA`
- **Writes (conditional):** `OE`, `CR`
## Status-Register Effects
- `addcx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.; **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
RT <- (RA) + (RB)
CA <- carry_out_of_32_or_64_bit_add((RA), (RB))
```
## 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
**`addcx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addcx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:64`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L64)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:861`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L861)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:190-205`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L190-L205)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::addcx => {
// PPCBUG-013+020: 32-bit truncation; CA from u32 unsigned compare.
let ra32 = ctx.gpr[instr.ra()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
let result32 = ra32.wrapping_add(rb32);
ctx.xer_ca = if result32 < ra32 { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
let true_sum = (ra32 as i32 as i128) + (rb32 as i32 as i128);
overflow::apply(ctx, true_sum != (result32 as i32) as i128);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Carry-out is mandatory.** `XER[CA]` is updated unconditionally — `addcx` exists *to* produce the carry. It seeds a multi-word add chain that continues with [`addex`](addex.md) for middle words and [`addzex`](addzex.md)/[`addmex`](addmex.md) for the final word.
- **Carry detection by overflow comparison.** Xenia computes `CA = (result < RA)` — the standard unsigned-add overflow test. Equivalent to `CA = (RA + RB) >> 64` mathematically. This is correct for the 64-bit operand width that the Xenon implements; the spec also allows a 32-bit width selected by the implementation but the 970/Xenon use 64-bit add throughout.
- **No trap on signed overflow.** `addco`/`addco.` only set `XER[OV]` and sticky `XER[SO]`; they do not raise an exception. Xenia-rs leaves the `OE` branch as a `// TODO` (see [`addx`](addx.md) for the same gap).
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** The `Rc=1` CR0 compare reads `result as i32 as i64` in [`interpreter.rs:97`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L97); spec demands the full 64-bit signed compare. Flag this as a xenia-rs quirk if you need bit-exact behaviour.
- **`XER[SO]` is sticky** — only `mcrxr` clears it. The `Rc=1` form folds it into `CR0[SO]`.
- **Operand aliasing is legal**, just like [`addx`](addx.md). `addc r3, r3, r3` simply doubles `r3` and records whether the result wrapped.
## Related Instructions
- [`addx`](addx.md) — same operation, but does **not** update `XER[CA]`.
- [`addex`](addex.md) — `RA + RB + XER[CA]`; chains a multi-word add after `addcx`.
- [`addmex`](addmex.md), [`addzex`](addzex.md) — terminate a carry chain by adding `1` or `0` to `XER[CA]`.
- [`addic`](addic.md), [`addicx`](addicx.md) — D-form immediate variants that also write `XER[CA]`.
- [`subfcx`](subfcx.md) — the dual: produces a borrow-out in `XER[CA]`.
## IBM Reference
- [AIX 7.3 — `addc` (Add Carrying)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-addc-add-carrying-instruction)
- PowerISA v2.07B, Book I, §3.3.8 — Fixed-Point Add with Carry; defines `XER[CA]` semantics independent of operand width.

View File

@@ -0,0 +1,139 @@
# `addex` — Add Extended
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000114`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `adde` | `addex` | — | Add Extended |
| `addeo` | `addex` | OE=1 | Add Extended |
| `adde.` | `addex` | Rc=1 | Add Extended |
| `addeo.` | `addex` | OE=1, Rc=1 | Add Extended |
## Syntax
```asm
adde[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `addex` — form `XO`
- **Opcode word:** `0x7c000114`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `138`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | addex: read | Source GPR (`r0``r31`). |
| `RB` | addex: read | Source GPR. |
| `CA` | addex: read | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
| `RD` | addex: write | Destination GPR. |
| `OE` | addex: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
| `CR` | addex: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `addex`
- **Reads (always):** `RA`, `RB`, `CA`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `OE`, `CR`
## Status-Register Effects
- `addex`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- (RA) + (RB) + CA
CA <- carry_out_of_the_add
```
## 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
**`addex`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addex"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:83`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L83)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:868`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L868)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:206-222`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L206-L222)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::addex => {
// PPCBUG-014+020: 32-bit truncation; CA from u32 unsigned compare.
let ra32 = ctx.gpr[instr.ra()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
let ca = ctx.xer_ca as u32;
let result32 = ra32.wrapping_add(rb32).wrapping_add(ca);
ctx.xer_ca = if result32 < ra32 || (ca != 0 && result32 == ra32) { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
let true_sum = (ra32 as i32 as i128) + (rb32 as i32 as i128) + (ca as i128);
overflow::apply(ctx, true_sum != (result32 as i32) as i128);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Carry-in is consumed and carry-out is produced.** `addex` is the middle link of a multi-word add chain seeded by [`addcx`](addcx.md): `RT ← RA + RB + XER[CA]`, then `XER[CA] ← carry_out`.
- **Carry-out detection handles both edges.** Xenia checks `result < ra OR (ca != 0 && result == ra)` — that second clause covers the case where adding the carry-in alone causes the result to *exactly equal* `RA` (i.e. `RB == ~0 && CA == 1`), which still constitutes overflow. The naive `result < ra` test misses it.
- **No trap on signed overflow.** `addeo`/`addeo.` only update `XER[OV]` and sticky `XER[SO]`; xenia-rs leaves the `OE` branch unimplemented.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** The `Rc=1` arm uses `result as i32 as i64`. For multi-word adds whose final word is the high 32 bits of a 64-bit value, this distinction matters; see [`addx`](addx.md).
- **`XER[CA]` must be initialised** by an earlier [`addcx`](addcx.md), [`subfcx`](subfcx.md), or `mtspr` to XER. Reading stale `CA` from an unrelated instruction is the most common bug in hand-written multi-word arithmetic.
- **`XER[SO]` is sticky** until cleared by `mcrxr`; `Rc=1` copies it into `CR0[SO]`.
## Related Instructions
- [`addcx`](addcx.md) — seeds the carry chain (no `CA` read, sets `CA`).
- [`addmex`](addmex.md), [`addzex`](addzex.md) — terminate the chain (`RA + 1 + CA`, `RA + 0 + CA`).
- [`addx`](addx.md) — plain add without `XER[CA]`.
- [`subfex`](subfex.md) — dual: `~RA + RB + XER[CA]`, used for multi-word subtract.
- [`addic`](addic.md) / [`addicx`](addicx.md) — immediate carrying adds that *initialise* a chain.
## IBM Reference
- [AIX 7.3 — `adde` (Add Extended)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-adde-add-extended-instruction)
- PowerISA v2.07B, Book I, §3.3.8 — defines the `RA + RB + CA` carry-chain composition.

View File

@@ -0,0 +1,116 @@
# `addi` — Add Immediate
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x38000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `addi` | `addi` | — | Add Immediate |
## Syntax
```asm
addi [RD], [RA0], [SIMM]
```
## Encoding
### `addi` — form `D`
- **Opcode word:** `0x38000000`
- **Primary opcode (bits 05):** `14`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA0` | addi: read | Source GPR; when the encoded register number is 0 the operand is the literal 64-bit zero, **not** `r0`. |
| `SIMM` | addi: read | 16-bit signed immediate. Sign-extended to 64 bits before use. |
| `RD` | addi: write | Destination GPR. |
## Register Effects
### `addi`
- **Reads (always):** `RA0`, `SIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
if RA = 0 then RT <- EXTS(SIMM)
else RT <- (RA) + EXTS(SIMM)
```
## C Translation Example
```c
/* addi RT, RA, SIMM — RA=0 means literal 0 */
uint64_t base = (insn.RA == 0) ? 0 : r[insn.RA];
r[insn.RT] = base + (uint64_t)(int64_t)(int16_t)insn.SIMM;
```
## Implementation References
**`addi`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addi"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:103`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L103)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:338`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L338)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:114-120`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L114-L120)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::addi => {
// PPCBUG-001: 32-bit ABI. `li rT, -1` (= addi rT, r0, -1) must produce
// 0x00000000_FFFFFFFF, not 0xFFFFFFFF_FFFFFFFF (sign-extended simm16).
let ra_val = if instr.ra() == 0 { 0 } else { ctx.gpr[instr.ra()] };
ctx.gpr[instr.rd()] = ra_val.wrapping_add(instr.simm16() as i64 as u64) as u32 as u64;
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA0` semantics.** When the encoded `RA` field is `0` the operand is the literal constant `0`, **not** the value of `r0`. This lets `addi rT, 0, SIMM` load a constant (the `li rT, SIMM` simplified mnemonic). To use `r0`'s value you must use a register-register add (`add RT, r0, RB` through a temp) or an instruction without `RA0` semantics.
- **No flags written.** Unlike `add`, `addi` cannot be `Rc` or `OE` — no CR or XER update. Use [`addic`](addic.md) if you need `XER[CA]`, or [`addicx`](addicx.md) (`addic.`) if you need both `XER[CA]` and a CR0 update.
- **Immediate is 16-bit signed** (`SIMM`, range `32768 … +32767`), sign-extended to 64 bits before the add. No carry/overflow is produced regardless of the result.
- **Simplified mnemonics.** Assemblers recognise several aliases that all assemble to `addi`:
- `li RT, SIMM``addi RT, 0, SIMM` (load immediate; relies on `RA0`).
- `la RT, D(RA)``addi RT, RA, D` (load address; purely syntactic).
- `subi RT, RA, SIMM``addi RT, RA, SIMM`.
- **PC-relative idiom.** `addi RT, RA, D` is the low-half completion of a two-instruction address load preceded by [`addis`](addis.md) `RT, 0, HI`. The assembler emits `@ha`/`@l` relocations so the low half can be negative without corrupting the high half (add-compensation).
## Related Instructions
- [`addis`](addis.md) — same encoding family but the immediate is shifted left by 16 bits. Together they build any 32-bit constant or PC-relative address.
- [`addic`](addic.md), [`addicx`](addicx.md) — D-form adds that **do** set `XER[CA]` (and CR0 for the record form).
- [`addx`](addx.md) — the register-register form.
- [`subfic`](subfic.md) — reverse-subtract immediate (`imm RA`) with carry.
- [`ori`](ori.md), [`oris`](oris.md) — the alternative D-form constant-building instructions (but these don't add, they OR).
## IBM Reference
- [AIX 7.3 — `addi` (Add Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-addi-add-immediate-instruction)
- [AIX 7.3 — `li` (Load Immediate, simplified mnemonic)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-li-load-immediate)

View File

@@ -0,0 +1,123 @@
# `addic` — Add Immediate Carrying
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x30000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `addic` | `addic` | — | Add Immediate Carrying |
## Syntax
```asm
addic [RD], [RA], [SIMM]
```
## Encoding
### `addic` — form `D`
- **Opcode word:** `0x30000000`
- **Primary opcode (bits 05):** `12`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | addic: read | Source GPR (`r0``r31`). |
| `SIMM` | addic: read | 16-bit signed immediate. Sign-extended to 64 bits before use. |
| `RD` | addic: write | Destination GPR. |
| `CA` | addic: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
## Register Effects
### `addic`
- **Reads (always):** `RA`, `SIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`, `CA`
- **Writes (conditional):** _none_
## Status-Register Effects
- `addic`: **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
RT <- (RA) + EXTS(SIMM)
CA <- carry_out
```
## 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
**`addic`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addic"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:117`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L117)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:336`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L336)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:135-144`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L135-L144)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::addic => {
// PPCBUG-002: 32-bit ABI. CA must be from a 32-bit unsigned compare;
// canary's `AddDidCarry` truncates both operands to int32 first.
let ra32 = ctx.gpr[instr.ra()] as u32;
let imm32 = instr.simm16() as i32 as u32;
let result32 = ra32.wrapping_add(imm32);
ctx.xer_ca = if result32 < ra32 { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Immediate is sign-extended.** `SIMM` is a 16-bit signed value extended to 64 bits before the add. So `addic r3, r4, -1` adds `0xFFFFFFFFFFFFFFFF` to `r4` — it does not zero-extend.
- **`XER[CA]` always written.** Unlike [`addi`](addi.md), this instruction exists to seed a multi-word add chain with an immediate. Carry-out is computed with the same `result < ra` unsigned-overflow check as [`addcx`](addcx.md).
- **No `Rc` bit available.** This is the *non-record* form. For a record-form variant that also updates `CR0`, use [`addicx`](addicx.md) (`addic.`).
- **No `OE` bit either.** `addic` cannot raise / observe signed overflow — only the carry. If you need `XER[OV]` you must use the XO-form [`addcx`](addcx.md) with `OE=1`.
- **`RA = 0` reads register r0.** Unlike [`addi`](addi.md), `addic` does **not** treat the `RA` field of zero as a literal zero. The PowerISA gives this instruction the regular `RA` semantics, not `RA0`.
- **Subtract immediate carrying via negation.** There is no `subic` mnemonic; assemblers synthesise `subic RT, RA, value` as `addic RT, RA, -value` (when `value` fits in 16 bits signed).
## Related Instructions
- [`addicx`](addicx.md) — same operation plus `Rc=1` CR0 update.
- [`addi`](addi.md) — D-form add immediate without `XER[CA]`.
- [`addis`](addis.md) — shifted form (immediate << 16).
- [`addcx`](addcx.md) — XO-form: register operands, sets `XER[CA]`.
- [`subfic`](subfic.md) — D-form: `RT ← SIMM RA` with `XER[CA]`.
## IBM Reference
- [AIX 7.3 — `addic` (Add Immediate Carrying)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-addic-add-immediate-carrying-instruction)

View File

@@ -0,0 +1,132 @@
# `addic.` — Add Immediate Carrying and Record
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x34000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `addic.` | `addic.` | — | Add Immediate Carrying and Record |
## Syntax
```asm
addic. [RD], [RA], [SIMM]
```
## Encoding
### `addic.` — form `D`
- **Opcode word:** `0x34000000`
- **Primary opcode (bits 05):** `13`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | addic.: read | Source GPR (`r0``r31`). |
| `SIMM` | addic.: read | 16-bit signed immediate. Sign-extended to 64 bits before use. |
| `RD` | addic.: write | Destination GPR. |
| `CA` | addic.: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
| `CR` | addic.: write | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `addic.`
- **Reads (always):** `RA`, `SIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`, `CA`, `CR`
- **Writes (conditional):** _none_
## Status-Register Effects
- `addic.`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]` (always).; **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`addic.`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addic."`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:127`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L127)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:337`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L337)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:145-154`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L145-L154)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::addicx => {
// PPCBUG-003: same fix as addic plus CR0 i32 view.
let ra32 = ctx.gpr[instr.ra()] as u32;
let imm32 = instr.simm16() as i32 as u32;
let result32 = ra32.wrapping_add(imm32);
ctx.xer_ca = if result32 < ra32 { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
ctx.update_cr_signed(0, result32 as i32 as i64);
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`Rc` bit is implicit, not encoded.** `addic.` has its *own* primary opcode (13) distinct from `addic`'s (12); there is no `Rc` field to set. The two forms are sibling D-form instructions, not flag variants of one encoding.
- **CR0 update is unconditional.** Unlike XO-form `Rc=1` instructions, `addic.` always updates `CR0` from the result; the `.` is part of the mnemonic itself.
- **Common idiom: `addic. rN, rN, -1`** — decrements `rN` and sets `CR0[EQ]` when it reaches zero, in a single instruction. Frequently used as a loop counter (often paired with `bne+ loop`).
- **`XER[CA]` written same as [`addic`](addic.md).** The carry-out from the unsigned 64-bit add is recorded; the `.` only adds the CR update on top.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:65`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L65) computes `result as i32 as i64`; spec demands a full 64-bit compare-to-zero. The truncation is a documented xenia-rs quirk shared with the rest of the carrying-add family.
- **`SIMM` is sign-extended** to 64 bits before the add — `addic. r3, r4, -1` adds `~0` and never sets `CR0[EQ]` unless `r4 == 1`.
## Related Instructions
- [`addic`](addic.md) — same op without the CR0 update.
- [`addi`](addi.md), [`addis`](addis.md) — immediate adds without `XER[CA]`.
- [`addcx`](addcx.md) — XO-form register equivalent.
- [`subfic`](subfic.md) — `RT ← SIMM RA` with `XER[CA]` (no record form exists).
- [`cmpi`](cmpi.md) — explicit immediate compare when the carry side-effect would be unwanted.
## IBM Reference
- [AIX 7.3 — `addic.` (Add Immediate Carrying and Record)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-addic-add-immediate-carrying-record-instruction)

View File

@@ -0,0 +1,121 @@
# `addis` — Add Immediate Shifted
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x3c000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `addis` | `addis` | — | Add Immediate Shifted |
## Syntax
```asm
addis [RD], [RA0], [SIMM]
```
## Encoding
### `addis` — form `D`
- **Opcode word:** `0x3c000000`
- **Primary opcode (bits 05):** `15`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA0` | addis: read | Source GPR; when the encoded register number is 0 the operand is the literal 64-bit zero, **not** `r0`. |
| `SIMM` | addis: read | 16-bit signed immediate. Sign-extended to 64 bits before use. |
| `RD` | addis: write | Destination GPR. |
## Register Effects
### `addis`
- **Reads (always):** `RA0`, `SIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
if RA = 0 then RT <- EXTS(SIMM) << 16
else RT <- (RA) + (EXTS(SIMM) << 16)
```
## C Translation Example
```c
/* addis RT, RA, SIMM — RA=0 means literal 0 */
uint64_t base = (insn.RA == 0) ? 0 : r[insn.RA];
r[insn.RT] = base + ((uint64_t)(int64_t)(int16_t)insn.SIMM << 16);
```
## Implementation References
**`addis`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addis"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:138`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L138)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:339`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L339)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:121-134`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L121-L134)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::addis => {
// Xbox 360 user mode is 32-bit ABI (MSR.SF=0), so addis must
// produce a value whose upper 32 bits don't pollute downstream
// 64-bit arithmetic. The PPC ISA in 64-bit mode sign-extends
// simm16 before the shift, producing 0xFFFFFFFF_xxxx0000 for
// negative simm16 (high bit set). When this value flows into
// a 64-bit subfc against a zero-extended lwz value, the unsigned
// 64-bit comparison yields wrong CA. Truncate to 32 bits to
// simulate 32-bit ABI behavior.
let ra_val = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] };
let result = ra_val.wrapping_add((instr.simm16() as i64 as u64) << 16);
ctx.gpr[instr.rd()] = result as u32 as u64;
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA0` semantics.** When the `RA` field encodes 0, the operand is the literal 64-bit zero, **not** `r0`. This makes `addis RT, 0, hi16` the canonical "load high half" idiom. To use `r0`'s actual value as a base, copy it via `mr` first or use a different opcode.
- **Immediate is sign-extended *then* shifted left 16.** So `addis r3, 0, 0x8000` writes `0xFFFFFFFF80000000`, not `0x000000008000_0000`. The 32-bit sign extension surprise is the most common bug in hand-written PPC assembly.
- **Forms the high half of a 32-bit immediate.** The classic `lis rT, hi; ori rT, rT, lo` (or `lis`/`addi`) sequence builds a full 32-bit constant. `lis rT, val` is a simplified mnemonic for `addis rT, 0, val`.
- **No `XER[CA]`, no `XER[OV]`, no `Rc`.** This instruction has no status side-effects whatsoever. Use [`addic`](addic.md) or [`addcx`](addcx.md) if a carry is required.
- **64-bit `RA` operand.** The shift-and-add is 64-bit on the Xenon; the immediate's sign-extension fills the high 48 bits. So `addis r3, r4, -1` adds `0xFFFFFFFFFFFF0000` to a 64-bit `r4`.
- **No overflow detection.** `lis r3, 0x7FFF; addis r3, r3, 0x7FFF` happily wraps without comment.
## Related Instructions
- [`addi`](addi.md) — D-form add immediate, no shift; same `RA0` rule.
- [`addic`](addic.md), [`addicx`](addicx.md) — immediate adds that also write `XER[CA]`.
- [`oris`](oris.md), [`ori`](ori.md) — pair with `addis`/`lis` to build 32-bit constants without affecting CR or XER.
- [`addx`](addx.md), [`addcx`](addcx.md) — XO-form register adds.
- `lis` (simplified) — assembler shorthand for `addis RT, 0, value`.
## IBM Reference
- [AIX 7.3 — `addis` (Add Immediate Shifted)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-addis-add-immediate-shifted-instruction)
- [AIX 7.3 — `lis` (Load Immediate Shifted, simplified mnemonic)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-li-lis-load-immediate-load-immediate-shifted)

View File

@@ -0,0 +1,136 @@
# `addmex` — Add to Minus One Extended
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c0001d4`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `addme` | `addmex` | — | Add to Minus One Extended |
| `addmeo` | `addmex` | OE=1 | Add to Minus One Extended |
| `addme.` | `addmex` | Rc=1 | Add to Minus One Extended |
| `addmeo.` | `addmex` | OE=1, Rc=1 | Add to Minus One Extended |
## Syntax
```asm
addme[OE][Rc] [RD], [RA]
```
## Encoding
### `addmex` — form `XO`
- **Opcode word:** `0x7c0001d4`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `234`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | addmex: read | Source GPR (`r0``r31`). |
| `CA` | addmex: read; addmex: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
| `RD` | addmex: write | Destination GPR. |
| `OE` | addmex: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
| `CR` | addmex: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `addmex`
- **Reads (always):** `RA`, `CA`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`, `CA`
- **Writes (conditional):** `OE`, `CR`
## Status-Register Effects
- `addmex`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.; **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
RT <- (RA) + CA + 0xFFFF_FFFF_FFFF_FFFF
CA <- carry_out
```
## 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
**`addmex`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addmex"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:152`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L152)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:873`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L873)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:239-254`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L239-L254)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::addmex => {
// PPCBUG-016+020: 32-bit truncation. RT = RA + CA - 1.
let ra32 = ctx.gpr[instr.ra()] as u32;
let ca = ctx.xer_ca as u32;
let result32 = ra32.wrapping_add(ca).wrapping_sub(1);
ctx.xer_ca = if ra32 != 0 || ca != 0 { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
let true_sum = (ra32 as i32 as i128) + (ca as i128) - 1;
overflow::apply(ctx, true_sum != (result32 as i32) as i128);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **No `RB` field used.** `addmex` is encoded in XO-form but ignores the `RB` slot — assemblers must still emit a value (typically zero). Disassemblers that parse a non-zero `RB` should not flag it as illegal; it is simply unused.
- **Operation is `RA + CA + (1)`**, i.e. `RA - 1 + CA`. Used to terminate a multi-word *subtract* chain when the high source word is implicitly all-ones (e.g. computing `-x` as `~x + 1` across 128 bits).
- **Carry-out predicate is `RA != 0 OR CA != 0`.** Equivalently, `CA' = NOT(RA == 0 AND CA == 0)`. Adding `1` to anything except a zero-with-no-carry produces a carry-out (no borrow needed). This terse form in xenia-rs is correct but easy to misread.
- **Overflow not implemented in xenia-rs.** The `OE=1` path is silently a no-op; spec says set `XER[OV]` if the signed result wraps.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:139`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L139) — same quirk as the rest of the add family.
- **`XER[CA]` must be initialised** by an earlier carrying instruction. `addme` is a *terminator*, not a seed.
## Related Instructions
- [`addzex`](addzex.md) — terminate a chain with `RA + 0 + CA` (no `1`).
- [`addex`](addex.md) — middle-of-chain `RA + RB + CA`.
- [`addcx`](addcx.md) — seeds a chain.
- [`subfmex`](subfmex.md) — subtract dual: `~RA + (1) + CA`.
- [`negx`](negx.md) — single-instruction two's-complement negate.
## IBM Reference
- [AIX 7.3 — `addme` (Add to Minus One Extended)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-addme-add-minus-one-extended-instruction)

View File

@@ -0,0 +1,148 @@
# `addx` — Add
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000214`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `add` | `addx` | — | Add |
| `addo` | `addx` | OE=1 | Add |
| `add.` | `addx` | Rc=1 | Add |
| `addo.` | `addx` | OE=1, Rc=1 | Add |
## Syntax
```asm
add[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `addx` — form `XO`
- **Opcode word:** `0x7c000214`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `266`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | addx: read | Source GPR (`r0``r31`). |
| `RB` | addx: read | Source GPR. |
| `RD` | addx: write | Destination GPR. |
| `OE` | addx: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
| `CR` | addx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `addx`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `OE`, `CR`
## Status-Register Effects
- `addx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- (RA) + (RB)
```
## C Translation Example
```c
/* add / add. / addo / addo. (XO-form) */
uint64_t a = r[insn.RA], b = r[insn.RB];
uint64_t result = a + b;
r[insn.RT] = result;
if (insn.OE) { bool ov = (~(a ^ b) & (a ^ result)) >> 63;
if (ov) { xer.OV = 1; xer.SO = 1; } else xer.OV = 0; }
if (insn.Rc) update_cr0_signed((int64_t)result);
```
## Implementation References
**`addx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:50`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L50)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:875`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L875)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:175-189`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L175-L189)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::addx => {
// PPCBUG-012+020: 32-bit ABI writeback truncation + CR0 i32 view.
let ra32 = ctx.gpr[instr.ra()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
let result32 = ra32.wrapping_add(rb32);
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
let true_sum = (ra32 as i32 as i128) + (rb32 as i32 as i128);
overflow::apply(ctx, true_sum != (result32 as i32) as i128);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Extended Pseudocode
```
RT <- (RA) + (RB) ; modulo 2^64, carry discarded
if OE then
XER[OV] <- (~(RA ^ RB) & (RA ^ RT))[0] ; signed overflow: same-sign inputs, opposite-sign result
XER[SO] <- XER[SO] | XER[OV]
if Rc then
CR0[LT,GT,EQ] <- signed_compare(RT, 0) ; 64-bit comparison on the Xenon
CR0[SO] <- XER[SO]
```
## Special Cases & Edge Conditions
- **No trap on overflow.** `addo` / `addo.` record overflow in `XER[OV]` and sticky-set `XER[SO]`. A trap can only be produced by a separate `td`/`tw` instruction examining the result.
- **Signed-overflow predicate.** Overflow occurs iff both addends share a sign bit and the result has the opposite sign bit: `OV = ((~(a ^ b)) & (a ^ rt)) >> 63`. Unsigned carry is *not* tracked — use [`addcx`](addcx.md) when you need `XER[CA]`.
- **`XER[SO]` is sticky.** Once set, it remains set until cleared by `mcrxr`. The `.` record forms copy it into `CR0[SO]`.
- **64-bit CR update on Xenon.** The Xbox 360 Xenon CPU is 64-bit, so `add.` compares the full 64-bit result against zero. **Xenia-rs presently truncates to 32 bits** before the CR update (`result as i32 as i64` in [`interpreter.rs:95`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L95)). If your translator must match xenia bit-for-bit, emit a 32-bit compare; if it must be spec-correct, emit a 64-bit compare. Most Xbox 360 object code works either way because results that overflow 32 bits are rare outside of explicit 64-bit math.
- **OE overflow detection not emulated in xenia-rs.** The `addo` / `addo.` branch in `interpreter.rs` is a `TODO` stub. A faithful translator should still emit the overflow check — titles rarely observe `XER[OV]`, but it's occasionally used by profiling / sanity-checking code paths.
- **Operand aliasing.** `add r3, r3, r3`, `add r3, r3, r4`, `add r3, r4, r3` are all legal. The addition reads both source operands before writing `RT`.
- **No immediate form.** For `RT = RA + imm` use [`addi`](addi.md) / [`addis`](addis.md). Those are distinct opcodes, not a flag on `add`.
## Related Instructions
- [`addcx`](addcx.md) — produces the carry-out in `XER[CA]`.
- [`addex`](addex.md) — sums `(RA) + (RB) + XER[CA]` (carry-in chain).
- [`addmex`](addmex.md), [`addzex`](addzex.md) — add to `1` or `0` with carry-in (used to propagate borrows across multiword subtracts).
- [`addi`](addi.md), [`addis`](addis.md) — D-form immediate adds; no `Rc`/`OE`.
- [`addic`](addic.md), [`addicx`](addicx.md) — D-form adds that set `XER[CA]`.
- [`subfx`](subfx.md) — the dual: `RT ← (RB) (RA)`.
- [`negx`](negx.md) — two's-complement negate.
## IBM Reference
- [AIX 7.3 — `add` (Add)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-add-instruction)
- [PowerISA v2.07B, Book I, §3.3.8 — Fixed-Point Arithmetic Instructions](https://openpowerfoundation.org/specifications/isa/) (overflow predicate, CR0 / `XER[SO]` semantics).

View File

@@ -0,0 +1,135 @@
# `addzex` — Add to Zero Extended
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000194`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `addze` | `addzex` | — | Add to Zero Extended |
| `addzeo` | `addzex` | OE=1 | Add to Zero Extended |
| `addze.` | `addzex` | Rc=1 | Add to Zero Extended |
| `addzeo.` | `addzex` | OE=1, Rc=1 | Add to Zero Extended |
## Syntax
```asm
addze[OE][Rc] [RD], [RA]
```
## Encoding
### `addzex` — form `XO`
- **Opcode word:** `0x7c000194`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `202`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | addzex: read | Source GPR (`r0``r31`). |
| `CA` | addzex: read; addzex: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
| `RD` | addzex: write | Destination GPR. |
| `OE` | addzex: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
| `CR` | addzex: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `addzex`
- **Reads (always):** `RA`, `CA`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`, `CA`
- **Writes (conditional):** `OE`, `CR`
## Status-Register Effects
- `addzex`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.; **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
RT <- (RA) + CA
CA <- carry_out
```
## 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
**`addzex`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addzex"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:172`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L172)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:870`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L870)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:223-238`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L223-L238)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::addzex => {
// PPCBUG-015+020: 32-bit truncation.
let ra32 = ctx.gpr[instr.ra()] as u32;
let ca = ctx.xer_ca as u32;
let result32 = ra32.wrapping_add(ca);
ctx.xer_ca = if result32 < ra32 { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
let true_sum = (ra32 as i32 as i128) + (ca as i128);
overflow::apply(ctx, true_sum != (result32 as i32) as i128);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **No `RB` field used.** Like [`addmex`](addmex.md), this XO-form instruction ignores the `RB` slot. Assemblers emit zero there.
- **Operation is `RA + 0 + CA``RA + CA`.** Used to terminate the *high word* of a multi-word add chain seeded by [`addcx`](addcx.md). After the low-word `addc` produces the carry, all middle words use [`addex`](addex.md), and the final word that has no register operand uses `addze`.
- **Carry-out is the simple unsigned overflow test** `result < ra` — same predicate as [`addcx`](addcx.md). `CA' = 1` only if `RA == ~0 && CA == 1`.
- **`OE=1` not implemented in xenia-rs.** The interpreter has no overflow branch at all; spec asks for the standard signed-overflow detect.
- **64-bit CR update on Xenon, 32-bit in xenia-rs** (truncation in [`interpreter.rs:128`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L128) — see [`addx`](addx.md) for context).
- **Common idiom: extracting a carry as a 0/1.** `addze rT, 0` (or `addze rT, rN` where `rN == 0`) materialises `XER[CA]` into `rT` as a plain integer.
## Related Instructions
- [`addmex`](addmex.md) — terminate with `RA + (1) + CA` instead of `+0`.
- [`addex`](addex.md) — middle of a multi-word add chain.
- [`addcx`](addcx.md) — seeds the chain.
- [`subfzex`](subfzex.md) — subtract dual: `~RA + 0 + CA`.
## IBM Reference
- [AIX 7.3 — `addze` (Add to Zero Extended)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-addze-add-zero-extended-instruction)

View File

@@ -0,0 +1,123 @@
# `andcx` — AND with Complement
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000078`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `andc` | `andcx` | — | AND with Complement |
| `andc.` | `andcx` | Rc=1 | AND with Complement |
## Syntax
```asm
andc[Rc] [RA], [RS], [RB]
```
## Encoding
### `andcx` — form `X`
- **Opcode word:** `0x7c000078`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `60`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | andcx: read | Source GPR (alias for RD in some stores). |
| `RB` | andcx: read | Source GPR. |
| `RA` | andcx: write | Source GPR (`r0``r31`). |
| `CR` | andcx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `andcx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `andcx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- (RS) & ~(RB)
```
## 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
**`andcx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andcx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:647`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L647)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:9`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L9)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:768`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L768)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:534-541`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L534-L541)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::andcx => {
// PPCBUG-033: !rb on u64 flips upper 32 bits — active poisoning.
let rs32 = ctx.gpr[instr.rs()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
ctx.gpr[instr.ra()] = (rs32 & !rb32) as u64;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`andc RA, RS, RB` computes `RS AND (NOT RB)`.** The complement is applied to `RB`, not `RS`. Useful for clearing a bitmask: `andc r3, r3, r4` clears in `r3` every bit set in `r4`.
- **Common idiom: `andc r3, r3, r3`** zeroes `r3` (every bit ANDed with its own complement). Cheaper-looking than `xor r3, r3, r3` on some pipelines but functionally identical; the assembler often prefers the `xor` idiom.
- **Operand convention is the X-form one** (`RA` is the destination, `RS` and `RB` are sources). Same gotcha as [`andx`](andx.md).
- **No `OE`/`XER` side effects.** Only `CR0` is updated when `Rc=1`.
- **64-bit operation** on Xenon; the AND is computed across all 64 bits of `RS` and `~RB`. Xenia-rs uses Rust's bitwise `!` on `u64`, which is the correct full-width complement.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:352`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L352) — same truncation pattern.
## Related Instructions
- [`andx`](andx.md) — plain AND (no complement).
- [`nandx`](nandx.md) — NAND (`~(RS & RB)`).
- [`orcx`](orcx.md) — OR with complement; sister `c` form.
- [`eqvx`](eqvx.md) — `~(RS ^ RB)` (NXOR / equivalence).
- [`norx`](norx.md) — NOR.
## IBM Reference
- [AIX 7.3 — `andc` (AND with Complement)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-andc-complement-instruction)

View File

@@ -0,0 +1,127 @@
# `andis.` — AND Immediate Shifted
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x74000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `andis.` | `andis.` | — | AND Immediate Shifted |
## Syntax
```asm
andis. [RA], [RS], [UIMM]
```
## Encoding
### `andis.` — form `D`
- **Opcode word:** `0x74000000`
- **Primary opcode (bits 05):** `29`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | andis.: read | Source GPR (alias for RD in some stores). |
| `UIMM` | andis.: read | 16-bit unsigned immediate. Zero-extended. |
| `RA` | andis.: write | Source GPR (`r0``r31`). |
| `CR` | andis.: write | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `andis.`
- **Reads (always):** `RS`, `UIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`, `CR`
- **Writes (conditional):** _none_
## Status-Register Effects
- `andis.`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]` (always).
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`andis.`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andis."`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:665`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L665)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:9`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L9)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:352`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L352)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:505-511`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L505-L511)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::andisx => {
// PPCBUG-023: 32-bit ABI CR0 view. `andis. rA, rS, 0x8000` to test
// sign bit of a 32-bit word now correctly classifies bit 31 = 1 as LT.
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] & ((instr.uimm16() as u64) << 16);
ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64);
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Always `Rc=1`.** Like [`andix`](andix.md), the dot is part of the mnemonic; no plain `andis` exists.
- **Immediate is shifted left 16, zero-extended.** Effective mask is `(UIMM << 16) & 0xFFFFFFFF`, so the only bits that can survive in `RA` are bits 3247 (in PowerISA bit numbering, equivalent to bits 1631 of the low 32 bits) of `RS`. Bits 031 and bits 4863 of `RA` are forced to zero.
- **Together with `andi.` covers the entire low 32 bits.** Any 32-bit mask can be applied with `andis. + andi.` (two instructions). Larger masks need `rlwinm` or a constructed register operand to [`andx`](andx.md).
- **High 32 bits of result are always zero.** Because the immediate is at bits 3247, no information from `RS[0:31]` survives. Useful as a quick "extract bits 3247, zero the rest" primitive.
- **CR0 update is unconditional** and uses the standard signed-compare-to-zero semantics with `XER[SO]` folded into `SO`.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** The `result as i32 as i64` truncation in [`interpreter.rs:326`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L326) is harmless: the result is bounded by `0x00000000_FFFF0000`, which fits the 32-bit window exactly.
## Related Instructions
- [`andix`](andix.md) — companion (immediate not shifted).
- [`andx`](andx.md), [`andcx`](andcx.md) — register AND.
- [`oris`](oris.md), [`xoris`](xoris.md) — sister immediate-shifted logicals.
- [`rlwinmx`](rlwinmx.md) — full mask-and-rotate when the bits of interest aren't aligned to a 16-bit boundary.
## IBM Reference
- [AIX 7.3 — `andis.` (AND Immediate Shifted)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-andis-immediate-shifted-instruction)

View File

@@ -0,0 +1,126 @@
# `andi.` — AND Immediate
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x70000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `andi.` | `andi.` | — | AND Immediate |
## Syntax
```asm
andi. [RA], [RS], [UIMM]
```
## Encoding
### `andi.` — form `D`
- **Opcode word:** `0x70000000`
- **Primary opcode (bits 05):** `28`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | andi.: read | Source GPR (alias for RD in some stores). |
| `UIMM` | andi.: read | 16-bit unsigned immediate. Zero-extended. |
| `RA` | andi.: write | Source GPR (`r0``r31`). |
| `CR` | andi.: write | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `andi.`
- **Reads (always):** `RS`, `UIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`, `CR`
- **Writes (conditional):** _none_
## Status-Register Effects
- `andi.`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]` (always).
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`andi.`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andi."`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:657`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L657)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:9`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L9)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:351`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L351)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:499-504`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L499-L504)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::andix => {
// PPCBUG-020: 32-bit ABI CR0 view.
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] & (instr.uimm16() as u64);
ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64);
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Always `Rc=1`.** There is no `andi` (without the dot). The mnemonic is `andi.` and the encoding always updates `CR0`. If you need a non-record AND-with-immediate, you have to materialise the immediate first (e.g. with `li`/`lis`) and use [`andx`](andx.md).
- **Immediate is zero-extended.** The 16-bit `UIMM` is widened with zeros, so `andi. rA, rS, 0xFFFF` masks `rS` to its low 16 bits — the high 48 bits of the 64-bit register are forced to zero.
- **Cannot mask the high half of a register in one instruction.** The immediate covers bits 4863 only; for higher bits use [`andisx`](andisx.md) (covers bits 3247) or compose with `rlwinm`/`rldicl`.
- **CR0 update is unconditional.** This is part of the encoding, not a flag — the primary opcode (28) *is* `andi.`.
- **Common idiom: `andi. r0, rN, mask`** to test bits without disturbing the source — but note `r0` is overwritten and `CR0` is set. If you only need the CR result, prefer `extrwi`/`rlwinm.` for arbitrary masks.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** Since the AND result has zeros in bits 047, the low-32 truncation in [`interpreter.rs:321`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L321) is harmless here — the result fits in 16 bits, so spec and xenia agree.
## Related Instructions
- [`andisx`](andisx.md) — same op with immediate shifted left 16 (covers bits 3247).
- [`andx`](andx.md), [`andcx`](andcx.md) — register AND family.
- [`ori`](ori.md), [`oris`](oris.md), [`xori`](xori.md), [`xoris`](xoris.md) — sister immediate logicals (notably *without* a record form).
- [`rlwinmx`](rlwinmx.md) — for masks that don't fit into a 16-bit immediate.
## IBM Reference
- [AIX 7.3 — `andi.` (AND Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-andi-immediate-instruction)

View File

@@ -0,0 +1,122 @@
# `andx` — AND
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000038`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `and` | `andx` | — | AND |
| `and.` | `andx` | Rc=1 | AND |
## Syntax
```asm
and[Rc] [RA], [RS], [RB]
```
## Encoding
### `andx` — form `X`
- **Opcode word:** `0x7c000038`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `28`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | andx: read | Source GPR (alias for RD in some stores). |
| `RB` | andx: read | Source GPR. |
| `RA` | andx: write | Source GPR (`r0``r31`). |
| `CR` | andx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `andx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `andx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- (RS) & (RB)
```
## 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
**`andx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:637`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L637)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:9`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L9)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:760`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L760)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:528-533`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L528-L533)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::andx => {
// PPCBUG-032+020: 32-bit ABI CR0 view (latent under clean inputs).
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] & ctx.gpr[instr.rb()];
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operand convention is reversed.** Unlike the arithmetic XO-form (`add RT, RA, RB`), the logical X-form writes `RA` and reads `RS`/`RB`: `and RA, RS, RB`. The destination is the **second** operand encoded. This convention applies to the entire and/or/xor family; mixing them up is a frequent disassembly error.
- **No `OE`, no `XER[CA]`, no `XER[OV]`.** Logical operations never affect XER. Only `Rc=1` updates `CR0` (signed compare against zero, with `SO ← XER[SO]`).
- **64-bit AND on Xenon.** Both inputs are 64-bit GPRs; the result is the bitwise AND of all 64 bits.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** The interpreter's `Rc=1` path in [`interpreter.rs:347`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L347) compares `result as i32 as i64`. For an AND whose high 32 bits are non-zero but low 32 bits are zero (e.g. `r3 = 0x1_0000_0000`, `and. r4, r3, r3`), spec sets CR0 to GT but xenia would set EQ. Flag this if reproducing CR-sensitive behaviour.
- **Operand aliasing.** `and RA, RA, RA` is a no-op except for the optional CR0 update — this is the canonical "test register against zero" pattern when no `cmpwi` is desired (though `cmpwi` is more typical).
- **No simplified mnemonic for AND-immediate.** Use [`andix`](andix.md) (`andi.`) or [`andisx`](andisx.md) (`andis.`) for immediate operands; both are *always* record forms (no plain `andi`).
## Related Instructions
- [`andcx`](andcx.md) — AND with complement: `RA ← RS & ~RB`.
- [`andix`](andix.md), [`andisx`](andisx.md) — D-form AND immediate (always `Rc=1`).
- [`nandx`](nandx.md) — NAND.
- [`orx`](orx.md), [`orcx`](orcx.md), [`xorx`](xorx.md), [`eqvx`](eqvx.md), [`norx`](norx.md) — sister logical instructions.
- [`cmp`](cmp.md), [`cmpi`](cmpi.md) — explicit zero/value test when CR-only effect is wanted without overwriting `RA`.
## IBM Reference
- [AIX 7.3 — `and` (AND)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-instruction)
- [AIX 7.3 — Reference: PowerPC instruction set](https://www.ibm.com/docs/en/aix/7.3.0?topic=reference-instruction-set)

View File

@@ -0,0 +1,153 @@
# `cmp` — Compare
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `cmp` | `cmp` | — | Compare |
## Syntax
```asm
cmp [CRFD], [L], [RA], [RB]
```
## Encoding
### `cmp` — form `X`
- **Opcode word:** `0x7c000000`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `0`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `L` | cmp: read | Operand-length bit for compare instructions (`0 ⇒ 32-bit`, `1 ⇒ 64-bit`). |
| `RA` | cmp: read | Source GPR (`r0``r31`). |
| `RB` | cmp: read | Source GPR. |
| `CRFD` | cmp: write | CR destination field (`crf`, 07). |
## Register Effects
### `cmp`
- **Reads (always):** `L`, `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `CRFD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
if L = 0 then a,b <- EXTS((RA)[32:63]), EXTS((RB)[32:63])
else a,b <- (RA), (RB)
CR[BF] <- signed_compare(a, b) || XER[SO]
```
## 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
**`cmp`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmp"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:523`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L523)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:13`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L13)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:749`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L749)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:863-885`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L863-L885)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::cmp => {
let bf = instr.crfd();
if instr.l() {
let ra = ctx.gpr[instr.ra()] as i64;
let rb = ctx.gpr[instr.rb()] as i64;
ctx.cr[bf] = crate::context::CrField {
lt: ra < rb,
gt: ra > rb,
eq: ra == rb,
so: ctx.xer_so != 0,
};
} else {
let ra = ctx.gpr[instr.ra()] as i32;
let rb = ctx.gpr[instr.rb()] as i32;
ctx.cr[bf] = crate::context::CrField {
lt: ra < rb,
gt: ra > rb,
eq: ra == rb,
so: ctx.xer_so != 0,
};
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Extended Pseudocode
```
if L = 0 then ; 32-bit compare
a <- EXTS((RA)[32:63]) ; sign-extend low word to 64
b <- EXTS((RB)[32:63])
else ; 64-bit compare
a <- (RA)
b <- (RB)
CR[BF] <- { LT: a <s b, GT: a >s b, EQ: a = b, SO: XER[SO] } ; signed
```
## Special Cases & Edge Conditions
- **`BF` is a CR field (07), not a bit.** The `crfD` operand encodes which of the eight 4-bit CR fields is updated. Assemblers write it as `crN` where `N ∈ 0..7`. The simplified mnemonic `cmpw RA, RB``cmp cr0, 0, RA, RB` is universal in Xbox 360 code.
- **`L` bit selects width.** `L = 0` (the usual `cmpw` / `cmpd`-is-rare path) performs a *32-bit* signed compare of `RA[32:63]` and `RB[32:63]`, both sign-extended to 64 bits. `L = 1` (`cmpd`) performs a full 64-bit signed compare.
- **Signed.** Use [`cmpl`](cmpl.md) / [`cmpli`](cmpli.md) for unsigned comparisons. Confusing signed/unsigned is the most common compare-family bug in hand-written asm.
- **SO is always copied from `XER[SO]`.** This makes overflow observable across arithmetic/compare sequences: an `addo.` followed by `beq` can branch on the record-form flag while `bso` can inspect the sticky overflow.
- **`cr0` is the default for record-form ALU**; by convention assemblers and generators reserve `cr0` for the chain of `Rc=1` instructions and use `cr1..cr7` (or `cmp` to an explicit field) for standalone compares. Don't assume `cmp` writes `cr0` unless the `BF` operand says so.
- **No register is written** beyond the 4-bit CR field. `cmp` has no `Rc` or `OE` bit.
- **Xenia-rs quirk.** The interpreter recomputes `EQ` after the signed compare to guard against a subtract-cancellation edge case; this is a defensive belt-and-braces against the 32-bit narrowing path. Functionally equivalent to the spec.
## Related Instructions
- [`cmpi`](cmpi.md) — signed compare against a 16-bit immediate.
- [`cmpl`](cmpl.md), [`cmpli`](cmpli.md) — unsigned versions.
- [`cmpw`](cmp.md), [`cmpd`](cmp.md) — simplified mnemonics selecting `L`.
- [`mcrxr`](mcrxr.md) — move `XER[SO..CA]` into a CR field and clear them; used to reset sticky overflow.
- Every `Rc=1` ALU instruction ([`addx`](addx.md), [`subfx`](subfx.md), [`andx`](andx.md), …) — these implicitly perform a signed-compare-to-zero into `cr0`; use explicit `cmp` only when comparing two non-zero values or using a non-zero CR field.
## IBM Reference
- [AIX 7.3 — `cmp` (Compare)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-cmp-compare-instruction)
- [AIX 7.3 — `cmpw` / `cmpd` (simplified mnemonics)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-cmpw-compare-word)

View File

@@ -0,0 +1,143 @@
# `cmpi` — Compare Immediate
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x2c000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `cmpi` | `cmpi` | — | Compare Immediate |
## Syntax
```asm
cmpi [CRFD], [L], [RA], [SIMM]
```
## Encoding
### `cmpi` — form `D`
- **Opcode word:** `0x2c000000`
- **Primary opcode (bits 05):** `11`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `L` | cmpi: read | Operand-length bit for compare instructions (`0 ⇒ 32-bit`, `1 ⇒ 64-bit`). |
| `RA` | cmpi: read | Source GPR (`r0``r31`). |
| `SIMM` | cmpi: read | 16-bit signed immediate. Sign-extended to 64 bits before use. |
| `RD` | cmpi: write | Destination GPR. |
| `CRFD` | cmpi: write | CR destination field (`crf`, 07). |
## Register Effects
### `cmpi`
- **Reads (always):** `L`, `RA`, `SIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`, `CRFD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
if L = 0 then a,b <- EXTS((RA)[32:63]), EXTS(SIMM)
else a,b <- (RA), EXTS(SIMM)
CR[BF] <- signed_compare(a, b) || XER[SO]
```
## 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
**`cmpi`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmpi"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:552`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L552)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:13`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L13)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:335`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L335)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:824-849`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L824-L849)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::cmpi => {
let bf = instr.crfd();
if instr.l() {
// 64-bit compare. Compare directly so boundary i64 values
// (e.g. ra=i64::MIN, imm=1) don't mis-sign through a
// wrapped subtract.
let ra = ctx.gpr[instr.ra()] as i64;
let imm = instr.simm16() as i64;
ctx.cr[bf] = crate::context::CrField {
lt: ra < imm,
gt: ra > imm,
eq: ra == imm,
so: ctx.xer_so != 0,
};
} else {
let ra = ctx.gpr[instr.ra()] as i32;
let imm = instr.simm16() as i32;
ctx.cr[bf] = crate::context::CrField {
lt: ra < imm,
gt: ra > imm,
eq: ra == imm,
so: ctx.xer_so != 0,
};
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Immediate is sign-extended.** `SIMM` is treated as a signed 16-bit value in the range `[-32768, 32767]` and sign-extended to the operand width. Use [`cmpli`](cmpli.md) for unsigned comparisons against a 16-bit value.
- **`L` bit selects width.** `L = 0` (the usual `cmpwi`) compares the low 32 bits of `RA` (sign-extended) against `EXTS(SIMM)`; `L = 1` (`cmpdi`) does a full 64-bit signed compare. Most Xbox 360 code uses `cmpwi` because pointers and counters are 32-bit ABI.
- **Simplified mnemonics dominate disassembly.** `cmpwi crN, RA, SIMM``cmpi crN, 0, RA, SIMM` and `cmpdi crN, RA, SIMM``cmpi crN, 1, RA, SIMM`. The default CR field is `cr0` if omitted.
- **`BF` is a CR field (07), not a bit.** Same convention as [`cmp`](cmp.md). Distinct standalone compares should target `cr1..cr7` to avoid clobbering the implicit `cr0` chain set up by `Rc=1` arithmetic.
- **SO is copied from `XER[SO]`.** This makes overflow observable downstream of an `addo.` / `mulo.` etc. via `bso`/`bns`.
- **Xenia-rs quirk.** The interpreter recomputes `EQ` after the signed subtract, defending against the same 32-bit narrowing edge case noted in [`cmp`](cmp.md). Functionally equivalent to spec.
- **No register written** other than the 4-bit CR field — there is no `Rc` or `OE` bit.
## Related Instructions
- [`cmp`](cmp.md) — register-register signed compare.
- [`cmpli`](cmpli.md) — unsigned compare against immediate (zero-extended).
- [`cmpl`](cmpl.md) — unsigned register compare.
- `cmpwi`, `cmpdi` (simplified mnemonics) — select `L=0` / `L=1`.
- [`mcrxr`](mcrxr.md) — clear sticky overflow before a fresh compare sequence.
## IBM Reference
- [AIX 7.3 — `cmpi` (Compare Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-cmpi-compare-immediate-instruction)
- [AIX 7.3 — `cmpwi` / `cmpdi` (simplified mnemonics)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-cmpwi-compare-word-immediate)

View File

@@ -0,0 +1,127 @@
# `cmpl` — Compare Logical
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000040`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `cmpl` | `cmpl` | — | Compare Logical |
## Syntax
```asm
cmpl [CRFD], [L], [RA], [RB]
```
## Encoding
### `cmpl` — form `X`
- **Opcode word:** `0x7c000040`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `32`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `L` | cmpl: read | Operand-length bit for compare instructions (`0 ⇒ 32-bit`, `1 ⇒ 64-bit`). |
| `RA` | cmpl: read | Source GPR (`r0``r31`). |
| `RB` | cmpl: read | Source GPR. |
| `CRFD` | cmpl: write | CR destination field (`crf`, 07). |
## Register Effects
### `cmpl`
- **Reads (always):** `L`, `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `CRFD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
if L = 0 then a,b <- (RA)[32:63], (RB)[32:63]
else a,b <- (RA), (RB)
CR[BF] <- unsigned_compare(a, b) || XER[SO]
```
## 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
**`cmpl`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmpl"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:579`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L579)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:13`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L13)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:761`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L761)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:886-894`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L886-L894)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::cmpl => {
let bf = instr.crfd();
if instr.l() {
ctx.update_cr_unsigned(bf, ctx.gpr[instr.ra()], ctx.gpr[instr.rb()]);
} else {
ctx.update_cr_unsigned(bf, ctx.gpr[instr.ra()] as u32 as u64, ctx.gpr[instr.rb()] as u32 as u64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Unsigned compare.** Treats both operands as unsigned magnitudes. The simplified mnemonics are `cmplw` (`L=0`) and `cmpld` (`L=1`).
- **`L = 0`: 32-bit operands.** Xenia narrows both registers via `as u32 as u64` so the high 32 bits of `RA`/`RB` are ignored — this matches spec `(RA)[32:63]` semantics. Most Xbox 360 code uses this mode.
- **`L = 1`: full 64-bit unsigned compare.** Used in 64-bit pointer arithmetic; rare in game code but appears in kernel-side helpers.
- **SO is copied from `XER[SO]`.** `cmpl` does not clear or set sticky overflow; it just exposes the current `SO` in the destination CR field's `SO` slot.
- **`BF` is a CR field 07.** Same convention as [`cmp`](cmp.md). Two consecutive `cmpl` instructions with the same `BF` simply overwrite the previous result.
- **Common signed/unsigned bug.** Misusing `cmp` instead of `cmpl` (or vice versa) for pointer comparisons is the canonical bug in PPC porting; pointers are always unsigned in C semantics. Always cross-check the comparison polarity in disassembly.
- **No `Rc`/`OE`** and no GPR write — purely a CR-field producer.
## Related Instructions
- [`cmp`](cmp.md) — signed register compare.
- [`cmpli`](cmpli.md) — unsigned compare against a 16-bit immediate.
- [`cmpi`](cmpi.md) — signed immediate compare.
- `cmplw`, `cmpld` (simplified) — preferred forms in disassembly.
- [`mcrxr`](mcrxr.md) — clear sticky overflow.
## IBM Reference
- [AIX 7.3 — `cmpl` (Compare Logical)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-cmpl-compare-logical-instruction)
- [AIX 7.3 — `cmplw` / `cmpld` (simplified mnemonics)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-cmplw-compare-logical-word)

View File

@@ -0,0 +1,127 @@
# `cmpli` — Compare Logical Immediate
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x28000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `cmpli` | `cmpli` | — | Compare Logical Immediate |
## Syntax
```asm
cmpli [CRFD], [L], [RA], [UIMM]
```
## Encoding
### `cmpli` — form `D`
- **Opcode word:** `0x28000000`
- **Primary opcode (bits 05):** `10`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `L` | cmpli: read | Operand-length bit for compare instructions (`0 ⇒ 32-bit`, `1 ⇒ 64-bit`). |
| `RA` | cmpli: read | Source GPR (`r0``r31`). |
| `UIMM` | cmpli: read | 16-bit unsigned immediate. Zero-extended. |
| `CRFD` | cmpli: write | CR destination field (`crf`, 07). |
## Register Effects
### `cmpli`
- **Reads (always):** `L`, `RA`, `UIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `CRFD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
if L = 0 then a,b <- (RA)[32:63], UIMM
else a,b <- (RA), (0 || UIMM)
CR[BF] <- unsigned_compare(a, b) || XER[SO]
```
## 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
**`cmpli`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmpli"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:608`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L608)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:13`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L13)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:334`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L334)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:850-862`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L850-L862)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::cmpli => {
let bf = instr.crfd();
if instr.l() {
let ra = ctx.gpr[instr.ra()];
let imm = instr.uimm16() as u64;
ctx.update_cr_unsigned(bf, ra, imm);
} else {
let ra = ctx.gpr[instr.ra()] as u32 as u64;
let imm = instr.uimm16() as u64;
ctx.update_cr_unsigned(bf, ra, imm);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Immediate is zero-extended.** `UIMM` is a 16-bit value extended with zeros, so the comparable range is `[0, 65535]`. To compare against a value with high bits set, materialise it in a register with `lis`/`ori` and use [`cmpl`](cmpl.md).
- **`L` bit selects width.** `L = 0` (`cmplwi`) zero-extends `RA[32:63]` to 64 bits and compares against the 16-bit immediate (also zero-extended). `L = 1` (`cmpldi`) compares the full 64-bit `RA` against the immediate.
- **Simplified mnemonics dominate.** `cmplwi cr0, RA, UIMM``cmpli cr0, 0, RA, UIMM`; the assembler injects the `L` bit automatically.
- **No sign-extension surprises.** Unlike [`cmpi`](cmpi.md), the immediate cannot be negative; `cmpli` always tests an unsigned magnitude.
- **Common idiom: `cmplwi rA, 0`** to test a register for zero — slightly clearer in disassembly than `cmpwi rA, 0` because it doesn't suggest signed semantics. Both produce the same `EQ` result for a zero argument.
- **`BF` chooses one of 8 CR fields**; same convention as `cmp`.
## Related Instructions
- [`cmpl`](cmpl.md) — register-register unsigned compare.
- [`cmpi`](cmpi.md) — signed compare against a 16-bit immediate.
- [`cmp`](cmp.md) — register-register signed compare.
- `cmplwi`, `cmpldi` (simplified) — most common form seen in disassembly.
## IBM Reference
- [AIX 7.3 — `cmpli` (Compare Logical Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-cmpli-compare-logical-immediate-instruction)
- [AIX 7.3 — `cmplwi` / `cmpldi` (simplified mnemonics)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-cmplwi-compare-logical-word-immediate)

View File

@@ -0,0 +1,119 @@
# `cntlzdx` — Count Leading Zeros Doubleword
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000074`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `cntlzd` | `cntlzdx` | — | Count Leading Zeros Doubleword |
| `cntlzd.` | `cntlzdx` | Rc=1 | Count Leading Zeros Doubleword |
## Syntax
```asm
cntlzd [RA], [RS]
```
## Encoding
### `cntlzdx` — form `X`
- **Opcode word:** `0x7c000074`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `58`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | cntlzdx: read | Source GPR (alias for RD in some stores). |
| `RA` | cntlzdx: write | Source GPR (`r0``r31`). |
| `CR` | cntlzdx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `cntlzdx`
- **Reads (always):** `RS`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `cntlzdx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
n <- number_of_leading_zero_bits((RS)) ; n in 0..64
RA <- zero_extend(n)
```
## 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
**`cntlzdx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cntlzdx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:674`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L674)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:15`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L15)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:767`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L767)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:615-619`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L615-L619)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::cntlzdx => {
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()].leading_zeros() as u64;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Result range is `0..=64`.** When `RS == 0`, every bit is a leading zero and `RA = 64`. When the high bit (`RS[0]`) is set, `RA = 0`. Any intermediate value yields the count of high-order zeros before the first 1-bit.
- **Counts across the full 64 bits.** Use [`cntlzwx`](cntlzwx.md) when you only want to count the low 32 bits.
- **Useful as `floor(log2(x)) = 63 cntlzd(x)`** for nonzero `x`. Frequently used in fast normalization, priority encoders, and bit-vector operations.
- **`RB` field unused.** This is X-form but only `RS` is read; `RB` is a placeholder slot.
- **`Rc=1` quirk.** `update_cr_signed(0, RA as i64)` is correct in xenia-rs because the result fits in 7 bits and is non-negative. The CR0 result will always be `EQ` (when `RS != 0` and `RA != 0`? — actually `EQ` only when `RS[0] == 1`, i.e. `RA == 0`) or `GT` (when `RS != 0` so `RA > 0`); never `LT`. `EQ` corresponds to "high bit set in `RS`", a useful one-instruction sign test for negative-as-signed values.
- **No `XER` side effects.** Counts neither overflow nor carry.
## Related Instructions
- [`cntlzwx`](cntlzwx.md) — 32-bit version (counts only `RS[32:63]`).
- [`sldx`](sldx.md), [`srdx`](srdx.md) — pair with `cntlzd` for normalisation.
- [`rldiclx`](rldiclx.md) — for extracting individual bit positions once the leading-zero count is known.
- [`cmpi`](cmpi.md) / [`cmp`](cmp.md) — alternative for testing the high bit.
## IBM Reference
- [AIX 7.3 — `cntlzd` (Count Leading Zeros Doubleword)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-cntlzd-count-leading-zeros-double-word-instruction)

View File

@@ -0,0 +1,121 @@
# `cntlzwx` — Count Leading Zeros Word
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000034`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `cntlzw` | `cntlzwx` | — | Count Leading Zeros Word |
| `cntlzw.` | `cntlzwx` | Rc=1 | Count Leading Zeros Word |
## Syntax
```asm
cntlzw[Rc] [RA], [RS]
```
## Encoding
### `cntlzwx` — form `X`
- **Opcode word:** `0x7c000034`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `26`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | cntlzwx: read | Source GPR (alias for RD in some stores). |
| `RA` | cntlzwx: write | Source GPR (`r0``r31`). |
| `CR` | cntlzwx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `cntlzwx`
- **Reads (always):** `RS`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `cntlzwx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
n <- number_of_leading_zero_bits((RS)[32:63]) ; n in 0..32
RA <- zero_extend(n)
```
## 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
**`cntlzwx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cntlzwx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:689`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L689)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:15`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L15)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:758`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L758)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:608-614`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L608-L614)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::cntlzwx => {
// Result is 0..=32, fits in u32 with bit 31 always zero, so the
// CR0 view is benign — use the catch-all 32-bit form for consistency.
ctx.gpr[instr.ra()] = (ctx.gpr[instr.rs()] as u32).leading_zeros() as u64;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operates only on the low 32 bits.** `RS[0:31]` is ignored; the count is taken on `RS[32:63]`. Result range is `0..=32`.
- **`RA = 32` when the low 32 bits are zero**, regardless of the high 32 bits. A common pitfall: `cntlzw` after computing a 64-bit value can give a counter-intuitive result when the leading 1-bit lives in the high half.
- **`RA = 0` when bit 32 (the sign bit of the low word) is set.** This makes `cntlzw RA, RS; cmpwi RA, 0` a one-instruction-pair "is the low half negative" test, though `srawi RA, RS, 31` is more idiomatic.
- **High 32 bits of the result are zero.** `RA[0:31] = 0`, `RA[32:63] = count`.
- **`Rc=1` CR0 update is small-positive-only.** Result fits in 6 bits; xenia's `as i32 as i64` truncation in [`interpreter.rs:404`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L404) is harmless. CR0 will be `EQ` only when `RS[32]` (sign bit of low word) is 1, otherwise `GT`.
- **Useful for `floor(log2)` of a 32-bit value.** `31 - cntlzw(x)` for nonzero `x`.
## Related Instructions
- [`cntlzdx`](cntlzdx.md) — 64-bit version (counts the full register).
- [`slwx`](slwx.md), [`srwx`](srwx.md), [`srawx`](srawx.md) — 32-bit shifts often paired with `cntlzw` for normalisation.
- [`rlwinmx`](rlwinmx.md) — to mask off bits before counting.
- [`cmpi`](cmpi.md), [`cmpl`](cmpl.md) — alternative ways to detect zero or sign.
## IBM Reference
- [AIX 7.3 — `cntlzw` (Count Leading Zeros Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-cntlzw-count-leading-zeros-word-instruction)

View File

@@ -0,0 +1,135 @@
# `divdux` — Divide Doubleword Unsigned
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000392`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `divdu` | `divdux` | — | Divide Doubleword Unsigned |
| `divduo` | `divdux` | OE=1 | Divide Doubleword Unsigned |
| `divdu.` | `divdux` | Rc=1 | Divide Doubleword Unsigned |
| `divduo.` | `divdux` | OE=1, Rc=1 | Divide Doubleword Unsigned |
## Syntax
```asm
divdu[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `divdux` — form `XO`
- **Opcode word:** `0x7c000392`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `457`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | divdux: read | Source GPR (`r0``r31`). |
| `RB` | divdux: read | Source GPR. |
| `RD` | divdux: write | Destination GPR. |
| `OE` | divdux: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
| `CR` | divdux: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `divdux`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `OE`, `CR`
## Status-Register Effects
- `divdux`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- (RA) /u (RB) ; undefined if RB=0
```
## 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
**`divdux`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divdux"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:217`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L217)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:21`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L21)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:876`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L876)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:480-496`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L480-L496)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::divdux => {
let ra = ctx.gpr[instr.ra()];
let rb = ctx.gpr[instr.rb()];
let ov = overflow::divd_ov_unsigned(rb);
if ov {
ctx.gpr[instr.rd()] = 0;
} else {
ctx.gpr[instr.rd()] = ra / rb;
}
if instr.oe() {
overflow::apply(ctx, ov);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Single undefined case.** Division by zero (`RB == 0`). There is no `INT_MIN/1` overflow because both operands are unsigned. Xenia-rs returns 0 for the divide-by-zero case ([`interpreter.rs:306`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L306)); spec leaves `RT` boundedly undefined.
- **No trap on Xenon.** As with [`divdx`](divdx.md), the processor does not raise an exception; consuming code must guard `RB` first (typically `cmpdi rb, 0; beq skip`).
- **`OE=1` should set `XER[OV]`** on `RB == 0`; xenia-rs ignores `OE` here.
- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:311`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L311) uses `as i64` directly, so the CR0 sign comparison reflects the full 64-bit unsigned quotient cast to signed. For very large unsigned quotients (`> INT64_MAX`) this CR0 will report `LT` even though the unsigned interpretation is positive — a rare but real source of CR-misuse bugs.
- **Slow.** Same ~70-cycle non-pipelined cost as the signed variant; consider reciprocal multiply for hot loops.
- **Truncating quotient.** Same C-style toward-zero rounding (trivially equal to floor for unsigned).
## Related Instructions
- [`divdx`](divdx.md) — signed 64-bit divide.
- [`divwux`](divwux.md), [`divwx`](divwx.md) — 32-bit unsigned/signed.
- [`mulldx`](mulldx.md), [`mulhdux`](mulhdux.md) — multiply pair for remainder calculation.
- [`cmpli`](cmpli.md), [`cmpl`](cmpl.md) — guard the divisor.
## IBM Reference
- [AIX 7.3 — `divdu` (Divide Doubleword Unsigned)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-divdu-divide-double-word-unsigned-instruction)

View File

@@ -0,0 +1,136 @@
# `divdx` — Divide Doubleword
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c0003d2`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `divd` | `divdx` | — | Divide Doubleword |
| `divdo` | `divdx` | OE=1 | Divide Doubleword |
| `divd.` | `divdx` | Rc=1 | Divide Doubleword |
| `divdo.` | `divdx` | OE=1, Rc=1 | Divide Doubleword |
## Syntax
```asm
divd[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `divdx` — form `XO`
- **Opcode word:** `0x7c0003d2`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `489`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | divdx: read | Source GPR (`r0``r31`). |
| `RB` | divdx: read | Source GPR. |
| `RD` | divdx: write | Destination GPR. |
| `OE` | divdx: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
| `CR` | divdx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `divdx`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `OE`, `CR`
## Status-Register Effects
- `divdx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- (RA) /s (RB) ; undefined if RB=0 or (RA=-2^63 and RB=-1)
```
## 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
**`divdx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divdx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:192`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L192)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:21`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L21)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:878`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L878)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:463-479`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L463-L479)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::divdx => {
let ra = ctx.gpr[instr.ra()] as i64;
let rb = ctx.gpr[instr.rb()] as i64;
let ov = overflow::divd_ov_signed(ra, rb);
if ov {
ctx.gpr[instr.rd()] = 0;
} else {
ctx.gpr[instr.rd()] = (ra / rb) as u64;
}
if instr.oe() {
overflow::apply(ctx, ov);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Two undefined-behaviour cases.** Division by zero (`RB == 0`) and signed-min divided by negative-one (`RA == INT64_MIN && RB == -1`, which would mathematically produce `2^63`, unrepresentable in `i64`). PowerISA leaves `RT` *boundedly undefined* in both cases; **xenia-rs returns 0** ([`interpreter.rs:293`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L293)). Matching this behaviour bit-for-bit is a defacto-spec on Xenon.
- **No exception raised.** Xenon does not trap on either undefined case; the consuming code is expected to have validated `RB` first, e.g. with `cmpdi`/`bne`. If you need a trap, follow the divide with [`tw`](../control/tw.md)/`twi` (these live outside the ALU page set).
- **`OE=1` should set `XER[OV]`** for both undefined cases plus any operand triggering overflow; xenia-rs does not implement the `OE` branch.
- **`Rc=1` CR0 update is correctly 64-bit here.** Unlike most ALU pages, [`interpreter.rs:298`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L298) uses `as i64` (no `as i32` truncation) — divide is one of the few xenia-rs instructions that already matches Xenon spec for the CR0 width.
- **Latency.** Integer divide is the slowest ALU instruction on Xenon — 70+ cycles, non-pipelined. Hot inner loops avoid it via reciprocal-multiply or shift; expect to see `mulhwu`-based reciprocals in optimised disassembly.
- **Rounds toward zero.** The signed quotient truncates toward zero, matching C99/C++11 `/` semantics. Use [`mulldx`](mulldx.md) and a subtract to recover the remainder; there is no `divmod` instruction.
## Related Instructions
- [`divdux`](divdux.md) — unsigned 64-bit divide.
- [`divwx`](divwx.md), [`divwux`](divwux.md) — 32-bit signed/unsigned variants.
- [`mulldx`](mulldx.md), [`mulhdx`](mulhdx.md) — multiply pair used to compute the remainder.
- [`cmpi`](cmpi.md), [`cmp`](cmp.md) — guard the divisor before invoking divide.
## IBM Reference
- [AIX 7.3 — `divd` (Divide Doubleword)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-divd-divide-double-word-instruction)
- PowerISA v2.07B, Book I, §3.3.9 — defines the boundedly-undefined behaviour for `RB=0` and `INT_MIN/1`.

View File

@@ -0,0 +1,137 @@
# `divwux` — Divide Word Unsigned
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000396`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `divwu` | `divwux` | — | Divide Word Unsigned |
| `divwuo` | `divwux` | OE=1 | Divide Word Unsigned |
| `divwu.` | `divwux` | Rc=1 | Divide Word Unsigned |
| `divwuo.` | `divwux` | OE=1, Rc=1 | Divide Word Unsigned |
## Syntax
```asm
divwu[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `divwux` — form `XO`
- **Opcode word:** `0x7c000396`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `459`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | divwux: read | Source GPR (`r0``r31`). |
| `RB` | divwux: read | Source GPR. |
| `RD` | divwux: write | Destination GPR. |
| `OE` | divwux: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
| `CR` | divwux: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `divwux`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `OE`, `CR`
## Status-Register Effects
- `divwux`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- ((RA)[32:63] /u (RB)[32:63]) zero-extended to 64 ; undefined if RB=0
```
## 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
**`divwux`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divwux"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:269`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L269)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:21`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L21)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:877`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L877)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:413-430`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L413-L430)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::divwux => {
// PPCBUG-020: 32-bit ABI CR0 view.
let ra = ctx.gpr[instr.ra()] as u32;
let rb = ctx.gpr[instr.rb()] as u32;
let ov = overflow::divw_ov_unsigned(rb);
if ov {
ctx.gpr[instr.rd()] = 0;
} else {
ctx.gpr[instr.rd()] = (ra / rb) as u64;
}
if instr.oe() {
overflow::apply(ctx, ov);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as u32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **32-bit operands, zero-extended result.** Both `RA` and `RB` are read as their low 32 bits, unsigned (`as u32`); the quotient is computed as `u32`, then *zero-extended* to 64 bits. The high 32 bits of `RA`/`RB` are ignored on input and the high 32 bits of `RT` are zero on output.
- **Single undefined case.** Division by zero (`RB == 0`); xenia-rs returns 0 ([`interpreter.rs:251`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L251)). No `INT_MIN/-1` case because the operands are unsigned.
- **No trap on Xenon.** Same as [`divdx`](divdx.md) — silent undefined result.
- **`OE=1` should set `XER[OV]` on `RB == 0`**; xenia-rs ignores this.
- **`Rc=1` CR0 update.** [`interpreter.rs:256`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L256) uses `as i32 as i64` — for an unsigned 32-bit quotient stored in the low 32 bits with high zeros, this matches spec exactly; the i32 view will be negative iff the unsigned quotient ≥ 2^31. Worth flagging when comparing CR0 against zero after a large `divwu`.
- **Truncating quotient.** Floor division for non-negative integers; matches C `unsigned` semantics.
- **Same slow non-pipelined latency** as `divw`.
## Related Instructions
- [`divwx`](divwx.md) — signed 32-bit divide.
- [`divdux`](divdux.md), [`divdx`](divdx.md) — 64-bit variants.
- [`mullwx`](mullwx.md) — pair to recover the remainder.
- [`cmplwi`](cmpli.md) (simplified) — guard the divisor.
## IBM Reference
- [AIX 7.3 — `divwu` (Divide Word Unsigned)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-divwu-divide-word-unsigned-instruction)

View File

@@ -0,0 +1,138 @@
# `divwx` — Divide Word
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c0003d6`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `divw` | `divwx` | — | Divide Word |
| `divwo` | `divwx` | OE=1 | Divide Word |
| `divw.` | `divwx` | Rc=1 | Divide Word |
| `divwo.` | `divwx` | OE=1, Rc=1 | Divide Word |
## Syntax
```asm
divw[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `divwx` — form `XO`
- **Opcode word:** `0x7c0003d6`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `491`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | divwx: read | Source GPR (`r0``r31`). |
| `RB` | divwx: read | Source GPR. |
| `RD` | divwx: write | Destination GPR. |
| `OE` | divwx: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
| `CR` | divwx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `divwx`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `OE`, `CR`
## Status-Register Effects
- `divwx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- ((RA)[32:63] /s (RB)[32:63]) sign-extended to 64 ; undefined if RB=0 or overflow
```
## 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
**`divwx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divwx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:242`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L242)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:21`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L21)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:879`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L879)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:394-412`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L394-L412)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::divwx => {
// PPCBUG-010+011 coupled: 32-bit ABI. Quotient zero-extended to u64
// (canary explicitly uses ZeroExtend(v, INT64_TYPE)). CR0 view via i32.
let ra = ctx.gpr[instr.ra()] as i32;
let rb = ctx.gpr[instr.rb()] as i32;
let ov = overflow::divw_ov_signed(ra, rb);
if ov {
ctx.gpr[instr.rd()] = 0;
} else {
ctx.gpr[instr.rd()] = (ra / rb) as u32 as u64;
}
if instr.oe() {
overflow::apply(ctx, ov);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as u32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **32-bit operands, sign-extended result.** Both `RA` and `RB` are read as their low 32 bits, signed; the quotient is computed as `i32`, then sign-extended to 64 bits before being stored in `RT`. The high 32 bits of `RA`/`RB` are *ignored*.
- **Two undefined cases:** `RB == 0` and `RA == INT32_MIN && RB == -1` (quotient `2^31` is unrepresentable). Xenia-rs returns 0 for both ([`interpreter.rs:238`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L238)); PowerISA leaves `RT` boundedly undefined.
- **No trap on Xenon.** Like [`divdx`](divdx.md), the processor silently produces an undefined value instead of raising an exception.
- **`OE=1` should set `XER[OV]`** in both undefined cases; xenia-rs does not implement this.
- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:243`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L243) uses `as i32 as i64`. This is *correct* for `divw` because the result is already a sign-extended 32-bit value — high bits agree with the low-32 sign extension. So spec and xenia agree for this instruction.
- **Truncating quotient.** Rounds toward zero, matching C `/` for `int32_t`.
- **Slow.** Same ~30-cycle non-pipelined cost as 64-bit divide; faster than `divd` because the underlying datapath is narrower but still much slower than multiply-then-shift reciprocal sequences.
## Related Instructions
- [`divwux`](divwux.md) — unsigned 32-bit divide.
- [`divdx`](divdx.md), [`divdux`](divdux.md) — 64-bit variants.
- [`mullwx`](mullwx.md) — pair with subtract to obtain the remainder.
- [`extsw`](extswx.md) — manual sign-extend if you only have a 64-bit value but want 32-bit divide semantics.
## IBM Reference
- [AIX 7.3 — `divw` (Divide Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-divw-divide-word-instruction)

View File

@@ -0,0 +1,111 @@
# `eieio` — Enforce In-Order Execution of I/O
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c0006ac`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `eieio` | `eieio` | — | Enforce In-Order Execution of I/O |
## Syntax
```asm
eieio
```
## Encoding
### `eieio` — form `X`
- **Opcode word:** `0x7c0006ac`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `854`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
## Register Effects
### `eieio`
- **Reads (always):** _none_
- **Reads (conditional):** _none_
- **Writes (always):** _none_
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
enforce in-order execution of I/O
```
## 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
**`eieio`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="eieio"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:749`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L749)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:23`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L23)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:844`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L844)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1691-1693`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1691-L1693)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::sync | PpcOpcode::eieio | PpcOpcode::isync => {
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Memory-ordering barrier for caching-inhibited / guarded storage.** `eieio` ensures all preceding loads/stores to caching-inhibited or guarded memory complete before any subsequent such accesses begin. It is *weaker* than [`sync`](sync.md): it does not order cacheable storage and does not flush the store queue.
- **No register or CR effects.** Every operand field is unused; assemblers emit the canonical `0x7c0006ac` word.
- **Used at MMIO boundaries.** Driver code touching device registers (e.g. the GPU command processor on Xenon) typically pairs writes with `eieio` to enforce write ordering at the bus.
- **Xenia-rs is a no-op.** The interpreter trivially advances PC ([`interpreter.rs:1267`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1267)). Because xenia-rs is a single-threaded interpreter targeting userland Xbox 360 binaries — which never see real MMIO — this is correct: the host's natural program order suffices.
- **Categorised under ALU here**, but operationally it's a memory ordering primitive (xenia-canary places it in `ppc_emit_memory.cc`). Disassembly tools may bin it differently.
- **Distinct from `sync` and `isync`.** All three share xenia's no-op arm in [`interpreter.rs:1266`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1266); on real hardware they have very different semantics and latencies.
## Related Instructions
- [`sync`](sync.md) — heavy memory barrier (orders *all* storage).
- [`isync`](isync.md) — instruction-fetch barrier; refetches and re-executes after the boundary.
- `lwsync` — lighter weight than `sync`; not in this page set.
## IBM Reference
- [AIX 7.3 — `eieio` (Enforce In-Order Execution of I/O)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-eieio-enforce-in-order-execution-i-o-instruction)

View File

@@ -0,0 +1,122 @@
# `eqvx` — Equivalent
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000238`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `eqv` | `eqvx` | — | Equivalent |
| `eqv.` | `eqvx` | Rc=1 | Equivalent |
## Syntax
```asm
eqv[Rc] [RA], [RS], [RB]
```
## Encoding
### `eqvx` — form `X`
- **Opcode word:** `0x7c000238`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `284`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | eqvx: read | Source GPR (alias for RD in some stores). |
| `RB` | eqvx: read | Source GPR. |
| `RA` | eqvx: write | Source GPR (`r0``r31`). |
| `CR` | eqvx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `eqvx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `eqvx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- ~((RS) ^ (RB))
```
## 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
**`eqvx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="eqvx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:704`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L704)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:25`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L25)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:796`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L796)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:578-586`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L578-L586)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::eqvx => {
// PPCBUG-031: `eqv rA, rA, rA` is a common "set to all-ones" idiom;
// 64-bit form gave 0xFFFFFFFFFFFFFFFF but 32-bit ABI expects 0x00000000FFFFFFFF.
let rs32 = ctx.gpr[instr.rs()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
ctx.gpr[instr.ra()] = (!(rs32 ^ rb32)) as u64;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **NXOR / equivalence.** `RA ← ~(RS XOR RB)`. A bit in `RA` is 1 iff the corresponding bits of `RS` and `RB` are equal. Useful as a per-bit equality test feeding into a `cntlzw` for run-length analysis.
- **Idiom: `eqv RA, RS, RS`** sets every bit to 1 — a one-instruction `RA = -1`. Cheaper than `li RA, -1` followed by `oris`/`ori` for full 64-bit `-1`.
- **Operand convention is X-form** (`RA` is destination; `RS`, `RB` are sources).
- **64-bit operation** on Xenon; `~` is full 64-bit on `u64`.
- **No `OE`, no `XER` side effects.** Only `Rc=1` updates `CR0`.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:382`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L382) truncates with `as i32 as i64`. Significant when the high 32 bits of the result differ from the low 32 — e.g. `eqv. RA, RS, RB` with `RS == 0x1_0000_0000`, `RB == 0`: spec sees `0xFFFFFFFE_FFFFFFFF` (`LT`), xenia sees `0xFFFFFFFFFFFFFFFF` (`LT`) — actually both negative here, but the *exact* CR contents differ for finer cases.
## Related Instructions
- [`xorx`](xorx.md) — base XOR (`eqv` is `xor` then `not`).
- [`andx`](andx.md), [`orx`](orx.md), [`nandx`](nandx.md), [`norx`](norx.md), [`andcx`](andcx.md), [`orcx`](orcx.md) — full logical family.
- [`xori`](xori.md), [`xoris`](xoris.md) — immediate XOR (no immediate `eqv` exists).
## IBM Reference
- [AIX 7.3 — `eqv` (Equivalent)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-eqv-equivalent-instruction)

View File

@@ -0,0 +1,121 @@
# `extsbx` — Extend Sign Byte
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000774`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `extsb` | `extsbx` | — | Extend Sign Byte |
| `extsb.` | `extsbx` | Rc=1 | Extend Sign Byte |
## Syntax
```asm
extsb[Rc] [RA], [RS]
```
## Encoding
### `extsbx` — form `X`
- **Opcode word:** `0x7c000774`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `954`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | extsbx: read | Source GPR (alias for RD in some stores). |
| `RA` | extsbx: write | Source GPR (`r0``r31`). |
| `CR` | extsbx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `extsbx`
- **Reads (always):** `RS`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `extsbx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- EXTS_8_to_64((RS)[56:63])
```
## 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
**`extsbx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="extsbx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:714`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L714)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:25`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L25)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:849`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L849)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:589-595`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L589-L595)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::extsbx => {
// PPCBUG-034: 32-bit ABI — sign-extend byte to i32, write zero-extended.
// PPCBUG-036 (coupled): CR0 must view result as i32, not i64.
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] as i8 as i32 as u32 as u64;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Sign-extends the low 8 bits of `RS` to 64 bits.** Bit 56 of `RS` (the sign bit of the byte) becomes bits 055 of `RA`; bits 5663 are copied verbatim.
- **Common after a byte load.** `lbz` zero-extends from memory; `extsb` converts the result to a signed-byte view. Many compilers emit this pair; the recent ISA `lba`/`lbau` family is *not* available on the Xenon, so this two-instruction sequence is the canonical pattern.
- **`Rc=1` updates CR0 from the full 64-bit signed value** — but xenia-rs truncates to 32 bits in [`interpreter.rs:384`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L384). For `extsb.` this is harmless because the result fits in 8 bits sign-extended; the low 32 bits already encode the sign correctly.
- **Operand convention** is the X-form one (`RA` destination, `RS` source). Same as the rest of the logical family.
- **No `XER` side effects.**
- **`RB` field unused.** Set to 0 by assemblers; ignored on decode.
- **Aliasing is fine.** `extsb r3, r3` rewrites `r3` in place.
## Related Instructions
- [`extshx`](extshx.md) — sign-extend half-word (16 bits).
- [`extswx`](extswx.md) — sign-extend word (32 bits).
- [`rlwinmx`](rlwinmx.md), [`rldiclx`](rldiclx.md) — for *zero*-extending or extracting non-byte-aligned fields.
- `lbz`, `lha` (memory ops, outside this page set) — pair with this for signed byte loads.
## IBM Reference
- [AIX 7.3 — `extsb` (Extend Sign Byte)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-extsb-extend-sign-byte-instruction)

View File

@@ -0,0 +1,121 @@
# `extshx` — Extend Sign Half Word
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000734`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `extsh` | `extshx` | — | Extend Sign Half Word |
| `extsh.` | `extshx` | Rc=1 | Extend Sign Half Word |
## Syntax
```asm
extsh[Rc] [RA], [RS]
```
## Encoding
### `extshx` — form `X`
- **Opcode word:** `0x7c000734`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `922`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | extshx: read | Source GPR (alias for RD in some stores). |
| `RA` | extshx: write | Source GPR (`r0``r31`). |
| `CR` | extshx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `extshx`
- **Reads (always):** `RS`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `extshx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- EXTS_16_to_64((RS)[48:63])
```
## 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
**`extshx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="extshx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:727`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L727)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:25`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L25)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:847`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L847)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:596-602`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L596-L602)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::extshx => {
// PPCBUG-035: same shape as extsbx for halfwords.
// PPCBUG-037 (coupled): CR0 i32 view.
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] as i16 as i32 as u32 as u64;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Sign-extends the low 16 bits of `RS` to 64 bits.** Bit 48 (the sign bit of the half-word) is replicated through bits 047 of `RA`.
- **Pairs with `lhz`** to convert an unsigned half-word load into a signed half-word value. Note that `lha` already does the sign extension on load — `extsh` is mostly emitted when the half-word is computed in a register first.
- **`Rc=1` CR0 update.** Xenia-rs uses `as i32 as i64` ([`interpreter.rs:389`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L389)) — harmless here because the sign-extended 16-bit value fits in 32 bits exactly.
- **Operand convention** is the X-form one (`RA` destination, `RS` source).
- **No `XER` side effects.**
- **`RB` field unused.**
- **Aliasing is fine.** `extsh r3, r3` is the standard "promote `r3`'s low 16 bits to a signed 64-bit value" sequence.
## Related Instructions
- [`extsbx`](extsbx.md) — sign-extend byte.
- [`extswx`](extswx.md) — sign-extend word (32 bits).
- [`rlwinmx`](rlwinmx.md) — when masking/zero-extending without sign-extension.
- `lha` (memory op, outside this set) — combined load + sign-extend.
## IBM Reference
- [AIX 7.3 — `extsh` (Extend Sign Half Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-extsh-extend-sign-half-word-instruction)

View File

@@ -0,0 +1,120 @@
# `extswx` — Extend Sign Word
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c0007b4`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `extsw` | `extswx` | — | Extend Sign Word |
| `extsw.` | `extswx` | Rc=1 | Extend Sign Word |
## Syntax
```asm
extsw[Rc] [RA], [RS]
```
## Encoding
### `extswx` — form `X`
- **Opcode word:** `0x7c0007b4`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `986`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | extswx: read | Source GPR (alias for RD in some stores). |
| `RA` | extswx: write | Source GPR (`r0``r31`). |
| `CR` | extswx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `extswx`
- **Reads (always):** `RS`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `extswx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- EXTS_32_to_64((RS)[32:63])
```
## 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
**`extswx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="extswx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:740`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L740)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:25`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L25)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:852`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L852)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:603-607`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L603-L607)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::extswx => {
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] as i32 as i64 as u64;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Sign-extends the low 32 bits of `RS` to 64 bits.** Bit 32 (sign bit of the word) is replicated through bits 031 of `RA`.
- **Used heavily in 32-to-64-bit promotion.** Most Xbox 360 ABI parameters are 32-bit; promoting a 32-bit `int` to a 64-bit GPR requires this instruction. Many functions emit it on entry to canonicalise their argument registers.
- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:399`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L399) uses `as i64` (no truncation) — one of the few xenia-rs sites where the spec width is honoured. The signed compare in CR0 reflects the full sign-extended value.
- **Operand convention** is the X-form one (`RA` destination, `RS` source).
- **No `XER` side effects.**
- **`RB` field unused.**
- **Aliasing is fine.** `extsw r3, r3` is the canonical "sign-extend in place" idiom.
- **Distinct from `srawi RA, RS, 31`**, which produces the *sign mask* (`-1` if negative else `0`) rather than the sign-extended value.
## Related Instructions
- [`extsbx`](extsbx.md), [`extshx`](extshx.md) — narrower sign extensions.
- [`srawix`](srawix.md) — to derive a sign mask instead.
- [`rldiclx`](rldiclx.md) — to *zero*-extend the low 32 bits.
- `lwa` / `lwax` (memory ops) — combined load-and-sign-extend; lives outside this set.
## IBM Reference
- [AIX 7.3 — `extsw` (Extend Sign Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-extsw-extend-sign-word-instruction)

View File

@@ -0,0 +1,111 @@
# `isync` — Instruction Synchronize
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c00012c`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `isync` | `isync` | — | Instruction Synchronize |
## Syntax
```asm
isync
```
## Encoding
### `isync` — form `XL`
- **Opcode word:** `0x4c00012c`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `150`
- **Synchronising:** no
| 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 |
| --- | --- | --- |
## Register Effects
### `isync`
- **Reads (always):** _none_
- **Reads (conditional):** _none_
- **Writes (always):** _none_
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
instruction-stream synchronisation — discards speculative state.
```
## 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
**`isync`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="isync"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:759`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L759)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:32`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L32)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:714`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L714)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1691-1693`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1691-L1693)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::sync | PpcOpcode::eieio | PpcOpcode::isync => {
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Instruction-fetch barrier.** Discards any speculatively fetched/decoded instructions and forces all subsequent ones to be re-fetched after preceding instructions complete. Required after self-modifying code, JIT-emitted code, and after MMU/page-table changes.
- **Stronger than [`sync`](sync.md) for instruction stream**, weaker for memory stream — `isync` does not order stores against later loads. It only forces a fetch refresh.
- **Common idiom: `dcbf` / `icbi` / `sync` / `isync`** — flush data cache, invalidate instruction cache, drain memory, refetch — used by JITs and self-modifying loaders.
- **No operands.** Encoded as a fixed-form `XL` instruction; assemblers always emit `0x4c00012c`.
- **Xenia-rs is a no-op.** [`interpreter.rs:1267`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1267) handles `sync`/`eieio`/`isync` together. Because xenia interprets in straight-line program order without any speculative instruction cache, no barrier behaviour is needed for correctness.
- **Privilege level: user.** Unlike most cache management ops, `isync` is unprivileged and frequently appears in userland trampolines.
## Related Instructions
- [`sync`](sync.md) — heavy memory barrier.
- [`eieio`](eieio.md) — I/O ordering for caching-inhibited storage.
- `icbi`, `dcbf`, `dcbst` — cache management ops (outside this page set) usually paired with `isync`.
## IBM Reference
- [AIX 7.3 — `isync` (Instruction Synchronize)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-isync-instruction-synchronize-instruction)

View File

@@ -0,0 +1,124 @@
# `mulhdux` — Multiply High Doubleword Unsigned
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000012`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mulhdu` | `mulhdux` | — | Multiply High Doubleword Unsigned |
| `mulhdu.` | `mulhdux` | Rc=1 | Multiply High Doubleword Unsigned |
## Syntax
```asm
mulhdu[Rc] [RD], [RA], [RB]
```
## Encoding
### `mulhdux` — form `XO`
- **Opcode word:** `0x7c000012`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `9`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | mulhdux: read | Source GPR (`r0``r31`). |
| `RB` | mulhdux: read | Source GPR. |
| `RD` | mulhdux: write | Destination GPR. |
| `CR` | mulhdux: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `mulhdux`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `mulhdux`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RT <- ((RA) * (RB))[0:63] ; high 64 of unsigned 64×64
```
## 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
**`mulhdux`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhdux"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:311`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L311)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:860`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L860)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:454-462`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L454-L462)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mulhdux => {
let ra = ctx.gpr[instr.ra()] as u128;
let rb = ctx.gpr[instr.rb()] as u128;
ctx.gpr[instr.rd()] = (ra.wrapping_mul(rb) >> 64) as u64;
if instr.rc_bit() {
ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Returns the high 64 bits of an unsigned 64×64 product.** Operands are zero-extended (treated as unsigned) before multiplication. Pair with [`mulldx`](mulldx.md) for the low 64 bits to form a full 128-bit unsigned product.
- **No `OE` bit.** No overflow signal — the high half is a defined function of the inputs even when the product fills 128 bits.
- **Xenia uses native `u128`.** [`interpreter.rs:284`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L284) widens both operands then shifts. Note `as u128` *zero*-extends, in contrast to [`mulhdx`](mulhdx.md)'s `as i64 as i128` which sign-extends — this is the entire semantic difference.
- **`Rc=1` CR0 update is correctly 64-bit.** Uses `as i64` directly. Because the high half is unsigned, treating it as signed for CR0 means very large unsigned values appear `LT` — keep this in mind when interpreting the CR0 bits after `mulhdu.`.
- **Used in reciprocal-multiply division strategies.** Compilers may strength-reduce divide-by-constant into `mulhdu` plus a shift; appears in optimised disassembly.
- **Slow.** Same multi-cycle cost as the signed variant.
## Related Instructions
- [`mulldx`](mulldx.md) — low 64 bits of the same unsigned product.
- [`mulhdx`](mulhdx.md) — signed high half.
- [`mulhwux`](mulhwux.md) — 32-bit unsigned high half.
- [`divdux`](divdux.md) — 64-bit unsigned divide; sometimes replaced by reciprocal `mulhdu`.
## IBM Reference
- [AIX 7.3 — `mulhdu` (Multiply High Doubleword Unsigned)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mulhdu-multiply-high-double-word-unsigned-instruction)

View File

@@ -0,0 +1,124 @@
# `mulhdx` — Multiply High Doubleword
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000092`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mulhd` | `mulhdx` | — | Multiply High Doubleword |
| `mulhd.` | `mulhdx` | Rc=1 | Multiply High Doubleword |
## Syntax
```asm
mulhd[Rc] [RD], [RA], [RB]
```
## Encoding
### `mulhdx` — form `XO`
- **Opcode word:** `0x7c000092`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `73`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | mulhdx: read | Source GPR (`r0``r31`). |
| `RB` | mulhdx: read | Source GPR. |
| `RD` | mulhdx: write | Destination GPR. |
| `CR` | mulhdx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `mulhdx`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `mulhdx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RT <- ((RA) * (RB))[0:63] ; high 64 of signed 64×64
```
## 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
**`mulhdx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhdx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:297`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L297)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:864`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L864)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:445-453`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L445-L453)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mulhdx => {
let ra = ctx.gpr[instr.ra()] as i64 as i128;
let rb = ctx.gpr[instr.rb()] as i64 as i128;
ctx.gpr[instr.rd()] = (ra.wrapping_mul(rb) >> 64) as u64;
if instr.rc_bit() {
ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Returns the high 64 bits of a signed 64×64 product.** Pair with [`mulldx`](mulldx.md) (which returns the low 64 bits) to obtain the full 128-bit product. Both must be issued separately; PowerPC has no fused multiply-double-wide instruction.
- **No `OE` bit.** This XO-form instruction has no overflow-enable variant — there is no "high half overflow" because the high half is always defined.
- **Xenia widens to `i128` natively.** [`interpreter.rs:275`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L275) does the multiply in 128 bits then extracts the high 64. The `i64 as i128` casts ensure signed extension on both sides.
- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:278`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L278) uses `as i64` directly. CR0 reflects the sign of the high half: `LT` if the product is negative, `GT` if positive and large enough to overflow into the high half, `EQ` if the product fits in 64 bits *signed* (so the high half is the sign-extension of the low half — but xenia's check uses raw signed-zero compare, which equates only when the high half is exactly zero, i.e. the product is in `[0, 2^63)`).
- **Use [`mulhdux`](mulhdux.md) for the unsigned high half.** The two instructions differ in whether the operands are sign- or zero-extended before the multiply.
- **Slow.** 64-bit multiply is multi-cycle on Xenon; combining `mulhd` with `mulld` for a full 128-bit product roughly doubles the cost.
## Related Instructions
- [`mulldx`](mulldx.md) — low 64 bits of the same signed product.
- [`mulhdux`](mulhdux.md) — high 64 bits, unsigned interpretation.
- [`mullwx`](mullwx.md), [`mulhwx`](mulhwx.md), [`mulhwux`](mulhwux.md) — 32-bit family.
- [`divdx`](divdx.md), [`divdux`](divdux.md) — 64-bit division.
## IBM Reference
- [AIX 7.3 — `mulhd` (Multiply High Doubleword)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mulhd-multiply-high-double-word-instruction)

View File

@@ -0,0 +1,126 @@
# `mulhwux` — Multiply High Word Unsigned
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000016`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mulhwu` | `mulhwux` | — | Multiply High Word Unsigned |
| `mulhwu.` | `mulhwux` | Rc=1 | Multiply High Word Unsigned |
## Syntax
```asm
mulhwu[Rc] [RD], [RA], [RB]
```
## Encoding
### `mulhwux` — form `XO`
- **Opcode word:** `0x7c000016`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `11`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | mulhwux: read | Source GPR (`r0``r31`). |
| `RB` | mulhwux: read | Source GPR. |
| `RD` | mulhwux: write | Destination GPR. |
| `CR` | mulhwux: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `mulhwux`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `mulhwux`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RT <- high_32_of_unsigned_multiply((RA)[32:63], (RB)[32:63]) zero-extended to 64
```
## 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
**`mulhwux`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhwux"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:347`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L347)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:862`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L862)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:383-393`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L383-L393)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mulhwux => {
// PPCBUG-020: 32-bit ABI CR0 view.
let ra = ctx.gpr[instr.ra()] as u32 as u64;
let rb = ctx.gpr[instr.rb()] as u32 as u64;
let result = ra.wrapping_mul(rb);
ctx.gpr[instr.rd()] = (result >> 32) & 0xFFFF_FFFF;
if instr.rc_bit() {
ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as u32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Inputs are the low 32 bits, zero-extended.** `RA[32:63]` and `RB[32:63]` are treated as unsigned, widened to 64-bit `u64`, multiplied; the high 32 bits of the 64-bit product land in `RT[32:63]`. Xenia masks the high 32 bits of `RT` to zero ([`interpreter.rs:231`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L231)).
- **Pair with [`mullwx`](mullwx.md) for the full 64-bit unsigned product.** `mullw` returns the low 32 sign-extended; for unsigned use, pair `mulhwu` with `rlwinm` to mask the low half. Xbox 360 compilers commonly emit this combination.
- **No `OE` bit.** Same family rule.
- **`Rc=1` CR0 update.** Uses `as i32 as i64` ([`interpreter.rs:234`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L234)). Because the result is bounded by `0xFFFFFFFF` and stored only in the low 32 bits, this CR0 will report `LT` for any unsigned high half ≥ `0x80000000` — a known signed/unsigned interpretation pitfall when `Rc=1` is used with `mulhwu`.
- **Common idiom for multi-precision arithmetic.** `mulhwu` + `mullw` + `addc` chains build extended-precision multiplies entirely in 32-bit ops; useful for cryptographic code that targets the Xenon's 32-bit ABI.
- **Multi-cycle latency** like the rest of the multiply family.
## Related Instructions
- [`mullwx`](mullwx.md) — low 32 bits of the same product (sign-extended).
- [`mulhwx`](mulhwx.md) — signed high half.
- [`mulhdux`](mulhdux.md) — 64-bit unsigned high half.
- [`addcx`](addcx.md), [`addex`](addex.md) — used to chain 32-bit products into wider precision.
## IBM Reference
- [AIX 7.3 — `mulhwu` (Multiply High Word Unsigned)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mulhwu-multiply-high-word-unsigned-instruction)

View File

@@ -0,0 +1,126 @@
# `mulhwx` — Multiply High Word
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000096`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mulhw` | `mulhwx` | — | Multiply High Word |
| `mulhw.` | `mulhwx` | Rc=1 | Multiply High Word |
## Syntax
```asm
mulhw[Rc] [RD], [RA], [RB]
```
## Encoding
### `mulhwx` — form `XO`
- **Opcode word:** `0x7c000096`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `75`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | mulhwx: read | Source GPR (`r0``r31`). |
| `RB` | mulhwx: read | Source GPR. |
| `RD` | mulhwx: write | Destination GPR. |
| `CR` | mulhwx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `mulhwx`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `mulhwx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RT <- high_32_of_signed_multiply((RA)[32:63], (RB)[32:63]) sign-extended to 64
```
## 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
**`mulhwx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhwx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:326`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L326)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:865`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L865)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:372-382`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L372-L382)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mulhwx => {
// PPCBUG-020: 32-bit ABI CR0 view.
let ra = ctx.gpr[instr.ra()] as i32 as i64;
let rb = ctx.gpr[instr.rb()] as i32 as i64;
let result = ra.wrapping_mul(rb);
ctx.gpr[instr.rd()] = ((result >> 32) as u32) as u64;
if instr.rc_bit() {
ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as u32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Inputs are the low 32 bits, signed-extended.** `RA[32:63]` and `RB[32:63]` are sign-extended to 64-bit signed values, multiplied, and the *high* 32 bits of the 64-bit product are returned in `RT[32:63]`. The high 32 bits of `RT` are *implementation-defined* per spec but xenia masks them to zero ([`interpreter.rs:222`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L222) `& 0xFFFF_FFFF`).
- **Pair with [`mullwx`](mullwx.md) for the full 64-bit product.** Both can issue independently — no fused 32×32→64 instruction.
- **No `OE` bit.** Like all `mulh*` instructions, no overflow flag is produced; the high half is by definition defined.
- **Xenia-rs quirk: high 32 bits zeroed.** Because spec says they're "undefined", legitimately matching either zero, sign-extension, or garbage. Xenia chooses zero, which differs from the literal Xenon behaviour (which sign-extends in some microarchitecture cases). For game code that doesn't read those bits, the difference is invisible.
- **`Rc=1` CR0 update.** [`interpreter.rs:225`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L225) uses `as i32 as i64` — operates on the truncated low 32 bits, which is correct for the *defined* portion of the result.
- **Multi-cycle latency.** Multiply is the slowest pipelined ALU op; `mulhw` shares the divider/multiplier unit.
## Related Instructions
- [`mullwx`](mullwx.md) — low 32 bits of a signed 32×32 product.
- [`mulhwux`](mulhwux.md) — high 32 bits, unsigned interpretation.
- [`mulhdx`](mulhdx.md), [`mulhdux`](mulhdux.md), [`mulldx`](mulldx.md) — 64-bit family.
- [`divwx`](divwx.md) — sometimes replaced by reciprocal-mul-then-shift in compiled code.
## IBM Reference
- [AIX 7.3 — `mulhw` (Multiply High Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mulhw-multiply-high-word-instruction)

View File

@@ -0,0 +1,130 @@
# `mulldx` — Multiply Low Doubleword
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c0001d2`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mulld` | `mulldx` | — | Multiply Low Doubleword |
| `mulldo` | `mulldx` | OE=1 | Multiply Low Doubleword |
| `mulld.` | `mulldx` | Rc=1 | Multiply Low Doubleword |
| `mulldo.` | `mulldx` | OE=1, Rc=1 | Multiply Low Doubleword |
## Syntax
```asm
mulld[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `mulldx` — form `XO`
- **Opcode word:** `0x7c0001d2`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `233`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | mulldx: read | Source GPR (`r0``r31`). |
| `RB` | mulldx: read | Source GPR. |
| `RD` | mulldx: write | Destination GPR. |
| `CR` | mulldx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `OE` | mulldx: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
## Register Effects
### `mulldx`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `CR`, `OE`
## Status-Register Effects
- `mulldx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- ((RA) * (RB))[64:127] ; low 64 of signed 64×64
```
## 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
**`mulldx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulldx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:368`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L368)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:872`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L872)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:433-444`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L433-L444)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mulldx => {
let ra = ctx.gpr[instr.ra()] as i64;
let rb = ctx.gpr[instr.rb()] as i64;
ctx.gpr[instr.rd()] = ra.wrapping_mul(rb) as u64;
if instr.oe() {
overflow::apply(ctx, overflow::mulld_ov(ra, rb));
}
if instr.rc_bit() {
ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Returns the low 64 bits of a signed 64×64 product.** Equivalent to `(int64_t)(RA * RB)` modulo `2^64`. Both operands are full 64-bit signed; no truncation on input.
- **High bits silently lost.** The high 64 bits of the true product are discarded; pair with [`mulhdx`](mulhdx.md) (signed) or [`mulhdux`](mulhdux.md) (unsigned) to recover them.
- **`OE=1` should set `XER[OV]`** when the 128-bit signed product cannot be represented in 64 bits — i.e. when `mulhd RA, RB` is not the sign-extension of `mulld RA, RB`. **Xenia-rs does not implement** `OE` ([`interpreter.rs:264`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L264) has no `oe()` branch).
- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:269`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L269) uses `as i64` — full 64-bit signed compare. One of the few non-truncating CR0 sites in xenia-rs; means `mulld.` gives spec-correct CR0 even when the result has non-zero high 32 bits.
- **Same instruction for signed and unsigned low halves.** Modular arithmetic is identical; only the high half (`mulhd` vs `mulhdu`) distinguishes the interpretations.
- **Multi-cycle latency** — slowest of the ALU pipelines after divide.
## Related Instructions
- [`mulhdx`](mulhdx.md), [`mulhdux`](mulhdux.md) — signed/unsigned high halves of the same multiply.
- [`mullwx`](mullwx.md) — 32-bit signed multiply (low 64).
- [`mulli`](mulli.md) — D-form: `RT ← (RA[32:63]) × SIMM`.
- [`divdx`](divdx.md), [`divdux`](divdux.md) — 64-bit divide, often paired with `mulld` for remainders.
## IBM Reference
- [AIX 7.3 — `mulld` (Multiply Low Doubleword)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mulld-multiply-low-double-word-instruction)

View File

@@ -0,0 +1,120 @@
# `mulli` — Multiply Low Immediate
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x1c000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mulli` | `mulli` | — | Multiply Low Immediate |
## Syntax
```asm
mulli [RD], [RA], [SIMM]
```
## Encoding
### `mulli` — form `D`
- **Opcode word:** `0x1c000000`
- **Primary opcode (bits 05):** `7`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | mulli: read | Source GPR (`r0``r31`). |
| `SIMM` | mulli: read | 16-bit signed immediate. Sign-extended to 64 bits before use. |
| `RD` | mulli: write | Destination GPR. |
## Register Effects
### `mulli`
- **Reads (always):** `RA`, `SIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
RT <- ((RA) * EXTS(SIMM))[64:127]
```
## 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
**`mulli`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulli"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:382`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L382)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:332`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L332)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:165-172`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L165-L172)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mulli => {
// PPCBUG-004: 32-bit ABI. Read RA as i32 (low 32, sign-extended for
// multiply), product fits in 32 bits per ISA (overflow wraps).
let ra = ctx.gpr[instr.ra()] as i32 as i64;
let imm = instr.simm16() as i64;
ctx.gpr[instr.rd()] = (ra.wrapping_mul(imm) as u32) as u64;
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **64-bit operand, sign-extended 16-bit immediate.** Xenia reads the full 64-bit `RA` as `i64` and the immediate as a sign-extended `i64` ([`interpreter.rs:80-81`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L80-L81)) — note this differs from the PPC pseudocode header which writes `(RA) * EXTS(SIMM)` as a 64-bit operation but other implementations sometimes treat it as 32×32. On the Xenon (and in xenia-rs), it is genuinely 64-bit.
- **Returns the low 64 bits.** No high half is produced — equivalent to `(int64_t)RA * (int64_t)SIMM` modulo `2^64`. There is no `mulhi`-immediate instruction.
- **No `Rc`, no `OE`.** This D-form has no flag bits — strictly `RT ← RA * SIMM`. To check overflow, compare the result to `(int32_t)RA * SIMM` after the fact, or use [`mulldx`](mulldx.md) with `OE=1` after materialising the immediate.
- **Common compiler idiom.** `mulli` is heavily used for fixed-stride array indexing (`r3 *= sizeof_struct`) when the size is a small signed constant.
- **No carry.** `XER[CA]` is untouched.
- **Same multi-cycle latency** as `mullw` / `mulld`. Compilers strength-reduce `mulli rD, rA, 2^k` to a left shift and `mulli rD, rA, 3` to `add+shift` when the immediate has cheap structure.
- **Aliasing fine.** `mulli r3, r3, 5` rewrites in place.
## Related Instructions
- [`mullwx`](mullwx.md) — register-register low 32 (signed).
- [`mulldx`](mulldx.md) — register-register low 64 (signed).
- [`mulhdx`](mulhdx.md), [`mulhdux`](mulhdux.md) — high halves (no immediate variant).
- [`addi`](addi.md) — add immediate; sometimes substituted by compilers when the multiplier is `2^k+1` etc.
- [`slwx`](slwx.md), [`sldx`](sldx.md) — shifts often replace `mulli` for power-of-two multipliers.
## IBM Reference
- [AIX 7.3 — `mulli` (Multiply Low Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mulli-multiply-low-immediate-instruction)

View File

@@ -0,0 +1,146 @@
# `mullwx` — Multiply Low Word
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c0001d6`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mullw` | `mullwx` | — | Multiply Low Word |
| `mullwo` | `mullwx` | OE=1 | Multiply Low Word |
| `mullw.` | `mullwx` | Rc=1 | Multiply Low Word |
| `mullwo.` | `mullwx` | OE=1, Rc=1 | Multiply Low Word |
## Syntax
```asm
mullw[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `mullwx` — form `XO`
- **Opcode word:** `0x7c0001d6`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `235`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | mullwx: read | Source GPR (`r0``r31`). |
| `RB` | mullwx: read | Source GPR. |
| `RD` | mullwx: write | Destination GPR. |
| `CR` | mullwx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `OE` | mullwx: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
## Register Effects
### `mullwx`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `CR`, `OE`
## Status-Register Effects
- `mullwx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- ((RA)[32:63]) * ((RB)[32:63]) ; signed 32×32 → 64
```
## 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
**`mullwx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mullwx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:390`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L390)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:874`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L874)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:357-371`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L357-L371)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mullwx => {
// PPCBUG-009: 32-bit ABI. Truncate product to u32 — overflow detection
// (mullw_ov) still uses the full i64 product to catch the overflow.
let ra = ctx.gpr[instr.ra()] as i32 as i64;
let rb = ctx.gpr[instr.rb()] as i32 as i64;
let product = ra.wrapping_mul(rb);
ctx.gpr[instr.rd()] = product as u32 as u64;
if instr.oe() {
overflow::apply(ctx, overflow::mullw_ov(product));
}
if instr.rc_bit() {
ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as u32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Extended Pseudocode
```
prod64 <- sign_extend_32_to_64((RA)[32:63]) *s sign_extend_32_to_64((RB)[32:63])
RT <- prod64 ; 64-bit result
if OE then
XER[OV] <- (prod64 ≠ sign_extend_32_to_64(prod64[32:63])) ; set when product doesn't fit in 32 bits
XER[SO] <- XER[SO] | XER[OV]
if Rc then
CR0 <- signed_compare(RT, 0) || XER[SO]
```
## Special Cases & Edge Conditions
- **Inputs are the low 32 bits.** `mullw` only looks at `RA[32:63]` and `RB[32:63]`; the high 32 bits of each source are ignored. This is a 32-bit × 32-bit → 64-bit signed multiply. For full 64-bit operands use [`mulldx`](mulldx.md).
- **Result is sign-extended to 64 bits.** The 64-bit product fits into a 64-bit GPR without loss. Subsequent 32-bit consumers see `RT[32:63]` (the low 32 bits of the product); use [`mulhwx`](mulhwx.md) for the signed high 32 bits or [`mulhwux`](mulhwux.md) for the unsigned high 32 bits, computed in parallel without this instruction.
- **`OE` overflow test is 32-bit.** `XER[OV]` is set iff the 64-bit signed product cannot be represented in 32 bits — equivalently, iff `RT[32] ≠ RT[33] = … = RT[63]` (sign bit disagrees with the next 32 bits). Xenia-rs does **not** implement this; `OE` on `mullwo` is a no-op in the interpreter.
- **Xenia-rs CR0 update bug footprint.** The interpreter computes CR0 from `result as i32 as i64` — the low 32 bits sign-extended. For a 32×32→64 multiply the high 32 bits may be non-zero even when the low 32 bits are zero, so xenia's CR0 can differ from the spec's (which compares the full 64-bit product to zero). In practice this matters only for code that relies on `mullw.` to detect overflow via CR0 — extremely rare.
- **Latency.** On the Xenon, `mullw` has higher latency than add/sub; many hot inner loops avoid it by strength-reduction or shift-add chains. This is irrelevant for correctness but sometimes explains surprising instruction sequences in disassembly.
## Related Instructions
- [`mulhwx`](mulhwx.md) — signed high 32 bits of the same 32×32 product.
- [`mulhwux`](mulhwux.md) — unsigned high 32 bits of a 32×32 product.
- [`mulli`](mulli.md) — D-form: `RT ← (RA[32:63]) × SIMM` (low 64 bits, signed).
- [`mulldx`](mulldx.md), [`mulhdx`](mulhdx.md), [`mulhdux`](mulhdux.md) — 64-bit multiplies (low/high, signed/unsigned).
- [`divwx`](divwx.md), [`divwux`](divwux.md) — 32-bit signed / unsigned division.
## IBM Reference
- [AIX 7.3 — `mullw` (Multiply Low Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mullw-multiply-low-word-instruction)
- [AIX 7.3 — `mulli` (Multiply Low Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mulli-multiply-low-immediate-instruction)

View File

@@ -0,0 +1,122 @@
# `nandx` — NAND
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c0003b8`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `nand` | `nandx` | — | NAND |
| `nand.` | `nandx` | Rc=1 | NAND |
## Syntax
```asm
nand[Rc] [RA], [RS], [RB]
```
## Encoding
### `nandx` — form `X`
- **Opcode word:** `0x7c0003b8`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `476`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | nandx: read | Source GPR (alias for RD in some stores). |
| `RB` | nandx: read | Source GPR. |
| `RA` | nandx: write | Source GPR (`r0``r31`). |
| `CR` | nandx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `nandx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `nandx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- ~((RS) & (RB))
```
## 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
**`nandx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="nandx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:753`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L753)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:812`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L812)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:570-577`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L570-L577)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::nandx => {
// PPCBUG-030: same shape — operate in u32.
let rs32 = ctx.gpr[instr.rs()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
ctx.gpr[instr.ra()] = (!(rs32 & rb32)) as u64;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← ~(RS AND RB)`.** Bit-wise NAND. Since `nand RA, RS, RS = ~RS` (NOT-OR-self), the simplified mnemonic `not RA, RS` assembles to `nor RA, RS, RS` (note: NOR, not NAND). NAND-self is equivalent — both produce `~RS` — but the assembler prefers the NOR form by convention.
- **Operand convention is X-form** (`RA` destination, `RS`/`RB` sources).
- **64-bit operation** on Xenon; `~` operates on the full `u64`.
- **No `OE` or `XER` side effects.** Only `Rc=1` updates `CR0` (signed compare to zero).
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:377`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L377) truncates with `as i32 as i64`. NAND results frequently have all-ones high bits when the low half AND is non-saturating, so the truncation can change CR0 semantics in subtle ways — call out as a quirk if reproducing CR-sensitive behaviour.
- **Idiom: NAND of two equal values produces NOT.** `nand. RA, RS, RS``~RS` with CR0 update. Sometimes used by compilers when `not.` is unavailable in their tablegen.
## Related Instructions
- [`andx`](andx.md), [`andcx`](andcx.md) — base AND family.
- [`norx`](norx.md) — assembler-preferred form for "NOT" via `nor RA, RS, RS`.
- [`eqvx`](eqvx.md) — NXOR.
- [`orx`](orx.md), [`orcx`](orcx.md), [`xorx`](xorx.md) — full logical family.
## IBM Reference
- [AIX 7.3 — `nand` (NAND)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-nand-instruction)

View File

@@ -0,0 +1,132 @@
# `negx` — Negate
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c0000d0`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `neg` | `negx` | — | Negate |
| `nego` | `negx` | OE=1 | Negate |
| `neg.` | `negx` | Rc=1 | Negate |
| `nego.` | `negx` | OE=1, Rc=1 | Negate |
## Syntax
```asm
neg[OE][Rc] [RD], [RA]
```
## Encoding
### `negx` — form `XO`
- **Opcode word:** `0x7c0000d0`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `104`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | negx: read | Source GPR (`r0``r31`). |
| `RD` | negx: write | Destination GPR. |
| `CR` | negx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `OE` | negx: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
## Register Effects
### `negx`
- **Reads (always):** `RA`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `CR`, `OE`
## Status-Register Effects
- `negx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- ~(RA) + 1
```
## 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
**`negx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="negx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:406`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L406)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:866`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L866)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:342-356`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L342-L356)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::negx => {
// PPCBUG-006: 32-bit ABI. `(!ra).wrapping_add(1)` on u64 always
// sets upper 32 bits — every neg poisoned the GPR. neg_ov also
// checks at 64-bit INT_MIN; should be 32-bit INT_MIN.
let ra32 = ctx.gpr[instr.ra()] as u32;
let result32 = (!ra32).wrapping_add(1);
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
overflow::apply(ctx, ra32 == 0x8000_0000);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Two's-complement negate.** `RT ← ~RA + 1`, equivalent to `0 RA`. A specialisation of [`subfx`](subfx.md) where `RB` is implicit zero.
- **`INT64_MIN` is its own negation.** `neg(0x8000000000000000) = 0x8000000000000000` — the only fixed point. `nego` should set `XER[OV]` in this case (it is the canonical signed-overflow trigger), but **xenia-rs does not implement `OE`** ([`interpreter.rs:201`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L201) has no `oe()` branch).
- **`RB` field unused.** Set to 0 by assemblers; ignored.
- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:204`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L204). Important: `neg.` of a 64-bit value with high bits set will give a CR0 that doesn't match spec (which compares the full 64-bit `~RA + 1` to zero).
- **No carry produced.** Use [`subfic`](subficx.md) `RT, RA, 0` (`RT ← 0 RA` with carry) when you need the borrow.
- **Latency: single cycle.** Negate is the cheapest XO-form ALU operation (cheaper than `subf` despite being a special case, because there's no `RB` operand fetch).
## Related Instructions
- [`subfx`](subfx.md) — generalisation: `neg RT, RA``subf RT, RA, 0` (but the latter requires materialising 0 in a register).
- [`subfic`](subficx.md) — `RT ← SIMM RA` with `XER[CA]`; `subfic RT, RA, 0` produces a borrow.
- [`addx`](addx.md), [`addmex`](addmex.md), [`addzex`](addzex.md) — for chained negation (multi-word two's complement).
- `not` (simplified) — bit-wise complement via `nor RA, RS, RS`; distinct from negate.
## IBM Reference
- [AIX 7.3 — `neg` (Negate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-neg-negate-instruction)

View File

@@ -0,0 +1,124 @@
# `norx` — NOR
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c0000f8`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `nor` | `norx` | — | NOR |
| `nor.` | `norx` | Rc=1 | NOR |
## Syntax
```asm
nor[Rc] [RA], [RS], [RB]
```
## Encoding
### `norx` — form `X`
- **Opcode word:** `0x7c0000f8`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `124`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | norx: read | Source GPR (alias for RD in some stores). |
| `RB` | norx: read | Source GPR. |
| `RA` | norx: write | Source GPR (`r0``r31`). |
| `CR` | norx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `norx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `norx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- ~((RS) | (RB))
```
## 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
**`norx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="norx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:763`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L763)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:777`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L777)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:562-569`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L562-L569)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::norx => {
// PPCBUG-029: `not` simplified mnemonic — every `not` poisoned the GPR.
let rs32 = ctx.gpr[instr.rs()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
ctx.gpr[instr.ra()] = (!(rs32 | rb32)) as u64;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← ~(RS OR RB)`.** Bit-wise NOR. The canonical idiom for one-instruction NOT: **`not RA, RS` is the simplified mnemonic for `nor RA, RS, RS`** — both source operands the same yields `~RS`. Almost every disassembly contains this pattern.
- **Operand convention** is X-form (`RA` destination, `RS`/`RB` sources).
- **64-bit operation** on Xenon; full 64-bit complement via `!` on `u64`.
- **No `OE` or `XER` side effects.**
- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:372`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L372) uses `as i32 as i64`. Note that NOR almost always produces results with high bits set (since the OR rarely covers all 64 bits), so the truncated CR0 is usually `LT` (negative low half) where spec might give a different signed compare for the full 64-bit value.
- **`nor.` after a clear-low operation is a common pattern** for testing whether some high-bit mask is empty.
## Related Instructions
- [`orx`](orx.md), [`orcx`](orcx.md) — base OR family.
- [`andx`](andx.md), [`andcx`](andcx.md), [`nandx`](nandx.md) — AND family.
- [`eqvx`](eqvx.md) — NXOR.
- [`xorx`](xorx.md) — XOR.
- `not` (simplified mnemonic for `nor RA, RS, RS`).
## IBM Reference
- [AIX 7.3 — `nor` (NOR)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-nor-instruction)
- [AIX 7.3 — `not` (simplified mnemonic)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-not-complement-register)

View File

@@ -0,0 +1,122 @@
# `orcx` — OR with Complement
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000338`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `orc` | `orcx` | — | OR with Complement |
| `orc.` | `orcx` | Rc=1 | OR with Complement |
## Syntax
```asm
orc[Rc] [RA], [RS], [RB]
```
## Encoding
### `orcx` — form `X`
- **Opcode word:** `0x7c000338`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `412`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | orcx: read | Source GPR (alias for RD in some stores). |
| `RB` | orcx: read | Source GPR. |
| `RA` | orcx: write | Source GPR (`r0``r31`). |
| `CR` | orcx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `orcx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `orcx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- (RS) | ~(RB)
```
## 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
**`orcx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="orcx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:800`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L800)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:807`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L807)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:548-555`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L548-L555)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::orcx => {
// PPCBUG-028: same shape as andcx — operate in u32.
let rs32 = ctx.gpr[instr.rs()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
ctx.gpr[instr.ra()] = (rs32 | !rb32) as u64;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← RS OR (NOT RB)`.** The complement is on `RB`. Useful for setting bits *outside* a mask — e.g. `orc r3, r3, r4` sets in `r3` every bit *not* set in `r4`.
- **Idiom: `orc RA, RS, RS`** = `RS | ~RS` = `-1` (all ones). Cheaper-looking than constructing `1` via `lis`+`ori`, but the assembler usually prefers `li RA, -1` or `eqv RA, RS, RS`.
- **Operand convention** is X-form (`RA` destination, `RS`/`RB` sources).
- **64-bit operation** on Xenon; xenia uses Rust's `!` on `u64` for full-width complement.
- **No `OE` or `XER` side effects.**
- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:362`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L362). Because `~RB` typically has high bits set, `orc.` results often appear `LT` in the truncated CR0.
## Related Instructions
- [`orx`](orx.md) — base OR (no complement).
- [`andcx`](andcx.md) — AND-with-complement; sister `c` form.
- [`norx`](norx.md), [`nandx`](nandx.md) — full-result complements.
- [`eqvx`](eqvx.md) — `~(RS XOR RB)`.
## IBM Reference
- [AIX 7.3 — `orc` (OR with Complement)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-orc-complement-instruction)

View File

@@ -0,0 +1,115 @@
# `ori` — OR Immediate
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x60000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `ori` | `ori` | — | OR Immediate |
## Syntax
```asm
ori [RA], [RS], [UIMM]
```
## Encoding
### `ori` — form `D`
- **Opcode word:** `0x60000000`
- **Primary opcode (bits 05):** `24`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | ori: read | Source GPR (alias for RD in some stores). |
| `UIMM` | ori: read | 16-bit unsigned immediate. Zero-extended. |
| `RA` | ori: write | Source GPR (`r0``r31`). |
## Register Effects
### `ori`
- **Reads (always):** `RS`, `UIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
RA <- (RS) | (0x0000 || UIMM)
```
## 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
**`ori`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ori"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:810`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L810)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:347`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L347)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:512-515`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L512-L515)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::ori => {
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] | (instr.uimm16() as u64);
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **No record form.** Unlike [`andix`](andix.md), `ori` does **not** update `CR0` — there is no `ori.`. If you need a CR update after OR-immediate, follow it with `cmpwi` or use [`orx`](orx.md) with `Rc=1`.
- **Immediate is zero-extended.** Only the low 16 bits of `RA` can be affected; the high 48 bits are passed through from `RS` unchanged.
- **`ori 0, 0, 0` is the canonical NOP.** All PowerPC NOPs assemble to this encoding (`0x60000000`). Disassemblers usually display this as `nop`.
- **Common idiom: build a 32-bit constant via `lis` + `ori`.** `lis r3, hi16; ori r3, r3, lo16` materialises any 32-bit immediate with no CR or XER disturbance.
- **64-bit operation in xenia-rs.** [`interpreter.rs:330`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L330) — full `u64` OR; high bits unchanged from `RS`.
- **`RA = 0` reads `r0`** (not the literal zero). Different from `addi`'s `RA0` semantics; `ori` uses the regular `RA` interpretation.
## Related Instructions
- [`oris`](oris.md) — same op with the immediate shifted left 16.
- [`orx`](orx.md) — register-register; supports `Rc=1`.
- [`xori`](xori.md), [`xoris`](xoris.md), [`andix`](andix.md), [`andisx`](andisx.md) — sister immediate logicals.
- `nop` (simplified) — `ori 0, 0, 0`.
## IBM Reference
- [AIX 7.3 — `ori` (OR Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-ori-immediate-instruction)
- [AIX 7.3 — `nop` (simplified)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-nop-no-operation)

View File

@@ -0,0 +1,113 @@
# `oris` — OR Immediate Shifted
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x64000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `oris` | `oris` | — | OR Immediate Shifted |
## Syntax
```asm
oris [RA], [RS], [UIMM]
```
## Encoding
### `oris` — form `D`
- **Opcode word:** `0x64000000`
- **Primary opcode (bits 05):** `25`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | oris: read | Source GPR (alias for RD in some stores). |
| `UIMM` | oris: read | 16-bit unsigned immediate. Zero-extended. |
| `RA` | oris: write | Source GPR (`r0``r31`). |
## Register Effects
### `oris`
- **Reads (always):** `RS`, `UIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
RA <- (RS) | (UIMM || 0x0000)
```
## 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
**`oris`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="oris"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:821`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L821)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:348`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L348)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:516-519`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L516-L519)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::oris => {
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] | ((instr.uimm16() as u64) << 16);
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **No record form.** No `oris.` — same as [`ori`](ori.md). For CR0 updates use [`orx`](orx.md) with `Rc=1`.
- **Immediate is zero-extended *then* shifted left 16.** Only bits 3247 of `RA` (in PowerISA bit numbering) can be affected; the high 32 bits and low 16 bits of `RA` come from `RS` unchanged.
- **Common pair with `lis`** to load a 32-bit constant: `lis r3, hi16` (= `addis r3, 0, hi16`), then `ori r3, r3, lo16`. **For unsigned constants whose low half has the high bit set**, `lis` followed by `ori` works cleanly because `ori` is zero-extending; using `addi` instead would sign-extend `lo16` and corrupt the constant.
- **64-bit operation in xenia-rs.** [`interpreter.rs:334`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L334).
- **No `XER`, no `CR` effect.** Pure register OR.
- **`RA = 0` reads `r0`** (not literal zero); see [`ori`](ori.md).
## Related Instructions
- [`ori`](ori.md) — companion (immediate not shifted).
- [`addis`](addis.md) — D-form add-immediate-shifted; pairs with `ori` to build constants.
- [`xoris`](xoris.md), [`andisx`](andisx.md) — sister immediate-shifted logicals.
## IBM Reference
- [AIX 7.3 — `oris` (OR Immediate Shifted)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-oris-immediate-shifted-instruction)

View File

@@ -0,0 +1,122 @@
# `orx` — OR
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000378`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `or` | `orx` | — | OR |
| `or.` | `orx` | Rc=1 | OR |
## Syntax
```asm
or[Rc] [RA], [RS], [RB]
```
## Encoding
### `orx` — form `X`
- **Opcode word:** `0x7c000378`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `444`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | orx: read | Source GPR (alias for RD in some stores). |
| `RB` | orx: read | Source GPR. |
| `RA` | orx: write | Source GPR (`r0``r31`). |
| `CR` | orx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `orx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `orx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- (RS) | (RB)
```
## 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
**`orx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="orx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:773`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L773)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:809`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L809)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:542-547`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L542-L547)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::orx => {
// PPCBUG-032+020: 32-bit ABI CR0 view.
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] | ctx.gpr[instr.rb()];
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Canonical "register move".** `or RA, RS, RS` copies `RS` to `RA` — assemblers expose this as the simplified mnemonic **`mr RA, RS`** (move register). It is the single most common instruction in PPC disassembly after loads/stores.
- **Operand convention** is X-form (`RA` destination, `RS`/`RB` sources).
- **64-bit operation** on Xenon; full bitwise OR across 64 bits.
- **No `OE` or `XER` side effects.** Only `Rc=1` updates `CR0`.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:357`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L357) truncates with `as i32 as i64`. For `or. RA, RS, RS` (i.e. `mr.`), this means CR0 reflects the low 32 bits of `RS` only — distinguishable from spec only when the high 32 bits are non-zero with all-zero low 32.
- **`or 26, 26, 26` is the Xbox 360 NOP variant** historically used to mark cache lines or signal the dispatch unit (alongside `nop``ori 0,0,0`). Disassembly may show this — it has no architectural effect.
## Related Instructions
- [`orcx`](orcx.md) — OR with complement.
- [`norx`](norx.md) — NOR (and the basis for `not`).
- [`andx`](andx.md), [`xorx`](xorx.md), [`eqvx`](eqvx.md) — sister logicals.
- [`ori`](ori.md), [`oris`](oris.md) — D-form immediate variants (no record form).
- `mr` (simplified) — `or RA, RS, RS`.
## IBM Reference
- [AIX 7.3 — `or` (OR)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-instruction-1)
- [AIX 7.3 — `mr` (Move Register, simplified)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-mr-move-register)

View File

@@ -0,0 +1,137 @@
# `rldclx` — Rotate Left Doubleword then Clear Left
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [MDS](../forms/MDS.md) · **Opcode:** `0x78000010`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `rldcl` | `rldclx` | — | Rotate Left Doubleword then Clear Left |
| `rldcl.` | `rldclx` | Rc=1 | Rotate Left Doubleword then Clear Left |
## Syntax
```asm
rldcl[Rc] [RA], [RS], [RB], [MB]
```
## Encoding
### `rldclx` — form `MDS`
- **Opcode word:** `0x78000010`
- **Primary opcode (bits 05):** `30`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (30) |
| 610 | `RS` | source GPR |
| 1115 | `RA` | destination GPR |
| 1620 | `RB` | source B GPR |
| 2126 | `mb/me` | 6-bit mask field (swapped halves) |
| 2730 | `XO` | extended opcode |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | rldclx: read | Source GPR (alias for RD in some stores). |
| `RB` | rldclx: read | Source GPR. |
| `MB` | rldclx: read | Mask begin bit. |
| `RA` | rldclx: write | Source GPR (`r0``r31`). |
| `CR` | rldclx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `rldclx`
- **Reads (always):** `RS`, `RB`, `MB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `rldclx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`rldclx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldclx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:856`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L856)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:733`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L733)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:802-811`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L802-L811)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::rldclx => {
let rs = ctx.gpr[instr.rs()];
let sh = ctx.gpr[instr.rb()] & 0x3F;
let mb = instr.mb_md();
let rotated = rs.rotate_left(sh as u32);
let mask = rld_mask_left(mb);
ctx.gpr[instr.ra()] = rotated & mask;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← ROTL64(RS, RB[58:63]) & MASK(MB, 63)`.** Rotate `RS` left by `RB & 0x3F`, then *clear* bits to the left of `MB` — i.e. keep bits `MB..63`, force bits `0..MB-1` to zero.
- **Shift comes from a register.** Unlike [`rldiclx`](rldiclx.md), the rotate amount is dynamic. Only the low 6 bits of `RB` are used (`& 0x3F`); the upper 58 bits are silently ignored.
- **`MB` is a split 6-bit field.** Bit 5 of the encoded `mb/me` is *swapped* into bit position 5 (raw bit 30) — xenia decodes via `(instr.mb() << 1) | ((raw >> 1) & 1)` ([`interpreter.rs:587`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L587)). This MDS form is unusual; if you write a decoder, follow this exact bit assembly.
- **Mask generation.** `rld_mask_left(MB)` is `(1 << (64 - MB)) - 1` — i.e. clear bits `0..MB-1`, keep bits `MB..63`. When `MB = 0` the mask is all ones; when `MB = 63` only bit 63 survives.
- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:592`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L592) uses `as i64` directly — no truncation. The rotate-and-mask family is one of the few xenia-rs instruction groups that already does the spec-correct 64-bit CR0 compare.
- **No `XER` effect.**
- **Use over [`rldiclx`](rldiclx.md)** when the shift amount is computed at runtime (e.g. via `cntlzd` for normalisation).
## Related Instructions
- [`rldcrx`](rldcrx.md) — sister: clear *right* instead of left.
- [`rldiclx`](rldiclx.md), [`rldicrx`](rldicrx.md), [`rldicx`](rldicx.md) — immediate-shift variants.
- [`rldimix`](rldimix.md) — rotate and mask insert.
- [`rlwnmx`](rlwnmx.md), [`rlwinmx`](rlwinmx.md) — 32-bit cousins.
- [`sldx`](sldx.md), [`srdx`](srdx.md) — preferred for plain 64-bit shifts.
## IBM Reference
- [AIX 7.3 — `rldcl` (Rotate Left Doubleword then Clear Left)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-rldcl-rotate-left-double-word-then-clear-left-instruction)

View File

@@ -0,0 +1,136 @@
# `rldcrx` — Rotate Left Doubleword then Clear Right
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [MDS](../forms/MDS.md) · **Opcode:** `0x78000012`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `rldcr` | `rldcrx` | — | Rotate Left Doubleword then Clear Right |
| `rldcr.` | `rldcrx` | Rc=1 | Rotate Left Doubleword then Clear Right |
## Syntax
```asm
rldcr[Rc] [RA], [RS], [RB], [ME]
```
## Encoding
### `rldcrx` — form `MDS`
- **Opcode word:** `0x78000012`
- **Primary opcode (bits 05):** `30`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (30) |
| 610 | `RS` | source GPR |
| 1115 | `RA` | destination GPR |
| 1620 | `RB` | source B GPR |
| 2126 | `mb/me` | 6-bit mask field (swapped halves) |
| 2730 | `XO` | extended opcode |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | rldcrx: read | Source GPR (alias for RD in some stores). |
| `RB` | rldcrx: read | Source GPR. |
| `ME` | rldcrx: read | Mask end bit. |
| `RA` | rldcrx: write | Source GPR (`r0``r31`). |
| `CR` | rldcrx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `rldcrx`
- **Reads (always):** `RS`, `RB`, `ME`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `rldcrx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`rldcrx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldcrx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:881`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L881)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:734`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L734)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:812-821`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L812-L821)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::rldcrx => {
let rs = ctx.gpr[instr.rs()];
let sh = ctx.gpr[instr.rb()] & 0x3F;
let me = instr.mb_md();
let rotated = rs.rotate_left(sh as u32);
let mask = rld_mask_right(me);
ctx.gpr[instr.ra()] = rotated & mask;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← ROTL64(RS, RB[58:63]) & MASK(0, ME)`.** Rotate `RS` left by `RB & 0x3F`, then *clear* bits to the right of `ME` — keep bits `0..ME`, force bits `ME+1..63` to zero.
- **Shift from register.** Same as [`rldclx`](rldclx.md): only the low 6 bits of `RB` count.
- **`ME` is a split 6-bit field.** Same swap-decoded layout as `MB` in `rldclx`: `(instr.mb() << 1) | ((raw >> 1) & 1)` ([`interpreter.rs:597`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L597)). Note that even though it represents `ME` here, xenia reads it from `instr.mb()` because the field shares the same encoding slot.
- **Mask generation.** `rld_mask_right(ME)` = `~((1 << (63 - ME)) - 1)` keeping bits `0..ME`. When `ME = 63` the mask is all ones; when `ME = 0` only bit 0 survives.
- **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly ([`interpreter.rs:602`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L602)).
- **No `XER` effect.**
- **Useful for left-shift with arbitrary discard.** `rldcr RA, RS, RB, 63 - n` is functionally close to a left-shift-and-mask sequence, with the rotate variant additionally allowing wrap-around.
## Related Instructions
- [`rldclx`](rldclx.md) — sister: clear *left* instead of right.
- [`rldicrx`](rldicrx.md) — immediate-shift form.
- [`rldicx`](rldicx.md), [`rldiclx`](rldiclx.md), [`rldimix`](rldimix.md) — full immediate rotate-and-mask family.
- [`sldx`](sldx.md) — plain 64-bit logical left shift (often a strength-reduced equivalent).
## IBM Reference
- [AIX 7.3 — `rldcr` (Rotate Left Doubleword then Clear Right)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-rldcr-rotate-left-double-word-then-clear-right-instruction)

View File

@@ -0,0 +1,142 @@
# `rldiclx` — Rotate Left Doubleword Immediate then Clear Left
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [MD](../forms/MD.md) · **Opcode:** `0x78000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `rldicl` | `rldiclx` | — | Rotate Left Doubleword Immediate then Clear Left |
| `rldicl.` | `rldiclx` | Rc=1 | Rotate Left Doubleword Immediate then Clear Left |
## Syntax
```asm
rldicl[Rc] [RA], [RS], [SH], [MB]
```
## Encoding
### `rldiclx` — form `MD`
- **Opcode word:** `0x78000000`
- **Primary opcode (bits 05):** `30`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (30) |
| 610 | `RS` | source GPR |
| 1115 | `RA` | destination GPR |
| 1620 | `sh` | shift amount low 5 bits |
| 2126 | `mb/me` | 6-bit mask field (swapped halves) |
| 2729 | `XO` | extended opcode |
| 30 | `sh5` | shift amount high bit |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | rldiclx: read | Source GPR (alias for RD in some stores). |
| `SH` | rldiclx: read | Shift amount. |
| `MB` | rldiclx: read | Mask begin bit. |
| `RA` | rldiclx: write | Source GPR (`r0``r31`). |
| `CR` | rldiclx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `rldiclx`
- **Reads (always):** `RS`, `SH`, `MB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `rldiclx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`rldiclx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldiclx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:929`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L929)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:728`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L728)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:762-771`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L762-L771)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::rldiclx => {
let rs = ctx.gpr[instr.rs()];
let sh = instr.sh64();
let mb = instr.mb_md();
let rotated = rs.rotate_left(sh);
let mask = rld_mask_left(mb);
ctx.gpr[instr.ra()] = rotated & mask;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← ROTL64(RS, SH) & MASK(MB, 63)`.** Rotate left by `SH`, then clear bits 0 through `MB-1`. The mask retains bits `MB..63`.
- **The Swiss-army knife of bit extraction.** Many assembler shorthands lower to this single instruction:
- `srdi RA, RS, n``rldicl RA, RS, 64-n, n` — logical right shift by `n`.
- `clrldi RA, RS, n``rldicl RA, RS, 0, n` — clear top `n` bits.
- `extrdi RA, RS, n, b``rldicl RA, RS, b+n, 64-n` — extract `n` bits starting at `b`.
- **`SH` is 6 bits, immediate** (bits 1620 + bit 30). Xenia uses `instr.sh64()` to assemble them.
- **`MB` is 6 bits, split-encoded** (`(instr.mb() << 1) | ((raw >> 1) & 1)`).
- **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly ([`interpreter.rs:551`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L551)).
- **No `XER` effect.**
- **Often appears in compiled disassembly** as a generic 64-bit shift. Decoding back to the simplified mnemonic above makes the intent obvious.
## Related Instructions
- [`rldicrx`](rldicrx.md) — clear-right counterpart (`MASK(0, ME)`).
- [`rldicx`](rldicx.md) — clear both ends.
- [`rldclx`](rldclx.md) — register-shift version.
- [`rlwinmx`](rlwinmx.md) — 32-bit cousin.
- `srdi`, `clrldi`, `extrdi` (simplified mnemonics).
## IBM Reference
- [AIX 7.3 — `rldicl` (Rotate Left Doubleword Immediate then Clear Left)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-rldicl-rotate-left-double-word-immediate-then-clear-left-instruction)
- [AIX 7.3 — Simplified shift/extract mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-rotate-shift)

View File

@@ -0,0 +1,142 @@
# `rldicrx` — Rotate Left Doubleword Immediate then Clear Right
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [MD](../forms/MD.md) · **Opcode:** `0x78000004`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `rldicr` | `rldicrx` | — | Rotate Left Doubleword Immediate then Clear Right |
| `rldicr.` | `rldicrx` | Rc=1 | Rotate Left Doubleword Immediate then Clear Right |
## Syntax
```asm
rldicr[Rc] [RA], [RS], [SH], [ME]
```
## Encoding
### `rldicrx` — form `MD`
- **Opcode word:** `0x78000004`
- **Primary opcode (bits 05):** `30`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (30) |
| 610 | `RS` | source GPR |
| 1115 | `RA` | destination GPR |
| 1620 | `sh` | shift amount low 5 bits |
| 2126 | `mb/me` | 6-bit mask field (swapped halves) |
| 2729 | `XO` | extended opcode |
| 30 | `sh5` | shift amount high bit |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | rldicrx: read | Source GPR (alias for RD in some stores). |
| `SH` | rldicrx: read | Shift amount. |
| `ME` | rldicrx: read | Mask end bit. |
| `RA` | rldicrx: write | Source GPR (`r0``r31`). |
| `CR` | rldicrx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `rldicrx`
- **Reads (always):** `RS`, `SH`, `ME`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `rldicrx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`rldicrx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldicrx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:957`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L957)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:729`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L729)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:772-781`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L772-L781)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::rldicrx => {
let rs = ctx.gpr[instr.rs()];
let sh = instr.sh64();
let me = instr.mb_md();
let rotated = rs.rotate_left(sh);
let mask = rld_mask_right(me);
ctx.gpr[instr.ra()] = rotated & mask;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← ROTL64(RS, SH) & MASK(0, ME)`.** Rotate left by `SH`, then clear bits `ME+1..63`.
- **Common simplified mnemonics:**
- `sldi RA, RS, n``rldicr RA, RS, n, 63-n` — logical left shift by `n`.
- `clrrdi RA, RS, n``rldicr RA, RS, 0, 63-n` — clear low `n` bits.
- `extldi RA, RS, n, b``rldicr RA, RS, b, n-1` — extract `n` bits from position `b` left-aligned.
- **`SH` is 6 bits, immediate.** Same `instr.sh64()` decode as the rest of the family.
- **`ME` is 6 bits, split-encoded.** Xenia stores it via `instr.mb()` — the field shares the slot with `MB` from sister instructions; the operation just interprets it as the right edge.
- **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly ([`interpreter.rs:561`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L561)).
- **No `XER` effect.**
- **Heavily emitted by 64-bit code generators** for left-shift-and-clear sequences. Recognising the simplified mnemonics aids disassembly.
## Related Instructions
- [`rldiclx`](rldiclx.md) — clear-left counterpart (`MASK(MB, 63)`).
- [`rldicx`](rldicx.md) — clear both ends.
- [`rldcrx`](rldcrx.md) — register-shift version.
- [`rldimix`](rldimix.md) — insert under mask.
- [`rlwinmx`](rlwinmx.md) — 32-bit cousin.
- `sldi`, `clrrdi`, `extldi` (simplified mnemonics).
## IBM Reference
- [AIX 7.3 — `rldicr` (Rotate Left Doubleword Immediate then Clear Right)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-rldicr-rotate-left-double-word-immediate-then-clear-right-instruction)

View File

@@ -0,0 +1,138 @@
# `rldicx` — Rotate Left Doubleword Immediate then Clear
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [MD](../forms/MD.md) · **Opcode:** `0x78000008`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `rldic` | `rldicx` | — | Rotate Left Doubleword Immediate then Clear |
| `rldic.` | `rldicx` | Rc=1 | Rotate Left Doubleword Immediate then Clear |
## Syntax
```asm
rldic[Rc] [RA], [RS], [SH], [MB]
```
## Encoding
### `rldicx` — form `MD`
- **Opcode word:** `0x78000008`
- **Primary opcode (bits 05):** `30`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (30) |
| 610 | `RS` | source GPR |
| 1115 | `RA` | destination GPR |
| 1620 | `sh` | shift amount low 5 bits |
| 2126 | `mb/me` | 6-bit mask field (swapped halves) |
| 2729 | `XO` | extended opcode |
| 30 | `sh5` | shift amount high bit |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | rldicx: read | Source GPR (alias for RD in some stores). |
| `SH` | rldicx: read | Shift amount. |
| `MB` | rldicx: read | Mask begin bit. |
| `RA` | rldicx: write | Source GPR (`r0``r31`). |
| `CR` | rldicx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `rldicx`
- **Reads (always):** `RS`, `SH`, `MB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `rldicx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`rldicx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldicx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:906`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L906)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:730`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L730)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:782-791`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L782-L791)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::rldicx => {
let rs = ctx.gpr[instr.rs()];
let sh = instr.sh64();
let mb = instr.mb_md();
let rotated = rs.rotate_left(sh);
let mask = rld_mask_left(mb) & rld_mask_right(63 - sh);
ctx.gpr[instr.ra()] = rotated & mask;
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← ROTL64(RS, SH) & MASK(MB, 63 - SH)`.** Rotate `RS` left by `SH` bits, then mask off both ends: clear bits `0..MB-1` *and* clear bits `64-SH..63`. This is the "clear at both edges" variant — useful for inserting a field into an otherwise-zero register.
- **`SH` is a 6-bit immediate** spanning bits 1620 plus bit 30 of the instruction word. Xenia uses the helper `instr.sh64()` ([`interpreter.rs:566`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L566)) to assemble the 6 bits.
- **`MB` is also 6-bit, split-encoded** like the rest of the `rld*` family: `(instr.mb() << 1) | ((raw >> 1) & 1)`.
- **Mask is computed as `MASK_LEFT(MB) AND MASK_RIGHT(63 - SH)`.** This produces the equivalent of "left-shift `RS` by `SH` then clear high bits above bit `MB`" — a common pattern when `MB ≤ 63 - SH`.
- **Equivalent to a logical shift when `MB = 0`.** `rldic RA, RS, SH, 0``sldi RA, RS, SH` (an alias the assembler may prefer).
- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:571`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L571) uses `as i64` directly.
- **No `XER` effect.**
## Related Instructions
- [`rldiclx`](rldiclx.md), [`rldicrx`](rldicrx.md) — clear-only-one-side variants.
- [`rldclx`](rldclx.md), [`rldcrx`](rldcrx.md) — register-shift forms.
- [`rldimix`](rldimix.md) — insert under mask.
- [`rlwinmx`](rlwinmx.md) — 32-bit cousin.
- `sldi` (simplified) — `rldic RA, RS, n, 0`; assemblers prefer this for plain logical left shifts.
## IBM Reference
- [AIX 7.3 — `rldic` (Rotate Left Doubleword Immediate then Clear)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-rldic-rotate-left-double-word-immediate-then-clear-instruction)

View File

@@ -0,0 +1,136 @@
# `rldimix` — Rotate Left Doubleword Immediate then Mask Insert
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [MD](../forms/MD.md) · **Opcode:** `0x7800000c`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `rldimi` | `rldimix` | — | Rotate Left Doubleword Immediate then Mask Insert |
| `rldimi.` | `rldimix` | Rc=1 | Rotate Left Doubleword Immediate then Mask Insert |
## Syntax
```asm
rldimi[Rc] [RA], [RS], [SH], [MB]
```
## Encoding
### `rldimix` — form `MD`
- **Opcode word:** `0x7800000c`
- **Primary opcode (bits 05):** `30`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (30) |
| 610 | `RS` | source GPR |
| 1115 | `RA` | destination GPR |
| 1620 | `sh` | shift amount low 5 bits |
| 2126 | `mb/me` | 6-bit mask field (swapped halves) |
| 2729 | `XO` | extended opcode |
| 30 | `sh5` | shift amount high bit |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | rldimix: read | Source GPR (alias for RD in some stores). |
| `SH` | rldimix: read | Shift amount. |
| `MB` | rldimix: read | Mask begin bit. |
| `RA` | rldimix: write | Source GPR (`r0``r31`). |
| `CR` | rldimix: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `rldimix`
- **Reads (always):** `RS`, `SH`, `MB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `rldimix`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`rldimix`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldimix"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:985`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L985)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:731`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L731)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:792-801`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L792-L801)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::rldimix => {
let rs = ctx.gpr[instr.rs()];
let sh = instr.sh64();
let mb = instr.mb_md();
let rotated = rs.rotate_left(sh);
let mask = rld_mask_left(mb) & rld_mask_right(63 - sh);
ctx.gpr[instr.ra()] = (rotated & mask) | (ctx.gpr[instr.ra()] & !mask);
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← (ROTL64(RS, SH) & MASK) | (RA & ~MASK)`.** *Reads* the prior `RA` so it can preserve the bits outside the mask — this is the only `rld*` instruction with `RA` as both source and destination.
- **Mask is `MASK_LEFT(MB) AND MASK_RIGHT(63 - SH)`** ([`interpreter.rs:578`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L578)) — same span as [`rldicx`](rldicx.md), but the un-masked region is preserved in the destination instead of being zeroed.
- **Use to insert a bit-field.** Common idiom: `rldimi RA, RS, b, mask_start` writes `RS`'s low (`64 - mask_start`) bits into `RA` starting at bit `b`.
- **`SH` and `MB` decoding** is identical to the rest of the family (6-bit `sh` via `instr.sh64()`, 6-bit `mb` via the swap layout).
- **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly.
- **No `XER` effect.**
- **Compile-time pattern.** When you see `rldimi r3, r4, n, m`, the compiler is splicing a value into `r3`; recover the meaning by computing the mask `MASK(m, 63 - n)`.
## Related Instructions
- [`rldicx`](rldicx.md), [`rldiclx`](rldiclx.md), [`rldicrx`](rldicrx.md) — same form family, but they zero outside the mask instead of preserving.
- [`rlwimix`](rlwimix.md) — 32-bit insert cousin.
- [`rldclx`](rldclx.md), [`rldcrx`](rldcrx.md) — register-shift forms (no insert variant).
## IBM Reference
- [AIX 7.3 — `rldimi` (Rotate Left Doubleword Immediate then Mask Insert)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-rldimi-rotate-left-double-word-immediate-then-mask-insert-instruction)

View File

@@ -0,0 +1,139 @@
# `rlwimix` — Rotate Left Word Immediate then Mask Insert
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [M](../forms/M.md) · **Opcode:** `0x50000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `rlwimi` | `rlwimix` | — | Rotate Left Word Immediate then Mask Insert |
| `rlwimi.` | `rlwimix` | Rc=1 | Rotate Left Word Immediate then Mask Insert |
## Syntax
```asm
rlwimi[Rc] [RA], [RS], [SH], [MB], [ME]
```
## Encoding
### `rlwimix` — form `M`
- **Opcode word:** `0x50000000`
- **Primary opcode (bits 05):** `20`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RS` | source GPR |
| 1115 | `RA` | destination GPR |
| 1620 | `SH/RB` | shift amount or source B |
| 2125 | `MB` | mask begin |
| 2630 | `ME` | mask end |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | rlwimix: read | Source GPR (alias for RD in some stores). |
| `SH` | rlwimix: read | Shift amount. |
| `MB` | rlwimix: read | Mask begin bit. |
| `ME` | rlwimix: read | Mask end bit. |
| `RA` | rlwimix: write | Source GPR (`r0``r31`). |
| `CR` | rlwimix: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `rlwimix`
- **Reads (always):** `RS`, `SH`, `MB`, `ME`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `rlwimix`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`rlwimix`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rlwimix"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1010`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1010)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:344`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L344)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:737-749`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L737-L749)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::rlwimix => {
let rs = ctx.gpr[instr.rs()] as u32;
let sh = instr.sh();
let mb = instr.mb();
let me = instr.me();
let rotated = rs.rotate_left(sh);
let mask = rlw_mask(mb, me);
let ra = ctx.gpr[instr.ra()] as u32;
ctx.gpr[instr.ra()] = ((rotated & mask) | (ra & !mask)) as u64;
// PPCBUG-025: 32-bit ABI CR0 view.
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← (ROTL32(RS[32:63], SH) & MASK) | (RA[32:63] & ~MASK)`.** Reads the low 32 bits of `RS`, rotates them, then *inserts* under the mask back into the low 32 bits of `RA`. The high 32 bits of `RA` are *implementation-defined* per spec; **xenia-rs zeroes them** (the `as u32` cast at [`interpreter.rs:529`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L529) discards them on read, then `as u64` zero-extends on write).
- **Mask follows the standard `MB..ME` PPC convention.** Both `MB` and `ME` are 5-bit fields; the mask is contiguous when `MB <= ME`, and *wraps* around (a "donut" mask: bits `MB..31` and `0..ME`) when `MB > ME`. Xenia's `rlw_mask(mb, me)` helper handles both cases.
- **`SH` is 5 bits.** Rotate amount is `SH mod 32`; values `≥ 32` are not encodable in this M-form.
- **Used for bit-field insertion** (`insrwi RA, RS, n, b``rlwimi RA, RS, 32-(b+n), b, b+n-1`). Compilers emit `rlwimi` extensively for struct-bitfield writes.
- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:531`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L531). Since the high 32 bits of the result are zero, this matches spec's compare on the (defined) low half — but if a real Xenon left high bits non-zero, behaviour would diverge.
- **No `XER` effect.**
## Related Instructions
- [`rlwinmx`](rlwinmx.md) — same mask family but zeroes outside (no read-modify-write).
- [`rlwnmx`](rlwnmx.md) — register-shift variant of `rlwinm`.
- [`rldimix`](rldimix.md) — 64-bit insert cousin.
- `insrwi`, `inslwi` (simplified mnemonics for common insert patterns).
## IBM Reference
- [AIX 7.3 — `rlwimi` (Rotate Left Word Immediate then Mask Insert)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-rlwimi-rotate-left-word-immediate-then-mask-insert-instruction)

View File

@@ -0,0 +1,145 @@
# `rlwinmx` — Rotate Left Word Immediate then AND with Mask
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [M](../forms/M.md) · **Opcode:** `0x54000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `rlwinm` | `rlwinmx` | — | Rotate Left Word Immediate then AND with Mask |
| `rlwinm.` | `rlwinmx` | Rc=1 | Rotate Left Word Immediate then AND with Mask |
## Syntax
```asm
rlwinm[Rc] [RA], [RS], [SH], [MB], [ME]
```
## Encoding
### `rlwinmx` — form `M`
- **Opcode word:** `0x54000000`
- **Primary opcode (bits 05):** `21`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RS` | source GPR |
| 1115 | `RA` | destination GPR |
| 1620 | `SH/RB` | shift amount or source B |
| 2125 | `MB` | mask begin |
| 2630 | `ME` | mask end |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | rlwinmx: read | Source GPR (alias for RD in some stores). |
| `SH` | rlwinmx: read | Shift amount. |
| `MB` | rlwinmx: read | Mask begin bit. |
| `ME` | rlwinmx: read | Mask end bit. |
| `RA` | rlwinmx: write | Source GPR (`r0``r31`). |
| `CR` | rlwinmx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `rlwinmx`
- **Reads (always):** `RS`, `SH`, `MB`, `ME`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `rlwinmx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`rlwinmx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rlwinmx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1046`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1046)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:345`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L345)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:725-736`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L725-L736)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::rlwinmx => {
let rs = ctx.gpr[instr.rs()] as u32;
let sh = instr.sh();
let mb = instr.mb();
let me = instr.me();
let rotated = rs.rotate_left(sh);
let mask = rlw_mask(mb, me);
ctx.gpr[instr.ra()] = (rotated & mask) as u64;
// PPCBUG-024: 32-bit ABI CR0 view.
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← ROTL32(RS[32:63], SH) & MASK(MB, ME)`.** Take the low 32 bits of `RS`, rotate them left by `SH`, AND with a 32-bit mask. The high 32 bits of `RA` are zero (`as u64` zero-extension on the result).
- **The 32-bit Swiss army knife.** Most 32-bit shift/extract simplified mnemonics expand to this single instruction:
- `slwi RA, RS, n``rlwinm RA, RS, n, 0, 31-n` — logical left shift.
- `srwi RA, RS, n``rlwinm RA, RS, 32-n, n, 31` — logical right shift.
- `clrlwi RA, RS, n``rlwinm RA, RS, 0, n, 31` — clear high `n` bits.
- `clrrwi RA, RS, n``rlwinm RA, RS, 0, 0, 31-n` — clear low `n` bits.
- `extlwi`, `extrwi`, `clrlslwi` — full mnemonic family in PowerISA appendix.
- **Mask convention `MB..ME`** is contiguous when `MB ≤ ME`. When `MB > ME`, the mask is the *complement* of bits `ME+1..MB-1` — a donut/wrap mask. Xenia's `rlw_mask` handles both.
- **`SH` is 5 bits**, rotate amount `0..31`.
- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:518`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L518). Since the result fits in 32 bits, the truncation matches spec exactly.
- **No `XER` effect.**
## Related Instructions
- [`rlwimix`](rlwimix.md) — same mask family with read-modify-write insert.
- [`rlwnmx`](rlwnmx.md) — register-shift version.
- [`rldiclx`](rldiclx.md), [`rldicrx`](rldicrx.md) — 64-bit cousins.
- [`slwx`](slwx.md), [`srwx`](srwx.md), [`srawix`](srawix.md) — straight 32-bit shift instructions.
- `slwi`, `srwi`, `clrlwi`, `clrrwi`, `extlwi`, `extrwi` (simplified mnemonics).
## IBM Reference
- [AIX 7.3 — `rlwinm` (Rotate Left Word Immediate then AND with Mask)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-rlwinm-rotate-left-word-immediate-then-mask-instruction)
- [AIX 7.3 — Rotate / shift simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-rotate-shift)

View File

@@ -0,0 +1,139 @@
# `rlwnmx` — Rotate Left Word then AND with Mask
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [M](../forms/M.md) · **Opcode:** `0x5c000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `rlwnm` | `rlwnmx` | — | Rotate Left Word then AND with Mask |
| `rlwnm.` | `rlwnmx` | Rc=1 | Rotate Left Word then AND with Mask |
## Syntax
```asm
rlwnm[Rc] [RA], [RS], [RB], [MB], [ME]
```
## Encoding
### `rlwnmx` — form `M`
- **Opcode word:** `0x5c000000`
- **Primary opcode (bits 05):** `23`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RS` | source GPR |
| 1115 | `RA` | destination GPR |
| 1620 | `SH/RB` | shift amount or source B |
| 2125 | `MB` | mask begin |
| 2630 | `ME` | mask end |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | rlwnmx: read | Source GPR (alias for RD in some stores). |
| `RB` | rlwnmx: read | Source GPR. |
| `MB` | rlwnmx: read | Mask begin bit. |
| `ME` | rlwnmx: read | Mask end bit. |
| `RA` | rlwnmx: write | Source GPR (`r0``r31`). |
| `CR` | rlwnmx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `rlwnmx`
- **Reads (always):** `RS`, `RB`, `MB`, `ME`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `rlwnmx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`rlwnmx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rlwnmx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1101`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1101)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:346`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L346)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:750-761`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L750-L761)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::rlwnmx => {
let rs = ctx.gpr[instr.rs()] as u32;
let sh = ctx.gpr[instr.rb()] as u32 & 0x1F;
let mb = instr.mb();
let me = instr.me();
let rotated = rs.rotate_left(sh);
let mask = rlw_mask(mb, me);
ctx.gpr[instr.ra()] = (rotated & mask) as u64;
// PPCBUG-026: 32-bit ABI CR0 view.
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← ROTL32(RS[32:63], RB[59:63]) & MASK(MB, ME)`.** Identical to [`rlwinmx`](rlwinmx.md) except the rotate amount comes from the low 5 bits of `RB`. Xenia masks with `& 0x1F` ([`interpreter.rs:535`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L535)).
- **Use over `rlwinm`** when the rotate amount is dynamic (e.g. computed from a `cntlzw` for normalisation, or read from a parameter).
- **Mask is still 5+5 bits immediate** — `MB` and `ME` are not register-sourced; only the shift is. This is the M-form's quirk: only one of (`SH`, `MB`, `ME`) is variable across the family.
- **Donut masks supported.** `MB > ME` produces a wraparound mask, same as `rlwinm`.
- **High 32 bits of `RA` are zero** (32-bit operation, then `as u64` zero-extends).
- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:540`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L540) — harmless because the result already fits in 32 bits.
- **No `XER` effect.**
## Related Instructions
- [`rlwinmx`](rlwinmx.md) — same op, immediate shift.
- [`rlwimix`](rlwimix.md) — insert variant (no register-shift form exists for insert).
- [`rldclx`](rldclx.md), [`rldcrx`](rldcrx.md) — 64-bit register-shift cousins.
- [`slwx`](slwx.md), [`srwx`](srwx.md) — straight 32-bit shifts.
## IBM Reference
- [AIX 7.3 — `rlwnm` (Rotate Left Word then AND with Mask)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-rlwnm-rotate-left-word-then-mask-instruction)

View File

@@ -0,0 +1,124 @@
# `sldx` — Shift Left Doubleword
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000036`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `sld` | `sldx` | — | Shift Left Doubleword |
| `sld.` | `sldx` | Rc=1 | Shift Left Doubleword |
## Syntax
```asm
sld[Rc] [RA], [RS], [RB]
```
## Encoding
### `sldx` — form `X`
- **Opcode word:** `0x7c000036`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `27`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | sldx: read | Source GPR (alias for RD in some stores). |
| `RB` | sldx: read | Source GPR. |
| `RA` | sldx: write | Source GPR (`r0``r31`). |
| `CR` | sldx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `sldx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `sldx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
n <- (RB)[57:63]
RA <- ((RS) << n) if n < 64 else 0
```
## 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
**`sldx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sldx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1122`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1122)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:759`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L759)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:676-683`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L676-L683)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::sldx => {
let sh = ctx.gpr[instr.rb()] & 0x7F;
ctx.gpr[instr.ra()] = if sh < 64 {
ctx.gpr[instr.rs()] << sh
} else { 0 };
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **64-bit logical left shift.** `RA ← RS << (RB & 0x7F)` if the shift count is `< 64`, otherwise `RA = 0`. Bits shifted past bit 0 are discarded.
- **Critical: shift count is *7 bits*, not 6.** PowerISA reads `RB[57:63]` (7 bits, `0..127`). Counts in `[64, 127]` produce zero, *not* `RS << (count mod 64)`. Xenia respects this with `& 0x7F` and an explicit `if sh < 64` check ([`interpreter.rs:464`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L464)). C semantics' undefined behaviour for `<<` with a count `>= width` is a spec-violation source if you naïvely translate.
- **No `XER[CA]` produced** by left shifts. Logical right [`srdx`](srdx.md) and arithmetic right [`sradx`](sradx.md) differ here — arithmetic right *does* set `CA`.
- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:467`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L467) uses `as i64` directly. CR0 reflects the sign of the full 64-bit shifted value (which is 0 for shifts ≥ 64, otherwise either `LT`/`GT`/`EQ`).
- **Strength-reduced from `mulli` for power-of-two multipliers.**
- **No `OE` bit.**
## Related Instructions
- [`slwx`](slwx.md) — 32-bit logical left shift.
- [`srdx`](srdx.md) — 64-bit logical right shift.
- [`sradx`](sradx.md), [`sradix`](sradix.md) — 64-bit arithmetic right shifts.
- [`rldicrx`](rldicrx.md) — `sldi` simplified mnemonic uses this.
- [`mulli`](mulli.md) — for non-power-of-two multipliers.
## IBM Reference
- [AIX 7.3 — `sld` (Shift Left Doubleword)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-sld-shift-left-double-word-instruction)

View File

@@ -0,0 +1,124 @@
# `slwx` — Shift Left Word
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000030`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `slw` | `slwx` | — | Shift Left Word |
| `slw.` | `slwx` | Rc=1 | Shift Left Word |
## Syntax
```asm
slw[Rc] [RA], [RS], [RB]
```
## Encoding
### `slwx` — form `X`
- **Opcode word:** `0x7c000030`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `24`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | slwx: read | Source GPR (alias for RD in some stores). |
| `RB` | slwx: read | Source GPR. |
| `RA` | slwx: write | Source GPR (`r0``r31`). |
| `CR` | slwx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `slwx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `slwx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
n <- (RB)[58:63]
RA <- ((RS) << n) & 0x0000_0000_FFFF_FFFF if n < 32 else 0
```
## 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
**`slwx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="slwx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1141`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1141)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:757`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L757)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:622-631`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L622-L631)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::slwx => {
// PPCBUG-044: 32-bit ABI CR0 view. A result with bit 31 set
// (e.g. 0x80000000) is negative in i32 view but positive in i64.
let sh = ctx.gpr[instr.rb()] as u32;
ctx.gpr[instr.ra()] = if sh < 32 {
((ctx.gpr[instr.rs()] as u32) << sh) as u64
} else { 0 };
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **32-bit logical left shift, zero-extended to 64.** `RA ← (RS[32:63] << (RB & 0x3F))[32:63]` if `(RB & 0x3F) < 32`, else `RA = 0`. The high 32 bits of `RA` are always zero (zero-extension of the 32-bit result).
- **Shift count is 6 bits**, `RB[58:63]` — not 7 like [`sldx`](sldx.md). Counts in `[32, 63]` produce zero. Xenia reads the full register but the explicit `if sh < 32` guard in [`interpreter.rs:417`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L417) prevents Rust UB.
- **Spec quirk worth flagging:** xenia reads `ctx.gpr[instr.rb()] as u32`, which uses the low 32 bits of `RB`, not the spec's `RB & 0x3F`. For ordinary code these agree (counts ≤ 63), but a maliciously high `RB` could in principle differ. In practice this is a non-issue.
- **No `XER[CA]` for left shifts.**
- **`Rc=1` CR0 update truncates to 32 bits** ([`interpreter.rs:420`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L420)). Since the high 32 bits are zero, this matches spec exactly.
- **No `OE` bit.**
## Related Instructions
- [`sldx`](sldx.md) — 64-bit logical left shift.
- [`srwx`](srwx.md), [`srawx`](srawx.md), [`srawix`](srawix.md) — 32-bit right shifts.
- [`rlwinmx`](rlwinmx.md) — `slwi` simplified mnemonic uses this.
## IBM Reference
- [AIX 7.3 — `slw` (Shift Left Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-slw-shift-left-word-instruction)

View File

@@ -0,0 +1,132 @@
# `sradix` — Shift Right Algebraic Doubleword Immediate
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XS](../forms/XS.md) · **Opcode:** `0x7c000674`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `sradi` | `sradix` | — | Shift Right Algebraic Doubleword Immediate |
| `sradi.` | `sradix` | Rc=1 | Shift Right Algebraic Doubleword Immediate |
## Syntax
```asm
sradi[Rc] [RA], [RS], [SH]
```
## Encoding
### `sradix` — form `XS`
- **Opcode word:** `0x7c000674`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `826`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RS` | source GPR |
| 1115 | `RA` | destination GPR |
| 1620 | `sh` | shift amount low 5 bits |
| 2129 | `XO` | extended opcode (9 bits) |
| 30 | `sh5` | shift amount high bit |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | sradix: read | Source GPR (alias for RD in some stores). |
| `SH` | sradix: read | Shift amount. |
| `RA` | sradix: write | Source GPR (`r0``r31`). |
| `CR` | sradix: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `CA` | sradix: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
## Register Effects
### `sradix`
- **Reads (always):** `RS`, `SH`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`, `CA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `sradix`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
RA <- ((RS) >>a SH) sign-extended
CA <- (RS signed < 0) && any_bit_shifted_out
```
## 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
**`sradix`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sradix"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1230`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1230)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:743`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L743)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:709-722`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L709-L722)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::sradix => {
let rs = ctx.gpr[instr.rs()] as i64;
let sh = instr.sh64();
if sh == 0 {
ctx.gpr[instr.ra()] = rs as u64;
ctx.xer_ca = 0;
} else {
let result = rs >> sh;
ctx.xer_ca = if rs < 0 && (rs as u64) << (64 - sh) != 0 { 1 } else { 0 };
ctx.gpr[instr.ra()] = result as u64;
}
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← (i64)RS >> SH`**, with `XER[CA]` set when `RS` is negative AND any one-bit was shifted out.
- **`SH` is 6 bits.** Encoded in bits 1620 (`sh`) plus bit 30 (`sh5`); xenia uses `instr.sh64()` to assemble the 6 bits ([`interpreter.rs:496`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L496)). Range `0..63`.
- **`SH = 0`** is a no-op (sign-extends `RS` to itself), and explicitly clears `XER[CA]` ([`interpreter.rs:498`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L498)). This matches spec.
- **Spec divergence: 6-bit immediate, no saturation arm.** Unlike [`sradx`](sradx.md) which has a 7-bit register count and saturates at `≥ 64`, `sradi` always uses a count `< 64` so no special saturation case is needed.
- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:506`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L506).
- **Idiom: `sradi rA, rS, n; addze rA, rA`** — signed integer divide by `2^n` rounded toward zero (the textbook PPC sequence).
- **No `OE` bit.**
## Related Instructions
- [`sradx`](sradx.md) — register-shift form.
- [`srawix`](srawix.md), [`srawx`](srawx.md) — 32-bit arithmetic right.
- [`addzex`](addzex.md) — pair for signed-divide-rounding.
- [`rldiclx`](rldiclx.md) — when arithmetic semantics not required (logical shift), `srdi` simplified mnemonic.
## IBM Reference
- [AIX 7.3 — `sradi` (Shift Right Algebraic Doubleword Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-sradi-shift-right-algebraic-double-word-immediate-instruction)

View File

@@ -0,0 +1,136 @@
# `sradx` — Shift Right Algebraic Doubleword
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000634`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `srad` | `sradx` | — | Shift Right Algebraic Doubleword |
| `srad.` | `sradx` | Rc=1 | Shift Right Algebraic Doubleword |
## Syntax
```asm
srad[Rc] [RA], [RS], [RB]
```
## Encoding
### `sradx` — form `X`
- **Opcode word:** `0x7c000634`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `794`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | sradx: read | Source GPR (alias for RD in some stores). |
| `RB` | sradx: read | Source GPR. |
| `RA` | sradx: write | Source GPR (`r0``r31`). |
| `CR` | sradx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `CA` | sradx: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
## Register Effects
### `sradx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`, `CA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `sradx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
n <- (RB)[57:63]
RA <- ((RS) >>a n) sign-extended if n < 64
CA <- (RS signed < 0) && any_bit_shifted_out
```
## 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
**`sradx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sradx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1201`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1201)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:841`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L841)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:692-708`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L692-L708)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::sradx => {
let rs = ctx.gpr[instr.rs()] as i64;
let sh = ctx.gpr[instr.rb()] & 0x7F;
if sh == 0 {
ctx.gpr[instr.ra()] = rs as u64;
ctx.xer_ca = 0;
} else if sh < 64 {
let result = rs >> sh;
ctx.xer_ca = if rs < 0 && (rs as u64) << (64 - sh) != 0 { 1 } else { 0 };
ctx.gpr[instr.ra()] = result as u64;
} else {
ctx.gpr[instr.ra()] = if rs < 0 { u64::MAX } else { 0 };
ctx.xer_ca = if rs < 0 { 1 } else { 0 };
}
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **64-bit arithmetic (sign-propagating) right shift.** `RA ← (i64)RS >> (RB & 0x7F)` with bits shifted in matching the sign bit of `RS`. Counts ≥ 64 saturate: `RA` becomes all-ones if `RS < 0`, else zero.
- **`XER[CA]` is the "lost-ones" indicator.** `CA = 1` iff `RS` is negative AND any of the bits shifted out were `1`. This makes `srad` / `sradi` the standard idiom for "divide negative integer by power of 2 with round-toward-zero" — followed by `addze` to compensate when `CA = 1`.
- **Three branches in xenia.** `sh == 0` (no shift, `CA=0`), `sh < 64` (normal shift, `CA` per spec), and `sh ≥ 64` (saturate to `0` or `1`, `CA` reflects sign). The `(rs as u64) << (64 - sh) != 0` check at [`interpreter.rs:486`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L486) extracts whether any non-zero bit was shifted out.
- **Shift count is 7 bits.** Same as [`sldx`](sldx.md): `RB[57:63]`.
- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:489`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L489).
- **No `OE` bit.**
- **Used by signed-divide-by-power-of-2 idiom:** `srad rA, rS, n; addze rA, rA` produces `rS / 2^n` with truncation toward zero rather than toward `-∞`.
## Related Instructions
- [`sradix`](sradix.md) — immediate-shift form (`SH` 6-bit immediate).
- [`srawx`](srawx.md), [`srawix`](srawix.md) — 32-bit arithmetic right shifts.
- [`srdx`](srdx.md) — 64-bit *logical* right shift (no `XER[CA]`).
- [`addzex`](addzex.md) — companion for the divide-rounding idiom.
- [`sldx`](sldx.md) — left shift.
## IBM Reference
- [AIX 7.3 — `srad` (Shift Right Algebraic Doubleword)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-srad-shift-right-algebraic-double-word-instruction)

View File

@@ -0,0 +1,132 @@
# `srawix` — Shift Right Algebraic Word Immediate
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000670`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `srawi` | `srawix` | — | Shift Right Algebraic Word Immediate |
| `srawi.` | `srawix` | Rc=1 | Shift Right Algebraic Word Immediate |
## Syntax
```asm
srawi[Rc] [RA], [RS], [SH]
```
## Encoding
### `srawix` — form `X`
- **Opcode word:** `0x7c000670`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `824`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | srawix: read | Source GPR (alias for RD in some stores). |
| `SH` | srawix: read | Shift amount. |
| `RA` | srawix: write | Source GPR (`r0``r31`). |
| `CR` | srawix: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `CA` | srawix: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
## Register Effects
### `srawix`
- **Reads (always):** `RS`, `SH`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`, `CA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `srawix`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
RA <- ((RS)[32:63] >>a SH) sign-extended
CA <- (RS[32] signed) && any_low_bit_shifted_out
```
## 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
**`srawix`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srawix"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1291`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1291)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:843`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L843)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:661-675`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L661-L675)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::srawix => {
// PPCBUG-042+043 coupled: same shape as srawx for the sh-immediate form.
let rs = ctx.gpr[instr.rs()] as i32;
let sh = instr.sh();
if sh == 0 {
ctx.gpr[instr.ra()] = rs as u32 as u64;
ctx.xer_ca = 0;
} else {
let result = rs >> sh;
ctx.xer_ca = if rs < 0 && (rs as u32) << (32 - sh) != 0 { 1 } else { 0 };
ctx.gpr[instr.ra()] = result as u32 as u64;
}
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← ((i32)RS >> SH) sign-extended`** with `XER[CA]` set when `RS` is negative AND any low bit was shifted out.
- **`SH` is 5 bits** (immediate, range `0..31`). Unlike [`srawx`](srawx.md), there is no saturation case because the count cannot exceed 31. Xenia reads it via `instr.sh()`.
- **`SH = 0`** sign-extends `RS[32:63]` to 64 bits and clears `CA`. This is *not* a no-op when `RS`'s high 32 bits differ from the sign extension of bit 32.
- **Common idiom: `srawi rA, rS, 31`** materialises the 32-bit sign of `rS` as `0` or `1` — the canonical "sign mask" pattern. Often used for branchless `abs` or conditional negation.
- **Idiom: `srawi rA, rS, n; addze rA, rA`** — divide signed by `2^n` rounding toward zero.
- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:457`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L457) — matches spec because the sign-extended result has consistent low/high 32-bit signs.
- **No `OE` bit.**
## Related Instructions
- [`srawx`](srawx.md) — register-shift form.
- [`sradix`](sradix.md), [`sradx`](sradx.md) — 64-bit arithmetic right.
- [`addzex`](addzex.md) — divide-rounding companion.
- [`extswx`](extswx.md) — `srawi rA, rS, 0` is functionally a sign-extend-32-to-64 plus `CA = 0` clear; `extsw` is preferred when CA isn't wanted.
## IBM Reference
- [AIX 7.3 — `srawi` (Shift Right Algebraic Word Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-srawi-shift-right-algebraic-word-immediate-instruction)

View File

@@ -0,0 +1,138 @@
# `srawx` — Shift Right Algebraic Word
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000630`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `sraw` | `srawx` | — | Shift Right Algebraic Word |
| `sraw.` | `srawx` | Rc=1 | Shift Right Algebraic Word |
## Syntax
```asm
sraw[Rc] [RA], [RS], [RB]
```
## Encoding
### `srawx` — form `X`
- **Opcode word:** `0x7c000630`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `792`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | srawx: read | Source GPR (alias for RD in some stores). |
| `RB` | srawx: read | Source GPR. |
| `RA` | srawx: write | Source GPR (`r0``r31`). |
| `CR` | srawx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `CA` | srawx: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
## Register Effects
### `srawx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`, `CA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `srawx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
n <- (RB)[58:63]
RA <- ((RS)[32:63] >>a n) sign-extended
CA <- 1 if (signed RS < 0) && any_bit_shifted_out else 0
```
## 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
**`srawx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srawx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1262`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1262)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:840`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L840)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:642-660`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L642-L660)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::srawx => {
// PPCBUG-041+043 coupled: 32-bit ABI writeback truncation + CR0 i32.
// CA logic is independently correct (uses u32 shifted-out test).
let rs = ctx.gpr[instr.rs()] as i32;
let sh = ctx.gpr[instr.rb()] as u32 & 0x3F;
if sh == 0 {
ctx.gpr[instr.ra()] = rs as u32 as u64;
ctx.xer_ca = 0;
} else if sh < 32 {
let result = rs >> sh;
ctx.xer_ca = if rs < 0 && (rs as u32) << (32 - sh) != 0 { 1 } else { 0 };
ctx.gpr[instr.ra()] = result as u32 as u64;
} else {
ctx.gpr[instr.ra()] = if rs < 0 { 0xFFFF_FFFFu64 } else { 0 };
ctx.xer_ca = if rs < 0 { 1 } else { 0 };
}
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **32-bit arithmetic right shift, sign-extended to 64.** `RA ← ((i32)RS >> n) sign-extended`, with `XER[CA]` set when `RS[32] = 1` (negative) AND any low bit was shifted out.
- **Shift count is 6 bits**, `RB[58:63]`. Counts `≥ 32` saturate: `RA = -1` (all-ones, sign-extended) if `RS < 0`, else `0`. Xenia handles this in three branches ([`interpreter.rs:432-444`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L432-L444)).
- **`SH = 0`** sign-extends `RS` to 64 bits and clears `XER[CA]` — like `extsw`, but additionally writing CA.
- **Result is always sign-extended to 64 bits.** `RA[0:31]` matches the sign of `RA[32]`. This is the key difference from [`srwx`](srwx.md) (zero-extension).
- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:443`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L443) — but since the result is sign-extended, the low 32 bits' sign matches the full 64-bit sign, so spec and xenia agree here.
- **Used with [`addzex`](addzex.md)** for signed divide by `2^n` rounding toward zero.
- **No `OE` bit.**
## Related Instructions
- [`srawix`](srawix.md) — immediate-shift form.
- [`sradx`](sradx.md), [`sradix`](sradix.md) — 64-bit arithmetic right shifts.
- [`srwx`](srwx.md) — 32-bit *logical* right shift (no `XER[CA]`).
- [`addzex`](addzex.md) — companion for divide-rounding idiom.
- [`slwx`](slwx.md) — left shift.
## IBM Reference
- [AIX 7.3 — `sraw` (Shift Right Algebraic Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-sraw-shift-right-algebraic-word-instruction)

View File

@@ -0,0 +1,123 @@
# `srdx` — Shift Right Doubleword
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000436`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `srd` | `srdx` | — | Shift Right Doubleword |
| `srd.` | `srdx` | Rc=1 | Shift Right Doubleword |
## Syntax
```asm
srd[Rc] [RA], [RS], [RB]
```
## Encoding
### `srdx` — form `X`
- **Opcode word:** `0x7c000436`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `539`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | srdx: read | Source GPR (alias for RD in some stores). |
| `RB` | srdx: read | Source GPR. |
| `RA` | srdx: write | Source GPR (`r0``r31`). |
| `CR` | srdx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `srdx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `srdx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
n <- (RB)[57:63]
RA <- ((RS) >> n) if n < 64 else 0
```
## 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
**`srdx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srdx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1161`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1161)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:821`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L821)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:684-691`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L684-L691)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::srdx => {
let sh = ctx.gpr[instr.rb()] & 0x7F;
ctx.gpr[instr.ra()] = if sh < 64 {
ctx.gpr[instr.rs()] >> sh
} else { 0 };
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **64-bit logical right shift.** `RA ← RS >> (RB & 0x7F)` if the count is `< 64`, else `RA = 0`. Bits shifted in from the high end are zero (no sign extension).
- **Shift count is 7 bits** (`RB[57:63]`). Counts `64..127` produce zero, not `RS >> (count mod 64)`. Xenia respects this with `& 0x7F` and an explicit `if sh < 64` check ([`interpreter.rs:472`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L472)).
- **No `XER[CA]` produced.** This is the logical right shift; for arithmetic shift with `XER[CA]` use [`sradx`](sradx.md).
- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:475`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L475). Result is non-negative as a signed value (high bit is always cleared by the shift), so CR0 will only ever be `EQ` or `GT`.
- **No `OE` bit.**
- **The `srdi` simplified mnemonic** uses [`rldiclx`](rldiclx.md) instead — `rldicl rA, rS, 64-n, n` — because it can be combined with masking. `srd` is for runtime-variable counts.
## Related Instructions
- [`srwx`](srwx.md) — 32-bit logical right shift.
- [`sradx`](sradx.md), [`sradix`](sradix.md) — 64-bit arithmetic right.
- [`sldx`](sldx.md) — 64-bit left shift.
- [`rldiclx`](rldiclx.md) — `srdi` immediate-shift expansion.
## IBM Reference
- [AIX 7.3 — `srd` (Shift Right Doubleword)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-srd-shift-right-double-word-instruction)

View File

@@ -0,0 +1,125 @@
# `srwx` — Shift Right Word
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000430`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `srw` | `srwx` | — | Shift Right Word |
| `srw.` | `srwx` | Rc=1 | Shift Right Word |
## Syntax
```asm
srw[Rc] [RA], [RS], [RB]
```
## Encoding
### `srwx` — form `X`
- **Opcode word:** `0x7c000430`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `536`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | srwx: read | Source GPR (alias for RD in some stores). |
| `RB` | srwx: read | Source GPR. |
| `RA` | srwx: write | Source GPR (`r0``r31`). |
| `CR` | srwx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `srwx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `srwx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
n <- (RB)[58:63]
RA <- ((RS)[32:63] >> n) zero-extended if n < 32 else 0
```
## 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
**`srwx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srwx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1180`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1180)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:820`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L820)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:632-641`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L632-L641)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::srwx => {
// PPCBUG-044: 32-bit ABI CR0 view (zero-extended right shift can never
// have bit 31 set, but use the canonical form for consistency).
let sh = ctx.gpr[instr.rb()] as u32;
ctx.gpr[instr.ra()] = if sh < 32 {
((ctx.gpr[instr.rs()] as u32) >> sh) as u64
} else { 0 };
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **32-bit logical right shift, zero-extended to 64.** `RA ← (u32)RS >> (RB & 0x3F)` if count `< 32`, else `RA = 0`. The high 32 bits of `RA` are always zero.
- **Shift count is 6 bits**, `RB[58:63]`. Counts `[32, 63]` produce zero (not `RS >> (count mod 32)`); xenia's explicit `if sh < 32` guards against Rust UB ([`interpreter.rs:425`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L425)).
- **No `XER[CA]` produced.** For arithmetic shift with `XER[CA]` use [`srawx`](srawx.md).
- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:428`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L428). Since the result has zeroed high 32 bits and zeroed sign bit (high bit of the 32-bit result is always 0 after a non-zero shift), CR0 will be `EQ` or `GT`.
- **No `OE` bit.**
- **`srwi` simplified mnemonic** uses [`rlwinmx`](rlwinmx.md), not this instruction. `srw` is for runtime-variable counts.
## Related Instructions
- [`srdx`](srdx.md) — 64-bit logical right shift.
- [`srawx`](srawx.md), [`srawix`](srawix.md) — 32-bit arithmetic right.
- [`slwx`](slwx.md) — 32-bit left shift.
- [`rlwinmx`](rlwinmx.md) — `srwi` immediate expansion.
## IBM Reference
- [AIX 7.3 — `srw` (Shift Right Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-srw-shift-right-word-instruction)

View File

@@ -0,0 +1,138 @@
# `subfcx` — Subtract From Carrying
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000010`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `subfc` | `subfcx` | — | Subtract From Carrying |
| `subfco` | `subfcx` | OE=1 | Subtract From Carrying |
| `subfc.` | `subfcx` | Rc=1 | Subtract From Carrying |
| `subfco.` | `subfcx` | OE=1, Rc=1 | Subtract From Carrying |
## Syntax
```asm
subfc[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `subfcx` — form `XO`
- **Opcode word:** `0x7c000010`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `8`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | subfcx: read | Source GPR (`r0``r31`). |
| `RB` | subfcx: read | Source GPR. |
| `RD` | subfcx: write | Destination GPR. |
| `CR` | subfcx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `OE` | subfcx: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
## Register Effects
### `subfcx`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `CR`, `OE`
## Status-Register Effects
- `subfcx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- ~(RA) + (RB) + 1
CA <- carry_out
```
## 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
**`subfcx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfcx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:441`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L441)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:859`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L859)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:270-287`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L270-L287)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::subfcx => {
// PPCBUG-007: 32-bit ABI. The `rb >= ra` u64 unsigned compare is
// exactly the shape that broke addis. Defensive 32-bit truncation
// is required for correct CA even after upstream cleanup.
let ra32 = ctx.gpr[instr.ra()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
let result32 = rb32.wrapping_sub(ra32);
ctx.xer_ca = if rb32 >= ra32 { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
let true_diff = (rb32 as i32 as i128) - (ra32 as i32 as i128);
overflow::apply(ctx, true_diff != (result32 as i32) as i128);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RT ← RB RA` with `XER[CA]` set on no-borrow.** Same operand-order convention as [`subfx`](subfx.md): the *first* source is subtracted *from* the second.
- **`XER[CA] = 1` means *no borrow occurred*** — i.e. `RB >= RA` as unsigned. PowerISA encodes this as the carry-out of `~RA + RB + 1`, not as a borrow flag. Xenia's `if rb >= ra` test ([`interpreter.rs:157`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L157)) is the correct boolean encoding.
- **No trap on signed overflow.** `subfco` / `subfco.` set `XER[OV]` and sticky `XER[SO]`; xenia-rs leaves the `OE` arm unimplemented.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:160`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L160) truncates with `as i32 as i64`. Spec demands a full 64-bit signed compare for `subfc.`.
- **Seeds a multi-word subtract chain.** Use as the low-word op; continue with [`subfex`](subfex.md) for middle words and [`subfmex`](subfmex.md)/[`subfzex`](subfzex.md) for the high word.
- **Operand aliasing fine.** `subfc r3, r3, r3` always yields `0` with `CA = 1`.
## Related Instructions
- [`subfx`](subfx.md) — same op without `XER[CA]`.
- [`subfex`](subfex.md) — `~RA + RB + CA` (chain continuation).
- [`subfmex`](subfmex.md), [`subfzex`](subfzex.md) — chain terminators.
- [`subfic`](subficx.md) — D-form: `RT ← SIMM RA` with `XER[CA]`.
- [`addcx`](addcx.md) — dual: addition seed-of-chain.
## IBM Reference
- [AIX 7.3 — `subfc` (Subtract From Carrying)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-subfc-subtract-from-carrying-instruction)

View File

@@ -0,0 +1,138 @@
# `subfex` — Subtract From Extended
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000110`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `subfe` | `subfex` | — | Subtract From Extended |
| `subfeo` | `subfex` | OE=1 | Subtract From Extended |
| `subfe.` | `subfex` | Rc=1 | Subtract From Extended |
| `subfeo.` | `subfex` | OE=1, Rc=1 | Subtract From Extended |
## Syntax
```asm
subfe[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `subfex` — form `XO`
- **Opcode word:** `0x7c000110`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `136`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | subfex: read | Source GPR (`r0``r31`). |
| `RB` | subfex: read | Source GPR. |
| `RD` | subfex: write | Destination GPR. |
| `CR` | subfex: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `OE` | subfex: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
## Register Effects
### `subfex`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `CR`, `OE`
## Status-Register Effects
- `subfex`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- ~(RA) + (RB) + CA
CA <- carry_out
```
## 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
**`subfex`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfex"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:468`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L468)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:867`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L867)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:288-306`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L288-L306)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::subfex => {
// PPCBUG-008: 32-bit ABI. Compute in u32 space — `!ra` on u64 always
// pollutes the upper 32 bits, making this an active poisoner.
let ra32 = ctx.gpr[instr.ra()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
let ca = ctx.xer_ca as u32;
let result32 = (!ra32).wrapping_add(rb32).wrapping_add(ca);
ctx.xer_ca = if rb32 > ra32 || (rb32 == ra32 && ca != 0) { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
// RT <- !RA + RB + CA == RB - RA - 1 + CA (32-bit semantics).
let true_sum = (rb32 as i32 as i128) - (ra32 as i32 as i128) - 1 + (ca as i128);
overflow::apply(ctx, true_sum != (result32 as i32) as i128);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RT ← ~RA + RB + XER[CA]`.** The middle link of a multi-word subtract chain seeded by [`subfcx`](subfcx.md). `XER[CA]` propagates the borrow from the previous word.
- **Carry-out predicate handles the boundary case.** Xenia computes `CA' = (rb > ra) || (rb == ra && CA != 0)` ([`interpreter.rs:170`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L170)). The second clause covers when `RB == RA` and the previous chain added a `+1` from the input carry — without it, the carry-out would be wrong.
- **`OE=1`** should set `XER[OV]` on signed overflow; xenia-rs ignores it.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:173`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L173).
- **`XER[CA]` must be initialised** (typically by [`subfcx`](subfcx.md)). Reading stale `CA` is a frequent multi-word-subtract bug.
- **Symmetry with [`addex`](addex.md).** `subfe RT, RA, RB``adde RT, ~RA, RB` (with the implicit complement).
## Related Instructions
- [`subfcx`](subfcx.md) — seeds the chain (no `CA` read).
- [`subfmex`](subfmex.md), [`subfzex`](subfzex.md) — terminate the chain (`~RA + 1 + CA`, `~RA + 0 + CA`).
- [`subfx`](subfx.md) — plain subtract.
- [`addex`](addex.md) — dual.
## IBM Reference
- [AIX 7.3 — `subfe` (Subtract From Extended)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-subfe-subtract-from-extended-instruction)

View File

@@ -0,0 +1,131 @@
# `subficx` — Subtract From Immediate Carrying
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x20000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `subfic` | `subficx` | — | Subtract From Immediate Carrying |
## Syntax
```asm
subfic [RD], [RA], [SIMM]
```
## Encoding
### `subficx` — form `D`
- **Opcode word:** `0x20000000`
- **Primary opcode (bits 05):** `8`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | subficx: read | Source GPR (`r0``r31`). |
| `SIMM` | subficx: read | 16-bit signed immediate. Sign-extended to 64 bits before use. |
| `RD` | subficx: write | Destination GPR. |
| `CA` | subficx: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
## Register Effects
### `subficx`
- **Reads (always):** `RA`, `SIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`, `CA`
- **Writes (conditional):** _none_
## Status-Register Effects
- `subficx`: **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`subficx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subficx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:459`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L459)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:333`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L333)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:155-164`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L155-L164)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::subficx => {
// PPCBUG-005: 32-bit ABI. Sign-extended imm has bits 32-63 set for
// negative SIMM, poisoning the writeback. Canary uses 32-bit form.
let ra32 = ctx.gpr[instr.ra()] as u32;
let imm32 = instr.simm16() as i32 as u32;
let result32 = imm32.wrapping_sub(ra32);
ctx.xer_ca = if imm32 >= ra32 { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RT ← SIMM RA` with `XER[CA]` always set.** Note the operand order: the *immediate* is the minuend, not the subtrahend. `subfic rD, rA, 1` computes `1 - rA`, useful for negation-plus-one or one's-complement-style operations.
- **Immediate is sign-extended** to 64 bits before the subtract. So `subfic rD, rA, -1` computes `-1 - rA`, equivalent to `~rA`.
- **`XER[CA] = 1` when `SIMM >= RA`** (no borrow). Computed in xenia as `if imm >= ra` ([`interpreter.rs:73`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L73)) — comparing the sign-extended unsigned representations.
- **No `Rc`, no `OE`.** This D-form has no flag bits beyond the implicit `CA` write.
- **No record-form variant.** There is no `subfic.` in the ISA; if you need CR0 to also reflect the result, follow with a `cmpwi`.
- **Synthesised "subtract immediate"**. Assemblers sometimes accept `subi rD, rA, value` as a shorthand for `addi rD, rA, -value`, but for the carry-producing variant you must use `subfic` explicitly.
- **Common idiom: `subfic rD, rA, 0`** computes `-rA` and sets `CA` according to whether `rA == 0` (no borrow) or `rA != 0` (borrow). Equivalent to [`negx`](negx.md) when `CA` doesn't matter.
## Related Instructions
- [`subfcx`](subfcx.md) — XO-form register version.
- [`subfx`](subfx.md) — register subtract without `XER[CA]`.
- [`addic`](addic.md), [`addicx`](addicx.md) — dual: add immediate carrying.
- [`negx`](negx.md) — equivalent to `subfic rD, rA, 0` when `CA` is unwanted.
## IBM Reference
- [AIX 7.3 — `subfic` (Subtract From Immediate Carrying)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-subfic-subtract-from-immediate-carrying-instruction)

View File

@@ -0,0 +1,145 @@
# `subfmex` — Subtract From Minus One Extended
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c0001d0`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `subfme` | `subfmex` | — | Subtract From Minus One Extended |
| `subfmeo` | `subfmex` | OE=1 | Subtract From Minus One Extended |
| `subfme.` | `subfmex` | Rc=1 | Subtract From Minus One Extended |
| `subfmeo.` | `subfmex` | OE=1, Rc=1 | Subtract From Minus One Extended |
## Syntax
```asm
subfme[OE][Rc] [RD], [RA]
```
## Encoding
### `subfmex` — form `XO`
- **Opcode word:** `0x7c0001d0`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `232`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | subfmex: read | Source GPR (`r0``r31`). |
| `CA` | subfmex: read; subfmex: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
| `RD` | subfmex: write | Destination GPR. |
| `CR` | subfmex: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `OE` | subfmex: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
## Register Effects
### `subfmex`
- **Reads (always):** `RA`, `CA`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`, `CA`
- **Writes (conditional):** `CR`, `OE`
## Status-Register Effects
- `subfmex`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.; **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`subfmex`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfmex"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:486`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L486)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:871`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L871)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:325-341`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L325-L341)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::subfmex => {
// PPCBUG-019: also fixes the always-true CA edge — `!ra` on u64
// is non-zero when ra32==0xFFFFFFFF and ca==0, so CA was stuck at 1.
let ra32 = ctx.gpr[instr.ra()] as u32;
let ca = ctx.xer_ca as u32;
let result32 = (!ra32).wrapping_add(ca).wrapping_sub(1);
ctx.xer_ca = if (!ra32) != 0 || ca != 0 { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
let true_sum = -(ra32 as i32 as i128) - 2 + (ca as i128);
overflow::apply(ctx, true_sum != (result32 as i32) as i128);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RT ← ~RA + (1) + XER[CA]``~RA 1 + CA`.** Terminator for a multi-word subtract chain when the high "minuend" word is implicitly all-ones (e.g. when computing `~x` style negation across many words).
- **`RB` field unused.** XO-form but only `RA` is read.
- **Carry-out predicate.** `CA' = (~RA != 0) || (CA != 0)` ([`interpreter.rs:191`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L191)). Only when `RA == ~0` (all ones) AND `CA == 0` does `CA'` become 0 — every other case produces no borrow on this final word.
- **`OE=1`** should set `XER[OV]` on signed overflow; xenia-rs ignores it.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:194`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L194).
- **`XER[CA]` must be initialised** (typically by a [`subfcx`](subfcx.md) or [`subfex`](subfex.md) earlier in the chain).
- **Symmetric with [`addmex`](addmex.md)**, the add-side terminator.
## Related Instructions
- [`subfzex`](subfzex.md) — terminate with `~RA + 0 + CA` instead.
- [`subfex`](subfex.md) — middle-of-chain.
- [`subfcx`](subfcx.md) — chain seed.
- [`addmex`](addmex.md) — dual.
## IBM Reference
- [AIX 7.3 — `subfme` (Subtract From Minus One Extended)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-subfme-subtract-from-minus-one-extended-instruction)

View File

@@ -0,0 +1,148 @@
# `subfx` — Subtract From
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000050`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `subf` | `subfx` | — | Subtract From |
| `subfo` | `subfx` | OE=1 | Subtract From |
| `subf.` | `subfx` | Rc=1 | Subtract From |
| `subfo.` | `subfx` | OE=1, Rc=1 | Subtract From |
## Syntax
```asm
subf[OE][Rc] [RD], [RA], [RB]
```
## Encoding
### `subfx` — form `XO`
- **Opcode word:** `0x7c000050`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `40`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | subfx: read | Source GPR (`r0``r31`). |
| `RB` | subfx: read | Source GPR. |
| `RD` | subfx: write | Destination GPR. |
| `CR` | subfx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `OE` | subfx: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
## Register Effects
### `subfx`
- **Reads (always):** `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** `CR`, `OE`
## Status-Register Effects
- `subfx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.
## Operation (pseudocode)
```
RT <- ~(RA) + (RB) + 1 ; = (RB) (RA)
```
## 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
**`subfx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:427`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L427)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:863`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L863)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:255-269`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L255-L269)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::subfx => {
// PPCBUG-017+020: 32-bit truncation.
let ra32 = ctx.gpr[instr.ra()] as u32;
let rb32 = ctx.gpr[instr.rb()] as u32;
let result32 = rb32.wrapping_sub(ra32);
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
let true_diff = (rb32 as i32 as i128) - (ra32 as i32 as i128);
overflow::apply(ctx, true_diff != (result32 as i32) as i128);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Extended Pseudocode
```
RT <- ~(RA) + (RB) + 1 ; = (RB) (RA)
if OE then
XER[OV] <- signed_overflow_of_subtract((RB), (RA), RT)
XER[SO] <- XER[SO] | XER[OV]
if Rc then
CR0[LT,GT,EQ] <- signed_compare(RT, 0)
CR0[SO] <- XER[SO]
```
## Special Cases & Edge Conditions
- **Operand order gotcha.** `subf RT, RA, RB` computes `RT ← RB RA`, **not** `RA RB`. This reverses the intuitive ordering seen in x86/ARM. The assembler exposes a simplified mnemonic `sub RT, RX, RY``subf RT, RY, RX` that restores the natural order — watch for both forms in disassembly.
- **Implemented as add-with-complement.** Hardware (and xenia) compute `~RA + RB + 1`. All overflow/CR semantics are the same as [`addx`](addx.md) with one operand complemented.
- **No `XER[CA]` update** — use [`subfcx`](subfcx.md) if you need a borrow-out bit.
- **No trap on overflow.** `subfo` / `subfo.` only record the event in `XER[OV]` and sticky-set `XER[SO]`.
- **Signed-overflow predicate.** `OV = ((RA ^ RB) & (RB ^ RT)) >> 63` — set when operands have different signs and the result's sign differs from `RB`'s.
- **64-bit CR update on Xenon** (xenia-rs truncates to 32 bits; see [`addx`](addx.md) note).
## Related Instructions
- [`subfcx`](subfcx.md) — subtract-from producing `XER[CA]` (borrow-out).
- [`subfex`](subfex.md) — `~RA + RB + XER[CA]` (subtract-with-borrow chain).
- [`subfmex`](subfmex.md), [`subfzex`](subfzex.md) — subtract-from `1` / `0` with carry-in (propagates borrows).
- [`subfic`](subfic.md) — D-form: `RT ← SIMM RA` with `XER[CA]`.
- [`negx`](negx.md) — specialises to `0 RA`.
- [`addx`](addx.md) — inverse; shares overflow machinery.
## IBM Reference
- [AIX 7.3 — `subf` (Subtract From)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-subf-subtract-from-instruction)
- [AIX 7.3 — `sub` (simplified mnemonic)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-sub-subtract)

View File

@@ -0,0 +1,146 @@
# `subfzex` — Subtract From Zero Extended
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [XO](../forms/XO.md) · **Opcode:** `0x7c000190`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `subfze` | `subfzex` | — | Subtract From Zero Extended |
| `subfzeo` | `subfzex` | OE=1 | Subtract From Zero Extended |
| `subfze.` | `subfzex` | Rc=1 | Subtract From Zero Extended |
| `subfzeo.` | `subfzex` | OE=1, Rc=1 | Subtract From Zero Extended |
## Syntax
```asm
subfze[OE][Rc] [RD], [RA]
```
## Encoding
### `subfzex` — form `XO`
- **Opcode word:** `0x7c000190`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `200`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination GPR |
| 1115 | `RA` | source A |
| 1620 | `RB` | source B |
| 21 | `OE` | overflow-enable flag |
| 2230 | `XO` | extended opcode (9 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RA` | subfzex: read | Source GPR (`r0``r31`). |
| `CA` | subfzex: read; subfzex: write | XER[CA] carry bit. Read by add-with-carry/subtract-with-borrow instructions, written by carrying instructions. |
| `RD` | subfzex: write | Destination GPR. |
| `CR` | subfzex: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `OE` | subfzex: write (conditional) | Overflow-enable bit. When 1, the instruction updates `XER[OV]` and stickies `XER[SO]` on signed overflow. |
## Register Effects
### `subfzex`
- **Reads (always):** `RA`, `CA`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`, `CA`
- **Writes (conditional):** `CR`, `OE`
## Status-Register Effects
- `subfzex`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.; **XER[OV]** ← signed-overflow(result); **XER[SO]** stickies, when `OE=1`.; **XER[CA]** ← carry-out of the add / borrow-in of the subtract (always).
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`subfzex`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfzex"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:504`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L504)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:869`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L869)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:307-324`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L307-L324)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::subfzex => {
// PPCBUG-018: same active-poisoning shape as subfex; operate in u32.
let ra32 = ctx.gpr[instr.ra()] as u32;
let ca = ctx.xer_ca as u32;
let result32 = (!ra32).wrapping_add(ca);
// RT <- !RA + CA (no -1 term). 32-bit carry-out only when
// !ra32 = u32::MAX (i.e. ra32 = 0) AND ca = 1.
ctx.xer_ca = if ra32 == 0 && ca != 0 { 1 } else { 0 };
ctx.gpr[instr.rd()] = result32 as u64;
if instr.oe() {
let true_sum = -(ra32 as i32 as i128) - 1 + (ca as i128);
overflow::apply(ctx, true_sum != (result32 as i32) as i128);
}
if instr.rc_bit() {
ctx.update_cr_signed(0, result32 as i32 as i64);
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RT ← ~RA + 0 + XER[CA]``~RA + CA`.** The subtract-side high-word terminator for a multi-word subtract chain. Implements `0 - (...) - borrow` for the high word.
- **`RB` field unused.**
- **Carry-out predicate.** `CA' = (~RA != 0) || (CA != 0)` ([`interpreter.rs:180`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L180)). Only `RA == ~0 && CA == 0` produces `CA' = 0`; every other case gives no-borrow.
- **`OE=1`** should set `XER[OV]` on signed overflow; xenia-rs ignores.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:183`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L183).
- **`XER[CA]` must be initialised** by an earlier carrying instruction.
- **Common idiom: extracting `XER[CA]` as 0/-1.** `subfze rT, rN` (where `rN == 0`) materialises `XER[CA]` to `0` or `-1` (`-1 = ~0 + CA = -1 + CA`); pair with [`addzex`](addzex.md) for `0/1` instead.
## Related Instructions
- [`subfmex`](subfmex.md) — terminator with `~RA + (1) + CA`.
- [`subfex`](subfex.md), [`subfcx`](subfcx.md) — chain middle / seed.
- [`addzex`](addzex.md) — dual; produces 0/1 from `CA`.
- [`negx`](negx.md) — `subfze` with `RA = 0` and `CA = 1` is functionally similar.
## IBM Reference
- [AIX 7.3 — `subfze` (Subtract From Zero Extended)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-subfze-subtract-from-zero-extended-instruction)

View File

@@ -0,0 +1,113 @@
# `sync` — Synchronize
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c0004ac`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `sync` | `sync` | — | Synchronize |
## Syntax
```asm
sync
```
## Encoding
### `sync` — form `X`
- **Opcode word:** `0x7c0004ac`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `598`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
## Register Effects
### `sync`
- **Reads (always):** _none_
- **Reads (conditional):** _none_
- **Writes (always):** _none_
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
multi-thread memory barrier (heavy). L=0 full sync; L=1 lightweight sync.
```
## 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
**`sync`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sync"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:754`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L754)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:85`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L85)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:825`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L825)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1691-1693`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1691-L1693)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::sync | PpcOpcode::eieio | PpcOpcode::isync => {
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Heavy multi-thread memory barrier.** All memory accesses (loads and stores, cacheable and not) issued by this thread before `sync` complete with respect to all other threads/processors before any subsequent memory access begins. Drains the store queue.
- **`L` field selects sync class.** `L=0` is full *hwsync* (the default). `L=1` is `lwsync` — orders only loads-after-loads, loads-after-stores, and stores-after-stores (not stores-after-loads). The Xenon implements both via the same encoding with `L` (bit 9) selecting variant. Most disassembly shows the unsuffixed `sync` mnemonic, which assembles to `L=0`.
- **No register or CR effects.** Pure ordering primitive.
- **Used to implement release semantics.** A typical lock-release sequence is `sync; stw r0, lock`. Acquire side uses `lwsync` after the load.
- **Xenia-rs is a no-op.** [`interpreter.rs:1267`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1267) collapses `sync`, `eieio`, `isync` into PC-advance. Since xenia is single-threaded interpretation, host program order subsumes all PPC ordering.
- **Distinct from [`isync`](isync.md)**, which orders the *instruction* stream — `sync` does not refetch instructions.
- **Slow on real hardware.** Hundreds of cycles when the store queue is full; hot paths avoid `sync` and use `lwsync` or no barrier when only single-thread ordering is needed.
## Related Instructions
- [`isync`](isync.md) — instruction-fetch barrier.
- [`eieio`](eieio.md) — lighter I/O barrier for caching-inhibited storage.
- `lwsync` — same encoding, `L=1`; not separately enumerated in this page set.
## IBM Reference
- [AIX 7.3 — `sync` (Synchronize)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-sync-synchronize-instruction)
- PowerISA v2.07B, Book II, §1.7 — defines `hwsync`/`lwsync`/`ptesync` semantics.

View File

@@ -0,0 +1,115 @@
# `xori` — XOR Immediate
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x68000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `xori` | `xori` | — | XOR Immediate |
## Syntax
```asm
xori [RA], [RS], [UIMM]
```
## Encoding
### `xori` — form `D`
- **Opcode word:** `0x68000000`
- **Primary opcode (bits 05):** `26`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | xori: read | Source GPR (alias for RD in some stores). |
| `UIMM` | xori: read | 16-bit unsigned immediate. Zero-extended. |
| `RA` | xori: write | Source GPR (`r0``r31`). |
## Register Effects
### `xori`
- **Reads (always):** `RS`, `UIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
RA <- (RS) ^ (0x0000 || UIMM)
```
## 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
**`xori`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="xori"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:839`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L839)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:132`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L132)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:349`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L349)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:520-523`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L520-L523)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::xori => {
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] ^ (instr.uimm16() as u64);
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **No record form.** Like [`ori`](ori.md), there is no `xori.`. To get a CR0 update follow with `cmpwi` or use [`xorx`](xorx.md) with `Rc=1`.
- **Immediate is zero-extended** to 64 bits. Only the low 16 bits of `RA` can be flipped; the high 48 bits are passed through from `RS` unchanged.
- **`xori 0, 0, 0` is a valid NOP encoding** but the canonical NOP is `ori 0, 0, 0`. Disassemblers should still display this as `xori r0, r0, 0` or recognise it as a no-op.
- **64-bit operation in xenia-rs.** [`interpreter.rs:338`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L338) — full `u64` XOR with the immediate.
- **No `XER`, no `CR`** side effects.
- **`RA = 0` reads `r0`** (not literal zero); see [`ori`](ori.md).
- **Useful for masked toggle.** `xori rA, rS, mask` flips the bits of `rS` indicated by `mask` (low 16 bits only).
## Related Instructions
- [`xoris`](xoris.md) — companion (immediate shifted left 16).
- [`xorx`](xorx.md) — register-register XOR.
- [`eqvx`](eqvx.md) — `~(RS ^ RB)`.
- [`ori`](ori.md), [`andix`](andix.md) — sister immediate logicals.
## IBM Reference
- [AIX 7.3 — `xori` (XOR Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-xori-immediate-instruction)

View File

@@ -0,0 +1,114 @@
# `xoris` — XOR Immediate Shifted
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x6c000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `xoris` | `xoris` | — | XOR Immediate Shifted |
## Syntax
```asm
xoris [RA], [RS], [UIMM]
```
## Encoding
### `xoris` — form `D`
- **Opcode word:** `0x6c000000`
- **Primary opcode (bits 05):** `27`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | xoris: read | Source GPR (alias for RD in some stores). |
| `UIMM` | xoris: read | 16-bit unsigned immediate. Zero-extended. |
| `RA` | xoris: write | Source GPR (`r0``r31`). |
## Register Effects
### `xoris`
- **Reads (always):** `RS`, `UIMM`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
RA <- (RS) ^ (UIMM || 0x0000)
```
## 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
**`xoris`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="xoris"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:846`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L846)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:132`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L132)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:350`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L350)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:524-527`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L524-L527)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::xoris => {
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] ^ ((instr.uimm16() as u64) << 16);
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **No record form.** Like all immediate logicals other than `andi.`/`andis.`, `xoris` does not update CR0.
- **Immediate is zero-extended *then* shifted left 16.** Only bits 3247 of `RA` (PowerISA bit numbering) can be flipped; the high 32 bits and low 16 bits of `RA` come from `RS` unchanged.
- **Common pattern with [`xori`](xori.md)** to flip arbitrary 32-bit bitmasks: `xoris RA, RS, hi16; xori RA, RA, lo16`.
- **64-bit operation.** [`interpreter.rs:342`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L342).
- **No `XER`, no `CR`.**
- **`RA = 0` reads `r0`** (not literal zero).
- **Used to toggle the high half of a 32-bit word**, e.g. `xoris r3, r3, 0x8000` flips bit 32 (the sign bit of the low word) — a one-instruction sign-flip on a 32-bit value.
## Related Instructions
- [`xori`](xori.md) — companion (immediate not shifted).
- [`xorx`](xorx.md) — register-register XOR.
- [`oris`](oris.md), [`andisx`](andisx.md) — sister immediate-shifted logicals.
## IBM Reference
- [AIX 7.3 — `xoris` (XOR Immediate Shifted)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-xoris-immediate-shifted-instruction)

View File

@@ -0,0 +1,121 @@
# `xorx` — XOR
> **Category:** [Integer ALU](../categories/alu.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000278`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `xor` | `xorx` | — | XOR |
| `xor.` | `xorx` | Rc=1 | XOR |
## Syntax
```asm
xor[Rc] [RA], [RS], [RB]
```
## Encoding
### `xorx` — form `X`
- **Opcode word:** `0x7c000278`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `316`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `RS` | xorx: read | Source GPR (alias for RD in some stores). |
| `RB` | xorx: read | Source GPR. |
| `RA` | xorx: write | Source GPR (`r0``r31`). |
| `CR` | xorx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
## Register Effects
### `xorx`
- **Reads (always):** `RS`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** `RA`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `xorx`: **CR0** ← signed-compare(result, 0) with `SO ← XER[SO]`, when `Rc=1`.
## Operation (pseudocode)
```
RA <- (RS) ^ (RB)
```
## 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
**`xorx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="xorx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:829`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L829)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:132`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L132)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:798`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L798)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:556-561`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L556-L561)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::xorx => {
// PPCBUG-032+020: 32-bit ABI CR0 view.
ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] ^ ctx.gpr[instr.rb()];
if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`RA ← RS XOR RB`.** Bit-wise XOR.
- **Idiom: `xor RA, RS, RS`** zeroes `RA` — the canonical "clear register" instruction. Cheaper than `li RA, 0` because no immediate-extraction stage is involved.
- **Operand convention** is X-form (`RA` destination, `RS`/`RB` sources).
- **64-bit operation** on Xenon.
- **No `OE` or `XER` side effects.** Only `Rc=1` updates `CR0`.
- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:367`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L367) truncates with `as i32 as i64`. For `xor.` whose result has differing high/low halves, spec and xenia diverge; `xor. RA, RS, RS` gives `EQ` either way.
- **Useful as bitmask toggle.** `xor r3, r3, r4` flips in `r3` every bit set in `r4`.
- **No `XER[CA]`.**
## Related Instructions
- [`xori`](xori.md), [`xoris`](xoris.md) — D-form immediate variants.
- [`eqvx`](eqvx.md) — NXOR (`~(RS ^ RB)`).
- [`andx`](andx.md), [`orx`](orx.md), [`norx`](norx.md), [`nandx`](nandx.md) — sister logicals.
## IBM Reference
- [AIX 7.3 — `xor` (XOR)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-xor-instruction)

View File

@@ -0,0 +1,164 @@
# `bcctrx` — Branch Conditional to Count Register
> **Category:** [Branch & System](../categories/branch.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000420` · _sync_
<!-- GENERATED: BEGIN -->
## 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 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
/* 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)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```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;
}
}
```
</details>
<!-- GENERATED: END -->
## 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)

View File

@@ -0,0 +1,180 @@
# `bclrx` — Branch Conditional to Link Register
> **Category:** [Branch & System](../categories/branch.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000020` · _sync_
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `bclr` | `bclrx` | — | Branch Conditional to Link Register |
| `bclrl` | `bclrx` | LK=1 | Branch Conditional to Link Register |
## Syntax
```asm
bclr[LK] [BO], [BI]
```
## Encoding
### `bclrx` — form `XL`
- **Opcode word:** `0x4c000020`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `16`
- **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` | bclrx: read | Link bit. When 1, LR ← address-of-next-instruction before the branch is taken. |
| `BO` | bclrx: read | 5-bit branch options — selects CTR decrement, CTR test polarity, and CR bit test polarity. See `forms/XL.md`. |
| `BI` | bclrx: read | CR bit index (031) selected by BO's condition test. |
| `CR` | bclrx: 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` | bclrx: read (conditional); bclrx: write (conditional) | Count register. Decremented and optionally tested by conditional branches when `BO[2]=0`. |
| `LR` | bclrx: write (conditional) | Link register. Written by `bl`/`bla`/`bcl`/`bclrl`/`bcctrl`; read by `bclr`/`bclrl`. |
## Register Effects
### `bclrx`
- **Reads (always):** `LK`, `BO`, `BI`
- **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 <- LR[0:61] || 0b00
if LK then LR <- CIA + 4
```
## C Translation Example
```c
/* bclr/bclrl — branch conditional to LR */
if (!(insn.BO & 4)) ctr -= 1;
bool ctr_ok = (insn.BO & 4) || ((ctr != 0) ^ !!(insn.BO & 2));
bool cond_ok = (insn.BO & 16) || (cr_bit(insn.BI) == !!(insn.BO & 8));
uint32_t next = pc + 4;
if (ctr_ok && cond_ok) pc = lr & ~3u; else pc = next;
if (insn.LK) lr = next;
```
## Implementation References
**`bclrx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bclrx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:282`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L282)
- 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:711`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L711)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:939-961`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L939-L961)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::bclrx => {
let bo = instr.bo();
let bi = instr.bi();
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));
let next_pc = ctx.pc + 4;
if ctr_ok && cond_ok {
ctx.pc = (ctx.lr as u32) & !3;
} else {
ctx.pc = next_pc;
}
if instr.lk() {
ctx.lr = next_pc as u64;
}
}
```
</details>
<!-- GENERATED: END -->
## BO Encoding (5 bits)
`BO` controls two independent tests and two "hints". Bit 0 is the MSB.
| BO (binary) | CTR decrement? | CTR test | CR test | Meaning |
| --- | --- | --- | --- | --- |
| `0000z` | yes | `CTR ≠ 0` | `¬CR[BI]` | decrement, branch if CTR ≠ 0 **and** CR[BI] false |
| `0001z` | yes | `CTR = 0` | `¬CR[BI]` | decrement, branch if CTR = 0 **and** CR[BI] false |
| `001at` | yes | `CTR ≠ 0` / `CTR = 0` | — | decrement, branch on CTR only |
| `0100z` | no | — | `¬CR[BI]` | branch if CR[BI] false |
| `0101z` | no | — | `CR[BI]` | branch if CR[BI] true |
| `011at` | no | — | — | branch always (`z` and `t` are prediction hints) |
| `1z00z` | yes | `CTR ≠ 0` | — | decrement, branch if CTR ≠ 0 |
| `1z01z` | yes | `CTR = 0` | — | decrement, branch if CTR = 0 |
| `1z1zz` | no | — | — | branch always |
Bit **`BO[0]` = 1** disables the CR test; **`BO[2]` = 1** disables the CTR decrement/test. `BO[1]` and `BO[3]` select the polarity of each test. `BO[4]` is a branch-prediction hint (0 = not taken, 1 = taken; ignored on the Xenon in most cases).
The most common bclr instance in Xbox 360 disassembly is `BO = 0b10100``blr` (branch always to LR), the function epilogue. `BO = 0b01100, BI = 2``beqlr` (return if `cr0.EQ`), also common.
## Special Cases & Edge Conditions
- **LR alignment mask.** The target address is `LR & ~3` — the low 2 bits are cleared. This silently ignores a misaligned LR; incoming code should always produce 4-byte-aligned LR values.
- **Ordering of CTR decrement and branch.** The CTR is decremented **first**, then compared to zero **after** the decrement. So after `bdnz` at `CTR = 1`, the CTR becomes `0` and the branch is not taken.
- **Self-referential LR write.** `bclrl` writes `LR ← CIA + 4` **before** reading `LR` to set `NIA`. Per the PowerISA, `bclrl` reads the *old* `LR` for the branch target and writes the *new* `LR` with the return address, atomically from software's perspective. Xenia implements it this way (`next_pc` captured first, then `lr` written).
- **Branch prediction hints (`BO[4]`).** The Xenon does static prediction on the basis of these hints, but behaviour is architecturally unobservable. Translators may ignore them.
- **Synchronisation.** `bclr` is **context-synchronising** (hence the `sync` flag in xenia's XML). Translators must ensure side-effecting instructions preceding the branch have committed — trivial in a sequential C translation but relevant for JIT backends.
- **xenia's `LR_HALT_SENTINEL`.** Xenia sets `LR` to `0xBCBCBCBC` at thread start; when the top-level guest function returns via `blr`, the interpreter loop halts cleanly. Translators replicating guest behaviour don't need this — but if you generate a test harness, the sentinel is a convenient "function returned" signal.
## Related Instructions
- [`bcctrx`](bcctrx.md) — branch conditional to **CTR** (used by indirect calls / vtables).
- [`bcx`](bcx.md) — branch conditional to an immediate displacement (D-form).
- [`bx`](bx.md) — unconditional branch (I-form).
- [`mtlr`](../control/mtspr.md), [`mflr`](../control/mfspr.md) — set/get LR via `mtspr 8, …` / `mfspr …, 8`.
- [`sc`](sc.md) — system call (alternative control-flow exit).
## Simplified Mnemonics
Assemblers fold common `BO`/`BI` patterns to single mnemonics:
| Simplified | Expansion |
| --- | --- |
| `blr` | `bclr BO=0b10100, BI=0` — branch always to LR |
| `blrl` | `bclrl BO=0b10100, BI=0` — branch always to LR with link (tail-call trampoline) |
| `beqlr crN` | `bclr BO=0b01100, BI=4·N+2` — return if `crN.EQ` |
| `bnelr crN` | `bclr BO=0b00100, BI=4·N+2` — return if `crN.NE` |
| `bltlr crN` | `bclr BO=0b01100, BI=4·N+0` — return if `crN.LT` |
| `bgelr crN` | `bclr BO=0b00100, BI=4·N+0` — return if `crN.GE` |
| `bgtlr crN` | `bclr BO=0b01100, BI=4·N+1` — return if `crN.GT` |
| `blelr crN` | `bclr BO=0b00100, BI=4·N+1` — return if `crN.LE` |
Xbox 360 disassemblers almost always emit the simplified form; the translation agent should learn to recognise them.
## IBM Reference
- [AIX 7.3 — `bclr` (Branch Conditional to Link Register)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-bclr-bclrl-branch-conditional-link-register-instruction)
- [AIX 7.3 — Branch simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-branch-simplified)

View 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 05):** `16`
- **Extended opcode:** —
- **Synchronising:** yes
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `BO` | branch options |
| 1115 | `BI` | CR bit to test |
| 1629 | `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 (031) 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)

View File

@@ -0,0 +1,133 @@
# `bx` — Branch
> **Category:** [Branch & System](../categories/branch.md) · **Form:** [I](../forms/I.md) · **Opcode:** `0x48000000` · _sync_
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `b` | `bx` | — | Branch |
| `bl` | `bx` | LK=1 | Branch |
## Syntax
```asm
b[LK][AA] [ADDR]
```
## Encoding
### `bx` — form `I`
- **Opcode word:** `0x48000000`
- **Primary opcode (bits 05):** `18`
- **Extended opcode:** —
- **Synchronising:** yes
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 629 | `LI` | signed 24-bit word-offset target |
| 30 | `AA` | absolute-address flag |
| 31 | `LK` | link flag (bl/ba/bla) |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `LK` | bx: read | Link bit. When 1, LR ← address-of-next-instruction before the branch is taken. |
| `AA` | bx: 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. |
| `ADDR` | bx: read | Encoded branch target displacement (24-bit for I-form, 14-bit for B-form, word-shifted). |
| `LR` | bx: write (conditional) | Link register. Written by `bl`/`bla`/`bcl`/`bclrl`/`bcctrl`; read by `bclr`/`bclrl`. |
## Register Effects
### `bx`
- **Reads (always):** `LK`, `AA`, `ADDR`
- **Reads (conditional):** _none_
- **Writes (always):** _none_
- **Writes (conditional):** `LR`
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
NIA <- (CIA + EXTS(LI || 0b00)) if AA=0
<- EXTS(LI || 0b00) if AA=1
if LK then LR <- CIA + 4
```
## C Translation Example
```c
/* b / bl / ba / bla — unconditional branch (I-form, primary 18) */
int32_t li = (int32_t)(insn.LI << 2); /* sign-extended word-offset */
uint32_t target = insn.AA ? (uint32_t)li : (uint32_t)(pc + li);
uint32_t next = pc + 4;
if (insn.LK) lr = next; /* bl / bla save return addr */
pc = target;
```
## Implementation References
**`bx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:154`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L154)
- 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:342`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L342)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:897-907`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L897-L907)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::bx => {
let target = if instr.aa() {
instr.li() as u32
} else {
ctx.pc.wrapping_add(instr.li() as u32)
};
if instr.lk() {
ctx.lr = (ctx.pc + 4) as u64;
}
ctx.pc = target;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **24-bit word-aligned target.** `LI` is a 24-bit signed word-count. Hardware concatenates `LI || 0b00` (adds the implicit two low zero bits) and sign-extends to 64 bits before using it as an address. The displacement range is therefore ±32 MiB in bytes (`2^25 … +2^25 4`).
- **Four mnemonics, one opcode.** The four runtime variants selected by `AA` and `LK`:
- `b``AA = 0, LK = 0` — PC-relative, no link.
- `bl``AA = 0, LK = 1` — PC-relative, `LR = CIA + 4` (the ubiquitous function-call primitive).
- `ba``AA = 1, LK = 0` — absolute, no link.
- `bla``AA = 1, LK = 1` — absolute, link.
Xbox 360 code almost exclusively uses `b` and `bl`; `ba` / `bla` appear only in kernel / firmware stubs.
- **Target alignment.** `LI` is scaled by 4, so all targets are 4-byte aligned by construction. There is no low-bit encoding of ARM-style Thumb — PPC has one instruction width.
- **LR write is *before* the branch.** In `bl`, `LR` receives `CIA + 4` (the address of the instruction *after* the branch) before execution transfers to the target. Nested calls naturally overwrite LR; callees must spill it ([`mflr`](../control/mfspr.md) + `std`) before making their own `bl`.
- **Indirect tail calls.** A tail call to an indirect target is encoded as `mtctr` + `bctr` (see [`bcctrx`](bcctrx.md)), not `bx``bx` has no register-based form.
- **No condition test.** Use [`bcx`](bcx.md) for conditional displacement branches or [`bclrx`](bclrx.md) / [`bcctrx`](bcctrx.md) for conditional LR/CTR jumps.
- **Speculative execution.** The Xenon fetches past `bx`; translators that mask control flow must treat the target as a single-destination control transfer.
## Related Instructions
- [`bcx`](bcx.md) — conditional displacement branch (B-form, ±32 KiB range).
- [`bclrx`](bclrx.md), [`bcctrx`](bcctrx.md) — branch to LR / CTR, conditional and unconditional.
- [`mtlr`](../control/mtspr.md), [`mflr`](../control/mfspr.md) — LR save/restore for nested `bl` calls.
- [`sc`](sc.md) — system call; an alternative control-flow exit to the kernel.
## Simplified Mnemonics
Assemblers emit `b`, `bl`, `ba`, `bla` for the four runtime combinations. There is no further simplification.
## IBM Reference
- [AIX 7.3 — `b` (Branch)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-b-branch-instruction)
- [AIX 7.3 — `bl` (Branch with Link, simplified mnemonic)](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-branch-simplified)

View File

@@ -0,0 +1,129 @@
# `sc` — System Call
> **Category:** [Branch & System](../categories/branch.md) · **Form:** [SC](../forms/SC.md) · **Opcode:** `0x44000002` · _sync_
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `sc` | `sc` | — | System Call |
## Syntax
```asm
sc [LEV]
```
## Encoding
### `sc` — form `SC`
- **Opcode word:** `0x44000002`
- **Primary opcode (bits 05):** `17`
- **Extended opcode:** —
- **Synchronising:** yes
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (17) |
| 619 | `—` | reserved |
| 2026 | `LEV` | exception level |
| 2729 | `—` | reserved |
| 30 | `1` | fixed 1 |
| 31 | `—` | reserved |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `LEV` | sc: read | System-call exception level (for `sc`). |
## Register Effects
### `sc`
- **Reads (always):** `LEV`
- **Reads (conditional):** _none_
- **Writes (always):** _none_
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
system_call_exception(LEV)
```
## 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
**`sc`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sc"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:455`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L455)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:63`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L63)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:341`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L341)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:984-997`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L984-L997)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::sc => {
// PPCBUG-064: log non-zero LEV (`sc 2` is the Xbox 360 hypervisor-call
// convention; canary dispatches it to a different handler than `sc 0`).
// Routing LEV=2 requires a StepResult variant extension; deferred.
let lev = (instr.raw >> 5) & 0x7F;
if lev != 0 {
tracing::warn!(
"sc with LEV={} at {:#010x}: dispatched as plain SystemCall (HVcall routing not implemented)",
lev, ctx.pc
);
}
ctx.pc += 4;
return StepResult::SystemCall;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`LEV` field — kernel vs hypervisor.** The 7-bit `LEV` operand selects the privilege level of the syscall:
- `LEV = 0` — supervisor (kernel) syscall. Standard application → kernel transition; targets the `0xC00` system-call vector.
- `LEV = 1` — reserved.
- `LEV = 2`**hypervisor syscall** (`HVcall`). On the Xenon, `sc 2` traps to the Xbox 360 hypervisor; this is how the kernel itself talks to the supervisor below it (e.g., for security operations, encrypted-memory accesses, page table updates).
- **`sc` as written by titles.** Almost all guest game code uses `LEV = 0` to call `XboxKrnl.exe`. Game disassembly will show large jump tables of small thunks each ending in `li r0, syscall_no; sc; blr`.
- **No condition or status side effects.** `sc` updates *no* general-purpose register on entry — neither LR nor CR. The kernel sees the GPR/FPR snapshot as-is and reads the syscall number out of `r0` (Xbox 360 ABI convention, not architectural).
- **Return path.** Hardware returns from `sc` via [`rfid`](../control/mtmsrd.md)-class instructions in the kernel handler; from the application's perspective execution resumes at `CIA + 4`. Xenia's interpreter realises this by simply pre-incrementing `pc` then returning `StepResult::SystemCall` — the host driver dispatches the syscall and re-enters the loop.
- **xenia divergence vs hardware.** xenia-rs *does not* model the `0xC00` exception vector or save SRR0/SRR1; the `LEV` operand is currently ignored. All `sc` instructions are treated identically and serviced by the host. This is sufficient because Xbox 360 titles don't observe SRR registers and the host kernel is implemented natively.
- **Synchronisation.** Marked `sync` in xenia's XML — `sc` is context-synchronising (hardware completes all prior instructions before raising the exception). JITs must flush pending state before emitting the host call.
- **Reserved bits.** Bit 30 is fixed `1`; bits 619 and 2729 are reserved (must be 0). The 1-bit field at position 30 distinguishes the `sc` encoding from `scv` (later PowerISA addition, not present on the Xenon).
## Related Instructions
- [`bx`](bx.md), [`bcx`](bcx.md), [`bclrx`](bclrx.md), [`bcctrx`](bcctrx.md) — ordinary control flow alternatives.
- [`tw`](tw.md), [`twi`](twi.md), [`td`](td.md), [`tdi`](tdi.md) — synchronous *trap* exceptions; another way to enter the kernel.
- [`mtmsr`](../control/mtmsr.md), [`mtmsrd`](../control/mtmsrd.md) — machine-state changes used by the kernel's `sc` handler on return (`rfid`/`hrfid` chain not separately documented in this manual).
- [`isync`](../control/mtmsr.md) — context-synchronising sibling; `sc` itself implies an isync-like fence.
## IBM Reference
- [AIX 7.3 — `sc` (System Call)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-sc-system-call-instruction)
- PowerISA v2.07B, Book III §7 — System Linkage interrupt definitions and `LEV` field semantics.

View File

@@ -0,0 +1,184 @@
# `td` — Trap Doubleword
> **Category:** [Branch & System](../categories/branch.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000088`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `td` | `td` | — | Trap Doubleword |
## Syntax
```asm
td [TO], [RA], [RB]
```
## Encoding
### `td` — form `X`
- **Opcode word:** `0x7c000088`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `68`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `TO` | td: read | Trap-on condition mask (5 bits) — LT, GT, EQ, LGT, LLT bits. |
| `RA` | td: read | Source GPR (`r0``r31`). |
| `RB` | td: read | Source GPR. |
## Register Effects
### `td`
- **Reads (always):** `TO`, `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** _none_
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`td`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="td"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:552`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L552)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:87`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L87)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:769`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L769)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1762-1796`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1762-L1796)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::tw | PpcOpcode::twi | PpcOpcode::td | PpcOpcode::tdi => {
// PPCBUG-063: save CIA before incrementing so a trap handler reads
// the faulting instruction address, not CIA+4.
// PPCBUG-065: log the SIMM type code on `twi 31, r0, IMM` (Xbox 360
// typed-trap convention used by the CRT/kernel for C++ exception
// class dispatch). The audit notes this is relevant to the Sylpheed
// throw investigation; routing the type code via a payload requires
// a StepResult enum extension that's deferred for now.
let trap_pc = ctx.pc;
let a = ctx.gpr[instr.ra()];
let b = match instr.opcode {
PpcOpcode::twi | PpcOpcode::tdi => instr.simm16() as i64 as u64,
_ => ctx.gpr[instr.rb()],
};
let width = match instr.opcode {
PpcOpcode::tw | PpcOpcode::twi => trap::TrapWidth::Word,
_ => trap::TrapWidth::Doubleword,
};
let fired = trap::evaluate(instr.to(), a, b, width);
if fired {
let typed_trap_simm = if matches!(instr.opcode, PpcOpcode::twi)
&& instr.to() == 31 && instr.ra() == 0 {
Some(instr.simm16() as u16)
} else { None };
tracing::warn!(
"Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}{}",
trap_pc, instr.opcode, instr.to(), a, b,
typed_trap_simm.map_or(String::new(), |t| format!(" typed_trap_simm={:#06x}", t))
);
// Leave ctx.pc at CIA (NOT NIA) so trap handlers / SEH delivery
// can read the faulting instruction address from ctx.pc.
return StepResult::Trap;
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **`TO` mask encoding (5 bits, MSB-first).** Each bit selects one comparison; the trap fires if *any* selected condition is true. Both operands are treated as 64-bit doublewords:
| Bit | Mnemonic | Triggered when |
| --- | --- | --- |
| `TO[0]` (16) | LT | `(int64) RA < (int64) RB` |
| `TO[1]` (8) | GT | `(int64) RA > (int64) RB` |
| `TO[2]` (4) | EQ | `RA == RB` |
| `TO[3]` (2) | LGT | `(uint64) RA < (uint64) RB` (logical less) |
| `TO[4]` (1) | LLT | `(uint64) RA > (uint64) RB` (logical greater — historical naming) |
- **`TO = 31` is unconditional trap.** All five bits set ⇒ the trap fires regardless of operand values; the simplified mnemonic `trap` is `tw 31, 0, 0` for words and **`td 31, 0, 0`** for doublewords. The PowerISA also uses `tdi 31, 0, 0` (or `twi`) as a debugger break.
- **64-bit comparison.** Unlike [`tw`](tw.md), `td` always compares the full 64-bit GPRs. On the Xenon (64-bit) this is meaningful; PPC32 implementations don't have `td`.
- **No register effects.** Only the side effect is the trap. No CR/LR/CTR/XER updates.
- **Hardware behaviour.** When the trap fires, hardware raises a Program interrupt with `SRR1[TRAP]` set and vectors to `0x700`. The Xbox 360 hypervisor / kernel handles it (assertion failure, debugger trap, etc.).
- **xenia simplification.** xenia-rs collapses all four trap variants (`td`, `tdi`, `tw`, `twi`) into one match arm that *unconditionally* logs and returns `StepResult::Trap` — it does **not** evaluate `TO` against the operands. This is a material divergence from the spec: in xenia every trap fires even if the condition is false. Real Xenon code rarely uses non-trivial `TO` masks (typical use is the unconditional `trap` for `__assert` / debugger break), so the divergence is normally invisible.
- **Distinguishing assert vs. break.** Compilers commonly emit `tdne r3, r3` (impossible) or `tdi 0, r0, 0` patterns that *cannot* trap as inert markers. Xenia's blanket trap would mis-fire on these — a small known bug; track it if you see spurious traps.
## Related Instructions
- [`tdi`](tdi.md) — same condition test against a 16-bit signed immediate (D-form).
- [`tw`](tw.md) / [`twi`](twi.md) — 32-bit (word) variants for comparing low halves of GPRs.
- [`sc`](sc.md) — synchronous kernel entry via system-call exception (different vector, different intent).
- [`mtmsr`](../control/mtmsr.md) — kernel returns from the trap handler via `rfid`-family instructions.
### Simplified Mnemonics
| Simplified | Expansion | Triggered when |
| --- | --- | --- |
| `td RA, RB` (=`tdu`) | `td 31, RA, RB` | unconditional trap |
| `tdeq RA, RB` | `td 4, RA, RB` | `RA == RB` |
| `tdne RA, RB` | `td 24, RA, RB` | `RA != RB` |
| `tdlt RA, RB` | `td 16, RA, RB` | signed less than |
| `tdle RA, RB` | `td 20, RA, RB` | signed less or equal |
| `tdgt RA, RB` | `td 8, RA, RB` | signed greater than |
| `tdge RA, RB` | `td 12, RA, RB` | signed greater or equal |
| `tdllt RA, RB` | `td 2, RA, RB` | unsigned less than |
| `tdlge RA, RB` | `td 5, RA, RB` | unsigned greater or equal |
| `tdlgt RA, RB` | `td 1, RA, RB` | unsigned greater than |
| `tdlle RA, RB` | `td 6, RA, RB` | unsigned less or equal |
## IBM Reference
- [AIX 7.3 — `td` (Trap Doubleword)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-td-trap-doubleword-instruction)
- [AIX 7.3 — Trap simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-trap-simplified)
- PowerISA v2.07B, Book I §3.3.11 — fixed-point trap instructions (`TO` semantics).

View File

@@ -0,0 +1,173 @@
# `tdi` — Trap Doubleword Immediate
> **Category:** [Branch & System](../categories/branch.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x08000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `tdi` | `tdi` | — | Trap Doubleword Immediate |
## Syntax
```asm
tdi [TO], [RA], [SIMM]
```
## Encoding
### `tdi` — form `D`
- **Opcode word:** `0x08000000`
- **Primary opcode (bits 05):** `2`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `TO` | tdi: read | Trap-on condition mask (5 bits) — LT, GT, EQ, LGT, LLT bits. |
| `RA` | tdi: read | Source GPR (`r0``r31`). |
| `SIMM` | tdi: read | 16-bit signed immediate. Sign-extended to 64 bits before use. |
## Register Effects
### `tdi`
- **Reads (always):** `TO`, `RA`, `SIMM`
- **Reads (conditional):** _none_
- **Writes (always):** _none_
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`tdi`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="tdi"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:568`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L568)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:87`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L87)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:327`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L327)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1762-1796`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1762-L1796)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::tw | PpcOpcode::twi | PpcOpcode::td | PpcOpcode::tdi => {
// PPCBUG-063: save CIA before incrementing so a trap handler reads
// the faulting instruction address, not CIA+4.
// PPCBUG-065: log the SIMM type code on `twi 31, r0, IMM` (Xbox 360
// typed-trap convention used by the CRT/kernel for C++ exception
// class dispatch). The audit notes this is relevant to the Sylpheed
// throw investigation; routing the type code via a payload requires
// a StepResult enum extension that's deferred for now.
let trap_pc = ctx.pc;
let a = ctx.gpr[instr.ra()];
let b = match instr.opcode {
PpcOpcode::twi | PpcOpcode::tdi => instr.simm16() as i64 as u64,
_ => ctx.gpr[instr.rb()],
};
let width = match instr.opcode {
PpcOpcode::tw | PpcOpcode::twi => trap::TrapWidth::Word,
_ => trap::TrapWidth::Doubleword,
};
let fired = trap::evaluate(instr.to(), a, b, width);
if fired {
let typed_trap_simm = if matches!(instr.opcode, PpcOpcode::twi)
&& instr.to() == 31 && instr.ra() == 0 {
Some(instr.simm16() as u16)
} else { None };
tracing::warn!(
"Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}{}",
trap_pc, instr.opcode, instr.to(), a, b,
typed_trap_simm.map_or(String::new(), |t| format!(" typed_trap_simm={:#06x}", t))
);
// Leave ctx.pc at CIA (NOT NIA) so trap handlers / SEH delivery
// can read the faulting instruction address from ctx.pc.
return StepResult::Trap;
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Immediate is sign-extended.** `SIMM` is treated as a 16-bit signed value, then sign-extended to 64 bits before comparison. To trap against a small unsigned constant, the same encoding works because both signed and unsigned interpretations agree for `SIMM ∈ [0, 0x7FFF]`.
- **`TO` mask.** Identical bit layout to [`td`](td.md): bit 0 = signed LT, 1 = signed GT, 2 = EQ, 3 = unsigned LT (LGT), 4 = unsigned GT (LLT). Trap fires if any selected bit's condition is true.
- **`TO = 31` is unconditional.** `tdi 31, 0, 0` is a debugger / assert trap. Compilers sometimes use it as a "should not reach" marker.
- **64-bit comparison only.** Unlike [`twi`](twi.md), `tdi` always compares the full 64-bit GPR — it has no PPC32 analogue. The Xenon's PPC64 mode makes this meaningful.
- **No register effects.** Pure side effect on success: Program interrupt → vector `0x700` with `SRR1[TRAP]=1`.
- **xenia simplification.** xenia-rs unconditionally treats `tdi` as a fired trap, regardless of `TO`/`RA`/`SIMM` values. This diverges from the spec — real hardware would silently fall through when no `TO` bit's condition holds. Most title code uses only the unconditional `trap` form, so the divergence is normally invisible; non-firing assertion patterns (e.g. `tdi 0, r0, 0`) will mis-fire under xenia.
- **Reserved bits.** Bits 610 carry the `TO` field; there is no `Rc` / `OE` on D-form trap immediates.
## Related Instructions
- [`td`](td.md) — register-register doubleword trap (X-form).
- [`twi`](twi.md) / [`tw`](tw.md) — 32-bit-comparison siblings.
- [`sc`](sc.md) — kernel-entry counterpart via system call exception.
- [`mtmsrd`](mtmsrd.md) (control category) — kernel `rfid`-style return path after handling.
### Simplified Mnemonics
| Simplified | Expansion | Triggered when |
| --- | --- | --- |
| `tdi RA, value` | `tdi 31, RA, value` | unconditional trap |
| `tdeqi RA, value` | `tdi 4, RA, value` | `RA == EXTS(value)` |
| `tdnei RA, value` | `tdi 24, RA, value` | `RA != EXTS(value)` |
| `tdlti RA, value` | `tdi 16, RA, value` | signed less than |
| `tdlei RA, value` | `tdi 20, RA, value` | signed less or equal |
| `tdgti RA, value` | `tdi 8, RA, value` | signed greater than |
| `tdgei RA, value` | `tdi 12, RA, value` | signed greater or equal |
| `tdllti RA, value` | `tdi 2, RA, value` | unsigned less than |
| `tdlgei RA, value` | `tdi 5, RA, value` | unsigned greater or equal |
| `tdlgti RA, value` | `tdi 1, RA, value` | unsigned greater than |
| `tdllei RA, value` | `tdi 6, RA, value` | unsigned less or equal |
## IBM Reference
- [AIX 7.3 — `tdi` (Trap Doubleword Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-tdi-trap-doubleword-immediate-instruction)
- [AIX 7.3 — Trap simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-trap-simplified)
- PowerISA v2.07B, Book I §3.3.11 — fixed-point trap instructions.

View File

@@ -0,0 +1,184 @@
# `tw` — Trap Word
> **Category:** [Branch & System](../categories/branch.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000008`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `tw` | `tw` | — | Trap Word |
## Syntax
```asm
tw [TO], [RA], [RB]
```
## Encoding
### `tw` — form `X`
- **Opcode word:** `0x7c000008`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `4`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `TO` | tw: read | Trap-on condition mask (5 bits) — LT, GT, EQ, LGT, LLT bits. |
| `RA` | tw: read | Source GPR (`r0``r31`). |
| `RB` | tw: read | Source GPR. |
## Register Effects
### `tw`
- **Reads (always):** `TO`, `RA`, `RB`
- **Reads (conditional):** _none_
- **Writes (always):** _none_
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`tw`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="tw"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:583`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L583)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:87`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L87)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:750`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L750)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1762-1796`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1762-L1796)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::tw | PpcOpcode::twi | PpcOpcode::td | PpcOpcode::tdi => {
// PPCBUG-063: save CIA before incrementing so a trap handler reads
// the faulting instruction address, not CIA+4.
// PPCBUG-065: log the SIMM type code on `twi 31, r0, IMM` (Xbox 360
// typed-trap convention used by the CRT/kernel for C++ exception
// class dispatch). The audit notes this is relevant to the Sylpheed
// throw investigation; routing the type code via a payload requires
// a StepResult enum extension that's deferred for now.
let trap_pc = ctx.pc;
let a = ctx.gpr[instr.ra()];
let b = match instr.opcode {
PpcOpcode::twi | PpcOpcode::tdi => instr.simm16() as i64 as u64,
_ => ctx.gpr[instr.rb()],
};
let width = match instr.opcode {
PpcOpcode::tw | PpcOpcode::twi => trap::TrapWidth::Word,
_ => trap::TrapWidth::Doubleword,
};
let fired = trap::evaluate(instr.to(), a, b, width);
if fired {
let typed_trap_simm = if matches!(instr.opcode, PpcOpcode::twi)
&& instr.to() == 31 && instr.ra() == 0 {
Some(instr.simm16() as u16)
} else { None };
tracing::warn!(
"Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}{}",
trap_pc, instr.opcode, instr.to(), a, b,
typed_trap_simm.map_or(String::new(), |t| format!(" typed_trap_simm={:#06x}", t))
);
// Leave ctx.pc at CIA (NOT NIA) so trap handlers / SEH delivery
// can read the faulting instruction address from ctx.pc.
return StepResult::Trap;
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **32-bit comparison only.** `tw` compares the *low 32 bits* of `RA` and `RB`. The high halves of the 64-bit GPRs on the Xenon are ignored. Use [`td`](td.md) for full 64-bit comparisons.
- **`TO` mask (5 bits, MSB-first).** Same encoding as the doubleword form:
| Bit | Mnemonic | Triggered when |
| --- | --- | --- |
| `TO[0]` (16) | LT | `(int32) RA < (int32) RB` |
| `TO[1]` (8) | GT | `(int32) RA > (int32) RB` |
| `TO[2]` (4) | EQ | `(uint32) RA == (uint32) RB` |
| `TO[3]` (2) | LGT | `(uint32) RA < (uint32) RB` |
| `TO[4]` (1) | LLT | `(uint32) RA > (uint32) RB` |
- **`tw 31, 0, 0` is `trap`.** The simplified mnemonic `trap` expands to `tw 31, r0, r0` — all five `TO` bits set ⇒ unconditional trap. Compilers and the kernel use this as the assertion / debugger break primitive; it appears as `0x7FE00008` in raw bytes.
- **Conditional asserts.** GCC's `__builtin_trap` and MSVC's `__assert` macros emit `tw` variants like `twge`/`twlt` to fault on bound-check failures.
- **No register effects.** Side effect only: Program interrupt (`0x700`) with `SRR1[TRAP]=1`.
- **xenia simplification.** xenia-rs collapses `td/tdi/tw/twi` into a single arm that *unconditionally* logs and returns `StepResult::Trap` — the `TO` operand is **not evaluated**. Real hardware would silently fall through when no `TO` bit's condition holds. In practice titles use mostly the unconditional `trap`, so the divergence rarely manifests, but inert-marker patterns like `tw 0, r0, r0` will fire under xenia.
- **Inert encoding.** `tw 0, r0, r0` (no `TO` bits set) can never trap on real hardware. It encodes as `0x7C000008` — sometimes used as a structured-NOP marker. Watch for it in xenia traces.
## Related Instructions
- [`twi`](twi.md) — same 32-bit comparison against a 16-bit signed immediate.
- [`td`](td.md) / [`tdi`](tdi.md) — 64-bit (doubleword) variants.
- [`sc`](sc.md) — kernel entry via system-call exception (different vector).
- [`mtmsr`](../control/mtmsr.md) — kernel returns from `0x700` via `rfid`.
### Simplified Mnemonics
| Simplified | Expansion | Triggered when |
| --- | --- | --- |
| `trap` | `tw 31, 0, 0` | unconditional |
| `tweq RA, RB` | `tw 4, RA, RB` | `RA == RB` |
| `twne RA, RB` | `tw 24, RA, RB` | `RA != RB` |
| `twlt RA, RB` | `tw 16, RA, RB` | signed less than |
| `twle RA, RB` | `tw 20, RA, RB` | signed less or equal |
| `twgt RA, RB` | `tw 8, RA, RB` | signed greater than |
| `twge RA, RB` | `tw 12, RA, RB` | signed greater or equal |
| `twllt RA, RB` | `tw 2, RA, RB` | unsigned less than |
| `twlge RA, RB` | `tw 5, RA, RB` | unsigned greater or equal |
| `twlgt RA, RB` | `tw 1, RA, RB` | unsigned greater than |
| `twlle RA, RB` | `tw 6, RA, RB` | unsigned less or equal |
## IBM Reference
- [AIX 7.3 — `tw` (Trap Word)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-tw-trap-word-instruction)
- [AIX 7.3 — Trap simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-trap-simplified)
- PowerISA v2.07B, Book I §3.3.11 — fixed-point trap instructions.

View File

@@ -0,0 +1,172 @@
# `twi` — Trap Word Immediate
> **Category:** [Branch & System](../categories/branch.md) · **Form:** [D](../forms/D.md) · **Opcode:** `0x0c000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `twi` | `twi` | — | Trap Word Immediate |
## Syntax
```asm
tw [TO], [RA], [SIMM]
```
## Encoding
### `twi` — form `D`
- **Opcode word:** `0x0c000000`
- **Primary opcode (bits 05):** `3`
- **Extended opcode:** —
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT` | destination GPR (or RS when storing) |
| 1115 | `RA` | source GPR (0 ⇒ literal 0 for RA0 forms) |
| 1631 | `D/SI/UI` | 16-bit signed or unsigned immediate |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `TO` | twi: read | Trap-on condition mask (5 bits) — LT, GT, EQ, LGT, LLT bits. |
| `RA` | twi: read | Source GPR (`r0``r31`). |
| `SIMM` | twi: read | 16-bit signed immediate. Sign-extended to 64 bits before use. |
## Register Effects
### `twi`
- **Reads (always):** `TO`, `RA`, `SIMM`
- **Reads (conditional):** _none_
- **Writes (always):** _none_
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`twi`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="twi"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:601`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L601)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:87`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L87)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:328`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L328)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1762-1796`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1762-L1796)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::tw | PpcOpcode::twi | PpcOpcode::td | PpcOpcode::tdi => {
// PPCBUG-063: save CIA before incrementing so a trap handler reads
// the faulting instruction address, not CIA+4.
// PPCBUG-065: log the SIMM type code on `twi 31, r0, IMM` (Xbox 360
// typed-trap convention used by the CRT/kernel for C++ exception
// class dispatch). The audit notes this is relevant to the Sylpheed
// throw investigation; routing the type code via a payload requires
// a StepResult enum extension that's deferred for now.
let trap_pc = ctx.pc;
let a = ctx.gpr[instr.ra()];
let b = match instr.opcode {
PpcOpcode::twi | PpcOpcode::tdi => instr.simm16() as i64 as u64,
_ => ctx.gpr[instr.rb()],
};
let width = match instr.opcode {
PpcOpcode::tw | PpcOpcode::twi => trap::TrapWidth::Word,
_ => trap::TrapWidth::Doubleword,
};
let fired = trap::evaluate(instr.to(), a, b, width);
if fired {
let typed_trap_simm = if matches!(instr.opcode, PpcOpcode::twi)
&& instr.to() == 31 && instr.ra() == 0 {
Some(instr.simm16() as u16)
} else { None };
tracing::warn!(
"Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}{}",
trap_pc, instr.opcode, instr.to(), a, b,
typed_trap_simm.map_or(String::new(), |t| format!(" typed_trap_simm={:#06x}", t))
);
// Leave ctx.pc at CIA (NOT NIA) so trap handlers / SEH delivery
// can read the faulting instruction address from ctx.pc.
return StepResult::Trap;
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **32-bit comparison against sign-extended immediate.** `SIMM` is a 16-bit signed value, sign-extended to 32 bits, then compared against the low 32 bits of `RA`. The high half of `RA` is *ignored*.
- **`TO` mask.** Identical to [`tw`](tw.md): bit 0 = signed LT, 1 = signed GT, 2 = EQ, 3 = unsigned LT (LGT), 4 = unsigned GT (LLT). Trap fires if any selected bit's condition is true.
- **`twi 31, 0, 0` is unconditional trap.** All `TO` bits set ⇒ guaranteed trap. The simplified mnemonic family (`twnei`, `twgei`, …) is much more common in real code: bound checks, null checks, integer-divide-by-zero pre-checks.
- **Compiler usage.** Xbox 360 GCC emits `twnei rN, -1` and similar to validate handle-style return values; the kernel handler turns the trap into an exception delivered to the title.
- **No register effects.** Side effect: Program interrupt → vector `0x700` with `SRR1[TRAP]=1`.
- **xenia simplification.** Same as the other three trap forms — xenia-rs unconditionally returns `StepResult::Trap` whenever it decodes any of `tdi`/`twi`/`td`/`tw`, regardless of the `TO` mask or operands. This means `twi 0, r0, 0` (architecturally a guaranteed-no-trap encoding) will spuriously fire under xenia. Keep this in mind when triaging unexpected trap signals.
- **No `Rc` / `OE`.** D-form trap immediates have neither.
## Related Instructions
- [`tw`](tw.md) — register-register 32-bit trap (X-form).
- [`tdi`](tdi.md) / [`td`](td.md) — 64-bit (doubleword) siblings.
- [`sc`](sc.md) — alternative synchronous kernel entry.
- [`cmpi`](../alu/cmpi.md), [`cmpli`](../alu/cmpli.md) — set CR for a subsequent [`bcx`](bcx.md) when you want a regular branch instead of a trap.
### Simplified Mnemonics
| Simplified | Expansion | Triggered when |
| --- | --- | --- |
| `tweqi RA, value` | `twi 4, RA, value` | `RA == EXTS(value)` |
| `twnei RA, value` | `twi 24, RA, value` | `RA != EXTS(value)` |
| `twlti RA, value` | `twi 16, RA, value` | signed less than |
| `twlei RA, value` | `twi 20, RA, value` | signed less or equal |
| `twgti RA, value` | `twi 8, RA, value` | signed greater than |
| `twgei RA, value` | `twi 12, RA, value` | signed greater or equal |
| `twllti RA, value` | `twi 2, RA, value` | unsigned less than |
| `twlgei RA, value` | `twi 5, RA, value` | unsigned greater or equal |
| `twlgti RA, value` | `twi 1, RA, value` | unsigned greater than |
| `twllei RA, value` | `twi 6, RA, value` | unsigned less or equal |
## IBM Reference
- [AIX 7.3 — `twi` (Trap Word Immediate)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-twi-trap-word-immediate-instruction)
- [AIX 7.3 — Trap simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-trap-simplified)
- PowerISA v2.07B, Book I §3.3.11 — fixed-point trap instructions.

View File

@@ -0,0 +1,82 @@
# Integer ALU
Fixed-point add/sub/multiply/divide, logical, rotate, shift, compare, count-leading-zeros, sign-extension, trap-on-condition.
**70 families** · **70 XML entries**.
<!-- GENERATED: BEGIN -->
| Family | Form | Description | Members |
| --- | --- | --- | --- |
| [`addcx`](addcx.md) | `XO` | Add Carrying | `addcx` |
| [`addex`](addex.md) | `XO` | Add Extended | `addex` |
| [`addi`](addi.md) | `D` | Add Immediate | `addi` |
| [`addic`](addic.md) | `D` | Add Immediate Carrying | `addic` |
| [`addic.`](addicx.md) | `D` | Add Immediate Carrying and Record | `addic.` |
| [`addis`](addis.md) | `D` | Add Immediate Shifted | `addis` |
| [`addmex`](addmex.md) | `XO` | Add to Minus One Extended | `addmex` |
| [`addx`](addx.md) | `XO` | Add | `addx` |
| [`addzex`](addzex.md) | `XO` | Add to Zero Extended | `addzex` |
| [`andcx`](andcx.md) | `X` | AND with Complement | `andcx` |
| [`andi.`](andix.md) | `D` | AND Immediate | `andi.` |
| [`andis.`](andisx.md) | `D` | AND Immediate Shifted | `andis.` |
| [`andx`](andx.md) | `X` | AND | `andx` |
| [`cmp`](cmp.md) | `X` | Compare | `cmp` |
| [`cmpi`](cmpi.md) | `D` | Compare Immediate | `cmpi` |
| [`cmpl`](cmpl.md) | `X` | Compare Logical | `cmpl` |
| [`cmpli`](cmpli.md) | `D` | Compare Logical Immediate | `cmpli` |
| [`cntlzdx`](cntlzdx.md) | `X` | Count Leading Zeros Doubleword | `cntlzdx` |
| [`cntlzwx`](cntlzwx.md) | `X` | Count Leading Zeros Word | `cntlzwx` |
| [`divdux`](divdux.md) | `XO` | Divide Doubleword Unsigned | `divdux` |
| [`divdx`](divdx.md) | `XO` | Divide Doubleword | `divdx` |
| [`divwux`](divwux.md) | `XO` | Divide Word Unsigned | `divwux` |
| [`divwx`](divwx.md) | `XO` | Divide Word | `divwx` |
| [`eieio`](eieio.md) | `X` | Enforce In-Order Execution of I/O | `eieio` |
| [`eqvx`](eqvx.md) | `X` | Equivalent | `eqvx` |
| [`extsbx`](extsbx.md) | `X` | Extend Sign Byte | `extsbx` |
| [`extshx`](extshx.md) | `X` | Extend Sign Half Word | `extshx` |
| [`extswx`](extswx.md) | `X` | Extend Sign Word | `extswx` |
| [`isync`](isync.md) | `XL` | Instruction Synchronize | `isync` |
| [`mulhdux`](mulhdux.md) | `XO` | Multiply High Doubleword Unsigned | `mulhdux` |
| [`mulhdx`](mulhdx.md) | `XO` | Multiply High Doubleword | `mulhdx` |
| [`mulhwux`](mulhwux.md) | `XO` | Multiply High Word Unsigned | `mulhwux` |
| [`mulhwx`](mulhwx.md) | `XO` | Multiply High Word | `mulhwx` |
| [`mulldx`](mulldx.md) | `XO` | Multiply Low Doubleword | `mulldx` |
| [`mulli`](mulli.md) | `D` | Multiply Low Immediate | `mulli` |
| [`mullwx`](mullwx.md) | `XO` | Multiply Low Word | `mullwx` |
| [`nandx`](nandx.md) | `X` | NAND | `nandx` |
| [`negx`](negx.md) | `XO` | Negate | `negx` |
| [`norx`](norx.md) | `X` | NOR | `norx` |
| [`orcx`](orcx.md) | `X` | OR with Complement | `orcx` |
| [`ori`](ori.md) | `D` | OR Immediate | `ori` |
| [`oris`](oris.md) | `D` | OR Immediate Shifted | `oris` |
| [`orx`](orx.md) | `X` | OR | `orx` |
| [`rldclx`](rldclx.md) | `MDS` | Rotate Left Doubleword then Clear Left | `rldclx` |
| [`rldcrx`](rldcrx.md) | `MDS` | Rotate Left Doubleword then Clear Right | `rldcrx` |
| [`rldiclx`](rldiclx.md) | `MD` | Rotate Left Doubleword Immediate then Clear Left | `rldiclx` |
| [`rldicrx`](rldicrx.md) | `MD` | Rotate Left Doubleword Immediate then Clear Right | `rldicrx` |
| [`rldicx`](rldicx.md) | `MD` | Rotate Left Doubleword Immediate then Clear | `rldicx` |
| [`rldimix`](rldimix.md) | `MD` | Rotate Left Doubleword Immediate then Mask Insert | `rldimix` |
| [`rlwimix`](rlwimix.md) | `M` | Rotate Left Word Immediate then Mask Insert | `rlwimix` |
| [`rlwinmx`](rlwinmx.md) | `M` | Rotate Left Word Immediate then AND with Mask | `rlwinmx` |
| [`rlwnmx`](rlwnmx.md) | `M` | Rotate Left Word then AND with Mask | `rlwnmx` |
| [`sldx`](sldx.md) | `X` | Shift Left Doubleword | `sldx` |
| [`slwx`](slwx.md) | `X` | Shift Left Word | `slwx` |
| [`sradix`](sradix.md) | `XS` | Shift Right Algebraic Doubleword Immediate | `sradix` |
| [`sradx`](sradx.md) | `X` | Shift Right Algebraic Doubleword | `sradx` |
| [`srawix`](srawix.md) | `X` | Shift Right Algebraic Word Immediate | `srawix` |
| [`srawx`](srawx.md) | `X` | Shift Right Algebraic Word | `srawx` |
| [`srdx`](srdx.md) | `X` | Shift Right Doubleword | `srdx` |
| [`srwx`](srwx.md) | `X` | Shift Right Word | `srwx` |
| [`subfcx`](subfcx.md) | `XO` | Subtract From Carrying | `subfcx` |
| [`subfex`](subfex.md) | `XO` | Subtract From Extended | `subfex` |
| [`subficx`](subficx.md) | `D` | Subtract From Immediate Carrying | `subficx` |
| [`subfmex`](subfmex.md) | `XO` | Subtract From Minus One Extended | `subfmex` |
| [`subfx`](subfx.md) | `XO` | Subtract From | `subfx` |
| [`subfzex`](subfzex.md) | `XO` | Subtract From Zero Extended | `subfzex` |
| [`sync`](sync.md) | `X` | Synchronize | `sync` |
| [`xori`](xori.md) | `D` | XOR Immediate | `xori` |
| [`xoris`](xoris.md) | `D` | XOR Immediate Shifted | `xoris` |
| [`xorx`](xorx.md) | `X` | XOR | `xorx` |
<!-- GENERATED: END -->

View File

@@ -0,0 +1,21 @@
# Branch & System
Unconditional / conditional branches, branch to LR/CTR, traps, system call.
**9 families** · **9 XML entries**.
<!-- GENERATED: BEGIN -->
| Family | Form | Description | Members |
| --- | --- | --- | --- |
| [`bcctrx`](bcctrx.md) | `XL` | Branch Conditional to Count Register | `bcctrx` |
| [`bclrx`](bclrx.md) | `XL` | Branch Conditional to Link Register | `bclrx` |
| [`bcx`](bcx.md) | `B` | Branch Conditional | `bcx` |
| [`bx`](bx.md) | `I` | Branch | `bx` |
| [`sc`](sc.md) | `SC` | System Call | `sc` |
| [`td`](td.md) | `X` | Trap Doubleword | `td` |
| [`tdi`](tdi.md) | `D` | Trap Doubleword Immediate | `tdi` |
| [`tw`](tw.md) | `X` | Trap Word | `tw` |
| [`twi`](twi.md) | `D` | Trap Word Immediate | `twi` |
<!-- GENERATED: END -->

View File

@@ -0,0 +1,38 @@
# Control / CR / SPR
Condition-register logical ops, CR field moves, mfspr/mtspr/mtcrf, time-base reads, synchronisation (sync, isync, eieio).
**26 families** · **26 XML entries**.
<!-- GENERATED: BEGIN -->
| Family | Form | Description | Members |
| --- | --- | --- | --- |
| [`crand`](crand.md) | `XL` | Condition Register AND | `crand` |
| [`crandc`](crandc.md) | `XL` | Condition Register AND with Complement | `crandc` |
| [`creqv`](creqv.md) | `XL` | Condition Register Equivalent | `creqv` |
| [`crnand`](crnand.md) | `XL` | Condition Register NAND | `crnand` |
| [`crnor`](crnor.md) | `XL` | Condition Register NOR | `crnor` |
| [`cror`](cror.md) | `XL` | Condition Register OR | `cror` |
| [`crorc`](crorc.md) | `XL` | Condition Register OR with Complement | `crorc` |
| [`crxor`](crxor.md) | `XL` | Condition Register XOR | `crxor` |
| [`mcrf`](mcrf.md) | `XL` | Move Condition Register Field | `mcrf` |
| [`mcrfs`](mcrfs.md) | `X` | Move to Condition Register from FPSCR | `mcrfs` |
| [`mcrxr`](mcrxr.md) | `X` | Move to Condition Register from XER | `mcrxr` |
| [`mfcr`](mfcr.md) | `X` | Move from Condition Register | `mfcr` |
| [`mffsx`](mffsx.md) | `X` | Move from FPSCR | `mffsx` |
| [`mfmsr`](mfmsr.md) | `X` | Move from Machine State Register | `mfmsr` |
| [`mfspr`](mfspr.md) | `XFX` | Move from Special-Purpose Register | `mfspr` |
| [`mftb`](mftb.md) | `XFX` | Move from Time Base | `mftb` |
| [`mfvscr`](mfvscr.md) | `VX` | Move from VSCR | `mfvscr` |
| [`mtcrf`](mtcrf.md) | `XFX` | Move to Condition Register Fields | `mtcrf` |
| [`mtfsb0x`](mtfsb0x.md) | `X` | Move to FPSCR Bit 0 | `mtfsb0x` |
| [`mtfsb1x`](mtfsb1x.md) | `X` | Move to FPSCR Bit 1 | `mtfsb1x` |
| [`mtfsfix`](mtfsfix.md) | `X` | Move to FPSCR Field Immediate | `mtfsfix` |
| [`mtfsfx`](mtfsfx.md) | `XFL` | Move to FPSCR Fields | `mtfsfx` |
| [`mtmsr`](mtmsr.md) | `X` | Move to Machine State Register | `mtmsr` |
| [`mtmsrd`](mtmsrd.md) | `X` | Move to Machine State Register Doubleword | `mtmsrd` |
| [`mtspr`](mtspr.md) | `XFX` | Move to Special-Purpose Register | `mtspr` |
| [`mtvscr`](mtvscr.md) | `VX` | Move to VSCR | `mtvscr` |
<!-- GENERATED: END -->

View File

@@ -0,0 +1,45 @@
# Floating-Point
IEEE-754 add/sub/mul/div/sqrt, fused multiply-add, conversions, compares, FPSCR moves.
**33 families** · **33 XML entries**.
<!-- GENERATED: BEGIN -->
| Family | Form | Description | Members |
| --- | --- | --- | --- |
| [`fabsx`](fabsx.md) | `X` | Floating Absolute Value | `fabsx` |
| [`faddsx`](faddsx.md) | `A` | Floating Add Single | `faddsx` |
| [`faddx`](faddx.md) | `A` | Floating Add | `faddx` |
| [`fcfidx`](fcfidx.md) | `X` | Floating Convert From Integer Doubleword | `fcfidx` |
| [`fcmpo`](fcmpo.md) | `X` | Floating Compare Ordered | `fcmpo` |
| [`fcmpu`](fcmpu.md) | `X` | Floating Compare Unordered | `fcmpu` |
| [`fctidx`](fctidx.md) | `X` | Floating Convert to Integer Doubleword | `fctidx` |
| [`fctidzx`](fctidzx.md) | `X` | Floating Convert to Integer Doubleword with Round Toward Zero | `fctidzx` |
| [`fctiwx`](fctiwx.md) | `X` | Floating Convert to Integer Word | `fctiwx` |
| [`fctiwzx`](fctiwzx.md) | `X` | Floating Convert to Integer Word with Round Toward Zero | `fctiwzx` |
| [`fdivsx`](fdivsx.md) | `A` | Floating Divide Single | `fdivsx` |
| [`fdivx`](fdivx.md) | `A` | Floating Divide | `fdivx` |
| [`fmaddsx`](fmaddsx.md) | `A` | Floating Multiply-Add Single | `fmaddsx` |
| [`fmaddx`](fmaddx.md) | `A` | Floating Multiply-Add | `fmaddx` |
| [`fmrx`](fmrx.md) | `X` | Floating Move Register | `fmrx` |
| [`fmsubsx`](fmsubsx.md) | `A` | Floating Multiply-Subtract Single | `fmsubsx` |
| [`fmsubx`](fmsubx.md) | `A` | Floating Multiply-Subtract | `fmsubx` |
| [`fmulsx`](fmulsx.md) | `A` | Floating Multiply Single | `fmulsx` |
| [`fmulx`](fmulx.md) | `A` | Floating Multiply | `fmulx` |
| [`fnabsx`](fnabsx.md) | `X` | Floating Negative Absolute Value | `fnabsx` |
| [`fnegx`](fnegx.md) | `X` | Floating Negate | `fnegx` |
| [`fnmaddsx`](fnmaddsx.md) | `A` | Floating Negative Multiply-Add Single | `fnmaddsx` |
| [`fnmaddx`](fnmaddx.md) | `A` | Floating Negative Multiply-Add | `fnmaddx` |
| [`fnmsubsx`](fnmsubsx.md) | `A` | Floating Negative Multiply-Subtract Single | `fnmsubsx` |
| [`fnmsubx`](fnmsubx.md) | `A` | Floating Negative Multiply-Subtract | `fnmsubx` |
| [`fresx`](fresx.md) | `A` | Floating Reciprocal Estimate Single | `fresx` |
| [`frspx`](frspx.md) | `X` | Floating Round to Single | `frspx` |
| [`frsqrtex`](frsqrtex.md) | `A` | Floating Reciprocal Square Root Estimate | `frsqrtex` |
| [`fselx`](fselx.md) | `A` | Floating Select | `fselx` |
| [`fsqrtsx`](fsqrtsx.md) | `A` | Floating Square Root Single | `fsqrtsx` |
| [`fsqrtx`](fsqrtx.md) | `A` | Floating Square Root | `fsqrtx` |
| [`fsubsx`](fsubsx.md) | `A` | Floating Subtract Single | `fsubsx` |
| [`fsubx`](fsubx.md) | `A` | Floating Subtract | `fsubx` |
<!-- GENERATED: END -->

View File

@@ -0,0 +1,68 @@
# Memory
Loads/stores for byte, half, word, doubleword, float, multiple and string; cache management (dcbt, dcbf, dcbz); reservation pair lwarx/stwcx.
**56 families** · **112 XML entries**.
<!-- GENERATED: BEGIN -->
| Family | Form | Description | Members |
| --- | --- | --- | --- |
| [`dcbf`](dcbf.md) | `X` | Data Cache Block Flush | `dcbf` |
| [`dcbi`](dcbi.md) | `X` | Data Cache Block Invalidate | `dcbi` |
| [`dcbst`](dcbst.md) | `X` | Data Cache Block Store | `dcbst` |
| [`dcbt`](dcbt.md) | `X` | Data Cache Block Touch | `dcbt` |
| [`dcbtst`](dcbtst.md) | `X` | Data Cache Block Touch for Store | `dcbtst` |
| [`dcbz`](dcbz.md) | `DCBZ` | Data Cache Block Clear to Zero | `dcbz`, `dcbz128` |
| [`icbi`](icbi.md) | `X` | Instruction Cache Block Invalidate | `icbi` |
| [`lbz`](lbz.md) | `D` | Load Byte and Zero | `lbz`, `lbzu`, `lbzux`, `lbzx` |
| [`ld`](ld.md) | `DS` | Load Doubleword | `ld`, `ldu`, `ldux`, `ldx` |
| [`ldarx`](ldarx.md) | `X` | Load Doubleword and Reserve Indexed | `ldarx` |
| [`ldbrx`](ldbrx.md) | `X` | Load Doubleword Byte-Reverse Indexed | `ldbrx` |
| [`lfd`](lfd.md) | `D` | Load Floating-Point Double | `lfd`, `lfdu`, `lfdux`, `lfdx` |
| [`lfs`](lfs.md) | `D` | Load Floating-Point Single | `lfs`, `lfsu`, `lfsux`, `lfsx` |
| [`lha`](lha.md) | `D` | Load Half Word Algebraic | `lha`, `lhau`, `lhaux`, `lhax` |
| [`lhbrx`](lhbrx.md) | `X` | Load Half Word Byte-Reverse Indexed | `lhbrx` |
| [`lhz`](lhz.md) | `D` | Load Half Word and Zero | `lhz`, `lhzu`, `lhzux`, `lhzx` |
| [`lmw`](lmw.md) | `D` | Load Multiple Word | `lmw` |
| [`lswi`](lswi.md) | `X` | Load String Word Immediate | `lswi` |
| [`lswx`](lswx.md) | `X` | Load String Word Indexed | `lswx` |
| [`lvebx`](lvebx.md) | `X` | Load Vector Element Byte Indexed | `lvebx` |
| [`lvehx`](lvehx.md) | `X` | Load Vector Element Half Word Indexed | `lvehx` |
| [`lvewx`](lvewx.md) | `X` | Load Vector Element Word Indexed | `lvewx`, `lvewx128` |
| [`lvlx`](lvlx.md) | `X` | Load Vector Left Indexed | `lvlx`, `lvlx128` |
| [`lvlxl`](lvlxl.md) | `X` | Load Vector Left Indexed LRU | `lvlxl`, `lvlxl128` |
| [`lvrx`](lvrx.md) | `X` | Load Vector Right Indexed | `lvrx`, `lvrx128` |
| [`lvrxl`](lvrxl.md) | `X` | Load Vector Right Indexed LRU | `lvrxl`, `lvrxl128` |
| [`lvx`](lvx.md) | `X` | Load Vector Indexed | `lvx`, `lvx128` |
| [`lvxl`](lvxl.md) | `X` | Load Vector Indexed LRU | `lvxl`, `lvxl128` |
| [`lwa`](lwa.md) | `DS` | Load Word Algebraic | `lwa`, `lwaux`, `lwax` |
| [`lwarx`](lwarx.md) | `X` | Load Word and Reserve Indexed | `lwarx` |
| [`lwbrx`](lwbrx.md) | `X` | Load Word Byte-Reverse Indexed | `lwbrx` |
| [`lwz`](lwz.md) | `D` | Load Word and Zero | `lwz`, `lwzu`, `lwzux`, `lwzx` |
| [`stb`](stb.md) | `D` | Store Byte | `stb`, `stbu`, `stbux`, `stbx` |
| [`std`](std.md) | `DS` | Store Doubleword | `std`, `stdu`, `stdux`, `stdx` |
| [`stdbrx`](stdbrx.md) | `X` | Store Doubleword Byte-Reverse Indexed | `stdbrx` |
| [`stdcx`](stdcx.md) | `X` | Store Doubleword Conditional Indexed | `stdcx` |
| [`stfd`](stfd.md) | `D` | Store Floating-Point Double | `stfd`, `stfdu`, `stfdux`, `stfdx` |
| [`stfiwx`](stfiwx.md) | `X` | Store Floating-Point as Integer Word Indexed | `stfiwx` |
| [`stfs`](stfs.md) | `D` | Store Floating-Point Single | `stfs`, `stfsu`, `stfsux`, `stfsx` |
| [`sth`](sth.md) | `D` | Store Half Word | `sth`, `sthu`, `sthux`, `sthx` |
| [`sthbrx`](sthbrx.md) | `X` | Store Half Word Byte-Reverse Indexed | `sthbrx` |
| [`stmw`](stmw.md) | `D` | Store Multiple Word | `stmw` |
| [`stswi`](stswi.md) | `X` | Store String Word Immediate | `stswi` |
| [`stswx`](stswx.md) | `X` | Store String Word Indexed | `stswx` |
| [`stvebx`](stvebx.md) | `X` | Store Vector Element Byte Indexed | `stvebx` |
| [`stvehx`](stvehx.md) | `X` | Store Vector Element Half Word Indexed | `stvehx` |
| [`stvewx`](stvewx.md) | `X` | Store Vector Element Word Indexed | `stvewx`, `stvewx128` |
| [`stvlx`](stvlx.md) | `X` | Store Vector Left Indexed | `stvlx`, `stvlx128` |
| [`stvlxl`](stvlxl.md) | `X` | Store Vector Left Indexed LRU | `stvlxl`, `stvlxl128` |
| [`stvrx`](stvrx.md) | `X` | Store Vector Right Indexed | `stvrx`, `stvrx128` |
| [`stvrxl`](stvrxl.md) | `X` | Store Vector Right Indexed LRU | `stvrxl`, `stvrxl128` |
| [`stvx`](stvx.md) | `X` | Store Vector Indexed | `stvx`, `stvx128` |
| [`stvxl`](stvxl.md) | `X` | Store Vector Indexed LRU | `stvxl`, `stvxl128` |
| [`stw`](stw.md) | `D` | Store Word | `stw`, `stwu`, `stwux`, `stwx` |
| [`stwbrx`](stwbrx.md) | `X` | Store Word Byte-Reverse Indexed | `stwbrx` |
| [`stwcx`](stwcx.md) | `X` | Store Word Conditional Indexed | `stwcx` |
<!-- GENERATED: END -->

View File

@@ -0,0 +1,156 @@
# VMX (Altivec)
128-bit SIMD over 32 registers V0V31. Integer/float arithmetic, logical, compare, permute/merge, pack/unpack, saturation helpers.
**144 families** · **193 XML entries**.
<!-- GENERATED: BEGIN -->
| Family | Form | Description | Members |
| --- | --- | --- | --- |
| [`lvsl`](lvsl.md) | `X` | Load Vector for Shift Left Indexed | `lvsl`, `lvsl128` |
| [`lvsr`](lvsr.md) | `X` | Load Vector for Shift Right Indexed | `lvsr`, `lvsr128` |
| [`vaddcuw`](vaddcuw.md) | `VX` | Vector Add Carryout Unsigned Word | `vaddcuw` |
| [`vaddfp`](vaddfp.md) | `VX` | Vector Add Floating Point | `vaddfp`, `vaddfp128` |
| [`vaddsbs`](vaddsbs.md) | `VX` | Vector Add Signed Byte Saturate | `vaddsbs` |
| [`vaddshs`](vaddshs.md) | `VX` | Vector Add Signed Half Word Saturate | `vaddshs` |
| [`vaddsws`](vaddsws.md) | `VX` | Vector Add Signed Word Saturate | `vaddsws` |
| [`vaddubm`](vaddubm.md) | `VX` | Vector Add Unsigned Byte Modulo | `vaddubm` |
| [`vaddubs`](vaddubs.md) | `VX` | Vector Add Unsigned Byte Saturate | `vaddubs` |
| [`vadduhm`](vadduhm.md) | `VX` | Vector Add Unsigned Half Word Modulo | `vadduhm` |
| [`vadduhs`](vadduhs.md) | `VX` | Vector Add Unsigned Half Word Saturate | `vadduhs` |
| [`vadduwm`](vadduwm.md) | `VX` | Vector Add Unsigned Word Modulo | `vadduwm` |
| [`vadduws`](vadduws.md) | `VX` | Vector Add Unsigned Word Saturate | `vadduws` |
| [`vand`](vand.md) | `VX` | Vector Logical AND | `vand`, `vand128` |
| [`vandc`](vandc.md) | `VX` | Vector Logical AND with Complement | `vandc`, `vandc128` |
| [`vavgsb`](vavgsb.md) | `VX` | Vector Average Signed Byte | `vavgsb` |
| [`vavgsh`](vavgsh.md) | `VX` | Vector Average Signed Half Word | `vavgsh` |
| [`vavgsw`](vavgsw.md) | `VX` | Vector Average Signed Word | `vavgsw` |
| [`vavgub`](vavgub.md) | `VX` | Vector Average Unsigned Byte | `vavgub` |
| [`vavguh`](vavguh.md) | `VX` | Vector Average Unsigned Half Word | `vavguh` |
| [`vavguw`](vavguw.md) | `VX` | Vector Average Unsigned Word | `vavguw` |
| [`vcfsx`](vcfsx.md) | `VX` | Vector Convert from Signed Fixed-Point Word | `vcfsx` |
| [`vcfux`](vcfux.md) | `VX` | Vector Convert from Unsigned Fixed-Point Word | `vcfux` |
| [`vcmpbfp`](vcmpbfp.md) | `VC` | Vector Compare Bounds Floating Point | `vcmpbfp`, `vcmpbfp128` |
| [`vcmpeqfp`](vcmpeqfp.md) | `VC` | Vector Compare Equal-to Floating Point | `vcmpeqfp`, `vcmpeqfp128` |
| [`vcmpequb`](vcmpequb.md) | `VC` | Vector Compare Equal-to Unsigned Byte | `vcmpequb` |
| [`vcmpequh`](vcmpequh.md) | `VC` | Vector Compare Equal-to Unsigned Half Word | `vcmpequh` |
| [`vcmpequw`](vcmpequw.md) | `VC` | Vector Compare Equal-to Unsigned Word | `vcmpequw`, `vcmpequw128` |
| [`vcmpgefp`](vcmpgefp.md) | `VC` | Vector Compare Greater-Than-or-Equal-to Floating Point | `vcmpgefp`, `vcmpgefp128` |
| [`vcmpgtfp`](vcmpgtfp.md) | `VC` | Vector Compare Greater-Than Floating Point | `vcmpgtfp`, `vcmpgtfp128` |
| [`vcmpgtsb`](vcmpgtsb.md) | `VC` | Vector Compare Greater-Than Signed Byte | `vcmpgtsb` |
| [`vcmpgtsh`](vcmpgtsh.md) | `VC` | Vector Compare Greater-Than Signed Half Word | `vcmpgtsh` |
| [`vcmpgtsw`](vcmpgtsw.md) | `VC` | Vector Compare Greater-Than Signed Word | `vcmpgtsw` |
| [`vcmpgtub`](vcmpgtub.md) | `VC` | Vector Compare Greater-Than Unsigned Byte | `vcmpgtub` |
| [`vcmpgtuh`](vcmpgtuh.md) | `VC` | Vector Compare Greater-Than Unsigned Half Word | `vcmpgtuh` |
| [`vcmpgtuw`](vcmpgtuw.md) | `VC` | Vector Compare Greater-Than Unsigned Word | `vcmpgtuw` |
| [`vctsxs`](vctsxs.md) | `VX` | Vector Convert to Signed Fixed-Point Word Saturate | `vctsxs` |
| [`vctuxs`](vctuxs.md) | `VX` | Vector Convert to Unsigned Fixed-Point Word Saturate | `vctuxs` |
| [`vexptefp`](vexptefp.md) | `VX` | Vector 2 Raised to the Exponent Estimate Floating Point | `vexptefp`, `vexptefp128` |
| [`vlogefp`](vlogefp.md) | `VX` | Vector Log2 Estimate Floating Point | `vlogefp`, `vlogefp128` |
| [`vmaddfp`](vmaddfp.md) | `VA` | Vector Multiply-Add Floating Point | `vmaddfp`, `vmaddfp128` |
| [`vmaxfp`](vmaxfp.md) | `VX` | Vector Maximum Floating Point | `vmaxfp`, `vmaxfp128` |
| [`vmaxsb`](vmaxsb.md) | `VX` | Vector Maximum Signed Byte | `vmaxsb` |
| [`vmaxsh`](vmaxsh.md) | `VX` | Vector Maximum Signed Half Word | `vmaxsh` |
| [`vmaxsw`](vmaxsw.md) | `VX` | Vector Maximum Signed Word | `vmaxsw` |
| [`vmaxub`](vmaxub.md) | `VX` | Vector Maximum Unsigned Byte | `vmaxub` |
| [`vmaxuh`](vmaxuh.md) | `VX` | Vector Maximum Unsigned Half Word | `vmaxuh` |
| [`vmaxuw`](vmaxuw.md) | `VX` | Vector Maximum Unsigned Word | `vmaxuw` |
| [`vmhaddshs`](vmhaddshs.md) | `VA` | Vector Multiply-High and Add Signed Signed Half Word Saturate | `vmhaddshs` |
| [`vmhraddshs`](vmhraddshs.md) | `VA` | Vector Multiply-High Round and Add Signed Signed Half Word Saturate | `vmhraddshs` |
| [`vminfp`](vminfp.md) | `VX` | Vector Minimum Floating Point | `vminfp`, `vminfp128` |
| [`vminsb`](vminsb.md) | `VX` | Vector Minimum Signed Byte | `vminsb` |
| [`vminsh`](vminsh.md) | `VX` | Vector Minimum Signed Half Word | `vminsh` |
| [`vminsw`](vminsw.md) | `VX` | Vector Minimum Signed Word | `vminsw` |
| [`vminub`](vminub.md) | `VX` | Vector Minimum Unsigned Byte | `vminub` |
| [`vminuh`](vminuh.md) | `VX` | Vector Minimum Unsigned Half Word | `vminuh` |
| [`vminuw`](vminuw.md) | `VX` | Vector Minimum Unsigned Word | `vminuw` |
| [`vmladduhm`](vmladduhm.md) | `VA` | Vector Multiply-Low and Add Unsigned Half Word Modulo | `vmladduhm` |
| [`vmrghb`](vmrghb.md) | `VX` | Vector Merge High Byte | `vmrghb` |
| [`vmrghh`](vmrghh.md) | `VX` | Vector Merge High Half Word | `vmrghh` |
| [`vmrghw`](vmrghw.md) | `VX` | Vector Merge High Word | `vmrghw`, `vmrghw128` |
| [`vmrglb`](vmrglb.md) | `VX` | Vector Merge Low Byte | `vmrglb` |
| [`vmrglh`](vmrglh.md) | `VX` | Vector Merge Low Half Word | `vmrglh` |
| [`vmrglw`](vmrglw.md) | `VX` | Vector Merge Low Word | `vmrglw`, `vmrglw128` |
| [`vmsummbm`](vmsummbm.md) | `VA` | Vector Multiply-Sum Mixed-Sign Byte Modulo | `vmsummbm` |
| [`vmsumshm`](vmsumshm.md) | `VA` | Vector Multiply-Sum Signed Half Word Modulo | `vmsumshm` |
| [`vmsumshs`](vmsumshs.md) | `VA` | Vector Multiply-Sum Signed Half Word Saturate | `vmsumshs` |
| [`vmsumubm`](vmsumubm.md) | `VA` | Vector Multiply-Sum Unsigned Byte Modulo | `vmsumubm` |
| [`vmsumuhm`](vmsumuhm.md) | `VA` | Vector Multiply-Sum Unsigned Half Word Modulo | `vmsumuhm` |
| [`vmsumuhs`](vmsumuhs.md) | `VA` | Vector Multiply-Sum Unsigned Half Word Saturate | `vmsumuhs` |
| [`vmulesb`](vmulesb.md) | `VX` | Vector Multiply Even Signed Byte | `vmulesb` |
| [`vmulesh`](vmulesh.md) | `VX` | Vector Multiply Even Signed Half Word | `vmulesh` |
| [`vmuleub`](vmuleub.md) | `VX` | Vector Multiply Even Unsigned Byte | `vmuleub` |
| [`vmuleuh`](vmuleuh.md) | `VX` | Vector Multiply Even Unsigned Half Word | `vmuleuh` |
| [`vmulosb`](vmulosb.md) | `VX` | Vector Multiply Odd Signed Byte | `vmulosb` |
| [`vmulosh`](vmulosh.md) | `VX` | Vector Multiply Odd Signed Half Word | `vmulosh` |
| [`vmuloub`](vmuloub.md) | `VX` | Vector Multiply Odd Unsigned Byte | `vmuloub` |
| [`vmulouh`](vmulouh.md) | `VX` | Vector Multiply Odd Unsigned Half Word | `vmulouh` |
| [`vnmsubfp`](vnmsubfp.md) | `VA` | Vector Negative Multiply-Subtract Floating Point | `vnmsubfp`, `vnmsubfp128` |
| [`vnor`](vnor.md) | `VX` | Vector Logical NOR | `vnor`, `vnor128` |
| [`vor`](vor.md) | `VX` | Vector Logical OR | `vor`, `vor128` |
| [`vperm`](vperm.md) | `VA` | Vector Permute | `vperm`, `vperm128` |
| [`vpkpx`](vpkpx.md) | `VX` | Vector Pack Pixel | `vpkpx` |
| [`vpkshss`](vpkshss.md) | `VX` | Vector Pack Signed Half Word Signed Saturate | `vpkshss`, `vpkshss128` |
| [`vpkshus`](vpkshus.md) | `VX` | Vector Pack Signed Half Word Unsigned Saturate | `vpkshus`, `vpkshus128` |
| [`vpkswss`](vpkswss.md) | `VX` | Vector Pack Signed Word Signed Saturate | `vpkswss`, `vpkswss128` |
| [`vpkswus`](vpkswus.md) | `VX` | Vector Pack Signed Word Unsigned Saturate | `vpkswus`, `vpkswus128` |
| [`vpkuhum`](vpkuhum.md) | `VX` | Vector Pack Unsigned Half Word Unsigned Modulo | `vpkuhum`, `vpkuhum128` |
| [`vpkuhus`](vpkuhus.md) | `VX` | Vector Pack Unsigned Half Word Unsigned Saturate | `vpkuhus`, `vpkuhus128` |
| [`vpkuwum`](vpkuwum.md) | `VX` | Vector Pack Unsigned Word Unsigned Modulo | `vpkuwum`, `vpkuwum128` |
| [`vpkuwus`](vpkuwus.md) | `VX` | Vector Pack Unsigned Word Unsigned Saturate | `vpkuwus`, `vpkuwus128` |
| [`vrefp`](vrefp.md) | `VX` | Vector Reciprocal Estimate Floating Point | `vrefp`, `vrefp128` |
| [`vrfim`](vrfim.md) | `VX` | Vector Round to Floating-Point Integer toward -Infinity | `vrfim`, `vrfim128` |
| [`vrfin`](vrfin.md) | `VX` | Vector Round to Floating-Point Integer Nearest | `vrfin`, `vrfin128` |
| [`vrfip`](vrfip.md) | `VX` | Vector Round to Floating-Point Integer toward +Infinity | `vrfip`, `vrfip128` |
| [`vrfiz`](vrfiz.md) | `VX` | Vector Round to Floating-Point Integer toward Zero | `vrfiz`, `vrfiz128` |
| [`vrlb`](vrlb.md) | `VX` | Vector Rotate Left Integer Byte | `vrlb` |
| [`vrlh`](vrlh.md) | `VX` | Vector Rotate Left Integer Half Word | `vrlh` |
| [`vrlw`](vrlw.md) | `VX` | Vector Rotate Left Integer Word | `vrlw`, `vrlw128` |
| [`vrsqrtefp`](vrsqrtefp.md) | `VX` | Vector Reciprocal Square Root Estimate Floating Point | `vrsqrtefp`, `vrsqrtefp128` |
| [`vsel`](vsel.md) | `VA` | Vector Conditional Select | `vsel`, `vsel128` |
| [`vsl`](vsl.md) | `VX` | Vector Shift Left | `vsl` |
| [`vslb`](vslb.md) | `VX` | Vector Shift Left Integer Byte | `vslb` |
| [`vsldoi`](vsldoi.md) | `VA` | Vector Shift Left Double by Octet Immediate | `vsldoi`, `vsldoi128` |
| [`vslh`](vslh.md) | `VX` | Vector Shift Left Integer Half Word | `vslh` |
| [`vslo`](vslo.md) | `VX` | Vector Shift Left by Octet | `vslo`, `vslo128` |
| [`vslw`](vslw.md) | `VX` | Vector Shift Left Integer Word | `vslw`, `vslw128` |
| [`vspltb`](vspltb.md) | `VX` | Vector Splat Byte | `vspltb` |
| [`vsplth`](vsplth.md) | `VX` | Vector Splat Half Word | `vsplth` |
| [`vspltisb`](vspltisb.md) | `VX` | Vector Splat Immediate Signed Byte | `vspltisb` |
| [`vspltish`](vspltish.md) | `VX` | Vector Splat Immediate Signed Half Word | `vspltish` |
| [`vspltisw`](vspltisw.md) | `VX` | Vector Splat Immediate Signed Word | `vspltisw`, `vspltisw128` |
| [`vspltw`](vspltw.md) | `VX` | Vector Splat Word | `vspltw`, `vspltw128` |
| [`vsr`](vsr.md) | `VX` | Vector Shift Right | `vsr` |
| [`vsrab`](vsrab.md) | `VX` | Vector Shift Right Algebraic Byte | `vsrab` |
| [`vsrah`](vsrah.md) | `VX` | Vector Shift Right Algebraic Half Word | `vsrah` |
| [`vsraw`](vsraw.md) | `VX` | Vector Shift Right Algebraic Word | `vsraw`, `vsraw128` |
| [`vsrb`](vsrb.md) | `VX` | Vector Shift Right Byte | `vsrb` |
| [`vsrh`](vsrh.md) | `VX` | Vector Shift Right Half Word | `vsrh` |
| [`vsro`](vsro.md) | `VX` | Vector Shift Right Octet | `vsro`, `vsro128` |
| [`vsrw`](vsrw.md) | `VX` | Vector Shift Right Word | `vsrw`, `vsrw128` |
| [`vsubcuw`](vsubcuw.md) | `VX` | Vector Subtract Carryout Unsigned Word | `vsubcuw` |
| [`vsubfp`](vsubfp.md) | `VX` | Vector Subtract Floating Point | `vsubfp`, `vsubfp128` |
| [`vsubsbs`](vsubsbs.md) | `VX` | Vector Subtract Signed Byte Saturate | `vsubsbs` |
| [`vsubshs`](vsubshs.md) | `VX` | Vector Subtract Signed Half Word Saturate | `vsubshs` |
| [`vsubsws`](vsubsws.md) | `VX` | Vector Subtract Signed Word Saturate | `vsubsws` |
| [`vsububm`](vsububm.md) | `VX` | Vector Subtract Unsigned Byte Modulo | `vsububm` |
| [`vsububs`](vsububs.md) | `VX` | Vector Subtract Unsigned Byte Saturate | `vsububs` |
| [`vsubuhm`](vsubuhm.md) | `VX` | Vector Subtract Unsigned Half Word Modulo | `vsubuhm` |
| [`vsubuhs`](vsubuhs.md) | `VX` | Vector Subtract Unsigned Half Word Saturate | `vsubuhs` |
| [`vsubuwm`](vsubuwm.md) | `VX` | Vector Subtract Unsigned Word Modulo | `vsubuwm` |
| [`vsubuws`](vsubuws.md) | `VX` | Vector Subtract Unsigned Word Saturate | `vsubuws` |
| [`vsum2sws`](vsum2sws.md) | `VX` | Vector Sum Across Partial (1/2) Signed Word Saturate | `vsum2sws` |
| [`vsum4sbs`](vsum4sbs.md) | `VX` | Vector Sum Across Partial (1/4) Signed Byte Saturate | `vsum4sbs` |
| [`vsum4shs`](vsum4shs.md) | `VX` | Vector Sum Across Partial (1/4) Signed Half Word Saturate | `vsum4shs` |
| [`vsum4ubs`](vsum4ubs.md) | `VX` | Vector Sum Across Partial (1/4) Unsigned Byte Saturate | `vsum4ubs` |
| [`vsumsws`](vsumsws.md) | `VX` | Vector Sum Across Signed Word Saturate | `vsumsws` |
| [`vupkhpx`](vupkhpx.md) | `VX` | Vector Unpack High Pixel | `vupkhpx` |
| [`vupkhsb`](vupkhsb.md) | `VX` | Vector Unpack High Signed Byte | `vupkhsb`, `vupkhsb128` |
| [`vupkhsh`](vupkhsh.md) | `VX` | Vector Unpack High Signed Half Word | `vupkhsh` |
| [`vupklpx`](vupklpx.md) | `VX` | Vector Unpack Low Pixel | `vupklpx` |
| [`vupklsb`](vupklsb.md) | `VX` | Vector Unpack Low Signed Byte | `vupklsb`, `vupklsb128` |
| [`vupklsh`](vupklsh.md) | `VX` | Vector Unpack Low Signed Half Word | `vupklsh` |
| [`vxor`](vxor.md) | `VX` | Vector Logical XOR | `vxor`, `vxor128` |
<!-- GENERATED: END -->

View File

@@ -0,0 +1,24 @@
# VMX128
Xbox-360-specific Altivec extension that widens the vector register file to 128 registers (V0V127). Register IDs are encoded with bit-fusion across non-contiguous fields.
**12 families** · **12 XML entries**.
<!-- GENERATED: BEGIN -->
| Family | Form | Description | Members |
| --- | --- | --- | --- |
| [`vcfpsxws128`](vcfpsxws128.md) | `VX128_3` | Vector128 Convert From Floating-Point to Signed Fixed-Point Word Saturate | `vcfpsxws128` |
| [`vcfpuxws128`](vcfpuxws128.md) | `VX128_3` | Vector128 Convert From Floating-Point to Unsigned Fixed-Point Word Saturate | `vcfpuxws128` |
| [`vcsxwfp128`](vcsxwfp128.md) | `VX128_3` | Vector128 Convert From Signed Fixed-Point Word to Floating-Point | `vcsxwfp128` |
| [`vcuxwfp128`](vcuxwfp128.md) | `VX128_3` | Vector128 Convert From Unsigned Fixed-Point Word to Floating-Point | `vcuxwfp128` |
| [`vmaddcfp128`](vmaddcfp128.md) | `VX128` | Vector128 Multiply Add Floating Point | `vmaddcfp128` |
| [`vmsum3fp128`](vmsum3fp128.md) | `VX128` | Vector128 Multiply Sum 3-way Floating Point | `vmsum3fp128` |
| [`vmsum4fp128`](vmsum4fp128.md) | `VX128` | Vector128 Multiply Sum 4-way Floating-Point | `vmsum4fp128` |
| [`vmulfp128`](vmulfp128.md) | `VX128` | Vector128 Multiply Floating-Point | `vmulfp128` |
| [`vpermwi128`](vpermwi128.md) | `VX128_P` | Vector128 Permutate Word Immediate | `vpermwi128` |
| [`vpkd3d128`](vpkd3d128.md) | `VX128_4` | Vector128 Pack D3Dtype, Rotate Left Immediate and Mask Insert | `vpkd3d128` |
| [`vrlimi128`](vrlimi128.md) | `VX128_4` | Vector128 Rotate Left Immediate and Mask Insert | `vrlimi128` |
| [`vupkd3d128`](vupkd3d128.md) | `VX128_3` | Vector128 Unpack D3Dtype | `vupkd3d128` |
<!-- GENERATED: END -->

View File

@@ -0,0 +1,127 @@
# `crand` — Condition Register AND
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000202`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `crand` | `crand` | — | Condition Register AND |
## Syntax
```asm
crand [CRBD], [CRBA], [CRBB]
```
## Encoding
### `crand` — form `XL`
- **Opcode word:** `0x4c000202`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `257`
- **Synchronising:** no
| 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 |
| --- | --- | --- |
| `CRBA` | crand: read | CR source bit A (031). |
| `CRBB` | crand: read | CR source bit B (031). |
| `CRBD` | crand: write | CR destination bit (031). |
## Register Effects
### `crand`
- **Reads (always):** `CRBA`, `CRBB`
- **Reads (conditional):** _none_
- **Writes (always):** `CRBD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`crand`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crand"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:352`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L352)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:717`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L717)
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Bit-level granularity.** All eight CR-logical instructions operate on **single CR bits**, not whole 4-bit fields. `CRBD`, `CRBA`, `CRBB` are 5-bit absolute indices into the 32-bit CR register: `BI = 4·field + bit-within-field`, where bit 0 = LT, 1 = GT, 2 = EQ, 3 = SO.
- **Operation.** `CR[CRBD] ← CR[CRBA] AND CR[CRBB]`. All other CR bits are preserved.
- **Same-source / same-destination quirks.** Identical sources and destinations are legal: `crand 6, 6, 6` is a NOP-style "force CR bit 6 to itself"; `crand bt, bt, bt` reads-then-writes the same bit (no observable change). Compilers exploit `crxor BT,BT,BT` ("clear bit") and `creqv BT,BT,BT` ("set bit") for similar tricks — see those pages.
- **Combining branch conditions.** The classic use: synthesise complex branch conditions from multiple compare results. Example: `cmpw cr0, r3, r4; cmpw cr1, r5, r6; crand 4*cr0+2, 4*cr0+2, 4*cr1+2; beq cr0, label` branches if `r3==r4 AND r5==r6` using a single conditional branch.
- **No `Rc` / `OE`.** XL-form CR-logical ops never set CR0 or XER; they only update the named CR bit.
- **Not synchronising.** Pure data-flow on CR; freely reorderable.
- **xenia status.** xenia-rs decodes `crand` (decoder slot 540) but the interpreter snapshot is not embedded on this page — implementation lives in [`crates/xenia-cpu/src/interpreter.rs`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs). xenia-canary's `InstrEmit_crand` emits the equivalent host AND of the two CR bits.
## Related Instructions
- [`crandc`](crandc.md) — AND with complement: `CR[BT] ← CR[BA] AND ¬CR[BB]`.
- [`cror`](cror.md), [`crorc`](crorc.md) — OR / OR-with-complement.
- [`crnand`](crnand.md), [`crnor`](crnor.md) — negated AND / OR.
- [`crxor`](crxor.md), [`creqv`](creqv.md) — XOR and equivalence (XNOR).
- [`mcrf`](mcrf.md) — copy a whole 4-bit CR field.
- [`bcx`](../branch/bcx.md) consumers — the typical reason to compute composite CR bits.
### Simplified Mnemonics
- `crmove BT, BA``cror BT, BA, BA` (use `cror`, not `crand`).
- `crset BT``creqv BT, BT, BT` (set to 1).
- `crclr BT``crxor BT, BT, BT` (clear to 0).
`crand` itself has no dedicated simplified mnemonic.
## IBM Reference
- [AIX 7.3 — `crand` (Condition Register AND)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-crand-condition-register-instruction)
- [AIX 7.3 — Condition register simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-condition-register-logical-simplified)

View File

@@ -0,0 +1,119 @@
# `crandc` — Condition Register AND with Complement
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000102`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `crandc` | `crandc` | — | Condition Register AND with Complement |
## Syntax
```asm
crandc [CRBD], [CRBA], [CRBB]
```
## Encoding
### `crandc` — form `XL`
- **Opcode word:** `0x4c000102`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `129`
- **Synchronising:** no
| 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 |
| --- | --- | --- |
| `CRBA` | crandc: read | CR source bit A (031). |
| `CRBB` | crandc: read | CR source bit B (031). |
| `CRBD` | crandc: write | CR destination bit (031). |
## Register Effects
### `crandc`
- **Reads (always):** `CRBA`, `CRBB`
- **Reads (conditional):** _none_
- **Writes (always):** `CRBD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`crandc`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crandc"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:361`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L361)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:713`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L713)
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operation.** `CR[CRBD] ← CR[CRBA] AND ¬CR[CRBB]` — a one-instruction "A and not B" that would otherwise need a complement-then-AND sequence. All other CR bits are preserved.
- **Bit-level operands.** `CRBD`, `CRBA`, `CRBB` are 5-bit indices into the 32 CR bits (0=CR0.LT, 1=CR0.GT, 2=CR0.EQ, 3=CR0.SO, 4=CR1.LT, …, 31=CR7.SO). They need not lie in the same CR field.
- **Identity / corner cases.** `crandc BT, BA, BA` always yields 0 (a clear-bit idiom, equivalent to but slower than `crxor BT, BT, BT`). `crandc BT, BA, BB` with `BB` always 0 reduces to `crmove BT, BA`.
- **Use case.** Synthesises "branch if A *and not* B" predicates without a dedicated `cmp` of `B`. Example: branch only if `cr0.EQ` *and not* `cr1.SO``crandc 2, 2, 7` then `beq` on `cr0`.
- **No `Rc` / `OE`.** Pure CR-bit dataflow; doesn't update CR0 or XER.
- **Not synchronising.** Reorderable.
- **xenia status.** Interpreter handles via the generic CR-logical helper. xenia-canary's `InstrEmit_crandc` emits a host AND of `A` and bitwise-NOT of `B`.
## Related Instructions
- [`crand`](crand.md), [`cror`](cror.md), [`crorc`](crorc.md) — closest siblings.
- [`crnand`](crnand.md), [`crnor`](crnor.md), [`crxor`](crxor.md), [`creqv`](creqv.md) — full set of CR Boolean ops.
- [`mcrf`](mcrf.md) — copy entire CR field; complementary "broad" CR move.
- [`bcx`](../branch/bcx.md) — typical consumer of synthesised CR bits.
`crandc` has no dedicated simplified mnemonic. See [`crand`](crand.md) for the standard `crmove` / `crset` / `crclr` family.
## IBM Reference
- [AIX 7.3 — `crandc` (Condition Register AND with Complement)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-crandc-condition-register-complement-instruction)
- [AIX 7.3 — Condition register simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-condition-register-logical-simplified)

View File

@@ -0,0 +1,124 @@
# `creqv` — Condition Register Equivalent
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000242`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `creqv` | `creqv` | — | Condition Register Equivalent |
## Syntax
```asm
creqv [CRBD], [CRBA], [CRBB]
```
## Encoding
### `creqv` — form `XL`
- **Opcode word:** `0x4c000242`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `289`
- **Synchronising:** no
| 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 |
| --- | --- | --- |
| `CRBA` | creqv: read | CR source bit A (031). |
| `CRBB` | creqv: read | CR source bit B (031). |
| `CRBD` | creqv: write | CR destination bit (031). |
## Register Effects
### `creqv`
- **Reads (always):** `CRBA`, `CRBB`
- **Reads (conditional):** _none_
- **Writes (always):** `CRBD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`creqv`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="creqv"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:370`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L370)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:718`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L718)
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operation.** `CR[CRBD] ← ¬(CR[CRBA] XOR CR[CRBB])` — i.e. logical equivalence (XNOR). Result is 1 iff `CRBA` and `CRBB` agree.
- **`crset BT` idiom.** With identical operands, `creqv BT, BT, BT` always yields 1 (any bit XNOR'd with itself is 1). This is the canonical PowerPC **set-to-1** for a single CR bit; assemblers recognise the simplified mnemonic `crset BT`.
- **Bit-level operands.** Like all CR-logical ops, the three operands are 5-bit absolute CR-bit indices (0..31). Mixing CR fields is fine.
- **Use case.** Branch on "A == B" of two prior compare results. Example: `crxor` of CR0.SO and CR1.SO gives "differ"; `creqv` gives "agree".
- **No `Rc` / `OE`.** Doesn't touch CR0, XER, or any other state beyond the named bit.
- **Not synchronising.** Reorderable.
- **xenia status.** Interpreter dispatches through the generic CR-logical helper; canary emits the host XNOR equivalent. The `crset` simplified form is the most common occurrence in real Xbox 360 code.
## Related Instructions
- [`crand`](crand.md), [`crandc`](crandc.md) — AND family.
- [`cror`](cror.md), [`crorc`](crorc.md), [`crnor`](crnor.md), [`crnand`](crnand.md) — OR family.
- [`crxor`](crxor.md) — the dual; `crxor BT, BT, BT` is the standard **clear-to-0** idiom.
- [`mcrf`](mcrf.md) — bulk CR-field move.
- [`bcx`](../branch/bcx.md) — consumes the synthesised bit.
### Simplified Mnemonics
| Simplified | Expansion | Effect |
| --- | --- | --- |
| `crset BT` | `creqv BT, BT, BT` | force `CR[BT] ← 1` |
## IBM Reference
- [AIX 7.3 — `creqv` (Condition Register Equivalent)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-creqv-condition-register-equivalent-instruction)
- [AIX 7.3 — Condition register simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-condition-register-logical-simplified)

View File

@@ -0,0 +1,121 @@
# `crnand` — Condition Register NAND
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c0001c2`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `crnand` | `crnand` | — | Condition Register NAND |
## Syntax
```asm
crnand [CRBD], [CRBA], [CRBB]
```
## Encoding
### `crnand` — form `XL`
- **Opcode word:** `0x4c0001c2`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `225`
- **Synchronising:** no
| 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 |
| --- | --- | --- |
| `CRBA` | crnand: read | CR source bit A (031). |
| `CRBB` | crnand: read | CR source bit B (031). |
| `CRBD` | crnand: write | CR destination bit (031). |
## Register Effects
### `crnand`
- **Reads (always):** `CRBA`, `CRBB`
- **Reads (conditional):** _none_
- **Writes (always):** `CRBD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`crnand`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crnand"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:379`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L379)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:716`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L716)
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operation.** `CR[CRBD] ← ¬(CR[CRBA] AND CR[CRBB])`. Result is 0 only when both source bits are 1; otherwise 1.
- **Bit-level operands.** 5-bit absolute CR-bit indices, identical to the rest of the CR-logical family. Source and destination bits may all be in different CR fields.
- **Identity case.** `crnand BT, BA, BA``¬CR[BA]` — a one-instruction CR-bit invert. Less common than `crxor` against a `crset`-prepared 1-bit, but legal.
- **Use case.** Branch on "NOT (A AND B)". Less common than the De Morgan equivalent (`cror BT, ¬A, ¬B`), but saves an extra `crnot` step.
- **No `Rc` / `OE`.** No CR0 / XER side effects.
- **Not synchronising.** Reorderable.
- **xenia status.** Decoded by the generic XL-form CR-logical handler; the interpreter snapshot is shared with `crand`/`cror`/etc. xenia-canary's `InstrEmit_crnand` emits a host AND followed by NOT.
## Related Instructions
- [`crand`](crand.md), [`crandc`](crandc.md) — non-negated AND siblings.
- [`crnor`](crnor.md) — negated OR (the De Morgan dual).
- [`cror`](cror.md), [`crorc`](crorc.md) — OR family.
- [`crxor`](crxor.md), [`creqv`](creqv.md) — XOR / XNOR.
- [`mcrf`](mcrf.md) — copy a 4-bit CR field wholesale.
- [`bcx`](../branch/bcx.md) — typical consumer.
`crnand` has no dedicated simplified mnemonic. Use `crand` + a separate complement, or use `crnand BT, BA, BA` to invert a single bit.
## IBM Reference
- [AIX 7.3 — `crnand` (Condition Register NAND)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-crnand-condition-register-nand-instruction)
- [AIX 7.3 — Condition register simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-condition-register-logical-simplified)

View File

@@ -0,0 +1,125 @@
# `crnor` — Condition Register NOR
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000042`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `crnor` | `crnor` | — | Condition Register NOR |
## Syntax
```asm
crnor [CRBD], [CRBA], [CRBB]
```
## Encoding
### `crnor` — form `XL`
- **Opcode word:** `0x4c000042`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `33`
- **Synchronising:** no
| 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 |
| --- | --- | --- |
| `CRBA` | crnor: read | CR source bit A (031). |
| `CRBB` | crnor: read | CR source bit B (031). |
| `CRBD` | crnor: write | CR destination bit (031). |
## Register Effects
### `crnor`
- **Reads (always):** `CRBA`, `CRBB`
- **Reads (conditional):** _none_
- **Writes (always):** `CRBD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`crnor`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crnor"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:388`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L388)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:712`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L712)
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operation.** `CR[CRBD] ← ¬(CR[CRBA] OR CR[CRBB])`. Result is 1 only when both source bits are 0; otherwise 0.
- **`crnot BT, BA` idiom.** With `BA == BB`, `crnor BT, BA, BA``¬CR[BA]` — this is the canonical PowerPC **single-bit invert**, recognised by assemblers as the simplified mnemonic `crnot BT, BA`.
- **Bit-level operands.** 5-bit absolute CR-bit indices (0..31). The three bits may live in any combination of the eight CR fields.
- **Use case.** Branch on "neither A nor B"; or, with `crnot`, simply complement a CR bit before consuming it in a `bcx`.
- **No `Rc` / `OE`.** Pure CR-bit dataflow; CR0/XER untouched.
- **Not synchronising.** Reorderable.
- **xenia status.** Decoded via the generic CR-logical handler. xenia-canary's `InstrEmit_crnor` emits a host OR followed by NOT.
## Related Instructions
- [`cror`](cror.md), [`crorc`](crorc.md) — non-negated OR siblings.
- [`crnand`](crnand.md) — negated AND (the De Morgan dual).
- [`crand`](crand.md), [`crandc`](crandc.md) — AND family.
- [`crxor`](crxor.md), [`creqv`](creqv.md) — XOR / XNOR.
- [`mcrf`](mcrf.md) — bulk CR-field copy.
- [`bcx`](../branch/bcx.md) — typical consumer of synthesised CR bits.
### Simplified Mnemonics
| Simplified | Expansion | Effect |
| --- | --- | --- |
| `crnot BT, BA` | `crnor BT, BA, BA` | `CR[BT] ← ¬CR[BA]` (invert single bit) |
## IBM Reference
- [AIX 7.3 — `crnor` (Condition Register NOR)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-crnor-condition-register-nor-instruction)
- [AIX 7.3 — Condition register simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-condition-register-logical-simplified)

View File

@@ -0,0 +1,125 @@
# `cror` — Condition Register OR
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000382`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `cror` | `cror` | — | Condition Register OR |
## Syntax
```asm
cror [CRBD], [CRBA], [CRBB]
```
## Encoding
### `cror` — form `XL`
- **Opcode word:** `0x4c000382`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `449`
- **Synchronising:** no
| 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 |
| --- | --- | --- |
| `CRBA` | cror: read | CR source bit A (031). |
| `CRBB` | cror: read | CR source bit B (031). |
| `CRBD` | cror: write | CR destination bit (031). |
## Register Effects
### `cror`
- **Reads (always):** `CRBA`, `CRBB`
- **Reads (conditional):** _none_
- **Writes (always):** `CRBD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`cror`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cror"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:397`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L397)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:720`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L720)
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operation.** `CR[CRBD] ← CR[CRBA] OR CR[CRBB]`. All other CR bits are preserved.
- **`crmove BT, BA` idiom.** With `BA == BB`, `cror BT, BA, BA` is the canonical PowerPC **single-bit copy** between CR bits, recognised by assemblers as the simplified mnemonic `crmove BT, BA`. This is the standard way to relocate a CR bit (e.g., promote `cr1.EQ` to `cr0.EQ` so a default-`cr0` branch can consume it).
- **Bit-level operands.** Three independent 5-bit CR-bit indices; mixing CR fields is the whole point of this family.
- **Use case.** Branch on "A OR B" of two prior compare results — saves an extra branch by collapsing two conditions.
- **No `Rc` / `OE`.** Pure CR-bit dataflow.
- **Not synchronising.** Reorderable.
- **xenia status.** Most-used CR-logical instruction in real code (almost always as `crmove`). Decoded by the generic XL-form CR-logical handler; canary emits a host OR.
## Related Instructions
- [`crand`](crand.md), [`crandc`](crandc.md) — AND family.
- [`crorc`](crorc.md) — OR with complement.
- [`crnor`](crnor.md), [`crnand`](crnand.md) — negated forms.
- [`crxor`](crxor.md), [`creqv`](creqv.md) — XOR / XNOR.
- [`mcrf`](mcrf.md) — copy a 4-bit CR field wholesale.
- [`bcx`](../branch/bcx.md), [`bclrx`](../branch/bclrx.md), [`bcctrx`](../branch/bcctrx.md) — typical consumers.
### Simplified Mnemonics
| Simplified | Expansion | Effect |
| --- | --- | --- |
| `crmove BT, BA` | `cror BT, BA, BA` | `CR[BT] ← CR[BA]` (single-bit copy) |
## IBM Reference
- [AIX 7.3 — `cror` (Condition Register OR)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-cror-condition-register-instruction)
- [AIX 7.3 — Condition register simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-condition-register-logical-simplified)

View File

@@ -0,0 +1,121 @@
# `crorc` — Condition Register OR with Complement
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000342`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `crorc` | `crorc` | — | Condition Register OR with Complement |
## Syntax
```asm
crorc [CRBD], [CRBA], [CRBB]
```
## Encoding
### `crorc` — form `XL`
- **Opcode word:** `0x4c000342`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `417`
- **Synchronising:** no
| 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 |
| --- | --- | --- |
| `CRBA` | crorc: read | CR source bit A (031). |
| `CRBB` | crorc: read | CR source bit B (031). |
| `CRBD` | crorc: write | CR destination bit (031). |
## Register Effects
### `crorc`
- **Reads (always):** `CRBA`, `CRBB`
- **Reads (conditional):** _none_
- **Writes (always):** `CRBD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`crorc`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crorc"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:406`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L406)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:719`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L719)
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operation.** `CR[CRBD] ← CR[CRBA] OR ¬CR[CRBB]` — a one-instruction "A or not B" implication. Result is 0 only when `A=0` and `B=1`.
- **Logical implication.** `B → A``¬B A`, which is exactly `crorc BT, BA, BB`. Useful for predicates of the form "if B holds, then A must hold".
- **Identity case.** `crorc BT, BA, BA` always yields 1 (`A ¬A`), an alternative to `creqv` for setting a bit.
- **Bit-level operands.** 5-bit absolute CR-bit indices; sources and destination may all be in different CR fields.
- **Use case.** Compose "if B then A" guards without a separate complement step.
- **No `Rc` / `OE`.** Doesn't update CR0 or XER.
- **Not synchronising.** Reorderable.
- **xenia status.** Decoded by the generic CR-logical handler; canary emits OR-with-NOT directly.
## Related Instructions
- [`cror`](cror.md), [`crnor`](crnor.md) — non-complement OR / NOR.
- [`crand`](crand.md), [`crandc`](crandc.md), [`crnand`](crnand.md) — AND family.
- [`crxor`](crxor.md), [`creqv`](creqv.md) — XOR / XNOR.
- [`mcrf`](mcrf.md) — bulk CR-field copy.
- [`bcx`](../branch/bcx.md) — typical consumer.
`crorc` has no dedicated simplified mnemonic. See [`cror`](cror.md) for `crmove`.
## IBM Reference
- [AIX 7.3 — `crorc` (Condition Register OR with Complement)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-crorc-condition-register-complement-instruction)
- [AIX 7.3 — Condition register simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-condition-register-logical-simplified)

View File

@@ -0,0 +1,124 @@
# `crxor` — Condition Register XOR
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000182`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `crxor` | `crxor` | — | Condition Register XOR |
## Syntax
```asm
crxor [CRBD], [CRBA], [CRBB]
```
## Encoding
### `crxor` — form `XL`
- **Opcode word:** `0x4c000182`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `193`
- **Synchronising:** no
| 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 |
| --- | --- | --- |
| `CRBA` | crxor: read | CR source bit A (031). |
| `CRBB` | crxor: read | CR source bit B (031). |
| `CRBD` | crxor: write | CR destination bit (031). |
## Register Effects
### `crxor`
- **Reads (always):** `CRBA`, `CRBB`
- **Reads (conditional):** _none_
- **Writes (always):** `CRBD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`crxor`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crxor"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:415`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L415)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:715`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L715)
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operation.** `CR[CRBD] ← CR[CRBA] XOR CR[CRBB]`. Result is 1 iff the two source bits differ.
- **`crclr BT` idiom.** With identical operands, `crxor BT, BT, BT` always yields 0 (any bit XOR'd with itself is 0). This is the canonical PowerPC **clear-to-0** for a single CR bit; assemblers recognise the simplified mnemonic `crclr BT`. Compilers emit it before variadic-argument calls (PPC ABI uses `cr1.SO` to flag presence of FP arguments).
- **Bit-level operands.** Three independent 5-bit absolute CR-bit indices (0..31).
- **Use case.** Branch on "A != B"; or, with the `crclr` idiom, zero a CR bit before fall-through CR computation.
- **No `Rc` / `OE`.** No CR0 / XER side effects.
- **Not synchronising.** Reorderable.
- **xenia status.** Common enough in real code (typically as `crclr 6` for the variadic-FP marker) that translators often special-case the `crclr` pattern. xenia-canary's `InstrEmit_crxor` emits a host XOR; xenia-rs decodes via the generic CR-logical handler.
## Related Instructions
- [`creqv`](creqv.md) — the dual; `creqv BT, BT, BT` is the standard **set-to-1** idiom.
- [`crand`](crand.md), [`crandc`](crandc.md), [`crnand`](crnand.md) — AND family.
- [`cror`](cror.md), [`crorc`](crorc.md), [`crnor`](crnor.md) — OR family.
- [`mcrf`](mcrf.md) — bulk CR-field copy.
- [`bcx`](../branch/bcx.md), [`bclrx`](../branch/bclrx.md) — typical consumers of synthesised CR bits.
### Simplified Mnemonics
| Simplified | Expansion | Effect |
| --- | --- | --- |
| `crclr BT` | `crxor BT, BT, BT` | force `CR[BT] ← 0` |
## IBM Reference
- [AIX 7.3 — `crxor` (Condition Register XOR)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-crxor-condition-register-xor-instruction)
- [AIX 7.3 — Condition register simplified mnemonics](https://www.ibm.com/docs/en/aix/7.3.0?topic=mnemonics-condition-register-logical-simplified)

View File

@@ -0,0 +1,129 @@
# `mcrf` — Move Condition Register Field
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [XL](../forms/XL.md) · **Opcode:** `0x4c000000`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mcrf` | `mcrf` | — | Move Condition Register Field |
## Syntax
```asm
mcrf [CRFD], [CRFS]
```
## Encoding
### `mcrf` — form `XL`
- **Opcode word:** `0x4c000000`
- **Primary opcode (bits 05):** `19`
- **Extended opcode:** `0`
- **Synchronising:** no
| 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 |
| --- | --- | --- |
| `CRFS` | mcrf: read | CR source field. |
| `CRFD` | mcrf: write | CR destination field (`crf`, 07). |
## Register Effects
### `mcrf`
- **Reads (always):** `CRFS`
- **Reads (conditional):** _none_
- **Writes (always):** `CRFD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`mcrf`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mcrf"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:424`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L424)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:51`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L51)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:710`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L710)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1683-1686`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1683-L1686)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mcrf => {
ctx.cr[instr.crfd()] = ctx.cr[instr.crfs()];
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Field-level (4-bit) move.** Unlike the bit-level CR-logical family ([`crand`](crand.md), …, [`crxor`](crxor.md)), `mcrf` copies *all four* bits of a CR field (LT, GT, EQ, SO) in one instruction. `CRFD` and `CRFS` are 3-bit field indices (0..7), each naming a 4-bit slice of the 32-bit CR.
- **No source-field clobber.** The source field is read, not modified — `mcrf 0, 1` copies CR1 into CR0 leaving CR1 intact.
- **Same-field is a NOP.** `mcrf cr0, cr0` reads-then-writes the same field; xenia's interpreter still does the assignment but the architectural state is unchanged.
- **Use case.** Promote a non-default compare result into `cr0` so a default-`cr0` simplified branch (`beq label`) can consume it without spelling out `cr1`/`cr2`/etc. The alternative — `crmove` — would require four `cror` instructions to move all four bits.
- **No CR0/XER side effects.** Pure CR-field dataflow.
- **Not synchronising.** Reorderable.
- **xenia exact match.** xenia-rs models the CR as an array of eight 4-bit fields, so `mcrf` is a single struct copy (`ctx.cr[crfd] = ctx.cr[crfs]`). Matches PowerISA semantics exactly.
## Related Instructions
- [`mfcr`](mfcr.md) — read the entire 32-bit CR into a GPR.
- [`mtcrf`](mtcrf.md) — write selected CR fields from a GPR (uses an 8-bit field-mask).
- [`mcrxr`](mcrxr.md) — copy `XER[SO..CA]` into a CR field and clear them.
- [`mcrfs`](mcrfs.md) — copy an FPSCR field into a CR field.
- [`crand`](crand.md), [`crandc`](crandc.md), [`creqv`](creqv.md), [`crnand`](crnand.md), [`crnor`](crnor.md), [`cror`](cror.md), [`crorc`](crorc.md), [`crxor`](crxor.md) — bit-level alternatives.
- [`bcx`](../branch/bcx.md) — typical consumer.
`mcrf` has no simplified mnemonics.
## IBM Reference
- [AIX 7.3 — `mcrf` (Move Condition Register Field)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mcrf-move-condition-register-field-instruction)

View File

@@ -0,0 +1,155 @@
# `mcrfs` — Move to Condition Register from FPSCR
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0xfc000080`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mcrfs` | `mcrfs` | — | Move to Condition Register from FPSCR |
## Syntax
```asm
mcrfs [CRFD], [CRFS]
```
## Encoding
### `mcrfs` — form `X`
- **Opcode word:** `0xfc000080`
- **Primary opcode (bits 05):** `63`
- **Extended opcode:** `64`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `CRFS` | mcrfs: read | CR source field. |
| `FPSCR` | mcrfs: read; mcrfs: write | Floating-Point Status and Control Register. |
| `CRFD` | mcrfs: write | CR destination field (`crf`, 07). |
## Register Effects
### `mcrfs`
- **Reads (always):** `CRFS`, `FPSCR`
- **Reads (conditional):** _none_
- **Writes (always):** `CRFD`, `FPSCR`
- **Writes (conditional):** _none_
## Status-Register Effects
- `mcrfs`: **FPSCR** updated per IEEE-754 flags (FX, FEX, FPRF, FR, FI, exceptions).
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`mcrfs`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mcrfs"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:371`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L371)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:51`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L51)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:904`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L904)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4716-4745`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4716-L4745)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mcrfs => {
let crfd = instr.crfd();
let crfs = instr.crfs();
let shift = 28 - (crfs as u32 * 4);
let nibble = ((ctx.fpscr >> shift) & 0xF) as u8;
ctx.cr[crfd] = crate::context::CrField::from_u8(nibble);
// Clearable exception bits: 0 (FX), 3 (OX), 4 (UX), 5 (ZX),
// 6 (XX), 7 (VXSNAN), 8 (VXISI), 9 (VXIDI), 10 (VXZDZ),
// 11 (VXIMZ), 12 (VXVC), 21 (VXSOFT), 22 (VXSQRT), 23 (VXCVI).
// (Bit positions are PowerISA MSB-0; here 'FPSCR bit n' means
// the bit at (31-n) in our little-endian u32.)
const CLEARABLE_MASK: u32 =
(1 << 31) | (1 << (31 - 3)) | (1 << (31 - 4)) |
(1 << (31 - 5)) | (1 << (31 - 6)) | (1 << (31 - 7)) |
(1 << (31 - 8)) | (1 << (31 - 9)) | (1 << (31 - 10)) |
(1 << (31 - 11)) | (1 << (31 - 12)) |
(1 << (31 - 21)) | (1 << (31 - 22)) | (1 << (31 - 23));
let nibble_mask = 0xFu32 << shift;
ctx.fpscr &= !(nibble_mask & CLEARABLE_MASK);
// PPCBUG-068: recompute the VX summary bit. If any VX* exception
// bit remains set, VX must remain set; if all are cleared, VX
// must clear. (FEX recomputation omitted — xenia doesn't model
// enabled-exception dispatch.)
if ctx.fpscr & fpscr::VX_ALL != 0 {
ctx.fpscr |= fpscr::VX;
} else {
ctx.fpscr &= !fpscr::VX;
}
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operation.** Copies one 4-bit FPSCR field into the chosen CR field, then **clears the source FPSCR exception-status bits** (sticky-bit reset). The non-exception status bits (FPRF, etc.) are *not* cleared.
- **Bits cleared in FPSCR.** The architectural rule is: any bit in the source FPSCR field that is one of {FX, OX, UX, ZX, XX, VXSNAN, VXISI, VXIDI, VXZDZ, VXIMZ, VXVC, VXSOFT, VXSQRT, VXCVI} is reset to 0 after the copy. FEX and VX (summary bits) are subsequently re-derived. Many other FPSCR bits (rounding mode, FPRF, FR/FI) are not affected — even if they fall in `CRFS`.
- **CR field destination.** `CRFD` is a 3-bit field index (0..7); the four bits land in their natural positions (LT, GT, EQ, SO) of the chosen CR field. After `mcrfs`, `crf` can be tested with the usual conditional branches.
- **Use case.** Inspect a particular FPSCR exception group, then act on it with a `bc` — e.g. test FPSCR[24..27] (the FI / FR / VXSNAN / VXISI cluster) and branch.
- **Privilege.** Non-privileged on the Xenon — application-visible.
- **xenia status.** Decoded (decoder slot 727), but the interpreter does **not** ship a body in the snapshot on this page — `mcrfs` is rare in title code. xenia's FPSCR model is incomplete (most exception bits are stubbed), so even when implemented, the cleared bits typically have no observable effect.
- **No `Rc`.** X-form, but the `Rc` bit position is unused (reserved 0).
## Related Instructions
- [`mffsx`](mffsx.md) — read entire FPSCR into an FPR.
- [`mtfsfx`](mtfsfx.md), [`mtfsb0x`](mtfsb0x.md), [`mtfsb1x`](mtfsb1x.md), [`mtfsfix`](mtfsfix.md) — write FPSCR bits/fields.
- [`mcrf`](mcrf.md) — copy a CR field to another CR field.
- [`mcrxr`](mcrxr.md) — analogous copy from XER (also clears).
`mcrfs` has no simplified mnemonics.
## IBM Reference
- [AIX 7.3 — `mcrfs` (Move to Condition Register from FPSCR)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mcrfs-move-condition-register-from-fpscr-instruction)
- PowerISA v2.07B, Book I §4.6 — FPSCR layout (sticky exception bits and which clear semantics apply).

View File

@@ -0,0 +1,145 @@
# `mcrxr` — Move to Condition Register from XER
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000400`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mcrxr` | `mcrxr` | — | Move to Condition Register from XER |
## Syntax
```asm
mcrxr [CRFD]
```
## Encoding
### `mcrxr` — form `X`
- **Opcode word:** `0x7c000400`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `512`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `CR` | mcrxr: read | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `CRFD` | mcrxr: write | CR destination field (`crf`, 07). |
## Register Effects
### `mcrxr`
- **Reads (always):** `CR`
- **Reads (conditional):** _none_
- **Writes (always):** `CRFD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
; Pseudocode derives directly from the xenia-rs interpreter
; arm (see Implementation References). Operation semantics:
; - Read source operands from the fields listed under Operands.
; - Apply the arithmetic / logical / memory action described
; in the Description field above.
; - Write results to the destination register(s); update any
; status bits enumerated under Status-Register Effects.
; Consult the IBM AIX reference link under IBM Reference for
; canonical PPC-style pseudocode where xenia's expression is
; terse.
```
## 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
**`mcrxr`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mcrxr"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:433`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L433)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:51`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L51)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:814`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L814)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4694-4706`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4694-L4706)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mcrxr => {
let crfd = instr.crfd();
ctx.cr[crfd] = crate::context::CrField {
lt: ctx.xer_so != 0,
gt: ctx.xer_ov != 0,
eq: ctx.xer_ca != 0,
so: false,
};
ctx.xer_so = 0;
ctx.xer_ov = 0;
ctx.xer_ca = 0;
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operation.** Copies XER's top 4 status bits into a CR field, **then atomically clears those XER bits**. Layout in the destination CR field after the move:
| CR bit | Source XER bit | Meaning |
| --- | --- | --- |
| LT | XER[SO] | summary overflow (sticky) |
| GT | XER[OV] | overflow (last `OE=1` op) |
| EQ | XER[CA] | carry |
| SO | 0 (cleared) | — |
- **Sticky-bit reset.** XER[SO], XER[OV], and XER[CA] are all *zeroed* after the copy. This is the **only** architecturally clean way to sample-then-clear XER's overflow/carry state — `mfxer` reads but does not clear.
- **Use case.** Saturating-arithmetic loops sample XER[OV] periodically; `mcrxr cr0; bso cr0, overflow` is the canonical "did overflow happen since last check?" idiom.
- **CR field destination.** `CRFD` is a 3-bit index (0..7). All other CR fields are preserved.
- **No reads of GPRs.** `mcrxr` reads only XER, writes only the chosen CR field and XER.
- **xenia exact match.** xenia-rs implements the full sample-and-clear semantics: writes `lt = SO`, `gt = OV`, `eq = CA`, `so = false`, then zeroes `xer_so`, `xer_ov`, `xer_ca`. Matches PowerISA exactly.
- **Deprecated in newer PowerISA.** PowerISA v2.06+ marked `mcrxr` deprecated in favour of `mcrxrx` and explicit `mfxer`/`mtxer` patterns, but the Xenon predates that; titles still emit it freely.
## Related Instructions
- [`mfcr`](mfcr.md), [`mtcrf`](mtcrf.md) — bulk CR <-> GPR moves.
- [`mcrf`](mcrf.md) — CR-field copy.
- [`mcrfs`](mcrfs.md) — analogous copy from FPSCR (also clears certain bits).
- [`mfspr`](mfspr.md) (with `SPR=1`, i.e. `mfxer`) — non-clearing read of XER into a GPR.
- [`mtspr`](mtspr.md) (with `SPR=1`, i.e. `mtxer`) — explicit XER write.
`mcrxr` has no simplified mnemonics.
## IBM Reference
- [AIX 7.3 — `mcrxr` (Move to Condition Register from XER)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mcrxr-move-condition-register-from-xer-instruction)

View File

@@ -0,0 +1,117 @@
# `mfcr` — Move from Condition Register
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000026`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mfcr` | `mfcr` | — | Move from Condition Register |
## Syntax
```asm
mfcr [RD]
```
## Encoding
### `mfcr` — form `X`
- **Opcode word:** `0x7c000026`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `19`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode |
| 610 | `RT/FRT/VRT` | destination |
| 1115 | `RA/FRA/VRA` | source A |
| 1620 | `RB/FRB/VRB` | source B |
| 2130 | `XO` | extended opcode (10 bits) |
| 31 | `Rc` | record-form flag |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `CR` | mfcr: read | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `RD` | mfcr: write | Destination GPR. |
## Register Effects
### `mfcr`
- **Reads (always):** `CR`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
RT <- 0x00000000 || CR
```
## 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
**`mfcr`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mfcr"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:625`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L625)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:53`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L53)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:753`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L753)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1627-1630`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1627-L1630)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mfcr => {
ctx.gpr[instr.rd()] = ctx.cr() as u64;
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Special Cases & Edge Conditions
- **Operation.** Packs all 32 CR bits into the low half of `RD`; the upper 32 bits of `RD` are zeroed. CR field 0 ends up in bits 32..35 of `RD` (i.e. bits 0..3 of the 32-bit packed value), CR field 7 in bits 60..63 (bits 28..31).
- **No CR side effect.** `mfcr` is a read; CR is unmodified. The XL-form's nominal `Rc` bit is unused on this opcode.
- **Saving CR across calls.** The Xbox 360 / SysV ABI requires non-volatile CR fields (CR2..CR4) to be preserved across calls. Standard prologue: `mfcr r12; stw r12, 8(r1)`. Epilogue restores via [`mtcrf`](mtcrf.md).
- **Bit ordering.** PowerPC numbers bits big-endian (bit 0 = MSB). The encoding into the GPR follows the same convention: CR0.LT lands in bit 32 of the doubleword (the MSB of the low word). C-side translations should mask with `0xFFFFFFFFu` before consuming.
- **`mfocrf` variant.** PowerISA defines `mfocrf` (one CR field), encoded as `mfcr` with the high bit of FXM set. xenia-rs decodes both as the same opcode and ignores the FXM hint, returning the entire CR. This is benign — the spec says implementations may treat `mfocrf` as `mfcr`.
- **Not synchronising.** Reorderable.
- **xenia exact match.** xenia-rs packs its eight `CrField` structs into a `u64` via `ctx.cr()`, mirroring spec semantics.
## Related Instructions
- [`mtcrf`](mtcrf.md) — inverse: write selected CR fields from a GPR.
- [`mcrf`](mcrf.md), [`mcrxr`](mcrxr.md), [`mcrfs`](mcrfs.md) — narrower CR-field moves.
- [`mfspr`](mfspr.md), [`mtspr`](mtspr.md) — generic SPR moves; CR is *not* an SPR (it has its own opcode).
`mfcr` has no simplified mnemonics. `mfocrf RT, FXM` is a related encoding handled by the same xenia-rs slot.
## IBM Reference
- [AIX 7.3 — `mfcr` (Move from Condition Register)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mfcr-move-from-condition-register-instruction)

Some files were not shown because too many files have changed in this diff Show More