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>
8.1 KiB
name, description, type, originSessionId
| name | description | type | originSessionId |
|---|---|---|---|
| Disassembler unification — Phase 4 complete (2026-04-27) | Assert-based fixture goldens replace println-only audits. Three JSON snapshots locked, VMX128 silent-bug area covered by direct accessor unit tests + integration fixture, DB schema golden enforces 7-table column layout + 5 SQL views. | project | 680cc54c-e77a-4d2d-a11b-ca562e9a68ec |
Phase 4 of disassembler unification is COMPLETE (2026-04-27, same session).
What's in place
Fixture-based goldens for the disassembler
- crates/xenia-cpu/tests/disasm_goldens.rs (~280 LOC) — three tests, each loads a JSON fixture and asserts every field of
xenia_cpu::disasm::format(decode(raw, addr))matches.tests/golden/base_mnemonics.json— 77 cases covering common ALU / load-store / branch / compare / FPU forms.tests/golden/extended_mnemonics.json— 51 cases covering the simplified-mnemonic priority order (li,lis,subi,mr,not,nop,slwi,srwi,clrlwi,clrrwi,extlwi,clrldi,srdi,rotldi,cmpwi,cmpdi,cmplwi,blr,blrl,bctr,bctrl,beqlr,bnelr,beq,bne,blt,bge,bgt,ble,bdnz,bdz,bfrombc 20,mflr,mfctr,mfxer,mtlr,mtctr,mtxer,crnot,crclr,crset,crmove,lwsync,trap,tdeqi,twlti).tests/golden/vmx128_registers.json— 16 cases covering standard VMX (5-bit regs) and the silent-bug VMX128 op6 vd128 high-bit area (vd128 = 96, 127 with vrlimi128; lower-bit encodings record what they actually decode to since the op6 secondary key constrains bits 21-23).
- Regen workflow:
REGEN_GOLDENS=1 cargo test -p xenia-cpu --test disasm_goldensoverwrites all three fixtures from currentformat()output. First run also auto-creates if the file is missing (with a panic afterwards forcing the developer to inspect+commit). - xenia-cpu Cargo.toml gains
serde+serde_jsonasdev-dependenciesonly — production lib stays serde-free, honoring constraint #1.
VMX128 silent-bug area: direct accessor unit tests
- crates/xenia-cpu/src/decoder.rs has 7 new unit tests in the existing
testsmodule that pin the canonical bit positions forva128/vb128/vd128/vs128:vmx128_vd128_low_5_bits_only— 32 iterations covering vd_lo = 0..31 with vd_b21 = vd_b22 = 0.vmx128_vd128_bit21_adds_32— bit 21 = 1 produces vd128 = 32.vmx128_vd128_bit22_adds_64— bit 22 = 1 produces vd128 = 64.vmx128_vd128_full_127— vd_lo = 31 + bit 21 + bit 22 = 127.vmx128_va128_uses_bit29— va128 = bits 6-10 + bit 29.vmx128_vb128_uses_bits28_and_30— vb128 = bits 16-20 + bit 28 + bit 30.vmx128_vs128_aliases_vd128— vs128 ≡ vd128 across {0, 31, 32, 64, 96, 127}.
- These pin decoder.rs as the canonical source. The pre-Phase-1 ppc.rs had different (wrong) positions; this test set guarantees the bug never returns silently.
Analysis-side goldens (shim parity)
- crates/xenia-analysis/tests/disasm_goldens.rs (~120 LOC) — 4 tests that load the same cpu-side fixture JSON files (via
..relative path) and verify:xenia_analysis::ppc::disasm(raw, addr).base==xenia_cpu::disasm::format(...).disasm.ext==format().ext_disasm- All structured fields (
mnemonic/operands/ext_*/branch_target) match the fixture row. display()returns extended form when present, base otherwise.
- The cpu fixtures are the single source of truth; analysis shim drift surfaces immediately.
DB schema golden
- crates/xenia-analysis/tests/db_schema_golden.rs (~230 LOC) — one test that builds an in-memory 16-byte PE-shaped fixture (4 instructions: mflr / nop / blr / nop), runs the full
DbWriterpipeline (write_base→ingest_instructions→write_analysis_results→create_sql_views), and asserts:- Every column name + type for all 7 tables (
metadata,sections,imports,instructions,functions,labels,xrefs) viaPRAGMA table_info. - Row counts (4 instructions, 0 with target_hex since the fixture is indirect-only).
- All 5 SQL views (
v_branch_xrefs,v_call_graph,v_function_first_instruction,v_imports_called,v_reachability_from_entry) exist aftercreate_sql_views.
- Every column name + type for all 7 tables (
- Schema drift caught immediately.
- Caveat noted in comments: SQL
LIKE 'v_%'matches DuckDB's built-inviewssystem view because_is a single-char wildcard. The test enumerates view names explicitly.
Deletions
- xenia-cpu/tests/disasm_audit.rs (161 LOC) — println-only, no assertions. Migrated to the assert-based goldens above.
- xenia-analysis/tests/disasm_audit.rs (164 LOC) — same.
Verification
cargo test --workspace: 29 test groups, 0 failures. All previously-passing tests still pass (176 cpu interpreter + 13 disasm + 7 VMX128 accessors + 4 analysis goldens + 1 schema golden + everything else).
$ cargo test --workspace 2>&1 | grep -c "test result: ok"
29
$ cargo test --workspace 2>&1 | grep -c "FAILED\|failed"
0
Discoveries / fixture-author surprises
-
VMX128 op6 vrlimi128 vd128 < 96 is not a valid encoding. The secondary key uses bits 21-23 = 111, so the high two bits of vd128 (which share bits 21+22) MUST be 11 for the dispatch to land on vrlimi128. Lower-bit attempts decode as vsrw128 / vpermwi128 instead. The fixture records this exact behavior — labeled honestly so future readers don't think these cases test what they don't.
-
Sylpheed's real corpus only contains vrlimi128 with vd128 ∈ 96..=127 (consistent with the constraint above). The decoder has been emitting these correctly since Phase 1's silent-bug fix; the goldens now lock that behavior.
-
PRAGMA table_infodoesn't accept bind parameters in DuckDB the wayWHEREdoes — it uses the statement-level interpolation route. Inlined the table name into the query string with simple format!. -
DuckDB has a built-in
viewssystem view that matches SQLLIKE 'v_%'(because_is a single-char wildcard,views=v+ 'i' + 'ews' fits). Always enumerate view names explicitly, or useLIKE 'v\_%' ESCAPE '\'.
LOC delta (Phase 4)
- xenia-cpu/tests/disasm_goldens.rs: +388 (new)
- xenia-cpu/tests/golden/*.json: +28k bytes (~700 lines committed JSON across 3 files)
- xenia-cpu/src/decoder.rs: +95 (7 new VMX128 accessor unit tests)
- xenia-cpu/Cargo.toml: +4 (dev-dependencies serde+serde_json)
- xenia-cpu/tests/disasm_audit.rs: −161 (deleted)
- xenia-analysis/tests/disasm_goldens.rs: +120 (new)
- xenia-analysis/tests/db_schema_golden.rs: +245 (new)
- xenia-analysis/tests/disasm_audit.rs: −164 (deleted)
- Net: +527 LOC test code + ~700 lines JSON fixtures, −325 LOC of useless println audits.
Tooling for future authors
- Adding new test cases: edit
cases: &[(u32, u32, &str)]array inline intests/disasm_goldens.rs, runREGEN_GOLDENS=1 cargo test -p xenia-cpu --test disasm_goldens, inspect the diff in the JSON fixture, commit. - Detecting drift: any change to
format()output that affects existing cases will fail the assertion test, naming the row label and showing the diff. Either the change is intentional (regen) or it's a regression (fix code). - Schema changes:
db_schema_golden.rswill fail if you add/remove/rename a column or change a type. Update theexpectedslice in the test.
End-of-phase status
All four phases of the disassembler unification are now complete:
- Phase 1: single-source-of-truth
format()in xenia-cpu; analysis ppc.rs collapsed to a 30-line shim; VMX128 silent bug fixed. - Phase 2: iterator + 3 sinks (text/JSON/DuckDB) layer;
--jsonCLI flag. - Phase 3: db.rs split into ingest/analyze; 5 additive SQL views;
--analyze=rust|sql|bothflag with cross-check warning. - Phase 4: assert-based fixture goldens + VMX128 accessor unit tests + DB schema golden replacing the println-only audits.
The DecodedInstr struct stays at 8 bytes throughout; the decode cache stays at 1.3 MiB; Rust analysis (func.rs, xref.rs) remains the default and is unchanged. All three user constraints honored end-to-end.