CONSOLIDATION.md Phase 6. Both lived untracked in the project root -- on one
disk, backed up by nothing.
tools/ppc-manual/ 393 files, 3.7 MB. 455 instructions, 350 family pages,
598 mnemonics resolvable through index.json, plus the
generator that produced them.
tools/run-canary.sh the oracle launcher.
🔴 THE LAUNCHER WAS BROKEN IN TWO WAYS AND IS REWRITTEN, not copied:
* it pointed at `xenia-rs/sylpheed.iso`, a SYMLINK. Wine cannot resolve one
and says "path invalid", which reads as a corrupt image rather than a path
problem -- it has cost a session before. It now points at the real file and
warns if handed a symlink.
* it hardcoded one machine's absolute paths, and named `xenia-rs`, which this
consolidation retires. Now derived from the script's own location, with
SYLPH_CANARY_BIN / SYLPH_ISO overrides and a check that each exists.
The standing constraints are in its header where someone will read them: one
emulator at a time, Canary runs MUTED, and never judge a crash or a hang from
a Bash-launched run -- a SIGKILL that looked like the binary was the editor's
process supervisor.
⚠️ The manual's GENERATOR reads the xenia-rs source tree, which is going away.
Its decoder now lives here as crates/sylpheed-ppc, so the generator must be
repointed before it is run again. Recorded in the README rather than left for
someone to discover; the manual's content is checked in and regenerates from
nothing implicitly.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
131 lines
5.3 KiB
Markdown
131 lines
5.3 KiB
Markdown
# `stdbrx` — Store Doubleword Byte-Reverse Indexed
|
||
|
||
> **Category:** [Memory](../categories/memory.md) · **Form:** [X](../forms/X.md) · **Opcode:** `0x7c000528`
|
||
|
||
<!-- GENERATED: BEGIN -->
|
||
|
||
## Assembler Mnemonics
|
||
|
||
| Mnemonic | XML entry | Flags | Description |
|
||
| --- | --- | --- | --- |
|
||
| `stdbrx` | `stdbrx` | — | Store Doubleword Byte-Reverse Indexed |
|
||
|
||
## Syntax
|
||
|
||
```asm
|
||
stdbrx [RS], [RA0], [RB]
|
||
```
|
||
|
||
## Encoding
|
||
|
||
### `stdbrx` — form `X`
|
||
|
||
- **Opcode word:** `0x7c000528`
|
||
- **Primary opcode (bits 0–5):** `31`
|
||
- **Extended opcode:** `660`
|
||
- **Synchronising:** no
|
||
|
||
| Bits | Field | Meaning |
|
||
| --- | --- | --- |
|
||
| 0–5 | `OPCD` | primary opcode |
|
||
| 6–10 | `RT/FRT/VRT` | destination |
|
||
| 11–15 | `RA/FRA/VRA` | source A |
|
||
| 16–20 | `RB/FRB/VRB` | source B |
|
||
| 21–30 | `XO` | extended opcode (10 bits) |
|
||
| 31 | `Rc` | record-form flag |
|
||
|
||
## Operands
|
||
|
||
| Field | Role | Description |
|
||
| --- | --- | --- |
|
||
| `RS` | stdbrx: read | Source GPR (alias for RD in some stores). |
|
||
| `RA0` | stdbrx: read | Source GPR; when the encoded register number is 0 the operand is the literal 64-bit zero, **not** `r0`. |
|
||
| `RB` | stdbrx: read | Source GPR. |
|
||
|
||
## Register Effects
|
||
|
||
### `stdbrx`
|
||
|
||
- **Reads (always):** `RS`, `RA0`, `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
|
||
|
||
**`stdbrx`**
|
||
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stdbrx"`](../../xenia-canary/tools/ppc-instructions.xml)
|
||
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:691`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L691)
|
||
- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:69`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L69)
|
||
- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:829`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L829)
|
||
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4632-4639`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4632-L4639)
|
||
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
|
||
|
||
```rust
|
||
PpcOpcode::stdbrx => {
|
||
let ea = ea_indexed(ctx, instr);
|
||
if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) {
|
||
if t.has_active_reservers() { t.invalidate_for_write(ea); }
|
||
}
|
||
mem.write_u64(ea, ctx.gpr[instr.rs()].swap_bytes());
|
||
ctx.pc += 4;
|
||
}
|
||
```
|
||
</details>
|
||
|
||
<!-- GENERATED: END -->
|
||
|
||
## Special Cases & Edge Conditions
|
||
|
||
- **Writes little-endian doubleword.** Reverses the 8 bytes of `RS` and stores them at `EA`. Compared to a regular `std`, the byte at `EA` becomes `RS[56:63]` (least-significant), and the byte at `EA+7` becomes `RS[0:7]` (most-significant). The xenia snapshot calls `mem.write_u64(ea, ctx.gpr[instr.rs()].swap_bytes())`.
|
||
- **Used to emit little-endian payloads.** Symmetric counterpart of [`ldbrx`](ldbrx.md). Common when writing PC-side file formats, network packets, or PE/COFF headers from PowerPC code.
|
||
- **X-form only — no update form, no DS-form.** Only the indexed form exists. `EA = (RA|0) + RB`. Pointer-bumping requires a separate `addi`.
|
||
- **`RA0` semantics.** When `RA = 0`, base is literal zero. `stdbrx RS, 0, RB` writes at exact `RB`.
|
||
- **Alignment.** Hardware tolerates unaligned 8-byte writes. Cache-inhibited storage may raise alignment exceptions on real hardware.
|
||
- **No CR / FPSCR effects.** Pure data movement.
|
||
- **Cache-line straddling cost.** As with `std`, writes that cross a 128-byte line boundary touch two cache lines; keep doublewords 8-byte aligned for best performance.
|
||
|
||
## Related Instructions
|
||
|
||
- [`ldbrx`](ldbrx.md) — load doubleword byte-reverse (the matching load).
|
||
- [`stwbrx`](stwbrx.md), [`sthbrx`](sthbrx.md) — narrower byte-reverse stores.
|
||
- [`std`](std.md), [`stdx`](std.md) — non-reversing doubleword stores.
|
||
|
||
## IBM Reference
|
||
|
||
- [AIX 7.3 — `stdbrx` (Store Doubleword Byte-Reverse Indexed)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-stdbrx-store-double-word-byte-reverse-indexed-instruction)
|
||
- `PowerISA v2.07B Book II` § "Byte-Reverse Storage Access".
|