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

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

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

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

144 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `faddx` — Floating Add
> **Category:** [Floating-Point](../categories/fpu.md) · **Form:** [A](../forms/A.md) · **Opcode:** `0xfc00002a`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `fadd` | `faddx` | — | Floating Add |
| `fadd.` | `faddx` | Rc=1 | Floating Add |
## Syntax
```asm
fadd[Rc] [FD], [FA], [FB]
```
## Encoding
### `faddx` — form `A`
- **Opcode word:** `0xfc00002a`
- **Primary opcode (bits 05):** `63`
- **Extended opcode:** `21`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (59 or 63) |
| 610 | `FRT` | destination FPR |
| 1115 | `FRA` | source A FPR |
| 1620 | `FRB` | source B FPR |
| 2125 | `FRC` | source C FPR (multiplier for madd-style ops) |
| 2630 | `XO` | extended opcode (5 bits) |
| 31 | `Rc` | record-form flag (updates CR1) |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `FA` | faddx: read | Source A floating-point register (`fr0``fr31`). |
| `FB` | faddx: read | Source B floating-point register. |
| `FD` | faddx: write | Destination floating-point register. |
| `CR` | faddx: write (conditional) | Condition-register update. When `Rc=1`, CR field 0 (or CR6 for vector compares, CR1 for FPU) is updated from the result. |
| `FPSCR` | faddx: write | Floating-Point Status and Control Register. |
## Register Effects
### `faddx`
- **Reads (always):** `FA`, `FB`
- **Reads (conditional):** _none_
- **Writes (always):** `FD`, `FPSCR`
- **Writes (conditional):** `CR`
## Status-Register Effects
- `faddx`: **CR1** ← FPSCR[FX, FEX, VX, OX] when `Rc=1`.; **FPSCR** updated per IEEE-754 flags (FX, FEX, FPRF, FR, FI, exceptions).
## Operation (pseudocode)
```
FRT <- FRA + FRB ; double-precision
```
## C Translation Example
```c
/* fadd / fadd. — IEEE-754 double-precision add (A-form) */
f[insn.FRT] = f[insn.FRA] + f[insn.FRB];
if (insn.Rc) update_cr1_from_fpscr();
/* FPSCR[FPRF, FR, FI, FX, exceptions] implicitly updated by the FPU. */
```
## Implementation References
**`faddx`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="faddx"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:38`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L38)
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27)
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:922`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L922)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2555-2564`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2555-L2564)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::faddx => {
let a = ctx.fpr[instr.ra()];
let b = ctx.fpr[instr.rb()];
fpscr::check_invalid_add(ctx, a, b, false);
let result = a + b;
ctx.fpr[instr.rd()] = result;
fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite());
if instr.rc_bit() { update_cr1_from_fpscr(ctx); }
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## Extended Pseudocode
```
FRT <- round(FRA + FRB, FPSCR[RN]) ; double precision, current rounding mode
; FPSCR side-effects (always)
FPSCR[FPRF] <- classify(FRT) ; sign / class bits
FPSCR[FR,FI] <- round_info
if overflow then FPSCR[OX] <- 1; FPSCR[FX] <- 1
if underflow then FPSCR[UX] <- 1; FPSCR[FX] <- 1
if inexact then FPSCR[XX] <- 1; FPSCR[FX] <- 1
if NaN input or ±∞−±∞ then FPSCR[VXISI]<- 1; FPSCR[FX] <- 1
FPSCR[FEX] <- any-enabled-exception
if Rc then
CR1 <- FPSCR[FX, FEX, VX, OX] ; the four "summary" bits
```
## Special Cases & Edge Conditions
- **Double precision.** `fadd` always operates on IEEE-754 binary64 regardless of whether either source was produced by a single-precision instruction. Single-precision adds use [`faddsx`](faddsx.md) and automatically round the result to binary32 precision.
- **No immediate / carry / OE.** FPU arithmetic has no immediate forms, no carry, and no overflow-enable bit. `Rc` is the only modifier — it writes `CR1` from the four top FPSCR bits.
- **FPSCR is always updated.** Even the non-record form (`fadd`) updates `FPSCR[FPRF, FR, FI, FX, …]` as a side effect of execution; xenia's interpreter currently **does not** model this, so translations that rely on observing FPSCR bits across a pair of FPU instructions will diverge from hardware. If your translator needs compatible FPSCR state, emit explicit updates — or accept the simplification, which matches real Xbox 360 title behaviour in practice (titles rarely read FPSCR except via `mffs` for exception sanity checks).
- **NaN propagation.** Per IEEE-754, any NaN input produces a NaN output; PowerPC specifies that the *signalling* bit of the result NaN is cleared (quietening a signalling input). Xenia uses host-native `f64 +`, which may preserve the signalling bit on some platforms — assume quietening for correctness.
- **`±∞ ±∞` is an invalid operation.** Produces a quiet NaN (`QNaN(VXISI)`) and sets `FPSCR[VXISI]`. Xenia emits the host-native NaN.
- **Denormal handling.** Xenon's default mode flushes denormal results to zero (FPSCR[NI] / "non-IEEE mode" bit set at boot). Xenia inherits host semantics by default; if title code explicitly clears NI (rare) you'll get IEEE-compliant denormals from the host FPU.
- **Rounding mode.** `FPSCR[RN]` selects one of four rounding modes (nearest-even, toward 0, toward +∞, toward −∞). Games rarely change RN from the default nearest-even. If your translator needs faithful rounding-mode support emit `fesetround` around the operation.
- **Register encoding.** A-form: `FRT`, `FRA`, `FRB`, `FRC`, `Rc` — but `fadd` ignores `FRC` (the "C" multiplier operand used by `fmadd`-style ops). The `FRC` field is architecturally don't-care but typically encoded as 0.
## Related Instructions
- [`faddsx`](faddsx.md) — single-precision add; result is rounded to binary32 then stored as binary64.
- [`fsubx`](fsubx.md), [`fsubsx`](fsubsx.md) — double / single subtract.
- [`fmulx`](fmulx.md), [`fmulsx`](fmulsx.md) — double / single multiply.
- [`fmaddx`](fmaddx.md), [`fmsubx`](fmsubx.md), [`fnmaddx`](fnmaddx.md), [`fnmsubx`](fnmsubx.md) — fused multiply-add family (single-rounding; preferred for dot products).
- [`mffsx`](mffsx.md), [`mtfsfx`](mtfsfx.md) — read/write FPSCR.
## IBM Reference
- [AIX 7.3 — `fadd` (Floating Add)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-fa-fadd-floating-add-instruction)
- [PowerISA v2.07B, Book I, Chapter 4 — Floating-Point Processor](https://openpowerfoundation.org/specifications/isa/) (complete FPSCR and NaN-propagation rules).