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,179 @@
# `mfspr` — Move from Special-Purpose Register
> **Category:** [Control / CR / SPR](../categories/control.md) · **Form:** [XFX](../forms/XFX.md) · **Opcode:** `0x7c0002a6`
<!-- GENERATED: BEGIN -->
## Assembler Mnemonics
| Mnemonic | XML entry | Flags | Description |
| --- | --- | --- | --- |
| `mfspr` | `mfspr` | — | Move from Special-Purpose Register |
## Syntax
```asm
mfspr [RD], [SPR]
```
## Encoding
### `mfspr` — form `XFX`
- **Opcode word:** `0x7c0002a6`
- **Primary opcode (bits 05):** `31`
- **Extended opcode:** `339`
- **Synchronising:** no
| Bits | Field | Meaning |
| --- | --- | --- |
| 05 | `OPCD` | primary opcode (31) |
| 610 | `RT` | destination / source GPR |
| 1120 | `spr/tbr/FXM` | SPR/TBR number (byte-swapped halves) or CR field mask |
| 2130 | `XO` | extended opcode |
| 31 | `—` | reserved |
## Operands
| Field | Role | Description |
| --- | --- | --- |
| `SPR` | mfspr: read | Special-Purpose-Register number. Encoded with the two 5-bit halves swapped (bits 11-15 become the high half, bits 16-20 the low half). |
| `RD` | mfspr: write | Destination GPR. |
## Register Effects
### `mfspr`
- **Reads (always):** `SPR`
- **Reads (conditional):** _none_
- **Writes (always):** `RD`
- **Writes (conditional):** _none_
## Status-Register Effects
_No condition-register or status-register effects._
## Operation (pseudocode)
```
n <- spr_number(SPR) ; SPR field has its two 5-bit halves swapped
RT <- SPR(n)
```
## C Translation Example
```c
/* mfspr RT, SPR — SPR field has swapped halves */
uint32_t n = ((insn.SPR & 0x1F) << 5) | ((insn.SPR >> 5) & 0x1F);
switch (n) {
case 1: r[insn.RT] = xer_pack(); break; /* XER */
case 8: r[insn.RT] = lr; break; /* LR */
case 9: r[insn.RT] = ctr; break; /* CTR */
case 256: r[insn.RT] = vrsave; break; /* VRSAVE*/
case 268: r[insn.RT] = tb & 0xFFFFFFFFu; break; /* TBL */
case 269: r[insn.RT] = tb >> 32; break; /* TBU */
default: r[insn.RT] = 0; break;
}
```
## Implementation References
**`mfspr`**
- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mfspr"`](../../xenia-canary/tools/ppc-instructions.xml)
- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:666`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L666)
- 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:799`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L799)
- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1567-1595`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1567-L1595)
<details><summary>xenia-rs interpreter body (frozen snapshot)</summary>
```rust
PpcOpcode::mfspr => {
let spr = instr.spr();
ctx.gpr[instr.rd()] = match spr {
crate::context::spr::XER => ctx.xer() as u64,
crate::context::spr::LR => ctx.lr,
crate::context::spr::CTR => ctx.ctr,
crate::context::spr::DEC => ctx.dec as u64,
crate::context::spr::TBL => ctx.timebase & 0xFFFF_FFFF,
crate::context::spr::TBU => ctx.timebase >> 32,
crate::context::spr::VRSAVE => ctx.vrsave as u64,
// Xbox 360 Xenon processor signature (from canary).
crate::context::spr::PVR => 0x0071_0800,
// Benign SPRs — titles read these but we don't model them.
crate::context::spr::SPRG0
| crate::context::spr::SPRG1
| crate::context::spr::SPRG2
| crate::context::spr::SPRG3
| crate::context::spr::HID0
| crate::context::spr::HID1
| crate::context::spr::DAR
| crate::context::spr::DSISR
| crate::context::spr::PIR => 0,
_ => {
tracing::warn!("mfspr: unimplemented SPR {}", spr);
0
}
};
ctx.pc += 4;
}
```
</details>
<!-- GENERATED: END -->
## SPR Number Encoding — the "halves swap"
The 10-bit `spr` field in the XFX form is **stored in a transposed order**: the bits that software names the *high* half (bits 5..9 of the SPR number) occupy instruction bits **16..20**, and the *low* half (bits 0..4) occupies instruction bits **11..15**. Software (and this manual) always refers to the logical, unswapped SPR number.
```
decoded_spr = ((field & 0x1F) << 5) | ((field >> 5) & 0x1F)
```
So a programmer writing `mfspr RT, 8` (read LR) encodes `spr-field = 0x100`*not* `8`. Assemblers handle this transparently; disassemblers reverse it. When writing a translator that parses raw instruction words, swap the halves explicitly.
## SPR Map (Xenon subset modelled by xenia)
| Decoded # | Name | Meaning | xenia-rs behaviour |
| --- | --- | --- | --- |
| 1 | `XER` | Fixed-point exception register (CA / OV / SO + length field) | packed with `ctx.xer()` |
| 8 | `LR` | Link register | `ctx.lr` |
| 9 | `CTR` | Count register | `ctx.ctr` |
| 18 | `DSISR` | Data-storage interrupt syndrome | returns 0 (stubbed) |
| 19 | `DAR` | Data-access register | returns 0 (stubbed) |
| 256 | `VRSAVE` | Vector-register save mask | `ctx.vrsave` |
| 268 | `TBL` | Time-base lower 32 bits | `ctx.timebase & 0xFFFFFFFF` |
| 269 | `TBU` | Time-base upper 32 bits | `ctx.timebase >> 32` |
| 272275 | `SPRG0..3` | Software scratch registers (kernel) | returns 0 (stubbed) |
| 287 | `PVR` | Processor-version register | `0x00710800` (Xenon signature) |
| 10081009 | `HID0/1` | Hardware implementation registers | returns 0 (stubbed) |
| 1023 | `PIR` | Processor-ID register | returns 0 (stubbed) |
Unrecognised SPRs return 0 and log a warning. Games rarely read unmodelled SPRs; when they do it's usually clock-skew or sanity checks.
## Special Cases & Edge Conditions
- **Privilege.** Some SPRs are privileged on real hardware (MSR, HID0/1, SPRG0..3, DSISR, DAR, PIR). Xbox 360 titles run in a mixed privilege model under the hypervisor; xenia exposes all SPRs without a privilege check because the captured title binaries never contain a real privileged read that should trap.
- **`LR` and `CTR` have dedicated simplified mnemonics.** Assemblers recognise `mflr RT``mfspr RT, 8` and `mfctr RT``mfspr RT, 9`. Similarly `mfxer RT``mfspr RT, 1`. Disassemblers emit the simplified forms; the translation agent should map both forms to the same abstract operation.
- **`mftb` vs. `mfspr TBL/TBU`.** Reading the time-base has a dedicated X-form variant [`mftb`](mftb.md) that uses a separate opcode. Post-Xbox-360 PowerISA deprecated `mfspr TBL/TBU`, but xenia accepts both. Prefer `mftb` in new translations.
- **Side-effect-free.** `mfspr` has no effect on any register beyond `RT`. It can be freely reordered with non-SPR-touching instructions.
- **No `Rc` / `OE`.** This is an XFX-form instruction; bit 31 is reserved (0).
## Related Instructions
- [`mtspr`](mtspr.md) — the inverse; write a GPR to an SPR.
- [`mftb`](mftb.md) — read time-base (preferred over `mfspr TBL/TBU`).
- [`mflr`](mfspr.md), [`mfctr`](mfspr.md), [`mfxer`](mfspr.md) — simplified mnemonics of this instruction.
- [`mcrxr`](mcrxr.md) — move `XER[SO..CA]` to a CR field and clear them.
## Simplified Mnemonics
| Simplified | Expansion |
| --- | --- |
| `mfxer RT` | `mfspr RT, 1` |
| `mflr RT` | `mfspr RT, 8` |
| `mfctr RT` | `mfspr RT, 9` |
## IBM Reference
- [AIX 7.3 — `mfspr` (Move from Special Purpose Register)](https://www.ibm.com/docs/en/aix/7.3.0?topic=set-mfspr-move-from-special-purpose-register-instruction)
- [PowerISA v2.07B — SPR number table and privilege rules](https://openpowerfoundation.org/specifications/isa/)