- Category pages linked each family as `<slug>.md`, relative to categories/, where no family page lives. They now link `../<category>/<slug>.md`. - Form pages linked a member into its *own* category directory, so every VMX128 sibling (`vsldoi128`) pointed at vmx128/ although its family page is under vmx/. They now link into the family's directory. - Hand-written "Related" and sibling mentions linked other categories' pages as if they were in the same directory. 109 are retargeted through the page index; 29 that pointed a family page at itself (`vrefp128` on vrefp.md) and 6 naming instructions the manual has no page for are plain text now. Regenerated at the existing Canary pin (f21ebd49e): upstream has moved on, and re-pinning belongs in its own change. The generator reports 0 family pages changed and is idempotent; the only dead links left are TEMPLATE.md's placeholders. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
140 lines
6.8 KiB
Markdown
140 lines
6.8 KiB
Markdown
# `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 0–5):** `63`
|
||
- **Extended opcode:** `21`
|
||
- **Synchronising:** no
|
||
|
||
| Bits | Field | Meaning |
|
||
| --- | --- | --- |
|
||
| 0–5 | `OPCD` | primary opcode (59 or 63) |
|
||
| 6–10 | `FRT` | destination FPR |
|
||
| 11–15 | `FRA` | source A FPR |
|
||
| 16–20 | `FRB` | source B FPR |
|
||
| 21–25 | `FRC` | source C FPR (multiplier for madd-style ops) |
|
||
| 26–30 | `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`**
|
||
- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="faddx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml)
|
||
- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:38`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L38)
|
||
- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:66`](../../../crates/sylpheed-ppc/src/opcode.rs#L66)
|
||
- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1037`](../../../crates/sylpheed-ppc/src/decoder.rs#L1037)
|
||
<details><summary>Canary emitter (frozen snapshot @ <code>f21ebd49e9</code>)</summary>
|
||
|
||
```cpp
|
||
int InstrEmit_faddx(PPCHIRBuilder& f, const InstrData& i) {
|
||
// frD <- (frA) + (frB)
|
||
Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB));
|
||
f.StoreFPR(i.A.FRT, v);
|
||
f.UpdateFPSCR(v, i.A.Rc);
|
||
return 0;
|
||
}
|
||
```
|
||
</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, …]` on hardware. Canary does not compute them: its `UpdateFPSCR` is a stub that clears `FEX` and `VX`, leaves every other FPSCR bit unchanged and, with `Rc=1`, writes CR1 as all zeros, 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 — 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 result NaN is quiet (a signalling input is quietened). Canary emits a host `f.Add` — SSE `addsd` on x64, which also returns a quietened NaN.
|
||
- **`±∞ − ±∞` is an invalid operation.** Produces a quiet NaN and sets `FPSCR[VXISI]`. Canary returns the host's default NaN and sets no FPSCR bit; note x64's default NaN is `0xFFF8_0000_0000_0000` (sign set), whereas PowerPC's is `0x7FF8_0000_0000_0000`.
|
||
- **Denormal flush.** That Xenon boots with `FPSCR[NI]=1` is unverified. Canary starts every guest thread in IEEE mode (MXCSR `0x1F80`; its init comment flags the startup state as unchecked) and turns on the host's flush-to-zero (`MXCSR.FZ`) only when the guest sets `NI` through `mtfsf`/`mtfsfi`.
|
||
- **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`](../control/mffsx.md), [`mtfsfx`](../control/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).
|