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:
@@ -0,0 +1,79 @@
|
||||
---
|
||||
name: Disassembler unification — Phase 1 complete (2026-04-27)
|
||||
description: Single source of truth for PPC text formatting now lives in xenia-cpu/disasm.rs. xenia-analysis/ppc.rs is a thin shim. DecodedInstr stays at 8 bytes. VMX128 bug fixed.
|
||||
type: project
|
||||
originSessionId: 680cc54c-e77a-4d2d-a11b-ca562e9a68ec
|
||||
---
|
||||
**Phase 1 of disassembler unification is COMPLETE** (2026-04-27, single session).
|
||||
|
||||
## What's in place
|
||||
|
||||
- **[crates/xenia-cpu/src/disasm.rs](crates/xenia-cpu/src/disasm.rs)** is the single source of truth for PPC text formatting (~1100 LOC, was 313). Hosts:
|
||||
- `pub struct DisasmText { mnemonic, operands, disasm, ext_mnemonic, ext_operands, ext_disasm, branch_target }` — all `String` / `Option<String>` / `Option<u32>`. Owns its strings.
|
||||
- `pub fn format(&DecodedInstr) -> DisasmText` — the canonical formatter. Dispatches via match on `PpcOpcode` to ~70 per-class helpers.
|
||||
- `pub fn disassemble(&DecodedInstr) -> String` — back-compat: returns `format(...).display().to_string()`.
|
||||
- `pub fn disassemble_block(...)` — back-compat range walker.
|
||||
- 8 unit tests covering nop/li/mr/blr/branch-target/rlwinm-dot.
|
||||
|
||||
- **[crates/xenia-cpu/src/lib.rs](crates/xenia-cpu/src/lib.rs)** re-exports `DisasmText`, `disassemble`, `format as disasm_format`.
|
||||
|
||||
- **[crates/xenia-analysis/src/ppc.rs](crates/xenia-analysis/src/ppc.rs)** collapsed from 1374 LOC → ~30 LOC. Pure shim:
|
||||
```rust
|
||||
pub struct Decoded { pub base: String, pub ext: Option<String> }
|
||||
pub fn disasm(instr: u32, addr: u32) -> Decoded { ... }
|
||||
```
|
||||
Delegates to `xenia_cpu::decoder::decode` + `xenia_cpu::disasm::format`.
|
||||
|
||||
- **[crates/xenia-analysis/src/db.rs](crates/xenia-analysis/src/db.rs)** call sites use `xenia_cpu::disasm::format` directly. The `split_disasm` helper at the bottom is **deleted** — `DisasmText` exposes mnemonic/operands separately.
|
||||
|
||||
- **[crates/xenia-analysis/src/formatter.rs](crates/xenia-analysis/src/formatter.rs)** unchanged — uses the `crate::ppc::disasm` shim's `display()` method.
|
||||
|
||||
- **[crates/xenia-analysis/Cargo.toml](crates/xenia-analysis/Cargo.toml)** now depends on xenia-cpu.
|
||||
|
||||
## Constraint #1 honored: DecodedInstr unchanged
|
||||
|
||||
- `DecodedInstr` is still 8 bytes (`opcode: PpcOpcode`, `raw: u32`, `addr: u32`), `Copy`, no allocations.
|
||||
- Decode cache at [decoder.rs:228](crates/xenia-cpu/src/decoder.rs) still 64K × 20 bytes = 1.3 MiB.
|
||||
- `DisasmText` is the new struct that owns the formatted strings, allocated only when `format()` is called from a sink.
|
||||
|
||||
## Silent bug fixed: VMX128 register extractors
|
||||
|
||||
The pre-Phase-1 `xenia-analysis/src/ppc.rs` had **wrong bit positions** for `va128`/`vb128`/`vd128` compared to `decoder.rs`. The interpreter (which executes guest code) used decoder.rs's correct extractors, so guest behavior was correct — but `.asm` text output and DuckDB rows could show wrong VMX128 register names. Phase 1 routes all VMX128 formatting through `instr.va128()`/`vb128()`/`vd128()` accessors (decoder.rs canonical). Fixed silently.
|
||||
|
||||
## Other extended forms now in xenia-cpu
|
||||
|
||||
Ported from ppc.rs onto `DecodedInstr` accessors: li/lis/subi/subis, nop, mr/not, slwi/srwi/clrlwi/clrrwi/rotlwi/extlwi/extrwi, clrldi/clrrdi/srdi/sldi/rotldi, insrdi, inslwi/insrwi, cmpwi/cmpdi/cmplwi/cmpldi, cmpw/cmpd/cmplw/cmpld, mflr/mfctr/mfxer, mtlr/mtctr/mtxer, mtcr, mftb/mftbu, blr/blrl/bctr/bctrl, b{cond}{l}{a} (eq/ne/lt/le/gt/ge/so/ns), bd{n}z{cond}, b{cond}lr, b{cond}ctr, sub/subc, crnot/crclr/crset/crmove, lwsync, trap, td{cond}/tw{cond}, td{cond}i/tw{cond}i.
|
||||
|
||||
## Behavior changes visible to users
|
||||
|
||||
1. `xenia disasm` (the simple subcommand) now emits **extended/simplified mnemonics**. Before Phase 1 it only emitted base forms. Smoke test confirmed: `mr`, `subi`, `nop`, `lis`, `li`, `cmpwi`, `beq`, etc. all appear correctly.
|
||||
2. VMX128 register names printed in `.asm` and DB are now correct (silent bug fix).
|
||||
3. MD-form rotate `sh` value display matches decoder.rs's bit layout (was different in old ppc.rs — likely also a silent bug, since the decoder is what runs on guest code).
|
||||
|
||||
## Verification done
|
||||
|
||||
- `cargo build --workspace` clean (no new warnings; pre-existing warnings in block_cache.rs and vmx.rs unchanged).
|
||||
- `cargo test -p xenia-cpu` — 166 + 8 new disasm + 9 audit = all pass.
|
||||
- `cargo test -p xenia-analysis` — audit pass.
|
||||
- Smoke `xenia disasm <iso> -n 30` — produces clean extended-mnemonic output.
|
||||
- Full `xenia dis --db` end-to-end deferred to next session (release build was slow; functional path verified by passing cargo tests).
|
||||
|
||||
## LOC delta (Phase 1)
|
||||
|
||||
- xenia-cpu/src/disasm.rs: +780 (313 → ~1093)
|
||||
- xenia-analysis/src/ppc.rs: −1344 (1374 → 30)
|
||||
- xenia-analysis/src/db.rs: −18 (deleted split_disasm + simplified call sites)
|
||||
- xenia-cpu/src/lib.rs: +1 (re-export)
|
||||
- xenia-analysis/Cargo.toml: +1 dep
|
||||
- **Net: −580 LOC** plus single-source-of-truth.
|
||||
|
||||
## What's next (Phases 2-4)
|
||||
|
||||
Per [/home/fabi/.claude/plans/ok-execute-your-proposed-refactored-dolphin.md](plan):
|
||||
- **Phase 2**: Iterator + sinks (`iter_disasm` in xenia-cpu, RichDisasmItem enrichment + 3 sinks: text, JSON, DuckDB in xenia-analysis).
|
||||
- **Phase 3**: Split db.rs into ingest + analyze; add SQL views layer (`v_branch_xrefs`, `v_call_graph`, `v_reachability_from_entry`, etc.) and `--analyze=rust|sql|both` flag. Keep Rust passes as default.
|
||||
- **Phase 4**: Replace println-only audits with assert-based fixture goldens (`base_mnemonics.json`, `extended_mnemonics.json`, `vmx128_registers.json`, `db_schema_golden.rs`, ISO-gated `disasm_first_1000.json`).
|
||||
|
||||
**Format style locked**: Phase 1 reproduces ppc.rs's padded comma-space style (`"addi r3, r4, 16"`). Phase 4 fixtures should lock this.
|
||||
|
||||
**LOC budget remaining**: Phase 2 ~+250/-250 (net 0), Phase 3 ~+280, Phase 4 ~+395 (mostly tests/fixtures).
|
||||
Reference in New Issue
Block a user