From 7f8a81b8f82f411b74ba9b63a31515e31555e1ed Mon Sep 17 00:00:00 2001 From: sim Date: Wed, 16 Sep 2026 20:34:34 +0200 Subject: [PATCH] docs(ppc-manual): quote Canary and our own decoder, not the retired xenia-rs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The generator had not been able to run correctly since the manual moved into `tools/ppc-manual/`: it computed the repository root as `HERE.parent.parent`, which now names `tools/`, so the XML, Canary's emitters and xenia-rs all stopped resolving — silently, because both scrapers skipped what they could not find. Every page's references had been pointing at paths that exist nowhere. What each source contributed, measured on the 350 pages before this change: Operation (pseudocode) 251 pages: fixed boilerplate "derives from the xenia-rs interpreter"; 99 carry real hand-written seeds C translation 337 pages: the same kind of boilerplate xenia-rs snapshot 336 pages: the interpreter arm, pasted in — the only per-instruction semantics on unseeded pages links xenia-rs opcode/decoder/interpreter + Canary emitter Now: * semantics come from **Xenia Canary**, the reference emulator, read through `git show` at a pinned upstream commit (`origin/canary_experimental`, f21ebd49e9). Not our checkout: it carries instrumentation and lacked upstream's `mcrf` fix, so it would have published probes and a wrong `mcrf`. Each page embeds the emitter (`InstrEmit_`), and for the 128 pure one-line delegations also the helper that holds the semantics. * decode references point at `crates/sylpheed-ppc` — the decoder that produces `sylpheed.db` — as in-repo relative links. * the boilerplate now says what is true, and the C translation guide maps Canary's actual HIR calls, checked against `ppc_hir_builder.h` (including that `UpdateCR(n, v)` truncates to 32 bits). * `rust_scraper.py` -> `decoder_scraper.py` (interpreter half dropped); missing sources are now errors, not empty results. Verified: consistency checks 455 XML entries, 350 families, 598 index keys hand-written tails 386/386 byte-identical after regeneration xenia-rs in generated 0 pages with a snapshot 349/350 (was 336) — `dcbi` has no Canary emitter at all in-repo decoder links 910/910 resolve to a line holding the identifier emitter boundaries brace counter == column-0 `}` rule on 521/521; preprocessor model unit-tested (#if 0/#else/#elif) idempotency re-run: 0 pages updated, 0 working-tree changes Hand-written notes (outside the generated regions) are not rewritten here: * 110 links into `../../xenia-rs/...` were dead; they now point at the file in the archived repository (git.mc02.dev/fabi/xenia-rs @ 8401d4d). Line anchors were dropped because the notes predate that commit — 0 of 441 old line ranges match it — and a precise-looking wrong anchor is worse than none. The link text, which carries the author's line numbers, is unchanged. * 140 prose claims about xenia-rs's behaviour remain. 23 are verified to hold for Canary too (the 32-bit CR0 truncation, OE left unimplemented); the other 114 need checking one by one, and some invert — e.g. `divdx` notes a correct 64-bit CR0 update in xenia-rs where Canary's `UpdateCR` truncates. Left for a deliberate pass rather than a blind substitution. Co-Authored-By: Claude Opus 5 (1M context) --- tools/ppc-manual/README.md | 21 +- tools/ppc-manual/TEMPLATE.md | 5 +- tools/ppc-manual/alu/addcx.md | 65 +++--- tools/ppc-manual/alu/addex.md | 65 +++--- tools/ppc-manual/alu/addi.md | 33 +-- tools/ppc-manual/alu/addic.md | 48 ++-- tools/ppc-manual/alu/addicx.md | 67 +++--- tools/ppc-manual/alu/addis.md | 40 ++-- tools/ppc-manual/alu/addmex.md | 66 +++--- tools/ppc-manual/alu/addx.md | 43 ++-- tools/ppc-manual/alu/addzex.md | 66 +++--- tools/ppc-manual/alu/andcx.md | 48 ++-- tools/ppc-manual/alu/andisx.md | 62 +++--- tools/ppc-manual/alu/andix.md | 60 +++-- tools/ppc-manual/alu/andx.md | 46 ++-- tools/ppc-manual/alu/cmp.md | 80 +++---- tools/ppc-manual/alu/cmpi.md | 81 +++---- tools/ppc-manual/alu/cmpl.md | 66 ++++-- tools/ppc-manual/alu/cmpli.md | 68 +++--- tools/ppc-manual/alu/cntlzdx.md | 48 ++-- tools/ppc-manual/alu/cntlzwx.md | 52 +++-- tools/ppc-manual/alu/divdux.md | 74 ++++--- tools/ppc-manual/alu/divdx.md | 74 ++++--- tools/ppc-manual/alu/divwux.md | 78 ++++--- tools/ppc-manual/alu/divwx.md | 78 ++++--- tools/ppc-manual/alu/eieio.md | 40 ++-- tools/ppc-manual/alu/eqvx.md | 49 +++-- tools/ppc-manual/alu/extsbx.md | 50 +++-- tools/ppc-manual/alu/extshx.md | 50 +++-- tools/ppc-manual/alu/extswx.md | 48 ++-- tools/ppc-manual/alu/isync.md | 39 ++-- tools/ppc-manual/alu/mulhdux.md | 54 +++-- tools/ppc-manual/alu/mulhdx.md | 55 ++--- tools/ppc-manual/alu/mulhwux.md | 64 +++--- tools/ppc-manual/alu/mulhwx.md | 64 +++--- tools/ppc-manual/alu/mulldx.md | 58 ++--- tools/ppc-manual/alu/mulli.md | 46 ++-- tools/ppc-manual/alu/mullwx.md | 59 ++--- tools/ppc-manual/alu/nandx.md | 48 ++-- tools/ppc-manual/alu/negx.md | 68 +++--- tools/ppc-manual/alu/norx.md | 48 ++-- tools/ppc-manual/alu/orcx.md | 48 ++-- tools/ppc-manual/alu/ori.md | 45 ++-- tools/ppc-manual/alu/oris.md | 42 ++-- tools/ppc-manual/alu/orx.md | 63 ++++-- tools/ppc-manual/alu/rldclx.md | 83 ++++--- tools/ppc-manual/alu/rldcrx.md | 83 ++++--- tools/ppc-manual/alu/rldiclx.md | 84 ++++--- tools/ppc-manual/alu/rldicrx.md | 84 ++++--- tools/ppc-manual/alu/rldicx.md | 81 ++++--- tools/ppc-manual/alu/rldimix.md | 81 ++++--- tools/ppc-manual/alu/rlwimix.md | 86 ++++---- tools/ppc-manual/alu/rlwinmx.md | 113 ++++++---- tools/ppc-manual/alu/rlwnmx.md | 79 +++---- tools/ppc-manual/alu/sldx.md | 59 +++-- tools/ppc-manual/alu/slwx.md | 62 +++--- tools/ppc-manual/alu/sradix.md | 80 ++++--- tools/ppc-manual/alu/sradx.md | 78 ++++--- tools/ppc-manual/alu/srawix.md | 84 ++++--- tools/ppc-manual/alu/srawx.md | 80 ++++--- tools/ppc-manual/alu/srdx.md | 59 +++-- tools/ppc-manual/alu/srwx.md | 63 +++--- tools/ppc-manual/alu/subfcx.md | 68 +++--- tools/ppc-manual/alu/subfex.md | 69 +++--- tools/ppc-manual/alu/subficx.md | 65 +++--- tools/ppc-manual/alu/subfmex.md | 83 ++++--- tools/ppc-manual/alu/subfx.md | 57 +++-- tools/ppc-manual/alu/subfzex.md | 83 ++++--- tools/ppc-manual/alu/sync.md | 38 ++-- tools/ppc-manual/alu/xori.md | 41 ++-- tools/ppc-manual/alu/xoris.md | 42 ++-- tools/ppc-manual/alu/xorx.md | 46 ++-- tools/ppc-manual/branch/bcctrx.md | 76 ++++--- tools/ppc-manual/branch/bclrx.md | 97 +++++--- tools/ppc-manual/branch/bcx.md | 130 +++++++---- tools/ppc-manual/branch/bx.md | 42 ++-- tools/ppc-manual/branch/sc.md | 58 ++--- tools/ppc-manual/branch/td.md | 95 +++----- tools/ppc-manual/branch/tdi.md | 94 +++----- tools/ppc-manual/branch/tw.md | 97 ++++---- tools/ppc-manual/branch/twi.md | 101 ++++----- tools/ppc-manual/control/crand.md | 55 +++-- tools/ppc-manual/control/crandc.md | 53 +++-- tools/ppc-manual/control/creqv.md | 53 +++-- tools/ppc-manual/control/crnand.md | 53 +++-- tools/ppc-manual/control/crnor.md | 53 +++-- tools/ppc-manual/control/cror.md | 53 +++-- tools/ppc-manual/control/crorc.md | 53 +++-- tools/ppc-manual/control/crxor.md | 53 +++-- tools/ppc-manual/control/mcrf.md | 59 ++--- tools/ppc-manual/control/mcrfs.md | 100 ++++----- tools/ppc-manual/control/mcrxr.md | 77 +++---- tools/ppc-manual/control/mfcr.md | 73 ++++-- tools/ppc-manual/control/mffsx.md | 59 +++-- tools/ppc-manual/control/mfmsr.md | 56 ++--- tools/ppc-manual/control/mfspr.md | 94 +++++--- tools/ppc-manual/control/mftb.md | 66 +++--- tools/ppc-manual/control/mfvscr.md | 59 +++-- tools/ppc-manual/control/mtcrf.md | 81 ++++--- tools/ppc-manual/control/mtfsb0x.md | 56 +++-- tools/ppc-manual/control/mtfsb1x.md | 56 +++-- tools/ppc-manual/control/mtfsfix.md | 77 ++++--- tools/ppc-manual/control/mtfsfx.md | 94 ++++---- tools/ppc-manual/control/mtmsr.md | 64 +++--- tools/ppc-manual/control/mtmsrd.md | 72 +++--- tools/ppc-manual/control/mtspr.md | 95 ++++---- tools/ppc-manual/control/mtvscr.md | 63 +++--- tools/ppc-manual/fpu/fabsx.md | 51 +++-- tools/ppc-manual/fpu/faddsx.md | 47 ++-- tools/ppc-manual/fpu/faddx.md | 30 ++- tools/ppc-manual/fpu/fcfidx.md | 66 +++--- tools/ppc-manual/fpu/fcmpo.md | 114 +++++----- tools/ppc-manual/fpu/fcmpu.md | 113 +++++----- tools/ppc-manual/fpu/fctidx.md | 90 ++++---- tools/ppc-manual/fpu/fctidzx.md | 89 ++++---- tools/ppc-manual/fpu/fctiwx.md | 90 ++++---- tools/ppc-manual/fpu/fctiwzx.md | 90 ++++---- tools/ppc-manual/fpu/fdivsx.md | 73 +++--- tools/ppc-manual/fpu/fdivx.md | 55 ++--- tools/ppc-manual/fpu/fmaddsx.md | 61 ++--- tools/ppc-manual/fpu/fmaddx.md | 45 ++-- tools/ppc-manual/fpu/fmrx.md | 41 ++-- tools/ppc-manual/fpu/fmsubsx.md | 61 ++--- tools/ppc-manual/fpu/fmsubx.md | 45 ++-- tools/ppc-manual/fpu/fmulsx.md | 63 +++--- tools/ppc-manual/fpu/fmulx.md | 47 ++-- tools/ppc-manual/fpu/fnabsx.md | 44 ++-- tools/ppc-manual/fpu/fnegx.md | 44 ++-- tools/ppc-manual/fpu/fnmaddsx.md | 69 +++--- tools/ppc-manual/fpu/fnmaddx.md | 51 ++--- tools/ppc-manual/fpu/fnmsubsx.md | 69 +++--- tools/ppc-manual/fpu/fnmsubx.md | 51 ++--- tools/ppc-manual/fpu/fresx.md | 77 +++---- tools/ppc-manual/fpu/frspx.md | 69 +++--- tools/ppc-manual/fpu/frsqrtex.md | 71 +++--- tools/ppc-manual/fpu/fselx.md | 65 +++--- tools/ppc-manual/fpu/fsqrtsx.md | 62 ++---- tools/ppc-manual/fpu/fsqrtx.md | 63 ++---- tools/ppc-manual/fpu/fsubsx.md | 63 +++--- tools/ppc-manual/fpu/fsubx.md | 46 ++-- tools/ppc-manual/generator/README.md | 68 ++++-- tools/ppc-manual/generator/cxx_scraper.py | 174 +++++++++++++-- tools/ppc-manual/generator/decoder_scraper.py | 104 +++++++++ tools/ppc-manual/generator/generate_manual.py | 160 ++++++++------ tools/ppc-manual/generator/rust_scraper.py | 184 ---------------- tools/ppc-manual/index.json | 12 +- tools/ppc-manual/memory/dcbf.md | 53 +++-- tools/ppc-manual/memory/dcbi.md | 38 ++-- tools/ppc-manual/memory/dcbst.md | 52 +++-- tools/ppc-manual/memory/dcbt.md | 52 +++-- tools/ppc-manual/memory/dcbtst.md | 53 +++-- tools/ppc-manual/memory/dcbz.md | 113 +++++----- tools/ppc-manual/memory/icbi.md | 50 +++-- tools/ppc-manual/memory/lbz.md | 144 +++++++----- tools/ppc-manual/memory/ld.md | 143 +++++++----- tools/ppc-manual/memory/ldarx.md | 89 ++++---- tools/ppc-manual/memory/ldbrx.md | 62 +++--- tools/ppc-manual/memory/lfd.md | 136 +++++++----- tools/ppc-manual/memory/lfs.md | 140 +++++++----- tools/ppc-manual/memory/lha.md | 146 +++++++----- tools/ppc-manual/memory/lhbrx.md | 64 +++--- tools/ppc-manual/memory/lhz.md | 146 +++++++----- tools/ppc-manual/memory/lmw.md | 79 +++---- tools/ppc-manual/memory/lswi.md | 68 +++--- tools/ppc-manual/memory/lswx.md | 68 +++--- tools/ppc-manual/memory/lvebx.md | 64 +++--- tools/ppc-manual/memory/lvehx.md | 66 +++--- tools/ppc-manual/memory/lvewx.md | 105 +++++---- tools/ppc-manual/memory/lvlx.md | 94 ++++---- tools/ppc-manual/memory/lvlxl.md | 104 +++++---- tools/ppc-manual/memory/lvrx.md | 102 +++++---- tools/ppc-manual/memory/lvrxl.md | 112 ++++++---- tools/ppc-manual/memory/lvx.md | 64 +++--- tools/ppc-manual/memory/lvxl.md | 110 ++++----- tools/ppc-manual/memory/lwa.md | 115 ++++++---- tools/ppc-manual/memory/lwarx.md | 92 ++++---- tools/ppc-manual/memory/lwbrx.md | 64 +++--- tools/ppc-manual/memory/lwz.md | 130 ++++++----- tools/ppc-manual/memory/stb.md | 151 +++++++------ tools/ppc-manual/memory/std.md | 151 +++++++------ tools/ppc-manual/memory/stdbrx.md | 64 +++--- tools/ppc-manual/memory/stdcx.md | 136 +++++------- tools/ppc-manual/memory/stfd.md | 144 ++++++------ tools/ppc-manual/memory/stfiwx.md | 67 +++--- tools/ppc-manual/memory/stfs.md | 148 +++++++------ tools/ppc-manual/memory/sth.md | 152 +++++++------ tools/ppc-manual/memory/sthbrx.md | 65 +++--- tools/ppc-manual/memory/stmw.md | 85 +++---- tools/ppc-manual/memory/stswi.md | 74 +++---- tools/ppc-manual/memory/stswx.md | 76 +++---- tools/ppc-manual/memory/stvebx.md | 65 +++--- tools/ppc-manual/memory/stvehx.md | 69 +++--- tools/ppc-manual/memory/stvewx.md | 124 +++++------ tools/ppc-manual/memory/stvlx.md | 121 +++++----- tools/ppc-manual/memory/stvlxl.md | 131 +++++------ tools/ppc-manual/memory/stvrx.md | 123 +++++------ tools/ppc-manual/memory/stvrxl.md | 133 +++++------ tools/ppc-manual/memory/stvx.md | 70 +++--- tools/ppc-manual/memory/stvxl.md | 114 +++++----- tools/ppc-manual/memory/stw.md | 136 ++++++------ tools/ppc-manual/memory/stwbrx.md | 65 +++--- tools/ppc-manual/memory/stwcx.md | 151 ++++++------- tools/ppc-manual/vmx/lvsl.md | 72 +++--- tools/ppc-manual/vmx/lvsr.md | 88 ++++---- tools/ppc-manual/vmx/vaddcuw.md | 65 +++--- tools/ppc-manual/vmx/vaddfp.md | 78 +++---- tools/ppc-manual/vmx/vaddsbs.md | 66 +++--- tools/ppc-manual/vmx/vaddshs.md | 66 +++--- tools/ppc-manual/vmx/vaddsws.md | 66 +++--- tools/ppc-manual/vmx/vaddubm.md | 59 +++-- tools/ppc-manual/vmx/vaddubs.md | 67 +++--- tools/ppc-manual/vmx/vadduhm.md | 59 +++-- tools/ppc-manual/vmx/vadduhs.md | 66 +++--- tools/ppc-manual/vmx/vadduwm.md | 59 +++-- tools/ppc-manual/vmx/vadduws.md | 66 +++--- tools/ppc-manual/vmx/vand.md | 100 ++++----- tools/ppc-manual/vmx/vandc.md | 98 ++++----- tools/ppc-manual/vmx/vavgsb.md | 61 +++-- tools/ppc-manual/vmx/vavgsh.md | 61 +++-- tools/ppc-manual/vmx/vavgsw.md | 65 +++--- tools/ppc-manual/vmx/vavgub.md | 61 +++-- tools/ppc-manual/vmx/vavguh.md | 61 +++-- tools/ppc-manual/vmx/vavguw.md | 61 +++-- tools/ppc-manual/vmx/vcfsx.md | 69 +++--- tools/ppc-manual/vmx/vcfux.md | 69 +++--- tools/ppc-manual/vmx/vcmpbfp.md | 141 +++++------- tools/ppc-manual/vmx/vcmpeqfp.md | 90 +++----- tools/ppc-manual/vmx/vcmpequb.md | 64 +++--- tools/ppc-manual/vmx/vcmpequh.md | 62 +++--- tools/ppc-manual/vmx/vcmpequw.md | 88 +++----- tools/ppc-manual/vmx/vcmpgefp.md | 88 +++----- tools/ppc-manual/vmx/vcmpgtfp.md | 88 +++----- tools/ppc-manual/vmx/vcmpgtsb.md | 62 +++--- tools/ppc-manual/vmx/vcmpgtsh.md | 62 +++--- tools/ppc-manual/vmx/vcmpgtsw.md | 59 +++-- tools/ppc-manual/vmx/vcmpgtub.md | 62 +++--- tools/ppc-manual/vmx/vcmpgtuh.md | 62 +++--- tools/ppc-manual/vmx/vcmpgtuw.md | 59 +++-- tools/ppc-manual/vmx/vctsxs.md | 77 +++---- tools/ppc-manual/vmx/vctuxs.md | 75 +++---- tools/ppc-manual/vmx/vexptefp.md | 100 +++++---- tools/ppc-manual/vmx/vlogefp.md | 100 +++++---- tools/ppc-manual/vmx/vmaddfp.md | 101 ++++----- tools/ppc-manual/vmx/vmaxfp.md | 96 ++++---- tools/ppc-manual/vmx/vmaxsb.md | 59 +++-- tools/ppc-manual/vmx/vmaxsh.md | 59 +++-- tools/ppc-manual/vmx/vmaxsw.md | 59 +++-- tools/ppc-manual/vmx/vmaxub.md | 60 +++-- tools/ppc-manual/vmx/vmaxuh.md | 60 +++-- tools/ppc-manual/vmx/vmaxuw.md | 60 +++-- tools/ppc-manual/vmx/vmhaddshs.md | 66 +++--- tools/ppc-manual/vmx/vmhraddshs.md | 64 +++--- tools/ppc-manual/vmx/vminfp.md | 96 ++++---- tools/ppc-manual/vmx/vminsb.md | 59 +++-- tools/ppc-manual/vmx/vminsh.md | 59 +++-- tools/ppc-manual/vmx/vminsw.md | 59 +++-- tools/ppc-manual/vmx/vminub.md | 60 +++-- tools/ppc-manual/vmx/vminuh.md | 60 +++-- tools/ppc-manual/vmx/vminuw.md | 60 +++-- tools/ppc-manual/vmx/vmladduhm.md | 61 +++-- tools/ppc-manual/vmx/vmrghb.md | 64 +++--- tools/ppc-manual/vmx/vmrghh.md | 62 +++--- tools/ppc-manual/vmx/vmrghw.md | 106 +++++---- tools/ppc-manual/vmx/vmrglb.md | 64 +++--- tools/ppc-manual/vmx/vmrglh.md | 63 +++--- tools/ppc-manual/vmx/vmrglw.md | 106 +++++---- tools/ppc-manual/vmx/vmsummbm.md | 65 +++--- tools/ppc-manual/vmx/vmsumshm.md | 63 +++--- tools/ppc-manual/vmx/vmsumshs.md | 68 +++--- tools/ppc-manual/vmx/vmsumubm.md | 64 +++--- tools/ppc-manual/vmx/vmsumuhm.md | 63 +++--- tools/ppc-manual/vmx/vmsumuhs.md | 67 +++--- tools/ppc-manual/vmx/vmulesb.md | 57 +++-- tools/ppc-manual/vmx/vmulesh.md | 57 +++-- tools/ppc-manual/vmx/vmuleub.md | 57 +++-- tools/ppc-manual/vmx/vmuleuh.md | 57 +++-- tools/ppc-manual/vmx/vmulosb.md | 57 +++-- tools/ppc-manual/vmx/vmulosh.md | 57 +++-- tools/ppc-manual/vmx/vmuloub.md | 57 +++-- tools/ppc-manual/vmx/vmulouh.md | 57 +++-- tools/ppc-manual/vmx/vnmsubfp.md | 97 ++++---- tools/ppc-manual/vmx/vnor.md | 98 ++++----- tools/ppc-manual/vmx/vor.md | 108 ++++----- tools/ppc-manual/vmx/vperm.md | 123 ++++------- tools/ppc-manual/vmx/vpkpx.md | 73 +++--- tools/ppc-manual/vmx/vpkshss.md | 124 ++++++----- tools/ppc-manual/vmx/vpkshus.md | 124 ++++++----- tools/ppc-manual/vmx/vpkswss.md | 124 ++++++----- tools/ppc-manual/vmx/vpkswus.md | 124 ++++++----- tools/ppc-manual/vmx/vpkuhum.md | 118 +++++----- tools/ppc-manual/vmx/vpkuhus.md | 124 ++++++----- tools/ppc-manual/vmx/vpkuwum.md | 118 +++++----- tools/ppc-manual/vmx/vpkuwus.md | 124 ++++++----- tools/ppc-manual/vmx/vrefp.md | 98 ++++----- tools/ppc-manual/vmx/vrfim.md | 98 ++++----- tools/ppc-manual/vmx/vrfin.md | 102 +++++---- tools/ppc-manual/vmx/vrfip.md | 98 ++++----- tools/ppc-manual/vmx/vrfiz.md | 98 ++++----- tools/ppc-manual/vmx/vrlb.md | 60 +++-- tools/ppc-manual/vmx/vrlh.md | 60 +++-- tools/ppc-manual/vmx/vrlw.md | 104 +++++---- tools/ppc-manual/vmx/vrsqrtefp.md | 104 ++++----- tools/ppc-manual/vmx/vsel.md | 130 +++++------ tools/ppc-manual/vmx/vsl.md | 62 +++--- tools/ppc-manual/vmx/vslb.md | 58 +++-- tools/ppc-manual/vmx/vsldoi.md | 121 +++++----- tools/ppc-manual/vmx/vslh.md | 58 +++-- tools/ppc-manual/vmx/vslo.md | 110 ++++----- tools/ppc-manual/vmx/vslw.md | 108 +++++---- tools/ppc-manual/vmx/vspltb.md | 61 +++-- tools/ppc-manual/vmx/vsplth.md | 59 +++-- tools/ppc-manual/vmx/vspltisb.md | 65 +++--- tools/ppc-manual/vmx/vspltish.md | 65 +++--- tools/ppc-manual/vmx/vspltisw.md | 112 ++++++---- tools/ppc-manual/vmx/vspltw.md | 98 +++++---- tools/ppc-manual/vmx/vsr.md | 63 +++--- tools/ppc-manual/vmx/vsrab.md | 59 +++-- tools/ppc-manual/vmx/vsrah.md | 59 +++-- tools/ppc-manual/vmx/vsraw.md | 104 +++++---- tools/ppc-manual/vmx/vsrb.md | 59 +++-- tools/ppc-manual/vmx/vsrh.md | 59 +++-- tools/ppc-manual/vmx/vsro.md | 110 ++++----- tools/ppc-manual/vmx/vsrw.md | 104 +++++---- tools/ppc-manual/vmx/vsubcuw.md | 62 +++--- tools/ppc-manual/vmx/vsubfp.md | 90 ++++---- tools/ppc-manual/vmx/vsubsbs.md | 65 +++--- tools/ppc-manual/vmx/vsubshs.md | 65 +++--- tools/ppc-manual/vmx/vsubsws.md | 65 +++--- tools/ppc-manual/vmx/vsububm.md | 60 +++-- tools/ppc-manual/vmx/vsububs.md | 65 +++--- tools/ppc-manual/vmx/vsubuhm.md | 60 +++-- tools/ppc-manual/vmx/vsubuhs.md | 65 +++--- tools/ppc-manual/vmx/vsubuwm.md | 60 +++-- tools/ppc-manual/vmx/vsubuws.md | 65 +++--- tools/ppc-manual/vmx/vsum2sws.md | 61 +++-- tools/ppc-manual/vmx/vsum4sbs.md | 62 +++--- tools/ppc-manual/vmx/vsum4shs.md | 62 +++--- tools/ppc-manual/vmx/vsum4ubs.md | 62 +++--- tools/ppc-manual/vmx/vsumsws.md | 59 +++-- tools/ppc-manual/vmx/vupkhpx.md | 56 +++-- tools/ppc-manual/vmx/vupkhsb.md | 100 +++++---- tools/ppc-manual/vmx/vupkhsh.md | 66 +++--- tools/ppc-manual/vmx/vupklpx.md | 56 +++-- tools/ppc-manual/vmx/vupklsb.md | 100 +++++---- tools/ppc-manual/vmx/vupklsh.md | 66 +++--- tools/ppc-manual/vmx/vxor.md | 110 ++++----- tools/ppc-manual/vmx128/vcfpsxws128.md | 73 +++--- tools/ppc-manual/vmx128/vcfpuxws128.md | 73 +++--- tools/ppc-manual/vmx128/vcsxwfp128.md | 69 +++--- tools/ppc-manual/vmx128/vcuxwfp128.md | 69 +++--- tools/ppc-manual/vmx128/vmaddcfp128.md | 68 +++--- tools/ppc-manual/vmx128/vmsum3fp128.md | 64 +++--- tools/ppc-manual/vmx128/vmsum4fp128.md | 64 +++--- tools/ppc-manual/vmx128/vmulfp128.md | 64 +++--- tools/ppc-manual/vmx128/vpermwi128.md | 70 +++--- tools/ppc-manual/vmx128/vpkd3d128.md | 208 +++++++++++------- tools/ppc-manual/vmx128/vrlimi128.md | 107 +++++---- tools/ppc-manual/vmx128/vupkd3d128.md | 111 +++++----- 358 files changed, 13828 insertions(+), 13520 deletions(-) create mode 100644 tools/ppc-manual/generator/decoder_scraper.py delete mode 100644 tools/ppc-manual/generator/rust_scraper.py diff --git a/tools/ppc-manual/README.md b/tools/ppc-manual/README.md index 1141e6e6..29d9d4ca 100644 --- a/tools/ppc-manual/README.md +++ b/tools/ppc-manual/README.md @@ -1,21 +1,12 @@ -> 📌 **Adopted 2026-09-13** from an untracked directory in the project root, -> where it had lived on one disk since April — see -> [`docs/agents/CONSOLIDATION.md`](../../docs/agents/CONSOLIDATION.md). -> -> ⚠️ **The generator's inputs have moved.** `generator/generate_manual.py` reads -> `xenia-canary/tools/ppc-instructions.xml` **and the `xenia-rs` source tree**. -> That emulator is retired: its decoder now lives here as -> [`crates/sylpheed-ppc`](../../crates/sylpheed-ppc), and the generator must be -> repointed before it is run again. The manual's *content* is unaffected — it is -> checked in, and nothing regenerates it implicitly. - # PowerPC Instruction Manual (Xenia Xbox 360 Subset) A reference for the **Xenon** PowerPC dialect used by the Xbox 360. Its primary audience is an AI agent translating PPC assembly functions into -equivalent C. The content is derived from the two authoritative sources in -this repository — **xenia-canary** (C++ emulator) and **xenia-rs** (Rust -rewrite) — and may be deepened with the IBM AIX PowerPC reference. +equivalent C. The content is derived from **Xenia Canary** — the reference +emulator: its instruction table and its PPC emitters, quoted at a pinned +upstream commit — and from Sylpheed's own decoder, `crates/sylpheed-ppc`, which +produces the disassembly in `sylpheed.db`. It may be deepened with the IBM AIX +PowerPC reference. - **455** distinct XML-level instructions (one page each). - **350** instruction family pages (VMX128 siblings folded). @@ -45,7 +36,7 @@ Every instruction page has the same sections, in this order: | **Status-Register Effects** | CR0/CR1/CR6, XER[CA/OV/SO], FPSCR, VSCR updates. | | **Operation** | PPC-style pseudocode (`RT <- …`, `EXTS(…)`, `MEM(EA, n)`). | | **C Translation Example** | Minimal idiomatic C rendering a translator could emit. | -| **Implementation References** | Direct links into `xenia-canary/` and `xenia-rs/` with line numbers. | +| **Implementation References** | Canary's XML entry and emitter (linked at the pinned commit, with a frozen snapshot of the emitter), and Sylpheed's opcode/decoder lines. | | **Special Cases & Edge Conditions** | RA=0, alignment, endian byte-reverse, reservation, SPR remapping, VMX128 fusion. | | **Related Instructions** | Sibling cross-links. | | **IBM Reference** | Optional link to IBM AIX PPC reference for canonical pseudocode. | diff --git a/tools/ppc-manual/TEMPLATE.md b/tools/ppc-manual/TEMPLATE.md index 8010c00f..e0db30ab 100644 --- a/tools/ppc-manual/TEMPLATE.md +++ b/tools/ppc-manual/TEMPLATE.md @@ -47,8 +47,9 @@ Every page follows this skeleton: ## Implementation References - block with the frozen interpreter body snapshot> + block with the + frozen Canary emitter snapshot — and the helper it calls, if it only delegates> diff --git a/tools/ppc-manual/alu/addcx.md b/tools/ppc-manual/alu/addcx.md index 617a2a2a..9dc3605c 100644 --- a/tools/ppc-manual/alu/addcx.md +++ b/tools/ppc-manual/alu/addcx.md @@ -72,13 +72,15 @@ CA <- carry_out_of_32_or_64_bit_add((RA), (RB)) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,30 +88,31 @@ CA <- carry_out_of_32_or_64_bit_add((RA), (RB)) ## Implementation References **`addcx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addcx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:64`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L64) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:861`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L861) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:190-205`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L190-L205) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addcx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:64`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L64) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:8`](../../../crates/sylpheed-ppc/src/opcode.rs#L8) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:976`](../../../crates/sylpheed-ppc/src/decoder.rs#L976) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::addcx => { - // PPCBUG-013+020: 32-bit truncation; CA from u32 unsigned compare. - let ra32 = ctx.gpr[instr.ra()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - let result32 = ra32.wrapping_add(rb32); - ctx.xer_ca = if result32 < ra32 { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - let true_sum = (ra32 as i32 as i128) + (rb32 as i32 as i128); - overflow::apply(ctx, true_sum != (result32 as i32) as i128); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_addcx(PPCHIRBuilder& f, const InstrData& i) { + // RD <- (RA) + (RB) + // CA <- carry bit + Value* ra = f.LoadGPR(i.XO.RA); + Value* rb = f.LoadGPR(i.XO.RB); + Value* v = f.Add(ra, rb); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEINSTRNOTIMPLEMENTED(); + // e.update_xer_with_overflow(EFLAGS OF?); + } else { + f.StoreCA(AddDidCarry(f, ra, rb)); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -120,7 +123,7 @@ CA <- carry_out_of_32_or_64_bit_add((RA), (RB)) - **Carry-out is mandatory.** `XER[CA]` is updated unconditionally — `addcx` exists *to* produce the carry. It seeds a multi-word add chain that continues with [`addex`](addex.md) for middle words and [`addzex`](addzex.md)/[`addmex`](addmex.md) for the final word. - **Carry detection by overflow comparison.** Xenia computes `CA = (result < RA)` — the standard unsigned-add overflow test. Equivalent to `CA = (RA + RB) >> 64` mathematically. This is correct for the 64-bit operand width that the Xenon implements; the spec also allows a 32-bit width selected by the implementation but the 970/Xenon use 64-bit add throughout. - **No trap on signed overflow.** `addco`/`addco.` only set `XER[OV]` and sticky `XER[SO]`; they do not raise an exception. Xenia-rs leaves the `OE` branch as a `// TODO` (see [`addx`](addx.md) for the same gap). -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** The `Rc=1` CR0 compare reads `result as i32 as i64` in [`interpreter.rs:97`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L97); spec demands the full 64-bit signed compare. Flag this as a xenia-rs quirk if you need bit-exact behaviour. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** The `Rc=1` CR0 compare reads `result as i32 as i64` in [`interpreter.rs:97`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs); spec demands the full 64-bit signed compare. Flag this as a xenia-rs quirk if you need bit-exact behaviour. - **`XER[SO]` is sticky** — only `mcrxr` clears it. The `Rc=1` form folds it into `CR0[SO]`. - **Operand aliasing is legal**, just like [`addx`](addx.md). `addc r3, r3, r3` simply doubles `r3` and records whether the result wrapped. diff --git a/tools/ppc-manual/alu/addex.md b/tools/ppc-manual/alu/addex.md index 94eeaaff..4ce5262c 100644 --- a/tools/ppc-manual/alu/addex.md +++ b/tools/ppc-manual/alu/addex.md @@ -72,13 +72,15 @@ CA <- carry_out_of_the_add ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,31 +88,32 @@ CA <- carry_out_of_the_add ## Implementation References **`addex`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addex"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:83`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L83) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:868`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L868) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:206-222`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L206-L222) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addex"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:83`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L83) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:9`](../../../crates/sylpheed-ppc/src/opcode.rs#L9) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:983`](../../../crates/sylpheed-ppc/src/decoder.rs#L983) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::addex => { - // PPCBUG-014+020: 32-bit truncation; CA from u32 unsigned compare. - let ra32 = ctx.gpr[instr.ra()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - let ca = ctx.xer_ca as u32; - let result32 = ra32.wrapping_add(rb32).wrapping_add(ca); - ctx.xer_ca = if result32 < ra32 || (ca != 0 && result32 == ra32) { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - let true_sum = (ra32 as i32 as i128) + (rb32 as i32 as i128) + (ca as i128); - overflow::apply(ctx, true_sum != (result32 as i32) as i128); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_addex(PPCHIRBuilder& f, const InstrData& i) { + // RD <- (RA) + (RB) + XER[CA] + // CA <- carry bit + Value* ra = f.LoadGPR(i.XO.RA); + Value* rb = f.LoadGPR(i.XO.RB); + Value* v = f.AddWithCarry(ra, rb, f.LoadCA()); + f.StoreGPR(i.XO.RT, v); + f.StoreCA(AddWithCarryDidCarry(f, ra, rb, f.LoadCA())); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + if (i.XO.OE) { + // Stub implementation. + // TODO: Handle overflow flag. + // NOTE: 535507D4 (Raiden Fighters Aces) never seems to rely on this + // behavior either, despite OE being set. + } + return 0; +} ```
diff --git a/tools/ppc-manual/alu/addi.md b/tools/ppc-manual/alu/addi.md index b5e83903..ca2a42fb 100644 --- a/tools/ppc-manual/alu/addi.md +++ b/tools/ppc-manual/alu/addi.md @@ -71,21 +71,26 @@ r[insn.RT] = base + (uint64_t)(int64_t)(int16_t)insn.SIMM; ## Implementation References **`addi`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addi"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:103`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L103) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:338`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L338) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:114-120`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L114-L120) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addi"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:103`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L103) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:10`](../../../crates/sylpheed-ppc/src/opcode.rs#L10) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:453`](../../../crates/sylpheed-ppc/src/decoder.rs#L453) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::addi => { - // PPCBUG-001: 32-bit ABI. `li rT, -1` (= addi rT, r0, -1) must produce - // 0x00000000_FFFFFFFF, not 0xFFFFFFFF_FFFFFFFF (sign-extended simm16). - let ra_val = if instr.ra() == 0 { 0 } else { ctx.gpr[instr.ra()] }; - ctx.gpr[instr.rd()] = ra_val.wrapping_add(instr.simm16() as i64 as u64) as u32 as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_addi(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // RT <- EXTS(SI) + // else + // RT <- (RA) + EXTS(SI) + Value* si = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + Value* v = si; + if (i.D.RA) { + v = f.Add(f.LoadGPR(i.D.RA), si); + } + f.StoreGPR(i.D.RT, v); + return 0; +} ```
diff --git a/tools/ppc-manual/alu/addic.md b/tools/ppc-manual/alu/addic.md index 288c4ebf..3065fd81 100644 --- a/tools/ppc-manual/alu/addic.md +++ b/tools/ppc-manual/alu/addic.md @@ -64,13 +64,15 @@ CA <- carry_out ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -78,24 +80,22 @@ CA <- carry_out ## Implementation References **`addic`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addic"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:117`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L117) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:336`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L336) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:135-144`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L135-L144) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addic"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:117`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L117) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:11`](../../../crates/sylpheed-ppc/src/opcode.rs#L11) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:451`](../../../crates/sylpheed-ppc/src/decoder.rs#L451) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::addic => { - // PPCBUG-002: 32-bit ABI. CA must be from a 32-bit unsigned compare; - // canary's `AddDidCarry` truncates both operands to int32 first. - let ra32 = ctx.gpr[instr.ra()] as u32; - let imm32 = instr.simm16() as i32 as u32; - let result32 = ra32.wrapping_add(imm32); - ctx.xer_ca = if result32 < ra32 { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_addic(PPCHIRBuilder& f, const InstrData& i) { + // RT <- (RA) + EXTS(SI) + // CA <- carry bit + Value* ra = f.LoadGPR(i.D.RA); + Value* v = f.Add(ra, f.LoadConstantInt64(XEEXTS16(i.D.DS))); + f.StoreGPR(i.D.RT, v); + f.StoreCA(AddDidCarry(f, ra, f.LoadConstantInt64(XEEXTS16(i.D.DS)))); + return 0; +} ```
diff --git a/tools/ppc-manual/alu/addicx.md b/tools/ppc-manual/alu/addicx.md index 972971ae..246056a6 100644 --- a/tools/ppc-manual/alu/addicx.md +++ b/tools/ppc-manual/alu/addicx.md @@ -58,28 +58,26 @@ addic. [RD], [RA], [SIMM] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,24 +85,23 @@ addic. [RD], [RA], [SIMM] ## Implementation References **`addic.`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addic."`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:127`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L127) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:337`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L337) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:145-154`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L145-L154) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addic."`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:127`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L127) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:12`](../../../crates/sylpheed-ppc/src/opcode.rs#L12) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:452`](../../../crates/sylpheed-ppc/src/decoder.rs#L452) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::addicx => { - // PPCBUG-003: same fix as addic plus CR0 i32 view. - let ra32 = ctx.gpr[instr.ra()] as u32; - let imm32 = instr.simm16() as i32 as u32; - let result32 = ra32.wrapping_add(imm32); - ctx.xer_ca = if result32 < ra32 { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - ctx.update_cr_signed(0, result32 as i32 as i64); - ctx.pc += 4; - } +```cpp +int InstrEmit_addicx(PPCHIRBuilder& f, const InstrData& i) { + // RT <- (RA) + EXTS(SI) + // CA <- carry bit + Value* ra = f.LoadGPR(i.D.RA); + Value* v = f.Add(f.LoadGPR(i.D.RA), f.LoadConstantInt64(XEEXTS16(i.D.DS))); + f.StoreGPR(i.D.RT, v); + f.StoreCA(AddDidCarry(f, ra, f.LoadConstantInt64(XEEXTS16(i.D.DS)))); + f.UpdateCR(0, v); + return 0; +} ```
@@ -116,7 +113,7 @@ addic. [RD], [RA], [SIMM] - **CR0 update is unconditional.** Unlike XO-form `Rc=1` instructions, `addic.` always updates `CR0` from the result; the `.` is part of the mnemonic itself. - **Common idiom: `addic. rN, rN, -1`** — decrements `rN` and sets `CR0[EQ]` when it reaches zero, in a single instruction. Frequently used as a loop counter (often paired with `bne+ loop`). - **`XER[CA]` written same as [`addic`](addic.md).** The carry-out from the unsigned 64-bit add is recorded; the `.` only adds the CR update on top. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:65`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L65) computes `result as i32 as i64`; spec demands a full 64-bit compare-to-zero. The truncation is a documented xenia-rs quirk shared with the rest of the carrying-add family. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:65`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) computes `result as i32 as i64`; spec demands a full 64-bit compare-to-zero. The truncation is a documented xenia-rs quirk shared with the rest of the carrying-add family. - **`SIMM` is sign-extended** to 64 bits before the add — `addic. r3, r4, -1` adds `~0` and never sets `CR0[EQ]` unless `r4 == 1`. ## Related Instructions diff --git a/tools/ppc-manual/alu/addis.md b/tools/ppc-manual/alu/addis.md index ae14a457..d6b74b1c 100644 --- a/tools/ppc-manual/alu/addis.md +++ b/tools/ppc-manual/alu/addis.md @@ -71,28 +71,26 @@ r[insn.RT] = base + ((uint64_t)(int64_t)(int16_t)insn.SIMM << 16); ## Implementation References **`addis`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addis"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:138`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L138) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:339`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L339) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:121-134`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L121-L134) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addis"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:138`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L138) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:13`](../../../crates/sylpheed-ppc/src/opcode.rs#L13) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:454`](../../../crates/sylpheed-ppc/src/decoder.rs#L454) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::addis => { - // Xbox 360 user mode is 32-bit ABI (MSR.SF=0), so addis must - // produce a value whose upper 32 bits don't pollute downstream - // 64-bit arithmetic. The PPC ISA in 64-bit mode sign-extends - // simm16 before the shift, producing 0xFFFFFFFF_xxxx0000 for - // negative simm16 (high bit set). When this value flows into - // a 64-bit subfc against a zero-extended lwz value, the unsigned - // 64-bit comparison yields wrong CA. Truncate to 32 bits to - // simulate 32-bit ABI behavior. - let ra_val = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let result = ra_val.wrapping_add((instr.simm16() as i64 as u64) << 16); - ctx.gpr[instr.rd()] = result as u32 as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_addis(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // RT <- EXTS(SI) || i16.0 + // else + // RT <- (RA) + EXTS(SI) || i16.0 + Value* si = f.LoadConstantInt64(XEEXTS16(i.D.DS) << 16); + Value* v = si; + if (i.D.RA) { + v = f.Add(f.LoadGPR(i.D.RA), si); + } + f.StoreGPR(i.D.RT, v); + return 0; +} ```
diff --git a/tools/ppc-manual/alu/addmex.md b/tools/ppc-manual/alu/addmex.md index d476a799..ae51b952 100644 --- a/tools/ppc-manual/alu/addmex.md +++ b/tools/ppc-manual/alu/addmex.md @@ -71,13 +71,15 @@ CA <- carry_out ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,30 +87,32 @@ CA <- carry_out ## Implementation References **`addmex`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addmex"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:152`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L152) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:873`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L873) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:239-254`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L239-L254) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addmex"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:152`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L152) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:14`](../../../crates/sylpheed-ppc/src/opcode.rs#L14) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:988`](../../../crates/sylpheed-ppc/src/decoder.rs#L988) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::addmex => { - // PPCBUG-016+020: 32-bit truncation. RT = RA + CA - 1. - let ra32 = ctx.gpr[instr.ra()] as u32; - let ca = ctx.xer_ca as u32; - let result32 = ra32.wrapping_add(ca).wrapping_sub(1); - ctx.xer_ca = if ra32 != 0 || ca != 0 { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - let true_sum = (ra32 as i32 as i128) + (ca as i128) - 1; - overflow::apply(ctx, true_sum != (result32 as i32) as i128); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_addmex(PPCHIRBuilder& f, const InstrData& i) { + // RT <- (RA) + CA - 1 + // CA <- carry bit + Value* ra = f.LoadGPR(i.XO.RA); + Value* v = f.AddWithCarry(ra, f.LoadConstantInt64(-1), f.LoadCA()); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + // With XER[SO] update too. + // e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + XEINSTRNOTIMPLEMENTED(); + } else { + // Just CA update. + f.StoreCA(AddWithCarryDidCarry(f, ra, f.LoadConstantInt64(-1), f.LoadCA())); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -120,7 +124,7 @@ CA <- carry_out - **Operation is `RA + CA + (−1)`**, i.e. `RA - 1 + CA`. Used to terminate a multi-word *subtract* chain when the high source word is implicitly all-ones (e.g. computing `-x` as `~x + 1` across 128 bits). - **Carry-out predicate is `RA != 0 OR CA != 0`.** Equivalently, `CA' = NOT(RA == 0 AND CA == 0)`. Adding `−1` to anything except a zero-with-no-carry produces a carry-out (no borrow needed). This terse form in xenia-rs is correct but easy to misread. - **Overflow not implemented in xenia-rs.** The `OE=1` path is silently a no-op; spec says set `XER[OV]` if the signed result wraps. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:139`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L139) — same quirk as the rest of the add family. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:139`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) — same quirk as the rest of the add family. - **`XER[CA]` must be initialised** by an earlier carrying instruction. `addme` is a *terminator*, not a seed. ## Related Instructions diff --git a/tools/ppc-manual/alu/addx.md b/tools/ppc-manual/alu/addx.md index 0e0003fd..0ea32700 100644 --- a/tools/ppc-manual/alu/addx.md +++ b/tools/ppc-manual/alu/addx.md @@ -82,29 +82,26 @@ if (insn.Rc) update_cr0_signed((int64_t)result); ## Implementation References **`addx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:50`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L50) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:875`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L875) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:175-189`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L175-L189) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:50`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L50) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:15`](../../../crates/sylpheed-ppc/src/opcode.rs#L15) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:990`](../../../crates/sylpheed-ppc/src/decoder.rs#L990) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::addx => { - // PPCBUG-012+020: 32-bit ABI writeback truncation + CR0 i32 view. - let ra32 = ctx.gpr[instr.ra()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - let result32 = ra32.wrapping_add(rb32); - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - let true_sum = (ra32 as i32 as i128) + (rb32 as i32 as i128); - overflow::apply(ctx, true_sum != (result32 as i32) as i128); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_addx(PPCHIRBuilder& f, const InstrData& i) { + // RD <- (RA) + (RB) + Value* v = f.Add(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEINSTRNOTIMPLEMENTED(); + // e.update_xer_with_overflow(EFLAGS OF?); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -127,7 +124,7 @@ if Rc then - **No trap on overflow.** `addo` / `addo.` record overflow in `XER[OV]` and sticky-set `XER[SO]`. A trap can only be produced by a separate `td`/`tw` instruction examining the result. - **Signed-overflow predicate.** Overflow occurs iff both addends share a sign bit and the result has the opposite sign bit: `OV = ((~(a ^ b)) & (a ^ rt)) >> 63`. Unsigned carry is *not* tracked — use [`addcx`](addcx.md) when you need `XER[CA]`. - **`XER[SO]` is sticky.** Once set, it remains set until cleared by `mcrxr`. The `.` record forms copy it into `CR0[SO]`. -- **64-bit CR update on Xenon.** The Xbox 360 Xenon CPU is 64-bit, so `add.` compares the full 64-bit result against zero. **Xenia-rs presently truncates to 32 bits** before the CR update (`result as i32 as i64` in [`interpreter.rs:95`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L95)). If your translator must match xenia bit-for-bit, emit a 32-bit compare; if it must be spec-correct, emit a 64-bit compare. Most Xbox 360 object code works either way because results that overflow 32 bits are rare outside of explicit 64-bit math. +- **64-bit CR update on Xenon.** The Xbox 360 Xenon CPU is 64-bit, so `add.` compares the full 64-bit result against zero. **Xenia-rs presently truncates to 32 bits** before the CR update (`result as i32 as i64` in [`interpreter.rs:95`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). If your translator must match xenia bit-for-bit, emit a 32-bit compare; if it must be spec-correct, emit a 64-bit compare. Most Xbox 360 object code works either way because results that overflow 32 bits are rare outside of explicit 64-bit math. - **OE overflow detection not emulated in xenia-rs.** The `addo` / `addo.` branch in `interpreter.rs` is a `TODO` stub. A faithful translator should still emit the overflow check — titles rarely observe `XER[OV]`, but it's occasionally used by profiling / sanity-checking code paths. - **Operand aliasing.** `add r3, r3, r3`, `add r3, r3, r4`, `add r3, r4, r3` are all legal. The addition reads both source operands before writing `RT`. - **No immediate form.** For `RT = RA + imm` use [`addi`](addi.md) / [`addis`](addis.md). Those are distinct opcodes, not a flag on `add`. diff --git a/tools/ppc-manual/alu/addzex.md b/tools/ppc-manual/alu/addzex.md index 49f32e73..53adcb3a 100644 --- a/tools/ppc-manual/alu/addzex.md +++ b/tools/ppc-manual/alu/addzex.md @@ -71,13 +71,15 @@ CA <- carry_out ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,30 +87,32 @@ CA <- carry_out ## Implementation References **`addzex`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addzex"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:172`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L172) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:8`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L8) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:870`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L870) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:223-238`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L223-L238) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="addzex"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:172`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L172) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:16`](../../../crates/sylpheed-ppc/src/opcode.rs#L16) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:985`](../../../crates/sylpheed-ppc/src/decoder.rs#L985) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::addzex => { - // PPCBUG-015+020: 32-bit truncation. - let ra32 = ctx.gpr[instr.ra()] as u32; - let ca = ctx.xer_ca as u32; - let result32 = ra32.wrapping_add(ca); - ctx.xer_ca = if result32 < ra32 { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - let true_sum = (ra32 as i32 as i128) + (ca as i128); - overflow::apply(ctx, true_sum != (result32 as i32) as i128); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_addzex(PPCHIRBuilder& f, const InstrData& i) { + // RT <- (RA) + CA + // CA <- carry bit + Value* ra = f.LoadGPR(i.XO.RA); + Value* v = f.AddWithCarry(ra, f.LoadZeroInt64(), f.LoadCA()); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + // With XER[SO] update too. + // e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + XEINSTRNOTIMPLEMENTED(); + } else { + // Just CA update. + f.StoreCA(AddWithCarryDidCarry(f, ra, f.LoadZeroInt64(), f.LoadCA())); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -120,7 +124,7 @@ CA <- carry_out - **Operation is `RA + 0 + CA` ≡ `RA + CA`.** Used to terminate the *high word* of a multi-word add chain seeded by [`addcx`](addcx.md). After the low-word `addc` produces the carry, all middle words use [`addex`](addex.md), and the final word that has no register operand uses `addze`. - **Carry-out is the simple unsigned overflow test** `result < ra` — same predicate as [`addcx`](addcx.md). `CA' = 1` only if `RA == ~0 && CA == 1`. - **`OE=1` not implemented in xenia-rs.** The interpreter has no overflow branch at all; spec asks for the standard signed-overflow detect. -- **64-bit CR update on Xenon, 32-bit in xenia-rs** (truncation in [`interpreter.rs:128`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L128) — see [`addx`](addx.md) for context). +- **64-bit CR update on Xenon, 32-bit in xenia-rs** (truncation in [`interpreter.rs:128`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) — see [`addx`](addx.md) for context). - **Common idiom: extracting a carry as a 0/1.** `addze rT, 0` (or `addze rT, rN` where `rN == 0`) materialises `XER[CA]` into `rT` as a plain integer. ## Related Instructions diff --git a/tools/ppc-manual/alu/andcx.md b/tools/ppc-manual/alu/andcx.md index 7b1ce281..09b49955 100644 --- a/tools/ppc-manual/alu/andcx.md +++ b/tools/ppc-manual/alu/andcx.md @@ -66,13 +66,15 @@ RA <- (RS) & ~(RB) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,22 +82,22 @@ RA <- (RS) & ~(RB) ## Implementation References **`andcx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andcx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:647`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L647) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:9`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L9) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:768`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L768) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:534-541`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L534-L541) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andcx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:647`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L647) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:17`](../../../crates/sylpheed-ppc/src/opcode.rs#L17) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:883`](../../../crates/sylpheed-ppc/src/decoder.rs#L883) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::andcx => { - // PPCBUG-033: !rb on u64 flips upper 32 bits — active poisoning. - let rs32 = ctx.gpr[instr.rs()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - ctx.gpr[instr.ra()] = (rs32 & !rb32) as u64; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_andcx(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) & ¬(RB) + Value* ra = f.AndNot(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)); + f.StoreGPR(i.X.RA, ra); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + return 0; +} ```
@@ -108,7 +110,7 @@ RA <- (RS) & ~(RB) - **Operand convention is the X-form one** (`RA` is the destination, `RS` and `RB` are sources). Same gotcha as [`andx`](andx.md). - **No `OE`/`XER` side effects.** Only `CR0` is updated when `Rc=1`. - **64-bit operation** on Xenon; the AND is computed across all 64 bits of `RS` and `~RB`. Xenia-rs uses Rust's bitwise `!` on `u64`, which is the correct full-width complement. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:352`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L352) — same truncation pattern. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:352`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) — same truncation pattern. ## Related Instructions diff --git a/tools/ppc-manual/alu/andisx.md b/tools/ppc-manual/alu/andisx.md index f57fd43c..1dd8935f 100644 --- a/tools/ppc-manual/alu/andisx.md +++ b/tools/ppc-manual/alu/andisx.md @@ -57,28 +57,26 @@ andis. [RA], [RS], [UIMM] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,21 +84,21 @@ andis. [RA], [RS], [UIMM] ## Implementation References **`andis.`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andis."`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:665`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L665) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:9`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L9) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:352`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L352) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:505-511`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L505-L511) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andis."`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:665`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L665) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:18`](../../../crates/sylpheed-ppc/src/opcode.rs#L18) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:467`](../../../crates/sylpheed-ppc/src/decoder.rs#L467) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::andisx => { - // PPCBUG-023: 32-bit ABI CR0 view. `andis. rA, rS, 0x8000` to test - // sign bit of a 32-bit word now correctly classifies bit 31 = 1 as LT. - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] & ((instr.uimm16() as u64) << 16); - ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); - ctx.pc += 4; - } +```cpp +int InstrEmit_andisx(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) & (i32.0 || UI || i16.0) + Value* ra = + f.And(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS) << 16)); + f.StoreGPR(i.D.RA, ra); + f.UpdateCR(0, ra); + return 0; +} ```
@@ -113,7 +111,7 @@ andis. [RA], [RS], [UIMM] - **Together with `andi.` covers the entire low 32 bits.** Any 32-bit mask can be applied with `andis. + andi.` (two instructions). Larger masks need `rlwinm` or a constructed register operand to [`andx`](andx.md). - **High 32 bits of result are always zero.** Because the immediate is at bits 32–47, no information from `RS[0:31]` survives. Useful as a quick "extract bits 32–47, zero the rest" primitive. - **CR0 update is unconditional** and uses the standard signed-compare-to-zero semantics with `XER[SO]` folded into `SO`. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** The `result as i32 as i64` truncation in [`interpreter.rs:326`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L326) is harmless: the result is bounded by `0x00000000_FFFF0000`, which fits the 32-bit window exactly. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** The `result as i32 as i64` truncation in [`interpreter.rs:326`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) is harmless: the result is bounded by `0x00000000_FFFF0000`, which fits the 32-bit window exactly. ## Related Instructions diff --git a/tools/ppc-manual/alu/andix.md b/tools/ppc-manual/alu/andix.md index 0b40aa25..4a31d28f 100644 --- a/tools/ppc-manual/alu/andix.md +++ b/tools/ppc-manual/alu/andix.md @@ -57,28 +57,26 @@ andi. [RA], [RS], [UIMM] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,20 +84,20 @@ andi. [RA], [RS], [UIMM] ## Implementation References **`andi.`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andi."`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:657`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L657) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:9`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L9) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:351`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L351) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:499-504`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L499-L504) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andi."`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:657`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L657) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:19`](../../../crates/sylpheed-ppc/src/opcode.rs#L19) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:466`](../../../crates/sylpheed-ppc/src/decoder.rs#L466) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::andix => { - // PPCBUG-020: 32-bit ABI CR0 view. - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] & (instr.uimm16() as u64); - ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); - ctx.pc += 4; - } +```cpp +int InstrEmit_andix(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) & (i48.0 || UI) + Value* ra = f.And(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS))); + f.StoreGPR(i.D.RA, ra); + f.UpdateCR(0, ra); + return 0; +} ```
@@ -112,7 +110,7 @@ andi. [RA], [RS], [UIMM] - **Cannot mask the high half of a register in one instruction.** The immediate covers bits 48–63 only; for higher bits use [`andisx`](andisx.md) (covers bits 32–47) or compose with `rlwinm`/`rldicl`. - **CR0 update is unconditional.** This is part of the encoding, not a flag — the primary opcode (28) *is* `andi.`. - **Common idiom: `andi. r0, rN, mask`** to test bits without disturbing the source — but note `r0` is overwritten and `CR0` is set. If you only need the CR result, prefer `extrwi`/`rlwinm.` for arbitrary masks. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** Since the AND result has zeros in bits 0–47, the low-32 truncation in [`interpreter.rs:321`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L321) is harmless here — the result fits in 16 bits, so spec and xenia agree. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** Since the AND result has zeros in bits 0–47, the low-32 truncation in [`interpreter.rs:321`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) is harmless here — the result fits in 16 bits, so spec and xenia agree. ## Related Instructions diff --git a/tools/ppc-manual/alu/andx.md b/tools/ppc-manual/alu/andx.md index 84936a93..0196d4ed 100644 --- a/tools/ppc-manual/alu/andx.md +++ b/tools/ppc-manual/alu/andx.md @@ -66,13 +66,15 @@ RA <- (RS) & (RB) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,20 +82,22 @@ RA <- (RS) & (RB) ## Implementation References **`andx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:637`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L637) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:9`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L9) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:760`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L760) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:528-533`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L528-L533) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="andx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:637`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L637) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:20`](../../../crates/sylpheed-ppc/src/opcode.rs#L20) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:875`](../../../crates/sylpheed-ppc/src/decoder.rs#L875) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::andx => { - // PPCBUG-032+020: 32-bit ABI CR0 view (latent under clean inputs). - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] & ctx.gpr[instr.rb()]; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_andx(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) & (RB) + Value* ra = f.And(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)); + f.StoreGPR(i.X.RA, ra); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + return 0; +} ```
@@ -104,7 +108,7 @@ RA <- (RS) & (RB) - **Operand convention is reversed.** Unlike the arithmetic XO-form (`add RT, RA, RB`), the logical X-form writes `RA` and reads `RS`/`RB`: `and RA, RS, RB`. The destination is the **second** operand encoded. This convention applies to the entire and/or/xor family; mixing them up is a frequent disassembly error. - **No `OE`, no `XER[CA]`, no `XER[OV]`.** Logical operations never affect XER. Only `Rc=1` updates `CR0` (signed compare against zero, with `SO ← XER[SO]`). - **64-bit AND on Xenon.** Both inputs are 64-bit GPRs; the result is the bitwise AND of all 64 bits. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** The interpreter's `Rc=1` path in [`interpreter.rs:347`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L347) compares `result as i32 as i64`. For an AND whose high 32 bits are non-zero but low 32 bits are zero (e.g. `r3 = 0x1_0000_0000`, `and. r4, r3, r3`), spec sets CR0 to GT but xenia would set EQ. Flag this if reproducing CR-sensitive behaviour. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** The interpreter's `Rc=1` path in [`interpreter.rs:347`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) compares `result as i32 as i64`. For an AND whose high 32 bits are non-zero but low 32 bits are zero (e.g. `r3 = 0x1_0000_0000`, `and. r4, r3, r3`), spec sets CR0 to GT but xenia would set EQ. Flag this if reproducing CR-sensitive behaviour. - **Operand aliasing.** `and RA, RA, RA` is a no-op except for the optional CR0 update — this is the canonical "test register against zero" pattern when no `cmpwi` is desired (though `cmpwi` is more typical). - **No simplified mnemonic for AND-immediate.** Use [`andix`](andix.md) (`andi.`) or [`andisx`](andisx.md) (`andis.`) for immediate operands; both are *always* record forms (no plain `andi`). diff --git a/tools/ppc-manual/alu/cmp.md b/tools/ppc-manual/alu/cmp.md index 2432066e..5e193317 100644 --- a/tools/ppc-manual/alu/cmp.md +++ b/tools/ppc-manual/alu/cmp.md @@ -67,13 +67,15 @@ CR[BF] <- signed_compare(a, b) || XER[SO] ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -81,37 +83,41 @@ CR[BF] <- signed_compare(a, b) || XER[SO] ## Implementation References **`cmp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:523`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L523) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:13`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L13) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:749`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L749) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:863-885`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L863-L885) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:523`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L523) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:27`](../../../crates/sylpheed-ppc/src/opcode.rs#L27) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:864`](../../../crates/sylpheed-ppc/src/decoder.rs#L864) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::cmp => { - let bf = instr.crfd(); - if instr.l() { - let ra = ctx.gpr[instr.ra()] as i64; - let rb = ctx.gpr[instr.rb()] as i64; - ctx.cr[bf] = crate::context::CrField { - lt: ra < rb, - gt: ra > rb, - eq: ra == rb, - so: ctx.xer_so != 0, - }; - } else { - let ra = ctx.gpr[instr.ra()] as i32; - let rb = ctx.gpr[instr.rb()] as i32; - ctx.cr[bf] = crate::context::CrField { - lt: ra < rb, - gt: ra > rb, - eq: ra == rb, - so: ctx.xer_so != 0, - }; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_cmp(PPCHIRBuilder& f, const InstrData& i) { + // if L = 0 then + // a <- EXTS((RA)[32:63]) + // b <- EXTS((RB)[32:63]) + // else + // a <- (RA) + // b <- (RB) + // if a < b then + // c <- 0b100 + // else if a > b then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + uint32_t BF = i.X.RT >> 2; + uint32_t L = i.X.RT & 1; + Value* lhs; + Value* rhs; + if (L) { + lhs = f.LoadGPR(i.X.RA); + rhs = f.LoadGPR(i.X.RB); + } else { + lhs = f.Truncate(f.LoadGPR(i.X.RA), INT32_TYPE); + rhs = f.Truncate(f.LoadGPR(i.X.RB), INT32_TYPE); + } + f.UpdateCR(BF, lhs, rhs); + return 0; +} ```
diff --git a/tools/ppc-manual/alu/cmpi.md b/tools/ppc-manual/alu/cmpi.md index b74c758a..c16aa5cf 100644 --- a/tools/ppc-manual/alu/cmpi.md +++ b/tools/ppc-manual/alu/cmpi.md @@ -66,13 +66,15 @@ CR[BF] <- signed_compare(a, b) || XER[SO] ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,40 +82,39 @@ CR[BF] <- signed_compare(a, b) || XER[SO] ## Implementation References **`cmpi`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmpi"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:552`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L552) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:13`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L13) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:335`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L335) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:824-849`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L824-L849) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmpi"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:552`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L552) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:28`](../../../crates/sylpheed-ppc/src/opcode.rs#L28) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:450`](../../../crates/sylpheed-ppc/src/decoder.rs#L450) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::cmpi => { - let bf = instr.crfd(); - if instr.l() { - // 64-bit compare. Compare directly so boundary i64 values - // (e.g. ra=i64::MIN, imm=1) don't mis-sign through a - // wrapped subtract. - let ra = ctx.gpr[instr.ra()] as i64; - let imm = instr.simm16() as i64; - ctx.cr[bf] = crate::context::CrField { - lt: ra < imm, - gt: ra > imm, - eq: ra == imm, - so: ctx.xer_so != 0, - }; - } else { - let ra = ctx.gpr[instr.ra()] as i32; - let imm = instr.simm16() as i32; - ctx.cr[bf] = crate::context::CrField { - lt: ra < imm, - gt: ra > imm, - eq: ra == imm, - so: ctx.xer_so != 0, - }; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_cmpi(PPCHIRBuilder& f, const InstrData& i) { + // if L = 0 then + // a <- EXTS((RA)[32:63]) + // else + // a <- (RA) + // if a < EXTS(SI) then + // c <- 0b100 + // else if a > EXTS(SI) then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + uint32_t BF = i.D.RT >> 2; + uint32_t L = i.D.RT & 1; + Value* lhs; + Value* rhs; + if (L) { + lhs = f.LoadGPR(i.D.RA); + rhs = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + } else { + lhs = f.Truncate(f.LoadGPR(i.D.RA), INT32_TYPE); + rhs = f.LoadConstantInt32(int32_t(XEEXTS16(i.D.DS))); + } + f.UpdateCR(BF, lhs, rhs); + return 0; +} ```
diff --git a/tools/ppc-manual/alu/cmpl.md b/tools/ppc-manual/alu/cmpl.md index 82ee3a5b..1d411631 100644 --- a/tools/ppc-manual/alu/cmpl.md +++ b/tools/ppc-manual/alu/cmpl.md @@ -67,13 +67,15 @@ CR[BF] <- unsigned_compare(a, b) || XER[SO] ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -81,23 +83,41 @@ CR[BF] <- unsigned_compare(a, b) || XER[SO] ## Implementation References **`cmpl`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmpl"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:579`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L579) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:13`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L13) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:761`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L761) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:886-894`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L886-L894) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmpl"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:579`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L579) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:29`](../../../crates/sylpheed-ppc/src/opcode.rs#L29) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:876`](../../../crates/sylpheed-ppc/src/decoder.rs#L876) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::cmpl => { - let bf = instr.crfd(); - if instr.l() { - ctx.update_cr_unsigned(bf, ctx.gpr[instr.ra()], ctx.gpr[instr.rb()]); - } else { - ctx.update_cr_unsigned(bf, ctx.gpr[instr.ra()] as u32 as u64, ctx.gpr[instr.rb()] as u32 as u64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_cmpl(PPCHIRBuilder& f, const InstrData& i) { + // if L = 0 then + // a <- i32.0 || (RA)[32:63] + // b <- i32.0 || (RB)[32:63] + // else + // a <- (RA) + // b <- (RB) + // if a u b then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + uint32_t BF = i.X.RT >> 2; + uint32_t L = i.X.RT & 1; + Value* lhs; + Value* rhs; + if (L) { + lhs = f.LoadGPR(i.X.RA); + rhs = f.LoadGPR(i.X.RB); + } else { + lhs = f.Truncate(f.LoadGPR(i.X.RA), INT32_TYPE); + rhs = f.Truncate(f.LoadGPR(i.X.RB), INT32_TYPE); + } + f.UpdateCR(BF, lhs, rhs, false); + return 0; +} ```
diff --git a/tools/ppc-manual/alu/cmpli.md b/tools/ppc-manual/alu/cmpli.md index 526a675e..8a3491fb 100644 --- a/tools/ppc-manual/alu/cmpli.md +++ b/tools/ppc-manual/alu/cmpli.md @@ -65,13 +65,15 @@ CR[BF] <- unsigned_compare(a, b) || XER[SO] ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -79,27 +81,39 @@ CR[BF] <- unsigned_compare(a, b) || XER[SO] ## Implementation References **`cmpli`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmpli"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:608`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L608) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:13`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L13) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:334`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L334) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:850-862`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L850-L862) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cmpli"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:608`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L608) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:30`](../../../crates/sylpheed-ppc/src/opcode.rs#L30) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:449`](../../../crates/sylpheed-ppc/src/decoder.rs#L449) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::cmpli => { - let bf = instr.crfd(); - if instr.l() { - let ra = ctx.gpr[instr.ra()]; - let imm = instr.uimm16() as u64; - ctx.update_cr_unsigned(bf, ra, imm); - } else { - let ra = ctx.gpr[instr.ra()] as u32 as u64; - let imm = instr.uimm16() as u64; - ctx.update_cr_unsigned(bf, ra, imm); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_cmpli(PPCHIRBuilder& f, const InstrData& i) { + // if L = 0 then + // a <- i32.0 || (RA)[32:63] + // else + // a <- (RA) + // if a u i48.0 || SI then + // c <- 0b010 + // else + // c <- 0b001 + // CR[4×BF+32:4×BF+35] <- c || XER[SO] + uint32_t BF = i.D.RT >> 2; + uint32_t L = i.D.RT & 1; + Value* lhs; + Value* rhs; + if (L) { + lhs = f.LoadGPR(i.D.RA); + rhs = f.LoadConstantUint64(i.D.DS); + } else { + lhs = f.Truncate(f.LoadGPR(i.D.RA), INT32_TYPE); + rhs = f.LoadConstantUint32(i.D.DS); + } + f.UpdateCR(BF, lhs, rhs, false); + return 0; +} ```
diff --git a/tools/ppc-manual/alu/cntlzdx.md b/tools/ppc-manual/alu/cntlzdx.md index 68f3767e..002107e8 100644 --- a/tools/ppc-manual/alu/cntlzdx.md +++ b/tools/ppc-manual/alu/cntlzdx.md @@ -66,13 +66,15 @@ RA <- zero_extend(n) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,19 +82,27 @@ RA <- zero_extend(n) ## Implementation References **`cntlzdx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cntlzdx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:674`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L674) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:15`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L15) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:767`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L767) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:615-619`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L615-L619) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cntlzdx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:674`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L674) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:32`](../../../crates/sylpheed-ppc/src/opcode.rs#L32) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:882`](../../../crates/sylpheed-ppc/src/decoder.rs#L882) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::cntlzdx => { - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()].leading_zeros() as u64; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_cntlzdx(PPCHIRBuilder& f, const InstrData& i) { + // n <- 0 + // do while n < 64 + // if (RS)[n] = 1 then leave n + // n <- n + 1 + // RA <- n + Value* v = f.CountLeadingZeros(f.LoadGPR(i.X.RT)); + v = f.ZeroExtend(v, INT64_TYPE); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
diff --git a/tools/ppc-manual/alu/cntlzwx.md b/tools/ppc-manual/alu/cntlzwx.md index d764154d..88828c79 100644 --- a/tools/ppc-manual/alu/cntlzwx.md +++ b/tools/ppc-manual/alu/cntlzwx.md @@ -66,13 +66,15 @@ RA <- zero_extend(n) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,21 +82,27 @@ RA <- zero_extend(n) ## Implementation References **`cntlzwx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cntlzwx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:689`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L689) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:15`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L15) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:758`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L758) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:608-614`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L608-L614) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cntlzwx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:689`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L689) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:33`](../../../crates/sylpheed-ppc/src/opcode.rs#L33) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:873`](../../../crates/sylpheed-ppc/src/decoder.rs#L873) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::cntlzwx => { - // Result is 0..=32, fits in u32 with bit 31 always zero, so the - // CR0 view is benign — use the catch-all 32-bit form for consistency. - ctx.gpr[instr.ra()] = (ctx.gpr[instr.rs()] as u32).leading_zeros() as u64; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_cntlzwx(PPCHIRBuilder& f, const InstrData& i) { + // n <- 32 + // do while n < 64 + // if (RS)[n] = 1 then leave n + // n <- n + 1 + // RA <- n - 32 + Value* v = f.CountLeadingZeros(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE)); + v = f.ZeroExtend(v, INT64_TYPE); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -106,7 +114,7 @@ RA <- zero_extend(n) - **`RA = 32` when the low 32 bits are zero**, regardless of the high 32 bits. A common pitfall: `cntlzw` after computing a 64-bit value can give a counter-intuitive result when the leading 1-bit lives in the high half. - **`RA = 0` when bit 32 (the sign bit of the low word) is set.** This makes `cntlzw RA, RS; cmpwi RA, 0` a one-instruction-pair "is the low half negative" test, though `srawi RA, RS, 31` is more idiomatic. - **High 32 bits of the result are zero.** `RA[0:31] = 0`, `RA[32:63] = count`. -- **`Rc=1` CR0 update is small-positive-only.** Result fits in 6 bits; xenia's `as i32 as i64` truncation in [`interpreter.rs:404`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L404) is harmless. CR0 will be `EQ` only when `RS[32]` (sign bit of low word) is 1, otherwise `GT`. +- **`Rc=1` CR0 update is small-positive-only.** Result fits in 6 bits; xenia's `as i32 as i64` truncation in [`interpreter.rs:404`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) is harmless. CR0 will be `EQ` only when `RS[32]` (sign bit of low word) is 1, otherwise `GT`. - **Useful for `floor(log2)` of a 32-bit value.** `31 - cntlzw(x)` for nonzero `x`. ## Related Instructions diff --git a/tools/ppc-manual/alu/divdux.md b/tools/ppc-manual/alu/divdux.md index 1ea26a1b..c0f33ed7 100644 --- a/tools/ppc-manual/alu/divdux.md +++ b/tools/ppc-manual/alu/divdux.md @@ -70,13 +70,15 @@ RT <- (RA) /u (RB) ; undefined if RB=0 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,31 +86,37 @@ RT <- (RA) /u (RB) ; undefined if RB=0 ## Implementation References **`divdux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divdux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:217`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L217) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:21`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L21) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:876`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L876) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:480-496`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L480-L496) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divdux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:217`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L217) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:52`](../../../crates/sylpheed-ppc/src/opcode.rs#L52) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:991`](../../../crates/sylpheed-ppc/src/decoder.rs#L991) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::divdux => { - let ra = ctx.gpr[instr.ra()]; - let rb = ctx.gpr[instr.rb()]; - let ov = overflow::divd_ov_unsigned(rb); - if ov { - ctx.gpr[instr.rd()] = 0; - } else { - ctx.gpr[instr.rd()] = ra / rb; - } - if instr.oe() { - overflow::apply(ctx, ov); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_divdux(PPCHIRBuilder& f, const InstrData& i) { + // dividend <- (RA) + // divisor <- (RB) + // if divisor = 0 then + // if OE = 1 then + // XER[OV] <- 1 + // return + // RT <- dividend ÷ divisor + Value* divisor = f.LoadGPR(i.XO.RB); + // TODO(benvanik): check if zero + // if OE=1, set XER[OV] = 1 + // else skip the divide + Value* v = f.Div(f.LoadGPR(i.XO.RA), divisor, ARITHMETIC_UNSIGNED); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + // If we are OE=1 we need to clear the overflow bit. + // e.update_xer_with_overflow(e.get_uint64(0)); + XEINSTRNOTIMPLEMENTED(); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -116,10 +124,10 @@ RT <- (RA) /u (RB) ; undefined if RB=0 ## Special Cases & Edge Conditions -- **Single undefined case.** Division by zero (`RB == 0`). There is no `INT_MIN/−1` overflow because both operands are unsigned. Xenia-rs returns 0 for the divide-by-zero case ([`interpreter.rs:306`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L306)); spec leaves `RT` boundedly undefined. +- **Single undefined case.** Division by zero (`RB == 0`). There is no `INT_MIN/−1` overflow because both operands are unsigned. Xenia-rs returns 0 for the divide-by-zero case ([`interpreter.rs:306`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)); spec leaves `RT` boundedly undefined. - **No trap on Xenon.** As with [`divdx`](divdx.md), the processor does not raise an exception; consuming code must guard `RB` first (typically `cmpdi rb, 0; beq skip`). - **`OE=1` should set `XER[OV]`** on `RB == 0`; xenia-rs ignores `OE` here. -- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:311`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L311) uses `as i64` directly, so the CR0 sign comparison reflects the full 64-bit unsigned quotient cast to signed. For very large unsigned quotients (`> INT64_MAX`) this CR0 will report `LT` even though the unsigned interpretation is positive — a rare but real source of CR-misuse bugs. +- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:311`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i64` directly, so the CR0 sign comparison reflects the full 64-bit unsigned quotient cast to signed. For very large unsigned quotients (`> INT64_MAX`) this CR0 will report `LT` even though the unsigned interpretation is positive — a rare but real source of CR-misuse bugs. - **Slow.** Same ~70-cycle non-pipelined cost as the signed variant; consider reciprocal multiply for hot loops. - **Truncating quotient.** Same C-style toward-zero rounding (trivially equal to floor for unsigned). diff --git a/tools/ppc-manual/alu/divdx.md b/tools/ppc-manual/alu/divdx.md index 581b428c..8f37fb1d 100644 --- a/tools/ppc-manual/alu/divdx.md +++ b/tools/ppc-manual/alu/divdx.md @@ -70,13 +70,15 @@ RT <- (RA) /s (RB) ; undefined if RB=0 or (RA=-2^63 and RB ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,31 +86,37 @@ RT <- (RA) /s (RB) ; undefined if RB=0 or (RA=-2^63 and RB ## Implementation References **`divdx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divdx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:192`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L192) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:21`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L21) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:878`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L878) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:463-479`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L463-L479) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divdx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:192`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L192) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:53`](../../../crates/sylpheed-ppc/src/opcode.rs#L53) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:993`](../../../crates/sylpheed-ppc/src/decoder.rs#L993) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::divdx => { - let ra = ctx.gpr[instr.ra()] as i64; - let rb = ctx.gpr[instr.rb()] as i64; - let ov = overflow::divd_ov_signed(ra, rb); - if ov { - ctx.gpr[instr.rd()] = 0; - } else { - ctx.gpr[instr.rd()] = (ra / rb) as u64; - } - if instr.oe() { - overflow::apply(ctx, ov); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_divdx(PPCHIRBuilder& f, const InstrData& i) { + // dividend <- (RA) + // divisor <- (RB) + // if divisor = 0 then + // if OE = 1 then + // XER[OV] <- 1 + // return + // RT <- dividend ÷ divisor + Value* divisor = f.LoadGPR(i.XO.RB); + // TODO(benvanik): check if zero + // if OE=1, set XER[OV] = 1 + // else skip the divide + Value* v = f.Div(f.LoadGPR(i.XO.RA), divisor); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + // If we are OE=1 we need to clear the overflow bit. + // e.update_xer_with_overflow(e.get_uint64(0)); + XEINSTRNOTIMPLEMENTED(); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -116,10 +124,10 @@ RT <- (RA) /s (RB) ; undefined if RB=0 or (RA=-2^63 and RB ## Special Cases & Edge Conditions -- **Two undefined-behaviour cases.** Division by zero (`RB == 0`) and signed-min divided by negative-one (`RA == INT64_MIN && RB == -1`, which would mathematically produce `2^63`, unrepresentable in `i64`). PowerISA leaves `RT` *boundedly undefined* in both cases; **xenia-rs returns 0** ([`interpreter.rs:293`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L293)). Matching this behaviour bit-for-bit is a defacto-spec on Xenon. +- **Two undefined-behaviour cases.** Division by zero (`RB == 0`) and signed-min divided by negative-one (`RA == INT64_MIN && RB == -1`, which would mathematically produce `2^63`, unrepresentable in `i64`). PowerISA leaves `RT` *boundedly undefined* in both cases; **xenia-rs returns 0** ([`interpreter.rs:293`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). Matching this behaviour bit-for-bit is a defacto-spec on Xenon. - **No exception raised.** Xenon does not trap on either undefined case; the consuming code is expected to have validated `RB` first, e.g. with `cmpdi`/`bne`. If you need a trap, follow the divide with [`tw`](../control/tw.md)/`twi` (these live outside the ALU page set). - **`OE=1` should set `XER[OV]`** for both undefined cases plus any operand triggering overflow; xenia-rs does not implement the `OE` branch. -- **`Rc=1` CR0 update is correctly 64-bit here.** Unlike most ALU pages, [`interpreter.rs:298`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L298) uses `as i64` (no `as i32` truncation) — divide is one of the few xenia-rs instructions that already matches Xenon spec for the CR0 width. +- **`Rc=1` CR0 update is correctly 64-bit here.** Unlike most ALU pages, [`interpreter.rs:298`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i64` (no `as i32` truncation) — divide is one of the few xenia-rs instructions that already matches Xenon spec for the CR0 width. - **Latency.** Integer divide is the slowest ALU instruction on Xenon — 70+ cycles, non-pipelined. Hot inner loops avoid it via reciprocal-multiply or shift; expect to see `mulhwu`-based reciprocals in optimised disassembly. - **Rounds toward zero.** The signed quotient truncates toward zero, matching C99/C++11 `/` semantics. Use [`mulldx`](mulldx.md) and a subtract to recover the remainder; there is no `divmod` instruction. diff --git a/tools/ppc-manual/alu/divwux.md b/tools/ppc-manual/alu/divwux.md index 713d7f0c..dfac6b68 100644 --- a/tools/ppc-manual/alu/divwux.md +++ b/tools/ppc-manual/alu/divwux.md @@ -70,13 +70,15 @@ RT <- ((RA)[32:63] /u (RB)[32:63]) zero-extended to 64 ; undefined if RB=0 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,32 +86,40 @@ RT <- ((RA)[32:63] /u (RB)[32:63]) zero-extended to 64 ; undefined if RB=0 ## Implementation References **`divwux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divwux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:269`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L269) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:21`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L21) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:877`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L877) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:413-430`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L413-L430) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divwux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:269`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L269) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:54`](../../../crates/sylpheed-ppc/src/opcode.rs#L54) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:992`](../../../crates/sylpheed-ppc/src/decoder.rs#L992) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::divwux => { - // PPCBUG-020: 32-bit ABI CR0 view. - let ra = ctx.gpr[instr.ra()] as u32; - let rb = ctx.gpr[instr.rb()] as u32; - let ov = overflow::divw_ov_unsigned(rb); - if ov { - ctx.gpr[instr.rd()] = 0; - } else { - ctx.gpr[instr.rd()] = (ra / rb) as u64; - } - if instr.oe() { - overflow::apply(ctx, ov); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as u32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_divwux(PPCHIRBuilder& f, const InstrData& i) { + // dividend[0:31] <- (RA)[32:63] + // divisor[0:31] <- (RB)[32:63] + // if divisor = 0 then + // if OE = 1 then + // XER[OV] <- 1 + // return + // RT[32:63] <- dividend ÷ divisor + // RT[0:31] <- undefined + Value* divisor = f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE); + // TODO(benvanik): check if zero + // if OE=1, set XER[OV] = 1 + // else skip the divide + Value* v = f.Div(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), divisor, + ARITHMETIC_UNSIGNED); + v = f.ZeroExtend(v, INT64_TYPE); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + // If we are OE=1 we need to clear the overflow bit. + // e.update_xer_with_overflow(e.get_uint64(0)); + XEINSTRNOTIMPLEMENTED(); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -118,10 +128,10 @@ RT <- ((RA)[32:63] /u (RB)[32:63]) zero-extended to 64 ; undefined if RB=0 ## Special Cases & Edge Conditions - **32-bit operands, zero-extended result.** Both `RA` and `RB` are read as their low 32 bits, unsigned (`as u32`); the quotient is computed as `u32`, then *zero-extended* to 64 bits. The high 32 bits of `RA`/`RB` are ignored on input and the high 32 bits of `RT` are zero on output. -- **Single undefined case.** Division by zero (`RB == 0`); xenia-rs returns 0 ([`interpreter.rs:251`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L251)). No `INT_MIN/-1` case because the operands are unsigned. +- **Single undefined case.** Division by zero (`RB == 0`); xenia-rs returns 0 ([`interpreter.rs:251`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). No `INT_MIN/-1` case because the operands are unsigned. - **No trap on Xenon.** Same as [`divdx`](divdx.md) — silent undefined result. - **`OE=1` should set `XER[OV]` on `RB == 0`**; xenia-rs ignores this. -- **`Rc=1` CR0 update.** [`interpreter.rs:256`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L256) uses `as i32 as i64` — for an unsigned 32-bit quotient stored in the low 32 bits with high zeros, this matches spec exactly; the i32 view will be negative iff the unsigned quotient ≥ 2^31. Worth flagging when comparing CR0 against zero after a large `divwu`. +- **`Rc=1` CR0 update.** [`interpreter.rs:256`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i32 as i64` — for an unsigned 32-bit quotient stored in the low 32 bits with high zeros, this matches spec exactly; the i32 view will be negative iff the unsigned quotient ≥ 2^31. Worth flagging when comparing CR0 against zero after a large `divwu`. - **Truncating quotient.** Floor division for non-negative integers; matches C `unsigned` semantics. - **Same slow non-pipelined latency** as `divw`. diff --git a/tools/ppc-manual/alu/divwx.md b/tools/ppc-manual/alu/divwx.md index 61eea801..dc277734 100644 --- a/tools/ppc-manual/alu/divwx.md +++ b/tools/ppc-manual/alu/divwx.md @@ -70,13 +70,15 @@ RT <- ((RA)[32:63] /s (RB)[32:63]) sign-extended to 64 ; undefined if RB=0 or ov ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,33 +86,39 @@ RT <- ((RA)[32:63] /s (RB)[32:63]) sign-extended to 64 ; undefined if RB=0 or ov ## Implementation References **`divwx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divwx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:242`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L242) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:21`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L21) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:879`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L879) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:394-412`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L394-L412) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="divwx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:242`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L242) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:55`](../../../crates/sylpheed-ppc/src/opcode.rs#L55) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:994`](../../../crates/sylpheed-ppc/src/decoder.rs#L994) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::divwx => { - // PPCBUG-010+011 coupled: 32-bit ABI. Quotient zero-extended to u64 - // (canary explicitly uses ZeroExtend(v, INT64_TYPE)). CR0 view via i32. - let ra = ctx.gpr[instr.ra()] as i32; - let rb = ctx.gpr[instr.rb()] as i32; - let ov = overflow::divw_ov_signed(ra, rb); - if ov { - ctx.gpr[instr.rd()] = 0; - } else { - ctx.gpr[instr.rd()] = (ra / rb) as u32 as u64; - } - if instr.oe() { - overflow::apply(ctx, ov); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as u32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_divwx(PPCHIRBuilder& f, const InstrData& i) { + // dividend[0:31] <- (RA)[32:63] + // divisor[0:31] <- (RB)[32:63] + // if divisor = 0 then + // if OE = 1 then + // XER[OV] <- 1 + // return + // RT[32:63] <- dividend ÷ divisor + // RT[0:31] <- undefined + Value* divisor = f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE); + // TODO(benvanik): check if zero + // if OE=1, set XER[OV] = 1 + // else skip the divide + Value* v = f.Div(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), divisor); + v = f.ZeroExtend(v, INT64_TYPE); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + // If we are OE=1 we need to clear the overflow bit. + // e.update_xer_with_overflow(e.get_uint64(0)); + XEINSTRNOTIMPLEMENTED(); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -119,10 +127,10 @@ RT <- ((RA)[32:63] /s (RB)[32:63]) sign-extended to 64 ; undefined if RB=0 or ov ## Special Cases & Edge Conditions - **32-bit operands, sign-extended result.** Both `RA` and `RB` are read as their low 32 bits, signed; the quotient is computed as `i32`, then sign-extended to 64 bits before being stored in `RT`. The high 32 bits of `RA`/`RB` are *ignored*. -- **Two undefined cases:** `RB == 0` and `RA == INT32_MIN && RB == -1` (quotient `2^31` is unrepresentable). Xenia-rs returns 0 for both ([`interpreter.rs:238`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L238)); PowerISA leaves `RT` boundedly undefined. +- **Two undefined cases:** `RB == 0` and `RA == INT32_MIN && RB == -1` (quotient `2^31` is unrepresentable). Xenia-rs returns 0 for both ([`interpreter.rs:238`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)); PowerISA leaves `RT` boundedly undefined. - **No trap on Xenon.** Like [`divdx`](divdx.md), the processor silently produces an undefined value instead of raising an exception. - **`OE=1` should set `XER[OV]`** in both undefined cases; xenia-rs does not implement this. -- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:243`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L243) uses `as i32 as i64`. This is *correct* for `divw` because the result is already a sign-extended 32-bit value — high bits agree with the low-32 sign extension. So spec and xenia agree for this instruction. +- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:243`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i32 as i64`. This is *correct* for `divw` because the result is already a sign-extended 32-bit value — high bits agree with the low-32 sign extension. So spec and xenia agree for this instruction. - **Truncating quotient.** Rounds toward zero, matching C `/` for `int32_t`. - **Slow.** Same ~30-cycle non-pipelined cost as 64-bit divide; faster than `divd` because the underlying datapath is narrower but still much slower than multiply-then-shift reciprocal sequences. diff --git a/tools/ppc-manual/alu/eieio.md b/tools/ppc-manual/alu/eieio.md index 4e5dac40..f5c77113 100644 --- a/tools/ppc-manual/alu/eieio.md +++ b/tools/ppc-manual/alu/eieio.md @@ -61,13 +61,15 @@ enforce in-order execution of I/O ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -75,17 +77,17 @@ enforce in-order execution of I/O ## Implementation References **`eieio`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="eieio"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:749`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L749) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:23`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L23) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:844`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L844) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1691-1693`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1691-L1693) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="eieio"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:749`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L749) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:57`](../../../crates/sylpheed-ppc/src/opcode.rs#L57) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:959`](../../../crates/sylpheed-ppc/src/decoder.rs#L959) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sync | PpcOpcode::eieio | PpcOpcode::isync => { - ctx.pc += 4; - } +```cpp +int InstrEmit_eieio(PPCHIRBuilder& f, const InstrData& i) { + f.MemoryBarrier(); + return 0; +} ```
@@ -96,9 +98,9 @@ enforce in-order execution of I/O - **Memory-ordering barrier for caching-inhibited / guarded storage.** `eieio` ensures all preceding loads/stores to caching-inhibited or guarded memory complete before any subsequent such accesses begin. It is *weaker* than [`sync`](sync.md): it does not order cacheable storage and does not flush the store queue. - **No register or CR effects.** Every operand field is unused; assemblers emit the canonical `0x7c0006ac` word. - **Used at MMIO boundaries.** Driver code touching device registers (e.g. the GPU command processor on Xenon) typically pairs writes with `eieio` to enforce write ordering at the bus. -- **Xenia-rs is a no-op.** The interpreter trivially advances PC ([`interpreter.rs:1267`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1267)). Because xenia-rs is a single-threaded interpreter targeting userland Xbox 360 binaries — which never see real MMIO — this is correct: the host's natural program order suffices. +- **Xenia-rs is a no-op.** The interpreter trivially advances PC ([`interpreter.rs:1267`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). Because xenia-rs is a single-threaded interpreter targeting userland Xbox 360 binaries — which never see real MMIO — this is correct: the host's natural program order suffices. - **Categorised under ALU here**, but operationally it's a memory ordering primitive (xenia-canary places it in `ppc_emit_memory.cc`). Disassembly tools may bin it differently. -- **Distinct from `sync` and `isync`.** All three share xenia's no-op arm in [`interpreter.rs:1266`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1266); on real hardware they have very different semantics and latencies. +- **Distinct from `sync` and `isync`.** All three share xenia's no-op arm in [`interpreter.rs:1266`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs); on real hardware they have very different semantics and latencies. ## Related Instructions diff --git a/tools/ppc-manual/alu/eqvx.md b/tools/ppc-manual/alu/eqvx.md index a3800fd0..7c8c1370 100644 --- a/tools/ppc-manual/alu/eqvx.md +++ b/tools/ppc-manual/alu/eqvx.md @@ -66,13 +66,15 @@ RA <- ~((RS) ^ (RB)) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,23 +82,22 @@ RA <- ~((RS) ^ (RB)) ## Implementation References **`eqvx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="eqvx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:704`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L704) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:25`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L25) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:796`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L796) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:578-586`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L578-L586) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="eqvx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:704`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L704) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:59`](../../../crates/sylpheed-ppc/src/opcode.rs#L59) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:911`](../../../crates/sylpheed-ppc/src/decoder.rs#L911) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::eqvx => { - // PPCBUG-031: `eqv rA, rA, rA` is a common "set to all-ones" idiom; - // 64-bit form gave 0xFFFFFFFFFFFFFFFF but 32-bit ABI expects 0x00000000FFFFFFFF. - let rs32 = ctx.gpr[instr.rs()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - ctx.gpr[instr.ra()] = (!(rs32 ^ rb32)) as u64; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_eqvx(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) == (RB) + Value* ra = f.Not(f.Xor(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB))); + f.StoreGPR(i.X.RA, ra); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + return 0; +} ```
@@ -109,7 +110,7 @@ RA <- ~((RS) ^ (RB)) - **Operand convention is X-form** (`RA` is destination; `RS`, `RB` are sources). - **64-bit operation** on Xenon; `~` is full 64-bit on `u64`. - **No `OE`, no `XER` side effects.** Only `Rc=1` updates `CR0`. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:382`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L382) truncates with `as i32 as i64`. Significant when the high 32 bits of the result differ from the low 32 — e.g. `eqv. RA, RS, RB` with `RS == 0x1_0000_0000`, `RB == 0`: spec sees `0xFFFFFFFE_FFFFFFFF` (`LT`), xenia sees `0xFFFFFFFFFFFFFFFF` (`LT`) — actually both negative here, but the *exact* CR contents differ for finer cases. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:382`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) truncates with `as i32 as i64`. Significant when the high 32 bits of the result differ from the low 32 — e.g. `eqv. RA, RS, RB` with `RS == 0x1_0000_0000`, `RB == 0`: spec sees `0xFFFFFFFE_FFFFFFFF` (`LT`), xenia sees `0xFFFFFFFFFFFFFFFF` (`LT`) — actually both negative here, but the *exact* CR contents differ for finer cases. ## Related Instructions diff --git a/tools/ppc-manual/alu/extsbx.md b/tools/ppc-manual/alu/extsbx.md index 5e736e72..fb0e59a3 100644 --- a/tools/ppc-manual/alu/extsbx.md +++ b/tools/ppc-manual/alu/extsbx.md @@ -65,13 +65,15 @@ RA <- EXTS_8_to_64((RS)[56:63]) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -79,21 +81,25 @@ RA <- EXTS_8_to_64((RS)[56:63]) ## Implementation References **`extsbx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="extsbx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:714`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L714) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:25`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L25) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:849`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L849) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:589-595`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L589-L595) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="extsbx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:714`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L714) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:60`](../../../crates/sylpheed-ppc/src/opcode.rs#L60) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:964`](../../../crates/sylpheed-ppc/src/decoder.rs#L964) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::extsbx => { - // PPCBUG-034: 32-bit ABI — sign-extend byte to i32, write zero-extended. - // PPCBUG-036 (coupled): CR0 must view result as i32, not i64. - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] as i8 as i32 as u32 as u64; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_extsbx(PPCHIRBuilder& f, const InstrData& i) { + // s <- (RS)[56] + // RA[56:63] <- (RS)[56:63] + // RA[0:55] <- i56.s + Value* rt = f.LoadGPR(i.X.RT); + rt = f.SignExtend(f.Truncate(rt, INT8_TYPE), INT64_TYPE); + f.StoreGPR(i.X.RA, rt); + if (i.X.Rc) { + f.UpdateCR(0, rt); + } + return 0; +} ```
@@ -103,7 +109,7 @@ RA <- EXTS_8_to_64((RS)[56:63]) - **Sign-extends the low 8 bits of `RS` to 64 bits.** Bit 56 of `RS` (the sign bit of the byte) becomes bits 0–55 of `RA`; bits 56–63 are copied verbatim. - **Common after a byte load.** `lbz` zero-extends from memory; `extsb` converts the result to a signed-byte view. Many compilers emit this pair; the recent ISA `lba`/`lbau` family is *not* available on the Xenon, so this two-instruction sequence is the canonical pattern. -- **`Rc=1` updates CR0 from the full 64-bit signed value** — but xenia-rs truncates to 32 bits in [`interpreter.rs:384`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L384). For `extsb.` this is harmless because the result fits in 8 bits sign-extended; the low 32 bits already encode the sign correctly. +- **`Rc=1` updates CR0 from the full 64-bit signed value** — but xenia-rs truncates to 32 bits in [`interpreter.rs:384`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). For `extsb.` this is harmless because the result fits in 8 bits sign-extended; the low 32 bits already encode the sign correctly. - **Operand convention** is the X-form one (`RA` destination, `RS` source). Same as the rest of the logical family. - **No `XER` side effects.** - **`RB` field unused.** Set to 0 by assemblers; ignored on decode. diff --git a/tools/ppc-manual/alu/extshx.md b/tools/ppc-manual/alu/extshx.md index 509cdc8c..72b90697 100644 --- a/tools/ppc-manual/alu/extshx.md +++ b/tools/ppc-manual/alu/extshx.md @@ -65,13 +65,15 @@ RA <- EXTS_16_to_64((RS)[48:63]) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -79,21 +81,25 @@ RA <- EXTS_16_to_64((RS)[48:63]) ## Implementation References **`extshx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="extshx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:727`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L727) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:25`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L25) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:847`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L847) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:596-602`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L596-L602) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="extshx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:727`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L727) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:61`](../../../crates/sylpheed-ppc/src/opcode.rs#L61) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:962`](../../../crates/sylpheed-ppc/src/decoder.rs#L962) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::extshx => { - // PPCBUG-035: same shape as extsbx for halfwords. - // PPCBUG-037 (coupled): CR0 i32 view. - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] as i16 as i32 as u32 as u64; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_extshx(PPCHIRBuilder& f, const InstrData& i) { + // s <- (RS)[48] + // RA[48:63] <- (RS)[48:63] + // RA[0:47] <- 48.s + Value* rt = f.LoadGPR(i.X.RT); + rt = f.SignExtend(f.Truncate(rt, INT16_TYPE), INT64_TYPE); + f.StoreGPR(i.X.RA, rt); + if (i.X.Rc) { + f.UpdateCR(0, rt); + } + return 0; +} ```
@@ -103,7 +109,7 @@ RA <- EXTS_16_to_64((RS)[48:63]) - **Sign-extends the low 16 bits of `RS` to 64 bits.** Bit 48 (the sign bit of the half-word) is replicated through bits 0–47 of `RA`. - **Pairs with `lhz`** to convert an unsigned half-word load into a signed half-word value. Note that `lha` already does the sign extension on load — `extsh` is mostly emitted when the half-word is computed in a register first. -- **`Rc=1` CR0 update.** Xenia-rs uses `as i32 as i64` ([`interpreter.rs:389`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L389)) — harmless here because the sign-extended 16-bit value fits in 32 bits exactly. +- **`Rc=1` CR0 update.** Xenia-rs uses `as i32 as i64` ([`interpreter.rs:389`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)) — harmless here because the sign-extended 16-bit value fits in 32 bits exactly. - **Operand convention** is the X-form one (`RA` destination, `RS` source). - **No `XER` side effects.** - **`RB` field unused.** diff --git a/tools/ppc-manual/alu/extswx.md b/tools/ppc-manual/alu/extswx.md index 18aaba2e..de300b08 100644 --- a/tools/ppc-manual/alu/extswx.md +++ b/tools/ppc-manual/alu/extswx.md @@ -65,13 +65,15 @@ RA <- EXTS_32_to_64((RS)[32:63]) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -79,19 +81,25 @@ RA <- EXTS_32_to_64((RS)[32:63]) ## Implementation References **`extswx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="extswx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:740`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L740) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:25`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L25) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:852`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L852) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:603-607`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L603-L607) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="extswx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:740`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L740) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:62`](../../../crates/sylpheed-ppc/src/opcode.rs#L62) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:967`](../../../crates/sylpheed-ppc/src/decoder.rs#L967) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::extswx => { - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] as i32 as i64 as u64; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_extswx(PPCHIRBuilder& f, const InstrData& i) { + // s <- (RS)[32] + // RA[32:63] <- (RS)[32:63] + // RA[0:31] <- i32.s + Value* rt = f.LoadGPR(i.X.RT); + rt = f.SignExtend(f.Truncate(rt, INT32_TYPE), INT64_TYPE); + f.StoreGPR(i.X.RA, rt); + if (i.X.Rc) { + f.UpdateCR(0, rt); + } + return 0; +} ```
@@ -101,7 +109,7 @@ RA <- EXTS_32_to_64((RS)[32:63]) - **Sign-extends the low 32 bits of `RS` to 64 bits.** Bit 32 (sign bit of the word) is replicated through bits 0–31 of `RA`. - **Used heavily in 32-to-64-bit promotion.** Most Xbox 360 ABI parameters are 32-bit; promoting a 32-bit `int` to a 64-bit GPR requires this instruction. Many functions emit it on entry to canonicalise their argument registers. -- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:399`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L399) uses `as i64` (no truncation) — one of the few xenia-rs sites where the spec width is honoured. The signed compare in CR0 reflects the full sign-extended value. +- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:399`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i64` (no truncation) — one of the few xenia-rs sites where the spec width is honoured. The signed compare in CR0 reflects the full sign-extended value. - **Operand convention** is the X-form one (`RA` destination, `RS` source). - **No `XER` side effects.** - **`RB` field unused.** diff --git a/tools/ppc-manual/alu/isync.md b/tools/ppc-manual/alu/isync.md index 75592421..93adede8 100644 --- a/tools/ppc-manual/alu/isync.md +++ b/tools/ppc-manual/alu/isync.md @@ -61,13 +61,15 @@ instruction-stream synchronisation — discards speculative state. ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -75,17 +77,18 @@ instruction-stream synchronisation — discards speculative state. ## Implementation References **`isync`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="isync"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:759`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L759) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:32`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L32) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:714`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L714) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1691-1693`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1691-L1693) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="isync"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:759`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L759) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:99`](../../../crates/sylpheed-ppc/src/opcode.rs#L99) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:829`](../../../crates/sylpheed-ppc/src/decoder.rs#L829) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sync | PpcOpcode::eieio | PpcOpcode::isync => { - ctx.pc += 4; - } +```cpp +int InstrEmit_isync(PPCHIRBuilder& f, const InstrData& i) { + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} ```
@@ -97,7 +100,7 @@ instruction-stream synchronisation — discards speculative state. - **Stronger than [`sync`](sync.md) for instruction stream**, weaker for memory stream — `isync` does not order stores against later loads. It only forces a fetch refresh. - **Common idiom: `dcbf` / `icbi` / `sync` / `isync`** — flush data cache, invalidate instruction cache, drain memory, refetch — used by JITs and self-modifying loaders. - **No operands.** Encoded as a fixed-form `XL` instruction; assemblers always emit `0x4c00012c`. -- **Xenia-rs is a no-op.** [`interpreter.rs:1267`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1267) handles `sync`/`eieio`/`isync` together. Because xenia interprets in straight-line program order without any speculative instruction cache, no barrier behaviour is needed for correctness. +- **Xenia-rs is a no-op.** [`interpreter.rs:1267`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) handles `sync`/`eieio`/`isync` together. Because xenia interprets in straight-line program order without any speculative instruction cache, no barrier behaviour is needed for correctness. - **Privilege level: user.** Unlike most cache management ops, `isync` is unprivileged and frequently appears in userland trampolines. ## Related Instructions diff --git a/tools/ppc-manual/alu/mulhdux.md b/tools/ppc-manual/alu/mulhdux.md index 10d93588..46cdc6ee 100644 --- a/tools/ppc-manual/alu/mulhdux.md +++ b/tools/ppc-manual/alu/mulhdux.md @@ -67,13 +67,15 @@ RT <- ((RA) * (RB))[0:63] ; high 64 of unsigned 64×64 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -81,23 +83,27 @@ RT <- ((RA) * (RB))[0:63] ; high 64 of unsigned 64×64 ## Implementation References **`mulhdux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhdux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:311`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L311) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:860`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L860) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:454-462`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L454-L462) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhdux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:311`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L311) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:188`](../../../crates/sylpheed-ppc/src/opcode.rs#L188) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:975`](../../../crates/sylpheed-ppc/src/decoder.rs#L975) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mulhdux => { - let ra = ctx.gpr[instr.ra()] as u128; - let rb = ctx.gpr[instr.rb()] as u128; - ctx.gpr[instr.rd()] = (ra.wrapping_mul(rb) >> 64) as u64; - if instr.rc_bit() { - ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_mulhdux(PPCHIRBuilder& f, const InstrData& i) { + // RT <- ((RA) × (RB) as 128)[0:63] + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + } + Value* v = + f.MulHi(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB), ARITHMETIC_UNSIGNED); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -107,7 +113,7 @@ RT <- ((RA) * (RB))[0:63] ; high 64 of unsigned 64×64 - **Returns the high 64 bits of an unsigned 64×64 product.** Operands are zero-extended (treated as unsigned) before multiplication. Pair with [`mulldx`](mulldx.md) for the low 64 bits to form a full 128-bit unsigned product. - **No `OE` bit.** No overflow signal — the high half is a defined function of the inputs even when the product fills 128 bits. -- **Xenia uses native `u128`.** [`interpreter.rs:284`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L284) widens both operands then shifts. Note `as u128` *zero*-extends, in contrast to [`mulhdx`](mulhdx.md)'s `as i64 as i128` which sign-extends — this is the entire semantic difference. +- **Xenia uses native `u128`.** [`interpreter.rs:284`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) widens both operands then shifts. Note `as u128` *zero*-extends, in contrast to [`mulhdx`](mulhdx.md)'s `as i64 as i128` which sign-extends — this is the entire semantic difference. - **`Rc=1` CR0 update is correctly 64-bit.** Uses `as i64` directly. Because the high half is unsigned, treating it as signed for CR0 means very large unsigned values appear `LT` — keep this in mind when interpreting the CR0 bits after `mulhdu.`. - **Used in reciprocal-multiply division strategies.** Compilers may strength-reduce divide-by-constant into `mulhdu` plus a shift; appears in optimised disassembly. - **Slow.** Same multi-cycle cost as the signed variant. diff --git a/tools/ppc-manual/alu/mulhdx.md b/tools/ppc-manual/alu/mulhdx.md index b9b49d6f..fa2231a0 100644 --- a/tools/ppc-manual/alu/mulhdx.md +++ b/tools/ppc-manual/alu/mulhdx.md @@ -67,13 +67,15 @@ RT <- ((RA) * (RB))[0:63] ; high 64 of signed 64×64 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -81,23 +83,26 @@ RT <- ((RA) * (RB))[0:63] ; high 64 of signed 64×64 ## Implementation References **`mulhdx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhdx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:297`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L297) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:864`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L864) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:445-453`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L445-L453) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhdx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:297`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L297) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:189`](../../../crates/sylpheed-ppc/src/opcode.rs#L189) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:979`](../../../crates/sylpheed-ppc/src/decoder.rs#L979) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mulhdx => { - let ra = ctx.gpr[instr.ra()] as i64 as i128; - let rb = ctx.gpr[instr.rb()] as i64 as i128; - ctx.gpr[instr.rd()] = (ra.wrapping_mul(rb) >> 64) as u64; - if instr.rc_bit() { - ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_mulhdx(PPCHIRBuilder& f, const InstrData& i) { + // RT <- ((RA) × (RB) as 128)[0:63] + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + } + Value* v = f.MulHi(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -107,8 +112,8 @@ RT <- ((RA) * (RB))[0:63] ; high 64 of signed 64×64 - **Returns the high 64 bits of a signed 64×64 product.** Pair with [`mulldx`](mulldx.md) (which returns the low 64 bits) to obtain the full 128-bit product. Both must be issued separately; PowerPC has no fused multiply-double-wide instruction. - **No `OE` bit.** This XO-form instruction has no overflow-enable variant — there is no "high half overflow" because the high half is always defined. -- **Xenia widens to `i128` natively.** [`interpreter.rs:275`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L275) does the multiply in 128 bits then extracts the high 64. The `i64 as i128` casts ensure signed extension on both sides. -- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:278`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L278) uses `as i64` directly. CR0 reflects the sign of the high half: `LT` if the product is negative, `GT` if positive and large enough to overflow into the high half, `EQ` if the product fits in 64 bits *signed* (so the high half is the sign-extension of the low half — but xenia's check uses raw signed-zero compare, which equates only when the high half is exactly zero, i.e. the product is in `[0, 2^63)`). +- **Xenia widens to `i128` natively.** [`interpreter.rs:275`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) does the multiply in 128 bits then extracts the high 64. The `i64 as i128` casts ensure signed extension on both sides. +- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:278`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i64` directly. CR0 reflects the sign of the high half: `LT` if the product is negative, `GT` if positive and large enough to overflow into the high half, `EQ` if the product fits in 64 bits *signed* (so the high half is the sign-extension of the low half — but xenia's check uses raw signed-zero compare, which equates only when the high half is exactly zero, i.e. the product is in `[0, 2^63)`). - **Use [`mulhdux`](mulhdux.md) for the unsigned high half.** The two instructions differ in whether the operands are sign- or zero-extended before the multiply. - **Slow.** 64-bit multiply is multi-cycle on Xenon; combining `mulhd` with `mulld` for a full 128-bit product roughly doubles the cost. diff --git a/tools/ppc-manual/alu/mulhwux.md b/tools/ppc-manual/alu/mulhwux.md index 4dce5e53..045aa9e9 100644 --- a/tools/ppc-manual/alu/mulhwux.md +++ b/tools/ppc-manual/alu/mulhwux.md @@ -67,13 +67,15 @@ RT <- high_32_of_unsigned_multiply((RA)[32:63], (RB)[32:63]) zero-extended to 64 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -81,25 +83,33 @@ RT <- high_32_of_unsigned_multiply((RA)[32:63], (RB)[32:63]) zero-extended to 64 ## Implementation References **`mulhwux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhwux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:347`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L347) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:862`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L862) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:383-393`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L383-L393) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhwux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:347`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L347) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:190`](../../../crates/sylpheed-ppc/src/opcode.rs#L190) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:977`](../../../crates/sylpheed-ppc/src/decoder.rs#L977) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mulhwux => { - // PPCBUG-020: 32-bit ABI CR0 view. - let ra = ctx.gpr[instr.ra()] as u32 as u64; - let rb = ctx.gpr[instr.rb()] as u32 as u64; - let result = ra.wrapping_mul(rb); - ctx.gpr[instr.rd()] = (result >> 32) & 0xFFFF_FFFF; - if instr.rc_bit() { - ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as u32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_mulhwux(PPCHIRBuilder& f, const InstrData& i) { + // RT[32:64] <- ((RA)[32:63] × (RB)[32:63])[0:31] + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + } + + Value* ratrunc = + f.ZeroExtend(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), INT64_TYPE); + + Value* rbtrunc = + f.ZeroExtend(f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE), INT64_TYPE); + + Value* v = f.Shr(f.Mul(ratrunc, rbtrunc, ARITHMETIC_UNSIGNED), 32); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -107,10 +117,10 @@ RT <- high_32_of_unsigned_multiply((RA)[32:63], (RB)[32:63]) zero-extended to 64 ## Special Cases & Edge Conditions -- **Inputs are the low 32 bits, zero-extended.** `RA[32:63]` and `RB[32:63]` are treated as unsigned, widened to 64-bit `u64`, multiplied; the high 32 bits of the 64-bit product land in `RT[32:63]`. Xenia masks the high 32 bits of `RT` to zero ([`interpreter.rs:231`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L231)). +- **Inputs are the low 32 bits, zero-extended.** `RA[32:63]` and `RB[32:63]` are treated as unsigned, widened to 64-bit `u64`, multiplied; the high 32 bits of the 64-bit product land in `RT[32:63]`. Xenia masks the high 32 bits of `RT` to zero ([`interpreter.rs:231`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). - **Pair with [`mullwx`](mullwx.md) for the full 64-bit unsigned product.** `mullw` returns the low 32 sign-extended; for unsigned use, pair `mulhwu` with `rlwinm` to mask the low half. Xbox 360 compilers commonly emit this combination. - **No `OE` bit.** Same family rule. -- **`Rc=1` CR0 update.** Uses `as i32 as i64` ([`interpreter.rs:234`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L234)). Because the result is bounded by `0xFFFFFFFF` and stored only in the low 32 bits, this CR0 will report `LT` for any unsigned high half ≥ `0x80000000` — a known signed/unsigned interpretation pitfall when `Rc=1` is used with `mulhwu`. +- **`Rc=1` CR0 update.** Uses `as i32 as i64` ([`interpreter.rs:234`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). Because the result is bounded by `0xFFFFFFFF` and stored only in the low 32 bits, this CR0 will report `LT` for any unsigned high half ≥ `0x80000000` — a known signed/unsigned interpretation pitfall when `Rc=1` is used with `mulhwu`. - **Common idiom for multi-precision arithmetic.** `mulhwu` + `mullw` + `addc` chains build extended-precision multiplies entirely in 32-bit ops; useful for cryptographic code that targets the Xenon's 32-bit ABI. - **Multi-cycle latency** like the rest of the multiply family. diff --git a/tools/ppc-manual/alu/mulhwx.md b/tools/ppc-manual/alu/mulhwx.md index 7d0f40ff..d08be710 100644 --- a/tools/ppc-manual/alu/mulhwx.md +++ b/tools/ppc-manual/alu/mulhwx.md @@ -67,13 +67,15 @@ RT <- high_32_of_signed_multiply((RA)[32:63], (RB)[32:63]) sign-extended to 64 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -81,25 +83,33 @@ RT <- high_32_of_signed_multiply((RA)[32:63], (RB)[32:63]) sign-extended to 64 ## Implementation References **`mulhwx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhwx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:326`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L326) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:865`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L865) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:372-382`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L372-L382) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulhwx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:326`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L326) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:191`](../../../crates/sylpheed-ppc/src/opcode.rs#L191) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:980`](../../../crates/sylpheed-ppc/src/decoder.rs#L980) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mulhwx => { - // PPCBUG-020: 32-bit ABI CR0 view. - let ra = ctx.gpr[instr.ra()] as i32 as i64; - let rb = ctx.gpr[instr.rb()] as i32 as i64; - let result = ra.wrapping_mul(rb); - ctx.gpr[instr.rd()] = ((result >> 32) as u32) as u64; - if instr.rc_bit() { - ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as u32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_mulhwx(PPCHIRBuilder& f, const InstrData& i) { + // RT[32:64] <- ((RA)[32:63] × (RB)[32:63])[0:31] + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + } + Value* ratrunc = + f.SignExtend(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), INT64_TYPE); + + Value* rbtrunc = + f.SignExtend(f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE), INT64_TYPE); + + Value* v = f.Sha(f.Mul(ratrunc, rbtrunc), 32); + + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -107,11 +117,11 @@ RT <- high_32_of_signed_multiply((RA)[32:63], (RB)[32:63]) sign-extended to 64 ## Special Cases & Edge Conditions -- **Inputs are the low 32 bits, signed-extended.** `RA[32:63]` and `RB[32:63]` are sign-extended to 64-bit signed values, multiplied, and the *high* 32 bits of the 64-bit product are returned in `RT[32:63]`. The high 32 bits of `RT` are *implementation-defined* per spec but xenia masks them to zero ([`interpreter.rs:222`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L222) `& 0xFFFF_FFFF`). +- **Inputs are the low 32 bits, signed-extended.** `RA[32:63]` and `RB[32:63]` are sign-extended to 64-bit signed values, multiplied, and the *high* 32 bits of the 64-bit product are returned in `RT[32:63]`. The high 32 bits of `RT` are *implementation-defined* per spec but xenia masks them to zero ([`interpreter.rs:222`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) `& 0xFFFF_FFFF`). - **Pair with [`mullwx`](mullwx.md) for the full 64-bit product.** Both can issue independently — no fused 32×32→64 instruction. - **No `OE` bit.** Like all `mulh*` instructions, no overflow flag is produced; the high half is by definition defined. - **Xenia-rs quirk: high 32 bits zeroed.** Because spec says they're "undefined", legitimately matching either zero, sign-extension, or garbage. Xenia chooses zero, which differs from the literal Xenon behaviour (which sign-extends in some microarchitecture cases). For game code that doesn't read those bits, the difference is invisible. -- **`Rc=1` CR0 update.** [`interpreter.rs:225`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L225) uses `as i32 as i64` — operates on the truncated low 32 bits, which is correct for the *defined* portion of the result. +- **`Rc=1` CR0 update.** [`interpreter.rs:225`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i32 as i64` — operates on the truncated low 32 bits, which is correct for the *defined* portion of the result. - **Multi-cycle latency.** Multiply is the slowest pipelined ALU op; `mulhw` shares the divider/multiplier unit. ## Related Instructions diff --git a/tools/ppc-manual/alu/mulldx.md b/tools/ppc-manual/alu/mulldx.md index b4cffb8b..ba4ea294 100644 --- a/tools/ppc-manual/alu/mulldx.md +++ b/tools/ppc-manual/alu/mulldx.md @@ -70,13 +70,15 @@ RT <- ((RA) * (RB))[64:127] ; low 64 of signed 64×64 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,26 +86,26 @@ RT <- ((RA) * (RB))[64:127] ; low 64 of signed 64×64 ## Implementation References **`mulldx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulldx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:368`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L368) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:872`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L872) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:433-444`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L433-L444) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulldx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:368`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L368) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:192`](../../../crates/sylpheed-ppc/src/opcode.rs#L192) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:987`](../../../crates/sylpheed-ppc/src/decoder.rs#L987) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mulldx => { - let ra = ctx.gpr[instr.ra()] as i64; - let rb = ctx.gpr[instr.rb()] as i64; - ctx.gpr[instr.rd()] = ra.wrapping_mul(rb) as u64; - if instr.oe() { - overflow::apply(ctx, overflow::mulld_ov(ra, rb)); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_mulldx(PPCHIRBuilder& f, const InstrData& i) { + // RT <- ((RA) × (RB))[64:127] + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + } + Value* v = f.Mul(f.LoadGPR(i.XO.RA), f.LoadGPR(i.XO.RB)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -113,8 +115,8 @@ RT <- ((RA) * (RB))[64:127] ; low 64 of signed 64×64 - **Returns the low 64 bits of a signed 64×64 product.** Equivalent to `(int64_t)(RA * RB)` modulo `2^64`. Both operands are full 64-bit signed; no truncation on input. - **High bits silently lost.** The high 64 bits of the true product are discarded; pair with [`mulhdx`](mulhdx.md) (signed) or [`mulhdux`](mulhdux.md) (unsigned) to recover them. -- **`OE=1` should set `XER[OV]`** when the 128-bit signed product cannot be represented in 64 bits — i.e. when `mulhd RA, RB` is not the sign-extension of `mulld RA, RB`. **Xenia-rs does not implement** `OE` ([`interpreter.rs:264`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L264) has no `oe()` branch). -- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:269`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L269) uses `as i64` — full 64-bit signed compare. One of the few non-truncating CR0 sites in xenia-rs; means `mulld.` gives spec-correct CR0 even when the result has non-zero high 32 bits. +- **`OE=1` should set `XER[OV]`** when the 128-bit signed product cannot be represented in 64 bits — i.e. when `mulhd RA, RB` is not the sign-extension of `mulld RA, RB`. **Xenia-rs does not implement** `OE` ([`interpreter.rs:264`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) has no `oe()` branch). +- **`Rc=1` CR0 update is correctly 64-bit.** [`interpreter.rs:269`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i64` — full 64-bit signed compare. One of the few non-truncating CR0 sites in xenia-rs; means `mulld.` gives spec-correct CR0 even when the result has non-zero high 32 bits. - **Same instruction for signed and unsigned low halves.** Modular arithmetic is identical; only the high half (`mulhd` vs `mulhdu`) distinguishes the interpretations. - **Multi-cycle latency** — slowest of the ALU pipelines after divide. diff --git a/tools/ppc-manual/alu/mulli.md b/tools/ppc-manual/alu/mulli.md index 315ec277..38bc946c 100644 --- a/tools/ppc-manual/alu/mulli.md +++ b/tools/ppc-manual/alu/mulli.md @@ -62,13 +62,15 @@ RT <- ((RA) * EXTS(SIMM))[64:127] ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -76,22 +78,20 @@ RT <- ((RA) * EXTS(SIMM))[64:127] ## Implementation References **`mulli`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulli"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:382`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L382) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:332`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L332) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:165-172`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L165-L172) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mulli"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:382`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L382) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:193`](../../../crates/sylpheed-ppc/src/opcode.rs#L193) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:447`](../../../crates/sylpheed-ppc/src/decoder.rs#L447) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mulli => { - // PPCBUG-004: 32-bit ABI. Read RA as i32 (low 32, sign-extended for - // multiply), product fits in 32 bits per ISA (overflow wraps). - let ra = ctx.gpr[instr.ra()] as i32 as i64; - let imm = instr.simm16() as i64; - ctx.gpr[instr.rd()] = (ra.wrapping_mul(imm) as u32) as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_mulli(PPCHIRBuilder& f, const InstrData& i) { + // prod[0:127] <- (RA) × EXTS(SI) + // RT <- prod[64:127] + Value* v = f.Mul(f.LoadGPR(i.D.RA), f.LoadConstantInt64(XEEXTS16(i.D.DS))); + f.StoreGPR(i.D.RT, v); + return 0; +} ```
@@ -99,7 +99,7 @@ RT <- ((RA) * EXTS(SIMM))[64:127] ## Special Cases & Edge Conditions -- **64-bit operand, sign-extended 16-bit immediate.** Xenia reads the full 64-bit `RA` as `i64` and the immediate as a sign-extended `i64` ([`interpreter.rs:80-81`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L80-L81)) — note this differs from the PPC pseudocode header which writes `(RA) * EXTS(SIMM)` as a 64-bit operation but other implementations sometimes treat it as 32×32. On the Xenon (and in xenia-rs), it is genuinely 64-bit. +- **64-bit operand, sign-extended 16-bit immediate.** Xenia reads the full 64-bit `RA` as `i64` and the immediate as a sign-extended `i64` ([`interpreter.rs:80-81`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)) — note this differs from the PPC pseudocode header which writes `(RA) * EXTS(SIMM)` as a 64-bit operation but other implementations sometimes treat it as 32×32. On the Xenon (and in xenia-rs), it is genuinely 64-bit. - **Returns the low 64 bits.** No high half is produced — equivalent to `(int64_t)RA * (int64_t)SIMM` modulo `2^64`. There is no `mulhi`-immediate instruction. - **No `Rc`, no `OE`.** This D-form has no flag bits — strictly `RT ← RA * SIMM`. To check overflow, compare the result to `(int32_t)RA * SIMM` after the fact, or use [`mulldx`](mulldx.md) with `OE=1` after materialising the immediate. - **Common compiler idiom.** `mulli` is heavily used for fixed-stride array indexing (`r3 *= sizeof_struct`) when the size is a small signed constant. diff --git a/tools/ppc-manual/alu/mullwx.md b/tools/ppc-manual/alu/mullwx.md index 0ade3cc4..5ae39b22 100644 --- a/tools/ppc-manual/alu/mullwx.md +++ b/tools/ppc-manual/alu/mullwx.md @@ -70,13 +70,15 @@ RT <- ((RA)[32:63]) * ((RB)[32:63]) ; signed 32×32 → 64 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,29 +86,28 @@ RT <- ((RA)[32:63]) * ((RB)[32:63]) ; signed 32×32 → 64 ## Implementation References **`mullwx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mullwx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:390`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L390) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:57`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L57) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:874`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L874) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:357-371`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L357-L371) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mullwx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:390`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L390) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:194`](../../../crates/sylpheed-ppc/src/opcode.rs#L194) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:989`](../../../crates/sylpheed-ppc/src/decoder.rs#L989) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mullwx => { - // PPCBUG-009: 32-bit ABI. Truncate product to u32 — overflow detection - // (mullw_ov) still uses the full i64 product to catch the overflow. - let ra = ctx.gpr[instr.ra()] as i32 as i64; - let rb = ctx.gpr[instr.rb()] as i32 as i64; - let product = ra.wrapping_mul(rb); - ctx.gpr[instr.rd()] = product as u32 as u64; - if instr.oe() { - overflow::apply(ctx, overflow::mullw_ov(product)); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, ctx.gpr[instr.rd()] as u32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_mullwx(PPCHIRBuilder& f, const InstrData& i) { + // RT <- (RA)[32:63] × (RB)[32:63] + if (i.XO.OE) { + // With XER update. + XEINSTRNOTIMPLEMENTED(); + } + Value* v = f.Mul( + f.SignExtend(f.Truncate(f.LoadGPR(i.XO.RA), INT32_TYPE), INT64_TYPE), + f.SignExtend(f.Truncate(f.LoadGPR(i.XO.RB), INT32_TYPE), INT64_TYPE)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
diff --git a/tools/ppc-manual/alu/nandx.md b/tools/ppc-manual/alu/nandx.md index 668dbf5b..cfe7a5d1 100644 --- a/tools/ppc-manual/alu/nandx.md +++ b/tools/ppc-manual/alu/nandx.md @@ -66,13 +66,15 @@ RA <- ~((RS) & (RB)) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,22 +82,22 @@ RA <- ~((RS) & (RB)) ## Implementation References **`nandx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="nandx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:753`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L753) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:812`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L812) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:570-577`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L570-L577) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="nandx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:753`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L753) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:196`](../../../crates/sylpheed-ppc/src/opcode.rs#L196) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:927`](../../../crates/sylpheed-ppc/src/decoder.rs#L927) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::nandx => { - // PPCBUG-030: same shape — operate in u32. - let rs32 = ctx.gpr[instr.rs()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - ctx.gpr[instr.ra()] = (!(rs32 & rb32)) as u64; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_nandx(PPCHIRBuilder& f, const InstrData& i) { + // RA <- ¬((RS) & (RB)) + Value* ra = f.Not(f.And(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB))); + f.StoreGPR(i.X.RA, ra); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + return 0; +} ```
@@ -107,7 +109,7 @@ RA <- ~((RS) & (RB)) - **Operand convention is X-form** (`RA` destination, `RS`/`RB` sources). - **64-bit operation** on Xenon; `~` operates on the full `u64`. - **No `OE` or `XER` side effects.** Only `Rc=1` updates `CR0` (signed compare to zero). -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:377`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L377) truncates with `as i32 as i64`. NAND results frequently have all-ones high bits when the low half AND is non-saturating, so the truncation can change CR0 semantics in subtle ways — call out as a quirk if reproducing CR-sensitive behaviour. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:377`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) truncates with `as i32 as i64`. NAND results frequently have all-ones high bits when the low half AND is non-saturating, so the truncation can change CR0 semantics in subtle ways — call out as a quirk if reproducing CR-sensitive behaviour. - **Idiom: NAND of two equal values produces NOT.** `nand. RA, RS, RS` ≡ `~RS` with CR0 update. Sometimes used by compilers when `not.` is unavailable in their tablegen. ## Related Instructions diff --git a/tools/ppc-manual/alu/negx.md b/tools/ppc-manual/alu/negx.md index 1b0316d7..cc847669 100644 --- a/tools/ppc-manual/alu/negx.md +++ b/tools/ppc-manual/alu/negx.md @@ -69,13 +69,15 @@ RT <- ~(RA) + 1 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -83,29 +85,33 @@ RT <- ~(RA) + 1 ## Implementation References **`negx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="negx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:406`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L406) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:866`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L866) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:342-356`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L342-L356) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="negx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:406`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L406) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:197`](../../../crates/sylpheed-ppc/src/opcode.rs#L197) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:981`](../../../crates/sylpheed-ppc/src/decoder.rs#L981) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::negx => { - // PPCBUG-006: 32-bit ABI. `(!ra).wrapping_add(1)` on u64 always - // sets upper 32 bits — every neg poisoned the GPR. neg_ov also - // checks at 64-bit INT_MIN; should be 32-bit INT_MIN. - let ra32 = ctx.gpr[instr.ra()] as u32; - let result32 = (!ra32).wrapping_add(1); - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - overflow::apply(ctx, ra32 == 0x8000_0000); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_negx(PPCHIRBuilder& f, const InstrData& i) { + // RT <- ¬(RA) + 1 + if (i.XO.OE) { + // Stub implementation. + // TODO: Handle overflow flag for XER. + // NOTE: 535507D4 (Raiden Fighters Aces) never seems to rely on this + // behavior, despite having OE set. + Value* v = f.LoadGPR(i.XO.RA); + if (v->AsUint64() == 0x8000000000000000) { + f.StoreGPR(i.XO.RT, v); + return 0; + } + } + Value* v = f.Neg(f.LoadGPR(i.XO.RA)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -114,9 +120,9 @@ RT <- ~(RA) + 1 ## Special Cases & Edge Conditions - **Two's-complement negate.** `RT ← ~RA + 1`, equivalent to `0 − RA`. A specialisation of [`subfx`](subfx.md) where `RB` is implicit zero. -- **`INT64_MIN` is its own negation.** `neg(0x8000000000000000) = 0x8000000000000000` — the only fixed point. `nego` should set `XER[OV]` in this case (it is the canonical signed-overflow trigger), but **xenia-rs does not implement `OE`** ([`interpreter.rs:201`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L201) has no `oe()` branch). +- **`INT64_MIN` is its own negation.** `neg(0x8000000000000000) = 0x8000000000000000` — the only fixed point. `nego` should set `XER[OV]` in this case (it is the canonical signed-overflow trigger), but **xenia-rs does not implement `OE`** ([`interpreter.rs:201`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) has no `oe()` branch). - **`RB` field unused.** Set to 0 by assemblers; ignored. -- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:204`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L204). Important: `neg.` of a 64-bit value with high bits set will give a CR0 that doesn't match spec (which compares the full 64-bit `~RA + 1` to zero). +- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:204`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). Important: `neg.` of a 64-bit value with high bits set will give a CR0 that doesn't match spec (which compares the full 64-bit `~RA + 1` to zero). - **No carry produced.** Use [`subfic`](subficx.md) `RT, RA, 0` (`RT ← 0 − RA` with carry) when you need the borrow. - **Latency: single cycle.** Negate is the cheapest XO-form ALU operation (cheaper than `subf` despite being a special case, because there's no `RB` operand fetch). diff --git a/tools/ppc-manual/alu/norx.md b/tools/ppc-manual/alu/norx.md index 20ebec25..64fd3b11 100644 --- a/tools/ppc-manual/alu/norx.md +++ b/tools/ppc-manual/alu/norx.md @@ -66,13 +66,15 @@ RA <- ~((RS) | (RB)) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,22 +82,22 @@ RA <- ~((RS) | (RB)) ## Implementation References **`norx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="norx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:763`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L763) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:777`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L777) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:562-569`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L562-L569) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="norx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:763`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L763) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:198`](../../../crates/sylpheed-ppc/src/opcode.rs#L198) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:892`](../../../crates/sylpheed-ppc/src/decoder.rs#L892) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::norx => { - // PPCBUG-029: `not` simplified mnemonic — every `not` poisoned the GPR. - let rs32 = ctx.gpr[instr.rs()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - ctx.gpr[instr.ra()] = (!(rs32 | rb32)) as u64; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_norx(PPCHIRBuilder& f, const InstrData& i) { + // RA <- ¬((RS) | (RB)) + Value* ra = f.Not(f.Or(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB))); + f.StoreGPR(i.X.RA, ra); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + return 0; +} ```
@@ -107,7 +109,7 @@ RA <- ~((RS) | (RB)) - **Operand convention** is X-form (`RA` destination, `RS`/`RB` sources). - **64-bit operation** on Xenon; full 64-bit complement via `!` on `u64`. - **No `OE` or `XER` side effects.** -- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:372`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L372) uses `as i32 as i64`. Note that NOR almost always produces results with high bits set (since the OR rarely covers all 64 bits), so the truncated CR0 is usually `LT` (negative low half) where spec might give a different signed compare for the full 64-bit value. +- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:372`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i32 as i64`. Note that NOR almost always produces results with high bits set (since the OR rarely covers all 64 bits), so the truncated CR0 is usually `LT` (negative low half) where spec might give a different signed compare for the full 64-bit value. - **`nor.` after a clear-low operation is a common pattern** for testing whether some high-bit mask is empty. ## Related Instructions diff --git a/tools/ppc-manual/alu/orcx.md b/tools/ppc-manual/alu/orcx.md index 3ad2f964..4af094ac 100644 --- a/tools/ppc-manual/alu/orcx.md +++ b/tools/ppc-manual/alu/orcx.md @@ -66,13 +66,15 @@ RA <- (RS) | ~(RB) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,22 +82,22 @@ RA <- (RS) | ~(RB) ## Implementation References **`orcx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="orcx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:800`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L800) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:807`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L807) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:548-555`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L548-L555) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="orcx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:800`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L800) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:199`](../../../crates/sylpheed-ppc/src/opcode.rs#L199) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:922`](../../../crates/sylpheed-ppc/src/decoder.rs#L922) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::orcx => { - // PPCBUG-028: same shape as andcx — operate in u32. - let rs32 = ctx.gpr[instr.rs()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - ctx.gpr[instr.ra()] = (rs32 | !rb32) as u64; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_orcx(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) | ¬(RB) + Value* ra = f.Or(f.LoadGPR(i.X.RT), f.Not(f.LoadGPR(i.X.RB))); + f.StoreGPR(i.X.RA, ra); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + return 0; +} ```
@@ -108,7 +110,7 @@ RA <- (RS) | ~(RB) - **Operand convention** is X-form (`RA` destination, `RS`/`RB` sources). - **64-bit operation** on Xenon; xenia uses Rust's `!` on `u64` for full-width complement. - **No `OE` or `XER` side effects.** -- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:362`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L362). Because `~RB` typically has high bits set, `orc.` results often appear `LT` in the truncated CR0. +- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:362`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). Because `~RB` typically has high bits set, `orc.` results often appear `LT` in the truncated CR0. ## Related Instructions diff --git a/tools/ppc-manual/alu/ori.md b/tools/ppc-manual/alu/ori.md index 8cafd10a..03c68b30 100644 --- a/tools/ppc-manual/alu/ori.md +++ b/tools/ppc-manual/alu/ori.md @@ -62,13 +62,15 @@ RA <- (RS) | (0x0000 || UIMM) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -76,18 +78,23 @@ RA <- (RS) | (0x0000 || UIMM) ## Implementation References **`ori`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ori"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:810`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L810) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:347`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L347) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:512-515`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L512-L515) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ori"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:810`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L810) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:200`](../../../crates/sylpheed-ppc/src/opcode.rs#L200) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:462`](../../../crates/sylpheed-ppc/src/decoder.rs#L462) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::ori => { - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] | (instr.uimm16() as u64); - ctx.pc += 4; - } +```cpp +int InstrEmit_ori(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) | (i48.0 || UI) + if (!i.D.RA && !i.D.RT && !i.D.DS) { + f.Nop(); + return 0; + } + Value* ra = f.Or(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS))); + f.StoreGPR(i.D.RA, ra); + return 0; +} ```
@@ -99,7 +106,7 @@ RA <- (RS) | (0x0000 || UIMM) - **Immediate is zero-extended.** Only the low 16 bits of `RA` can be affected; the high 48 bits are passed through from `RS` unchanged. - **`ori 0, 0, 0` is the canonical NOP.** All PowerPC NOPs assemble to this encoding (`0x60000000`). Disassemblers usually display this as `nop`. - **Common idiom: build a 32-bit constant via `lis` + `ori`.** `lis r3, hi16; ori r3, r3, lo16` materialises any 32-bit immediate with no CR or XER disturbance. -- **64-bit operation in xenia-rs.** [`interpreter.rs:330`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L330) — full `u64` OR; high bits unchanged from `RS`. +- **64-bit operation in xenia-rs.** [`interpreter.rs:330`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) — full `u64` OR; high bits unchanged from `RS`. - **`RA = 0` reads `r0`** (not the literal zero). Different from `addi`'s `RA0` semantics; `ori` uses the regular `RA` interpretation. ## Related Instructions diff --git a/tools/ppc-manual/alu/oris.md b/tools/ppc-manual/alu/oris.md index b659c45d..347d5b06 100644 --- a/tools/ppc-manual/alu/oris.md +++ b/tools/ppc-manual/alu/oris.md @@ -62,13 +62,15 @@ RA <- (RS) | (UIMM || 0x0000) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -76,18 +78,20 @@ RA <- (RS) | (UIMM || 0x0000) ## Implementation References **`oris`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="oris"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:821`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L821) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:348`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L348) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:516-519`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L516-L519) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="oris"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:821`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L821) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:201`](../../../crates/sylpheed-ppc/src/opcode.rs#L201) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:463`](../../../crates/sylpheed-ppc/src/decoder.rs#L463) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::oris => { - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] | ((instr.uimm16() as u64) << 16); - ctx.pc += 4; - } +```cpp +int InstrEmit_oris(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) | (i32.0 || UI || i16.0) + Value* ra = + f.Or(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS) << 16)); + f.StoreGPR(i.D.RA, ra); + return 0; +} ```
@@ -98,7 +102,7 @@ RA <- (RS) | (UIMM || 0x0000) - **No record form.** No `oris.` — same as [`ori`](ori.md). For CR0 updates use [`orx`](orx.md) with `Rc=1`. - **Immediate is zero-extended *then* shifted left 16.** Only bits 32–47 of `RA` (in PowerISA bit numbering) can be affected; the high 32 bits and low 16 bits of `RA` come from `RS` unchanged. - **Common pair with `lis`** to load a 32-bit constant: `lis r3, hi16` (= `addis r3, 0, hi16`), then `ori r3, r3, lo16`. **For unsigned constants whose low half has the high bit set**, `lis` followed by `ori` works cleanly because `ori` is zero-extending; using `addi` instead would sign-extend `lo16` and corrupt the constant. -- **64-bit operation in xenia-rs.** [`interpreter.rs:334`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L334). +- **64-bit operation in xenia-rs.** [`interpreter.rs:334`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). - **No `XER`, no `CR` effect.** Pure register OR. - **`RA = 0` reads `r0`** (not literal zero); see [`ori`](ori.md). diff --git a/tools/ppc-manual/alu/orx.md b/tools/ppc-manual/alu/orx.md index 6d15a85b..66323070 100644 --- a/tools/ppc-manual/alu/orx.md +++ b/tools/ppc-manual/alu/orx.md @@ -66,13 +66,15 @@ RA <- (RS) | (RB) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,20 +82,39 @@ RA <- (RS) | (RB) ## Implementation References **`orx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="orx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:773`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L773) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:59`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L59) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:809`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L809) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:542-547`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L542-L547) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="orx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:773`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L773) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:202`](../../../crates/sylpheed-ppc/src/opcode.rs#L202) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:924`](../../../crates/sylpheed-ppc/src/decoder.rs#L924) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::orx => { - // PPCBUG-032+020: 32-bit ABI CR0 view. - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] | ctx.gpr[instr.rb()]; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_orx(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) | (RB) + if (i.X.RT == i.X.RB && i.X.RT == i.X.RA && !i.X.Rc) { + // chrispy: this special version of orx is db16cyc and is heavily used in + // spinlocks. since we do not emit any code for this we end up wasting a ton + // of power + if (i.code == 0x7FFFFB78) { + f.DelayExecution(); + } else { + // Sometimes used as no-op. + f.Nop(); + } + return 0; + } + Value* ra; + if (i.X.RT == i.X.RB) { + ra = f.LoadGPR(i.X.RT); + } else { + ra = f.Or(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)); + } + f.StoreGPR(i.X.RA, ra); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + return 0; +} ```
@@ -105,7 +126,7 @@ RA <- (RS) | (RB) - **Operand convention** is X-form (`RA` destination, `RS`/`RB` sources). - **64-bit operation** on Xenon; full bitwise OR across 64 bits. - **No `OE` or `XER` side effects.** Only `Rc=1` updates `CR0`. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:357`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L357) truncates with `as i32 as i64`. For `or. RA, RS, RS` (i.e. `mr.`), this means CR0 reflects the low 32 bits of `RS` only — distinguishable from spec only when the high 32 bits are non-zero with all-zero low 32. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:357`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) truncates with `as i32 as i64`. For `or. RA, RS, RS` (i.e. `mr.`), this means CR0 reflects the low 32 bits of `RS` only — distinguishable from spec only when the high 32 bits are non-zero with all-zero low 32. - **`or 26, 26, 26` is the Xbox 360 NOP variant** historically used to mark cache lines or signal the dispatch unit (alongside `nop` ≡ `ori 0,0,0`). Disassembly may show this — it has no architectural effect. ## Related Instructions diff --git a/tools/ppc-manual/alu/rldclx.md b/tools/ppc-manual/alu/rldclx.md index 067175b0..6e901b66 100644 --- a/tools/ppc-manual/alu/rldclx.md +++ b/tools/ppc-manual/alu/rldclx.md @@ -62,28 +62,26 @@ rldcl[Rc] [RA], [RS], [RB], [MB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -91,24 +89,37 @@ rldcl[Rc] [RA], [RS], [RB], [MB] ## Implementation References **`rldclx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldclx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:856`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L856) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:733`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L733) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:802-811`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L802-L811) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldclx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:856`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L856) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:204`](../../../crates/sylpheed-ppc/src/opcode.rs#L204) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:848`](../../../crates/sylpheed-ppc/src/decoder.rs#L848) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::rldclx => { - let rs = ctx.gpr[instr.rs()]; - let sh = ctx.gpr[instr.rb()] & 0x3F; - let mb = instr.mb_md(); - let rotated = rs.rotate_left(sh as u32); - let mask = rld_mask_left(mb); - ctx.gpr[instr.ra()] = rotated & mask; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_rldclx(PPCHIRBuilder& f, const InstrData& i) { + // n <- rB[58:63] + // r <- ROTL[64](rS, n) + // b <- mb[5] || mb[0:4] + // m <- MASK(b, 63) + // rA <- r & m + Value* n = f.And(f.Truncate(f.LoadGPR(i.MDS.RB), INT8_TYPE), + f.LoadConstantInt8(0x3F)); + + uint32_t mb = (i.MDS.MB5 << 5) | i.MDS.MB; + uint64_t m = XEMASK(mb, 63); + Value* v = f.LoadGPR(i.MDS.RT); + + v = f.RotateLeft(v, n); + if (m != 0xFFFFFFFFFFFFFFFF) { + v = f.And(v, f.LoadConstantUint64(m)); + } + + f.StoreGPR(i.MDS.RA, v); + if (i.MDS.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -118,9 +129,9 @@ rldcl[Rc] [RA], [RS], [RB], [MB] - **`RA ← ROTL64(RS, RB[58:63]) & MASK(MB, 63)`.** Rotate `RS` left by `RB & 0x3F`, then *clear* bits to the left of `MB` — i.e. keep bits `MB..63`, force bits `0..MB-1` to zero. - **Shift comes from a register.** Unlike [`rldiclx`](rldiclx.md), the rotate amount is dynamic. Only the low 6 bits of `RB` are used (`& 0x3F`); the upper 58 bits are silently ignored. -- **`MB` is a split 6-bit field.** Bit 5 of the encoded `mb/me` is *swapped* into bit position 5 (raw bit 30) — xenia decodes via `(instr.mb() << 1) | ((raw >> 1) & 1)` ([`interpreter.rs:587`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L587)). This MDS form is unusual; if you write a decoder, follow this exact bit assembly. +- **`MB` is a split 6-bit field.** Bit 5 of the encoded `mb/me` is *swapped* into bit position 5 (raw bit 30) — xenia decodes via `(instr.mb() << 1) | ((raw >> 1) & 1)` ([`interpreter.rs:587`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). This MDS form is unusual; if you write a decoder, follow this exact bit assembly. - **Mask generation.** `rld_mask_left(MB)` is `(1 << (64 - MB)) - 1` — i.e. clear bits `0..MB-1`, keep bits `MB..63`. When `MB = 0` the mask is all ones; when `MB = 63` only bit 63 survives. -- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:592`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L592) uses `as i64` directly — no truncation. The rotate-and-mask family is one of the few xenia-rs instruction groups that already does the spec-correct 64-bit CR0 compare. +- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:592`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i64` directly — no truncation. The rotate-and-mask family is one of the few xenia-rs instruction groups that already does the spec-correct 64-bit CR0 compare. - **No `XER` effect.** - **Use over [`rldiclx`](rldiclx.md)** when the shift amount is computed at runtime (e.g. via `cntlzd` for normalisation). diff --git a/tools/ppc-manual/alu/rldcrx.md b/tools/ppc-manual/alu/rldcrx.md index f0caf251..6ce0bc8b 100644 --- a/tools/ppc-manual/alu/rldcrx.md +++ b/tools/ppc-manual/alu/rldcrx.md @@ -62,28 +62,26 @@ rldcr[Rc] [RA], [RS], [RB], [ME] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -91,24 +89,37 @@ rldcr[Rc] [RA], [RS], [RB], [ME] ## Implementation References **`rldcrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldcrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:881`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L881) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:734`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L734) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:812-821`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L812-L821) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldcrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:881`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L881) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:205`](../../../crates/sylpheed-ppc/src/opcode.rs#L205) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:849`](../../../crates/sylpheed-ppc/src/decoder.rs#L849) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::rldcrx => { - let rs = ctx.gpr[instr.rs()]; - let sh = ctx.gpr[instr.rb()] & 0x3F; - let me = instr.mb_md(); - let rotated = rs.rotate_left(sh as u32); - let mask = rld_mask_right(me); - ctx.gpr[instr.ra()] = rotated & mask; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_rldcrx(PPCHIRBuilder& f, const InstrData& i) { + // n <- rB[58:63] + // r <- ROTL[64](rS, n) + // b <- mb[5] || mb[0:4] + // m <- MASK(0, b) + // rA <- r & m + Value* n = f.And(f.Truncate(f.LoadGPR(i.MDS.RB), INT8_TYPE), + f.LoadConstantInt8(0x3F)); + + uint32_t mb = (i.MDS.MB5 << 5) | i.MDS.MB; + uint64_t m = XEMASK(0, mb); + Value* v = f.LoadGPR(i.MDS.RT); + + v = f.RotateLeft(v, n); + if (m != 0xFFFFFFFFFFFFFFFF) { + v = f.And(v, f.LoadConstantUint64(m)); + } + + f.StoreGPR(i.MDS.RA, v); + if (i.MDS.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -118,9 +129,9 @@ rldcr[Rc] [RA], [RS], [RB], [ME] - **`RA ← ROTL64(RS, RB[58:63]) & MASK(0, ME)`.** Rotate `RS` left by `RB & 0x3F`, then *clear* bits to the right of `ME` — keep bits `0..ME`, force bits `ME+1..63` to zero. - **Shift from register.** Same as [`rldclx`](rldclx.md): only the low 6 bits of `RB` count. -- **`ME` is a split 6-bit field.** Same swap-decoded layout as `MB` in `rldclx`: `(instr.mb() << 1) | ((raw >> 1) & 1)` ([`interpreter.rs:597`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L597)). Note that even though it represents `ME` here, xenia reads it from `instr.mb()` because the field shares the same encoding slot. +- **`ME` is a split 6-bit field.** Same swap-decoded layout as `MB` in `rldclx`: `(instr.mb() << 1) | ((raw >> 1) & 1)` ([`interpreter.rs:597`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). Note that even though it represents `ME` here, xenia reads it from `instr.mb()` because the field shares the same encoding slot. - **Mask generation.** `rld_mask_right(ME)` = `~((1 << (63 - ME)) - 1)` keeping bits `0..ME`. When `ME = 63` the mask is all ones; when `ME = 0` only bit 0 survives. -- **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly ([`interpreter.rs:602`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L602)). +- **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly ([`interpreter.rs:602`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). - **No `XER` effect.** - **Useful for left-shift with arbitrary discard.** `rldcr RA, RS, RB, 63 - n` is functionally close to a left-shift-and-mask sequence, with the rotate variant additionally allowing wrap-around. diff --git a/tools/ppc-manual/alu/rldiclx.md b/tools/ppc-manual/alu/rldiclx.md index e688ecd9..3cb8bd2f 100644 --- a/tools/ppc-manual/alu/rldiclx.md +++ b/tools/ppc-manual/alu/rldiclx.md @@ -63,28 +63,26 @@ rldicl[Rc] [RA], [RS], [SH], [MB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,24 +90,40 @@ rldicl[Rc] [RA], [RS], [SH], [MB] ## Implementation References **`rldiclx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldiclx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:929`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L929) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:728`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L728) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:762-771`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L762-L771) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldiclx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:929`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L929) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:206`](../../../crates/sylpheed-ppc/src/opcode.rs#L206) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:843`](../../../crates/sylpheed-ppc/src/decoder.rs#L843) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::rldiclx => { - let rs = ctx.gpr[instr.rs()]; - let sh = instr.sh64(); - let mb = instr.mb_md(); - let rotated = rs.rotate_left(sh); - let mask = rld_mask_left(mb); - ctx.gpr[instr.ra()] = rotated & mask; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_rldiclx(PPCHIRBuilder& f, const InstrData& i) { + // n <- sh[5] || sh[0:4] + // r <- ROTL64((RS), n) + // b <- mb[5] || mb[0:4] + // m <- MASK(b, 63) + // RA <- r & m + uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; + uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; + uint64_t m = XEMASK(mb, 63); + Value* v = f.LoadGPR(i.MD.RT); + if (sh == 64 - mb) { + // srdi == rldicl ra,rs,64-n,n + v = f.Shr(v, int8_t(mb)); + } else { + if (sh) { + v = f.RotateLeft(v, f.LoadConstantInt8(sh)); + } + if (m != 0xFFFFFFFFFFFFFFFF) { + v = f.And(v, f.LoadConstantUint64(m)); + } + } + f.StoreGPR(i.MD.RA, v); + if (i.MD.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -124,7 +138,7 @@ rldicl[Rc] [RA], [RS], [SH], [MB] - `extrdi RA, RS, n, b` ≡ `rldicl RA, RS, b+n, 64-n` — extract `n` bits starting at `b`. - **`SH` is 6 bits, immediate** (bits 16–20 + bit 30). Xenia uses `instr.sh64()` to assemble them. - **`MB` is 6 bits, split-encoded** (`(instr.mb() << 1) | ((raw >> 1) & 1)`). -- **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly ([`interpreter.rs:551`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L551)). +- **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly ([`interpreter.rs:551`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). - **No `XER` effect.** - **Often appears in compiled disassembly** as a generic 64-bit shift. Decoding back to the simplified mnemonic above makes the intent obvious. diff --git a/tools/ppc-manual/alu/rldicrx.md b/tools/ppc-manual/alu/rldicrx.md index d416089e..4300f9f7 100644 --- a/tools/ppc-manual/alu/rldicrx.md +++ b/tools/ppc-manual/alu/rldicrx.md @@ -63,28 +63,26 @@ rldicr[Rc] [RA], [RS], [SH], [ME] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,24 +90,40 @@ rldicr[Rc] [RA], [RS], [SH], [ME] ## Implementation References **`rldicrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldicrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:957`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L957) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:729`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L729) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:772-781`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L772-L781) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldicrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:957`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L957) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:207`](../../../crates/sylpheed-ppc/src/opcode.rs#L207) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:844`](../../../crates/sylpheed-ppc/src/decoder.rs#L844) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::rldicrx => { - let rs = ctx.gpr[instr.rs()]; - let sh = instr.sh64(); - let me = instr.mb_md(); - let rotated = rs.rotate_left(sh); - let mask = rld_mask_right(me); - ctx.gpr[instr.ra()] = rotated & mask; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_rldicrx(PPCHIRBuilder& f, const InstrData& i) { + // n <- sh[5] || sh[0:4] + // r <- ROTL64((RS), n) + // e <- me[5] || me[0:4] + // m <- MASK(0, e) + // RA <- r & m + uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; + uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; + uint64_t m = XEMASK(0, mb); + Value* v = f.LoadGPR(i.MD.RT); + if (mb == 63 - sh) { + // sldi == rldicr ra,rs,n,63-n + v = f.Shl(v, int8_t(sh)); + } else { + if (sh) { + v = f.RotateLeft(v, f.LoadConstantInt8(sh)); + } + if (m != 0xFFFFFFFFFFFFFFFF) { + v = f.And(v, f.LoadConstantUint64(m)); + } + } + f.StoreGPR(i.MD.RA, v); + if (i.MD.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -124,7 +138,7 @@ rldicr[Rc] [RA], [RS], [SH], [ME] - `extldi RA, RS, n, b` ≡ `rldicr RA, RS, b, n-1` — extract `n` bits from position `b` left-aligned. - **`SH` is 6 bits, immediate.** Same `instr.sh64()` decode as the rest of the family. - **`ME` is 6 bits, split-encoded.** Xenia stores it via `instr.mb()` — the field shares the slot with `MB` from sister instructions; the operation just interprets it as the right edge. -- **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly ([`interpreter.rs:561`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L561)). +- **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly ([`interpreter.rs:561`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). - **No `XER` effect.** - **Heavily emitted by 64-bit code generators** for left-shift-and-clear sequences. Recognising the simplified mnemonics aids disassembly. diff --git a/tools/ppc-manual/alu/rldicx.md b/tools/ppc-manual/alu/rldicx.md index da8dca47..4a9f3159 100644 --- a/tools/ppc-manual/alu/rldicx.md +++ b/tools/ppc-manual/alu/rldicx.md @@ -63,28 +63,26 @@ rldic[Rc] [RA], [RS], [SH], [MB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,24 +90,35 @@ rldic[Rc] [RA], [RS], [SH], [MB] ## Implementation References **`rldicx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldicx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:906`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L906) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:730`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L730) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:782-791`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L782-L791) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldicx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:906`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L906) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:208`](../../../crates/sylpheed-ppc/src/opcode.rs#L208) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:845`](../../../crates/sylpheed-ppc/src/decoder.rs#L845) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::rldicx => { - let rs = ctx.gpr[instr.rs()]; - let sh = instr.sh64(); - let mb = instr.mb_md(); - let rotated = rs.rotate_left(sh); - let mask = rld_mask_left(mb) & rld_mask_right(63 - sh); - ctx.gpr[instr.ra()] = rotated & mask; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_rldicx(PPCHIRBuilder& f, const InstrData& i) { + // n <- sh[5] || sh[0:4] + // r <- ROTL64(RS, n) + // b <- mb[5] || mb[0:4] + // m <- MASK(b, ~n) + // RA <- r & m + // TODO: Check if this makes any sense. It works in 535507D4, + // but it's the only title I could find that uses this instruction. + uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; + uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; + uint64_t m = XEMASK(mb, ~sh); + Value* v = f.LoadGPR(i.MD.RT); + if (sh) { + v = f.RotateLeft(v, f.LoadConstantInt8(sh)); + } + v = f.And(v, f.LoadConstantUint64(m)); + f.StoreGPR(i.MD.RA, v); + if (i.MD.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -118,11 +127,11 @@ rldic[Rc] [RA], [RS], [SH], [MB] ## Special Cases & Edge Conditions - **`RA ← ROTL64(RS, SH) & MASK(MB, 63 - SH)`.** Rotate `RS` left by `SH` bits, then mask off both ends: clear bits `0..MB-1` *and* clear bits `64-SH..63`. This is the "clear at both edges" variant — useful for inserting a field into an otherwise-zero register. -- **`SH` is a 6-bit immediate** spanning bits 16–20 plus bit 30 of the instruction word. Xenia uses the helper `instr.sh64()` ([`interpreter.rs:566`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L566)) to assemble the 6 bits. +- **`SH` is a 6-bit immediate** spanning bits 16–20 plus bit 30 of the instruction word. Xenia uses the helper `instr.sh64()` ([`interpreter.rs:566`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)) to assemble the 6 bits. - **`MB` is also 6-bit, split-encoded** like the rest of the `rld*` family: `(instr.mb() << 1) | ((raw >> 1) & 1)`. - **Mask is computed as `MASK_LEFT(MB) AND MASK_RIGHT(63 - SH)`.** This produces the equivalent of "left-shift `RS` by `SH` then clear high bits above bit `MB`" — a common pattern when `MB ≤ 63 - SH`. - **Equivalent to a logical shift when `MB = 0`.** `rldic RA, RS, SH, 0` ≡ `sldi RA, RS, SH` (an alias the assembler may prefer). -- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:571`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L571) uses `as i64` directly. +- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:571`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i64` directly. - **No `XER` effect.** ## Related Instructions diff --git a/tools/ppc-manual/alu/rldimix.md b/tools/ppc-manual/alu/rldimix.md index 678e091d..ff19058f 100644 --- a/tools/ppc-manual/alu/rldimix.md +++ b/tools/ppc-manual/alu/rldimix.md @@ -63,28 +63,26 @@ rldimi[Rc] [RA], [RS], [SH], [MB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,24 +90,37 @@ rldimi[Rc] [RA], [RS], [SH], [MB] ## Implementation References **`rldimix`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldimix"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:985`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L985) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:731`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L731) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:792-801`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L792-L801) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rldimix"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:985`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L985) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:209`](../../../crates/sylpheed-ppc/src/opcode.rs#L209) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:846`](../../../crates/sylpheed-ppc/src/decoder.rs#L846) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::rldimix => { - let rs = ctx.gpr[instr.rs()]; - let sh = instr.sh64(); - let mb = instr.mb_md(); - let rotated = rs.rotate_left(sh); - let mask = rld_mask_left(mb) & rld_mask_right(63 - sh); - ctx.gpr[instr.ra()] = (rotated & mask) | (ctx.gpr[instr.ra()] & !mask); - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_rldimix(PPCHIRBuilder& f, const InstrData& i) { + // n <- sh[5] || sh[0:4] + // r <- ROTL64((RS), n) + // b <- me[5] || me[0:4] + // m <- MASK(b, ¬n) + // RA <- (r & m) | ((RA)&¬m) + uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; + uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; + uint64_t m = XEMASK(mb, ~sh); + Value* v = f.LoadGPR(i.MD.RT); + if (sh) { + v = f.RotateLeft(v, f.LoadConstantInt8(sh)); + } + if (m != 0xFFFFFFFFFFFFFFFF) { + Value* ra = f.LoadGPR(i.MD.RA); + v = f.Or(f.And(v, f.LoadConstantUint64(m)), + f.And(ra, f.LoadConstantUint64(~m))); + } + f.StoreGPR(i.MD.RA, v); + if (i.MD.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -118,7 +129,7 @@ rldimi[Rc] [RA], [RS], [SH], [MB] ## Special Cases & Edge Conditions - **`RA ← (ROTL64(RS, SH) & MASK) | (RA & ~MASK)`.** *Reads* the prior `RA` so it can preserve the bits outside the mask — this is the only `rld*` instruction with `RA` as both source and destination. -- **Mask is `MASK_LEFT(MB) AND MASK_RIGHT(63 - SH)`** ([`interpreter.rs:578`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L578)) — same span as [`rldicx`](rldicx.md), but the un-masked region is preserved in the destination instead of being zeroed. +- **Mask is `MASK_LEFT(MB) AND MASK_RIGHT(63 - SH)`** ([`interpreter.rs:578`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)) — same span as [`rldicx`](rldicx.md), but the un-masked region is preserved in the destination instead of being zeroed. - **Use to insert a bit-field.** Common idiom: `rldimi RA, RS, b, mask_start` writes `RS`'s low (`64 - mask_start`) bits into `RA` starting at bit `b`. - **`SH` and `MB` decoding** is identical to the rest of the family (6-bit `sh` via `instr.sh64()`, 6-bit `mb` via the swap layout). - **`Rc=1` CR0 is correctly 64-bit.** Uses `as i64` directly. diff --git a/tools/ppc-manual/alu/rlwimix.md b/tools/ppc-manual/alu/rlwimix.md index 70322621..73f78280 100644 --- a/tools/ppc-manual/alu/rlwimix.md +++ b/tools/ppc-manual/alu/rlwimix.md @@ -63,28 +63,26 @@ rlwimi[Rc] [RA], [RS], [SH], [MB], [ME] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,27 +90,37 @@ rlwimi[Rc] [RA], [RS], [SH], [MB], [ME] ## Implementation References **`rlwimix`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rlwimix"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1010`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1010) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:344`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L344) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:737-749`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L737-L749) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rlwimix"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1010`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1010) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:210`](../../../crates/sylpheed-ppc/src/opcode.rs#L210) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:459`](../../../crates/sylpheed-ppc/src/decoder.rs#L459) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::rlwimix => { - let rs = ctx.gpr[instr.rs()] as u32; - let sh = instr.sh(); - let mb = instr.mb(); - let me = instr.me(); - let rotated = rs.rotate_left(sh); - let mask = rlw_mask(mb, me); - let ra = ctx.gpr[instr.ra()] as u32; - ctx.gpr[instr.ra()] = ((rotated & mask) | (ra & !mask)) as u64; - // PPCBUG-025: 32-bit ABI CR0 view. - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_rlwimix(PPCHIRBuilder& f, const InstrData& i) { + // n <- SH + // r <- ROTL32((RS)[32:63], n) + // m <- MASK(MB+32, ME+32) + // RA <- r&m | (RA)&¬m + Value* v = f.LoadGPR(i.M.RT); + // (x||x) + v = f.Or(f.Shl(v, 32), f.ZeroExtend(f.Truncate(v, INT32_TYPE), INT64_TYPE)); + if (i.M.SH) { + v = f.RotateLeft(v, f.LoadConstantInt8(i.M.SH)); + } + // Compiler sometimes masks with 0xFFFFFFFF (identity) - avoid the work here + // as our truncation/zero-extend does it for us. + uint64_t m = XEMASK(i.M.MB + 32, i.M.ME + 32); + if (m != 0xFFFFFFFFFFFFFFFFull) { + v = f.And(v, f.LoadConstantUint64(m)); + } + v = f.Or(v, f.And(f.LoadGPR(i.M.RA), f.LoadConstantUint64(~m))); + f.StoreGPR(i.M.RA, v); + if (i.M.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -120,11 +128,11 @@ rlwimi[Rc] [RA], [RS], [SH], [MB], [ME] ## Special Cases & Edge Conditions -- **`RA ← (ROTL32(RS[32:63], SH) & MASK) | (RA[32:63] & ~MASK)`.** Reads the low 32 bits of `RS`, rotates them, then *inserts* under the mask back into the low 32 bits of `RA`. The high 32 bits of `RA` are *implementation-defined* per spec; **xenia-rs zeroes them** (the `as u32` cast at [`interpreter.rs:529`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L529) discards them on read, then `as u64` zero-extends on write). +- **`RA ← (ROTL32(RS[32:63], SH) & MASK) | (RA[32:63] & ~MASK)`.** Reads the low 32 bits of `RS`, rotates them, then *inserts* under the mask back into the low 32 bits of `RA`. The high 32 bits of `RA` are *implementation-defined* per spec; **xenia-rs zeroes them** (the `as u32` cast at [`interpreter.rs:529`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) discards them on read, then `as u64` zero-extends on write). - **Mask follows the standard `MB..ME` PPC convention.** Both `MB` and `ME` are 5-bit fields; the mask is contiguous when `MB <= ME`, and *wraps* around (a "donut" mask: bits `MB..31` and `0..ME`) when `MB > ME`. Xenia's `rlw_mask(mb, me)` helper handles both cases. - **`SH` is 5 bits.** Rotate amount is `SH mod 32`; values `≥ 32` are not encodable in this M-form. - **Used for bit-field insertion** (`insrwi RA, RS, n, b` ≡ `rlwimi RA, RS, 32-(b+n), b, b+n-1`). Compilers emit `rlwimi` extensively for struct-bitfield writes. -- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:531`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L531). Since the high 32 bits of the result are zero, this matches spec's compare on the (defined) low half — but if a real Xenon left high bits non-zero, behaviour would diverge. +- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:531`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). Since the high 32 bits of the result are zero, this matches spec's compare on the (defined) low half — but if a real Xenon left high bits non-zero, behaviour would diverge. - **No `XER` effect.** ## Related Instructions diff --git a/tools/ppc-manual/alu/rlwinmx.md b/tools/ppc-manual/alu/rlwinmx.md index da4bbcff..a904f73a 100644 --- a/tools/ppc-manual/alu/rlwinmx.md +++ b/tools/ppc-manual/alu/rlwinmx.md @@ -63,28 +63,26 @@ rlwinm[Rc] [RA], [RS], [SH], [MB], [ME] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,26 +90,67 @@ rlwinm[Rc] [RA], [RS], [SH], [MB], [ME] ## Implementation References **`rlwinmx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rlwinmx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1046`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1046) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:345`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L345) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:725-736`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L725-L736) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rlwinmx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1046`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1046) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:211`](../../../crates/sylpheed-ppc/src/opcode.rs#L211) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:460`](../../../crates/sylpheed-ppc/src/decoder.rs#L460) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::rlwinmx => { - let rs = ctx.gpr[instr.rs()] as u32; - let sh = instr.sh(); - let mb = instr.mb(); - let me = instr.me(); - let rotated = rs.rotate_left(sh); - let mask = rlw_mask(mb, me); - ctx.gpr[instr.ra()] = (rotated & mask) as u64; - // PPCBUG-024: 32-bit ABI CR0 view. - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_rlwinmx(PPCHIRBuilder& f, const InstrData& i) { + // n <- SH + // r <- ROTL32((RS)[32:63], n) + // m <- MASK(MB+32, ME+32) + // RA <- r & m + Value* v = f.LoadGPR(i.M.RT); + + unsigned rotation = i.M.SH; + + uint64_t m = XEMASK(i.M.MB + 32, i.M.ME + 32); + + // in uint32 range (so no register concat/truncate/zx needed) and no rotation + if (m < (1ULL << 32) && (rotation == 0)) { + v = f.And(v, f.LoadConstantUint64(m)); + } + // masks out all the bits that are rotated in from the right, so just do a + // shift + and. the and with 0xFFFFFFFF is done instead of a truncate/zx + // because we have a special case for it in the emitters that will just do a + // single insn (mov reg32, lowpartofreg64), otherwise we generate + // significantly more code from setting up the opnds of the truncate/zx + else if (InstrCheck_rlx_only_needs_low(rotation, m)) { + // this path is taken for like 90% of all rlwinms + v = f.And(f.Shl(v, rotation), f.LoadConstantUint64(0xFFFFFFFF)); + } + + else { + // (x||x) + // cs: changed this to mask with UINT32_MAX instead of doing the + // truncate/extend, this generates better code in the backend and is easier + // to do analysis on + v = f.And(v, f.LoadConstantUint64(0xFFFFFFFF)); + + v = f.Or(f.Shl(v, 32), v); + + // TODO(benvanik): optimize srwi + // TODO(benvanik): optimize slwi + // The compiler will generate a bunch of these for the special case of SH=0. + // Which seems to just select some bits and set cr0 for use with a branch. + // We can detect this and do less work. + if (i.M.SH) { + v = f.RotateLeft(v, f.LoadConstantInt8(rotation)); + } + // Compiler sometimes masks with 0xFFFFFFFF (identity) - avoid the work here + // as our truncation/zero-extend does it for us. + if (m != 0xFFFFFFFFFFFFFFFFull) { + v = f.And(v, f.LoadConstantUint64(m)); + } + } + f.StoreGPR(i.M.RA, v); + if (i.M.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -128,7 +167,7 @@ rlwinm[Rc] [RA], [RS], [SH], [MB], [ME] - `extlwi`, `extrwi`, `clrlslwi` — full mnemonic family in PowerISA appendix. - **Mask convention `MB..ME`** is contiguous when `MB ≤ ME`. When `MB > ME`, the mask is the *complement* of bits `ME+1..MB-1` — a donut/wrap mask. Xenia's `rlw_mask` handles both. - **`SH` is 5 bits**, rotate amount `0..31`. -- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:518`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L518). Since the result fits in 32 bits, the truncation matches spec exactly. +- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:518`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). Since the result fits in 32 bits, the truncation matches spec exactly. - **No `XER` effect.** ## Related Instructions diff --git a/tools/ppc-manual/alu/rlwnmx.md b/tools/ppc-manual/alu/rlwnmx.md index e5c96ff7..128c7890 100644 --- a/tools/ppc-manual/alu/rlwnmx.md +++ b/tools/ppc-manual/alu/rlwnmx.md @@ -63,28 +63,26 @@ rlwnm[Rc] [RA], [RS], [RB], [MB], [ME] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,26 +90,31 @@ rlwnm[Rc] [RA], [RS], [RB], [MB], [ME] ## Implementation References **`rlwnmx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rlwnmx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1101`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1101) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:61`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L61) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:346`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L346) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:750-761`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L750-L761) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="rlwnmx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1101`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1101) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:212`](../../../crates/sylpheed-ppc/src/opcode.rs#L212) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:461`](../../../crates/sylpheed-ppc/src/decoder.rs#L461) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::rlwnmx => { - let rs = ctx.gpr[instr.rs()] as u32; - let sh = ctx.gpr[instr.rb()] as u32 & 0x1F; - let mb = instr.mb(); - let me = instr.me(); - let rotated = rs.rotate_left(sh); - let mask = rlw_mask(mb, me); - ctx.gpr[instr.ra()] = (rotated & mask) as u64; - // PPCBUG-026: 32-bit ABI CR0 view. - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_rlwnmx(PPCHIRBuilder& f, const InstrData& i) { + // n <- (RB)[59:63] + // r <- ROTL32((RS)[32:63], n) + // m <- MASK(MB+32, ME+32) + // RA <- r & m + Value* sh = + f.And(f.Truncate(f.LoadGPR(i.M.SH), INT8_TYPE), f.LoadConstantInt8(0x1F)); + Value* v = f.LoadGPR(i.M.RT); + // (x||x) + v = f.Or(f.Shl(v, 32), f.ZeroExtend(f.Truncate(v, INT32_TYPE), INT64_TYPE)); + v = f.RotateLeft(v, sh); + v = f.And(v, f.LoadConstantUint64(XEMASK(i.M.MB + 32, i.M.ME + 32))); + f.StoreGPR(i.M.RA, v); + if (i.M.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -119,12 +122,12 @@ rlwnm[Rc] [RA], [RS], [RB], [MB], [ME] ## Special Cases & Edge Conditions -- **`RA ← ROTL32(RS[32:63], RB[59:63]) & MASK(MB, ME)`.** Identical to [`rlwinmx`](rlwinmx.md) except the rotate amount comes from the low 5 bits of `RB`. Xenia masks with `& 0x1F` ([`interpreter.rs:535`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L535)). +- **`RA ← ROTL32(RS[32:63], RB[59:63]) & MASK(MB, ME)`.** Identical to [`rlwinmx`](rlwinmx.md) except the rotate amount comes from the low 5 bits of `RB`. Xenia masks with `& 0x1F` ([`interpreter.rs:535`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). - **Use over `rlwinm`** when the rotate amount is dynamic (e.g. computed from a `cntlzw` for normalisation, or read from a parameter). - **Mask is still 5+5 bits immediate** — `MB` and `ME` are not register-sourced; only the shift is. This is the M-form's quirk: only one of (`SH`, `MB`, `ME`) is variable across the family. - **Donut masks supported.** `MB > ME` produces a wraparound mask, same as `rlwinm`. - **High 32 bits of `RA` are zero** (32-bit operation, then `as u64` zero-extends). -- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:540`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L540) — harmless because the result already fits in 32 bits. +- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:540`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) — harmless because the result already fits in 32 bits. - **No `XER` effect.** ## Related Instructions diff --git a/tools/ppc-manual/alu/sldx.md b/tools/ppc-manual/alu/sldx.md index c77837c4..629ba7db 100644 --- a/tools/ppc-manual/alu/sldx.md +++ b/tools/ppc-manual/alu/sldx.md @@ -67,13 +67,15 @@ RA <- ((RS) << n) if n < 64 else 0 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -81,22 +83,31 @@ RA <- ((RS) << n) if n < 64 else 0 ## Implementation References **`sldx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sldx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1122`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1122) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:759`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L759) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:676-683`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L676-L683) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sldx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1122`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1122) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:216`](../../../crates/sylpheed-ppc/src/opcode.rs#L216) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:874`](../../../crates/sylpheed-ppc/src/decoder.rs#L874) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sldx => { - let sh = ctx.gpr[instr.rb()] & 0x7F; - ctx.gpr[instr.ra()] = if sh < 64 { - ctx.gpr[instr.rs()] << sh - } else { 0 }; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_sldx(PPCHIRBuilder& f, const InstrData& i) { + // n <- (RB)[58:63] + // r <- ROTL64((RS), n) + // if (RB)[57] = 0 then + // m <- MASK(0, 63-n) + // else + // m <- i64.0 + // RA <- r & m + Value* sh = + f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x7F)); + Value* v = f.Select(f.IsTrue(f.Shr(sh, 6)), f.LoadZeroInt64(), + f.Shl(f.LoadGPR(i.X.RT), sh)); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -105,9 +116,9 @@ RA <- ((RS) << n) if n < 64 else 0 ## Special Cases & Edge Conditions - **64-bit logical left shift.** `RA ← RS << (RB & 0x7F)` if the shift count is `< 64`, otherwise `RA = 0`. Bits shifted past bit 0 are discarded. -- **Critical: shift count is *7 bits*, not 6.** PowerISA reads `RB[57:63]` (7 bits, `0..127`). Counts in `[64, 127]` produce zero, *not* `RS << (count mod 64)`. Xenia respects this with `& 0x7F` and an explicit `if sh < 64` check ([`interpreter.rs:464`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L464)). C semantics' undefined behaviour for `<<` with a count `>= width` is a spec-violation source if you naïvely translate. +- **Critical: shift count is *7 bits*, not 6.** PowerISA reads `RB[57:63]` (7 bits, `0..127`). Counts in `[64, 127]` produce zero, *not* `RS << (count mod 64)`. Xenia respects this with `& 0x7F` and an explicit `if sh < 64` check ([`interpreter.rs:464`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). C semantics' undefined behaviour for `<<` with a count `>= width` is a spec-violation source if you naïvely translate. - **No `XER[CA]` produced** by left shifts. Logical right [`srdx`](srdx.md) and arithmetic right [`sradx`](sradx.md) differ here — arithmetic right *does* set `CA`. -- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:467`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L467) uses `as i64` directly. CR0 reflects the sign of the full 64-bit shifted value (which is 0 for shifts ≥ 64, otherwise either `LT`/`GT`/`EQ`). +- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:467`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) uses `as i64` directly. CR0 reflects the sign of the full 64-bit shifted value (which is 0 for shifts ≥ 64, otherwise either `LT`/`GT`/`EQ`). - **Strength-reduced from `mulli` for power-of-two multipliers.** - **No `OE` bit.** diff --git a/tools/ppc-manual/alu/slwx.md b/tools/ppc-manual/alu/slwx.md index 287d9b7d..9a6ce6bf 100644 --- a/tools/ppc-manual/alu/slwx.md +++ b/tools/ppc-manual/alu/slwx.md @@ -67,13 +67,15 @@ RA <- ((RS) << n) & 0x0000_0000_FFFF_FFFF if n < 32 else 0 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -81,24 +83,32 @@ RA <- ((RS) << n) & 0x0000_0000_FFFF_FFFF if n < 32 else 0 ## Implementation References **`slwx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="slwx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1141`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1141) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:757`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L757) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:622-631`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L622-L631) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="slwx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1141`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1141) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:217`](../../../crates/sylpheed-ppc/src/opcode.rs#L217) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:872`](../../../crates/sylpheed-ppc/src/decoder.rs#L872) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::slwx => { - // PPCBUG-044: 32-bit ABI CR0 view. A result with bit 31 set - // (e.g. 0x80000000) is negative in i32 view but positive in i64. - let sh = ctx.gpr[instr.rb()] as u32; - ctx.gpr[instr.ra()] = if sh < 32 { - ((ctx.gpr[instr.rs()] as u32) << sh) as u64 - } else { 0 }; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_slwx(PPCHIRBuilder& f, const InstrData& i) { + // n <- (RB)[59:63] + // r <- ROTL32((RS)[32:63], n) + // if (RB)[58] = 0 then + // m <- MASK(32, 63-n) + // else + // m <- i64.0 + // RA <- r & m + Value* sh = + f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x3F)); + Value* v = f.Select(f.IsTrue(f.Shr(sh, 5)), f.LoadZeroInt32(), + f.Shl(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE), sh)); + v = f.ZeroExtend(v, INT64_TYPE); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -107,10 +117,10 @@ RA <- ((RS) << n) & 0x0000_0000_FFFF_FFFF if n < 32 else 0 ## Special Cases & Edge Conditions - **32-bit logical left shift, zero-extended to 64.** `RA ← (RS[32:63] << (RB & 0x3F))[32:63]` if `(RB & 0x3F) < 32`, else `RA = 0`. The high 32 bits of `RA` are always zero (zero-extension of the 32-bit result). -- **Shift count is 6 bits**, `RB[58:63]` — not 7 like [`sldx`](sldx.md). Counts in `[32, 63]` produce zero. Xenia reads the full register but the explicit `if sh < 32` guard in [`interpreter.rs:417`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L417) prevents Rust UB. +- **Shift count is 6 bits**, `RB[58:63]` — not 7 like [`sldx`](sldx.md). Counts in `[32, 63]` produce zero. Xenia reads the full register but the explicit `if sh < 32` guard in [`interpreter.rs:417`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) prevents Rust UB. - **Spec quirk worth flagging:** xenia reads `ctx.gpr[instr.rb()] as u32`, which uses the low 32 bits of `RB`, not the spec's `RB & 0x3F`. For ordinary code these agree (counts ≤ 63), but a maliciously high `RB` could in principle differ. In practice this is a non-issue. - **No `XER[CA]` for left shifts.** -- **`Rc=1` CR0 update truncates to 32 bits** ([`interpreter.rs:420`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L420)). Since the high 32 bits are zero, this matches spec exactly. +- **`Rc=1` CR0 update truncates to 32 bits** ([`interpreter.rs:420`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). Since the high 32 bits are zero, this matches spec exactly. - **No `OE` bit.** ## Related Instructions diff --git a/tools/ppc-manual/alu/sradix.md b/tools/ppc-manual/alu/sradix.md index a6a336e5..8d87f3a2 100644 --- a/tools/ppc-manual/alu/sradix.md +++ b/tools/ppc-manual/alu/sradix.md @@ -69,13 +69,15 @@ CA <- (RS signed < 0) && any_bit_shifted_out ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -83,28 +85,44 @@ CA <- (RS signed < 0) && any_bit_shifted_out ## Implementation References **`sradix`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sradix"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1230`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1230) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:743`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L743) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:709-722`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L709-L722) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sradix"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1230`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1230) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:218`](../../../crates/sylpheed-ppc/src/opcode.rs#L218) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:858`](../../../crates/sylpheed-ppc/src/decoder.rs#L858) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sradix => { - let rs = ctx.gpr[instr.rs()] as i64; - let sh = instr.sh64(); - if sh == 0 { - ctx.gpr[instr.ra()] = rs as u64; - ctx.xer_ca = 0; - } else { - let result = rs >> sh; - ctx.xer_ca = if rs < 0 && (rs as u64) << (64 - sh) != 0 { 1 } else { 0 }; - ctx.gpr[instr.ra()] = result as u64; - } - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_sradix(PPCHIRBuilder& f, const InstrData& i) { + // n <- sh[5] || sh[0-4] + // r <- ROTL[64](rS, 64 - n) + // m ← MASK(n, 63) + // S ← rS[0] + // rA <- (r & m) | (((64)S) & ¬ m) + // XER[CA] <- S & ((r & ¬ m) ¦ 0) + // if n == 0: rA <- rS, XER[CA] = 0 + // if n >= 64: rA <- 64 sign bits of rS, XER[CA] = sign bit of rS + Value* v = f.LoadGPR(i.XS.RT); + int8_t sh = (i.XS.SH5 << 5) | i.XS.SH; + + // CA is set if any bits are shifted out of the right and if the result + // is negative. + if (sh) { + uint64_t mask = XEMASK(64 - sh, 63); + Value* ca = f.And(f.Truncate(f.Shr(v, 63), INT8_TYPE), + f.IsTrue(f.And(v, f.LoadConstantUint64(mask)))); + f.StoreCA(ca); + + v = f.Sha(v, sh); + } else { + f.StoreCA(f.LoadZeroInt8()); + } + + f.StoreGPR(i.XS.RA, v); + if (i.XS.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -113,10 +131,10 @@ CA <- (RS signed < 0) && any_bit_shifted_out ## Special Cases & Edge Conditions - **`RA ← (i64)RS >> SH`**, with `XER[CA]` set when `RS` is negative AND any one-bit was shifted out. -- **`SH` is 6 bits.** Encoded in bits 16–20 (`sh`) plus bit 30 (`sh5`); xenia uses `instr.sh64()` to assemble the 6 bits ([`interpreter.rs:496`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L496)). Range `0..63`. -- **`SH = 0`** is a no-op (sign-extends `RS` to itself), and explicitly clears `XER[CA]` ([`interpreter.rs:498`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L498)). This matches spec. +- **`SH` is 6 bits.** Encoded in bits 16–20 (`sh`) plus bit 30 (`sh5`); xenia uses `instr.sh64()` to assemble the 6 bits ([`interpreter.rs:496`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). Range `0..63`. +- **`SH = 0`** is a no-op (sign-extends `RS` to itself), and explicitly clears `XER[CA]` ([`interpreter.rs:498`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). This matches spec. - **Spec divergence: 6-bit immediate, no saturation arm.** Unlike [`sradx`](sradx.md) which has a 7-bit register count and saturates at `≥ 64`, `sradi` always uses a count `< 64` so no special saturation case is needed. -- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:506`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L506). +- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:506`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). - **Idiom: `sradi rA, rS, n; addze rA, rA`** — signed integer divide by `2^n` rounded toward zero (the textbook PPC sequence). - **No `OE` bit.** diff --git a/tools/ppc-manual/alu/sradx.md b/tools/ppc-manual/alu/sradx.md index 07cf0c92..9e4c70f2 100644 --- a/tools/ppc-manual/alu/sradx.md +++ b/tools/ppc-manual/alu/sradx.md @@ -69,13 +69,15 @@ CA <- (RS signed < 0) && any_bit_shifted_out ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -83,31 +85,41 @@ CA <- (RS signed < 0) && any_bit_shifted_out ## Implementation References **`sradx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sradx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1201`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1201) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:841`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L841) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:692-708`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L692-L708) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sradx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1201`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1201) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:219`](../../../crates/sylpheed-ppc/src/opcode.rs#L219) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:956`](../../../crates/sylpheed-ppc/src/decoder.rs#L956) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sradx => { - let rs = ctx.gpr[instr.rs()] as i64; - let sh = ctx.gpr[instr.rb()] & 0x7F; - if sh == 0 { - ctx.gpr[instr.ra()] = rs as u64; - ctx.xer_ca = 0; - } else if sh < 64 { - let result = rs >> sh; - ctx.xer_ca = if rs < 0 && (rs as u64) << (64 - sh) != 0 { 1 } else { 0 }; - ctx.gpr[instr.ra()] = result as u64; - } else { - ctx.gpr[instr.ra()] = if rs < 0 { u64::MAX } else { 0 }; - ctx.xer_ca = if rs < 0 { 1 } else { 0 }; - } - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_sradx(PPCHIRBuilder& f, const InstrData& i) { + // n <- rB[58-63] + // r <- ROTL[64](rS, 64 - n) + // if rB[57] = 0 then m ← MASK(n, 63) + // else m ← (64)0 + // S ← rS[0] + // rA <- (r & m) | (((64)S) & ¬ m) + // XER[CA] <- S & ((r & ¬ m) ¦ 0) + // if n == 0: rA <- rS, XER[CA] = 0 + // if n >= 64: rA <- 64 sign bits of rS, XER[CA] = sign bit of rS + Value* rt = f.LoadGPR(i.X.RT); + Value* sh = + f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x7F)); + Value* clamp_sh = f.Min(sh, f.LoadConstantInt8(0x3F)); + Value* v = f.Sha(rt, clamp_sh); + + // CA is set if any bits are shifted out of the right and if the result + // is negative. + Value* ca = + f.And(f.IsTrue(f.Shr(rt, 63)), f.CompareNE(f.Shl(v, clamp_sh), rt)); + f.StoreCA(ca); + + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -117,9 +129,9 @@ CA <- (RS signed < 0) && any_bit_shifted_out - **64-bit arithmetic (sign-propagating) right shift.** `RA ← (i64)RS >> (RB & 0x7F)` with bits shifted in matching the sign bit of `RS`. Counts ≥ 64 saturate: `RA` becomes all-ones if `RS < 0`, else zero. - **`XER[CA]` is the "lost-ones" indicator.** `CA = 1` iff `RS` is negative AND any of the bits shifted out were `1`. This makes `srad` / `sradi` the standard idiom for "divide negative integer by power of 2 with round-toward-zero" — followed by `addze` to compensate when `CA = 1`. -- **Three branches in xenia.** `sh == 0` (no shift, `CA=0`), `sh < 64` (normal shift, `CA` per spec), and `sh ≥ 64` (saturate to `0` or `−1`, `CA` reflects sign). The `(rs as u64) << (64 - sh) != 0` check at [`interpreter.rs:486`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L486) extracts whether any non-zero bit was shifted out. +- **Three branches in xenia.** `sh == 0` (no shift, `CA=0`), `sh < 64` (normal shift, `CA` per spec), and `sh ≥ 64` (saturate to `0` or `−1`, `CA` reflects sign). The `(rs as u64) << (64 - sh) != 0` check at [`interpreter.rs:486`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) extracts whether any non-zero bit was shifted out. - **Shift count is 7 bits.** Same as [`sldx`](sldx.md): `RB[57:63]`. -- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:489`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L489). +- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:489`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). - **No `OE` bit.** - **Used by signed-divide-by-power-of-2 idiom:** `srad rA, rS, n; addze rA, rA` produces `rS / 2^n` with truncation toward zero rather than toward `-∞`. diff --git a/tools/ppc-manual/alu/srawix.md b/tools/ppc-manual/alu/srawix.md index baae2ab2..08e98a02 100644 --- a/tools/ppc-manual/alu/srawix.md +++ b/tools/ppc-manual/alu/srawix.md @@ -68,13 +68,15 @@ CA <- (RS[32] signed) && any_low_bit_shifted_out ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -82,29 +84,51 @@ CA <- (RS[32] signed) && any_low_bit_shifted_out ## Implementation References **`srawix`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srawix"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1291`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1291) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:843`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L843) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:661-675`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L661-L675) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srawix"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1291`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1291) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:220`](../../../crates/sylpheed-ppc/src/opcode.rs#L220) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:958`](../../../crates/sylpheed-ppc/src/decoder.rs#L958) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::srawix => { - // PPCBUG-042+043 coupled: same shape as srawx for the sh-immediate form. - let rs = ctx.gpr[instr.rs()] as i32; - let sh = instr.sh(); - if sh == 0 { - ctx.gpr[instr.ra()] = rs as u32 as u64; - ctx.xer_ca = 0; - } else { - let result = rs >> sh; - ctx.xer_ca = if rs < 0 && (rs as u32) << (32 - sh) != 0 { 1 } else { 0 }; - ctx.gpr[instr.ra()] = result as u32 as u64; - } - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_srawix(PPCHIRBuilder& f, const InstrData& i) { + // n <- SH + // r <- ROTL32((RS)[32:63], 64-n) + // m <- MASK(n+32, 63) + // s <- (RS)[32] + // RA <- r&m | (i64.s)&¬m + // CA <- s & ((r&¬m)[32:63]≠0) + // if n == 0: rA <- sign_extend(rS), XER[CA] = 0 + // if n >= 32: rA <- 64 sign bits of rS, XER[CA] = sign bit of lo_32(rS) + Value* v = f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE); + Value* ca; + if (!i.X.RB) { + // No shift, just a fancy sign extend and CA clearer. + v = f.SignExtend(v, INT64_TYPE); + ca = f.LoadZeroInt8(); + } else { + // CA is set if any bits are shifted out of the right and if the result + // is negative. + uint32_t mask = (uint32_t)XEMASK(64 - i.X.RB, 63); + + if (mask == 1) { + ca = f.And(f.CompareSLT(v, f.LoadConstantInt32(0)), + f.Truncate(v, INT8_TYPE)); + + } else { + ca = f.And(f.CompareSLT(v, f.LoadConstantInt32(0)), + f.IsTrue(f.And(v, f.LoadConstantUint32(mask)))); + } + + v = f.Sha(v, (int8_t)i.X.RB), v = f.SignExtend(v, INT64_TYPE); + } + f.StoreCA(ca); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -117,7 +141,7 @@ CA <- (RS[32] signed) && any_low_bit_shifted_out - **`SH = 0`** sign-extends `RS[32:63]` to 64 bits and clears `CA`. This is *not* a no-op when `RS`'s high 32 bits differ from the sign extension of bit 32. - **Common idiom: `srawi rA, rS, 31`** materialises the 32-bit sign of `rS` as `0` or `−1` — the canonical "sign mask" pattern. Often used for branchless `abs` or conditional negation. - **Idiom: `srawi rA, rS, n; addze rA, rA`** — divide signed by `2^n` rounding toward zero. -- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:457`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L457) — matches spec because the sign-extended result has consistent low/high 32-bit signs. +- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:457`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) — matches spec because the sign-extended result has consistent low/high 32-bit signs. - **No `OE` bit.** ## Related Instructions diff --git a/tools/ppc-manual/alu/srawx.md b/tools/ppc-manual/alu/srawx.md index f07950a6..497477a1 100644 --- a/tools/ppc-manual/alu/srawx.md +++ b/tools/ppc-manual/alu/srawx.md @@ -69,13 +69,15 @@ CA <- 1 if (signed RS < 0) && any_bit_shifted_out else 0 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -83,33 +85,41 @@ CA <- 1 if (signed RS < 0) && any_bit_shifted_out else 0 ## Implementation References **`srawx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srawx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1262`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1262) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:840`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L840) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:642-660`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L642-L660) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srawx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1262`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1262) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:221`](../../../crates/sylpheed-ppc/src/opcode.rs#L221) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:955`](../../../crates/sylpheed-ppc/src/decoder.rs#L955) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::srawx => { - // PPCBUG-041+043 coupled: 32-bit ABI writeback truncation + CR0 i32. - // CA logic is independently correct (uses u32 shifted-out test). - let rs = ctx.gpr[instr.rs()] as i32; - let sh = ctx.gpr[instr.rb()] as u32 & 0x3F; - if sh == 0 { - ctx.gpr[instr.ra()] = rs as u32 as u64; - ctx.xer_ca = 0; - } else if sh < 32 { - let result = rs >> sh; - ctx.xer_ca = if rs < 0 && (rs as u32) << (32 - sh) != 0 { 1 } else { 0 }; - ctx.gpr[instr.ra()] = result as u32 as u64; - } else { - ctx.gpr[instr.ra()] = if rs < 0 { 0xFFFF_FFFFu64 } else { 0 }; - ctx.xer_ca = if rs < 0 { 1 } else { 0 }; - } - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_srawx(PPCHIRBuilder& f, const InstrData& i) { + // n <- rB[59-63] + // r <- ROTL32((RS)[32:63], 64-n) + // m <- MASK(n+32, 63) + // s <- (RS)[32] + // RA <- r&m | (i64.s)&¬m + // CA <- s & ((r&¬m)[32:63]≠0) + // if n == 0: rA <- sign_extend(rS), XER[CA] = 0 + // if n >= 32: rA <- 64 sign bits of rS, XER[CA] = sign bit of lo_32(rS) + Value* rt = f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE); + Value* sh = + f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x3F)); + Value* clamp_sh = f.Min(sh, f.LoadConstantInt8(0x1F)); + Value* v = f.Sha(rt, f.Min(sh, clamp_sh)); + + // CA is set if any bits are shifted out of the right and if the result + // is negative. + Value* ca = + f.And(f.IsTrue(f.Shr(rt, 31)), f.CompareNE(f.Shl(v, clamp_sh), rt)); + f.StoreCA(ca); + + v = f.SignExtend(v, INT64_TYPE); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -118,10 +128,10 @@ CA <- 1 if (signed RS < 0) && any_bit_shifted_out else 0 ## Special Cases & Edge Conditions - **32-bit arithmetic right shift, sign-extended to 64.** `RA ← ((i32)RS >> n) sign-extended`, with `XER[CA]` set when `RS[32] = 1` (negative) AND any low bit was shifted out. -- **Shift count is 6 bits**, `RB[58:63]`. Counts `≥ 32` saturate: `RA = -1` (all-ones, sign-extended) if `RS < 0`, else `0`. Xenia handles this in three branches ([`interpreter.rs:432-444`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L432-L444)). +- **Shift count is 6 bits**, `RB[58:63]`. Counts `≥ 32` saturate: `RA = -1` (all-ones, sign-extended) if `RS < 0`, else `0`. Xenia handles this in three branches ([`interpreter.rs:432-444`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). - **`SH = 0`** sign-extends `RS` to 64 bits and clears `XER[CA]` — like `extsw`, but additionally writing CA. - **Result is always sign-extended to 64 bits.** `RA[0:31]` matches the sign of `RA[32]`. This is the key difference from [`srwx`](srwx.md) (zero-extension). -- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:443`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L443) — but since the result is sign-extended, the low 32 bits' sign matches the full 64-bit sign, so spec and xenia agree here. +- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:443`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) — but since the result is sign-extended, the low 32 bits' sign matches the full 64-bit sign, so spec and xenia agree here. - **Used with [`addzex`](addzex.md)** for signed divide by `2^n` rounding toward zero. - **No `OE` bit.** diff --git a/tools/ppc-manual/alu/srdx.md b/tools/ppc-manual/alu/srdx.md index 34965967..23f6581d 100644 --- a/tools/ppc-manual/alu/srdx.md +++ b/tools/ppc-manual/alu/srdx.md @@ -67,13 +67,15 @@ RA <- ((RS) >> n) if n < 64 else 0 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -81,22 +83,31 @@ RA <- ((RS) >> n) if n < 64 else 0 ## Implementation References **`srdx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srdx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1161`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1161) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:821`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L821) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:684-691`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L684-L691) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srdx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1161`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1161) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:222`](../../../crates/sylpheed-ppc/src/opcode.rs#L222) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:936`](../../../crates/sylpheed-ppc/src/decoder.rs#L936) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::srdx => { - let sh = ctx.gpr[instr.rb()] & 0x7F; - ctx.gpr[instr.ra()] = if sh < 64 { - ctx.gpr[instr.rs()] >> sh - } else { 0 }; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_srdx(PPCHIRBuilder& f, const InstrData& i) { + // n <- (RB)[58:63] + // r <- ROTL64((RS), 64-n) + // if (RB)[57] = 0 then + // m <- MASK(n, 63) + // else + // m <- i64.0 + // RA <- r & m + Value* sh = + f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x7F)); + Value* v = f.Select(f.IsTrue(f.And(sh, f.LoadConstantInt8(0x40))), + f.LoadZeroInt64(), f.Shr(f.LoadGPR(i.X.RT), sh)); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -105,9 +116,9 @@ RA <- ((RS) >> n) if n < 64 else 0 ## Special Cases & Edge Conditions - **64-bit logical right shift.** `RA ← RS >> (RB & 0x7F)` if the count is `< 64`, else `RA = 0`. Bits shifted in from the high end are zero (no sign extension). -- **Shift count is 7 bits** (`RB[57:63]`). Counts `64..127` produce zero, not `RS >> (count mod 64)`. Xenia respects this with `& 0x7F` and an explicit `if sh < 64` check ([`interpreter.rs:472`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L472)). +- **Shift count is 7 bits** (`RB[57:63]`). Counts `64..127` produce zero, not `RS >> (count mod 64)`. Xenia respects this with `& 0x7F` and an explicit `if sh < 64` check ([`interpreter.rs:472`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). - **No `XER[CA]` produced.** This is the logical right shift; for arithmetic shift with `XER[CA]` use [`sradx`](sradx.md). -- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:475`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L475). Result is non-negative as a signed value (high bit is always cleared by the shift), so CR0 will only ever be `EQ` or `GT`. +- **`Rc=1` CR0 is correctly 64-bit.** [`interpreter.rs:475`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). Result is non-negative as a signed value (high bit is always cleared by the shift), so CR0 will only ever be `EQ` or `GT`. - **No `OE` bit.** - **The `srdi` simplified mnemonic** uses [`rldiclx`](rldiclx.md) instead — `rldicl rA, rS, 64-n, n` — because it can be combined with masking. `srd` is for runtime-variable counts. diff --git a/tools/ppc-manual/alu/srwx.md b/tools/ppc-manual/alu/srwx.md index 86f4799e..b0889e89 100644 --- a/tools/ppc-manual/alu/srwx.md +++ b/tools/ppc-manual/alu/srwx.md @@ -67,13 +67,15 @@ RA <- ((RS)[32:63] >> n) zero-extended if n < 32 else 0 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -81,24 +83,33 @@ RA <- ((RS)[32:63] >> n) zero-extended if n < 32 else 0 ## Implementation References **`srwx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srwx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1180`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1180) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:65`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L65) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:820`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L820) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:632-641`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L632-L641) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="srwx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:1180`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L1180) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:223`](../../../crates/sylpheed-ppc/src/opcode.rs#L223) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:935`](../../../crates/sylpheed-ppc/src/decoder.rs#L935) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::srwx => { - // PPCBUG-044: 32-bit ABI CR0 view (zero-extended right shift can never - // have bit 31 set, but use the canonical form for consistency). - let sh = ctx.gpr[instr.rb()] as u32; - ctx.gpr[instr.ra()] = if sh < 32 { - ((ctx.gpr[instr.rs()] as u32) >> sh) as u64 - } else { 0 }; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_srwx(PPCHIRBuilder& f, const InstrData& i) { + // n <- (RB)[59:63] + // r <- ROTL32((RS)[32:63], 64-n) + // if (RB)[58] = 0 then + // m <- MASK(n+32, 63) + // else + // m <- i64.0 + // RA <- r & m + Value* sh = + f.And(f.Truncate(f.LoadGPR(i.X.RB), INT8_TYPE), f.LoadConstantInt8(0x3F)); + Value* v = + f.Select(f.IsTrue(f.And(sh, f.LoadConstantInt8(0x20))), f.LoadZeroInt32(), + f.Shr(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE), sh)); + v = f.ZeroExtend(v, INT64_TYPE); + f.StoreGPR(i.X.RA, v); + if (i.X.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -107,9 +118,9 @@ RA <- ((RS)[32:63] >> n) zero-extended if n < 32 else 0 ## Special Cases & Edge Conditions - **32-bit logical right shift, zero-extended to 64.** `RA ← (u32)RS >> (RB & 0x3F)` if count `< 32`, else `RA = 0`. The high 32 bits of `RA` are always zero. -- **Shift count is 6 bits**, `RB[58:63]`. Counts `[32, 63]` produce zero (not `RS >> (count mod 32)`); xenia's explicit `if sh < 32` guards against Rust UB ([`interpreter.rs:425`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L425)). +- **Shift count is 6 bits**, `RB[58:63]`. Counts `[32, 63]` produce zero (not `RS >> (count mod 32)`); xenia's explicit `if sh < 32` guards against Rust UB ([`interpreter.rs:425`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). - **No `XER[CA]` produced.** For arithmetic shift with `XER[CA]` use [`srawx`](srawx.md). -- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:428`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L428). Since the result has zeroed high 32 bits and zeroed sign bit (high bit of the 32-bit result is always 0 after a non-zero shift), CR0 will be `EQ` or `GT`. +- **`Rc=1` CR0 update truncates to 32 bits in xenia-rs.** [`interpreter.rs:428`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). Since the result has zeroed high 32 bits and zeroed sign bit (high bit of the 32-bit result is always 0 after a non-zero shift), CR0 will be `EQ` or `GT`. - **No `OE` bit.** - **`srwi` simplified mnemonic** uses [`rlwinmx`](rlwinmx.md), not this instruction. `srw` is for runtime-variable counts. diff --git a/tools/ppc-manual/alu/subfcx.md b/tools/ppc-manual/alu/subfcx.md index 0b6255a6..c2b1fe8e 100644 --- a/tools/ppc-manual/alu/subfcx.md +++ b/tools/ppc-manual/alu/subfcx.md @@ -71,13 +71,15 @@ CA <- carry_out ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,32 +87,30 @@ CA <- carry_out ## Implementation References **`subfcx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfcx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:441`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L441) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:859`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L859) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:270-287`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L270-L287) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfcx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:441`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L441) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:281`](../../../crates/sylpheed-ppc/src/opcode.rs#L281) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:974`](../../../crates/sylpheed-ppc/src/decoder.rs#L974) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::subfcx => { - // PPCBUG-007: 32-bit ABI. The `rb >= ra` u64 unsigned compare is - // exactly the shape that broke addis. Defensive 32-bit truncation - // is required for correct CA even after upstream cleanup. - let ra32 = ctx.gpr[instr.ra()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - let result32 = rb32.wrapping_sub(ra32); - ctx.xer_ca = if rb32 >= ra32 { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - let true_diff = (rb32 as i32 as i128) - (ra32 as i32 as i128); - overflow::apply(ctx, true_diff != (result32 as i32) as i128); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_subfcx(PPCHIRBuilder& f, const InstrData& i) { + // RT <- ¬(RA) + (RB) + 1 + Value* ra = f.LoadGPR(i.XO.RA); + Value* rb = f.LoadGPR(i.XO.RB); + Value* v = f.Sub(rb, ra); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEINSTRNOTIMPLEMENTED(); + // e.update_xer_with_overflow(EFLAGS??); + } else { + f.StoreCA(SubDidCarry(f, rb, ra)); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -119,9 +119,9 @@ CA <- carry_out ## Special Cases & Edge Conditions - **`RT ← RB − RA` with `XER[CA]` set on no-borrow.** Same operand-order convention as [`subfx`](subfx.md): the *first* source is subtracted *from* the second. -- **`XER[CA] = 1` means *no borrow occurred*** — i.e. `RB >= RA` as unsigned. PowerISA encodes this as the carry-out of `~RA + RB + 1`, not as a borrow flag. Xenia's `if rb >= ra` test ([`interpreter.rs:157`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L157)) is the correct boolean encoding. +- **`XER[CA] = 1` means *no borrow occurred*** — i.e. `RB >= RA` as unsigned. PowerISA encodes this as the carry-out of `~RA + RB + 1`, not as a borrow flag. Xenia's `if rb >= ra` test ([`interpreter.rs:157`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)) is the correct boolean encoding. - **No trap on signed overflow.** `subfco` / `subfco.` set `XER[OV]` and sticky `XER[SO]`; xenia-rs leaves the `OE` arm unimplemented. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:160`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L160) truncates with `as i32 as i64`. Spec demands a full 64-bit signed compare for `subfc.`. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:160`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) truncates with `as i32 as i64`. Spec demands a full 64-bit signed compare for `subfc.`. - **Seeds a multi-word subtract chain.** Use as the low-word op; continue with [`subfex`](subfex.md) for middle words and [`subfmex`](subfmex.md)/[`subfzex`](subfzex.md) for the high word. - **Operand aliasing fine.** `subfc r3, r3, r3` always yields `0` with `CA = 1`. diff --git a/tools/ppc-manual/alu/subfex.md b/tools/ppc-manual/alu/subfex.md index 40d2cdcb..14277082 100644 --- a/tools/ppc-manual/alu/subfex.md +++ b/tools/ppc-manual/alu/subfex.md @@ -71,13 +71,15 @@ CA <- carry_out ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,33 +87,30 @@ CA <- carry_out ## Implementation References **`subfex`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfex"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:468`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L468) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:867`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L867) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:288-306`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L288-L306) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfex"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:468`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L468) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:282`](../../../crates/sylpheed-ppc/src/opcode.rs#L282) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:982`](../../../crates/sylpheed-ppc/src/decoder.rs#L982) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::subfex => { - // PPCBUG-008: 32-bit ABI. Compute in u32 space — `!ra` on u64 always - // pollutes the upper 32 bits, making this an active poisoner. - let ra32 = ctx.gpr[instr.ra()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - let ca = ctx.xer_ca as u32; - let result32 = (!ra32).wrapping_add(rb32).wrapping_add(ca); - ctx.xer_ca = if rb32 > ra32 || (rb32 == ra32 && ca != 0) { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - // RT <- !RA + RB + CA == RB - RA - 1 + CA (32-bit semantics). - let true_sum = (rb32 as i32 as i128) - (ra32 as i32 as i128) - 1 + (ca as i128); - overflow::apply(ctx, true_sum != (result32 as i32) as i128); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_subfex(PPCHIRBuilder& f, const InstrData& i) { + // RT <- ¬(RA) + (RB) + CA + Value* not_ra = f.Not(f.LoadGPR(i.XO.RA)); + Value* rb = f.LoadGPR(i.XO.RB); + Value* v = f.AddWithCarry(not_ra, rb, f.LoadCA()); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEINSTRNOTIMPLEMENTED(); + // e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + } else { + f.StoreCA(AddWithCarryDidCarry(f, not_ra, rb, f.LoadCA())); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -120,9 +119,9 @@ CA <- carry_out ## Special Cases & Edge Conditions - **`RT ← ~RA + RB + XER[CA]`.** The middle link of a multi-word subtract chain seeded by [`subfcx`](subfcx.md). `XER[CA]` propagates the borrow from the previous word. -- **Carry-out predicate handles the boundary case.** Xenia computes `CA' = (rb > ra) || (rb == ra && CA != 0)` ([`interpreter.rs:170`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L170)). The second clause covers when `RB == RA` and the previous chain added a `+1` from the input carry — without it, the carry-out would be wrong. +- **Carry-out predicate handles the boundary case.** Xenia computes `CA' = (rb > ra) || (rb == ra && CA != 0)` ([`interpreter.rs:170`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). The second clause covers when `RB == RA` and the previous chain added a `+1` from the input carry — without it, the carry-out would be wrong. - **`OE=1`** should set `XER[OV]` on signed overflow; xenia-rs ignores it. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:173`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L173). +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:173`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). - **`XER[CA]` must be initialised** (typically by [`subfcx`](subfcx.md)). Reading stale `CA` is a frequent multi-word-subtract bug. - **Symmetry with [`addex`](addex.md).** `subfe RT, RA, RB` ≡ `adde RT, ~RA, RB` (with the implicit complement). diff --git a/tools/ppc-manual/alu/subficx.md b/tools/ppc-manual/alu/subficx.md index 3ab4de0c..2ecff5d6 100644 --- a/tools/ppc-manual/alu/subficx.md +++ b/tools/ppc-manual/alu/subficx.md @@ -57,28 +57,26 @@ subfic [RD], [RA], [SIMM] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,24 +84,21 @@ subfic [RD], [RA], [SIMM] ## Implementation References **`subficx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subficx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:459`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L459) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:333`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L333) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:155-164`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L155-L164) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subficx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:459`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L459) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:283`](../../../crates/sylpheed-ppc/src/opcode.rs#L283) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:448`](../../../crates/sylpheed-ppc/src/decoder.rs#L448) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::subficx => { - // PPCBUG-005: 32-bit ABI. Sign-extended imm has bits 32-63 set for - // negative SIMM, poisoning the writeback. Canary uses 32-bit form. - let ra32 = ctx.gpr[instr.ra()] as u32; - let imm32 = instr.simm16() as i32 as u32; - let result32 = imm32.wrapping_sub(ra32); - ctx.xer_ca = if imm32 >= ra32 { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_subficx(PPCHIRBuilder& f, const InstrData& i) { + // RT <- ¬(RA) + EXTS(SI) + 1 + Value* ra = f.LoadGPR(i.D.RA); + Value* v = f.Sub(f.LoadConstantInt64(XEEXTS16(i.D.DS)), ra); + f.StoreGPR(i.D.RT, v); + f.StoreCA(SubDidCarry(f, f.LoadConstantInt64(XEEXTS16(i.D.DS)), ra)); + return 0; +} ```
@@ -113,7 +108,7 @@ subfic [RD], [RA], [SIMM] - **`RT ← SIMM − RA` with `XER[CA]` always set.** Note the operand order: the *immediate* is the minuend, not the subtrahend. `subfic rD, rA, 1` computes `1 - rA`, useful for negation-plus-one or one's-complement-style operations. - **Immediate is sign-extended** to 64 bits before the subtract. So `subfic rD, rA, -1` computes `-1 - rA`, equivalent to `~rA`. -- **`XER[CA] = 1` when `SIMM >= RA`** (no borrow). Computed in xenia as `if imm >= ra` ([`interpreter.rs:73`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L73)) — comparing the sign-extended unsigned representations. +- **`XER[CA] = 1` when `SIMM >= RA`** (no borrow). Computed in xenia as `if imm >= ra` ([`interpreter.rs:73`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)) — comparing the sign-extended unsigned representations. - **No `Rc`, no `OE`.** This D-form has no flag bits beyond the implicit `CA` write. - **No record-form variant.** There is no `subfic.` in the ISA; if you need CR0 to also reflect the result, follow with a `cmpwi`. - **Synthesised "subtract immediate"**. Assemblers sometimes accept `subi rD, rA, value` as a shorthand for `addi rD, rA, -value`, but for the carry-producing variant you must use `subfic` explicitly. diff --git a/tools/ppc-manual/alu/subfmex.md b/tools/ppc-manual/alu/subfmex.md index aa4611ab..199ac907 100644 --- a/tools/ppc-manual/alu/subfmex.md +++ b/tools/ppc-manual/alu/subfmex.md @@ -64,28 +64,26 @@ subfme[OE][Rc] [RD], [RA] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -93,31 +91,30 @@ subfme[OE][Rc] [RD], [RA] ## Implementation References **`subfmex`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfmex"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:486`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L486) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:871`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L871) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:325-341`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L325-L341) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfmex"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:486`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L486) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:284`](../../../crates/sylpheed-ppc/src/opcode.rs#L284) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:986`](../../../crates/sylpheed-ppc/src/decoder.rs#L986) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::subfmex => { - // PPCBUG-019: also fixes the always-true CA edge — `!ra` on u64 - // is non-zero when ra32==0xFFFFFFFF and ca==0, so CA was stuck at 1. - let ra32 = ctx.gpr[instr.ra()] as u32; - let ca = ctx.xer_ca as u32; - let result32 = (!ra32).wrapping_add(ca).wrapping_sub(1); - ctx.xer_ca = if (!ra32) != 0 || ca != 0 { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - let true_sum = -(ra32 as i32 as i128) - 2 + (ca as i128); - overflow::apply(ctx, true_sum != (result32 as i32) as i128); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_subfmex(PPCHIRBuilder& f, const InstrData& i) { + // RT <- ¬(RA) + CA - 1 + Value* not_ra = f.Not(f.LoadGPR(i.XO.RA)); + Value* v = f.AddWithCarry(not_ra, f.LoadConstantInt64(-1), f.LoadCA()); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEINSTRNOTIMPLEMENTED(); + // e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + } else { + f.StoreCA( + AddWithCarryDidCarry(f, not_ra, f.LoadConstantInt64(-1), f.LoadCA())); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -127,9 +124,9 @@ subfme[OE][Rc] [RD], [RA] - **`RT ← ~RA + (−1) + XER[CA]` ≡ `~RA − 1 + CA`.** Terminator for a multi-word subtract chain when the high "minuend" word is implicitly all-ones (e.g. when computing `~x` style negation across many words). - **`RB` field unused.** XO-form but only `RA` is read. -- **Carry-out predicate.** `CA' = (~RA != 0) || (CA != 0)` ([`interpreter.rs:191`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L191)). Only when `RA == ~0` (all ones) AND `CA == 0` does `CA'` become 0 — every other case produces no borrow on this final word. +- **Carry-out predicate.** `CA' = (~RA != 0) || (CA != 0)` ([`interpreter.rs:191`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). Only when `RA == ~0` (all ones) AND `CA == 0` does `CA'` become 0 — every other case produces no borrow on this final word. - **`OE=1`** should set `XER[OV]` on signed overflow; xenia-rs ignores it. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:194`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L194). +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:194`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). - **`XER[CA]` must be initialised** (typically by a [`subfcx`](subfcx.md) or [`subfex`](subfex.md) earlier in the chain). - **Symmetric with [`addmex`](addmex.md)**, the add-side terminator. diff --git a/tools/ppc-manual/alu/subfx.md b/tools/ppc-manual/alu/subfx.md index 98bf7404..2d8de523 100644 --- a/tools/ppc-manual/alu/subfx.md +++ b/tools/ppc-manual/alu/subfx.md @@ -70,13 +70,15 @@ RT <- ~(RA) + (RB) + 1 ; = (RB) − (RA) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,29 +86,26 @@ RT <- ~(RA) + (RB) + 1 ; = (RB) − (RA) ## Implementation References **`subfx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:427`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L427) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:863`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L863) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:255-269`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L255-L269) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:427`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L427) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:285`](../../../crates/sylpheed-ppc/src/opcode.rs#L285) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:978`](../../../crates/sylpheed-ppc/src/decoder.rs#L978) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::subfx => { - // PPCBUG-017+020: 32-bit truncation. - let ra32 = ctx.gpr[instr.ra()] as u32; - let rb32 = ctx.gpr[instr.rb()] as u32; - let result32 = rb32.wrapping_sub(ra32); - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - let true_diff = (rb32 as i32 as i128) - (ra32 as i32 as i128); - overflow::apply(ctx, true_diff != (result32 as i32) as i128); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_subfx(PPCHIRBuilder& f, const InstrData& i) { + // RT <- ¬(RA) + (RB) + 1 + Value* v = f.Sub(f.LoadGPR(i.XO.RB), f.LoadGPR(i.XO.RA)); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEINSTRNOTIMPLEMENTED(); + // e.update_xer_with_overflow(EFLAGS??); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
diff --git a/tools/ppc-manual/alu/subfzex.md b/tools/ppc-manual/alu/subfzex.md index 53ef64d6..facd3ed9 100644 --- a/tools/ppc-manual/alu/subfzex.md +++ b/tools/ppc-manual/alu/subfzex.md @@ -64,28 +64,26 @@ subfze[OE][Rc] [RD], [RA] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -93,32 +91,29 @@ subfze[OE][Rc] [RD], [RA] ## Implementation References **`subfzex`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfzex"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:504`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L504) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:83`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L83) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:869`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L869) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:307-324`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L307-L324) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="subfzex"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:504`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L504) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:286`](../../../crates/sylpheed-ppc/src/opcode.rs#L286) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:984`](../../../crates/sylpheed-ppc/src/decoder.rs#L984) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::subfzex => { - // PPCBUG-018: same active-poisoning shape as subfex; operate in u32. - let ra32 = ctx.gpr[instr.ra()] as u32; - let ca = ctx.xer_ca as u32; - let result32 = (!ra32).wrapping_add(ca); - // RT <- !RA + CA (no -1 term). 32-bit carry-out only when - // !ra32 = u32::MAX (i.e. ra32 = 0) AND ca = 1. - ctx.xer_ca = if ra32 == 0 && ca != 0 { 1 } else { 0 }; - ctx.gpr[instr.rd()] = result32 as u64; - if instr.oe() { - let true_sum = -(ra32 as i32 as i128) - 1 + (ca as i128); - overflow::apply(ctx, true_sum != (result32 as i32) as i128); - } - if instr.rc_bit() { - ctx.update_cr_signed(0, result32 as i32 as i64); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_subfzex(PPCHIRBuilder& f, const InstrData& i) { + // RT <- ¬(RA) + CA + Value* not_ra = f.Not(f.LoadGPR(i.XO.RA)); + Value* v = f.AddWithCarry(not_ra, f.LoadZeroInt64(), f.LoadCA()); + f.StoreGPR(i.XO.RT, v); + if (i.XO.OE) { + XEINSTRNOTIMPLEMENTED(); + // e.update_xer_with_overflow_and_carry(b.CreateExtractValue(v, 1)); + } else { + f.StoreCA(AddWithCarryDidCarry(f, not_ra, f.LoadZeroInt64(), f.LoadCA())); + } + if (i.XO.Rc) { + f.UpdateCR(0, v); + } + return 0; +} ```
@@ -128,9 +123,9 @@ subfze[OE][Rc] [RD], [RA] - **`RT ← ~RA + 0 + XER[CA]` ≡ `~RA + CA`.** The subtract-side high-word terminator for a multi-word subtract chain. Implements `0 - (...) - borrow` for the high word. - **`RB` field unused.** -- **Carry-out predicate.** `CA' = (~RA != 0) || (CA != 0)` ([`interpreter.rs:180`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L180)). Only `RA == ~0 && CA == 0` produces `CA' = 0`; every other case gives no-borrow. +- **Carry-out predicate.** `CA' = (~RA != 0) || (CA != 0)` ([`interpreter.rs:180`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). Only `RA == ~0 && CA == 0` produces `CA' = 0`; every other case gives no-borrow. - **`OE=1`** should set `XER[OV]` on signed overflow; xenia-rs ignores. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:183`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L183). +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:183`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). - **`XER[CA]` must be initialised** by an earlier carrying instruction. - **Common idiom: extracting `XER[CA]` as 0/-1.** `subfze rT, rN` (where `rN == 0`) materialises `XER[CA]` to `0` or `-1` (`-1 = ~0 + CA = -1 + CA`); pair with [`addzex`](addzex.md) for `0/1` instead. diff --git a/tools/ppc-manual/alu/sync.md b/tools/ppc-manual/alu/sync.md index 4c29bc9f..af78a5f0 100644 --- a/tools/ppc-manual/alu/sync.md +++ b/tools/ppc-manual/alu/sync.md @@ -61,13 +61,15 @@ multi-thread memory barrier (heavy). L=0 full sync; L=1 lightweight sync. ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -75,17 +77,17 @@ multi-thread memory barrier (heavy). L=0 full sync; L=1 lightweight sync. ## Implementation References **`sync`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sync"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:754`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L754) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:85`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L85) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:825`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L825) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1691-1693`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1691-L1693) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sync"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:754`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L754) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:288`](../../../crates/sylpheed-ppc/src/opcode.rs#L288) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:940`](../../../crates/sylpheed-ppc/src/decoder.rs#L940) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sync | PpcOpcode::eieio | PpcOpcode::isync => { - ctx.pc += 4; - } +```cpp +int InstrEmit_sync(PPCHIRBuilder& f, const InstrData& i) { + f.MemoryBarrier(); + return 0; +} ```
@@ -97,7 +99,7 @@ multi-thread memory barrier (heavy). L=0 full sync; L=1 lightweight sync. - **`L` field selects sync class.** `L=0` is full *hwsync* (the default). `L=1` is `lwsync` — orders only loads-after-loads, loads-after-stores, and stores-after-stores (not stores-after-loads). The Xenon implements both via the same encoding with `L` (bit 9) selecting variant. Most disassembly shows the unsuffixed `sync` mnemonic, which assembles to `L=0`. - **No register or CR effects.** Pure ordering primitive. - **Used to implement release semantics.** A typical lock-release sequence is `sync; stw r0, lock`. Acquire side uses `lwsync` after the load. -- **Xenia-rs is a no-op.** [`interpreter.rs:1267`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1267) collapses `sync`, `eieio`, `isync` into PC-advance. Since xenia is single-threaded interpretation, host program order subsumes all PPC ordering. +- **Xenia-rs is a no-op.** [`interpreter.rs:1267`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) collapses `sync`, `eieio`, `isync` into PC-advance. Since xenia is single-threaded interpretation, host program order subsumes all PPC ordering. - **Distinct from [`isync`](isync.md)**, which orders the *instruction* stream — `sync` does not refetch instructions. - **Slow on real hardware.** Hundreds of cycles when the store queue is full; hot paths avoid `sync` and use `lwsync` or no barrier when only single-thread ordering is needed. diff --git a/tools/ppc-manual/alu/xori.md b/tools/ppc-manual/alu/xori.md index 369dfdf2..ed0cc7fa 100644 --- a/tools/ppc-manual/alu/xori.md +++ b/tools/ppc-manual/alu/xori.md @@ -62,13 +62,15 @@ RA <- (RS) ^ (0x0000 || UIMM) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -76,18 +78,19 @@ RA <- (RS) ^ (0x0000 || UIMM) ## Implementation References **`xori`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="xori"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:839`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L839) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:132`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L132) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:349`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L349) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:520-523`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L520-L523) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="xori"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:839`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L839) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:497`](../../../crates/sylpheed-ppc/src/opcode.rs#L497) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:464`](../../../crates/sylpheed-ppc/src/decoder.rs#L464) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::xori => { - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] ^ (instr.uimm16() as u64); - ctx.pc += 4; - } +```cpp +int InstrEmit_xori(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) XOR (i48.0 || UI) + Value* ra = f.Xor(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS))); + f.StoreGPR(i.D.RA, ra); + return 0; +} ```
@@ -98,7 +101,7 @@ RA <- (RS) ^ (0x0000 || UIMM) - **No record form.** Like [`ori`](ori.md), there is no `xori.`. To get a CR0 update follow with `cmpwi` or use [`xorx`](xorx.md) with `Rc=1`. - **Immediate is zero-extended** to 64 bits. Only the low 16 bits of `RA` can be flipped; the high 48 bits are passed through from `RS` unchanged. - **`xori 0, 0, 0` is a valid NOP encoding** but the canonical NOP is `ori 0, 0, 0`. Disassemblers should still display this as `xori r0, r0, 0` or recognise it as a no-op. -- **64-bit operation in xenia-rs.** [`interpreter.rs:338`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L338) — full `u64` XOR with the immediate. +- **64-bit operation in xenia-rs.** [`interpreter.rs:338`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) — full `u64` XOR with the immediate. - **No `XER`, no `CR`** side effects. - **`RA = 0` reads `r0`** (not literal zero); see [`ori`](ori.md). - **Useful for masked toggle.** `xori rA, rS, mask` flips the bits of `rS` indicated by `mask` (low 16 bits only). diff --git a/tools/ppc-manual/alu/xoris.md b/tools/ppc-manual/alu/xoris.md index afd2a9e9..d2c66947 100644 --- a/tools/ppc-manual/alu/xoris.md +++ b/tools/ppc-manual/alu/xoris.md @@ -62,13 +62,15 @@ RA <- (RS) ^ (UIMM || 0x0000) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -76,18 +78,20 @@ RA <- (RS) ^ (UIMM || 0x0000) ## Implementation References **`xoris`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="xoris"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:846`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L846) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:132`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L132) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:350`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L350) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:524-527`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L524-L527) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="xoris"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:846`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L846) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:498`](../../../crates/sylpheed-ppc/src/opcode.rs#L498) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:465`](../../../crates/sylpheed-ppc/src/decoder.rs#L465) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::xoris => { - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] ^ ((instr.uimm16() as u64) << 16); - ctx.pc += 4; - } +```cpp +int InstrEmit_xoris(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) XOR (i32.0 || UI || i16.0) + Value* ra = + f.Xor(f.LoadGPR(i.D.RT), f.LoadConstantUint64(XEEXTZ16(i.D.DS) << 16)); + f.StoreGPR(i.D.RA, ra); + return 0; +} ```
@@ -98,7 +102,7 @@ RA <- (RS) ^ (UIMM || 0x0000) - **No record form.** Like all immediate logicals other than `andi.`/`andis.`, `xoris` does not update CR0. - **Immediate is zero-extended *then* shifted left 16.** Only bits 32–47 of `RA` (PowerISA bit numbering) can be flipped; the high 32 bits and low 16 bits of `RA` come from `RS` unchanged. - **Common pattern with [`xori`](xori.md)** to flip arbitrary 32-bit bitmasks: `xoris RA, RS, hi16; xori RA, RA, lo16`. -- **64-bit operation.** [`interpreter.rs:342`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L342). +- **64-bit operation.** [`interpreter.rs:342`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). - **No `XER`, no `CR`.** - **`RA = 0` reads `r0`** (not literal zero). - **Used to toggle the high half of a 32-bit word**, e.g. `xoris r3, r3, 0x8000` flips bit 32 (the sign bit of the low word) — a one-instruction sign-flip on a 32-bit value. diff --git a/tools/ppc-manual/alu/xorx.md b/tools/ppc-manual/alu/xorx.md index 4e809348..85792516 100644 --- a/tools/ppc-manual/alu/xorx.md +++ b/tools/ppc-manual/alu/xorx.md @@ -66,13 +66,15 @@ RA <- (RS) ^ (RB) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -80,20 +82,22 @@ RA <- (RS) ^ (RB) ## Implementation References **`xorx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="xorx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:829`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_alu.cc#L829) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:132`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L132) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:798`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L798) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:556-561`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L556-L561) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="xorx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_alu.cc:829`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_alu.cc#L829) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:499`](../../../crates/sylpheed-ppc/src/opcode.rs#L499) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:913`](../../../crates/sylpheed-ppc/src/decoder.rs#L913) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::xorx => { - // PPCBUG-032+020: 32-bit ABI CR0 view. - ctx.gpr[instr.ra()] = ctx.gpr[instr.rs()] ^ ctx.gpr[instr.rb()]; - if instr.rc_bit() { ctx.update_cr_signed(0, ctx.gpr[instr.ra()] as u32 as i32 as i64); } - ctx.pc += 4; - } +```cpp +int InstrEmit_xorx(PPCHIRBuilder& f, const InstrData& i) { + // RA <- (RS) XOR (RB) + Value* ra = f.Xor(f.LoadGPR(i.X.RT), f.LoadGPR(i.X.RB)); + f.StoreGPR(i.X.RA, ra); + if (i.X.Rc) { + f.UpdateCR(0, ra); + } + return 0; +} ```
@@ -106,7 +110,7 @@ RA <- (RS) ^ (RB) - **Operand convention** is X-form (`RA` destination, `RS`/`RB` sources). - **64-bit operation** on Xenon. - **No `OE` or `XER` side effects.** Only `Rc=1` updates `CR0`. -- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:367`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L367) truncates with `as i32 as i64`. For `xor.` whose result has differing high/low halves, spec and xenia diverge; `xor. RA, RS, RS` gives `EQ` either way. +- **64-bit CR update on Xenon, 32-bit in xenia-rs.** [`interpreter.rs:367`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs) truncates with `as i32 as i64`. For `xor.` whose result has differing high/low halves, spec and xenia diverge; `xor. RA, RS, RS` gives `EQ` either way. - **Useful as bitmask toggle.** `xor r3, r3, r4` flips in `r3` every bit set in `r4`. - **No `XER[CA]`.** diff --git a/tools/ppc-manual/branch/bcctrx.md b/tools/ppc-manual/branch/bcctrx.md index af2a2c3a..571b3abe 100644 --- a/tools/ppc-manual/branch/bcctrx.md +++ b/tools/ppc-manual/branch/bcctrx.md @@ -70,13 +70,15 @@ if LK then LR <- CIA + 4 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,34 +86,44 @@ if LK then LR <- CIA + 4 ## Implementation References **`bcctrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bcctrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:250`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L250) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:11`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L11) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:721`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L721) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:962-981`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L962-L981) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bcctrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:250`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L250) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:22`](../../../crates/sylpheed-ppc/src/opcode.rs#L22) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:836`](../../../crates/sylpheed-ppc/src/decoder.rs#L836) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::bcctrx => { - let bo = instr.bo(); - let bi = instr.bi(); +```cpp +int InstrEmit_bcctrx(PPCHIRBuilder& f, const InstrData& i) { + // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) + // if cond_ok then + // NIA <- CTR[0:61] || 0b00 + // if LK then + // LR <- CIA + 4 - let cond_ok = (bo & 0b10000) != 0 - || (ctx.get_cr_bit(bi) == ((bo & 0b01000) != 0)); + // NOTE: the condition bits are reversed! + // 01234 (docs) + // 43210 (real) - if cond_ok { - let next_pc = ctx.pc + 4; - ctx.pc = (ctx.ctr as u32) & !3; - if instr.lk() { - ctx.lr = next_pc as u64; - } - } else { - if instr.lk() { - ctx.lr = (ctx.pc + 4) as u64; - } - ctx.pc += 4; - } - } + Value* cond_ok = NULL; + bool not_cond_ok = false; + if (select_bits(i.XL.BO, 4, 4)) { + // Ignore cond. + } else { + Value* cr = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + cond_ok = cr; + if (select_bits(i.XL.BO, 3, 3)) { + // Expect true. + not_cond_ok = false; + } else { + // Expect false. + not_cond_ok = true; + } + } + + bool expect_true = !not_cond_ok; + return InstrEmit_branch(f, "bcctrx", i.address, f.LoadCTR(), i.XL.LK, cond_ok, + expect_true); +} ```
diff --git a/tools/ppc-manual/branch/bclrx.md b/tools/ppc-manual/branch/bclrx.md index 3279453c..562ef1fb 100644 --- a/tools/ppc-manual/branch/bclrx.md +++ b/tools/ppc-manual/branch/bclrx.md @@ -84,37 +84,80 @@ if (insn.LK) lr = next; ## Implementation References **`bclrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bclrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:282`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L282) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:11`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L11) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:711`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L711) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:939-961`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L939-L961) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bclrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:282`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L282) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:23`](../../../crates/sylpheed-ppc/src/opcode.rs#L23) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:826`](../../../crates/sylpheed-ppc/src/decoder.rs#L826) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::bclrx => { - let bo = instr.bo(); - let bi = instr.bi(); +```cpp +int InstrEmit_bclrx(PPCHIRBuilder& f, const InstrData& i) { + // if ¬BO[2] then + // CTR <- CTR - 1 + // ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3] + // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) + // if ctr_ok & cond_ok then + // NIA <- LR[0:61] || 0b00 + // if LK then + // LR <- CIA + 4 - if bo & 0b00100 == 0 { - ctx.ctr = ctx.ctr.wrapping_sub(1); - } + // NOTE: the condition bits are reversed! + // 01234 (docs) + // 43210 (real) - let ctr_ok = (bo & 0b00100) != 0 - || (((ctx.ctr as u32) != 0) ^ ((bo & 0b00010) != 0)); - let cond_ok = (bo & 0b10000) != 0 - || (ctx.get_cr_bit(bi) == ((bo & 0b01000) != 0)); + Value* ctr_ok = NULL; + if (select_bits(i.XL.BO, 2, 2)) { + // Ignore ctr. + } else { + // Decrement counter. + Value* ctr = f.LoadCTR(); + ctr = f.Sub(ctr, f.LoadConstantUint64(1)); + f.StoreCTR(ctr); + // Ctr check. + ctr = f.Truncate(ctr, INT32_TYPE); + // TODO(benvanik): could do something similar to cond and avoid the + // is_true/branch_true pairing. + if (select_bits(i.XL.BO, 1, 1)) { + ctr_ok = f.IsFalse(ctr); + } else { + ctr_ok = f.IsTrue(ctr); + } + } - let next_pc = ctx.pc + 4; - if ctr_ok && cond_ok { - ctx.pc = (ctx.lr as u32) & !3; - } else { - ctx.pc = next_pc; - } - if instr.lk() { - ctx.lr = next_pc as u64; - } - } + Value* cond_ok = NULL; + bool not_cond_ok = false; + if (select_bits(i.XL.BO, 4, 4)) { + // Ignore cond. + } else { + Value* cr = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + cond_ok = cr; + if (select_bits(i.XL.BO, 3, 3)) { + // Expect true. + not_cond_ok = false; + } else { + // Expect false. + not_cond_ok = true; + } + } + + // We do a bit of optimization here to make the llvm assembly easier to read. + Value* ok = NULL; + bool expect_true = true; + if (ctr_ok && cond_ok) { + if (not_cond_ok) { + cond_ok = f.IsFalse(cond_ok); + } + ok = f.And(ctr_ok, cond_ok); + } else if (ctr_ok) { + ok = ctr_ok; + } else if (cond_ok) { + ok = cond_ok; + expect_true = !not_cond_ok; + } + + return InstrEmit_branch(f, "bclrx", i.address, f.LoadLR(), i.XL.LK, ok, + expect_true, true); +} ```
diff --git a/tools/ppc-manual/branch/bcx.md b/tools/ppc-manual/branch/bcx.md index 0fc880e8..cb0f3880 100644 --- a/tools/ppc-manual/branch/bcx.md +++ b/tools/ppc-manual/branch/bcx.md @@ -75,13 +75,15 @@ if LK then LR <- CIA + 4 ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,45 +91,89 @@ if LK then LR <- CIA + 4 ## Implementation References **`bcx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bcx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:173`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L173) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:11`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L11) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:340`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L340) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:908-938`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L908-L938) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bcx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:173`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L173) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:24`](../../../crates/sylpheed-ppc/src/opcode.rs#L24) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:455`](../../../crates/sylpheed-ppc/src/decoder.rs#L455) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::bcx => { - let bo = instr.bo(); - let bi = instr.bi(); +```cpp +int InstrEmit_bcx(PPCHIRBuilder& f, const InstrData& i) { + // if ¬BO[2] then + // CTR <- CTR - 1 + // ctr_ok <- BO[2] | ((CTR[0:63] != 0) XOR BO[3]) + // cond_ok <- BO[0] | (CR[BI+32] ≡ BO[1]) + // if ctr_ok & cond_ok then + // if AA then + // NIA <- EXTS(BD || 0b00) + // else + // NIA <- CIA + EXTS(BD || 0b00) + // if LK then + // LR <- CIA + 4 - // Decrement CTR if needed - if bo & 0b00100 == 0 { - ctx.ctr = ctx.ctr.wrapping_sub(1); - } + // NOTE: the condition bits are reversed! + // 01234 (docs) + // 43210 (real) - let ctr_ok = (bo & 0b00100) != 0 - || (((ctx.ctr as u32) != 0) ^ ((bo & 0b00010) != 0)); - let cond_ok = (bo & 0b10000) != 0 - || (ctx.get_cr_bit(bi) == ((bo & 0b01000) != 0)); + Value* ctr_ok = NULL; + if (select_bits(i.B.BO, 2, 2)) { + // Ignore ctr. + } else { + // Decrement counter. + Value* ctr = f.LoadCTR(); + ctr = f.Sub(ctr, f.LoadConstantUint64(1)); + f.StoreCTR(ctr); + // Ctr check. + ctr = f.Truncate(ctr, INT32_TYPE); + // TODO(benvanik): could do something similar to cond and avoid the + // is_true/branch_true pairing. + if (select_bits(i.B.BO, 1, 1)) { + ctr_ok = f.IsFalse(ctr); + } else { + ctr_ok = f.IsTrue(ctr); + } + } - if ctr_ok && cond_ok { - let target = if instr.aa() { - instr.bd() as u32 - } else { - ctx.pc.wrapping_add(instr.bd() as u32) - }; - if instr.lk() { - ctx.lr = (ctx.pc + 4) as u64; - } - ctx.pc = target; - } else { - if instr.lk() { - ctx.lr = (ctx.pc + 4) as u64; - } - ctx.pc += 4; - } - } + Value* cond_ok = NULL; + bool not_cond_ok = false; + if (select_bits(i.B.BO, 4, 4)) { + // Ignore cond. + } else { + Value* cr = f.LoadCRField(i.B.BI >> 2, i.B.BI & 3); + cond_ok = cr; + if (select_bits(i.B.BO, 3, 3)) { + // Expect true. + not_cond_ok = false; + } else { + // Expect false. + not_cond_ok = true; + } + } + + // We do a bit of optimization here to make the llvm assembly easier to read. + Value* ok = NULL; + bool expect_true = true; + if (ctr_ok && cond_ok) { + if (not_cond_ok) { + cond_ok = f.IsFalse(cond_ok); + } + ok = f.And(ctr_ok, cond_ok); + } else if (ctr_ok) { + ok = ctr_ok; + } else if (cond_ok) { + ok = cond_ok; + expect_true = !not_cond_ok; + } + + uint32_t nia; + if (i.B.AA) { + nia = (uint32_t)XEEXTS16(i.B.BD << 2); + } else { + nia = (uint32_t)(i.address + XEEXTS16(i.B.BD << 2)); + } + return InstrEmit_branch(f, "bcx", i.address, f.LoadConstantUint32(nia), + i.B.LK, ok, expect_true); +} ```
diff --git a/tools/ppc-manual/branch/bx.md b/tools/ppc-manual/branch/bx.md index fd781a59..584b9c59 100644 --- a/tools/ppc-manual/branch/bx.md +++ b/tools/ppc-manual/branch/bx.md @@ -77,25 +77,31 @@ pc = target; ## Implementation References **`bx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:154`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L154) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:11`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L11) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:342`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L342) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:897-907`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L897-L907) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="bx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:154`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L154) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:25`](../../../crates/sylpheed-ppc/src/opcode.rs#L25) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:457`](../../../crates/sylpheed-ppc/src/decoder.rs#L457) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::bx => { - let target = if instr.aa() { - instr.li() as u32 - } else { - ctx.pc.wrapping_add(instr.li() as u32) - }; - if instr.lk() { - ctx.lr = (ctx.pc + 4) as u64; - } - ctx.pc = target; - } +```cpp +int InstrEmit_bx(PPCHIRBuilder& f, const InstrData& i) { + // if AA then + // NIA <- EXTS(LI || 0b00) + // else + // NIA <- CIA + EXTS(LI || 0b00) + // if LK then + // LR <- CIA + 4 + + uint32_t nia; + if (i.I.AA) { + nia = (uint32_t)XEEXTS26(i.I.LI << 2); + } else { + nia = (uint32_t)(i.address + XEEXTS26(i.I.LI << 2)); + } + + return InstrEmit_branch(f, "bx", i.address, f.LoadConstantUint32(nia), + i.I.LK); +} ```
diff --git a/tools/ppc-manual/branch/sc.md b/tools/ppc-manual/branch/sc.md index 1ec660a3..4aa42533 100644 --- a/tools/ppc-manual/branch/sc.md +++ b/tools/ppc-manual/branch/sc.md @@ -62,13 +62,15 @@ system_call_exception(LEV) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -76,28 +78,28 @@ system_call_exception(LEV) ## Implementation References **`sc`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sc"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:455`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L455) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:63`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L63) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:341`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L341) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:984-997`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L984-L997) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sc"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:457`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L457) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:214`](../../../crates/sylpheed-ppc/src/opcode.rs#L214) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:456`](../../../crates/sylpheed-ppc/src/decoder.rs#L456) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sc => { - // PPCBUG-064: log non-zero LEV (`sc 2` is the Xbox 360 hypervisor-call - // convention; canary dispatches it to a different handler than `sc 0`). - // Routing LEV=2 requires a StepResult variant extension; deferred. - let lev = (instr.raw >> 5) & 0x7F; - if lev != 0 { - tracing::warn!( - "sc with LEV={} at {:#010x}: dispatched as plain SystemCall (HVcall routing not implemented)", - lev, ctx.pc - ); - } - ctx.pc += 4; - return StepResult::SystemCall; - } +```cpp +int InstrEmit_sc(PPCHIRBuilder& f, const InstrData& i) { + // Game code should only ever use LEV=0. + // LEV=2 is to signify 'call import' from Xenia. + // TODO(gibbed): syscalls! + if (i.SC.LEV == 0) { + f.CallExtern(f.builtins()->syscall_handler); + return 0; + } + if (i.SC.LEV == 2) { + f.CallExtern(f.function()); + return 0; + } + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/branch/td.md b/tools/ppc-manual/branch/td.md index 8a23ccd2..8ae2232d 100644 --- a/tools/ppc-manual/branch/td.md +++ b/tools/ppc-manual/branch/td.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,49 +85,28 @@ _No condition-register or status-register effects._ ## Implementation References **`td`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="td"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:552`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L552) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:87`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L87) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:769`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L769) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1762-1796`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1762-L1796) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="td"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:554`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L554) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:290`](../../../crates/sylpheed-ppc/src/opcode.rs#L290) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:884`](../../../crates/sylpheed-ppc/src/decoder.rs#L884) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::tw | PpcOpcode::twi | PpcOpcode::td | PpcOpcode::tdi => { - // PPCBUG-063: save CIA before incrementing so a trap handler reads - // the faulting instruction address, not CIA+4. - // PPCBUG-065: log the SIMM type code on `twi 31, r0, IMM` (Xbox 360 - // typed-trap convention used by the CRT/kernel for C++ exception - // class dispatch). The audit notes this is relevant to the Sylpheed - // throw investigation; routing the type code via a payload requires - // a StepResult enum extension that's deferred for now. - let trap_pc = ctx.pc; - let a = ctx.gpr[instr.ra()]; - let b = match instr.opcode { - PpcOpcode::twi | PpcOpcode::tdi => instr.simm16() as i64 as u64, - _ => ctx.gpr[instr.rb()], - }; - let width = match instr.opcode { - PpcOpcode::tw | PpcOpcode::twi => trap::TrapWidth::Word, - _ => trap::TrapWidth::Doubleword, - }; - let fired = trap::evaluate(instr.to(), a, b, width); - if fired { - let typed_trap_simm = if matches!(instr.opcode, PpcOpcode::twi) - && instr.to() == 31 && instr.ra() == 0 { - Some(instr.simm16() as u16) - } else { None }; - tracing::warn!( - "Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}{}", - trap_pc, instr.opcode, instr.to(), a, b, - typed_trap_simm.map_or(String::new(), |t| format!(" typed_trap_simm={:#06x}", t)) - ); - // Leave ctx.pc at CIA (NOT NIA) so trap handlers / SEH delivery - // can read the faulting instruction address from ctx.pc. - return StepResult::Trap; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_td(PPCHIRBuilder& f, const InstrData& i) { + if (cvars::ignore_trap_instructions) { + return 0; + } + // a <- (RA) + // b <- (RB) + // if (a < b) & TO[0] then TRAP + // if (a > b) & TO[1] then TRAP + // if (a = b) & TO[2] then TRAP + // if (a u b) & TO[4] then TRAP + Value* ra = f.LoadGPR(i.X.RA); + Value* rb = f.LoadGPR(i.X.RB); + return InstrEmit_trap(f, i, ra, rb, i.X.RT); +} ```
diff --git a/tools/ppc-manual/branch/tdi.md b/tools/ppc-manual/branch/tdi.md index 77f10da3..c5ad1b9e 100644 --- a/tools/ppc-manual/branch/tdi.md +++ b/tools/ppc-manual/branch/tdi.md @@ -56,28 +56,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,49 +83,27 @@ _No condition-register or status-register effects._ ## Implementation References **`tdi`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="tdi"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:568`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L568) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:87`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L87) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:327`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L327) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1762-1796`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1762-L1796) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="tdi"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:570`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L570) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:291`](../../../crates/sylpheed-ppc/src/opcode.rs#L291) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:442`](../../../crates/sylpheed-ppc/src/decoder.rs#L442) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::tw | PpcOpcode::twi | PpcOpcode::td | PpcOpcode::tdi => { - // PPCBUG-063: save CIA before incrementing so a trap handler reads - // the faulting instruction address, not CIA+4. - // PPCBUG-065: log the SIMM type code on `twi 31, r0, IMM` (Xbox 360 - // typed-trap convention used by the CRT/kernel for C++ exception - // class dispatch). The audit notes this is relevant to the Sylpheed - // throw investigation; routing the type code via a payload requires - // a StepResult enum extension that's deferred for now. - let trap_pc = ctx.pc; - let a = ctx.gpr[instr.ra()]; - let b = match instr.opcode { - PpcOpcode::twi | PpcOpcode::tdi => instr.simm16() as i64 as u64, - _ => ctx.gpr[instr.rb()], - }; - let width = match instr.opcode { - PpcOpcode::tw | PpcOpcode::twi => trap::TrapWidth::Word, - _ => trap::TrapWidth::Doubleword, - }; - let fired = trap::evaluate(instr.to(), a, b, width); - if fired { - let typed_trap_simm = if matches!(instr.opcode, PpcOpcode::twi) - && instr.to() == 31 && instr.ra() == 0 { - Some(instr.simm16() as u16) - } else { None }; - tracing::warn!( - "Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}{}", - trap_pc, instr.opcode, instr.to(), a, b, - typed_trap_simm.map_or(String::new(), |t| format!(" typed_trap_simm={:#06x}", t)) - ); - // Leave ctx.pc at CIA (NOT NIA) so trap handlers / SEH delivery - // can read the faulting instruction address from ctx.pc. - return StepResult::Trap; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_tdi(PPCHIRBuilder& f, const InstrData& i) { + if (cvars::ignore_trap_instructions) { + return 0; + } + // a <- (RA) + // if (a < EXTS(SI)) & TO[0] then TRAP + // if (a > EXTS(SI)) & TO[1] then TRAP + // if (a = EXTS(SI)) & TO[2] then TRAP + // if (a u EXTS(SI)) & TO[4] then TRAP + Value* ra = f.LoadGPR(i.D.RA); + Value* rb = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + return InstrEmit_trap(f, i, ra, rb, i.D.RT); +} ```
diff --git a/tools/ppc-manual/branch/tw.md b/tools/ppc-manual/branch/tw.md index 60b62813..13061d87 100644 --- a/tools/ppc-manual/branch/tw.md +++ b/tools/ppc-manual/branch/tw.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,49 +85,30 @@ _No condition-register or status-register effects._ ## Implementation References **`tw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="tw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:583`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L583) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:87`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L87) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:750`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L750) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1762-1796`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1762-L1796) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="tw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:585`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L585) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:292`](../../../crates/sylpheed-ppc/src/opcode.rs#L292) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:865`](../../../crates/sylpheed-ppc/src/decoder.rs#L865) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::tw | PpcOpcode::twi | PpcOpcode::td | PpcOpcode::tdi => { - // PPCBUG-063: save CIA before incrementing so a trap handler reads - // the faulting instruction address, not CIA+4. - // PPCBUG-065: log the SIMM type code on `twi 31, r0, IMM` (Xbox 360 - // typed-trap convention used by the CRT/kernel for C++ exception - // class dispatch). The audit notes this is relevant to the Sylpheed - // throw investigation; routing the type code via a payload requires - // a StepResult enum extension that's deferred for now. - let trap_pc = ctx.pc; - let a = ctx.gpr[instr.ra()]; - let b = match instr.opcode { - PpcOpcode::twi | PpcOpcode::tdi => instr.simm16() as i64 as u64, - _ => ctx.gpr[instr.rb()], - }; - let width = match instr.opcode { - PpcOpcode::tw | PpcOpcode::twi => trap::TrapWidth::Word, - _ => trap::TrapWidth::Doubleword, - }; - let fired = trap::evaluate(instr.to(), a, b, width); - if fired { - let typed_trap_simm = if matches!(instr.opcode, PpcOpcode::twi) - && instr.to() == 31 && instr.ra() == 0 { - Some(instr.simm16() as u16) - } else { None }; - tracing::warn!( - "Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}{}", - trap_pc, instr.opcode, instr.to(), a, b, - typed_trap_simm.map_or(String::new(), |t| format!(" typed_trap_simm={:#06x}", t)) - ); - // Leave ctx.pc at CIA (NOT NIA) so trap handlers / SEH delivery - // can read the faulting instruction address from ctx.pc. - return StepResult::Trap; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_tw(PPCHIRBuilder& f, const InstrData& i) { + if (cvars::ignore_trap_instructions) { + return 0; + } + // a <- EXTS((RA)[32:63]) + // b <- EXTS((RB)[32:63]) + // if (a < b) & TO[0] then TRAP + // if (a > b) & TO[1] then TRAP + // if (a = b) & TO[2] then TRAP + // if (a u b) & TO[4] then TRAP + Value* ra = + f.SignExtend(f.Truncate(f.LoadGPR(i.X.RA), INT32_TYPE), INT64_TYPE); + Value* rb = + f.SignExtend(f.Truncate(f.LoadGPR(i.X.RB), INT32_TYPE), INT64_TYPE); + return InstrEmit_trap(f, i, ra, rb, i.X.RT); +} ```
diff --git a/tools/ppc-manual/branch/twi.md b/tools/ppc-manual/branch/twi.md index 7a793fba..f51d3e12 100644 --- a/tools/ppc-manual/branch/twi.md +++ b/tools/ppc-manual/branch/twi.md @@ -56,28 +56,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,49 +83,34 @@ _No condition-register or status-register effects._ ## Implementation References **`twi`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="twi"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:601`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L601) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:87`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L87) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:328`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L328) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1762-1796`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1762-L1796) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="twi"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:603`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L603) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:293`](../../../crates/sylpheed-ppc/src/opcode.rs#L293) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:443`](../../../crates/sylpheed-ppc/src/decoder.rs#L443) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::tw | PpcOpcode::twi | PpcOpcode::td | PpcOpcode::tdi => { - // PPCBUG-063: save CIA before incrementing so a trap handler reads - // the faulting instruction address, not CIA+4. - // PPCBUG-065: log the SIMM type code on `twi 31, r0, IMM` (Xbox 360 - // typed-trap convention used by the CRT/kernel for C++ exception - // class dispatch). The audit notes this is relevant to the Sylpheed - // throw investigation; routing the type code via a payload requires - // a StepResult enum extension that's deferred for now. - let trap_pc = ctx.pc; - let a = ctx.gpr[instr.ra()]; - let b = match instr.opcode { - PpcOpcode::twi | PpcOpcode::tdi => instr.simm16() as i64 as u64, - _ => ctx.gpr[instr.rb()], - }; - let width = match instr.opcode { - PpcOpcode::tw | PpcOpcode::twi => trap::TrapWidth::Word, - _ => trap::TrapWidth::Doubleword, - }; - let fired = trap::evaluate(instr.to(), a, b, width); - if fired { - let typed_trap_simm = if matches!(instr.opcode, PpcOpcode::twi) - && instr.to() == 31 && instr.ra() == 0 { - Some(instr.simm16() as u16) - } else { None }; - tracing::warn!( - "Trap fired at {:#010x}: {:?} TO={} a={:#x} b={:#x}{}", - trap_pc, instr.opcode, instr.to(), a, b, - typed_trap_simm.map_or(String::new(), |t| format!(" typed_trap_simm={:#06x}", t)) - ); - // Leave ctx.pc at CIA (NOT NIA) so trap handlers / SEH delivery - // can read the faulting instruction address from ctx.pc. - return StepResult::Trap; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_twi(PPCHIRBuilder& f, const InstrData& i) { + if (cvars::ignore_trap_instructions) { + return 0; + } + // a <- EXTS((RA)[32:63]) + // if (a < EXTS(SI)) & TO[0] then TRAP + // if (a > EXTS(SI)) & TO[1] then TRAP + // if (a = EXTS(SI)) & TO[2] then TRAP + // if (a u EXTS(SI)) & TO[4] then TRAP + if (i.D.RA == 0 && i.D.RT == 0x1F) { + // This is a special trap. Probably. + uint16_t type = (uint16_t)XEEXTS16(i.D.DS); + f.Trap(type); + return 0; + } + Value* ra = + f.SignExtend(f.Truncate(f.LoadGPR(i.D.RA), INT32_TYPE), INT64_TYPE); + Value* rb = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + return InstrEmit_trap(f, i, ra, rb, i.D.RT); +} ```
diff --git a/tools/ppc-manual/control/crand.md b/tools/ppc-manual/control/crand.md index 0ae37693..9b8e3cbf 100644 --- a/tools/ppc-manual/control/crand.md +++ b/tools/ppc-manual/control/crand.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,10 +85,23 @@ _No condition-register or status-register effects._ ## Implementation References **`crand`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crand"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:352`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L352) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:717`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L717) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crand"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:352`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L352) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:35`](../../../crates/sylpheed-ppc/src/opcode.rs#L35) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:832`](../../../crates/sylpheed-ppc/src/decoder.rs#L832) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_crand(PPCHIRBuilder& f, const InstrData& i) { + // CR[bt] <- CR[ba] & CR[bb] bt=bo, ba=bi, bb=bb + Value* ba = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + Value* bb = f.LoadCRField(i.XL.BB >> 2, i.XL.BB & 3); + Value* bt = f.And(ba, bb); + f.StoreCRField(i.XL.BO >> 2, i.XL.BO & 3, bt); + return 0; +} +``` +
@@ -102,7 +113,7 @@ _No condition-register or status-register effects._ - **Combining branch conditions.** The classic use: synthesise complex branch conditions from multiple compare results. Example: `cmpw cr0, r3, r4; cmpw cr1, r5, r6; crand 4*cr0+2, 4*cr0+2, 4*cr1+2; beq cr0, label` branches if `r3==r4 AND r5==r6` using a single conditional branch. - **No `Rc` / `OE`.** XL-form CR-logical ops never set CR0 or XER; they only update the named CR bit. - **Not synchronising.** Pure data-flow on CR; freely reorderable. -- **xenia status.** xenia-rs decodes `crand` (decoder slot 540) but the interpreter snapshot is not embedded on this page — implementation lives in [`crates/xenia-cpu/src/interpreter.rs`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs). xenia-canary's `InstrEmit_crand` emits the equivalent host AND of the two CR bits. +- **xenia status.** xenia-rs decodes `crand` (decoder slot 540) but the interpreter snapshot is not embedded on this page — implementation lives in [`crates/xenia-cpu/src/interpreter.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs). xenia-canary's `InstrEmit_crand` emits the equivalent host AND of the two CR bits. ## Related Instructions diff --git a/tools/ppc-manual/control/crandc.md b/tools/ppc-manual/control/crandc.md index cc395b53..d69f6d1d 100644 --- a/tools/ppc-manual/control/crandc.md +++ b/tools/ppc-manual/control/crandc.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,10 +85,23 @@ _No condition-register or status-register effects._ ## Implementation References **`crandc`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crandc"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:361`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L361) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:713`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L713) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crandc"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:361`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L361) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:36`](../../../crates/sylpheed-ppc/src/opcode.rs#L36) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:828`](../../../crates/sylpheed-ppc/src/decoder.rs#L828) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_crandc(PPCHIRBuilder& f, const InstrData& i) { + // CR[bt] <- CR[ba] & ¬CR[bb] bt=bo, ba=bi, bb=bb + Value* ba = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + Value* bb = f.LoadCRField(i.XL.BB >> 2, i.XL.BB & 3); + Value* bt = f.And(ba, f.And(f.Not(bb), f.LoadConstantInt8(0x01))); + f.StoreCRField(i.XL.BO >> 2, i.XL.BO & 3, bt); + return 0; +} +``` +
diff --git a/tools/ppc-manual/control/creqv.md b/tools/ppc-manual/control/creqv.md index 03f6a050..70b9dc97 100644 --- a/tools/ppc-manual/control/creqv.md +++ b/tools/ppc-manual/control/creqv.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,10 +85,23 @@ _No condition-register or status-register effects._ ## Implementation References **`creqv`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="creqv"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:370`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L370) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:718`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L718) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="creqv"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:370`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L370) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:37`](../../../crates/sylpheed-ppc/src/opcode.rs#L37) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:833`](../../../crates/sylpheed-ppc/src/decoder.rs#L833) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_creqv(PPCHIRBuilder& f, const InstrData& i) { + // CR[bt] <- CR[ba] == CR[bb] bt=bo, ba=bi, bb=bb + Value* ba = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + Value* bb = f.LoadCRField(i.XL.BB >> 2, i.XL.BB & 3); + Value* bt = f.CompareEQ(ba, bb); + f.StoreCRField(i.XL.BO >> 2, i.XL.BO & 3, bt); + return 0; +} +``` +
diff --git a/tools/ppc-manual/control/crnand.md b/tools/ppc-manual/control/crnand.md index 7b0ea7cf..74777ce3 100644 --- a/tools/ppc-manual/control/crnand.md +++ b/tools/ppc-manual/control/crnand.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,10 +85,23 @@ _No condition-register or status-register effects._ ## Implementation References **`crnand`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crnand"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:379`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L379) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:716`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L716) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crnand"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:379`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L379) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:38`](../../../crates/sylpheed-ppc/src/opcode.rs#L38) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:831`](../../../crates/sylpheed-ppc/src/decoder.rs#L831) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_crnand(PPCHIRBuilder& f, const InstrData& i) { + // CR[bt] <- ¬(CR[ba] & CR[bb]) bt=bo, ba=bi, bb=bb + Value* ba = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + Value* bb = f.LoadCRField(i.XL.BB >> 2, i.XL.BB & 3); + Value* bt = f.And(f.Not(f.And(ba, bb)), f.LoadConstantInt8(0x01)); + f.StoreCRField(i.XL.BO >> 2, i.XL.BO & 3, bt); + return 0; +} +``` +
diff --git a/tools/ppc-manual/control/crnor.md b/tools/ppc-manual/control/crnor.md index d495ac4b..9d934ad0 100644 --- a/tools/ppc-manual/control/crnor.md +++ b/tools/ppc-manual/control/crnor.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,10 +85,23 @@ _No condition-register or status-register effects._ ## Implementation References **`crnor`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crnor"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:388`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L388) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:712`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L712) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crnor"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:388`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L388) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:39`](../../../crates/sylpheed-ppc/src/opcode.rs#L39) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:827`](../../../crates/sylpheed-ppc/src/decoder.rs#L827) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_crnor(PPCHIRBuilder& f, const InstrData& i) { + // CR[bt] <- ¬(CR[ba] | CR[bb]) bt=bo, ba=bi, bb=bb + Value* ba = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + Value* bb = f.LoadCRField(i.XL.BB >> 2, i.XL.BB & 3); + Value* bt = f.And(f.Not(f.Or(ba, bb)), f.LoadConstantInt8(0x01)); + f.StoreCRField(i.XL.BO >> 2, i.XL.BO & 3, bt); + return 0; +} +``` +
diff --git a/tools/ppc-manual/control/cror.md b/tools/ppc-manual/control/cror.md index 5ed28c55..cb315af8 100644 --- a/tools/ppc-manual/control/cror.md +++ b/tools/ppc-manual/control/cror.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,10 +85,23 @@ _No condition-register or status-register effects._ ## Implementation References **`cror`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cror"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:397`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L397) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:720`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L720) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="cror"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:397`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L397) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:40`](../../../crates/sylpheed-ppc/src/opcode.rs#L40) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:835`](../../../crates/sylpheed-ppc/src/decoder.rs#L835) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_cror(PPCHIRBuilder& f, const InstrData& i) { + // CR[bt] <- CR[ba] | CR[bb] bt=bo, ba=bi, bb=bb + Value* ba = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + Value* bb = f.LoadCRField(i.XL.BB >> 2, i.XL.BB & 3); + Value* bt = f.Or(ba, bb); + f.StoreCRField(i.XL.BO >> 2, i.XL.BO & 3, bt); + return 0; +} +``` +
diff --git a/tools/ppc-manual/control/crorc.md b/tools/ppc-manual/control/crorc.md index abb3c17e..665b4209 100644 --- a/tools/ppc-manual/control/crorc.md +++ b/tools/ppc-manual/control/crorc.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,10 +85,23 @@ _No condition-register or status-register effects._ ## Implementation References **`crorc`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crorc"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:406`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L406) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:719`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L719) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crorc"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:406`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L406) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:41`](../../../crates/sylpheed-ppc/src/opcode.rs#L41) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:834`](../../../crates/sylpheed-ppc/src/decoder.rs#L834) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_crorc(PPCHIRBuilder& f, const InstrData& i) { + // CR[bt] <- CR[ba] | ¬CR[bb] bt=bo, ba=bi, bb=bb + Value* ba = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + Value* bb = f.LoadCRField(i.XL.BB >> 2, i.XL.BB & 3); + Value* bt = f.Or(ba, f.And(f.Not(bb), f.LoadConstantInt8(0x01))); + f.StoreCRField(i.XL.BO >> 2, i.XL.BO & 3, bt); + return 0; +} +``` +
diff --git a/tools/ppc-manual/control/crxor.md b/tools/ppc-manual/control/crxor.md index 35f79e5a..34859084 100644 --- a/tools/ppc-manual/control/crxor.md +++ b/tools/ppc-manual/control/crxor.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,10 +85,23 @@ _No condition-register or status-register effects._ ## Implementation References **`crxor`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crxor"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:415`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L415) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:17`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L17) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:715`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L715) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="crxor"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:415`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L415) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:42`](../../../crates/sylpheed-ppc/src/opcode.rs#L42) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:830`](../../../crates/sylpheed-ppc/src/decoder.rs#L830) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_crxor(PPCHIRBuilder& f, const InstrData& i) { + // CR[bt] <- CR[ba] xor CR[bb] bt=bo, ba=bi, bb=bb + Value* ba = f.LoadCRField(i.XL.BI >> 2, i.XL.BI & 3); + Value* bb = f.LoadCRField(i.XL.BB >> 2, i.XL.BB & 3); + Value* bt = f.Xor(ba, bb); + f.StoreCRField(i.XL.BO >> 2, i.XL.BO & 3, bt); + return 0; +} +``` +
diff --git a/tools/ppc-manual/control/mcrf.md b/tools/ppc-manual/control/mcrf.md index b40b1142..2ebeab44 100644 --- a/tools/ppc-manual/control/mcrf.md +++ b/tools/ppc-manual/control/mcrf.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,18 +84,23 @@ _No condition-register or status-register effects._ ## Implementation References **`mcrf`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mcrf"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:424`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L424) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:51`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L51) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:710`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L710) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1683-1686`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1683-L1686) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mcrf"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:424`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L424) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:167`](../../../crates/sylpheed-ppc/src/opcode.rs#L167) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:825`](../../../crates/sylpheed-ppc/src/decoder.rs#L825) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mcrf => { - ctx.cr[instr.crfd()] = ctx.cr[instr.crfs()]; - ctx.pc += 4; - } +```cpp +int InstrEmit_mcrf(PPCHIRBuilder& f, const InstrData& i) { + // CR[4*bf:4*bf+3] <- CR[4*bfa:4*bfa+3] bf=bo, bfa=bi + // LoadCR/StoreCR bake the field position into the word and cannot cross it. + uint32_t crfd = i.XL.BO >> 2; + uint32_t crfs = i.XL.BI >> 2; + for (uint32_t bit = 0; bit < 4; ++bit) { + f.StoreCRField(crfd, bit, f.LoadCRField(crfs, bit)); + } + return 0; +} ```
diff --git a/tools/ppc-manual/control/mcrfs.md b/tools/ppc-manual/control/mcrfs.md index 36ee4307..61634b07 100644 --- a/tools/ppc-manual/control/mcrfs.md +++ b/tools/ppc-manual/control/mcrfs.md @@ -58,28 +58,26 @@ mcrfs [CRFD], [CRFS] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,44 +85,38 @@ mcrfs [CRFD], [CRFS] ## Implementation References **`mcrfs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mcrfs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:371`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L371) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:51`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L51) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:904`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L904) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4716-4745`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4716-L4745) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mcrfs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:371`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L371) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:168`](../../../crates/sylpheed-ppc/src/opcode.rs#L168) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1019`](../../../crates/sylpheed-ppc/src/decoder.rs#L1019) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mcrfs => { - let crfd = instr.crfd(); - let crfs = instr.crfs(); - let shift = 28 - (crfs as u32 * 4); - let nibble = ((ctx.fpscr >> shift) & 0xF) as u8; - ctx.cr[crfd] = crate::context::CrField::from_u8(nibble); - // Clearable exception bits: 0 (FX), 3 (OX), 4 (UX), 5 (ZX), - // 6 (XX), 7 (VXSNAN), 8 (VXISI), 9 (VXIDI), 10 (VXZDZ), - // 11 (VXIMZ), 12 (VXVC), 21 (VXSOFT), 22 (VXSQRT), 23 (VXCVI). - // (Bit positions are PowerISA MSB-0; here 'FPSCR bit n' means - // the bit at (31-n) in our little-endian u32.) - const CLEARABLE_MASK: u32 = - (1 << 31) | (1 << (31 - 3)) | (1 << (31 - 4)) | - (1 << (31 - 5)) | (1 << (31 - 6)) | (1 << (31 - 7)) | - (1 << (31 - 8)) | (1 << (31 - 9)) | (1 << (31 - 10)) | - (1 << (31 - 11)) | (1 << (31 - 12)) | - (1 << (31 - 21)) | (1 << (31 - 22)) | (1 << (31 - 23)); - let nibble_mask = 0xFu32 << shift; - ctx.fpscr &= !(nibble_mask & CLEARABLE_MASK); - // PPCBUG-068: recompute the VX summary bit. If any VX* exception - // bit remains set, VX must remain set; if all are cleared, VX - // must clear. (FEX recomputation omitted — xenia doesn't model - // enabled-exception dispatch.) - if ctx.fpscr & fpscr::VX_ALL != 0 { - ctx.fpscr |= fpscr::VX; - } else { - ctx.fpscr &= !fpscr::VX; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_mcrfs(PPCHIRBuilder& f, const InstrData& i) { + // mcrfs CRFD, CRFS + // CR[4*CRFD:4*CRFD+3] <- FPSCR[4*CRFS:4*CRFS+3] + // FPSCR[4*CRFS:4*CRFS+3] <- 0 (exception bits cleared) + + uint32_t crfd = i.X.RT >> 2; // Destination CR field + uint32_t crfs = i.X.RA >> 2; // Source FPSCR field + + Value* fpscr = f.LoadFPSCR(); + + // Extract 4-bit field from FPSCR + // FPSCR fields are numbered from left to right (0-7), with field 0 being bits + // 0-3 + uint32_t shift = 4 * (7 - crfs); + Value* fpscr_field = f.And(f.Shr(fpscr, shift), f.LoadConstantUint32(0xF)); + + // Store to CR field (need to shift to proper position in 64-bit CR) + f.StoreCR(crfd, f.Shl(f.ZeroExtend(fpscr_field, INT64_TYPE), 4 * (7 - crfd))); + + // Clear the FPSCR field (set to 0) + uint32_t mask = ~(0xF << shift); + f.StoreFPSCR(f.And(fpscr, f.LoadConstantUint32(mask))); + + return 0; +} ```
diff --git a/tools/ppc-manual/control/mcrxr.md b/tools/ppc-manual/control/mcrxr.md index ebfaae33..68570b3d 100644 --- a/tools/ppc-manual/control/mcrxr.md +++ b/tools/ppc-manual/control/mcrxr.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,27 +84,32 @@ _No condition-register or status-register effects._ ## Implementation References **`mcrxr`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mcrxr"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:433`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L433) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:51`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L51) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:814`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L814) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4694-4706`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4694-L4706) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mcrxr"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:435`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L435) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:169`](../../../crates/sylpheed-ppc/src/opcode.rs#L169) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:929`](../../../crates/sylpheed-ppc/src/decoder.rs#L929) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mcrxr => { - let crfd = instr.crfd(); - ctx.cr[crfd] = crate::context::CrField { - lt: ctx.xer_so != 0, - gt: ctx.xer_ov != 0, - eq: ctx.xer_ca != 0, - so: false, - }; - ctx.xer_so = 0; - ctx.xer_ov = 0; - ctx.xer_ca = 0; - ctx.pc += 4; - } +```cpp +int InstrEmit_mcrxr(PPCHIRBuilder& f, const InstrData& i) { + // CR[4*CRFD:4*CRFD+3] <- XER[0:3] + // XER[0:3] <- 0 + // XER bits: SO (bit 31), OV (bit 30), CA (bit 29), reserved (bit 28) + + uint32_t crfd = i.X.RT >> 2; + Value* xer = f.LoadXER(); + + // Extract XER[0:3] which are bits 31-28 + Value* xer_bits = f.And(f.Shr(xer, 28), f.LoadConstantUint64(0xF)); + + // Store to CR field + f.StoreCR(crfd, f.Shl(xer_bits, 4 * (7 - crfd))); + + // Clear XER[0:3] (bits 31-28) + f.StoreXER(f.And(xer, f.LoadConstantUint64(~(0xFULL << 28)))); + + return 0; +} ```
diff --git a/tools/ppc-manual/control/mfcr.md b/tools/ppc-manual/control/mfcr.md index 9cccdcac..deba93c1 100644 --- a/tools/ppc-manual/control/mfcr.md +++ b/tools/ppc-manual/control/mfcr.md @@ -63,13 +63,15 @@ RT <- 0x00000000 || CR ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -77,18 +79,53 @@ RT <- 0x00000000 || CR ## Implementation References **`mfcr`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mfcr"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:625`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L625) -- 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:753`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L753) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1627-1630`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1627-L1630) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mfcr"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:627`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L627) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:171`](../../../crates/sylpheed-ppc/src/opcode.rs#L171) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:868`](../../../crates/sylpheed-ppc/src/decoder.rs#L868) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mfcr => { - ctx.gpr[instr.rd()] = ctx.cr() as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_mfcr(PPCHIRBuilder& f, const InstrData& i) { + // mfocrf RT,FXM + // RT <- undefined + // count <- 0 + // do i = 0 to 7 + // if FXMi = 1 then + // n <- i + // count <- count + 1 + // if count = 1 then + // RT4un + 32:4un + 35 <- CR4un + 32 : 4un + 35 + + // TODO(benvanik): optimize mfcr sequences. + // Often look something like this: + // mfocrf r11, cr6 + // not r10, r11 + // extrwi r3, r10, 1, 26 + // Could recognize this and only load the appropriate CR bit. + + Value* v; + if (i.XFX.spr & (1 << 9)) { + uint32_t bits = (i.XFX.spr & 0x1FF) >> 1; + int count = 0; + int cri = 0; + for (int b = 0; b <= 7; ++b) { + if (bits & (1 << b)) { + cri = 7 - b; + ++count; + } + } + if (count == 1) { + v = f.LoadCR(cri); + } else { + v = f.LoadZeroInt64(); + } + } else { + v = f.LoadCR(); + } + f.StoreGPR(i.XFX.RT, v); + return 0; +} ```
diff --git a/tools/ppc-manual/control/mffsx.md b/tools/ppc-manual/control/mffsx.md index 344fb6e7..bfcd808f 100644 --- a/tools/ppc-manual/control/mffsx.md +++ b/tools/ppc-manual/control/mffsx.md @@ -59,28 +59,26 @@ mffs[Rc] [RD] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,20 +86,21 @@ mffs[Rc] [RD] ## Implementation References **`mffsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mffsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:397`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L397) -- 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:910`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L910) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3035-3040`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3035-L3040) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mffsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:397`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L397) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:172`](../../../crates/sylpheed-ppc/src/opcode.rs#L172) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1025`](../../../crates/sylpheed-ppc/src/decoder.rs#L1025) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mffsx => { - // Move from FPSCR: frD = FPSCR as double (low 32 bits) - ctx.fpr[instr.rd()] = f64::from_bits(ctx.fpscr as u64); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_mffsx(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.Cast(f.ZeroExtend(f.LoadFPSCR(), INT64_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + if (i.X.Rc) { + f.CopyFPSCRToCR1(); + } + return 0; +} ```
diff --git a/tools/ppc-manual/control/mfmsr.md b/tools/ppc-manual/control/mfmsr.md index 0efaa829..0ace8b49 100644 --- a/tools/ppc-manual/control/mfmsr.md +++ b/tools/ppc-manual/control/mfmsr.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,18 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`mfmsr`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mfmsr"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:814`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L814) -- 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:771`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L771) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1645-1648`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1645-L1648) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mfmsr"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:816`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L816) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:173`](../../../crates/sylpheed-ppc/src/opcode.rs#L173) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:886`](../../../crates/sylpheed-ppc/src/decoder.rs#L886) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mfmsr => { - ctx.gpr[instr.rd()] = ctx.msr; - ctx.pc += 4; - } +```cpp +int InstrEmit_mfmsr(PPCHIRBuilder& f, const InstrData& i) { + // bit 48 = EE; interrupt enabled + // bit 62 = RI; recoverable interrupt + // return 8000h if unlocked (interrupts enabled), else 0 + f.StoreGPR(i.X.RT, f.LoadContext(offsetof(PPCContext, msr), INT64_TYPE)); + return 0; +} ```
diff --git a/tools/ppc-manual/control/mfspr.md b/tools/ppc-manual/control/mfspr.md index 57ca1d4d..2258ee19 100644 --- a/tools/ppc-manual/control/mfspr.md +++ b/tools/ppc-manual/control/mfspr.md @@ -79,43 +79,65 @@ switch (n) { ## 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) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mfspr"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:668`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L668) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:174`](../../../crates/sylpheed-ppc/src/opcode.rs#L174) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:914`](../../../crates/sylpheed-ppc/src/decoder.rs#L914) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```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; - } +```cpp +int InstrEmit_mfspr(PPCHIRBuilder& f, const InstrData& i) { + // n <- spr[5:9] || spr[0:4] + // if length(SPR(n)) = 64 then + // RT <- SPR(n) + // else + // RT <- i32.0 || SPR(n) + Value* v; + const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F); + switch (n) { + case 1: + // XER + v = f.LoadXER(); + break; + case 8: + // LR + v = f.LoadLR(); + break; + case 9: + // CTR + v = f.LoadCTR(); + break; + case 256: + // VRSAVE + + v = f.ZeroExtend(f.LoadContext(offsetof(PPCContext, vrsave), INT32_TYPE), + INT64_TYPE); + break; + case 268: + // TB + v = f.LoadClock(); + break; + case 269: + // TBU + v = f.Shr(f.LoadClock(), 32); + break; + case 287: + // [ Processor Version Register (PVR) ] + // PVR is a 32 bit, read-only register within the supervisor level. + // Bits 0 to 15 are the version number. + // Bits 16 to 31 are the revision number. + // Known Values: 0x710600?, 0x710700, 0x710800 (Corona?); + // Note: Some XEXs (such as mfgbootlauncher.xex) may check for a value + // that's less than 0x710700. + v = f.LoadConstantUint64(cvars::pvr); + break; + default: + XEINSTRNOTIMPLEMENTED(); + return 1; + } + f.StoreGPR(i.XFX.RT, v); + return 0; +} ```
diff --git a/tools/ppc-manual/control/mftb.md b/tools/ppc-manual/control/mftb.md index dd0298df..c2d20e13 100644 --- a/tools/ppc-manual/control/mftb.md +++ b/tools/ppc-manual/control/mftb.md @@ -56,28 +56,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,23 +83,25 @@ _No condition-register or status-register effects._ ## Implementation References **`mftb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mftb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:719`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L719) -- 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:803`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L803) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1664-1672`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1664-L1672) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mftb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:721`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L721) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:175`](../../../crates/sylpheed-ppc/src/opcode.rs#L175) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:918`](../../../crates/sylpheed-ppc/src/decoder.rs#L918) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mftb => { - let tbr = instr.spr(); - ctx.gpr[instr.rd()] = match tbr { - 268 => ctx.timebase & 0xFFFF_FFFF, - 269 => ctx.timebase >> 32, - _ => 0, - }; - ctx.pc += 4; - } +```cpp +int InstrEmit_mftb(PPCHIRBuilder& f, const InstrData& i) { + Value* time = f.LoadClock(); + const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F); + if (n == 268) { + // TB - full bits. + } else { + // TBU - upper bits only. + time = f.Shr(time, 32); + } + f.StoreGPR(i.XFX.RT, time); + return 0; +} ```
diff --git a/tools/ppc-manual/control/mfvscr.md b/tools/ppc-manual/control/mfvscr.md index bccfa371..a99cfb40 100644 --- a/tools/ppc-manual/control/mfvscr.md +++ b/tools/ppc-manual/control/mfvscr.md @@ -56,28 +56,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,22 +83,19 @@ _No condition-register or status-register effects._ ## Implementation References **`mfvscr`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mfvscr"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:303`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L303) -- 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:539`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L539) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2506-2513`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2506-L2513) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mfvscr"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:303`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L303) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:176`](../../../crates/sylpheed-ppc/src/opcode.rs#L176) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:654`](../../../crates/sylpheed-ppc/src/decoder.rs#L654) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mfvscr => { - // PPCBUG-080: ISA places VSCR in the rightmost word of VD with - // bytes 0-11 zeroed. Previously the full 128-bit ctx.vscr was - // copied (leaking stale upper data to guest). - let vscr_word = ctx.vscr.as_u32x4()[3]; - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array([0, 0, 0, vscr_word]); - ctx.pc += 4; - } +```cpp +int InstrEmit_mfvscr(PPCHIRBuilder& f, const InstrData& i) { + // mfvscr VD - Move from VSCR to VD + f.StoreVR(i.VX.VD, + f.LoadContext(offsetof(PPCContext, vscr_vec), VEC128_TYPE)); + return 0; +} ```
diff --git a/tools/ppc-manual/control/mtcrf.md b/tools/ppc-manual/control/mtcrf.md index e3b92b6e..537d6cc9 100644 --- a/tools/ppc-manual/control/mtcrf.md +++ b/tools/ppc-manual/control/mtcrf.md @@ -63,13 +63,15 @@ for i in 0..7: ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -77,28 +79,51 @@ for i in 0..7: ## Implementation References **`mtcrf`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtcrf"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:732`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L732) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:55`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L55) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:779`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L779) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1631-1644`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1631-L1644) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtcrf"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:734`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L734) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:178`](../../../crates/sylpheed-ppc/src/opcode.rs#L178) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:894`](../../../crates/sylpheed-ppc/src/decoder.rs#L894) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mtcrf => { - let crm = instr.crm(); - let val = ctx.gpr[instr.rs()] as u32; - let old = ctx.cr(); - let mut new = old; - for i in 0..8u32 { - if crm & (1 << (7 - i)) != 0 { - let mask = 0xF << (28 - i * 4); - new = (new & !mask) | (val & mask); - } - } - ctx.set_cr(new); - ctx.pc += 4; - } +```cpp +int InstrEmit_mtcrf(PPCHIRBuilder& f, const InstrData& i) { + // mtocrf FXM,RS + // count <- 0 + // do i = 0 to 7 + // if FXMi = 1 then + // n <- i + // count <- count + 1 + // if count = 1 then + // CR4un + 32 : 4un + 35 <- RS4un + 32:4un + 35 + + Value* v = f.LoadGPR(i.XFX.RT); + if (i.XFX.spr & (1 << 9)) { + uint32_t bits = (i.XFX.spr & 0x1FF) >> 1; + int count = 0; + int cri = 0; + for (int b = 0; b <= 7; ++b) { + if (bits & (1 << b)) { + cri = 7 - b; + ++count; + } + } + if (count == 1) { + f.StoreCR(cri, v); + } else { + // Invalid; store zero to CR. + f.StoreCR(f.LoadZeroInt64()); + } + } else { + uint32_t bits = (i.XFX.spr & 0x1FF) >> 1; + for (int b = 0; b <= 7; ++b) { + if (bits & (1 << b)) { + int cri = 7 - b; + f.StoreCR(cri, v); + } + } + } + return 0; +} ```
diff --git a/tools/ppc-manual/control/mtfsb0x.md b/tools/ppc-manual/control/mtfsb0x.md index 2c562af9..1dd99ee2 100644 --- a/tools/ppc-manual/control/mtfsb0x.md +++ b/tools/ppc-manual/control/mtfsb0x.md @@ -58,28 +58,26 @@ mtfsb0[Rc] [FPSCRD] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,21 +85,17 @@ mtfsb0[Rc] [FPSCRD] ## Implementation References **`mtfsb0x`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtfsb0x"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:406`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L406) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:55`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L55) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:905`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L905) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3055-3061`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3055-L3061) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtfsb0x"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:406`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L406) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:179`](../../../crates/sylpheed-ppc/src/opcode.rs#L179) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1020`](../../../crates/sylpheed-ppc/src/decoder.rs#L1020) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mtfsb0x => { - // Clear FPSCR bit crbd - let bit = instr.crbd(); - ctx.fpscr &= !(1 << (31 - bit)); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_mtfsb0x(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/control/mtfsb1x.md b/tools/ppc-manual/control/mtfsb1x.md index 4b936a1e..b43f3e35 100644 --- a/tools/ppc-manual/control/mtfsb1x.md +++ b/tools/ppc-manual/control/mtfsb1x.md @@ -58,28 +58,26 @@ mtfsb1[Rc] [FPSCRD] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,21 +85,17 @@ mtfsb1[Rc] [FPSCRD] ## Implementation References **`mtfsb1x`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtfsb1x"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:411`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L411) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:55`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L55) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:902`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L902) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3062-3068`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3062-L3068) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtfsb1x"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:411`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L411) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:180`](../../../crates/sylpheed-ppc/src/opcode.rs#L180) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1017`](../../../crates/sylpheed-ppc/src/decoder.rs#L1017) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mtfsb1x => { - // Set FPSCR bit crbd - let bit = instr.crbd(); - ctx.fpscr |= 1 << (31 - bit); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_mtfsb1x(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/control/mtfsfix.md b/tools/ppc-manual/control/mtfsfix.md index 9e258d52..2be1b1f1 100644 --- a/tools/ppc-manual/control/mtfsfix.md +++ b/tools/ppc-manual/control/mtfsfix.md @@ -59,28 +59,26 @@ mtfsfi[Rc] [CRFD], [IMM] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,23 +86,36 @@ mtfsfi[Rc] [CRFD], [IMM] ## Implementation References **`mtfsfix`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtfsfix"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:452`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L452) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:55`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L55) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:907`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L907) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3069-3077`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3069-L3077) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtfsfix"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:452`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L452) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:181`](../../../crates/sylpheed-ppc/src/opcode.rs#L181) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1022`](../../../crates/sylpheed-ppc/src/decoder.rs#L1022) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mtfsfix => { - // Move to FPSCR field immediate: crfD = IMM (4 bits) - let crfd = instr.crfd(); - let imm = (instr.raw >> 12) & 0xF; - let shift = 28 - crfd as u32 * 4; - ctx.fpscr = (ctx.fpscr & !(0xF << shift)) | (imm << shift); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_mtfsfix(PPCHIRBuilder& f, const InstrData& i) { + // FPSCR[crfD] <- IMM + + // Create a mask. + uint32_t mask = 0xF << (0x1C - (i.X.RT & 0x1C)); + uint32_t value = i.X.RB << (0x1C - (i.X.RT & 0x1C)); + + Value* fpscr = f.LoadFPSCR(); + fpscr = f.And(fpscr, f.LoadConstantInt32(~mask)); + fpscr = f.Or(fpscr, f.LoadConstantInt32(value)); + f.StoreFPSCR(fpscr); + + // Update the system rounding mode. + if (mask & 0x7) { + f.SetRoundingMode(f.And(fpscr, f.LoadConstantInt32(7))); + } + + if (i.X.Rc) { + f.CopyFPSCRToCR1(); + } + + return 0; +} ```
diff --git a/tools/ppc-manual/control/mtfsfx.md b/tools/ppc-manual/control/mtfsfx.md index e0d6fd65..26950396 100644 --- a/tools/ppc-manual/control/mtfsfx.md +++ b/tools/ppc-manual/control/mtfsfx.md @@ -61,28 +61,26 @@ mtfsf[Rc] [FM], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -90,28 +88,48 @@ mtfsf[Rc] [FM], [FB] ## Implementation References **`mtfsfx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtfsfx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:416`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L416) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:55`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L55) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:911`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L911) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3041-3054`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3041-L3054) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtfsfx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:416`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L416) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:182`](../../../crates/sylpheed-ppc/src/opcode.rs#L182) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1026`](../../../crates/sylpheed-ppc/src/decoder.rs#L1026) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mtfsfx => { - // Move to FPSCR fields: fm mask in bits 7-14, frB value - let fm = (instr.raw >> 17) & 0xFF; - let val = ctx.fpr[instr.rb()].to_bits() as u32; - let mut mask = 0u32; - for i in 0..8 { - if fm & (1 << (7 - i)) != 0 { - mask |= 0xF << (28 - i * 4); - } - } - ctx.fpscr = (ctx.fpscr & !mask) | (val & mask); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_mtfsfx(PPCHIRBuilder& f, const InstrData& i) { + if (i.XFL.L) { + // Move/shift. + f.StoreFPSCR( + f.Truncate(f.Cast(f.LoadFPR(i.XFL.RB), INT64_TYPE), INT32_TYPE)); + return 1; + } else { + assert_zero(i.XFL.W); + // Store under control of mask. + // Expand the mask from 8 bits -> 32 bits. + uint32_t mask = 0; + for (int j = 0; j < 8; j++) { + if (i.XFL.FM & (1 << (j ^ 7))) { + mask |= 0xF << (4 * j); + } + } + + Value* v = f.Truncate(f.Cast(f.LoadFPR(i.XFL.RB), INT64_TYPE), INT32_TYPE); + if (mask != 0xFFFFFFFF) { + Value* fpscr = f.LoadFPSCR(); + v = f.And(v, f.LoadConstantInt32(mask)); + v = f.Or(v, f.And(fpscr, f.LoadConstantInt32(~mask))); + } + f.StoreFPSCR(v); + + // Update the system rounding mode. + if (mask & 0x7) { + f.SetRoundingMode(f.And(v, f.LoadConstantInt32(7))); + } + } + if (i.XFL.Rc) { + f.CopyFPSCRToCR1(); + } + return 0; +} ```
diff --git a/tools/ppc-manual/control/mtmsr.md b/tools/ppc-manual/control/mtmsr.md index 2c597af2..cb24458c 100644 --- a/tools/ppc-manual/control/mtmsr.md +++ b/tools/ppc-manual/control/mtmsr.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,29 +84,17 @@ _No condition-register or status-register effects._ ## Implementation References **`mtmsr`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtmsr"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:822`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L822) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:55`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L55) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:780`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L780) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1649-1663`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1649-L1663) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtmsr"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:824`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L824) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:183`](../../../crates/sylpheed-ppc/src/opcode.rs#L183) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:895`](../../../crates/sylpheed-ppc/src/decoder.rs#L895) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mtmsr | PpcOpcode::mtmsrd => { - // PPCBUG-078: mtmsrd L=1 is a partial-MSR-write — only MSR[EE] - // (u64 bit 15) and MSR[RI] (u64 bit 0) are modified; all other - // MSR bits preserved. Used by kernel code to re-enable external - // interrupts without disturbing the rest of the MSR. - let l = (instr.raw >> (31 - 15)) & 1; - let rs = ctx.gpr[instr.rs()]; - if matches!(instr.opcode, PpcOpcode::mtmsrd) && l == 1 { - let mask: u64 = (1u64 << 15) | 1u64; - ctx.msr = (ctx.msr & !mask) | (rs & mask); - } else { - ctx.msr = rs; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_mtmsr(PPCHIRBuilder& f, const InstrData& i) { + f.StoreContext(offsetof(PPCContext, msr), f.LoadGPR(i.X.RT)); + return 0; +} ```
diff --git a/tools/ppc-manual/control/mtmsrd.md b/tools/ppc-manual/control/mtmsrd.md index 47f3c06c..f6df6e1a 100644 --- a/tools/ppc-manual/control/mtmsrd.md +++ b/tools/ppc-manual/control/mtmsrd.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,29 +84,25 @@ _No condition-register or status-register effects._ ## Implementation References **`mtmsrd`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtmsrd"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:827`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L827) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:55`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L55) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:785`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L785) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1649-1663`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1649-L1663) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtmsrd"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:829`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L829) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:184`](../../../crates/sylpheed-ppc/src/opcode.rs#L184) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:900`](../../../crates/sylpheed-ppc/src/decoder.rs#L900) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mtmsr | PpcOpcode::mtmsrd => { - // PPCBUG-078: mtmsrd L=1 is a partial-MSR-write — only MSR[EE] - // (u64 bit 15) and MSR[RI] (u64 bit 0) are modified; all other - // MSR bits preserved. Used by kernel code to re-enable external - // interrupts without disturbing the rest of the MSR. - let l = (instr.raw >> (31 - 15)) & 1; - let rs = ctx.gpr[instr.rs()]; - if matches!(instr.opcode, PpcOpcode::mtmsrd) && l == 1 { - let mask: u64 = (1u64 << 15) | 1u64; - ctx.msr = (ctx.msr & !mask) | (rs & mask); - } else { - ctx.msr = rs; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_mtmsrd(PPCHIRBuilder& f, const InstrData& i) { + // todo: this is moving msr under a mask, so only writing EE and RI + + Value* from = f.LoadGPR(i.X.RT); + Value* mtmsrd_mask = f.LoadConstantUint64((1ULL << 15)); + Value* msr = f.LoadContext(offsetof(PPCContext, msr), INT64_TYPE); + + Value* new_msr = f.Or(f.And(from, mtmsrd_mask), f.AndNot(msr, mtmsrd_mask)); + + f.StoreContext(offsetof(PPCContext, msr), new_msr); + return 0; +} ```
diff --git a/tools/ppc-manual/control/mtspr.md b/tools/ppc-manual/control/mtspr.md index 6103cde5..bd833828 100644 --- a/tools/ppc-manual/control/mtspr.md +++ b/tools/ppc-manual/control/mtspr.md @@ -63,13 +63,15 @@ SPR(n) <- (RS) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -77,45 +79,48 @@ SPR(n) <- (RS) ## Implementation References **`mtspr`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtspr"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_control.cc:771`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_control.cc#L771) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:55`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L55) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:810`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L810) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1596-1626`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1596-L1626) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtspr"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_control.cc:773`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_control.cc#L773) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:185`](../../../crates/sylpheed-ppc/src/opcode.rs#L185) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:925`](../../../crates/sylpheed-ppc/src/decoder.rs#L925) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mtspr => { - let spr = instr.spr(); - let val = ctx.gpr[instr.rs()]; - match spr { - crate::context::spr::XER => ctx.set_xer(val as u32), - crate::context::spr::LR => ctx.lr = val, - crate::context::spr::CTR => ctx.ctr = val as u32 as u64, - crate::context::spr::DEC => ctx.dec = val as u32, - crate::context::spr::TBL_WRITE => { - ctx.timebase = (ctx.timebase & 0xFFFF_FFFF_0000_0000) | (val & 0xFFFF_FFFF); - } - crate::context::spr::TBU_WRITE => { - ctx.timebase = (ctx.timebase & 0x0000_0000_FFFF_FFFF) | ((val & 0xFFFF_FFFF) << 32); - } - crate::context::spr::VRSAVE => ctx.vrsave = val as u32, - // Benign writes — swallow silently to avoid false Unimplemented - // warnings on SPRs that have no observable effect in userspace. - 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 => {} - _ => { - tracing::warn!("mtspr: unimplemented SPR {}", spr); - } - } - ctx.pc += 4; - } +```cpp +int InstrEmit_mtspr(PPCHIRBuilder& f, const InstrData& i) { + // n <- spr[5:9] || spr[0:4] + // if length(SPR(n)) = 64 then + // SPR(n) <- (RS) + // else + // SPR(n) <- (RS)[32:63] + + Value* rt = f.LoadGPR(i.XFX.RT); + + const uint32_t n = ((i.XFX.spr & 0x1F) << 5) | ((i.XFX.spr >> 5) & 0x1F); + switch (n) { + case 1: + // XER + f.StoreXER(rt); + break; + case 8: + // LR + f.StoreLR(rt); + break; + case 9: + // CTR + f.StoreCTR(rt); + break; + case 256: + + f.StoreContext(offsetof(PPCContext, vrsave), f.Truncate(rt, INT32_TYPE)); + // VRSAVE + break; + default: + XEINSTRNOTIMPLEMENTED(); + return 1; + } + + return 0; +} ```
diff --git a/tools/ppc-manual/control/mtvscr.md b/tools/ppc-manual/control/mtvscr.md index ea991d34..e1a5966d 100644 --- a/tools/ppc-manual/control/mtvscr.md +++ b/tools/ppc-manual/control/mtvscr.md @@ -56,28 +56,26 @@ ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,18 +83,27 @@ ## Implementation References **`mtvscr`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtvscr"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:310`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L310) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:55`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L55) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:542`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L542) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2514-2517`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2514-L2517) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="mtvscr"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:310`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L310) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:186`](../../../crates/sylpheed-ppc/src/opcode.rs#L186) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:657`](../../../crates/sylpheed-ppc/src/decoder.rs#L657) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::mtvscr => { - ctx.vscr = ctx.vr[instr.rb()]; - ctx.pc += 4; - } +```cpp +int InstrEmit_mtvscr(PPCHIRBuilder& f, const InstrData& i) { + // mtvscr VB - Move from VB to VSCR + // todo: what mtvscr does with the unused bits is implementation defined, + // figure out what it does + + Value* v = f.LoadVR(i.VX.VB); + + Value* has_njm_value = f.Extract(v, (uint8_t)3, INT32_TYPE); + + f.SetNJM(f.IsTrue(f.And(has_njm_value, f.LoadConstantInt32(65536)))); + + f.StoreContext(offsetof(PPCContext, vscr_vec), v); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fabsx.md b/tools/ppc-manual/fpu/fabsx.md index a3493974..c3e11088 100644 --- a/tools/ppc-manual/fpu/fabsx.md +++ b/tools/ppc-manual/fpu/fabsx.md @@ -65,13 +65,15 @@ FRT <- clear_sign(FRB) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -79,19 +81,30 @@ FRT <- clear_sign(FRB) ## Implementation References **`fabsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fabsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:478`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L478) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:909`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L909) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2757-2761`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2757-L2761) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fabsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:478`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L478) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:64`](../../../crates/sylpheed-ppc/src/opcode.rs#L64) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1024`](../../../crates/sylpheed-ppc/src/decoder.rs#L1024) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fabsx => { - ctx.fpr[instr.rd()] = ctx.fpr[instr.rb()].abs(); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fabsx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- abs(frB) + Value* v = f.Abs(f.LoadFPR(i.X.RB)); + f.StoreFPR(i.X.RT, v); + /* + The contents of frB with bit 0 cleared are placed into frD. +Note that the fabs instruction treats NaNs just like any other kind of value. +That is, the sign bit of a NaN may be altered by fabs. This instruction does not +alter the FPSCR. Other registers altered: • Condition Register (CR1 field): +Affected: FX, FEX, VX, OX (if Rc = 1) + */ + // f.UpdateFPSCR(v, i.X.Rc); + if (i.X.Rc) { + // todo + } + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/faddsx.md b/tools/ppc-manual/fpu/faddsx.md index 7bc26a19..c768ac3f 100644 --- a/tools/ppc-manual/fpu/faddsx.md +++ b/tools/ppc-manual/fpu/faddsx.md @@ -68,13 +68,15 @@ FRT <- RoundToSingle(FRA + FRB) ; single-precision ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -82,24 +84,21 @@ FRT <- RoundToSingle(FRA + FRB) ; single-precision ## Implementation References **`faddsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="faddsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:46`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L46) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:388`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L388) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2565-2574`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2565-L2574) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="faddsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:46`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L46) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:65`](../../../crates/sylpheed-ppc/src/opcode.rs#L65) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:503`](../../../crates/sylpheed-ppc/src/decoder.rs#L503) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::faddsx => { - let a = ctx.fpr[instr.ra()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_add(ctx, a, b, false); - let result = to_single(ctx, a + b); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_faddsx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- (frA) + (frB) + Value* v = f.Add(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + v = f.ToSingle(v); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/faddx.md b/tools/ppc-manual/fpu/faddx.md index a64a65e4..930a0d4e 100644 --- a/tools/ppc-manual/fpu/faddx.md +++ b/tools/ppc-manual/fpu/faddx.md @@ -77,24 +77,20 @@ if (insn.Rc) update_cr1_from_fpscr(); ## Implementation References **`faddx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="faddx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:38`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L38) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:922`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L922) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2555-2564`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2555-L2564) -
xenia-rs interpreter body (frozen snapshot) +- 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) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::faddx => { - let a = ctx.fpr[instr.ra()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_add(ctx, a, b, false); - let result = a + b; - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```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; +} ```
diff --git a/tools/ppc-manual/fpu/fcfidx.md b/tools/ppc-manual/fpu/fcfidx.md index 3ed31684..7437eb47 100644 --- a/tools/ppc-manual/fpu/fcfidx.md +++ b/tools/ppc-manual/fpu/fcfidx.md @@ -60,28 +60,26 @@ fcfid[Rc] [FD], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,28 +87,20 @@ fcfid[Rc] [FD], [FB] ## Implementation References **`fcfidx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fcfidx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:253`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L253) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:914`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L914) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2872-2885`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2872-L2885) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fcfidx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:253`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L253) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:67`](../../../crates/sylpheed-ppc/src/opcode.rs#L67) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1029`](../../../crates/sylpheed-ppc/src/decoder.rs#L1029) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fcfidx => { - // Convert from integer doubleword: frD = (double)(int64_t)frB_as_bits. - // PPCBUG-224: set XX when |i64| > 2^53 (precision loss in conversion). - let bits = ctx.fpr[instr.rb()].to_bits(); - let i = bits as i64; - let result = i as f64; - if (result as i64) != i { - fpscr::set_exception(ctx, fpscr::XX); - } - ctx.fpr[instr.rd()] = result; - fpscr::set_fprf(ctx, fpscr::classify_fprf(result)); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fcfidx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- signed_int64_to_double( frB ) + Value* v = f.Convert(f.Cast(f.LoadFPR(i.X.RB), INT64_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fcmpo.md b/tools/ppc-manual/fpu/fcmpo.md index 87f02b2a..13105dfc 100644 --- a/tools/ppc-manual/fpu/fcmpo.md +++ b/tools/ppc-manual/fpu/fcmpo.md @@ -59,28 +59,26 @@ fcmpo [CRFD], [FA], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,45 +86,51 @@ fcmpo [CRFD], [FA], [FB] ## Implementation References **`fcmpo`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fcmpo"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:362`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L362) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:901`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L901) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3002-3032`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3002-L3032) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fcmpo"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:362`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L362) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:68`](../../../crates/sylpheed-ppc/src/opcode.rs#L68) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1016`](../../../crates/sylpheed-ppc/src/decoder.rs#L1016) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fcmpo => { - // Ordered compare: like fcmpu but also sets VXVC on QNaN (or VXSNAN on SNaN). - let fra = ctx.fpr[instr.ra()]; - let frb = ctx.fpr[instr.rb()]; - let crfd = instr.crfd(); - if fra.is_nan() || frb.is_nan() { - ctx.cr[crfd] = crate::context::CrField { lt: false, gt: false, eq: false, so: true }; - if fpscr::is_snan(fra) || fpscr::is_snan(frb) { - fpscr::set_exception(ctx, fpscr::VXSNAN | fpscr::VXVC); - } else { - fpscr::set_exception(ctx, fpscr::VXVC); - } - } else if fra < frb { - ctx.cr[crfd] = crate::context::CrField { lt: true, gt: false, eq: false, so: false }; - } else if fra > frb { - ctx.cr[crfd] = crate::context::CrField { lt: false, gt: true, eq: false, so: false }; - } else { - ctx.cr[crfd] = crate::context::CrField { lt: false, gt: false, eq: true, so: false }; - } - let fprf = if fra.is_nan() || frb.is_nan() { - 0b0_0001 - } else if fra < frb { - 0b0_1000 - } else if fra > frb { - 0b0_0100 - } else { - 0b0_0010 - }; - fpscr::set_fprf(ctx, fprf); - ctx.pc += 4; - } +```cpp +int InstrEmit_fcmpo(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_fcmpx_(f, i, true); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_fpu.cc:329) ── +int InstrEmit_fcmpx_(PPCHIRBuilder& f, const InstrData& i, bool ordered) { + // if (FRA) is a NaN or (FRB) is a NaN then + // c <- 0b0001 + // else if (FRA) < (FRB) then + // c <- 0b1000 + // else if (FRA) > (FRB) then + // c <- 0b0100 + // else { + // c <- 0b0010 + // } + // FPCC <- c + // CR[4*BF:4*BF+3] <- c + // if (FRA) is an SNaN or (FRB) is an SNaN then + // VXSNAN <- 1 + + // TODO(benvanik): update FPCC for mffsx/etc + // TODO(benvanik): update VXSNAN + const uint32_t crf = i.X.RT >> 2; + Value* ra = f.LoadFPR(i.X.RA); + Value* rb = f.LoadFPR(i.X.RB); + + Value* nan = f.Or(f.IsNan(ra), f.IsNan(rb)); + f.StoreContext(offsetof(PPCContext, cr0) + (4 * crf) + 3, nan); + Value* not_nan = f.Xor(nan, f.LoadConstantInt8(0x01)); + + Value* lt = f.And(not_nan, f.CompareSLT(ra, rb)); + f.StoreContext(offsetof(PPCContext, cr0) + (4 * crf) + 0, lt); + Value* gt = f.And(not_nan, f.CompareSGT(ra, rb)); + f.StoreContext(offsetof(PPCContext, cr0) + (4 * crf) + 1, gt); + Value* eq = f.And(not_nan, f.CompareEQ(ra, rb)); + f.StoreContext(offsetof(PPCContext, cr0) + (4 * crf) + 2, eq); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fcmpu.md b/tools/ppc-manual/fpu/fcmpu.md index f588a925..f4283442 100644 --- a/tools/ppc-manual/fpu/fcmpu.md +++ b/tools/ppc-manual/fpu/fcmpu.md @@ -59,28 +59,26 @@ fcmpu [CRFD], [FA], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,44 +86,51 @@ fcmpu [CRFD], [FA], [FB] ## Implementation References **`fcmpu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fcmpu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:365`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L365) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:897`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L897) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2972-3001`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2972-L3001) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fcmpu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:365`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L365) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:69`](../../../crates/sylpheed-ppc/src/opcode.rs#L69) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1012`](../../../crates/sylpheed-ppc/src/decoder.rs#L1012) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fcmpu => { - let fra = ctx.fpr[instr.ra()]; - let frb = ctx.fpr[instr.rb()]; - let crfd = instr.crfd(); - if fra.is_nan() || frb.is_nan() { - ctx.cr[crfd] = crate::context::CrField { lt: false, gt: false, eq: false, so: true }; - // fcmpu: VXSNAN on SNaN input; no VXVC even on QNaN. - if fpscr::is_snan(fra) || fpscr::is_snan(frb) { - fpscr::set_exception(ctx, fpscr::VXSNAN); - } - } else if fra < frb { - ctx.cr[crfd] = crate::context::CrField { lt: true, gt: false, eq: false, so: false }; - } else if fra > frb { - ctx.cr[crfd] = crate::context::CrField { lt: false, gt: true, eq: false, so: false }; - } else { - ctx.cr[crfd] = crate::context::CrField { lt: false, gt: false, eq: true, so: false }; - } - // Also mirror the comparison result into FPSCR[FPRF (FL/FG/FE/FU)]. - let fprf = if fra.is_nan() || frb.is_nan() { - 0b0_0001 - } else if fra < frb { - 0b0_1000 - } else if fra > frb { - 0b0_0100 - } else { - 0b0_0010 - }; - fpscr::set_fprf(ctx, fprf); - ctx.pc += 4; - } +```cpp +int InstrEmit_fcmpu(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_fcmpx_(f, i, false); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_fpu.cc:329) ── +int InstrEmit_fcmpx_(PPCHIRBuilder& f, const InstrData& i, bool ordered) { + // if (FRA) is a NaN or (FRB) is a NaN then + // c <- 0b0001 + // else if (FRA) < (FRB) then + // c <- 0b1000 + // else if (FRA) > (FRB) then + // c <- 0b0100 + // else { + // c <- 0b0010 + // } + // FPCC <- c + // CR[4*BF:4*BF+3] <- c + // if (FRA) is an SNaN or (FRB) is an SNaN then + // VXSNAN <- 1 + + // TODO(benvanik): update FPCC for mffsx/etc + // TODO(benvanik): update VXSNAN + const uint32_t crf = i.X.RT >> 2; + Value* ra = f.LoadFPR(i.X.RA); + Value* rb = f.LoadFPR(i.X.RB); + + Value* nan = f.Or(f.IsNan(ra), f.IsNan(rb)); + f.StoreContext(offsetof(PPCContext, cr0) + (4 * crf) + 3, nan); + Value* not_nan = f.Xor(nan, f.LoadConstantInt8(0x01)); + + Value* lt = f.And(not_nan, f.CompareSLT(ra, rb)); + f.StoreContext(offsetof(PPCContext, cr0) + (4 * crf) + 0, lt); + Value* gt = f.And(not_nan, f.CompareSGT(ra, rb)); + f.StoreContext(offsetof(PPCContext, cr0) + (4 * crf) + 1, gt); + Value* eq = f.And(not_nan, f.CompareEQ(ra, rb)); + f.StoreContext(offsetof(PPCContext, cr0) + (4 * crf) + 2, eq); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fctidx.md b/tools/ppc-manual/fpu/fctidx.md index 33f30a22..a7ba7745 100644 --- a/tools/ppc-manual/fpu/fctidx.md +++ b/tools/ppc-manual/fpu/fctidx.md @@ -60,28 +60,26 @@ fctid[Rc] [FD], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,35 +87,37 @@ fctid[Rc] [FD], [FB] ## Implementation References **`fctidx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fctidx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:280`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L280) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:912`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L912) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2886-2906`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2886-L2906) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fctidx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:280`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L280) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:70`](../../../crates/sylpheed-ppc/src/opcode.rs#L70) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1027`](../../../crates/sylpheed-ppc/src/decoder.rs#L1027) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fctidx => { - // Convert to integer doubleword (round per FPSCR[RN]). - // PPCBUG-229: set XX on inexact (fractional input). - let val = ctx.fpr[instr.rb()]; - let result = if val.is_nan() { - fpscr::set_exception(ctx, fpscr::VXCVI | if fpscr::is_snan(val) { fpscr::VXSNAN } else { 0 }); - 0x8000_0000_0000_0000u64 - } else if val >= (i64::MAX as f64) { - fpscr::set_exception(ctx, fpscr::VXCVI); - 0x7FFF_FFFF_FFFF_FFFFu64 - } else if val < (i64::MIN as f64) { - fpscr::set_exception(ctx, fpscr::VXCVI); - 0x8000_0000_0000_0000u64 - } else { - if val != val.trunc() { fpscr::set_exception(ctx, fpscr::XX); } - fpscr::round_to_i64(ctx, val) as u64 - }; - ctx.fpr[instr.rd()] = f64::from_bits(result); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fctidx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- double_to_signed_int64( frB ) + return InstrEmit_fctidxx_(f, i, ROUND_DYNAMIC); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_fpu.cc:261) ── +int InstrEmit_fctidxx_(PPCHIRBuilder& f, const InstrData& i, + RoundMode round_mode) { + auto end = f.NewLabel(); + auto isnan = f.NewLabel(); + Value* v; + f.BranchTrue(f.IsNan(f.LoadFPR(i.X.RB)), isnan); + v = f.Convert(f.LoadFPR(i.X.RB), INT64_TYPE, round_mode); + v = f.Cast(v, FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + f.Branch(end); + f.MarkLabel(isnan); + v = f.Cast(f.LoadConstantUint64(0x8000000000000000u), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + f.MarkLabel(end); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fctidzx.md b/tools/ppc-manual/fpu/fctidzx.md index ccc50e4d..4514597a 100644 --- a/tools/ppc-manual/fpu/fctidzx.md +++ b/tools/ppc-manual/fpu/fctidzx.md @@ -60,28 +60,26 @@ fctidz[Rc] [FD], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,35 +87,36 @@ fctidz[Rc] [FD], [FB] ## Implementation References **`fctidzx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fctidzx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:285`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L285) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:913`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L913) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2907-2927`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2907-L2927) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fctidzx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:285`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L285) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:71`](../../../crates/sylpheed-ppc/src/opcode.rs#L71) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1028`](../../../crates/sylpheed-ppc/src/decoder.rs#L1028) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fctidzx => { - // Convert to integer doubleword (round toward zero). - // PPCBUG-229: set XX on inexact. - let val = ctx.fpr[instr.rb()]; - let result = if val.is_nan() { - fpscr::set_exception(ctx, fpscr::VXCVI | if fpscr::is_snan(val) { fpscr::VXSNAN } else { 0 }); - 0x8000_0000_0000_0000u64 - } else if val >= (i64::MAX as f64) { - fpscr::set_exception(ctx, fpscr::VXCVI); - 0x7FFF_FFFF_FFFF_FFFFu64 - } else if val < (i64::MIN as f64) { - fpscr::set_exception(ctx, fpscr::VXCVI); - 0x8000_0000_0000_0000u64 - } else { - if val != val.trunc() { fpscr::set_exception(ctx, fpscr::XX); } - (val.trunc() as i64) as u64 - }; - ctx.fpr[instr.rd()] = f64::from_bits(result); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fctidzx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_fctidxx_(f, i, ROUND_TO_ZERO); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_fpu.cc:261) ── +int InstrEmit_fctidxx_(PPCHIRBuilder& f, const InstrData& i, + RoundMode round_mode) { + auto end = f.NewLabel(); + auto isnan = f.NewLabel(); + Value* v; + f.BranchTrue(f.IsNan(f.LoadFPR(i.X.RB)), isnan); + v = f.Convert(f.LoadFPR(i.X.RB), INT64_TYPE, round_mode); + v = f.Cast(v, FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + f.Branch(end); + f.MarkLabel(isnan); + v = f.Cast(f.LoadConstantUint64(0x8000000000000000u), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + f.MarkLabel(end); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fctiwx.md b/tools/ppc-manual/fpu/fctiwx.md index 96bb4831..ce69e924 100644 --- a/tools/ppc-manual/fpu/fctiwx.md +++ b/tools/ppc-manual/fpu/fctiwx.md @@ -60,28 +60,26 @@ fctiw[Rc] [FD], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,35 +87,37 @@ fctiw[Rc] [FD], [FB] ## Implementation References **`fctiwx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fctiwx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:308`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L308) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:899`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L899) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2928-2948`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2928-L2948) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fctiwx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:308`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L308) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:72`](../../../crates/sylpheed-ppc/src/opcode.rs#L72) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1014`](../../../crates/sylpheed-ppc/src/decoder.rs#L1014) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fctiwx => { - // Convert to integer word (round per FPSCR[RN]). - // PPCBUG-230: set XX on inexact. - let val = ctx.fpr[instr.rb()]; - let result_u32: u32 = if val.is_nan() { - fpscr::set_exception(ctx, fpscr::VXCVI | if fpscr::is_snan(val) { fpscr::VXSNAN } else { 0 }); - 0x8000_0000 - } else if val > (i32::MAX as f64) { - fpscr::set_exception(ctx, fpscr::VXCVI); - 0x7FFF_FFFF - } else if val < (i32::MIN as f64) { - fpscr::set_exception(ctx, fpscr::VXCVI); - 0x8000_0000 - } else { - if val != val.trunc() { fpscr::set_exception(ctx, fpscr::XX); } - fpscr::round_to_i32(ctx, val) as u32 - }; - ctx.fpr[instr.rd()] = f64::from_bits(result_u32 as u64); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fctiwx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- double_to_signed_int32( frB ) + return InstrEmit_fctiwxx_(f, i, ROUND_DYNAMIC); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_fpu.cc:289) ── +int InstrEmit_fctiwxx_(PPCHIRBuilder& f, const InstrData& i, + RoundMode round_mode) { + auto end = f.NewLabel(); + auto isnan = f.NewLabel(); + Value* v; + f.BranchTrue(f.IsNan(f.LoadFPR(i.X.RB)), isnan); + v = f.Convert(f.LoadFPR(i.X.RB), INT32_TYPE, round_mode); + v = f.Cast(f.SignExtend(v, INT64_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + f.Branch(end); + f.MarkLabel(isnan); + v = f.Cast(f.LoadConstantUint32(0x80000000u), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + f.MarkLabel(end); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fctiwzx.md b/tools/ppc-manual/fpu/fctiwzx.md index 4d108bf4..4d6745bd 100644 --- a/tools/ppc-manual/fpu/fctiwzx.md +++ b/tools/ppc-manual/fpu/fctiwzx.md @@ -60,28 +60,26 @@ fctiwz[Rc] [FD], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,35 +87,37 @@ fctiwz[Rc] [FD], [FB] ## Implementation References **`fctiwzx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fctiwzx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:313`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L313) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:27`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L27) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:900`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L900) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2949-2969`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2949-L2969) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fctiwzx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:313`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L313) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:73`](../../../crates/sylpheed-ppc/src/opcode.rs#L73) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1015`](../../../crates/sylpheed-ppc/src/decoder.rs#L1015) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fctiwzx => { - // Convert to integer word (round toward zero). - // PPCBUG-230: set XX on inexact. - let val = ctx.fpr[instr.rb()]; - let result_u32: u32 = if val.is_nan() { - fpscr::set_exception(ctx, fpscr::VXCVI | if fpscr::is_snan(val) { fpscr::VXSNAN } else { 0 }); - 0x8000_0000 - } else if val > (i32::MAX as f64) { - fpscr::set_exception(ctx, fpscr::VXCVI); - 0x7FFF_FFFF - } else if val < (i32::MIN as f64) { - fpscr::set_exception(ctx, fpscr::VXCVI); - 0x8000_0000 - } else { - if val != val.trunc() { fpscr::set_exception(ctx, fpscr::XX); } - val.trunc() as i32 as u32 - }; - ctx.fpr[instr.rd()] = f64::from_bits(result_u32 as u64); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fctiwzx(PPCHIRBuilder& f, const InstrData& i) { + // TODO(benvanik): assuming round to zero is always set, is that ok? + return InstrEmit_fctiwxx_(f, i, ROUND_TO_ZERO); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_fpu.cc:289) ── +int InstrEmit_fctiwxx_(PPCHIRBuilder& f, const InstrData& i, + RoundMode round_mode) { + auto end = f.NewLabel(); + auto isnan = f.NewLabel(); + Value* v; + f.BranchTrue(f.IsNan(f.LoadFPR(i.X.RB)), isnan); + v = f.Convert(f.LoadFPR(i.X.RB), INT32_TYPE, round_mode); + v = f.Cast(f.SignExtend(v, INT64_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + f.Branch(end); + f.MarkLabel(isnan); + v = f.Cast(f.LoadConstantUint32(0x80000000u), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + f.MarkLabel(end); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fdivsx.md b/tools/ppc-manual/fpu/fdivsx.md index b2e8e7b8..4727553e 100644 --- a/tools/ppc-manual/fpu/fdivsx.md +++ b/tools/ppc-manual/fpu/fdivsx.md @@ -62,28 +62,26 @@ fdivs[Rc] [FD], [FA], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -91,25 +89,30 @@ fdivs[Rc] [FD], [FA], [FB] ## Implementation References **`fdivsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fdivsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:71`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L71) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:28`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L28) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:386`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L386) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2627-2637`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2627-L2637) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fdivsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:71`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L71) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:74`](../../../crates/sylpheed-ppc/src/opcode.rs#L74) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:501`](../../../crates/sylpheed-ppc/src/decoder.rs#L501) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fdivsx => { - let a = ctx.fpr[instr.ra()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_div(ctx, a, b); - fpscr::check_zero_divide(ctx, a, b); - let result = to_single(ctx, a / b); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite() && b != 0.0); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fdivsx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- frA / frB +#if XE_PLATFORM_LINUX + // TODO(has207): verify if this is needed on Windows + // On Linux, fdivs needs to use A format fields instead of X format + Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + v = f.ToSingle(v); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); +#else + Value* v = f.Div(f.LoadFPR(i.X.RA), f.LoadFPR(i.X.RB)); + v = f.ToSingle(v); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); +#endif + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fdivx.md b/tools/ppc-manual/fpu/fdivx.md index 2e0de3eb..a3e8434b 100644 --- a/tools/ppc-manual/fpu/fdivx.md +++ b/tools/ppc-manual/fpu/fdivx.md @@ -68,13 +68,15 @@ FRT <- FRA ÷ FRB ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -82,25 +84,28 @@ FRT <- FRA ÷ FRB ## Implementation References **`fdivx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fdivx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:55`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L55) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:28`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L28) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:920`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L920) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2616-2626`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2616-L2626) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fdivx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:55`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L55) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:75`](../../../crates/sylpheed-ppc/src/opcode.rs#L75) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1035`](../../../crates/sylpheed-ppc/src/decoder.rs#L1035) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fdivx => { - let a = ctx.fpr[instr.ra()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_div(ctx, a, b); - fpscr::check_zero_divide(ctx, a, b); - let result = a / b; - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite() && b != 0.0); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fdivx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- frA / frB +#if XE_PLATFORM_LINUX + // TODO(has207): verify if this is needed on Windows + // On Linux, fdiv needs to use A format fields instead of X format + Value* v = f.Div(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); +#else + Value* v = f.Div(f.LoadFPR(i.X.RA), f.LoadFPR(i.X.RB)); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); +#endif + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fmaddsx.md b/tools/ppc-manual/fpu/fmaddsx.md index ab4bd51a..b0df1aa3 100644 --- a/tools/ppc-manual/fpu/fmaddsx.md +++ b/tools/ppc-manual/fpu/fmaddsx.md @@ -63,28 +63,26 @@ fmadds[Rc] [FD], [FA], [FC], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,27 +90,16 @@ fmadds[Rc] [FD], [FA], [FC], [FB] ## Implementation References **`fmaddsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmaddsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:190`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L190) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:28`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L28) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:393`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L393) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2653-2665`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2653-L2665) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmaddsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:190`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L190) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:76`](../../../crates/sylpheed-ppc/src/opcode.rs#L76) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:508`](../../../crates/sylpheed-ppc/src/decoder.rs#L508) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fmaddsx => { - // PPCBUG-181: missing VXISI on add step. - let a = ctx.fpr[instr.ra()]; - let c = ctx.fpr[instr.rc()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_mul(ctx, a, c); - fpscr::check_invalid_fma_add(ctx, a, c, b, false); - let result = to_single(ctx, a.mul_add(c, b)); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite() && c.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fmaddsx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_fmadd(f, i, true); +} ```
diff --git a/tools/ppc-manual/fpu/fmaddx.md b/tools/ppc-manual/fpu/fmaddx.md index a7e567fa..1bbfacb6 100644 --- a/tools/ppc-manual/fpu/fmaddx.md +++ b/tools/ppc-manual/fpu/fmaddx.md @@ -69,13 +69,15 @@ FRT <- (FRA × FRC) + FRB ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -83,27 +85,16 @@ FRT <- (FRA × FRC) + FRB ## Implementation References **`fmaddx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmaddx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:186`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L186) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:28`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L28) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:928`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L928) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2640-2652`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2640-L2652) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmaddx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:186`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L186) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:77`](../../../crates/sylpheed-ppc/src/opcode.rs#L77) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1043`](../../../crates/sylpheed-ppc/src/decoder.rs#L1043) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fmaddx => { - // PPCBUG-202: VXISI from input properties (not from `a*c` which has wrong sign on overflow). - let a = ctx.fpr[instr.ra()]; - let c = ctx.fpr[instr.rc()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_mul(ctx, a, c); - fpscr::check_invalid_fma_add(ctx, a, c, b, false); - let result = a.mul_add(c, b); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite() && c.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fmaddx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_fmadd(f, i, false); +} ```
diff --git a/tools/ppc-manual/fpu/fmrx.md b/tools/ppc-manual/fpu/fmrx.md index 76e5b984..06ce9860 100644 --- a/tools/ppc-manual/fpu/fmrx.md +++ b/tools/ppc-manual/fpu/fmrx.md @@ -65,13 +65,15 @@ FRT <- FRB ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -79,19 +81,20 @@ FRT <- FRB ## Implementation References **`fmrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:496`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L496) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:28`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L28) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:906`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L906) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2752-2756`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2752-L2756) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:496`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L496) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:78`](../../../crates/sylpheed-ppc/src/opcode.rs#L78) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1021`](../../../crates/sylpheed-ppc/src/decoder.rs#L1021) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fmrx => { - ctx.fpr[instr.rd()] = ctx.fpr[instr.rb()]; - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fmrx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- (frB) + Value* v = f.LoadFPR(i.X.RB); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fmsubsx.md b/tools/ppc-manual/fpu/fmsubsx.md index 5a9c70c1..ed12fa89 100644 --- a/tools/ppc-manual/fpu/fmsubsx.md +++ b/tools/ppc-manual/fpu/fmsubsx.md @@ -63,28 +63,26 @@ fmsubs[Rc] [FD], [FA], [FC], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,27 +90,16 @@ fmsubs[Rc] [FD], [FA], [FC], [FB] ## Implementation References **`fmsubsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmsubsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:209`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L209) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:28`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L28) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:392`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L392) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2679-2691`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2679-L2691) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmsubsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:209`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L209) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:79`](../../../crates/sylpheed-ppc/src/opcode.rs#L79) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:507`](../../../crates/sylpheed-ppc/src/decoder.rs#L507) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fmsubsx => { - // PPCBUG-182: missing VXISI on sub step. - let a = ctx.fpr[instr.ra()]; - let c = ctx.fpr[instr.rc()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_mul(ctx, a, c); - fpscr::check_invalid_fma_add(ctx, a, c, b, true); - let result = to_single(ctx, a.mul_add(c, -b)); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite() && c.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fmsubsx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_fmsub(f, i, true); +} ```
diff --git a/tools/ppc-manual/fpu/fmsubx.md b/tools/ppc-manual/fpu/fmsubx.md index 5393ce2f..8bd15981 100644 --- a/tools/ppc-manual/fpu/fmsubx.md +++ b/tools/ppc-manual/fpu/fmsubx.md @@ -69,13 +69,15 @@ FRT <- (FRA × FRC) − FRB ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -83,27 +85,16 @@ FRT <- (FRA × FRC) − FRB ## Implementation References **`fmsubx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmsubx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:205`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L205) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:28`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L28) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:927`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L927) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2666-2678`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2666-L2678) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmsubx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:205`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L205) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:80`](../../../crates/sylpheed-ppc/src/opcode.rs#L80) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1042`](../../../crates/sylpheed-ppc/src/decoder.rs#L1042) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fmsubx => { - // PPCBUG-203: missing VXISI on sub step. - let a = ctx.fpr[instr.ra()]; - let c = ctx.fpr[instr.rc()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_mul(ctx, a, c); - fpscr::check_invalid_fma_add(ctx, a, c, b, true); - let result = a.mul_add(c, -b); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite() && c.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fmsubx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_fmsub(f, i, false); +} ```
diff --git a/tools/ppc-manual/fpu/fmulsx.md b/tools/ppc-manual/fpu/fmulsx.md index b931f6ac..fab0b9c3 100644 --- a/tools/ppc-manual/fpu/fmulsx.md +++ b/tools/ppc-manual/fpu/fmulsx.md @@ -62,28 +62,26 @@ fmuls[Rc] [FD], [FA], [FC] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -91,24 +89,21 @@ fmuls[Rc] [FD], [FA], [FC] ## Implementation References **`fmulsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmulsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:97`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L97) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:28`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L28) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:391`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L391) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2606-2615`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2606-L2615) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmulsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:97`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L97) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:81`](../../../crates/sylpheed-ppc/src/opcode.rs#L81) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:506`](../../../crates/sylpheed-ppc/src/decoder.rs#L506) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fmulsx => { - let a = ctx.fpr[instr.ra()]; - let c = ctx.fpr[instr.rc()]; - fpscr::check_invalid_mul(ctx, a, c); - let result = to_single(ctx, a * c); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && c.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fmulsx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- (frA) x (frC) + Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC)); + v = f.ToSingle(v); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fmulx.md b/tools/ppc-manual/fpu/fmulx.md index ae418f6b..cf1ad7d6 100644 --- a/tools/ppc-manual/fpu/fmulx.md +++ b/tools/ppc-manual/fpu/fmulx.md @@ -68,13 +68,15 @@ FRT <- FRA × FRC ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -82,25 +84,20 @@ FRT <- FRA × FRC ## Implementation References **`fmulx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmulx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:89`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L89) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:28`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L28) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:925`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L925) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2595-2605`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2595-L2605) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fmulx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:89`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L89) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:82`](../../../crates/sylpheed-ppc/src/opcode.rs#L82) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1040`](../../../crates/sylpheed-ppc/src/decoder.rs#L1040) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fmulx => { - // A-form: frD = frA * frC (frC is at rc() field, bits 21-25) - let a = ctx.fpr[instr.ra()]; - let c = ctx.fpr[instr.rc()]; - fpscr::check_invalid_mul(ctx, a, c); - let result = a * c; - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && c.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fmulx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- (frA) x (frC) + Value* v = f.Mul(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC)); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fnabsx.md b/tools/ppc-manual/fpu/fnabsx.md index 2314a133..c6a04a30 100644 --- a/tools/ppc-manual/fpu/fnabsx.md +++ b/tools/ppc-manual/fpu/fnabsx.md @@ -65,13 +65,15 @@ FRT <- set_sign(FRB) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -79,19 +81,23 @@ FRT <- set_sign(FRB) ## Implementation References **`fnabsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnabsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:504`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L504) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:29`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L29) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:908`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L908) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2767-2771`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2767-L2771) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnabsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:504`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L504) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:83`](../../../crates/sylpheed-ppc/src/opcode.rs#L83) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1023`](../../../crates/sylpheed-ppc/src/decoder.rs#L1023) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fnabsx => { - ctx.fpr[instr.rd()] = -(ctx.fpr[instr.rb()].abs()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fnabsx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- !abs(frB) + Value* v = f.Neg(f.Abs(f.LoadFPR(i.X.RB))); + f.StoreFPR(i.X.RT, v); + // f.UpdateFPSCR(v, i.X.Rc); + if (i.X.Rc) { + // todo + } + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fnegx.md b/tools/ppc-manual/fpu/fnegx.md index 4f772536..6e7ff8ea 100644 --- a/tools/ppc-manual/fpu/fnegx.md +++ b/tools/ppc-manual/fpu/fnegx.md @@ -65,13 +65,15 @@ FRT <- flip_sign(FRB) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -79,19 +81,23 @@ FRT <- flip_sign(FRB) ## Implementation References **`fnegx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnegx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:515`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L515) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:29`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L29) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:903`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L903) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2762-2766`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2762-L2766) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnegx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:515`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L515) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:84`](../../../crates/sylpheed-ppc/src/opcode.rs#L84) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1018`](../../../crates/sylpheed-ppc/src/decoder.rs#L1018) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fnegx => { - ctx.fpr[instr.rd()] = -ctx.fpr[instr.rb()]; - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fnegx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- ¬ frB[0] || frB[1-63] + Value* v = f.Neg(f.LoadFPR(i.X.RB)); + f.StoreFPR(i.X.RT, v); + // f.UpdateFPSCR(v, i.X.Rc); + if (i.X.Rc) { + // todo + } + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fnmaddsx.md b/tools/ppc-manual/fpu/fnmaddsx.md index 0de9ac68..4667d381 100644 --- a/tools/ppc-manual/fpu/fnmaddsx.md +++ b/tools/ppc-manual/fpu/fnmaddsx.md @@ -63,28 +63,26 @@ fnmadds[Rc] [FD], [FA], [FC], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,29 +90,22 @@ fnmadds[Rc] [FD], [FA], [FC], [FB] ## Implementation References **`fnmaddsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnmaddsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:222`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L222) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:29`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L29) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:395`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L395) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2706-2720`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2706-L2720) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnmaddsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:222`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L222) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:85`](../../../crates/sylpheed-ppc/src/opcode.rs#L85) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:510`](../../../crates/sylpheed-ppc/src/decoder.rs#L510) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fnmaddsx => { - // PPCBUG-181 + PPCBUG-183: VXISI + NaN sign preservation. - let a = ctx.fpr[instr.ra()]; - let c = ctx.fpr[instr.rc()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_mul(ctx, a, c); - fpscr::check_invalid_fma_add(ctx, a, c, b, false); - let fma = a.mul_add(c, b); - let neg = if fma.is_nan() { fma } else { -fma }; - let result = to_single(ctx, neg); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite() && c.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fnmaddsx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- -([frA x frC] + frB) + Value* v = f.Neg( + f.MulAdd(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB))); + v = f.ToSingle(v); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fnmaddx.md b/tools/ppc-manual/fpu/fnmaddx.md index 9fc37a1a..b56b7252 100644 --- a/tools/ppc-manual/fpu/fnmaddx.md +++ b/tools/ppc-manual/fpu/fnmaddx.md @@ -69,13 +69,15 @@ FRT <- −((FRA × FRC) + FRB) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -83,28 +85,21 @@ FRT <- −((FRA × FRC) + FRB) ## Implementation References **`fnmaddx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnmaddx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:213`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L213) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:29`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L29) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:930`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L930) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2692-2705`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2692-L2705) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnmaddx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:213`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L213) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:86`](../../../crates/sylpheed-ppc/src/opcode.rs#L86) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1045`](../../../crates/sylpheed-ppc/src/decoder.rs#L1045) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fnmaddx => { - // PPCBUG-203: missing VXISI. PPCBUG-205: NaN sign preserved (no negation on NaN). - let a = ctx.fpr[instr.ra()]; - let c = ctx.fpr[instr.rc()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_mul(ctx, a, c); - fpscr::check_invalid_fma_add(ctx, a, c, b, false); - let fma = a.mul_add(c, b); - let result = if fma.is_nan() { fma } else { -fma }; - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite() && c.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fnmaddx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- -([frA x frC] + frB) + Value* v = f.Neg( + f.MulAdd(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB))); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fnmsubsx.md b/tools/ppc-manual/fpu/fnmsubsx.md index 6556f775..62e55168 100644 --- a/tools/ppc-manual/fpu/fnmsubsx.md +++ b/tools/ppc-manual/fpu/fnmsubsx.md @@ -63,28 +63,26 @@ fnmsubs[Rc] [FD], [FA], [FC], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,29 +90,22 @@ fnmsubs[Rc] [FD], [FA], [FC], [FB] ## Implementation References **`fnmsubsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnmsubsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:241`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L241) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:29`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L29) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:394`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L394) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2735-2749`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2735-L2749) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnmsubsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:241`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L241) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:87`](../../../crates/sylpheed-ppc/src/opcode.rs#L87) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:509`](../../../crates/sylpheed-ppc/src/decoder.rs#L509) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fnmsubsx => { - // PPCBUG-182 + PPCBUG-183: VXISI + NaN sign preservation. - let a = ctx.fpr[instr.ra()]; - let c = ctx.fpr[instr.rc()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_mul(ctx, a, c); - fpscr::check_invalid_fma_add(ctx, a, c, b, true); - let fma = a.mul_add(c, -b); - let neg = if fma.is_nan() { fma } else { -fma }; - let result = to_single(ctx, neg); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite() && c.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fnmsubsx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- -([frA x frC] - frB) + Value* v = f.Neg( + f.MulSub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB))); + v = f.ToSingle(v); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fnmsubx.md b/tools/ppc-manual/fpu/fnmsubx.md index 3f06634b..05a4620e 100644 --- a/tools/ppc-manual/fpu/fnmsubx.md +++ b/tools/ppc-manual/fpu/fnmsubx.md @@ -69,13 +69,15 @@ FRT <- −((FRA × FRC) − FRB) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -83,28 +85,21 @@ FRT <- −((FRA × FRC) − FRB) ## Implementation References **`fnmsubx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnmsubx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:232`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L232) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:29`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L29) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:929`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L929) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2721-2734`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2721-L2734) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fnmsubx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:232`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L232) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:88`](../../../crates/sylpheed-ppc/src/opcode.rs#L88) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1044`](../../../crates/sylpheed-ppc/src/decoder.rs#L1044) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fnmsubx => { - // PPCBUG-203: VXISI. PPCBUG-205: NaN sign preservation. - let a = ctx.fpr[instr.ra()]; - let c = ctx.fpr[instr.rc()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_mul(ctx, a, c); - fpscr::check_invalid_fma_add(ctx, a, c, b, true); - let fma = a.mul_add(c, -b); - let result = if fma.is_nan() { fma } else { -fma }; - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite() && c.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fnmsubx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- -([frA x frC] - frB) + Value* v = f.Neg( + f.MulSub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB))); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fresx.md b/tools/ppc-manual/fpu/fresx.md index f6f03e8c..7c38c419 100644 --- a/tools/ppc-manual/fpu/fresx.md +++ b/tools/ppc-manual/fpu/fresx.md @@ -61,28 +61,26 @@ fres[Rc] [FD], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -90,35 +88,24 @@ fres[Rc] [FD], [FB] ## Implementation References **`fresx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fresx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:106`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L106) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:29`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L29) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:390`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L390) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2815-2835`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2815-L2835) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fresx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:106`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L106) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:89`](../../../crates/sylpheed-ppc/src/opcode.rs#L89) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:505`](../../../crates/sylpheed-ppc/src/decoder.rs#L505) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fresx => { - // Single-precision reciprocal estimate: frD = 1.0 / frB. - // PPCBUG-184: pre-quantize input to f32 to match canary's - // `f.Recip(f.Convert(frB, FLOAT32_TYPE))` behavior. Hardware - // produces a ~12-bit LUT estimate; both emulators produce a - // fully-IEEE single reciprocal, but the f32 quantization at - // least makes the input precision match. - let b_full = ctx.fpr[instr.rb()]; - let b = b_full as f32 as f64; - if b == 0.0 { - fpscr::set_exception(ctx, fpscr::ZX); - } - if fpscr::is_snan(b_full) { - fpscr::set_exception(ctx, fpscr::VXSNAN); - } - let result = to_single(ctx, 1.0 / b); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, b.is_finite() && b != 0.0); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fresx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- 1.0 / (frB) + + // this actually does seem to require single precision, oddly + // more research is needed + Value* v = f.Recip(f.Convert(f.LoadFPR(i.A.FRB), FLOAT32_TYPE)); + v = f.Convert(v, FLOAT64_TYPE); // f.ToSingle(v); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/frspx.md b/tools/ppc-manual/fpu/frspx.md index 83e126b8..20738c19 100644 --- a/tools/ppc-manual/fpu/frspx.md +++ b/tools/ppc-manual/fpu/frspx.md @@ -60,28 +60,26 @@ frsp[Rc] [FD], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,30 +87,21 @@ frsp[Rc] [FD], [FB] ## Implementation References **`frspx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="frspx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:318`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L318) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:29`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L29) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:898`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L898) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2856-2871`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2856-L2871) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="frspx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:318`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L318) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:90`](../../../crates/sylpheed-ppc/src/opcode.rs#L90) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1013`](../../../crates/sylpheed-ppc/src/decoder.rs#L1013) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::frspx => { - // Round to single precision honouring FPSCR[RN]. - // PPCBUG-225: set XX on inexact rounding (almost every frsp call). - let b = ctx.fpr[instr.rb()]; - if fpscr::is_snan(b) { - fpscr::set_exception(ctx, fpscr::VXSNAN); - } - let result = to_single(ctx, b); - if b.is_finite() && result.is_finite() && result != b { - fpscr::set_exception(ctx, fpscr::XX); - } - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, b.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_frspx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- Round_single(frB) + Value* v = f.Convert(f.LoadFPR(i.X.RB), FLOAT32_TYPE, ROUND_DYNAMIC); + v = f.Convert(v, FLOAT64_TYPE); + f.StoreFPR(i.X.RT, v); + f.UpdateFPSCR(v, i.X.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/frsqrtex.md b/tools/ppc-manual/fpu/frsqrtex.md index cdf99253..17d3d575 100644 --- a/tools/ppc-manual/fpu/frsqrtex.md +++ b/tools/ppc-manual/fpu/frsqrtex.md @@ -61,28 +61,26 @@ frsqrte[Rc] [FD], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -90,32 +88,21 @@ frsqrte[Rc] [FD], [FB] ## Implementation References **`frsqrtex`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="frsqrtex"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:118`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L118) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:29`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L29) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:926`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L926) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2836-2853`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2836-L2853) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="frsqrtex"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:118`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L118) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:91`](../../../crates/sylpheed-ppc/src/opcode.rs#L91) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1041`](../../../crates/sylpheed-ppc/src/decoder.rs#L1041) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::frsqrtex => { - // Reciprocal square root estimate: frD = 1.0 / sqrt(frB) - let b = ctx.fpr[instr.rb()]; - if b == 0.0 { - fpscr::set_exception(ctx, fpscr::ZX); - } - if b.is_sign_negative() && b != 0.0 && !b.is_nan() { - fpscr::set_exception(ctx, fpscr::VXSQRT); - } - if fpscr::is_snan(b) { - fpscr::set_exception(ctx, fpscr::VXSNAN); - } - let result = 1.0 / b.sqrt(); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, b.is_finite() && b > 0.0); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_frsqrtex(PPCHIRBuilder& f, const InstrData& i) { + // Double precision: + // frD <- 1/sqrt(frB) + Value* v = f.RSqrt(f.LoadFPR(i.A.FRB)); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fselx.md b/tools/ppc-manual/fpu/fselx.md index 5c031756..4802a8f4 100644 --- a/tools/ppc-manual/fpu/fselx.md +++ b/tools/ppc-manual/fpu/fselx.md @@ -62,28 +62,26 @@ fsel[Rc] [FD], [FA], [FC], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -91,24 +89,23 @@ fsel[Rc] [FD], [FA], [FC], [FB] ## Implementation References **`fselx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fselx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:144`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L144) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:30`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L30) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:924`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L924) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2774-2783`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2774-L2783) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fselx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:144`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L144) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:92`](../../../crates/sylpheed-ppc/src/opcode.rs#L92) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1039`](../../../crates/sylpheed-ppc/src/decoder.rs#L1039) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fselx => { - // frD = if frA >= 0.0 then frC else frB - ctx.fpr[instr.rd()] = if ctx.fpr[instr.ra()] >= 0.0 { - ctx.fpr[instr.rc()] - } else { - ctx.fpr[instr.rb()] - }; - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fselx(PPCHIRBuilder& f, const InstrData& i) { + // if (frA) >= 0.0 + // then frD <- (frC) + // else frD <- (frB) + Value* ge = f.CompareSGE(f.LoadFPR(i.A.FRA), f.LoadZeroFloat64()); + Value* v = f.Select(ge, f.LoadFPR(i.A.FRC), f.LoadFPR(i.A.FRB)); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fsqrtsx.md b/tools/ppc-manual/fpu/fsqrtsx.md index fca8344a..2c38990d 100644 --- a/tools/ppc-manual/fpu/fsqrtsx.md +++ b/tools/ppc-manual/fpu/fsqrtsx.md @@ -61,28 +61,26 @@ fsqrts[Rc] [FD], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -90,28 +88,16 @@ fsqrts[Rc] [FD], [FB] ## Implementation References **`fsqrtsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fsqrtsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:168`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L168) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:30`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L30) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:389`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L389) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2801-2814`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2801-L2814) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fsqrtsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:168`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L168) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:93`](../../../crates/sylpheed-ppc/src/opcode.rs#L93) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:504`](../../../crates/sylpheed-ppc/src/decoder.rs#L504) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fsqrtsx => { - let b = ctx.fpr[instr.rb()]; - if b.is_sign_negative() && b != 0.0 && !b.is_nan() { - fpscr::set_exception(ctx, fpscr::VXSQRT); - } - if fpscr::is_snan(b) { - fpscr::set_exception(ctx, fpscr::VXSNAN); - } - let result = to_single(ctx, b.sqrt()); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, b.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fsqrtsx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_fsqrt(f, i, true); +} ```
diff --git a/tools/ppc-manual/fpu/fsqrtx.md b/tools/ppc-manual/fpu/fsqrtx.md index 91a3b185..bfb8b522 100644 --- a/tools/ppc-manual/fpu/fsqrtx.md +++ b/tools/ppc-manual/fpu/fsqrtx.md @@ -61,28 +61,26 @@ fsqrt[Rc] [FD], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -90,29 +88,16 @@ fsqrt[Rc] [FD], [FB] ## Implementation References **`fsqrtx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fsqrtx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:164`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L164) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:30`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L30) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:923`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L923) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2786-2800`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2786-L2800) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fsqrtx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:164`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L164) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:94`](../../../crates/sylpheed-ppc/src/opcode.rs#L94) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1038`](../../../crates/sylpheed-ppc/src/decoder.rs#L1038) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fsqrtx => { - let b = ctx.fpr[instr.rb()]; - // sqrt of negative (non-zero) is invalid operation → VXSQRT. - if b.is_sign_negative() && b != 0.0 && !b.is_nan() { - fpscr::set_exception(ctx, fpscr::VXSQRT); - } - if fpscr::is_snan(b) { - fpscr::set_exception(ctx, fpscr::VXSNAN); - } - let result = b.sqrt(); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, b.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fsqrtx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_fsqrt(f, i, false); +} ```
diff --git a/tools/ppc-manual/fpu/fsubsx.md b/tools/ppc-manual/fpu/fsubsx.md index a06b0b0e..44d60109 100644 --- a/tools/ppc-manual/fpu/fsubsx.md +++ b/tools/ppc-manual/fpu/fsubsx.md @@ -62,28 +62,26 @@ fsubs[Rc] [FD], [FA], [FB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -91,24 +89,21 @@ fsubs[Rc] [FD], [FA], [FB] ## Implementation References **`fsubsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fsubsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:135`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L135) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:30`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L30) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:387`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L387) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2585-2594`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2585-L2594) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fsubsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:135`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L135) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:95`](../../../crates/sylpheed-ppc/src/opcode.rs#L95) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:502`](../../../crates/sylpheed-ppc/src/decoder.rs#L502) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fsubsx => { - let a = ctx.fpr[instr.ra()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_add(ctx, a, b, true); - let result = to_single(ctx, a - b); - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fsubsx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- (frA) - (frB) + Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + v = f.ToSingle(v); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/fpu/fsubx.md b/tools/ppc-manual/fpu/fsubx.md index cf34199e..1a65239e 100644 --- a/tools/ppc-manual/fpu/fsubx.md +++ b/tools/ppc-manual/fpu/fsubx.md @@ -68,13 +68,15 @@ FRT <- FRA − FRB ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -82,24 +84,20 @@ FRT <- FRA − FRB ## Implementation References **`fsubx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fsubx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:127`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L127) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:30`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L30) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:921`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L921) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2575-2584`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2575-L2584) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="fsubx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_fpu.cc:127`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_fpu.cc#L127) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:96`](../../../crates/sylpheed-ppc/src/opcode.rs#L96) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1036`](../../../crates/sylpheed-ppc/src/decoder.rs#L1036) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::fsubx => { - let a = ctx.fpr[instr.ra()]; - let b = ctx.fpr[instr.rb()]; - fpscr::check_invalid_add(ctx, a, b, true); - let result = a - b; - ctx.fpr[instr.rd()] = result; - fpscr::update_after_op(ctx, result, a.is_finite() && b.is_finite()); - if instr.rc_bit() { update_cr1_from_fpscr(ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_fsubx(PPCHIRBuilder& f, const InstrData& i) { + // frD <- (frA) - (frB) + Value* v = f.Sub(f.LoadFPR(i.A.FRA), f.LoadFPR(i.A.FRB)); + f.StoreFPR(i.A.FRT, v); + f.UpdateFPSCR(v, i.A.Rc); + return 0; +} ```
diff --git a/tools/ppc-manual/generator/README.md b/tools/ppc-manual/generator/README.md index 92b55ece..1a5e7cd7 100644 --- a/tools/ppc-manual/generator/README.md +++ b/tools/ppc-manual/generator/README.md @@ -1,15 +1,24 @@ # Manual generator -Python scripts that build the `ppc-manual/` tree from the two -authoritative sources in this repository: +Python scripts that build the `tools/ppc-manual/` tree from: -- `xenia-canary/tools/ppc-instructions.xml` — metadata for all 455 - Xbox 360 PPC instructions (mnemonic, form, group, opcode, in/out - fields, disasm template). -- `xenia-rs/crates/xenia-cpu/src/` — the Rust interpreter. Individual - instruction semantics live in `interpreter.rs` match arms. -- `xenia-canary/src/xenia/cpu/ppc/ppc_emit_*.cc` — the C++ emit - functions; referenced by line number only. +- **Xenia Canary** — the reference emulator — read at a **pinned commit** through + `git show`, never from a working tree: + - `tools/ppc-instructions.xml` — metadata for all 455 Xbox 360 PPC instructions + (mnemonic, form, group, opcode, in/out fields, disasm template); + - `src/xenia/cpu/ppc/ppc_emit_*.cc` — each instruction's `InstrEmit_` + emitter, quoted on its page as the semantic snapshot. +- **`crates/sylpheed-ppc`** — Sylpheed's own decoder, the one that produces the + disassembly in `sylpheed.db`; referenced by opcode and decoder line. + +The pin is `origin/canary_experimental` by default. Our own Canary checkout is a +working branch: it carries instrumentation and can lag upstream by months — it +lacked upstream's `mcrf` fix when this was written — so quoting it would publish +probes and stale semantics as "Canary". + +`xenia-rs` was a source until 2026-09-16. It is retired and archived; its +interpreter is no longer quoted. Hand-written notes that still discuss its +behaviour link to the archived repository. ## Files @@ -18,19 +27,29 @@ authoritative sources in this repository: | `generate_manual.py` | Main entry point. Parses XML, builds families, renders pages, writes `index.json`. | | `xml_model.py` | XML parser + `expand_runtime_variants()` (produces the set of Rc/OE/LK-expanded mnemonics a single XML entry covers). | | `bit_layout.py` | Per-form bit-field tables (rendered into the Encoding section of every page and into `forms/*.md`). | -| `rust_scraper.py` | Locates each `PpcOpcode::` enum variant, decoder arm, and interpreter match-arm line range. | -| `cxx_scraper.py` | Locates `InstrEmit_` in the xenia-canary emit `.cc` files. | +| `cxx_scraper.py` | `CanarySource` (one pinned commit) and `CxxScraper`: locates each `InstrEmit_`, captures its full text, and follows pure one-line delegations to the helper that holds the semantics. Brace matching models `#if 0` / `#else`. | +| `decoder_scraper.py` | Locates each `PpcOpcode::` variant and decoder producer in `crates/sylpheed-ppc`. | ## Running +From the repository root: + ```bash -python3 ppc-manual/generator/generate_manual.py # full generate -python3 ppc-manual/generator/generate_manual.py --dry-run # parse + consistency checks only -python3 ppc-manual/generator/generate_manual.py --out /tmp/out # alternate output root -python3 ppc-manual/generator/generate_manual.py --xml /path/to/ppc-instructions.xml +python3 tools/ppc-manual/generator/generate_manual.py # full generate +python3 tools/ppc-manual/generator/generate_manual.py --dry-run # parse + consistency checks only +python3 tools/ppc-manual/generator/generate_manual.py --canary ../xenia-canary --canary-ref origin/canary_experimental +python3 tools/ppc-manual/generator/generate_manual.py --out /tmp/out # alternate output root ``` -No third-party dependencies; Python 3.10+ standard library only. +`--canary` defaults to the `xenia-canary` checkout beside this repository. +Fetch upstream first (`git -C ../xenia-canary fetch origin`) to move the pin +forward; the commit used is printed, recorded in `index.json` under +`sources.canary.commit`, and stamped on every snapshot. A missing checkout, ref +or source file is an **error** — the previous generator skipped what it could +not find, which is how every reference in the manual rotted unnoticed when it +moved into `tools/`. + +No third-party dependencies; Python 3.10+ standard library and `git`. ## Idempotency @@ -99,14 +118,15 @@ Mnemonics" table. - Extended-opcode extraction in `xml_model.Instruction.extended_opcode` is best-effort per form. For VMX128 variants the extracted value may - not match the exact pattern used by xenia's decoder tree — the page - still shows it as a reference but the decoder source (linked on - every page) is authoritative. -- `rust_scraper` uses a naive brace counter to delimit interpreter - match arms. It works for the current interpreter because the match - arms use balanced braces and no string literals with unbalanced - braces. If the interpreter ever adopts such literals the scraper - will need a Rust-aware parser. + not match the exact pattern used by the decoder — the page still + shows it as a reference, but the `sylpheed-ppc` decoder line (linked + on every page) is authoritative. +- `cxx_scraper` delimits emitters with a brace counter that ignores comments, + string literals and preprocessor-dead lines. On the pinned commit it agrees with + the column-0 `}` convention on all 521 functions that follow it; the one that + does not, `InstrEmit_branch`, closes on a `}` carrying a stale + `// namespace ppc` comment. `memory/dcbi.md` has no snapshot because Canary has + no `InstrEmit_dcbi` at all. - The generator treats mnemonics ending in `x` as xenia convention ("extended/XO form") and strips them for assembly display — except for the memory group, where `x` is the natural indexed-form suffix. diff --git a/tools/ppc-manual/generator/cxx_scraper.py b/tools/ppc-manual/generator/cxx_scraper.py index acb68567..fa36092a 100644 --- a/tools/ppc-manual/generator/cxx_scraper.py +++ b/tools/ppc-manual/generator/cxx_scraper.py @@ -1,6 +1,6 @@ """ -Scrapes xenia-canary's emit files for the location of each instruction's -semantic implementation function `InstrEmit_`. +Scrapes Xenia Canary's PPC front-end for each instruction's semantic +implementation, `InstrEmit_`, at a PINNED commit. The files are: src/xenia/cpu/ppc/ppc_emit_alu.cc (integer ALU) @@ -9,8 +9,21 @@ The files are: src/xenia/cpu/ppc/ppc_emit_fpu.cc (floating-point) src/xenia/cpu/ppc/ppc_emit_control.cc (branch/CR/SPR/syscall/trap) -Returns, for each mnemonic, the relative file path and the starting line -of the `int InstrEmit_(...)` definition. +Returns, for each mnemonic, the file, the starting line of the +`int InstrEmit_(...)` definition, and the full function text. + +🔴 Everything is read through `git show :`, never from the +checkout's working tree. The local Canary checkout is a working branch: it +carries our instrumentation, and it can sit months behind upstream — at the +time this was written it lacked upstream's fix to `mcrf` ("copy the CR field +instead of comparing it against zero"). A manual quoting the working tree +would publish probes and a wrong `mcrf` as "Canary semantics". Pinning also +makes every line number in the manual match the commit its links name. + +🔴 And a missing input is an ERROR, not an empty result. The previous version +skipped any file it could not find, and when the manual moved into +`tools/ppc-manual/` every source path stopped resolving without a single +warning. """ from __future__ import annotations @@ -18,6 +31,7 @@ from __future__ import annotations from dataclasses import dataclass from pathlib import Path import re +import subprocess CXX_EMIT_FILES = [ @@ -28,12 +42,44 @@ CXX_EMIT_FILES = [ "src/xenia/cpu/ppc/ppc_emit_control.cc", ] +XML_PATH_IN_CANARY = "tools/ppc-instructions.xml" + + +class CanarySource: + """One Canary commit, read through git.""" + + def __init__(self, repo: Path, ref: str): + self.repo = repo + if not (repo / ".git").exists(): + raise SystemExit(f"no Canary git checkout at {repo} (pass --canary)") + res = subprocess.run( + ["git", "-C", str(repo), "rev-parse", "--verify", f"{ref}^{{commit}}"], + capture_output=True, text=True, + ) + if res.returncode != 0: + raise SystemExit( + f"Canary ref {ref!r} does not resolve in {repo} — fetch it first " + f"(`git -C {repo} fetch origin`) or pass --canary-ref" + ) + self.ref = ref + self.sha = res.stdout.strip() + + def read(self, rel: str) -> str: + res = subprocess.run( + ["git", "-C", str(self.repo), "show", f"{self.sha}:{rel}"], + capture_output=True, text=True, + ) + if res.returncode != 0: + raise SystemExit(f"{rel} is not in Canary @ {self.sha[:10]}: {res.stderr.strip()}") + return res.stdout + @dataclass class CxxRef: mnem: str - emit_file: str | None = None # relative to xenia-canary/ + emit_file: str | None = None # relative to the Canary repository root emit_line: int | None = None + emit_body: str = "" # the whole `int InstrEmit_…(…) { … }` text def _cxx_ident(mnem: str) -> str: @@ -42,34 +88,118 @@ def _cxx_ident(mnem: str) -> str: return mnem.replace(".", "x") +def _live_lines(lines: list[str]) -> list[bool]: + """Per line: is it compiled? Models just enough of the preprocessor to + count braces honestly. `#if 0` blocks are dead; for any other conditional + only the FIRST branch is taken, so `#if X { … #else { … #endif` counts one + opening brace rather than two. `InstrEmit_branch` straddles exactly such + an `#if 0 / #else / #endif`, and a naive counter ran past its end to the + close of the namespace. + """ + live: list[bool] = [] + stack: list[list[bool]] = [] # per level: [a branch was already taken, this branch is live] + for raw in lines: + t = raw.strip() + if t.startswith("#if"): + taken = not re.match(r"#if\s+0\b", t) + stack.append([taken, taken]) + live.append(False) + elif t.startswith("#el"): # #else / #elif: live only if nothing was taken yet + if stack: + stack[-1][1] = not stack[-1][0] + stack[-1][0] = True + live.append(False) + elif t.startswith("#endif"): + if stack: + stack.pop() + live.append(False) + else: + live.append(all(level[1] for level in stack)) + return live + + +def _function_end(lines: list[str], start: int, live: list[bool]) -> int: + """Index of the line holding the brace that closes the function opened at + `start`. Ignores braces in `//` comments, string/char literals and + preprocessor-dead lines. + """ + depth = 0 + opened = False + for j in range(start, len(lines)): + if not live[j]: + continue + code = re.sub(r'"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\'', "", lines[j]) + code = code.split("//", 1)[0] + for ch in code: + if ch == "{": + depth += 1 + opened = True + elif ch == "}": + depth -= 1 + if opened and depth == 0: + return j + raise ValueError(f"unterminated function starting at line {start + 1}") + + +_DELEGATION = re.compile(r"^\s*return\s+InstrEmit_([A-Za-z0-9_]+)\s*\(") + + class CxxScraper: - def __init__(self, repo_root: Path): - self.canary_root = repo_root / "xenia-canary" - self._index: dict[str, tuple[str, int]] = {} + def __init__(self, canary: CanarySource): + self.canary = canary + self._index: dict[str, tuple[str, int, str]] = {} fn_pat = re.compile(r"^\s*int\s+InstrEmit_([A-Za-z_][A-Za-z0-9_]*)\s*\(") for rel in CXX_EMIT_FILES: - path = self.canary_root / rel - if not path.is_file(): - continue - for i, line in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1): + lines = canary.read(rel).splitlines() + live = _live_lines(lines) + for i, line in enumerate(lines): m = fn_pat.match(line) if not m: continue - name = m.group(1) - self._index.setdefault(name, (rel, i)) + end = _function_end(lines, i, live) + body = "\n".join(lines[i:end + 1]) + self._index.setdefault(m.group(1), (rel, i + 1, body)) + if not self._index: + raise SystemExit(f"no InstrEmit_ functions found in Canary @ {canary.sha[:10]}") + + def __len__(self) -> int: + return len(self._index) + + def delegate_of(self, name: str) -> str | None: + """The helper a PURE one-line delegation calls, e.g. `InstrEmit_stvx` + is only `return InstrEmit_stvx_(f, i, …);`. 134 of 522 emitters are + like this, and a snapshot of the wrapper alone shows no semantics.""" + body = self._index.get(name, ("", 0, ""))[2].splitlines() + inner = [l for l in body[1:-1] if l.strip() and not l.strip().startswith("//")] + if len(inner) == 1: + m = _DELEGATION.match(inner[0]) + if m and m.group(1) in self._index and m.group(1) != name: + return m.group(1) + return None def lookup(self, mnem: str) -> CxxRef: - ident = _cxx_ident(mnem) - hit = self._index.get(ident) + name = _cxx_ident(mnem) + hit = self._index.get(name) if hit is None: return CxxRef(mnem=mnem) - return CxxRef(mnem=mnem, emit_file=hit[0], emit_line=hit[1]) + body = hit[2] + seen = {name} + helper = self.delegate_of(name) + while helper and helper not in seen: # follow the chain, never loop + seen.add(helper) + h = self._index[helper] + body += f"\n\n// ── delegates to ({h[0]}:{h[1]}) ──\n" + h[2] + helper = self.delegate_of(helper) + return CxxRef(mnem=mnem, emit_file=hit[0], emit_line=hit[1], emit_body=body) if __name__ == "__main__": - root = Path(__file__).resolve().parent.parent.parent - s = CxxScraper(root) - for m in ("addx", "addic.", "lwz", "bclrx", "mfspr", "stvx", "vaddfp", - "vaddfp128", "faddx", "lvsl"): + import sys + repo = Path(sys.argv[1]) if len(sys.argv) > 1 else \ + Path(__file__).resolve().parents[3].parent / "xenia-canary" + s = CxxScraper(CanarySource(repo, "origin/canary_experimental")) + print(f"{len(s)} emitters @ {s.canary.sha[:10]}") + for m in ("addcx", "addic.", "lwz", "bclrx", "mfspr", "stvx", "vaddfp", + "vaddfp128", "faddx", "mcrf"): r = s.lookup(m) - print(f"{m:12s} {r.emit_file}:{r.emit_line}") + print(f"{m:12s} {r.emit_file}:{r.emit_line} ({r.emit_body.count(chr(10)) + 1 if r.emit_body else 0} lines)") diff --git a/tools/ppc-manual/generator/decoder_scraper.py b/tools/ppc-manual/generator/decoder_scraper.py new file mode 100644 index 00000000..3587afe2 --- /dev/null +++ b/tools/ppc-manual/generator/decoder_scraper.py @@ -0,0 +1,104 @@ +""" +Locates each instruction in Sylpheed's own PowerPC decoder, +`crates/sylpheed-ppc` — the decoder that produces the disassembly in +`sylpheed.db`, and so the one whose mnemonics a reader of that database sees. + +Outputs produced for each mnemonic: + - opcode_line: line in `crates/sylpheed-ppc/src/opcode.rs` where the + `PpcOpcode` variant is declared (1-indexed) + - decoder_line: line in `crates/sylpheed-ppc/src/decoder.rs` where the + variant is produced from raw bits + +This used to scrape `xenia-rs/crates/xenia-cpu/src/`, including an +interpreter-arm snapshot. `xenia-rs` is retired and archived, and the decoder +half was lifted into `sylpheed-ppc` unchanged in shape — the same +`pub enum PpcOpcode` and `PpcOpcode::` producers — so only the path and +the interpreter half changed. Semantics now come from Canary; see +`cxx_scraper.py`. + +🔴 Missing sources are an error, not an empty index. The previous version +returned `[]` for a file it could not find, so once the manual moved and the +path stopped resolving, every page silently lost its references. +""" + +from __future__ import annotations + +from dataclasses import dataclass +from pathlib import Path +import re + +DECODER_CRATE = Path("crates") / "sylpheed-ppc" / "src" + + +@dataclass +class DecoderRef: + mnem: str + opcode_line: int | None = None + decoder_line: int | None = None + + +def _ident(mnem: str) -> str: + """XML mnemonic -> `PpcOpcode` variant: `.` is not legal in a Rust + identifier, so `addic.` is `addicx` (the same rule Canary uses).""" + return mnem.replace(".", "x") + + +class DecoderScraper: + def __init__(self, repo_root: Path): + self.src = repo_root / DECODER_CRATE + self._opcode_lines = self._read_lines(self.src / "opcode.rs") + self._decoder_lines = self._read_lines(self.src / "decoder.rs") + self._opcode_index = self._index_opcode_enum() + self._decoder_index = self._index_decoder() + if not self._opcode_index or not self._decoder_index: + raise SystemExit(f"no PpcOpcode variants/producers found under {self.src}") + + @staticmethod + def _read_lines(path: Path) -> list[str]: + if not path.is_file(): + raise SystemExit(f"decoder source missing: {path}") + return path.read_text(encoding="utf-8").splitlines() + + def _index_opcode_enum(self) -> dict[str, int]: + """Map identifier -> 1-indexed line inside `pub enum PpcOpcode { ... }` + (several identifiers may share a line).""" + idx: dict[str, int] = {} + token = re.compile(r"\b([A-Za-z_][A-Za-z0-9_]*)\b") + in_enum = False + for i, line in enumerate(self._opcode_lines, start=1): + if "pub enum PpcOpcode" in line: + in_enum = True + continue + if not in_enum: + continue + if line.startswith("}"): + break + code = line.strip().split("//", 1)[0] + for m in token.finditer(code): + idx.setdefault(m.group(1), i) + return idx + + def _index_decoder(self) -> dict[str, int]: + """Map identifier -> 1-indexed line of its FIRST `PpcOpcode::` + occurrence, i.e. where the decoder produces it.""" + idx: dict[str, int] = {} + pat = re.compile(r"PpcOpcode::([A-Za-z_][A-Za-z0-9_]*)") + for i, line in enumerate(self._decoder_lines, start=1): + for m in pat.finditer(line): + idx.setdefault(m.group(1), i) + return idx + + def lookup(self, mnem: str) -> DecoderRef: + ident = _ident(mnem) + return DecoderRef(mnem=mnem, + opcode_line=self._opcode_index.get(ident), + decoder_line=self._decoder_index.get(ident)) + + +if __name__ == "__main__": + root = Path(__file__).resolve().parents[3] + s = DecoderScraper(root) + for m in ("addcx", "addic.", "lwz", "bclrx", "mfspr", "stvx", "vaddfp", + "vaddfp128", "faddx", "mcrf"): + r = s.lookup(m) + print(f"{m:12s} opcode@{r.opcode_line} decoder@{r.decoder_line}") diff --git a/tools/ppc-manual/generator/generate_manual.py b/tools/ppc-manual/generator/generate_manual.py index 1fb49931..3a36a112 100644 --- a/tools/ppc-manual/generator/generate_manual.py +++ b/tools/ppc-manual/generator/generate_manual.py @@ -2,13 +2,14 @@ """ PowerPC Instruction Manual generator. -Reads `xenia-canary/tools/ppc-instructions.xml` plus the xenia-rs and -xenia-canary source trees, and emits a tree of one Markdown page per -instruction family together with a machine-readable `index.json` at the -manual root. +Reads Xenia Canary's `tools/ppc-instructions.xml` and PPC emitters at a +pinned commit, plus Sylpheed's own decoder (`crates/sylpheed-ppc`), and emits +a tree of one Markdown page per instruction family together with a +machine-readable `index.json` at the manual root. -Usage: - python3 generator/generate_manual.py [--dry-run] [--out PATH] +Usage (from the repository root): + python3 tools/ppc-manual/generator/generate_manual.py [--dry-run] + [--canary ../xenia-canary] [--canary-ref origin/canary_experimental] The generator is idempotent. Each page is delimited by sentinel markers so that hand-written enhancements live outside the generated region and @@ -21,6 +22,7 @@ import argparse import json import re import sys +import tempfile from collections import defaultdict from dataclasses import dataclass, field from pathlib import Path @@ -36,17 +38,30 @@ from xml_model import ( # noqa: E402 expand_runtime_variants, ) from bit_layout import FORM_LAYOUTS, render_bit_table # noqa: E402 -from rust_scraper import RustScraper # noqa: E402 -from cxx_scraper import CxxScraper # noqa: E402 +from decoder_scraper import DecoderScraper # noqa: E402 +from cxx_scraper import ( # noqa: E402 + CanarySource, CxxScraper, XML_PATH_IN_CANARY, +) # --------------------------------------------------------------------------- # Configuration # --------------------------------------------------------------------------- -REPO_ROOT = HERE.parent.parent -MANUAL_ROOT_DEFAULT = REPO_ROOT / "ppc-manual" -XML_PATH = REPO_ROOT / "xenia-canary" / "tools" / "ppc-instructions.xml" +# 🔴 `HERE.parent.parent` was the repository root while the manual lived at the +# project root. After it moved to `tools/ppc-manual/` that expression named +# `tools/`, and every source below stopped resolving — silently, because the +# scrapers skipped what they could not find. Pages kept linking to paths that +# existed nowhere. +REPO_ROOT = HERE.parents[2] # tools/ppc-manual/generator -> repo +MANUAL_ROOT_DEFAULT = REPO_ROOT / "tools" / "ppc-manual" +PAGE_TO_REPO = "../../.." # tools/ppc-manual//.md + +# Canary is the semantic source. Read at a pinned UPSTREAM commit — not the +# local checkout, which carries our instrumentation and lags upstream fixes. +CANARY_DEFAULT = REPO_ROOT.parent / "xenia-canary" +CANARY_REF_DEFAULT = "origin/canary_experimental" +CANARY_URL_DEFAULT = "https://github.com/xenia-canary/xenia-canary" # VMX (group=v) entries with these forms go under vmx128/; others under vmx/. VMX128_FORMS = { @@ -401,7 +416,7 @@ def _operand_block(family: Family) -> str: else: role_bits.append(f"{member.mnem}: write") role_summary = "; ".join(role_bits) or "—" - desc = FIELD_DESCRIPTIONS.get(name, "_Field-specific description pending — consult the xenia-rs interpreter body below for its actual usage._") + desc = FIELD_DESCRIPTIONS.get(name, "_Field-specific description pending — see how the Canary emitter below uses it._") rows.append(f"| `{name}` | {role_summary} | {desc} |") return "\n".join(rows) @@ -464,16 +479,12 @@ def _pseudocode_block(family: Family) -> str: if seed: return f"```\n{seed}\n```" return ("```\n" - "; Pseudocode derives directly from the xenia-rs interpreter\n" - "; arm (see Implementation References). Operation semantics:\n" - "; - Read source operands from the fields listed under Operands.\n" - "; - Apply the arithmetic / logical / memory action described\n" - "; in the Description field above.\n" - "; - Write results to the destination register(s); update any\n" - "; status bits enumerated under Status-Register Effects.\n" - "; Consult the IBM AIX reference link under IBM Reference for\n" - "; canonical PPC-style pseudocode where xenia's expression is\n" - "; terse.\n" + "; No hand-written pseudocode for this instruction yet.\n" + "; The authoritative semantics are the Canary emitter snapshot under\n" + "; Implementation References; about half of Canary's emitters open\n" + "; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`).\n" + "; Every side effect is also enumerated in the Register Effects and\n" + "; Status-Register Effects tables above.\n" "```") @@ -552,62 +563,60 @@ def _c_translation_block(family: Family) -> str: # translator at the authoritative source snapshot on this same # page. No TODO wording. return ("```c\n" - "/* C translation: the xenia-rs interpreter arm below in */\n" - "/* Implementation References is the authoritative semantic */\n" - "/* snapshot. Translate it line-by-line: */\n" - "/* - ctx.gpr[N] -> r[N] (or f[]/v[] for FPRs/VRs) */\n" - "/* - mem.read_u*/write_u* -> mem_read_u*_be / mem_write_u*_be */\n" - "/* - ctx.update_cr_signed(fld, v) -> update_cr_signed(fld, v) */\n" - "/* - ctx.xer_ca / xer_ov / xer_so -> xer.CA / xer.OV / xer.SO */\n" + "/* No hand-written C yet. Translate the Canary emitter snapshot */\n" + "/* under Implementation References; its HIR maps directly: */\n" + "/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */\n" + "/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */\n" + "/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */\n" + "/* wrap them in f.ByteSwap for the big-endian guest value */\n" + "/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */\n" + "/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */\n" + "/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */\n" "/* The Register Effects and Status-Register Effects tables above */\n" "/* enumerate every side effect a faithful translation must emit. */\n" "```") return f"```c\n{seed}\n```" -def _implementation_refs_block(family: Family, rust: RustScraper, cxx: CxxScraper) -> str: +def _implementation_refs_block(family: Family, dec: DecoderScraper, cxx: CxxScraper, + canary_url: str) -> str: + sha = cxx.canary.sha + blob = f"{canary_url}/blob/{sha}" lines = [] for member in family.members: cxx_ref = cxx.lookup(member.mnem) - rs_ref = rust.lookup(member.mnem) + dec_ref = dec.lookup(member.mnem) bullets = [f"**`{member.mnem}`**"] bullets.append( - f"- xenia-canary XML: " - f"[`tools/ppc-instructions.xml` — search for `mnem=\"{member.mnem}\"`]" - f"(../../xenia-canary/tools/ppc-instructions.xml)" + f"- Canary XML: [`{XML_PATH_IN_CANARY}` — search for `mnem=\"{member.mnem}\"`]" + f"({blob}/{XML_PATH_IN_CANARY})" ) if cxx_ref.emit_file and cxx_ref.emit_line: bullets.append( - f"- xenia-canary emit: [`{cxx_ref.emit_file}:{cxx_ref.emit_line}`]" - f"(../../xenia-canary/{cxx_ref.emit_file}#L{cxx_ref.emit_line})" + f"- Canary emitter: [`{cxx_ref.emit_file}:{cxx_ref.emit_line}`]" + f"({blob}/{cxx_ref.emit_file}#L{cxx_ref.emit_line})" ) - if rs_ref.opcode_line: + if dec_ref.opcode_line: bullets.append( - f"- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:{rs_ref.opcode_line}`]" - f"(../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L{rs_ref.opcode_line})" + f"- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:{dec_ref.opcode_line}`]" + f"({PAGE_TO_REPO}/crates/sylpheed-ppc/src/opcode.rs#L{dec_ref.opcode_line})" ) - if rs_ref.decoder_line: + if dec_ref.decoder_line: bullets.append( - f"- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:{rs_ref.decoder_line}`]" - f"(../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L{rs_ref.decoder_line})" + f"- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:{dec_ref.decoder_line}`]" + f"({PAGE_TO_REPO}/crates/sylpheed-ppc/src/decoder.rs#L{dec_ref.decoder_line})" ) - if rs_ref.interp_start and rs_ref.interp_end: + if cxx_ref.emit_body: bullets.append( - f"- xenia-rs interpreter: " - f"[`crates/xenia-cpu/src/interpreter.rs:{rs_ref.interp_start}-{rs_ref.interp_end}`]" - f"(../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L{rs_ref.interp_start}-L{rs_ref.interp_end})" - ) - if rs_ref.interp_body: - bullets.append( - "
xenia-rs interpreter body (frozen snapshot)\n\n" - "```rust\n" + rs_ref.interp_body.rstrip() + "\n```\n
" + f"
Canary emitter (frozen snapshot @ {sha[:10]})\n\n" + "```cpp\n" + cxx_ref.emit_body.rstrip() + "\n```\n
" ) lines.append("\n".join(bullets)) return "\n\n".join(lines) -def render_page(family: Family, rust: RustScraper, cxx: CxxScraper) -> str: +def render_page(family: Family, dec: DecoderScraper, cxx: CxxScraper, canary_url: str) -> str: primary = family.primary category_label, _ = CATEGORY_LABELS[family.category] title = family.head @@ -658,7 +667,7 @@ def render_page(family: Family, rust: RustScraper, cxx: CxxScraper) -> str: "", "## Implementation References", "", - _implementation_refs_block(family, rust, cxx), + _implementation_refs_block(family, dec, cxx, canary_url), "", GENERATED_END, ]) @@ -770,7 +779,7 @@ def build_index(families: dict[str, Family]) -> dict: # mnemonic (the primary) plus any runtime-expanded aliases. return { "version": "1.0", - "generator": "ppc-manual/generator/generate_manual.py", + "generator": "tools/ppc-manual/generator/generate_manual.py", "instruction_count": sum(1 for v in instructions.values() if v.get("is_primary")), "mnemonic_count": len(instructions), "family_count": len(families), @@ -892,9 +901,11 @@ def render_readme(families: dict[str, Family], insns: list[Instruction]) -> str: A reference for the **Xenon** PowerPC dialect used by the Xbox 360. Its primary audience is an AI agent translating PPC assembly functions into -equivalent C. The content is derived from the two authoritative sources in -this repository — **xenia-canary** (C++ emulator) and **xenia-rs** (Rust -rewrite) — and may be deepened with the IBM AIX PowerPC reference. +equivalent C. The content is derived from **Xenia Canary** — the reference +emulator: its instruction table and its PPC emitters, quoted at a pinned +upstream commit — and from Sylpheed's own decoder, `crates/sylpheed-ppc`, which +produces the disassembly in `sylpheed.db`. It may be deepened with the IBM AIX +PowerPC reference. - **{len(insns)}** distinct XML-level instructions (one page each). - **{len(families)}** instruction family pages (VMX128 siblings folded). @@ -924,7 +935,7 @@ Every instruction page has the same sections, in this order: | **Status-Register Effects** | CR0/CR1/CR6, XER[CA/OV/SO], FPSCR, VSCR updates. | | **Operation** | PPC-style pseudocode (`RT <- …`, `EXTS(…)`, `MEM(EA, n)`). | | **C Translation Example** | Minimal idiomatic C rendering a translator could emit. | -| **Implementation References** | Direct links into `xenia-canary/` and `xenia-rs/` with line numbers. | +| **Implementation References** | Canary's XML entry and emitter (linked at the pinned commit, with a frozen snapshot of the emitter), and Sylpheed's opcode/decoder lines. | | **Special Cases & Edge Conditions** | RA=0, alignment, endian byte-reverse, reservation, SPR remapping, VMX128 fusion. | | **Related Instructions** | Sibling cross-links. | | **IBM Reference** | Optional link to IBM AIX PPC reference for canonical pseudocode. | @@ -981,11 +992,27 @@ def main(): parser.add_argument("--dry-run", action="store_true", help="Parse + group only. Don't write any files. " "Exit non-zero if any consistency check fails.") - parser.add_argument("--xml", type=Path, default=XML_PATH, - help="Path to ppc-instructions.xml") + parser.add_argument("--canary", type=Path, default=CANARY_DEFAULT, + help="Xenia Canary git checkout (default: ../xenia-canary)") + parser.add_argument("--canary-ref", default=CANARY_REF_DEFAULT, + help="Canary commit to quote, read via git (default: origin/canary_experimental)") + parser.add_argument("--canary-url", default=CANARY_URL_DEFAULT, + help="Web base for Canary links (default: upstream GitHub)") + parser.add_argument("--xml", type=Path, default=None, + help="Override: read ppc-instructions.xml from this file instead of the pinned commit") args = parser.parse_args() - insns = load_instructions(args.xml) + canary = CanarySource(args.canary, args.canary_ref) + print(f"Canary: {args.canary_ref} @ {canary.sha[:10]}") + if args.xml is not None: + insns = load_instructions(args.xml) + else: + with tempfile.NamedTemporaryFile("w", suffix=".xml", delete=False) as tmp: + tmp.write(canary.read(XML_PATH_IN_CANARY)) + try: + insns = load_instructions(tmp.name) + finally: + Path(tmp.name).unlink(missing_ok=True) if len(insns) != 455: print(f"WARNING: expected 455 XML entries, found {len(insns)}", file=sys.stderr) @@ -1021,8 +1048,13 @@ def main(): if args.dry_run: return 0 - rust = RustScraper(REPO_ROOT) - cxx = CxxScraper(REPO_ROOT) + dec = DecoderScraper(REPO_ROOT) + cxx = CxxScraper(canary) + index["sources"] = { + "canary": {"url": args.canary_url, "ref": args.canary_ref, "commit": canary.sha, + "xml": XML_PATH_IN_CANARY, "emitters": len(cxx)}, + "decoder": "crates/sylpheed-ppc/src", + } out = args.out out.mkdir(parents=True, exist_ok=True) @@ -1035,7 +1067,7 @@ def main(): cat_dir = out / family.category cat_dir.mkdir(exist_ok=True) page_path = cat_dir / f"{_cxx_slug(family.head)}.md" - fresh = render_page(family, rust, cxx) + fresh = render_page(family, dec, cxx, args.canary_url) if page_path.exists(): existing = page_path.read_text(encoding="utf-8") merged = merge_preserving_handwritten(existing, fresh) diff --git a/tools/ppc-manual/generator/rust_scraper.py b/tools/ppc-manual/generator/rust_scraper.py deleted file mode 100644 index c71f0b7c..00000000 --- a/tools/ppc-manual/generator/rust_scraper.py +++ /dev/null @@ -1,184 +0,0 @@ -""" -Scrapes xenia-rs source files for per-instruction references and -snippets of the interpreter semantics. - -Outputs produced for each mnemonic: - - opcode_line: line in crates/xenia-cpu/src/opcode.rs where the - PpcOpcode variant is declared (1-indexed) - - decoder_line: line in crates/xenia-cpu/src/decoder.rs where the - variant is produced from raw bits - - interp_start: line in crates/xenia-cpu/src/interpreter.rs where - the match arm `PpcOpcode:: =>` begins - - interp_end: line where the arm closes (matching brace, naive) - - interp_body: raw text of the arm body (for reviewer reference) - -The xenia-rs opcode identifier often has trailing `x` preserved -(PpcOpcode::addx) — this scraper matches on the XML mnemonic directly -plus a stripped alternative without trailing 'x' and the xenia-style -identifier forms. -""" - -from __future__ import annotations - -from dataclasses import dataclass -from pathlib import Path -import re - - -@dataclass -class RustRef: - mnem: str - opcode_line: int | None = None - decoder_line: int | None = None - interp_start: int | None = None - interp_end: int | None = None - interp_body: str = "" - - -# PpcOpcode identifiers in xenia-rs match the XML mnemonic *exactly* except -# that '.' is illegal in Rust identifiers. Mnemonics ending in '.' appear as -# a trailing 'x' replacement in some cases but the codebase seems to keep the -# XML name verbatim (e.g. addic. → addicx OR addic_). Check the codebase. - - -def _rust_ident(mnem: str) -> str: - """Convert XML mnemonic to the xenia-rs PpcOpcode variant name.""" - # Xenia-rs uses the same name as xenia-canary's opcode enum, which - # mirrors ppc-instructions.xml directly. '.' is replaced with 'x' in - # the opcode enum (e.g. 'addic.' → 'addicx'), but the XML entry is - # already 'addic.'. We only need to handle that single case. - return mnem.replace(".", "x") - - -class RustScraper: - def __init__(self, repo_root: Path): - self.repo_root = repo_root - self.cpu_root = repo_root / "xenia-rs" / "crates" / "xenia-cpu" / "src" - self._opcode_lines = self._read_lines(self.cpu_root / "opcode.rs") - self._decoder_lines = self._read_lines(self.cpu_root / "decoder.rs") - self._interp_lines = self._read_lines(self.cpu_root / "interpreter.rs") - self._opcode_index: dict[str, int] = self._index_opcode_enum() - self._decoder_index: dict[str, int] = self._index_decoder() - self._interp_index: dict[str, tuple[int, int]] = self._index_interpreter() - - @staticmethod - def _read_lines(path: Path) -> list[str]: - if not path.is_file(): - return [] - return path.read_text(encoding="utf-8").splitlines() - - def _index_opcode_enum(self) -> dict[str, int]: - """Map rust-identifier → 1-indexed line in opcode.rs. The enum uses - comma-separated identifiers (often many per line) so we extract - every identifier match inside the enum body.""" - idx: dict[str, int] = {} - token = re.compile(r"\b([A-Za-z_][A-Za-z0-9_]*)\b") - in_enum = False - for i, line in enumerate(self._opcode_lines, start=1): - if "pub enum PpcOpcode" in line: - in_enum = True - continue - if not in_enum: - continue - if line.startswith("}"): - break - stripped = line.strip() - # skip blank / comment-only lines - if not stripped or stripped.startswith("//"): - continue - # split off any trailing line comment - code = stripped.split("//", 1)[0] - for m in token.finditer(code): - idx.setdefault(m.group(1), i) - return idx - - def _index_decoder(self) -> dict[str, int]: - """Map rust-identifier → 1-indexed line of its `PpcOpcode::` producer.""" - idx: dict[str, int] = {} - pat = re.compile(r"PpcOpcode::([A-Za-z_][A-Za-z0-9_]*)") - for i, line in enumerate(self._decoder_lines, start=1): - for m in pat.finditer(line): - name = m.group(1) - # keep the FIRST occurrence (the match-arm line where it's - # produced, not any later references) - idx.setdefault(name, i) - return idx - - def _index_interpreter(self) -> dict[str, tuple[int, int]]: - """Map rust-identifier → (start, end) lines of the match arm. - - An arm starts at `PpcOpcode::` and ends at the closing `}` - at the same indentation level. We accept multi-variant arms of - the form `PpcOpcode::a | PpcOpcode::b => {` by recording the same - (start, end) for every named variant. - """ - arm_header = re.compile(r"^(\s*)((?:PpcOpcode::[A-Za-z_][A-Za-z0-9_]*\s*\|\s*)*PpcOpcode::[A-Za-z_][A-Za-z0-9_]*)\s*=>\s*\{?\s*$") - # Some arms use no leading whitespace quirks — adjusted regex: - arm_header = re.compile( - r"^(\s*)" # indent - r"((?:PpcOpcode::[A-Za-z_][A-Za-z0-9_]*" # first variant - r"(?:\s*\|\s*PpcOpcode::[A-Za-z_][A-Za-z0-9_]*)*))" # more variants - r"\s*=>\s*\{?\s*$" - ) - var_re = re.compile(r"PpcOpcode::([A-Za-z_][A-Za-z0-9_]*)") - idx: dict[str, tuple[int, int]] = {} - i = 0 - n = len(self._interp_lines) - while i < n: - line = self._interp_lines[i] - m = arm_header.match(line) - if not m: - i += 1 - continue - indent = m.group(1) - names = var_re.findall(m.group(2)) - # Find the closing '}' at the same indentation. The arm body - # starts on line i (which ends with '{') and ends at a line - # whose content (after `indent`) is '}' (with optional trailing - # comma). - start = i + 1 # 1-indexed - end = start - j = i + 1 - depth = 1 if line.rstrip().endswith("{") else 0 - if depth == 0: - # Single-expression arm like `... => foo(),` — treat the line - # itself as start=end. - end = start - j = i + 1 - else: - while j < n: - l = self._interp_lines[j] - # A naive brace counter suffices for this codebase — the - # interpreter arms use balanced braces and no string - # literals containing stray braces. - depth += l.count("{") - l.count("}") - if depth == 0: - end = j + 1 # 1-indexed - break - j += 1 - for name in names: - idx.setdefault(name, (start, end)) - i = j + 1 - return idx - - def lookup(self, mnem: str) -> RustRef: - ident = _rust_ident(mnem) - ref = RustRef(mnem=mnem) - ref.opcode_line = self._opcode_index.get(ident) - ref.decoder_line = self._decoder_index.get(ident) - rng = self._interp_index.get(ident) - if rng: - ref.interp_start, ref.interp_end = rng - body = "\n".join(self._interp_lines[ref.interp_start - 1: ref.interp_end]) - ref.interp_body = body - return ref - - -if __name__ == "__main__": - root = Path(__file__).resolve().parent.parent.parent - s = RustScraper(root) - for m in ("addx", "addic.", "lwz", "bclrx", "mfspr", "stvx", "vaddfp", - "vaddfp128", "faddx", "lvsl"): - r = s.lookup(m) - print(f"{m:12s} opcode@{r.opcode_line} decoder@{r.decoder_line} " - f"interp@{r.interp_start}-{r.interp_end}") diff --git a/tools/ppc-manual/index.json b/tools/ppc-manual/index.json index f6c9f02e..058b9e27 100644 --- a/tools/ppc-manual/index.json +++ b/tools/ppc-manual/index.json @@ -1,6 +1,6 @@ { "version": "1.0", - "generator": "ppc-manual/generator/generate_manual.py", + "generator": "tools/ppc-manual/generator/generate_manual.py", "instruction_count": 455, "mnemonic_count": 598, "family_count": 350, @@ -19124,5 +19124,15 @@ "is_primary": true, "flags": {} } + }, + "sources": { + "canary": { + "url": "https://github.com/xenia-canary/xenia-canary", + "ref": "origin/canary_experimental", + "commit": "f21ebd49e979e44f081f474df78c3fbfee9cb3f2", + "xml": "tools/ppc-instructions.xml", + "emitters": 522 + }, + "decoder": "crates/sylpheed-ppc/src" } } diff --git a/tools/ppc-manual/memory/dcbf.md b/tools/ppc-manual/memory/dcbf.md index c863c03c..9c3a8771 100644 --- a/tools/ppc-manual/memory/dcbf.md +++ b/tools/ppc-manual/memory/dcbf.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,10 +84,23 @@ _No condition-register or status-register effects._ ## Implementation References **`dcbf`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbf"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1125`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1125) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:19`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L19) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:773`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L773) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbf"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1125`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1125) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:44`](../../../crates/sylpheed-ppc/src/opcode.rs#L44) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:888`](../../../crates/sylpheed-ppc/src/decoder.rs#L888) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_dcbf(PPCHIRBuilder& f, const InstrData& i) { + if (!cvars::disable_prefetch_and_cachecontrol) { + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.CacheControl(ea, 128, + CacheControlType::CACHE_CONTROL_TYPE_DATA_STORE_AND_FLUSH); + } + return 0; +} +``` +
diff --git a/tools/ppc-manual/memory/dcbi.md b/tools/ppc-manual/memory/dcbi.md index e59abc65..27fdb478 100644 --- a/tools/ppc-manual/memory/dcbi.md +++ b/tools/ppc-manual/memory/dcbi.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,9 +84,9 @@ _No condition-register or status-register effects._ ## Implementation References **`dcbi`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbi"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:19`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L19) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:811`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L811) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbi"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:45`](../../../crates/sylpheed-ppc/src/opcode.rs#L45) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:926`](../../../crates/sylpheed-ppc/src/decoder.rs#L926) diff --git a/tools/ppc-manual/memory/dcbst.md b/tools/ppc-manual/memory/dcbst.md index 05126a81..2025d859 100644 --- a/tools/ppc-manual/memory/dcbst.md +++ b/tools/ppc-manual/memory/dcbst.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,10 +84,22 @@ _No condition-register or status-register effects._ ## Implementation References **`dcbst`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbst"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1134`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1134) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:19`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L19) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:765`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L765) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbst"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1134`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1134) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:46`](../../../crates/sylpheed-ppc/src/opcode.rs#L46) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:880`](../../../crates/sylpheed-ppc/src/decoder.rs#L880) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_dcbst(PPCHIRBuilder& f, const InstrData& i) { + if (!cvars::disable_prefetch_and_cachecontrol) { + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.CacheControl(ea, 128, CacheControlType::CACHE_CONTROL_TYPE_DATA_STORE); + } + return 0; +} +``` +
diff --git a/tools/ppc-manual/memory/dcbt.md b/tools/ppc-manual/memory/dcbt.md index d3085dfe..221d4eba 100644 --- a/tools/ppc-manual/memory/dcbt.md +++ b/tools/ppc-manual/memory/dcbt.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,10 +84,22 @@ _No condition-register or status-register effects._ ## Implementation References **`dcbt`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbt"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1142`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1142) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:19`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L19) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:794`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L794) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbt"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1142`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1142) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:47`](../../../crates/sylpheed-ppc/src/opcode.rs#L47) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:909`](../../../crates/sylpheed-ppc/src/decoder.rs#L909) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_dcbt(PPCHIRBuilder& f, const InstrData& i) { + if (!cvars::disable_prefetch_and_cachecontrol) { + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.CacheControl(ea, 128, CacheControlType::CACHE_CONTROL_TYPE_DATA_TOUCH); + } + return 0; +} +``` +
diff --git a/tools/ppc-manual/memory/dcbtst.md b/tools/ppc-manual/memory/dcbtst.md index 92e1e464..9f4aab97 100644 --- a/tools/ppc-manual/memory/dcbtst.md +++ b/tools/ppc-manual/memory/dcbtst.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,10 +84,23 @@ _No condition-register or status-register effects._ ## Implementation References **`dcbtst`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbtst"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1150`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1150) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:19`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L19) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:792`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L792) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbtst"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1150`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1150) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:48`](../../../crates/sylpheed-ppc/src/opcode.rs#L48) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:907`](../../../crates/sylpheed-ppc/src/decoder.rs#L907) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_dcbtst(PPCHIRBuilder& f, const InstrData& i) { + if (!cvars::disable_prefetch_and_cachecontrol) { + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.CacheControl(ea, 128, + CacheControlType::CACHE_CONTROL_TYPE_DATA_TOUCH_FOR_STORE); + } + return 0; +} +``` +
diff --git a/tools/ppc-manual/memory/dcbz.md b/tools/ppc-manual/memory/dcbz.md index c879da6e..c5b38b38 100644 --- a/tools/ppc-manual/memory/dcbz.md +++ b/tools/ppc-manual/memory/dcbz.md @@ -82,28 +82,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -111,50 +109,55 @@ _No condition-register or status-register effects._ ## Implementation References **`dcbz`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbz"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1159`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1159) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:19`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L19) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:886`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L886) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1694-1705`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1694-L1705) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbz"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1171`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1171) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:49`](../../../crates/sylpheed-ppc/src/opcode.rs#L49) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1001`](../../../crates/sylpheed-ppc/src/decoder.rs#L1001) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::dcbz => { - // Zero 32 bytes at effective address - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = (ea.wrapping_add(ctx.gpr[instr.rb()]) as u32) & !31; - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { t.invalidate_for_write(ea); } - } - for i in 0..8 { - mem.write_u32(ea + i * 4, 0); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_dcbz(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // memset(EA & ~31, 0, 32) + // On Xbox360 there is no short cache line. Normal dcbz always clears 128 + // bytes. + return InstrEmit_dcbz128(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_memory.cc:1159) ── +int InstrEmit_dcbz128(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // memset(EA & ~31, 0, 32) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + // dcbz128 - 128 byte set + int block_size = 128; + int address_mask = ~127; + f.Memset(f.And(ea, f.LoadConstantInt64(address_mask)), f.LoadZeroInt8(), + f.LoadConstantInt64(block_size)); + return 0; +} ```
**`dcbz128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbz128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1171`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1171) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:19`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L19) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:887`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L887) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1706-1717`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1706-L1717) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="dcbz128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1159`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1159) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:50`](../../../crates/sylpheed-ppc/src/opcode.rs#L50) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:1002`](../../../crates/sylpheed-ppc/src/decoder.rs#L1002) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::dcbz128 => { - // Zero 128 bytes - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = (ea.wrapping_add(ctx.gpr[instr.rb()]) as u32) & !127; - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { t.invalidate_for_write(ea); } - } - for i in 0..32 { - mem.write_u32(ea + i * 4, 0); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_dcbz128(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // memset(EA & ~31, 0, 32) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + // dcbz128 - 128 byte set + int block_size = 128; + int address_mask = ~127; + f.Memset(f.And(ea, f.LoadConstantInt64(address_mask)), f.LoadZeroInt8(), + f.LoadConstantInt64(block_size)); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/icbi.md b/tools/ppc-manual/memory/icbi.md index eb8105b3..096368cd 100644 --- a/tools/ppc-manual/memory/icbi.md +++ b/tools/ppc-manual/memory/icbi.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,10 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`icbi`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="icbi"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1183`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1183) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:32`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L32) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:850`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L850) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="icbi"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1179`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1179) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:98`](../../../crates/sylpheed-ppc/src/opcode.rs#L98) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:965`](../../../crates/sylpheed-ppc/src/decoder.rs#L965) +
Canary emitter (frozen snapshot @ f21ebd49e9) + +```cpp +int InstrEmit_icbi(PPCHIRBuilder& f, const InstrData& i) { + // XEINSTRNOTIMPLEMENTED(); + f.Nop(); + return 0; +} +``` +
diff --git a/tools/ppc-manual/memory/lbz.md b/tools/ppc-manual/memory/lbz.md index 1242cb67..912f28f8 100644 --- a/tools/ppc-manual/memory/lbz.md +++ b/tools/ppc-manual/memory/lbz.md @@ -138,13 +138,15 @@ RT <- 0x00000000_000000_00 || MEM(EA, 1) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -152,74 +154,98 @@ RT <- 0x00000000_000000_00 || MEM(EA, 1) ## Implementation References **`lbz`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lbz"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:72`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L72) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:34`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L34) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:357`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L357) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1024-1029`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1024-L1029) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lbz"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:72`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L72) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:101`](../../../crates/sylpheed-ppc/src/opcode.rs#L101) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:472`](../../../crates/sylpheed-ppc/src/decoder.rs#L472) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lbz => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u8(ea) as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lbz(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // RT <- i56.0 || MEM(EA, 1) + Value* b; + if (i.D.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.D.RA); + } + + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + Value* rt = f.ZeroExtend(f.LoadOffset(b, offset, INT8_TYPE), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + return 0; +} ```
**`lbzu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lbzu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:92`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L92) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:34`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L34) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:358`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L358) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1030-1035`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1030-L1035) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lbzu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:92`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L92) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:102`](../../../crates/sylpheed-ppc/src/opcode.rs#L102) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:473`](../../../crates/sylpheed-ppc/src/decoder.rs#L473) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lbzu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u8(ea) as u64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lbzu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // RT <- i56.0 || MEM(EA, 1) + // RA <- EA + Value* ra = f.LoadGPR(i.D.RA); + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + Value* rt = f.ZeroExtend(f.LoadOffset(ra, offset, INT8_TYPE), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + StoreEA(f, i.D.RA, f.Add(ra, offset)); + return 0; +} ```
**`lbzux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lbzux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:104`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L104) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:34`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L34) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:776`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L776) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1042-1047`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1042-L1047) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lbzux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:104`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L104) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:103`](../../../crates/sylpheed-ppc/src/opcode.rs#L103) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:891`](../../../crates/sylpheed-ppc/src/decoder.rs#L891) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lbzux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u8(ea) as u64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lbzux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // RT <- i56.0 || MEM(EA, 1) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + Value* rt = f.ZeroExtend(f.Load(ea, INT8_TYPE), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`lbzx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lbzx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:115`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L115) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:34`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L34) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:774`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L774) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1036-1041`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1036-L1041) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lbzx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:115`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L115) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:104`](../../../crates/sylpheed-ppc/src/opcode.rs#L104) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:889`](../../../crates/sylpheed-ppc/src/decoder.rs#L889) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lbzx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u8(ea) as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lbzx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i56.0 || MEM(EA, 1) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.ZeroExtend(f.Load(ea, INT8_TYPE), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/ld.md b/tools/ppc-manual/memory/ld.md index 129e7e0b..c844f060 100644 --- a/tools/ppc-manual/memory/ld.md +++ b/tools/ppc-manual/memory/ld.md @@ -140,13 +140,15 @@ RT <- MEM(EA, 8) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -154,74 +156,97 @@ RT <- MEM(EA, 8) ## Implementation References **`ld`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ld"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:347`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L347) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:36`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L36) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:380`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L380) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1096-1101`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1096-L1101) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ld"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:347`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L347) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:106`](../../../crates/sylpheed-ppc/src/opcode.rs#L106) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:495`](../../../crates/sylpheed-ppc/src/decoder.rs#L495) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::ld => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.ds() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u64(ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_ld(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(DS || 0b00) + // RT <- MEM(EA, 8) + Value* b; + if (i.DS.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.DS.RA); + } + + Value* offset = f.LoadConstantInt64(XEEXTS16(i.DS.DS << 2)); + Value* rt = f.ByteSwap(f.LoadOffset(b, offset, INT64_TYPE)); + f.StoreGPR(i.DS.RT, rt); + return 0; +} ```
**`ldu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ldu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:367`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L367) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:36`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L36) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:381`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L381) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1126-1131`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1126-L1131) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ldu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:367`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L367) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:109`](../../../crates/sylpheed-ppc/src/opcode.rs#L109) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:496`](../../../crates/sylpheed-ppc/src/decoder.rs#L496) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::ldu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.ds() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u64(ea); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_ldu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(DS || 0b00) + // RT <- MEM(EA, 8) + // RA <- EA + Value* ea = CalculateEA_i(f, i.DS.RA, XEEXTS16(i.DS.DS << 2)); + Value* rt = f.ByteSwap(f.Load(ea, INT64_TYPE)); + f.StoreGPR(i.DS.RT, rt); + StoreEA(f, i.DS.RA, ea); + return 0; +} ```
**`ldux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ldux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:378`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L378) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:36`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L36) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:764`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L764) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1132-1137`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1132-L1137) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ldux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:378`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L378) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:110`](../../../crates/sylpheed-ppc/src/opcode.rs#L110) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:879`](../../../crates/sylpheed-ppc/src/decoder.rs#L879) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::ldux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u64(ea); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_ldux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // RT <- MEM(EA, 8) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + Value* rt = f.ByteSwap(f.Load(ea, INT64_TYPE)); + f.StoreGPR(i.X.RT, rt); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`ldx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ldx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:389`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L389) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:36`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L36) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:755`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L755) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1102-1107`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1102-L1107) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ldx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:389`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L389) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:111`](../../../crates/sylpheed-ppc/src/opcode.rs#L111) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:870`](../../../crates/sylpheed-ppc/src/decoder.rs#L870) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::ldx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u64(ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_ldx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- MEM(EA, 8) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.ByteSwap(f.Load(ea, INT64_TYPE)); + f.StoreGPR(i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/ldarx.md b/tools/ppc-manual/memory/ldarx.md index f70716a5..f05c61e9 100644 --- a/tools/ppc-manual/memory/ldarx.md +++ b/tools/ppc-manual/memory/ldarx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,29 +85,42 @@ _No condition-register or status-register effects._ ## Implementation References **`ldarx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ldarx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:765`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L765) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:36`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L36) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:772`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L772) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4559-4573`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4559-L4573) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ldarx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:765`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L765) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:107`](../../../crates/sylpheed-ppc/src/opcode.rs#L107) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:887`](../../../crates/sylpheed-ppc/src/decoder.rs#L887) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::ldarx => { - let ea = ea_indexed(ctx, instr); - let val = mem.read_u64(ea); - ctx.gpr[instr.rd()] = val; - ctx.reserved_line = ea & !RESERVATION_MASK; - ctx.reserved_val = val; - ctx.has_reservation = true; - ctx.reservation_width = 8; // PPCBUG-151: doubleword reservation - if let Some(t) = &ctx.reservation_table { - if t.is_enabled() { - ctx.reserved_generation = t.reserve(ea, ctx.hw_id); - } - } - ctx.pc += 4; - } +```cpp +int InstrEmit_ldarx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RESERVE <- 1 + // RESERVE_LENGTH <- 8 + // RESERVE_ADDR <- real_addr(EA) + // RT <- MEM(EA, 8) + + // NOTE: we assume we are within a global lock. + // We could assert here that the block (or its parent) has taken a global lock + // already, but I haven't see anything but interrupt callbacks (which are + // always under a global lock) do that yet. + // We issue a memory barrier here to make sure that we get good values. + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + + if (cvars::no_reserved_ops) { + f.StoreGPR(i.X.RT, f.ByteSwap(f.Load(ea, INT64_TYPE))); + + } else { + f.MemoryBarrier(); + + Value* rt = f.ByteSwap(f.LoadWithReserve(ea, INT64_TYPE)); + f.StoreGPR(i.X.RT, rt); + } + return 0; +} ```
diff --git a/tools/ppc-manual/memory/ldbrx.md b/tools/ppc-manual/memory/ldbrx.md index 6c88dfc1..ae72bc02 100644 --- a/tools/ppc-manual/memory/ldbrx.md +++ b/tools/ppc-manual/memory/ldbrx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,19 +85,25 @@ _No condition-register or status-register effects._ ## Implementation References **`ldbrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ldbrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:654`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L654) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:36`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L36) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:816`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L816) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4627-4631`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4627-L4631) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="ldbrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:654`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L654) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:108`](../../../crates/sylpheed-ppc/src/opcode.rs#L108) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:931`](../../../crates/sylpheed-ppc/src/decoder.rs#L931) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::ldbrx => { - let ea = ea_indexed(ctx, instr); - ctx.gpr[instr.rd()] = mem.read_u64(ea).swap_bytes(); - ctx.pc += 4; - } +```cpp +int InstrEmit_ldbrx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- bswap(MEM(EA, 8)) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.Load(ea, INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lfd.md b/tools/ppc-manual/memory/lfd.md index e6a87b1a..85d83587 100644 --- a/tools/ppc-manual/memory/lfd.md +++ b/tools/ppc-manual/memory/lfd.md @@ -138,13 +138,15 @@ FRT <- MEM(EA, 8) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -152,74 +154,90 @@ FRT <- MEM(EA, 8) ## Implementation References **`lfd`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfd"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:912`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L912) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:38`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L38) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:373`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L373) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1152-1157`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1152-L1157) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfd"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:912`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L912) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:113`](../../../crates/sylpheed-ppc/src/opcode.rs#L113) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:488`](../../../crates/sylpheed-ppc/src/decoder.rs#L488) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lfd => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - ctx.fpr[instr.rd()] = mem.read_f64(ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_lfd(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // FRT <- MEM(EA, 8) + Value* ea = CalculateEA_0_i(f, i.D.RA, XEEXTS16(i.D.DS)); + Value* rt = f.Cast(f.ByteSwap(f.Load(ea, INT64_TYPE)), FLOAT64_TYPE); + f.StoreFPR(i.D.RT, rt); + return 0; +} ```
**`lfdu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfdu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:925`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L925) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:38`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L38) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:374`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L374) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1176-1181`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1176-L1181) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfdu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:925`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L925) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:114`](../../../crates/sylpheed-ppc/src/opcode.rs#L114) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:489`](../../../crates/sylpheed-ppc/src/decoder.rs#L489) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lfdu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - ctx.fpr[instr.rd()] = mem.read_f64(ea); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lfdu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // FRT <- MEM(EA, 8) + // RA <- EA + Value* ea = CalculateEA_i(f, i.D.RA, XEEXTS16(i.D.DS)); + Value* rt = f.Cast(f.ByteSwap(f.Load(ea, INT64_TYPE)), FLOAT64_TYPE); + f.StoreFPR(i.D.RT, rt); + StoreEA(f, i.D.RA, ea); + return 0; +} ```
**`lfdux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfdux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:936`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L936) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:38`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L38) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:827`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L827) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1182-1187`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1182-L1187) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfdux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:936`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L936) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:115`](../../../crates/sylpheed-ppc/src/opcode.rs#L115) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:942`](../../../crates/sylpheed-ppc/src/decoder.rs#L942) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lfdux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.fpr[instr.rd()] = mem.read_f64(ea); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lfdux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // FRT <- MEM(EA, 8) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + Value* rt = f.Cast(f.ByteSwap(f.Load(ea, INT64_TYPE)), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, rt); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`lfdx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfdx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:947`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L947) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:38`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L38) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:826`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L826) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1158-1163`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1158-L1163) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfdx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:947`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L947) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:116`](../../../crates/sylpheed-ppc/src/opcode.rs#L116) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:941`](../../../crates/sylpheed-ppc/src/decoder.rs#L941) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lfdx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.fpr[instr.rd()] = mem.read_f64(ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_lfdx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // FRT <- MEM(EA, 8) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.Cast(f.ByteSwap(f.Load(ea, INT64_TYPE)), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lfs.md b/tools/ppc-manual/memory/lfs.md index e021a314..5d72ff10 100644 --- a/tools/ppc-manual/memory/lfs.md +++ b/tools/ppc-manual/memory/lfs.md @@ -138,13 +138,15 @@ FRT <- DoubleFromSingle(MEM(EA, 4)) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -152,74 +154,94 @@ FRT <- DoubleFromSingle(MEM(EA, 4)) ## Implementation References **`lfs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:960`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L960) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:38`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L38) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:371`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L371) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1140-1145`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1140-L1145) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:960`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L960) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:117`](../../../crates/sylpheed-ppc/src/opcode.rs#L117) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:486`](../../../crates/sylpheed-ppc/src/decoder.rs#L486) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lfs => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - ctx.fpr[instr.rd()] = mem.read_f32(ea) as f64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lfs(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // FRT <- DOUBLE(MEM(EA, 4)) + Value* ea = CalculateEA_0_i(f, i.D.RA, XEEXTS16(i.D.DS)); + Value* rt = f.Convert( + f.Cast(f.ByteSwap(f.Load(ea, INT32_TYPE)), FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.D.RT, rt); + return 0; +} ```
**`lfsu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfsu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:974`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L974) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:38`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L38) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:372`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L372) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1164-1169`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1164-L1169) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfsu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:974`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L974) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:118`](../../../crates/sylpheed-ppc/src/opcode.rs#L118) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:487`](../../../crates/sylpheed-ppc/src/decoder.rs#L487) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lfsu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - ctx.fpr[instr.rd()] = mem.read_f32(ea) as f64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lfsu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // FRT <- DOUBLE(MEM(EA, 4)) + // RA <- EA + Value* ea = CalculateEA_i(f, i.D.RA, XEEXTS16(i.D.DS)); + Value* rt = f.Convert( + f.Cast(f.ByteSwap(f.Load(ea, INT32_TYPE)), FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.D.RT, rt); + StoreEA(f, i.D.RA, ea); + return 0; +} ```
**`lfsux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfsux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:986`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L986) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:38`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L38) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:823`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L823) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1170-1175`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1170-L1175) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfsux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:986`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L986) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:119`](../../../crates/sylpheed-ppc/src/opcode.rs#L119) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:938`](../../../crates/sylpheed-ppc/src/decoder.rs#L938) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lfsux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.fpr[instr.rd()] = mem.read_f32(ea) as f64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lfsux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // FRT <- DOUBLE(MEM(EA, 4)) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + Value* rt = f.Convert( + f.Cast(f.ByteSwap(f.Load(ea, INT32_TYPE)), FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, rt); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`lfsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:998`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L998) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:38`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L38) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:819`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L819) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1146-1151`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1146-L1151) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lfsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:998`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L998) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:120`](../../../crates/sylpheed-ppc/src/opcode.rs#L120) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:934`](../../../crates/sylpheed-ppc/src/decoder.rs#L934) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lfsx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.fpr[instr.rd()] = mem.read_f32(ea) as f64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lfsx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // FRT <- DOUBLE(MEM(EA, 4)) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.Convert( + f.Cast(f.ByteSwap(f.Load(ea, INT32_TYPE)), FLOAT32_TYPE), FLOAT64_TYPE); + f.StoreFPR(i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lha.md b/tools/ppc-manual/memory/lha.md index 52c20d66..cd816217 100644 --- a/tools/ppc-manual/memory/lha.md +++ b/tools/ppc-manual/memory/lha.md @@ -138,13 +138,15 @@ RT <- SEXT16_to_64(MEM(EA, 2)) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -152,74 +154,100 @@ RT <- SEXT16_to_64(MEM(EA, 2)) ## Implementation References **`lha`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lha"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:128`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L128) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:40`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L40) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:365`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L365) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1066-1071`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1066-L1071) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lha"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:128`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L128) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:122`](../../../crates/sylpheed-ppc/src/opcode.rs#L122) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:480`](../../../crates/sylpheed-ppc/src/decoder.rs#L480) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lha => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u16(ea) as i16 as i32 as u32 as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lha(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // RT <- EXTS(MEM(EA, 2)) + Value* b; + if (i.D.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.D.RA); + } + + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + Value* rt = + f.SignExtend(f.ByteSwap(f.LoadOffset(b, offset, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + return 0; +} ```
**`lhau`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhau"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:149`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L149) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:40`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L40) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:366`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L366) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1084-1089`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1084-L1089) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhau"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:149`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L149) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:123`](../../../crates/sylpheed-ppc/src/opcode.rs#L123) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:481`](../../../crates/sylpheed-ppc/src/decoder.rs#L481) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lhau => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u16(ea) as i16 as i32 as u32 as u64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lhau(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // RT <- EXTS(MEM(EA, 2)) + // RA <- EA + Value* ra = f.LoadGPR(i.D.RA); + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + Value* rt = f.SignExtend(f.ByteSwap(f.LoadOffset(ra, offset, INT16_TYPE)), + INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + StoreEA(f, i.D.RA, f.Add(ra, offset)); + return 0; +} ```
**`lhaux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhaux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:162`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L162) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:40`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L40) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:805`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L805) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1090-1095`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1090-L1095) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhaux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:162`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L162) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:124`](../../../crates/sylpheed-ppc/src/opcode.rs#L124) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:920`](../../../crates/sylpheed-ppc/src/decoder.rs#L920) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lhaux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u16(ea) as i16 as i32 as u32 as u64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lhaux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // RT <- EXTS(MEM(EA, 2)) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + Value* rt = f.SignExtend(f.ByteSwap(f.Load(ea, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`lhax`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhax"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:173`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L173) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:40`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L40) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:801`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L801) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1072-1077`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1072-L1077) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhax"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:173`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L173) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:125`](../../../crates/sylpheed-ppc/src/opcode.rs#L125) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:916`](../../../crates/sylpheed-ppc/src/decoder.rs#L916) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lhax => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u16(ea) as i16 as i32 as u32 as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lhax(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- EXTS(MEM(EA, 2)) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.SignExtend(f.ByteSwap(f.Load(ea, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lhbrx.md b/tools/ppc-manual/memory/lhbrx.md index 433c083c..41e5b7a5 100644 --- a/tools/ppc-manual/memory/lhbrx.md +++ b/tools/ppc-manual/memory/lhbrx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,21 +85,25 @@ _No condition-register or status-register effects._ ## Implementation References **`lhbrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhbrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:628`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L628) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:40`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L40) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:839`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L839) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1806-1812`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1806-L1812) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhbrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:628`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L628) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:126`](../../../crates/sylpheed-ppc/src/opcode.rs#L126) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:954`](../../../crates/sylpheed-ppc/src/decoder.rs#L954) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lhbrx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - let val = mem.read_u16(ea); - ctx.gpr[instr.rd()] = val.swap_bytes() as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lhbrx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i48.0 || bswap(MEM(EA, 2)) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.ZeroExtend(f.Load(ea, INT16_TYPE), INT64_TYPE); + StoreEA(f, i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lhz.md b/tools/ppc-manual/memory/lhz.md index f21537e2..29a70fb8 100644 --- a/tools/ppc-manual/memory/lhz.md +++ b/tools/ppc-manual/memory/lhz.md @@ -138,13 +138,15 @@ RT <- ZEXT16_to_64(MEM(EA, 2)) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -152,74 +154,100 @@ RT <- ZEXT16_to_64(MEM(EA, 2)) ## Implementation References **`lhz`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhz"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:186`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L186) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:40`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L40) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:363`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L363) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1048-1053`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1048-L1053) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhz"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:186`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L186) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:127`](../../../crates/sylpheed-ppc/src/opcode.rs#L127) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:478`](../../../crates/sylpheed-ppc/src/decoder.rs#L478) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lhz => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u16(ea) as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lhz(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // RT <- i48.0 || MEM(EA, 2) + Value* b; + if (i.D.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.D.RA); + } + + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + Value* rt = + f.ZeroExtend(f.ByteSwap(f.LoadOffset(b, offset, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + return 0; +} ```
**`lhzu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhzu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:207`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L207) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:40`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L40) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:364`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L364) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1054-1059`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1054-L1059) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhzu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:207`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L207) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:128`](../../../crates/sylpheed-ppc/src/opcode.rs#L128) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:479`](../../../crates/sylpheed-ppc/src/decoder.rs#L479) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lhzu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u16(ea) as u64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lhzu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // RT <- i48.0 || MEM(EA, 2) + // RA <- EA + Value* ra = f.LoadGPR(i.D.RA); + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + Value* rt = f.ZeroExtend(f.ByteSwap(f.LoadOffset(ra, offset, INT16_TYPE)), + INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + StoreEA(f, i.D.RA, f.Add(ra, offset)); + return 0; +} ```
**`lhzux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhzux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:220`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L220) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:40`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L40) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:797`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L797) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1078-1083`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1078-L1083) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhzux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:220`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L220) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:129`](../../../crates/sylpheed-ppc/src/opcode.rs#L129) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:912`](../../../crates/sylpheed-ppc/src/decoder.rs#L912) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lhzux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u16(ea) as u64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lhzux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // RT <- i48.0 || MEM(EA, 2) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`lhzx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhzx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:231`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L231) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:40`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L40) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:795`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L795) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1060-1065`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1060-L1065) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lhzx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:231`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L231) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:130`](../../../crates/sylpheed-ppc/src/opcode.rs#L130) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:910`](../../../crates/sylpheed-ppc/src/decoder.rs#L910) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lhzx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u16(ea) as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lhzx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i48.0 || MEM(EA, 2) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT16_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lmw.md b/tools/ppc-manual/memory/lmw.md index b19cb3e0..50bc7abd 100644 --- a/tools/ppc-manual/memory/lmw.md +++ b/tools/ppc-manual/memory/lmw.md @@ -53,28 +53,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -82,29 +80,32 @@ _No condition-register or status-register effects._ ## Implementation References **`lmw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lmw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:705`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L705) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:42`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L42) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:369`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L369) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1720-1734`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1720-L1734) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lmw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:705`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L705) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:132`](../../../crates/sylpheed-ppc/src/opcode.rs#L132) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:484`](../../../crates/sylpheed-ppc/src/decoder.rs#L484) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lmw => { - // PPCBUG-125: PowerISA marks `lmw` invalid when rA is in [rT..31]; - // canary skips the write to rA in that case to preserve the EA base. - let mut ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - ea = ea.wrapping_add(instr.d() as i64 as u64); - for r in instr.rd()..32 { - if r == instr.ra() { - ea = ea.wrapping_add(4); - continue; - } - ctx.gpr[r] = mem.read_u32(ea as u32) as u64; - ea = ea.wrapping_add(4); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_lmw(PPCHIRBuilder& f, const InstrData& i) { + Value* b; + if (i.D.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.D.RA); + } + + for (uint32_t j = 0; j < 32 - i.D.RT; ++j) { + if (i.D.RT + j == i.D.RA) { + continue; + } + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS) + j * 4); + Value* rt = f.ZeroExtend(f.ByteSwap(f.LoadOffset(b, offset, INT32_TYPE)), + INT64_TYPE); + f.StoreGPR(i.D.RT + j, rt); + } + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lswi.md b/tools/ppc-manual/memory/lswi.md index 2e29c225..a08d6202 100644 --- a/tools/ppc-manual/memory/lswi.md +++ b/tools/ppc-manual/memory/lswi.md @@ -55,28 +55,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,33 +82,17 @@ _No condition-register or status-register effects._ ## Implementation References **`lswi`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lswi"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:727`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L727) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:42`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L42) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:824`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L824) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1521-1539`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1521-L1539) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lswi"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:727`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L727) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:133`](../../../crates/sylpheed-ppc/src/opcode.rs#L133) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:939`](../../../crates/sylpheed-ppc/src/decoder.rs#L939) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lswi => { - let mut ea = if instr.ra() == 0 { 0u32 } else { ctx.gpr[instr.ra()] as u32 }; - let nb = if instr.nb() == 0 { 32 } else { instr.nb() }; - let mut rd = instr.rd(); - let mut bytes_left = nb; - while bytes_left > 0 { - let mut val = 0u32; - for byte_idx in 0..4 { - if bytes_left == 0 { break; } - let b = mem.read_u8(ea) as u32; - val |= b << (24 - byte_idx * 8); - ea = ea.wrapping_add(1); - bytes_left -= 1; - } - ctx.gpr[rd] = val as u64; - rd = (rd + 1) % 32; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_lswi(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/memory/lswx.md b/tools/ppc-manual/memory/lswx.md index f51e6cc7..38f1ac3a 100644 --- a/tools/ppc-manual/memory/lswx.md +++ b/tools/ppc-manual/memory/lswx.md @@ -55,28 +55,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,33 +82,17 @@ _No condition-register or status-register effects._ ## Implementation References **`lswx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lswx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:732`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L732) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:42`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L42) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:817`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L817) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4644-4662`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4644-L4662) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lswx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:732`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L732) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:134`](../../../crates/sylpheed-ppc/src/opcode.rs#L134) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:932`](../../../crates/sylpheed-ppc/src/decoder.rs#L932) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lswx => { - let mut ea = ea_indexed(ctx, instr); - let nb = ctx.xer() & 0x7F; // XER[25..31] - let mut rd = instr.rd(); - let mut bytes_left = nb; - while bytes_left > 0 { - let mut val = 0u32; - for byte_idx in 0..4 { - if bytes_left == 0 { break; } - let b = mem.read_u8(ea) as u32; - val |= b << (24 - byte_idx * 8); - ea = ea.wrapping_add(1); - bytes_left -= 1; - } - ctx.gpr[rd] = val as u64; - rd = (rd + 1) % 32; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_lswx(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/memory/lvebx.md b/tools/ppc-manual/memory/lvebx.md index 711cd161..cd2e3028 100644 --- a/tools/ppc-manual/memory/lvebx.md +++ b/tools/ppc-manual/memory/lvebx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,20 @@ _No condition-register or status-register effects._ ## Implementation References **`lvebx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvebx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:73`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L73) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:44`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L44) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:752`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L752) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1872-1883`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1872-L1883) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvebx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:73`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L73) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:136`](../../../crates/sylpheed-ppc/src/opcode.rs#L136) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:867`](../../../crates/sylpheed-ppc/src/decoder.rs#L867) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvebx => { - // Load 1 byte from EA into vD[EA & 0xF]. PowerISA marks the - // other lanes as "undefined" but real Xenon (and Canary) - // preserve their prior contents, so seed from vD. - let base = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = base.wrapping_add(ctx.gpr[instr.rb()]) as u32; - let slot = (ea & 0xF) as usize; - let mut bytes = ctx.vr[instr.rd()].as_bytes(); - bytes[slot] = mem.read_u8(ea); - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(bytes); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvebx(PPCHIRBuilder& f, const InstrData& i) { + // Same as lvx. + Value* ea = + f.And(CalculateEA_0(f, i.X.RA, i.X.RB), f.LoadConstantUint64(~0xFull)); + f.StoreVR(i.X.RT, f.ByteSwap(f.Load(ea, VEC128_TYPE))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lvehx.md b/tools/ppc-manual/memory/lvehx.md index e24cc817..b3c63251 100644 --- a/tools/ppc-manual/memory/lvehx.md +++ b/tools/ppc-manual/memory/lvehx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,28 +85,20 @@ _No condition-register or status-register effects._ ## Implementation References **`lvehx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvehx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:81`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L81) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:44`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L44) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:763`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L763) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1884-1897`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1884-L1897) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvehx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:81`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L81) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:137`](../../../crates/sylpheed-ppc/src/opcode.rs#L137) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:878`](../../../crates/sylpheed-ppc/src/decoder.rs#L878) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvehx => { - // Load a halfword from (EA & ~1) into vD at halfword slot - // (EA & 0xF) >> 1. Other halfword lanes preserved (see lvebx). - let base = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea_unaligned = base.wrapping_add(ctx.gpr[instr.rb()]) as u32; - let ea = ea_unaligned & !0x1u32; - let slot = ((ea_unaligned & 0xF) >> 1) as usize; - let mut bytes = ctx.vr[instr.rd()].as_bytes(); - let h = mem.read_u16(ea); - bytes[slot * 2] = (h >> 8) as u8; - bytes[slot * 2 + 1] = (h & 0xFF) as u8; - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(bytes); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvehx(PPCHIRBuilder& f, const InstrData& i) { + // Same as lvx. + Value* ea = + f.And(CalculateEA_0(f, i.X.RA, i.X.RB), f.LoadConstantUint64(~0xFull)); + f.StoreVR(i.X.RT, f.ByteSwap(f.Load(ea, VEC128_TYPE))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lvewx.md b/tools/ppc-manual/memory/lvewx.md index 5b2eebd3..6e119ef2 100644 --- a/tools/ppc-manual/memory/lvewx.md +++ b/tools/ppc-manual/memory/lvewx.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,49 +111,48 @@ _No condition-register or status-register effects._ ## Implementation References **`lvewx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvewx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:96`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L96) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:44`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L44) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:770`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L770) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1898-1913`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1898-L1913) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvewx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:96`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L96) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:138`](../../../crates/sylpheed-ppc/src/opcode.rs#L138) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:885`](../../../crates/sylpheed-ppc/src/decoder.rs#L885) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvewx => { - // Load a word from (EA & ~3) into vD at word slot - // (EA & 0xF) >> 2. Other word lanes preserved (see lvebx). - let base = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea_unaligned = base.wrapping_add(ctx.gpr[instr.rb()]) as u32; - let ea = ea_unaligned & !0x3u32; - let slot = ((ea_unaligned & 0xF) >> 2) as usize; - let mut bytes = ctx.vr[instr.rd()].as_bytes(); - let w = mem.read_u32(ea); - bytes[slot * 4] = (w >> 24) as u8; - bytes[slot * 4 + 1] = (w >> 16) as u8; - bytes[slot * 4 + 2] = (w >> 8) as u8; - bytes[slot * 4 + 3] = (w & 0xFF) as u8; - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(bytes); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvewx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvewx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:89) ── +int InstrEmit_lvewx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // Same as lvx. + Value* ea = f.And(CalculateEA_0(f, ra, rb), f.LoadConstantUint64(~0xFull)); + f.StoreVR(vd, f.ByteSwap(f.Load(ea, VEC128_TYPE))); + return 0; +} ```
**`lvewx128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvewx128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:99`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L99) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:44`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L44) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:414`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L414) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3168-3174`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3168-L3174) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvewx128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:99`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L99) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:139`](../../../crates/sylpheed-ppc/src/opcode.rs#L139) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:529`](../../../crates/sylpheed-ppc/src/decoder.rs#L529) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvewx128 => { - let ea = ea_indexed(ctx, instr) & !0xF; - let mut bytes = [0u8; 16]; - for i in 0..16 { bytes[i] = mem.read_u8(ea + i as u32); } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_bytes(bytes); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvewx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvewx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:89) ── +int InstrEmit_lvewx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // Same as lvx. + Value* ea = f.And(CalculateEA_0(f, ra, rb), f.LoadConstantUint64(~0xFull)); + f.StoreVR(vd, f.ByteSwap(f.Load(ea, VEC128_TYPE))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lvlx.md b/tools/ppc-manual/memory/lvlx.md index 188b50dd..3cfe0f2a 100644 --- a/tools/ppc-manual/memory/lvlx.md +++ b/tools/ppc-manual/memory/lvlx.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,36 +111,50 @@ _No condition-register or status-register effects._ ## Implementation References **`lvlx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvlx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:216`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L216) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:44`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L44) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:815`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L815) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3083-3087`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3083-L3087) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvlx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:216`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L216) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:140`](../../../crates/sylpheed-ppc/src/opcode.rs#L140) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:930`](../../../crates/sylpheed-ppc/src/decoder.rs#L930) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvlx | PpcOpcode::lvlxl => { - let ea = ea_indexed(ctx, instr); - ctx.vr[instr.rd()] = crate::vmx::load_vector_left(mem, ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvlx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvlx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:208) ── +int InstrEmit_lvlx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = CalculateEA_0(f, ra, rb); + + Value* val = f.LoadVectorLeft(ea); + f.StoreVR(vd, val); + return 0; +} ```
**`lvlx128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvlx128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:219`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L219) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:44`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L44) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:420`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L420) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3088-3092`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3088-L3092) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvlx128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:219`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L219) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:141`](../../../crates/sylpheed-ppc/src/opcode.rs#L141) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:535`](../../../crates/sylpheed-ppc/src/decoder.rs#L535) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvlx128 | PpcOpcode::lvlxl128 => { - let ea = ea_indexed(ctx, instr); - ctx.vr[instr.vd128()] = crate::vmx::load_vector_left(mem, ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvlx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvlx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:208) ── +int InstrEmit_lvlx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = CalculateEA_0(f, ra, rb); + + Value* val = f.LoadVectorLeft(ea); + f.StoreVR(vd, val); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lvlxl.md b/tools/ppc-manual/memory/lvlxl.md index 762c45a8..e05e74c5 100644 --- a/tools/ppc-manual/memory/lvlxl.md +++ b/tools/ppc-manual/memory/lvlxl.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,36 +111,60 @@ _No condition-register or status-register effects._ ## Implementation References **`lvlxl`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvlxl"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:222`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L222) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:44`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L44) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:838`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L838) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3083-3087`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3083-L3087) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvlxl"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:222`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L222) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:142`](../../../crates/sylpheed-ppc/src/opcode.rs#L142) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:953`](../../../crates/sylpheed-ppc/src/decoder.rs#L953) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvlx | PpcOpcode::lvlxl => { - let ea = ea_indexed(ctx, instr); - ctx.vr[instr.rd()] = crate::vmx::load_vector_left(mem, ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvlxl(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvlx(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:216) ── +int InstrEmit_lvlx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvlx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:208) ── +int InstrEmit_lvlx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = CalculateEA_0(f, ra, rb); + + Value* val = f.LoadVectorLeft(ea); + f.StoreVR(vd, val); + return 0; +} ```
**`lvlxl128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvlxl128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:225`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L225) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:44`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L44) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:424`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L424) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3088-3092`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3088-L3092) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvlxl128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:225`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L225) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:143`](../../../crates/sylpheed-ppc/src/opcode.rs#L143) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:539`](../../../crates/sylpheed-ppc/src/decoder.rs#L539) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvlx128 | PpcOpcode::lvlxl128 => { - let ea = ea_indexed(ctx, instr); - ctx.vr[instr.vd128()] = crate::vmx::load_vector_left(mem, ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvlxl128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvlx128(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:219) ── +int InstrEmit_lvlx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvlx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:208) ── +int InstrEmit_lvlx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = CalculateEA_0(f, ra, rb); + + Value* val = f.LoadVectorLeft(ea); + f.StoreVR(vd, val); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lvrx.md b/tools/ppc-manual/memory/lvrx.md index d58e0bca..aa1f83a6 100644 --- a/tools/ppc-manual/memory/lvrx.md +++ b/tools/ppc-manual/memory/lvrx.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,36 +111,58 @@ _No condition-register or status-register effects._ ## Implementation References **`lvrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:241`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L241) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:45`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L45) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:822`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L822) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3093-3097`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3093-L3097) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:241`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L241) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:144`](../../../crates/sylpheed-ppc/src/opcode.rs#L144) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:937`](../../../crates/sylpheed-ppc/src/decoder.rs#L937) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvrx | PpcOpcode::lvrxl => { - let ea = ea_indexed(ctx, instr); - ctx.vr[instr.rd()] = crate::vmx::load_vector_right(mem, ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvrx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvrx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:229) ── +int InstrEmit_lvrx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) then no data is loaded. This is important + // as often times memcpy's will use this to handle the remaining <=16b of a + // buffer, which sometimes may be nothing and hang off the end of the valid + // page area. We still need to zero the resulting register, though. + Value* ea = CalculateEA_0(f, ra, rb); + + Value* val = f.LoadVectorRight(ea); + f.StoreVR(vd, val); + return 0; +} ```
**`lvrx128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvrx128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:244`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L244) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:45`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L45) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:421`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L421) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3098-3102`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3098-L3102) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvrx128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:244`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L244) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:145`](../../../crates/sylpheed-ppc/src/opcode.rs#L145) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:536`](../../../crates/sylpheed-ppc/src/decoder.rs#L536) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvrx128 | PpcOpcode::lvrxl128 => { - let ea = ea_indexed(ctx, instr); - ctx.vr[instr.vd128()] = crate::vmx::load_vector_right(mem, ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvrx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvrx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:229) ── +int InstrEmit_lvrx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) then no data is loaded. This is important + // as often times memcpy's will use this to handle the remaining <=16b of a + // buffer, which sometimes may be nothing and hang off the end of the valid + // page area. We still need to zero the resulting register, though. + Value* ea = CalculateEA_0(f, ra, rb); + + Value* val = f.LoadVectorRight(ea); + f.StoreVR(vd, val); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lvrxl.md b/tools/ppc-manual/memory/lvrxl.md index b82c5707..a6f9bc25 100644 --- a/tools/ppc-manual/memory/lvrxl.md +++ b/tools/ppc-manual/memory/lvrxl.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,36 +111,68 @@ _No condition-register or status-register effects._ ## Implementation References **`lvrxl`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvrxl"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:247`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L247) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:45`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L45) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:842`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L842) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3093-3097`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3093-L3097) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvrxl"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:247`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L247) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:146`](../../../crates/sylpheed-ppc/src/opcode.rs#L146) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:957`](../../../crates/sylpheed-ppc/src/decoder.rs#L957) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvrx | PpcOpcode::lvrxl => { - let ea = ea_indexed(ctx, instr); - ctx.vr[instr.rd()] = crate::vmx::load_vector_right(mem, ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvrxl(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvrx(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:241) ── +int InstrEmit_lvrx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvrx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:229) ── +int InstrEmit_lvrx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) then no data is loaded. This is important + // as often times memcpy's will use this to handle the remaining <=16b of a + // buffer, which sometimes may be nothing and hang off the end of the valid + // page area. We still need to zero the resulting register, though. + Value* ea = CalculateEA_0(f, ra, rb); + + Value* val = f.LoadVectorRight(ea); + f.StoreVR(vd, val); + return 0; +} ```
**`lvrxl128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvrxl128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:250`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L250) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:45`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L45) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:425`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L425) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3098-3102`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3098-L3102) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvrxl128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:250`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L250) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:147`](../../../crates/sylpheed-ppc/src/opcode.rs#L147) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:540`](../../../crates/sylpheed-ppc/src/decoder.rs#L540) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvrx128 | PpcOpcode::lvrxl128 => { - let ea = ea_indexed(ctx, instr); - ctx.vr[instr.vd128()] = crate::vmx::load_vector_right(mem, ea); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvrxl128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvrx128(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:244) ── +int InstrEmit_lvrx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvrx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:229) ── +int InstrEmit_lvrx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) then no data is loaded. This is important + // as often times memcpy's will use this to handle the remaining <=16b of a + // buffer, which sometimes may be nothing and hang off the end of the valid + // page area. We still need to zero the resulting register, though. + Value* ea = CalculateEA_0(f, ra, rb); + + Value* val = f.LoadVectorRight(ea); + f.StoreVR(vd, val); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lvx.md b/tools/ppc-manual/memory/lvx.md index 82637767..a47d2408 100644 --- a/tools/ppc-manual/memory/lvx.md +++ b/tools/ppc-manual/memory/lvx.md @@ -100,42 +100,46 @@ v[insn.VD] = mem_read_vec128_be(ea); ## Implementation References **`lvx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:139`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L139) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:47`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L47) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:775`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L775) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1833-1840`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1833-L1840) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:139`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L139) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:152`](../../../crates/sylpheed-ppc/src/opcode.rs#L152) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:890`](../../../crates/sylpheed-ppc/src/decoder.rs#L890) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = (ea.wrapping_add(ctx.gpr[instr.rb()]) & !0xF) as u32; // aligned - let mut bytes = [0u8; 16]; - for i in 0..16 { bytes[i] = mem.read_u8(ea + i as u32); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(bytes); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:133) ── +int InstrEmit_lvx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = f.And(CalculateEA_0(f, ra, rb), f.LoadConstantInt64(~0xFull)); + f.StoreVR(vd, f.ByteSwap(f.Load(ea, VEC128_TYPE))); + return 0; +} ```
**`lvx128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvx128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:142`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L142) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:47`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L47) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:415`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L415) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1841-1848`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1841-L1848) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvx128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:142`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L142) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:153`](../../../crates/sylpheed-ppc/src/opcode.rs#L153) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:530`](../../../crates/sylpheed-ppc/src/decoder.rs#L530) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvx128 => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = (ea.wrapping_add(ctx.gpr[instr.rb()]) & !0xF) as u32; - let mut bytes = [0u8; 16]; - for i in 0..16 { bytes[i] = mem.read_u8(ea + i as u32); } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_bytes(bytes); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:133) ── +int InstrEmit_lvx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = f.And(CalculateEA_0(f, ra, rb), f.LoadConstantInt64(~0xFull)); + f.StoreVR(vd, f.ByteSwap(f.Load(ea, VEC128_TYPE))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lvxl.md b/tools/ppc-manual/memory/lvxl.md index f7f3fa8a..bbedd32d 100644 --- a/tools/ppc-manual/memory/lvxl.md +++ b/tools/ppc-manual/memory/lvxl.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,46 +111,56 @@ _No condition-register or status-register effects._ ## Implementation References **`lvxl`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvxl"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:145`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L145) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:47`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L47) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:802`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L802) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1960-1969`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1960-L1969) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvxl"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:145`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L145) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:154`](../../../crates/sylpheed-ppc/src/opcode.rs#L154) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:917`](../../../crates/sylpheed-ppc/src/decoder.rs#L917) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvxl | PpcOpcode::lvxl128 => { - // Same as lvx but with cache hint (ignored) - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = (ea.wrapping_add(ctx.gpr[instr.rb()]) & !0xF) as u32; - let mut bytes = [0u8; 16]; - for i in 0..16 { bytes[i] = mem.read_u8(ea + i as u32); } - let vd = if matches!(instr.opcode, PpcOpcode::lvxl128) { instr.vd128() } else { instr.rd() }; - ctx.vr[vd] = xenia_types::Vec128::from_bytes(bytes); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvxl(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvx(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:139) ── +int InstrEmit_lvx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:133) ── +int InstrEmit_lvx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = f.And(CalculateEA_0(f, ra, rb), f.LoadConstantInt64(~0xFull)); + f.StoreVR(vd, f.ByteSwap(f.Load(ea, VEC128_TYPE))); + return 0; +} ```
**`lvxl128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvxl128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:148`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L148) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:47`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L47) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:418`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L418) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1960-1969`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1960-L1969) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvxl128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:148`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L148) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:155`](../../../crates/sylpheed-ppc/src/opcode.rs#L155) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:533`](../../../crates/sylpheed-ppc/src/decoder.rs#L533) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvxl | PpcOpcode::lvxl128 => { - // Same as lvx but with cache hint (ignored) - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = (ea.wrapping_add(ctx.gpr[instr.rb()]) & !0xF) as u32; - let mut bytes = [0u8; 16]; - for i in 0..16 { bytes[i] = mem.read_u8(ea + i as u32); } - let vd = if matches!(instr.opcode, PpcOpcode::lvxl128) { instr.vd128() } else { instr.rd() }; - ctx.vr[vd] = xenia_types::Vec128::from_bytes(bytes); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvxl128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvx128(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:142) ── +int InstrEmit_lvx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:133) ── +int InstrEmit_lvx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = f.And(CalculateEA_0(f, ra, rb), f.LoadConstantInt64(~0xFull)); + f.StoreVR(vd, f.ByteSwap(f.Load(ea, VEC128_TYPE))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lwa.md b/tools/ppc-manual/memory/lwa.md index 30a0bd47..dc89695b 100644 --- a/tools/ppc-manual/memory/lwa.md +++ b/tools/ppc-manual/memory/lwa.md @@ -116,13 +116,15 @@ RT <- SEXT32_to_64(MEM(EA, 4)) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -130,56 +132,77 @@ RT <- SEXT32_to_64(MEM(EA, 4)) ## Implementation References **`lwa`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwa"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:244`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L244) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:382`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L382) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1108-1113`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1108-L1113) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwa"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:244`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L244) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:157`](../../../crates/sylpheed-ppc/src/opcode.rs#L157) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:497`](../../../crates/sylpheed-ppc/src/decoder.rs#L497) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lwa => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.ds() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lwa(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D || 00) + // RT <- EXTS(MEM(EA, 4)) + Value* b; + if (i.DS.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.DS.RA); + } + + Value* offset = f.LoadConstantInt64(XEEXTS16(i.DS.DS << 2)); + Value* rt = + f.SignExtend(f.ByteSwap(f.LoadOffset(b, offset, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.DS.RT, rt); + return 0; +} ```
**`lwaux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwaux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:265`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L265) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:804`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L804) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1120-1125`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1120-L1125) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwaux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:265`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L265) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:159`](../../../crates/sylpheed-ppc/src/opcode.rs#L159) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:919`](../../../crates/sylpheed-ppc/src/decoder.rs#L919) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lwaux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lwaux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // RT <- EXTS(MEM(EA, 4)) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + Value* rt = f.SignExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`lwax`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwax"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:276`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L276) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:800`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L800) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1114-1119`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1114-L1119) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwax"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:276`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L276) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:160`](../../../crates/sylpheed-ppc/src/opcode.rs#L160) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:915`](../../../crates/sylpheed-ppc/src/decoder.rs#L915) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lwax => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lwax(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- EXTS(MEM(EA, 4)) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.SignExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lwarx.md b/tools/ppc-manual/memory/lwarx.md index a9eeb367..3ee5f189 100644 --- a/tools/ppc-manual/memory/lwarx.md +++ b/tools/ppc-manual/memory/lwarx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,30 +85,44 @@ _No condition-register or status-register effects._ ## Implementation References **`lwarx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwarx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:795`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L795) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:754`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L754) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1207-1222`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1207-L1222) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwarx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:795`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L795) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:158`](../../../crates/sylpheed-ppc/src/opcode.rs#L158) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:869`](../../../crates/sylpheed-ppc/src/decoder.rs#L869) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lwarx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - let val = mem.read_u32(ea); - ctx.gpr[instr.rd()] = val as u64; - ctx.reserved_line = ea & !RESERVATION_MASK; - ctx.reserved_val = val as u64; - ctx.has_reservation = true; - ctx.reservation_width = 4; // PPCBUG-151: word reservation - if let Some(t) = &ctx.reservation_table { - if t.is_enabled() { - ctx.reserved_generation = t.reserve(ea, ctx.hw_id); - } - } - ctx.pc += 4; - } +```cpp +int InstrEmit_lwarx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RESERVE <- 1 + // RESERVE_LENGTH <- 4 + // RESERVE_ADDR <- real_addr(EA) + // RT <- i32.0 || MEM(EA, 4) + + // NOTE: we assume we are within a global lock. + // We could assert here that the block (or its parent) has taken a global lock + // already, but I haven't see anything but interrupt callbacks (which are + // always under a global lock) do that yet. + // We issue a memory barrier here to make sure that we get good values. + + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + if (cvars::no_reserved_ops) { + f.StoreGPR(i.X.RT, + f.ZeroExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE)); + + } else { + f.MemoryBarrier(); + + Value* rt = + f.ZeroExtend(f.ByteSwap(f.LoadWithReserve(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + } + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lwbrx.md b/tools/ppc-manual/memory/lwbrx.md index 9f89c7df..4a331b76 100644 --- a/tools/ppc-manual/memory/lwbrx.md +++ b/tools/ppc-manual/memory/lwbrx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,21 +85,25 @@ _No condition-register or status-register effects._ ## Implementation References **`lwbrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwbrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:641`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L641) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:818`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L818) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1799-1805`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1799-L1805) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwbrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:641`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L641) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:161`](../../../crates/sylpheed-ppc/src/opcode.rs#L161) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:933`](../../../crates/sylpheed-ppc/src/decoder.rs#L933) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lwbrx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - let val = mem.read_u32(ea); - ctx.gpr[instr.rd()] = val.swap_bytes() as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lwbrx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i32.0 || bswap(MEM(EA, 4)) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.ZeroExtend(f.Load(ea, INT32_TYPE), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/lwz.md b/tools/ppc-manual/memory/lwz.md index 9552570e..cb0f5b0a 100644 --- a/tools/ppc-manual/memory/lwz.md +++ b/tools/ppc-manual/memory/lwz.md @@ -147,74 +147,100 @@ r[insn.RT] = (uint64_t)mem_read_u32_be(ea); /* zero-extend */ ## Implementation References **`lwz`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwz"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:289`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L289) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:355`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L355) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1000-1005`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1000-L1005) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwz"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:289`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L289) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:162`](../../../crates/sylpheed-ppc/src/opcode.rs#L162) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:470`](../../../crates/sylpheed-ppc/src/decoder.rs#L470) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lwz => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lwz(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // RT <- i32.0 || MEM(EA, 4) + Value* b; + if (i.D.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.D.RA); + } + + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + Value* rt = + f.ZeroExtend(f.ByteSwap(f.LoadOffset(b, offset, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + return 0; +} ```
**`lwzu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:310`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L310) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:356`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L356) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1006-1011`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1006-L1011) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:310`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L310) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:163`](../../../crates/sylpheed-ppc/src/opcode.rs#L163) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:471`](../../../crates/sylpheed-ppc/src/decoder.rs#L471) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lwzu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lwzu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // RT <- i32.0 || MEM(EA, 4) + // RA <- EA + Value* ra = f.LoadGPR(i.D.RA); + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + Value* rt = f.ZeroExtend(f.ByteSwap(f.LoadOffset(ra, offset, INT32_TYPE)), + INT64_TYPE); + f.StoreGPR(i.D.RT, rt); + StoreEA(f, i.D.RA, f.Add(ra, offset)); + return 0; +} ```
**`lwzux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:323`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L323) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:766`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L766) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1018-1023`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1018-L1023) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:323`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L323) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:164`](../../../crates/sylpheed-ppc/src/opcode.rs#L164) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:881`](../../../crates/sylpheed-ppc/src/decoder.rs#L881) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lwzux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lwzux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // RT <- i32.0 || MEM(EA, 4) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`lwzx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:334`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L334) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:49`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L49) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:756`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L756) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1012-1017`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1012-L1017) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lwzx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:334`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L334) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:165`](../../../crates/sylpheed-ppc/src/opcode.rs#L165) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:871`](../../../crates/sylpheed-ppc/src/decoder.rs#L871) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lwzx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - ctx.gpr[instr.rd()] = mem.read_u32(ea) as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_lwzx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RT <- i32.0 || MEM(EA, 4) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.ZeroExtend(f.ByteSwap(f.Load(ea, INT32_TYPE)), INT64_TYPE); + f.StoreGPR(i.X.RT, rt); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stb.md b/tools/ppc-manual/memory/stb.md index 10926bec..8e63cb5b 100644 --- a/tools/ppc-manual/memory/stb.md +++ b/tools/ppc-manual/memory/stb.md @@ -138,13 +138,15 @@ MEM(EA, 1) <- (RS)[56:63] ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -152,86 +154,93 @@ MEM(EA, 1) <- (RS)[56:63] ## Implementation References **`stb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:404`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L404) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:67`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L67) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:361`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L361) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1327-1335`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1327-L1335) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:404`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L404) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:225`](../../../crates/sylpheed-ppc/src/opcode.rs#L225) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:476`](../../../crates/sylpheed-ppc/src/decoder.rs#L476) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stb => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - 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_u8(ea, ctx.gpr[instr.rs()] as u8); - ctx.pc += 4; - } +```cpp +int InstrEmit_stb(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // MEM(EA, 1) <- (RS)[56:63] + Value* b; + if (i.D.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.D.RA); + } + + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + f.StoreOffset(b, offset, f.Truncate(f.LoadGPR(i.D.RT), INT8_TYPE)); + return 0; +} ```
**`stbu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stbu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:423`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L423) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:67`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L67) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:362`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L362) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1336-1344`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1336-L1344) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stbu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:423`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L423) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:226`](../../../crates/sylpheed-ppc/src/opcode.rs#L226) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:477`](../../../crates/sylpheed-ppc/src/decoder.rs#L477) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stbu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - 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_u8(ea, ctx.gpr[instr.rs()] as u8); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_stbu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // MEM(EA, 1) <- (RS)[56:63] + // RA <- EA + Value* ea = CalculateEA_i(f, i.D.RA, XEEXTS16(i.D.DS)); + f.Store(ea, f.Truncate(f.LoadGPR(i.D.RT), INT8_TYPE)); + StoreEA(f, i.D.RA, ea); + return 0; +} ```
**`stbux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stbux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:433`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L433) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:67`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L67) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:793`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L793) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1354-1362`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1354-L1362) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stbux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:433`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L433) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:227`](../../../crates/sylpheed-ppc/src/opcode.rs#L227) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:908`](../../../crates/sylpheed-ppc/src/decoder.rs#L908) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stbux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_u8(ea, ctx.gpr[instr.rs()] as u8); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_stbux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 1) <- (RS)[56:63] + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + f.Store(ea, f.Truncate(f.LoadGPR(i.X.RT), INT8_TYPE)); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`stbx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stbx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:443`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L443) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:67`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L67) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:790`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L790) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1345-1353`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1345-L1353) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stbx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:443`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L443) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:228`](../../../crates/sylpheed-ppc/src/opcode.rs#L228) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:905`](../../../crates/sylpheed-ppc/src/decoder.rs#L905) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stbx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_u8(ea, ctx.gpr[instr.rs()] as u8); - ctx.pc += 4; - } +```cpp +int InstrEmit_stbx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 1) <- (RS)[56:63] + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.Store(ea, f.Truncate(f.LoadGPR(i.X.RT), INT8_TYPE)); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/std.md b/tools/ppc-manual/memory/std.md index ee01e445..8fc8e097 100644 --- a/tools/ppc-manual/memory/std.md +++ b/tools/ppc-manual/memory/std.md @@ -140,13 +140,15 @@ MEM(EA, 8) <- (RS) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -154,86 +156,93 @@ MEM(EA, 8) <- (RS) ## Implementation References **`std`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="std"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:575`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L575) -- 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:399`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L399) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1399-1407`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1399-L1407) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="std"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:575`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L575) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:230`](../../../crates/sylpheed-ppc/src/opcode.rs#L230) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:514`](../../../crates/sylpheed-ppc/src/decoder.rs#L514) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::std => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.ds() as i64 as u64) as u32; - 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()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_std(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(DS || 0b00) + // MEM(EA, 8) <- (RS) + Value* b; + if (i.DS.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.DS.RA); + } + + Value* offset = f.LoadConstantInt64(XEEXTS16(i.DS.DS << 2)); + f.StoreOffset(b, offset, f.ByteSwap(f.LoadGPR(i.DS.RT))); + return 0; +} ```
**`stdu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stdu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:594`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L594) -- 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:400`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L400) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1417-1425`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1417-L1425) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stdu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:594`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L594) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:233`](../../../crates/sylpheed-ppc/src/opcode.rs#L233) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:515`](../../../crates/sylpheed-ppc/src/decoder.rs#L515) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stdu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.ds() as i64 as u64) as u32; - 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()]); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_stdu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(DS || 0b00) + // MEM(EA, 8) <- (RS) + // RA <- EA + Value* ea = CalculateEA_i(f, i.DS.RA, XEEXTS16(i.DS.DS << 2)); + f.Store(ea, f.ByteSwap(f.LoadGPR(i.DS.RT))); + StoreEA(f, i.DS.RA, ea); + return 0; +} ```
**`stdux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stdux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:604`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L604) -- 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:786`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L786) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1426-1434`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1426-L1434) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stdux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:604`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L604) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:234`](../../../crates/sylpheed-ppc/src/opcode.rs#L234) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:901`](../../../crates/sylpheed-ppc/src/decoder.rs#L901) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stdux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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()]); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_stdux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 8) <- (RS) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.LoadGPR(i.X.RT))); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`stdx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stdx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:614`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L614) -- 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:781`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L781) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1408-1416`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1408-L1416) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stdx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:614`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L614) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:235`](../../../crates/sylpheed-ppc/src/opcode.rs#L235) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:896`](../../../crates/sylpheed-ppc/src/decoder.rs#L896) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stdx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stdx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 8) <- (RS) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.LoadGPR(i.X.RT))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stdbrx.md b/tools/ppc-manual/memory/stdbrx.md index a27e9b1a..9d2c6d9c 100644 --- a/tools/ppc-manual/memory/stdbrx.md +++ b/tools/ppc-manual/memory/stdbrx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,22 +85,24 @@ _No condition-register or status-register effects._ ## 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) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stdbrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:691`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L691) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:231`](../../../crates/sylpheed-ppc/src/opcode.rs#L231) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:944`](../../../crates/sylpheed-ppc/src/decoder.rs#L944) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```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; - } +```cpp +int InstrEmit_stdbrx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 8) <- bswap(RS) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.Store(ea, f.LoadGPR(i.X.RT)); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stdcx.md b/tools/ppc-manual/memory/stdcx.md index 4bacab70..27d01c53 100644 --- a/tools/ppc-manual/memory/stdcx.md +++ b/tools/ppc-manual/memory/stdcx.md @@ -59,28 +59,26 @@ stdcx. [RS], [RA0], [RB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,65 +86,53 @@ stdcx. [RS], [RA0], [RB] ## Implementation References **`stdcx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stdcx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:827`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L827) -- 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:789`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L789) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4576-4626`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4576-L4626) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stdcx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:827`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L827) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:232`](../../../crates/sylpheed-ppc/src/opcode.rs#L232) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:904`](../../../crates/sylpheed-ppc/src/decoder.rs#L904) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stdcx => { - let ea = ea_indexed(ctx, instr); - let line = ea & !RESERVATION_MASK; - let table_route = ctx - .reservation_table - .as_ref() - .filter(|t| t.is_enabled()) - .cloned(); - // PPCBUG-151: stdcx. requires a doubleword (ldarx) reservation; - // a word (lwarx) reservation must not commit here. - let width_ok = ctx.reservation_width == 8; - let success = if let Some(t) = &table_route { - ctx.has_reservation - && width_ok - && ctx.reserved_line == line - && t.try_commit(ea, ctx.reserved_generation, ctx.hw_id) - } else { - // Legacy per-ctx path (M2 default / lockstep). - // PPCBUG-108: same sentinel as stwcx. — fires on non-primary - // HW slots if the table is disabled under --parallel. - debug_assert!( - ctx.hw_id == 0, - "PPCBUG-108: legacy per-ctx stdcx. on non-primary HW slot \ - (hw_id={}) — ReservationTable must be enabled under --parallel", - ctx.hw_id - ); - ctx.has_reservation && width_ok && ctx.reserved_line == line - }; - if success { - mem.write_u64(ea, ctx.gpr[instr.rs()]); - ctx.cr[0] = crate::context::CrField { - lt: false, - gt: false, - eq: true, - so: ctx.xer_so != 0, - }; - } else { - ctx.cr[0] = crate::context::CrField { - lt: false, - gt: false, - eq: false, - so: ctx.xer_so != 0, - }; - if let Some(t) = &table_route { - t.release(ea, ctx.reserved_generation, ctx.hw_id); - } - } - ctx.has_reservation = false; - ctx.reservation_width = 0; // PPCBUG-151: always clear on exit - ctx.pc += 4; - } +```cpp +int InstrEmit_stdcx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RESERVE stuff... + // MEM(EA, 8) <- (RS) + // n <- 1 if store performed + // CR0[LT GT EQ SO] = 0b00 || n || XER[SO] + + // NOTE: we assume we are within a global lock. + // As we have been exclusively executing this entire time, we assume that no + // one else could have possibly touched the memory and must always succeed. + // We use atomic compare exchange here to support reserved load/store without + // being under the global lock (flag disable_global_lock - see mtmsr/mtmsrd). + // This will always succeed if under the global lock, however. + + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* rt = f.ByteSwap(f.LoadGPR(i.X.RT)); + + if (cvars::no_reserved_ops) { + f.Store(ea, rt); + + f.StoreContext(offsetof(PPCContext, cr0.cr0_eq), f.LoadConstantInt8(1)); + } else { + Value* v = f.StoreWithReserve(ea, rt, INT64_TYPE); + + f.StoreContext(offsetof(PPCContext, cr0.cr0_eq), v); + } + f.StoreContext(offsetof(PPCContext, cr0.cr0_lt), f.LoadZeroInt8()); + f.StoreContext(offsetof(PPCContext, cr0.cr0_gt), f.LoadZeroInt8()); + + // Issue memory barrier for when we go out of lock and want others to see our + // updates. + if (!cvars::no_reserved_ops) { + f.MemoryBarrier(); + } + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stfd.md b/tools/ppc-manual/memory/stfd.md index 86522397..47134c51 100644 --- a/tools/ppc-manual/memory/stfd.md +++ b/tools/ppc-manual/memory/stfd.md @@ -138,13 +138,15 @@ MEM(EA, 8) <- (FRS) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -152,86 +154,86 @@ MEM(EA, 8) <- (FRS) ## Implementation References **`stfd`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfd"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1014`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1014) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:71`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L71) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:377`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L377) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1473-1481`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1473-L1481) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfd"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1014`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1014) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:237`](../../../crates/sylpheed-ppc/src/opcode.rs#L237) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:492`](../../../crates/sylpheed-ppc/src/decoder.rs#L492) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stfd => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - 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_f64(ea, ctx.fpr[instr.rs()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stfd(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // MEM(EA, 8) <- (FRS) + Value* ea = CalculateEA_0_i(f, i.D.RA, XEEXTS16(i.D.DS)); + f.Store(ea, f.ByteSwap(f.Cast(f.LoadFPR(i.D.RT), INT64_TYPE))); + return 0; +} ```
**`stfdu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfdu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1026`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1026) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:71`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L71) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:378`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L378) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1482-1490`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1482-L1490) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfdu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1026`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1026) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:238`](../../../crates/sylpheed-ppc/src/opcode.rs#L238) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:493`](../../../crates/sylpheed-ppc/src/decoder.rs#L493) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stfdu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - 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_f64(ea, ctx.fpr[instr.rs()]); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_stfdu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // MEM(EA, 8) <- (FRS) + // RA <- EA + Value* ea = CalculateEA_i(f, i.D.RA, XEEXTS16(i.D.DS)); + f.Store(ea, f.ByteSwap(f.Cast(f.LoadFPR(i.D.RT), INT64_TYPE))); + StoreEA(f, i.D.RA, ea); + return 0; +} ```
**`stfdux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfdux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1036`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1036) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:71`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L71) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:837`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L837) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1500-1508`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1500-L1508) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfdux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1036`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1036) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:239`](../../../crates/sylpheed-ppc/src/opcode.rs#L239) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:952`](../../../crates/sylpheed-ppc/src/decoder.rs#L952) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stfdux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_f64(ea, ctx.fpr[instr.rs()]); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_stfdux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 8) <- (FRS) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.Cast(f.LoadFPR(i.X.RT), INT64_TYPE))); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`stfdx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfdx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1046`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1046) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:71`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L71) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:836`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L836) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1491-1499`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1491-L1499) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfdx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1046`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1046) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:240`](../../../crates/sylpheed-ppc/src/opcode.rs#L240) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:951`](../../../crates/sylpheed-ppc/src/decoder.rs#L951) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stfdx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_f64(ea, ctx.fpr[instr.rs()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stfdx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 8) <- (FRS) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.Cast(f.LoadFPR(i.X.RT), INT64_TYPE))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stfiwx.md b/tools/ppc-manual/memory/stfiwx.md index 1a4ade81..31417892 100644 --- a/tools/ppc-manual/memory/stfiwx.md +++ b/tools/ppc-manual/memory/stfiwx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,24 +85,25 @@ _No condition-register or status-register effects._ ## Implementation References **`stfiwx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfiwx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1058`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1058) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:71`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L71) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:851`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L851) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1509-1518`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1509-L1518) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfiwx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1058`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1058) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:241`](../../../crates/sylpheed-ppc/src/opcode.rs#L241) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:966`](../../../crates/sylpheed-ppc/src/decoder.rs#L966) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stfiwx => { - // Store FP as integer word: stores low 32 bits of FPR as-is - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_u32(ea, ctx.fpr[instr.rs()].to_bits() as u32); - ctx.pc += 4; - } +```cpp +int InstrEmit_stfiwx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 4) <- (FRS)[32:63] + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.Truncate(f.Cast(f.LoadFPR(i.X.RT), INT64_TYPE), + INT32_TYPE))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stfs.md b/tools/ppc-manual/memory/stfs.md index e484e65a..070ae3ef 100644 --- a/tools/ppc-manual/memory/stfs.md +++ b/tools/ppc-manual/memory/stfs.md @@ -138,13 +138,15 @@ MEM(EA, 4) <- SingleFromDouble(FRS) ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -152,86 +154,90 @@ MEM(EA, 4) <- SingleFromDouble(FRS) ## Implementation References **`stfs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1071`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1071) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:71`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L71) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:375`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L375) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1437-1445`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1437-L1445) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1071`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1071) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:242`](../../../crates/sylpheed-ppc/src/opcode.rs#L242) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:490`](../../../crates/sylpheed-ppc/src/decoder.rs#L490) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stfs => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - 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_f32(ea, ctx.fpr[instr.rs()] as f32); - ctx.pc += 4; - } +```cpp +int InstrEmit_stfs(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // MEM(EA, 4) <- SINGLE(FRS) + Value* ea = CalculateEA_0_i(f, i.D.RA, XEEXTS16(i.D.DS)); + f.Store(ea, f.ByteSwap(f.Cast(f.Convert(f.LoadFPR(i.D.RT), FLOAT32_TYPE), + INT32_TYPE))); + return 0; +} ```
**`stfsu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfsu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1084`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1084) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:71`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L71) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:376`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L376) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1446-1454`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1446-L1454) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfsu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1084`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1084) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:243`](../../../crates/sylpheed-ppc/src/opcode.rs#L243) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:491`](../../../crates/sylpheed-ppc/src/decoder.rs#L491) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stfsu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - 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_f32(ea, ctx.fpr[instr.rs()] as f32); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_stfsu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // MEM(EA, 4) <- SINGLE(FRS) + // RA <- EA + Value* ea = CalculateEA_i(f, i.D.RA, XEEXTS16(i.D.DS)); + f.Store(ea, f.ByteSwap(f.Cast(f.Convert(f.LoadFPR(i.D.RT), FLOAT32_TYPE), + INT32_TYPE))); + StoreEA(f, i.D.RA, ea); + return 0; +} ```
**`stfsux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfsux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1095`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1095) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:71`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L71) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:834`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L834) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1464-1472`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1464-L1472) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfsux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1095`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1095) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:244`](../../../crates/sylpheed-ppc/src/opcode.rs#L244) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:949`](../../../crates/sylpheed-ppc/src/decoder.rs#L949) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stfsux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_f32(ea, ctx.fpr[instr.rs()] as f32); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_stfsux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 4) <- SINGLE(FRS) + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.Cast(f.Convert(f.LoadFPR(i.X.RT), FLOAT32_TYPE), + INT32_TYPE))); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`stfsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1106`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1106) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:71`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L71) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:832`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L832) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1455-1463`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1455-L1463) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stfsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:1106`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L1106) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:245`](../../../crates/sylpheed-ppc/src/opcode.rs#L245) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:947`](../../../crates/sylpheed-ppc/src/decoder.rs#L947) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stfsx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_f32(ea, ctx.fpr[instr.rs()] as f32); - ctx.pc += 4; - } +```cpp +int InstrEmit_stfsx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 4) <- SINGLE(FRS) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.Cast(f.Convert(f.LoadFPR(i.X.RT), FLOAT32_TYPE), + INT32_TYPE))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/sth.md b/tools/ppc-manual/memory/sth.md index 49028c62..4f735162 100644 --- a/tools/ppc-manual/memory/sth.md +++ b/tools/ppc-manual/memory/sth.md @@ -138,13 +138,15 @@ MEM(EA, 2) <- (RS)[48:63] ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -152,86 +154,94 @@ MEM(EA, 2) <- (RS)[48:63] ## Implementation References **`sth`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sth"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:455`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L455) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:73`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L73) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:367`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L367) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1363-1371`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1363-L1371) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sth"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:455`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L455) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:247`](../../../crates/sylpheed-ppc/src/opcode.rs#L247) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:482`](../../../crates/sylpheed-ppc/src/decoder.rs#L482) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sth => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - 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_u16(ea, ctx.gpr[instr.rs()] as u16); - ctx.pc += 4; - } +```cpp +int InstrEmit_sth(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // MEM(EA, 2) <- (RS)[48:63] + Value* b; + if (i.D.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.D.RA); + } + + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + f.StoreOffset(b, offset, + f.ByteSwap(f.Truncate(f.LoadGPR(i.D.RT), INT16_TYPE))); + return 0; +} ```
**`sthu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sthu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:475`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L475) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:73`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L73) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:368`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L368) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1372-1380`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1372-L1380) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sthu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:475`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L475) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:249`](../../../crates/sylpheed-ppc/src/opcode.rs#L249) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:483`](../../../crates/sylpheed-ppc/src/decoder.rs#L483) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sthu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - 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_u16(ea, ctx.gpr[instr.rs()] as u16); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_sthu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // MEM(EA, 2) <- (RS)[48:63] + // RA <- EA + Value* ea = CalculateEA_i(f, i.D.RA, XEEXTS16(i.D.DS)); + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.D.RT), INT16_TYPE))); + StoreEA(f, i.D.RA, ea); + return 0; +} ```
**`sthux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sthux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:485`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L485) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:73`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L73) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:808`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L808) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1390-1398`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1390-L1398) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sthux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:485`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L485) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:250`](../../../crates/sylpheed-ppc/src/opcode.rs#L250) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:923`](../../../crates/sylpheed-ppc/src/decoder.rs#L923) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sthux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_u16(ea, ctx.gpr[instr.rs()] as u16); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_sthux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 2) <- (RS)[48:63] + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT16_TYPE))); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`sthx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sthx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:495`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L495) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:73`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L73) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:806`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L806) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1381-1389`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1381-L1389) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sthx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:495`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L495) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:251`](../../../crates/sylpheed-ppc/src/opcode.rs#L251) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:921`](../../../crates/sylpheed-ppc/src/decoder.rs#L921) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sthx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_u16(ea, ctx.gpr[instr.rs()] as u16); - ctx.pc += 4; - } +```cpp +int InstrEmit_sthx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 2) <- (RS)[48:63] + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT16_TYPE))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/sthbrx.md b/tools/ppc-manual/memory/sthbrx.md index 0860cc27..0cee50ea 100644 --- a/tools/ppc-manual/memory/sthbrx.md +++ b/tools/ppc-manual/memory/sthbrx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,23 +85,24 @@ _No condition-register or status-register effects._ ## Implementation References **`sthbrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sthbrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:667`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L667) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:73`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L73) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:846`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L846) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1822-1830`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1822-L1830) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="sthbrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:667`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L667) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:248`](../../../crates/sylpheed-ppc/src/opcode.rs#L248) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:961`](../../../crates/sylpheed-ppc/src/decoder.rs#L961) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::sthbrx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_u16(ea, (ctx.gpr[instr.rs()] as u16).swap_bytes()); - ctx.pc += 4; - } +```cpp +int InstrEmit_sthbrx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 2) <- bswap((RS)[48:63]) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.Store(ea, f.Truncate(f.LoadGPR(i.X.RT), INT16_TYPE)); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stmw.md b/tools/ppc-manual/memory/stmw.md index c64bbe12..a86f8fbd 100644 --- a/tools/ppc-manual/memory/stmw.md +++ b/tools/ppc-manual/memory/stmw.md @@ -53,28 +53,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -82,39 +80,28 @@ _No condition-register or status-register effects._ ## Implementation References **`stmw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stmw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:527`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L527) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:75`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L75) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:370`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L370) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1735-1759`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1735-L1759) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stmw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:527`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L527) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:253`](../../../crates/sylpheed-ppc/src/opcode.rs#L253) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:485`](../../../crates/sylpheed-ppc/src/decoder.rs#L485) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stmw => { - let mut ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - ea = ea.wrapping_add(instr.d() as i64 as u64); - // PPCBUG-160: stmw can span two cache lines when (32-rs)*4 > one line. - // Iterate over every touched line so any reservation on a later line - // is also invalidated (same guarantee as single-word stores). - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let start_ea = ea as u32; - let last_ea = start_ea.wrapping_add((32 - instr.rs() as u32) * 4).wrapping_sub(1); - let line_size = RESERVATION_MASK + 1; - let mut line = start_ea & !RESERVATION_MASK; - loop { - t.invalidate_for_write(line); - if line >= (last_ea & !RESERVATION_MASK) { break; } - line = line.wrapping_add(line_size); - } - } - } - for r in instr.rs()..32 { - mem.write_u32(ea as u32, ctx.gpr[r] as u32); - ea = ea.wrapping_add(4); - } - ctx.pc += 4; - } +```cpp +int InstrEmit_stmw(PPCHIRBuilder& f, const InstrData& i) { + Value* b; + if (i.D.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.D.RA); + } + + for (uint32_t j = 0; j < 32 - i.D.RT; ++j) { + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS) + j * 4); + f.StoreOffset(b, offset, + f.ByteSwap(f.Truncate(f.LoadGPR(i.D.RT + j), INT32_TYPE))); + } + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stswi.md b/tools/ppc-manual/memory/stswi.md index 7cc9772c..4326e64c 100644 --- a/tools/ppc-manual/memory/stswi.md +++ b/tools/ppc-manual/memory/stswi.md @@ -55,28 +55,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,39 +82,17 @@ _No condition-register or status-register effects._ ## Implementation References **`stswi`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stswi"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:737`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L737) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:75`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L75) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:835`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L835) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1540-1564`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1540-L1564) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stswi"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:737`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L737) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:254`](../../../crates/sylpheed-ppc/src/opcode.rs#L254) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:950`](../../../crates/sylpheed-ppc/src/decoder.rs#L950) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stswi => { - let mut ea = if instr.ra() == 0 { 0u32 } else { ctx.gpr[instr.ra()] as u32 }; - let nb = if instr.nb() == 0 { 32 } else { instr.nb() }; - let mut rs = instr.rs(); - let mut bytes_left = nb; - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let first_line = ea & !RESERVATION_MASK; - let last_line = ea.wrapping_add(nb - 1) & !RESERVATION_MASK; - t.invalidate_for_write(first_line); - if last_line != first_line { t.invalidate_for_write(last_line); } - } - } - while bytes_left > 0 { - let val = ctx.gpr[rs] as u32; - for byte_idx in 0..4 { - if bytes_left == 0 { break; } - mem.write_u8(ea, (val >> (24 - byte_idx * 8)) as u8); - ea = ea.wrapping_add(1); - bytes_left -= 1; - } - rs = (rs + 1) % 32; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_stswi(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/memory/stswx.md b/tools/ppc-manual/memory/stswx.md index cad9b716..4d94ba7f 100644 --- a/tools/ppc-manual/memory/stswx.md +++ b/tools/ppc-manual/memory/stswx.md @@ -55,28 +55,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -84,41 +82,17 @@ _No condition-register or status-register effects._ ## Implementation References **`stswx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stswx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:742`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L742) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:75`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L75) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:830`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L830) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4663-4689`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4663-L4689) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stswx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:742`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L742) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:255`](../../../crates/sylpheed-ppc/src/opcode.rs#L255) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:945`](../../../crates/sylpheed-ppc/src/decoder.rs#L945) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stswx => { - let mut ea = ea_indexed(ctx, instr); - let nb = ctx.xer() & 0x7F; - let mut rs = instr.rs(); - let mut bytes_left = nb; - if nb > 0 { - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let first_line = ea & !RESERVATION_MASK; - let last_line = ea.wrapping_add(nb - 1) & !RESERVATION_MASK; - t.invalidate_for_write(first_line); - if last_line != first_line { t.invalidate_for_write(last_line); } - } - } - } - while bytes_left > 0 { - let val = ctx.gpr[rs] as u32; - for byte_idx in 0..4 { - if bytes_left == 0 { break; } - mem.write_u8(ea, (val >> (24 - byte_idx * 8)) as u8); - ea = ea.wrapping_add(1); - bytes_left -= 1; - } - rs = (rs + 1) % 32; - } - ctx.pc += 4; - } +```cpp +int InstrEmit_stswx(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/memory/stvebx.md b/tools/ppc-manual/memory/stvebx.md index 7b7f1f8f..2a353526 100644 --- a/tools/ppc-manual/memory/stvebx.md +++ b/tools/ppc-manual/memory/stvebx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,27 +85,20 @@ _No condition-register or status-register effects._ ## Implementation References **`stvebx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvebx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:152`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L152) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:77`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L77) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:778`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L778) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1914-1926`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1914-L1926) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvebx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:152`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L152) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:257`](../../../crates/sylpheed-ppc/src/opcode.rs#L257) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:893`](../../../crates/sylpheed-ppc/src/decoder.rs#L893) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvebx => { - // Store vS[EA & 0xF] (1 byte) to memory at EA. - let base = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = base.wrapping_add(ctx.gpr[instr.rb()]) as u32; - // PPCBUG-512: stvebx was missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { t.invalidate_for_write(ea); } - } - let slot = (ea & 0xF) as usize; - let bytes = ctx.vr[instr.rs()].as_bytes(); - mem.write_u8(ea, bytes[slot]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvebx(PPCHIRBuilder& f, const InstrData& i) { + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + Value* el = f.And(f.Truncate(ea, INT8_TYPE), f.LoadConstantUint8(0xF)); + Value* v = f.Extract(f.LoadVR(i.X.RT), el, INT8_TYPE); + f.Store(ea, v); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stvehx.md b/tools/ppc-manual/memory/stvehx.md index 3b67f2ad..eccc72cc 100644 --- a/tools/ppc-manual/memory/stvehx.md +++ b/tools/ppc-manual/memory/stvehx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,29 +85,22 @@ _No condition-register or status-register effects._ ## Implementation References **`stvehx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvehx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:160`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L160) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:77`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L77) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:784`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L784) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1927-1941`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1927-L1941) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvehx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:160`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L160) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:258`](../../../crates/sylpheed-ppc/src/opcode.rs#L258) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:899`](../../../crates/sylpheed-ppc/src/decoder.rs#L899) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvehx => { - // Store vS[slot] (1 halfword) at EA & ~1. slot = (EA & 0xF) >> 1. - let base = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea_unaligned = base.wrapping_add(ctx.gpr[instr.rb()]) as u32; - let ea = ea_unaligned & !0x1u32; - // PPCBUG-512: stvehx was missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { t.invalidate_for_write(ea); } - } - let slot = ((ea_unaligned & 0xF) >> 1) as usize; - let bytes = ctx.vr[instr.rs()].as_bytes(); - let h = ((bytes[slot * 2] as u16) << 8) | (bytes[slot * 2 + 1] as u16); - mem.write_u16(ea, h); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvehx(PPCHIRBuilder& f, const InstrData& i) { + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + ea = f.And(ea, f.LoadConstantUint64(~0x1ull)); + Value* el = + f.Shr(f.And(f.Truncate(ea, INT8_TYPE), f.LoadConstantUint8(0xF)), 1); + Value* v = f.Extract(f.LoadVR(i.X.RT), el, INT16_TYPE); + f.Store(ea, f.ByteSwap(v)); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stvewx.md b/tools/ppc-manual/memory/stvewx.md index c1355c6c..7f635e3e 100644 --- a/tools/ppc-manual/memory/stvewx.md +++ b/tools/ppc-manual/memory/stvewx.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,62 +111,54 @@ _No condition-register or status-register effects._ ## Implementation References **`stvewx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvewx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:180`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L180) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:77`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L77) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:788`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L788) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1942-1959`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1942-L1959) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvewx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:180`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L180) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:259`](../../../crates/sylpheed-ppc/src/opcode.rs#L259) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:903`](../../../crates/sylpheed-ppc/src/decoder.rs#L903) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvewx => { - // Store vS[slot] (1 word) at EA & ~3. slot = (EA & 0xF) >> 2. - let base = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea_unaligned = base.wrapping_add(ctx.gpr[instr.rb()]) as u32; - let ea = ea_unaligned & !0x3u32; - // PPCBUG-512: stvewx was missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { t.invalidate_for_write(ea); } - } - let slot = ((ea_unaligned & 0xF) >> 2) as usize; - let bytes = ctx.vr[instr.rs()].as_bytes(); - let w = ((bytes[slot * 4] as u32) << 24) - | ((bytes[slot * 4 + 1] as u32) << 16) - | ((bytes[slot * 4 + 2] as u32) << 8) - | (bytes[slot * 4 + 3] as u32); - mem.write_u32(ea, w); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvewx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvewx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:170) ── +int InstrEmit_stvewx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = CalculateEA_0(f, ra, rb); + ea = f.And(ea, f.LoadConstantUint64(~0x3ull)); + Value* el = + f.Shr(f.And(f.Truncate(ea, INT8_TYPE), f.LoadConstantUint8(0xF)), 2); + Value* v = f.Extract(f.LoadVR(vd), el, INT32_TYPE); + f.Store(ea, f.ByteSwap(v)); + return 0; +} ```
**`stvewx128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvewx128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:183`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L183) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:77`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L77) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:416`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L416) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3175-3192`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3175-L3192) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvewx128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:183`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L183) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:260`](../../../crates/sylpheed-ppc/src/opcode.rs#L260) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:531`](../../../crates/sylpheed-ppc/src/decoder.rs#L531) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvewx128 => { - // Mirror of stvewx: word-align EA, extract one 32-bit lane, write 4 bytes only. - // Previous code used & !0xF (16-byte) and wrote all 16 bytes, corrupting 12 - // adjacent bytes on every execution (PPCBUG-510). - let ea_unaligned = ea_indexed(ctx, instr); - let ea = ea_unaligned & !0x3u32; - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { t.invalidate_for_write(ea); } - } - let slot = ((ea_unaligned & 0xF) >> 2) as usize; - let bytes = ctx.vr[instr.vs128()].as_bytes(); - let w = ((bytes[slot * 4] as u32) << 24) - | ((bytes[slot * 4 + 1] as u32) << 16) - | ((bytes[slot * 4 + 2] as u32) << 8) - | (bytes[slot * 4 + 3] as u32); - mem.write_u32(ea, w); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvewx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvewx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:170) ── +int InstrEmit_stvewx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = CalculateEA_0(f, ra, rb); + ea = f.And(ea, f.LoadConstantUint64(~0x3ull)); + Value* el = + f.Shr(f.And(f.Truncate(ea, INT8_TYPE), f.LoadConstantUint8(0xF)), 2); + Value* v = f.Extract(f.LoadVR(vd), el, INT32_TYPE); + f.Store(ea, f.ByteSwap(v)); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stvlx.md b/tools/ppc-manual/memory/stvlx.md index f18c6afa..10065c75 100644 --- a/tools/ppc-manual/memory/stvlx.md +++ b/tools/ppc-manual/memory/stvlx.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,57 +111,56 @@ _No condition-register or status-register effects._ ## Implementation References **`stvlx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvlx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:265`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L265) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:77`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L77) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:828`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L828) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3103-3119`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3103-L3119) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvlx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:265`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L265) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:261`](../../../crates/sylpheed-ppc/src/opcode.rs#L261) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:943`](../../../crates/sylpheed-ppc/src/decoder.rs#L943) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvlx | PpcOpcode::stvlxl => { - let ea = ea_indexed(ctx, instr); - // PPCBUG-513: stvlx/stvlxl were missing invalidate_for_write. - // store_vector_left writes [ea, (ea & !0xF)+15]; in the worst case (ea & 0xF == 0) - // that is exactly 16 bytes all within the same 16-byte block, so ea+15 lands in the - // same 128-byte cache line. Two-call form is kept for defensive correctness. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let first_line = ea & !RESERVATION_MASK; - let last_line = ea.wrapping_add(15) & !RESERVATION_MASK; - t.invalidate_for_write(first_line); - if last_line != first_line { t.invalidate_for_write(last_line); } - } - } - crate::vmx::store_vector_left(mem, ea, ctx.vr[instr.rs()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvlx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvlx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:254) ── +int InstrEmit_stvlx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) this equals new_value + // we could optimize this to prevent the other load/mask, in that case. + + Value* ea = CalculateEA_0(f, ra, rb); + + Value* vdr = f.LoadVR(vd); + f.StoreVectorLeft(ea, vdr); + return 0; +} ```
**`stvlx128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvlx128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:268`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L268) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:77`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L77) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:422`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L422) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3120-3133`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3120-L3133) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvlx128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:268`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L268) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:262`](../../../crates/sylpheed-ppc/src/opcode.rs#L262) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:537`](../../../crates/sylpheed-ppc/src/decoder.rs#L537) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvlx128 | PpcOpcode::stvlxl128 => { - let ea = ea_indexed(ctx, instr); - // PPCBUG-513: stvlx128/stvlxl128 were missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let first_line = ea & !RESERVATION_MASK; - let last_line = ea.wrapping_add(15) & !RESERVATION_MASK; - t.invalidate_for_write(first_line); - if last_line != first_line { t.invalidate_for_write(last_line); } - } - } - crate::vmx::store_vector_left(mem, ea, ctx.vr[instr.vs128()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvlx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvlx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:254) ── +int InstrEmit_stvlx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) this equals new_value + // we could optimize this to prevent the other load/mask, in that case. + + Value* ea = CalculateEA_0(f, ra, rb); + + Value* vdr = f.LoadVR(vd); + f.StoreVectorLeft(ea, vdr); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stvlxl.md b/tools/ppc-manual/memory/stvlxl.md index e5aef13b..0fc35dba 100644 --- a/tools/ppc-manual/memory/stvlxl.md +++ b/tools/ppc-manual/memory/stvlxl.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,57 +111,66 @@ _No condition-register or status-register effects._ ## Implementation References **`stvlxl`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvlxl"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:271`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L271) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:77`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L77) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:845`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L845) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3103-3119`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3103-L3119) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvlxl"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:271`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L271) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:263`](../../../crates/sylpheed-ppc/src/opcode.rs#L263) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:960`](../../../crates/sylpheed-ppc/src/decoder.rs#L960) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvlx | PpcOpcode::stvlxl => { - let ea = ea_indexed(ctx, instr); - // PPCBUG-513: stvlx/stvlxl were missing invalidate_for_write. - // store_vector_left writes [ea, (ea & !0xF)+15]; in the worst case (ea & 0xF == 0) - // that is exactly 16 bytes all within the same 16-byte block, so ea+15 lands in the - // same 128-byte cache line. Two-call form is kept for defensive correctness. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let first_line = ea & !RESERVATION_MASK; - let last_line = ea.wrapping_add(15) & !RESERVATION_MASK; - t.invalidate_for_write(first_line); - if last_line != first_line { t.invalidate_for_write(last_line); } - } - } - crate::vmx::store_vector_left(mem, ea, ctx.vr[instr.rs()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvlxl(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvlx(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:265) ── +int InstrEmit_stvlx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvlx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:254) ── +int InstrEmit_stvlx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) this equals new_value + // we could optimize this to prevent the other load/mask, in that case. + + Value* ea = CalculateEA_0(f, ra, rb); + + Value* vdr = f.LoadVR(vd); + f.StoreVectorLeft(ea, vdr); + return 0; +} ```
**`stvlxl128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvlxl128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:274`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L274) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:77`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L77) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:426`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L426) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3120-3133`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3120-L3133) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvlxl128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:274`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L274) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:264`](../../../crates/sylpheed-ppc/src/opcode.rs#L264) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:541`](../../../crates/sylpheed-ppc/src/decoder.rs#L541) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvlx128 | PpcOpcode::stvlxl128 => { - let ea = ea_indexed(ctx, instr); - // PPCBUG-513: stvlx128/stvlxl128 were missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let first_line = ea & !RESERVATION_MASK; - let last_line = ea.wrapping_add(15) & !RESERVATION_MASK; - t.invalidate_for_write(first_line); - if last_line != first_line { t.invalidate_for_write(last_line); } - } - } - crate::vmx::store_vector_left(mem, ea, ctx.vr[instr.vs128()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvlxl128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvlx128(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:268) ── +int InstrEmit_stvlx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvlx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:254) ── +int InstrEmit_stvlx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) this equals new_value + // we could optimize this to prevent the other load/mask, in that case. + + Value* ea = CalculateEA_0(f, ra, rb); + + Value* vdr = f.LoadVR(vd); + f.StoreVectorLeft(ea, vdr); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stvrx.md b/tools/ppc-manual/memory/stvrx.md index f900103c..d65eb4f1 100644 --- a/tools/ppc-manual/memory/stvrx.md +++ b/tools/ppc-manual/memory/stvrx.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,57 +111,58 @@ _No condition-register or status-register effects._ ## Implementation References **`stvrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:290`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L290) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:78`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L78) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:833`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L833) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3134-3150`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3134-L3150) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:290`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L290) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:265`](../../../crates/sylpheed-ppc/src/opcode.rs#L265) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:948`](../../../crates/sylpheed-ppc/src/decoder.rs#L948) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvrx | PpcOpcode::stvrxl => { - let ea = ea_indexed(ctx, instr); - // PPCBUG-514: stvrx/stvrxl were missing invalidate_for_write. - // store_vector_right writes [ea & !0xF, ea-1] (up to 15 bytes, all within a single - // 16-byte-aligned block). Two-call form is kept for defensive correctness. - // stvrx at shift==0 is a no-op; the guard fires unconditionally (cheap). - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let first_line = ea & !RESERVATION_MASK; - let last_line = ea.wrapping_add(15) & !RESERVATION_MASK; - t.invalidate_for_write(first_line); - if last_line != first_line { t.invalidate_for_write(last_line); } - } - } - crate::vmx::store_vector_right(mem, ea, ctx.vr[instr.rs()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvrx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvrx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:278) ── +int InstrEmit_stvrx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) then no data is loaded. This is important + // as often times memcpy's will use this to handle the remaining <=16b of a + // buffer, which sometimes may be nothing and hang off the end of the valid + // page area. + Value* ea = CalculateEA_0(f, ra, rb); + + Value* vdr = f.LoadVR(vd); + f.StoreVectorRight(ea, vdr); + return 0; +} ```
**`stvrx128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvrx128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:293`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L293) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:78`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L78) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:423`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L423) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3151-3164`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3151-L3164) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvrx128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:293`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L293) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:266`](../../../crates/sylpheed-ppc/src/opcode.rs#L266) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:538`](../../../crates/sylpheed-ppc/src/decoder.rs#L538) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvrx128 | PpcOpcode::stvrxl128 => { - let ea = ea_indexed(ctx, instr); - // PPCBUG-514: stvrx128/stvrxl128 were missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let first_line = ea & !RESERVATION_MASK; - let last_line = ea.wrapping_add(15) & !RESERVATION_MASK; - t.invalidate_for_write(first_line); - if last_line != first_line { t.invalidate_for_write(last_line); } - } - } - crate::vmx::store_vector_right(mem, ea, ctx.vr[instr.vs128()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvrx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvrx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:278) ── +int InstrEmit_stvrx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) then no data is loaded. This is important + // as often times memcpy's will use this to handle the remaining <=16b of a + // buffer, which sometimes may be nothing and hang off the end of the valid + // page area. + Value* ea = CalculateEA_0(f, ra, rb); + + Value* vdr = f.LoadVR(vd); + f.StoreVectorRight(ea, vdr); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stvrxl.md b/tools/ppc-manual/memory/stvrxl.md index f65d9015..43276fcc 100644 --- a/tools/ppc-manual/memory/stvrxl.md +++ b/tools/ppc-manual/memory/stvrxl.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,57 +111,68 @@ _No condition-register or status-register effects._ ## Implementation References **`stvrxl`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvrxl"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:296`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L296) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:78`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L78) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:848`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L848) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3134-3150`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3134-L3150) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvrxl"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:296`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L296) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:267`](../../../crates/sylpheed-ppc/src/opcode.rs#L267) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:963`](../../../crates/sylpheed-ppc/src/decoder.rs#L963) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvrx | PpcOpcode::stvrxl => { - let ea = ea_indexed(ctx, instr); - // PPCBUG-514: stvrx/stvrxl were missing invalidate_for_write. - // store_vector_right writes [ea & !0xF, ea-1] (up to 15 bytes, all within a single - // 16-byte-aligned block). Two-call form is kept for defensive correctness. - // stvrx at shift==0 is a no-op; the guard fires unconditionally (cheap). - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let first_line = ea & !RESERVATION_MASK; - let last_line = ea.wrapping_add(15) & !RESERVATION_MASK; - t.invalidate_for_write(first_line); - if last_line != first_line { t.invalidate_for_write(last_line); } - } - } - crate::vmx::store_vector_right(mem, ea, ctx.vr[instr.rs()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvrxl(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvrx(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:290) ── +int InstrEmit_stvrx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvrx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:278) ── +int InstrEmit_stvrx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) then no data is loaded. This is important + // as often times memcpy's will use this to handle the remaining <=16b of a + // buffer, which sometimes may be nothing and hang off the end of the valid + // page area. + Value* ea = CalculateEA_0(f, ra, rb); + + Value* vdr = f.LoadVR(vd); + f.StoreVectorRight(ea, vdr); + return 0; +} ```
**`stvrxl128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvrxl128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:299`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L299) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:78`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L78) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:427`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L427) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3151-3164`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3151-L3164) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvrxl128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:299`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L299) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:268`](../../../crates/sylpheed-ppc/src/opcode.rs#L268) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:542`](../../../crates/sylpheed-ppc/src/decoder.rs#L542) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvrx128 | PpcOpcode::stvrxl128 => { - let ea = ea_indexed(ctx, instr); - // PPCBUG-514: stvrx128/stvrxl128 were missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { - let first_line = ea & !RESERVATION_MASK; - let last_line = ea.wrapping_add(15) & !RESERVATION_MASK; - t.invalidate_for_write(first_line); - if last_line != first_line { t.invalidate_for_write(last_line); } - } - } - crate::vmx::store_vector_right(mem, ea, ctx.vr[instr.vs128()]); - ctx.pc += 4; - } +```cpp +int InstrEmit_stvrxl128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvrx128(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:293) ── +int InstrEmit_stvrx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvrx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:278) ── +int InstrEmit_stvrx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + // NOTE: if eb == 0 (so 16b aligned) then no data is loaded. This is important + // as often times memcpy's will use this to handle the remaining <=16b of a + // buffer, which sometimes may be nothing and hang off the end of the valid + // page area. + Value* ea = CalculateEA_0(f, ra, rb); + + Value* vdr = f.LoadVR(vd); + f.StoreVectorRight(ea, vdr); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stvx.md b/tools/ppc-manual/memory/stvx.md index d7fdca1e..16951df5 100644 --- a/tools/ppc-manual/memory/stvx.md +++ b/tools/ppc-manual/memory/stvx.md @@ -100,48 +100,46 @@ mem_write_vec128_be(ea, v[insn.VS]); ## Implementation References **`stvx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:193`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L193) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:79`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L79) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:791`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L791) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1849-1859`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1849-L1859) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:193`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L193) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:269`](../../../crates/sylpheed-ppc/src/opcode.rs#L269) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:906`](../../../crates/sylpheed-ppc/src/decoder.rs#L906) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = (ea.wrapping_add(ctx.gpr[instr.rb()]) & !0xF) as u32; - // PPCBUG-511: stvx was missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { t.invalidate_for_write(ea); } - } - let bytes = ctx.vr[instr.rs()].as_bytes(); - for i in 0..16 { mem.write_u8(ea + i as u32, bytes[i]); } - ctx.pc += 4; - } +```cpp +int InstrEmit_stvx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:187) ── +int InstrEmit_stvx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = f.And(CalculateEA_0(f, ra, rb), f.LoadConstantUint64(~0xFull)); + f.Store(ea, f.ByteSwap(f.LoadVR(vd))); + return 0; +} ```
**`stvx128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvx128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:196`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L196) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:79`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L79) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:417`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L417) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1860-1870`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1860-L1870) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvx128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:196`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L196) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:270`](../../../crates/sylpheed-ppc/src/opcode.rs#L270) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:532`](../../../crates/sylpheed-ppc/src/decoder.rs#L532) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvx128 => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = (ea.wrapping_add(ctx.gpr[instr.rb()]) & !0xF) as u32; - // PPCBUG-511: stvx128 was missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { t.invalidate_for_write(ea); } - } - let bytes = ctx.vr[instr.vs128()].as_bytes(); - for i in 0..16 { mem.write_u8(ea + i as u32, bytes[i]); } - ctx.pc += 4; - } +```cpp +int InstrEmit_stvx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:187) ── +int InstrEmit_stvx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = f.And(CalculateEA_0(f, ra, rb), f.LoadConstantUint64(~0xFull)); + f.Store(ea, f.ByteSwap(f.LoadVR(vd))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stvxl.md b/tools/ppc-manual/memory/stvxl.md index b3affd0d..aa7376e7 100644 --- a/tools/ppc-manual/memory/stvxl.md +++ b/tools/ppc-manual/memory/stvxl.md @@ -84,28 +84,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -113,50 +111,56 @@ _No condition-register or status-register effects._ ## Implementation References **`stvxl`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvxl"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:199`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L199) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:79`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L79) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:813`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L813) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1970-1981`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1970-L1981) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvxl"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:199`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L199) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:271`](../../../crates/sylpheed-ppc/src/opcode.rs#L271) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:928`](../../../crates/sylpheed-ppc/src/decoder.rs#L928) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvxl | PpcOpcode::stvxl128 => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = (ea.wrapping_add(ctx.gpr[instr.rb()]) & !0xF) as u32; - // PPCBUG-511: stvxl/stvxl128 were missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { t.invalidate_for_write(ea); } - } - let vs = if matches!(instr.opcode, PpcOpcode::stvxl128) { instr.vs128() } else { instr.rs() }; - let bytes = ctx.vr[vs].as_bytes(); - for i in 0..16 { mem.write_u8(ea + i as u32, bytes[i]); } - ctx.pc += 4; - } +```cpp +int InstrEmit_stvxl(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvx(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:193) ── +int InstrEmit_stvx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvx_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:187) ── +int InstrEmit_stvx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = f.And(CalculateEA_0(f, ra, rb), f.LoadConstantUint64(~0xFull)); + f.Store(ea, f.ByteSwap(f.LoadVR(vd))); + return 0; +} ```
**`stvxl128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvxl128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:202`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L202) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:79`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L79) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:419`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L419) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1970-1981`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1970-L1981) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stvxl128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:202`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L202) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:272`](../../../crates/sylpheed-ppc/src/opcode.rs#L272) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:534`](../../../crates/sylpheed-ppc/src/decoder.rs#L534) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stvxl | PpcOpcode::stvxl128 => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = (ea.wrapping_add(ctx.gpr[instr.rb()]) & !0xF) as u32; - // PPCBUG-511: stvxl/stvxl128 were missing invalidate_for_write. - if let Some(t) = ctx.reservation_table.as_ref().filter(|t| t.is_enabled()) { - if t.has_active_reservers() { t.invalidate_for_write(ea); } - } - let vs = if matches!(instr.opcode, PpcOpcode::stvxl128) { instr.vs128() } else { instr.rs() }; - let bytes = ctx.vr[vs].as_bytes(); - for i in 0..16 { mem.write_u8(ea + i as u32, bytes[i]); } - ctx.pc += 4; - } +```cpp +int InstrEmit_stvxl128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvx128(f, i); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:196) ── +int InstrEmit_stvx128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_stvx_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:187) ── +int InstrEmit_stvx_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = f.And(CalculateEA_0(f, ra, rb), f.LoadConstantUint64(~0xFull)); + f.Store(ea, f.ByteSwap(f.LoadVR(vd))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stw.md b/tools/ppc-manual/memory/stw.md index 56c6d6e0..42cf5f48 100644 --- a/tools/ppc-manual/memory/stw.md +++ b/tools/ppc-manual/memory/stw.md @@ -147,86 +147,94 @@ mem_write_u32_be(ea, (uint32_t)r[insn.RS]); ## Implementation References **`stw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:507`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L507) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:81`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L81) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:359`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L359) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1291-1299`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1291-L1299) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:507`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L507) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:274`](../../../crates/sylpheed-ppc/src/opcode.rs#L274) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:474`](../../../crates/sylpheed-ppc/src/decoder.rs#L474) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stw => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(instr.d() as i64 as u64) as u32; - 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_u32(ea, ctx.gpr[instr.rs()] as u32); - ctx.pc += 4; - } +```cpp +int InstrEmit_stw(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + EXTS(D) + // MEM(EA, 4) <- (RS)[32:63] + Value* b; + if (i.D.RA == 0) { + b = f.LoadZeroInt64(); + } else { + b = f.LoadGPR(i.D.RA); + } + Value* offset = f.LoadConstantInt64(XEEXTS16(i.D.DS)); + f.StoreOffset(b, offset, + f.ByteSwap(f.Truncate(f.LoadGPR(i.D.RT), INT32_TYPE))); + + return 0; +} ```
**`stwu`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stwu"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:543`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L543) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:81`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L81) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:360`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L360) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1300-1308`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1300-L1308) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stwu"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:543`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L543) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:277`](../../../crates/sylpheed-ppc/src/opcode.rs#L277) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:475`](../../../crates/sylpheed-ppc/src/decoder.rs#L475) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stwu => { - let ea = ctx.gpr[instr.ra()].wrapping_add(instr.d() as i64 as u64) as u32; - 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_u32(ea, ctx.gpr[instr.rs()] as u32); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_stwu(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + EXTS(D) + // MEM(EA, 4) <- (RS)[32:63] + // RA <- EA + Value* ea = CalculateEA_i(f, i.D.RA, XEEXTS16(i.D.DS)); + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.D.RT), INT32_TYPE))); + StoreEA(f, i.D.RA, ea); + return 0; +} ```
**`stwux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stwux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:553`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L553) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:81`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L81) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:787`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L787) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1318-1326`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1318-L1326) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stwux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:553`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L553) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:278`](../../../crates/sylpheed-ppc/src/opcode.rs#L278) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:902`](../../../crates/sylpheed-ppc/src/decoder.rs#L902) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stwux => { - let ea = ctx.gpr[instr.ra()].wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_u32(ea, ctx.gpr[instr.rs()] as u32); - ctx.gpr[instr.ra()] = ea as u64; - ctx.pc += 4; - } +```cpp +int InstrEmit_stwux(PPCHIRBuilder& f, const InstrData& i) { + // EA <- (RA) + (RB) + // MEM(EA, 4) <- (RS)[32:63] + // RA <- EA + Value* ea = CalculateEA(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE))); + StoreEA(f, i.X.RA, ea); + return 0; +} ```
**`stwx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stwx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:563`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L563) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:81`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L81) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:783`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L783) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1309-1317`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1309-L1317) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stwx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:563`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L563) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:279`](../../../crates/sylpheed-ppc/src/opcode.rs#L279) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:898`](../../../crates/sylpheed-ppc/src/decoder.rs#L898) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stwx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_u32(ea, ctx.gpr[instr.rs()] as u32); - ctx.pc += 4; - } +```cpp +int InstrEmit_stwx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 4) <- (RS)[32:63] + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.Store(ea, f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE))); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stwbrx.md b/tools/ppc-manual/memory/stwbrx.md index bb5ab11f..9b995c8c 100644 --- a/tools/ppc-manual/memory/stwbrx.md +++ b/tools/ppc-manual/memory/stwbrx.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,23 +85,24 @@ _No condition-register or status-register effects._ ## Implementation References **`stwbrx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stwbrx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:679`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L679) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:81`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L81) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:831`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L831) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1813-1821`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1813-L1821) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stwbrx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:679`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L679) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:275`](../../../crates/sylpheed-ppc/src/opcode.rs#L275) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:946`](../../../crates/sylpheed-ppc/src/decoder.rs#L946) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stwbrx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - 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_u32(ea, (ctx.gpr[instr.rs()] as u32).swap_bytes()); - ctx.pc += 4; - } +```cpp +int InstrEmit_stwbrx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // MEM(EA, 4) <- bswap((RS)[32:63]) + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + f.Store(ea, f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE)); + return 0; +} ```
diff --git a/tools/ppc-manual/memory/stwcx.md b/tools/ppc-manual/memory/stwcx.md index e287586b..9e1f0a5a 100644 --- a/tools/ppc-manual/memory/stwcx.md +++ b/tools/ppc-manual/memory/stwcx.md @@ -59,28 +59,26 @@ stwcx. [RS], [RA0], [RB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,78 +86,55 @@ stwcx. [RS], [RA0], [RB] ## Implementation References **`stwcx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stwcx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:868`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_memory.cc#L868) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:81`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L81) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:782`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L782) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1225-1288`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1225-L1288) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="stwcx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_memory.cc:868`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_memory.cc#L868) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:276`](../../../crates/sylpheed-ppc/src/opcode.rs#L276) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:897`](../../../crates/sylpheed-ppc/src/decoder.rs#L897) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::stwcx => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]) as u32; - let line = ea & !RESERVATION_MASK; - let table_route = ctx - .reservation_table - .as_ref() - .filter(|t| t.is_enabled()) - .cloned(); - // PPCBUG-151: stwcx. requires a word (lwarx) reservation; - // a doubleword (ldarx) reservation must not commit here. - let width_ok = ctx.reservation_width == 4; - let success = if let Some(t) = &table_route { - // Table-routed: success iff the slot still holds our - // reservation AND the per-ctx flag agrees (the per-ctx - // flag would be cleared by an intervening write or - // context switch). - ctx.has_reservation - && width_ok - && ctx.reserved_line == line - && t.try_commit(ea, ctx.reserved_generation, ctx.hw_id) - } else { - // Legacy per-ctx path (M2 default / lockstep). - // PPCBUG-108: fires on non-primary HW slots under misconfig — - // if the table is disabled while workers are active, slots - // 1..N will trip this assert, surfacing the misconfiguration - // early in debug builds. Note: hw_id==0 (primary slot) taking - // this path while other slots run in parallel would NOT be - // caught; that case requires the table to be enabled instead. - debug_assert!( - ctx.hw_id == 0, - "PPCBUG-108: legacy per-ctx stwcx. on non-primary HW slot \ - (hw_id={}) — ReservationTable must be enabled under --parallel", - ctx.hw_id - ); - ctx.has_reservation && width_ok && ctx.reserved_line == line - }; - if success { - mem.write_u32(ea, ctx.gpr[instr.rs()] as u32); - ctx.cr[0] = crate::context::CrField { - lt: false, - gt: false, - eq: true, - so: ctx.xer_so != 0, - }; - } else { - ctx.cr[0] = crate::context::CrField { - lt: false, - gt: false, - eq: false, - so: ctx.xer_so != 0, - }; - // Failed stwcx: if we held the reservation in the table - // (someone else displaced our gen), release it from the - // counter so `has_active_reservers` returns to zero - // when no real reserver exists. - if let Some(t) = &table_route { - t.release(ea, ctx.reserved_generation, ctx.hw_id); - } - } - ctx.has_reservation = false; - ctx.reservation_width = 0; // PPCBUG-151: always clear on exit - ctx.pc += 4; - } +```cpp +int InstrEmit_stwcx(PPCHIRBuilder& f, const InstrData& i) { + // if RA = 0 then + // b <- 0 + // else + // b <- (RA) + // EA <- b + (RB) + // RESERVE stuff... + // MEM(EA, 4) <- (RS)[32:63] + // n <- 1 if store performed + // CR0[LT GT EQ SO] = 0b00 || n || XER[SO] + + // NOTE: we assume we are within a global lock. + // As we have been exclusively executing this entire time, we assume that no + // one else could have possibly touched the memory and must always succeed. + // We use atomic compare exchange here to support reserved load/store without + // being under the global lock (flag disable_global_lock - see mtmsr/mtmsrd). + // This will always succeed if under the global lock, however. + + Value* ea = CalculateEA_0(f, i.X.RA, i.X.RB); + + Value* rt = f.ByteSwap(f.Truncate(f.LoadGPR(i.X.RT), INT32_TYPE)); + + if (cvars::no_reserved_ops) { + f.Store(ea, rt); + + f.StoreContext(offsetof(PPCContext, cr0.cr0_eq), f.LoadConstantInt8(1)); + } else { + Value* v = f.StoreWithReserve(ea, rt, INT64_TYPE); + f.StoreContext(offsetof(PPCContext, cr0.cr0_eq), v); + } + + f.StoreContext(offsetof(PPCContext, cr0.cr0_lt), f.LoadZeroInt8()); + f.StoreContext(offsetof(PPCContext, cr0.cr0_gt), f.LoadZeroInt8()); + + // Issue memory barrier for when we go out of lock and want others to see our + // updates. + if (!cvars::no_reserved_ops) { + f.MemoryBarrier(); + } + + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/lvsl.md b/tools/ppc-manual/vmx/lvsl.md index 3f5002ef..8fb33c45 100644 --- a/tools/ppc-manual/vmx/lvsl.md +++ b/tools/ppc-manual/vmx/lvsl.md @@ -100,46 +100,50 @@ for (int i = 0; i < 16; ++i) v[insn.VD].b[i] = sh + i; ## Implementation References **`lvsl`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvsl"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:111`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L111) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:46`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L46) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:751`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L751) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2520-2529`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2520-L2529) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvsl"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:111`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L111) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:148`](../../../crates/sylpheed-ppc/src/opcode.rs#L148) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:866`](../../../crates/sylpheed-ppc/src/decoder.rs#L866) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvsl | PpcOpcode::lvsl128 => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]); - let sh = (ea & 0xF) as u8; - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = sh + i as u8; } - let vd = if matches!(instr.opcode, PpcOpcode::lvsl128) { instr.vd128() } else { instr.rd() }; - ctx.vr[vd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvsl(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvsl_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:103) ── +int InstrEmit_lvsl_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = CalculateEA_0(f, ra, rb); + Value* sh = f.Truncate(f.And(ea, f.LoadConstantInt64(0xF)), INT8_TYPE); + Value* v = f.LoadVectorShl(sh); + f.StoreVR(vd, v); + return 0; +} ```
**`lvsl128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvsl128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:114`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L114) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:46`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L46) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:412`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L412) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2520-2529`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2520-L2529) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvsl128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:114`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L114) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:149`](../../../crates/sylpheed-ppc/src/opcode.rs#L149) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:527`](../../../crates/sylpheed-ppc/src/decoder.rs#L527) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvsl | PpcOpcode::lvsl128 => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]); - let sh = (ea & 0xF) as u8; - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = sh + i as u8; } - let vd = if matches!(instr.opcode, PpcOpcode::lvsl128) { instr.vd128() } else { instr.rd() }; - ctx.vr[vd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvsl128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvsl_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:103) ── +int InstrEmit_lvsl_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = CalculateEA_0(f, ra, rb); + Value* sh = f.Truncate(f.And(ea, f.LoadConstantInt64(0xF)), INT8_TYPE); + Value* v = f.LoadVectorShl(sh); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/lvsr.md b/tools/ppc-manual/vmx/lvsr.md index 859ff7b4..ad6a687f 100644 --- a/tools/ppc-manual/vmx/lvsr.md +++ b/tools/ppc-manual/vmx/lvsr.md @@ -91,13 +91,15 @@ for i in 0..15: VD[i] <- 16 − addr_lo + i ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -105,46 +107,50 @@ for i in 0..15: VD[i] <- 16 − addr_lo + i ## Implementation References **`lvsr`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvsr"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:126`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L126) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:46`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L46) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:762`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L762) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2530-2539`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2530-L2539) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvsr"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:126`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L126) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:150`](../../../crates/sylpheed-ppc/src/opcode.rs#L150) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:877`](../../../crates/sylpheed-ppc/src/decoder.rs#L877) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvsr | PpcOpcode::lvsr128 => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]); - let sh = (ea & 0xF) as u8; - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = (16 - sh) + i as u8; } - let vd = if matches!(instr.opcode, PpcOpcode::lvsr128) { instr.vd128() } else { instr.rd() }; - ctx.vr[vd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvsr(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvsr_(f, i, i.X.RT, i.X.RA, i.X.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:118) ── +int InstrEmit_lvsr_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = CalculateEA_0(f, ra, rb); + Value* sh = f.Truncate(f.And(ea, f.LoadConstantInt64(0xF)), INT8_TYPE); + Value* v = f.LoadVectorShr(sh); + f.StoreVR(vd, v); + return 0; +} ```
**`lvsr128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvsr128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:129`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L129) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:46`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L46) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:413`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L413) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2530-2539`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2530-L2539) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="lvsr128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:129`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L129) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:151`](../../../crates/sylpheed-ppc/src/opcode.rs#L151) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:528`](../../../crates/sylpheed-ppc/src/decoder.rs#L528) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::lvsr | PpcOpcode::lvsr128 => { - let ea = if instr.ra() == 0 { 0u64 } else { ctx.gpr[instr.ra()] }; - let ea = ea.wrapping_add(ctx.gpr[instr.rb()]); - let sh = (ea & 0xF) as u8; - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = (16 - sh) + i as u8; } - let vd = if matches!(instr.opcode, PpcOpcode::lvsr128) { instr.vd128() } else { instr.rd() }; - ctx.vr[vd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_lvsr128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_lvsr_(f, i, VX128_1_VD128, i.VX128_1.RA, i.VX128_1.RB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:118) ── +int InstrEmit_lvsr_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t ra, uint32_t rb) { + Value* ea = CalculateEA_0(f, ra, rb); + Value* sh = f.Truncate(f.And(ea, f.LoadConstantInt64(0xF)), INT8_TYPE); + Value* v = f.LoadVectorShr(sh); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vaddcuw.md b/tools/ppc-manual/vmx/vaddcuw.md index 37582b35..bbbae221 100644 --- a/tools/ppc-manual/vmx/vaddcuw.md +++ b/tools/ppc-manual/vmx/vaddcuw.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,25 +84,22 @@ _No condition-register or status-register effects._ ## Implementation References **`vaddcuw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddcuw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:325`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L325) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:89`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L89) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:466`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L466) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3380-3390`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3380-L3390) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddcuw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:325`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L325) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:295`](../../../crates/sylpheed-ppc/src/opcode.rs#L295) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:581`](../../../crates/sylpheed-ppc/src/decoder.rs#L581) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vaddcuw => { - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let (_, c) = a[i].overflowing_add(b[i]); - r[i] = if c { 1 } else { 0 }; - } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vaddcuw(PPCHIRBuilder& f, const InstrData& i) { + Value* sum = f.VectorAdd(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, + ARITHMETIC_UNSIGNED); + Value* overflow = f.VectorCompareUGT(f.LoadVR(i.VX.VA), sum, INT32_TYPE); + Value* carry = + f.VectorShr(overflow, f.LoadConstantVec128(vec128i(31)), INT32_TYPE); + f.StoreVR(i.VX.VD, carry); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vaddfp.md b/tools/ppc-manual/vmx/vaddfp.md index 5059af5a..82f399b7 100644 --- a/tools/ppc-manual/vmx/vaddfp.md +++ b/tools/ppc-manual/vmx/vaddfp.md @@ -101,54 +101,46 @@ for (int i = 0; i < 4; ++i) v[insn.VD].f[i] = v[insn.VA].f[i] + v[insn.VB].f[i]; ## Implementation References **`vaddfp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddfp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:341`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L341) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:89`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L89) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:438`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L438) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1984-1998`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1984-L1998) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddfp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:341`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L341) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:296`](../../../crates/sylpheed-ppc/src/opcode.rs#L296) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:553`](../../../crates/sylpheed-ppc/src/decoder.rs#L553) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vaddfp => { - // PPCBUG-435: VSCR.NJ=1 (Xbox 360 always boots with this set) requires - // flush-to-zero on subnormal inputs and outputs. Canary VMX float - // arithmetic flushes denormals unconditionally. - let a = ctx.vr[instr.ra()].as_f32x4(); - let b = ctx.vr[instr.rb()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { - let ai = vmx::flush_denorm(a[i]); - let bi = vmx::flush_denorm(b[i]); - r[i] = vmx::flush_denorm(ai + bi); - } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vaddfp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vaddfp_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:335) ── +int InstrEmit_vaddfp_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) + (VB) (4 x fp) + Value* v = f.VectorAdd(f.LoadVR(va), f.LoadVR(vb), FLOAT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vaddfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:344`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L344) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:89`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L89) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:610`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L610) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:1999-2011`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L1999-L2011) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:344`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L344) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:297`](../../../crates/sylpheed-ppc/src/opcode.rs#L297) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:725`](../../../crates/sylpheed-ppc/src/decoder.rs#L725) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vaddfp128 => { - // PPCBUG-435: same as vaddfp. - let a = ctx.vr[instr.va128()].as_f32x4(); - let b = ctx.vr[instr.vb128()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { - let ai = vmx::flush_denorm(a[i]); - let bi = vmx::flush_denorm(b[i]); - r[i] = vmx::flush_denorm(ai + bi); - } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vaddfp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vaddfp_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:335) ── +int InstrEmit_vaddfp_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) + (VB) (4 x fp) + Value* v = f.VectorAdd(f.LoadVR(va), f.LoadVR(vb), FLOAT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
@@ -167,7 +159,7 @@ for i in 0..3: ## Special Cases & Edge Conditions - **Lane indexing is big-endian.** Lane 0 is the **most significant** 4 bytes of the 128-bit register (the one that appears at the lowest byte offset after a `stvx`). Xenia's `Vec128::as_f32x4()` already reads lanes in PPC order on x86-64. When writing C that manipulates individual lanes, index `v.f[0]` as "the byte 0..3" of the big-endian layout. -- **Flush-denormals ("NJ") mode.** Altivec is independent of FPSCR — it has its own 2-bit VSCR (`NJ` for non-Java mode + `SAT` sticky-saturation). VMX float operations honour `VSCR[NJ]`: when set (the Xenon boot default), denormal inputs and outputs are flushed to zero. This is **opposite** to the scalar FPU, which has its own non-IEEE bit. Xenia sets `NJ = 1` at context creation ([`context.rs`](../../xenia-rs/crates/xenia-cpu/src/context.rs)). +- **Flush-denormals ("NJ") mode.** Altivec is independent of FPSCR — it has its own 2-bit VSCR (`NJ` for non-Java mode + `SAT` sticky-saturation). VMX float operations honour `VSCR[NJ]`: when set (the Xenon boot default), denormal inputs and outputs are flushed to zero. This is **opposite** to the scalar FPU, which has its own non-IEEE bit. Xenia sets `NJ = 1` at context creation ([`context.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/context.rs)). - **No exception, no trap.** Altivec floats never raise exceptions. NaN inputs produce NaN outputs; `±∞ − ±∞` yields a NaN; there is no VXISI-style status bit. `VSCR[SAT]` is **not** touched by `vaddfp` (it saturates integer ops, not floats). - **Four independent lanes.** Each lane's operation is unaffected by the others. Aliasing between `VA`, `VB`, and `VD` is legal and common (`vaddfp v3, v3, v4`). - **VMX128 sibling (`vaddfp128`).** Semantics identical; only the register encoding differs. VMX128 uses a 7-bit operand ID per source (and destination) built from two or three non-contiguous bit fields — see [`categories/vmx128.md`](../categories/vmx128.md). Any bit pattern encodable as a 32-register VX-form is also encodable as a VMX128 form, so compilers picked the more compact form that reached the needed register range. diff --git a/tools/ppc-manual/vmx/vaddsbs.md b/tools/ppc-manual/vmx/vaddsbs.md index c6040edb..26f38a5c 100644 --- a/tools/ppc-manual/vmx/vaddsbs.md +++ b/tools/ppc-manual/vmx/vaddsbs.md @@ -58,28 +58,26 @@ vaddsbs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,20 @@ vaddsbs [VD], [VA], [VB] ## Implementation References **`vaddsbs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddsbs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:348`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L348) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:89`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L89) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:498`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L498) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3258-3269`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3258-L3269) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddsbs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:348`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L348) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:298`](../../../crates/sylpheed-ppc/src/opcode.rs#L298) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:613`](../../../crates/sylpheed-ppc/src/decoder.rs#L613) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vaddsbs => { - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i8x16(ctx.vr[instr.rb()]); - let mut r = [0i8; 16]; let mut sat = false; - for i in 0..16 { - let (v, s) = crate::vmx::sat_add_i8(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i8x16(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vaddsbs(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAdd(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE, + ARITHMETIC_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -115,7 +107,7 @@ vaddsbs [VD], [VA], [VB] ## Special Cases & Edge Conditions - **Sixteen signed-byte lanes, saturating.** Each `VD[i] = clamp(VA[i] + VB[i], -128, +127)` for `i = 0..15`, with both inputs interpreted as signed `int8`. Lane 0 is the most-significant byte (the byte at the lowest address after `stvx`). -- **`VSCR[SAT]` is sticky-set** when *any* lane saturates — either positively (overflow above `+127`) or negatively (underflow below `-128`). The SAT bit is never cleared by this op; software must use [`mtvscr`](mtvscr.md) to clear it. Xenia routes the OR of per-lane saturation flags into `ctx.set_vscr_sat(true)` exactly when at least one lane clamped (see `crate::vmx::sat_add_i8` in [`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)). +- **`VSCR[SAT]` is sticky-set** when *any* lane saturates — either positively (overflow above `+127`) or negatively (underflow below `-128`). The SAT bit is never cleared by this op; software must use [`mtvscr`](mtvscr.md) to clear it. Xenia routes the OR of per-lane saturation flags into `ctx.set_vscr_sat(true)` exactly when at least one lane clamped (see `crate::vmx::sat_add_i8` in [`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)). - **Compare with the modulo sibling.** [`vaddubm`](vaddubm.md) is bit-pattern-identical to a hypothetical `vaddsbm` and silently wraps without touching `VSCR[SAT]`. Use `vaddsbs` whenever clipping is desired and you need the sticky overflow flag. - **Asymmetric clamp.** `+127 + 1 = +127`; `-128 + (-1) = -128`. Tests that look for "any saturation" should mask both saturation directions. - **No XER side effects.** Altivec never updates `XER[CA]` / `XER[OV]`. The only status bit affected is `VSCR[SAT]`. diff --git a/tools/ppc-manual/vmx/vaddshs.md b/tools/ppc-manual/vmx/vaddshs.md index d42cc41f..57c6f80c 100644 --- a/tools/ppc-manual/vmx/vaddshs.md +++ b/tools/ppc-manual/vmx/vaddshs.md @@ -58,28 +58,26 @@ vaddshs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,20 @@ vaddshs [VD], [VA], [VB] ## Implementation References **`vaddshs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddshs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:356`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L356) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:89`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L89) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:505`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L505) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3306-3317`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3306-L3317) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddshs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:356`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L356) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:299`](../../../crates/sylpheed-ppc/src/opcode.rs#L299) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:620`](../../../crates/sylpheed-ppc/src/decoder.rs#L620) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vaddshs => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let mut r = [0i16; 8]; let mut sat = false; - for i in 0..8 { - let (v, s) = crate::vmx::sat_add_i16(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vaddshs(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAdd(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE, + ARITHMETIC_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -115,7 +107,7 @@ vaddshs [VD], [VA], [VB] ## Special Cases & Edge Conditions - **Eight signed-half lanes, saturating.** Each `VD[i] = clamp(VA[i] + VB[i], -32768, +32767)` for `i = 0..7`, with both inputs interpreted as signed `int16`. Lane 0 (`VD[0..1]` after `stvx`) is the most-significant half. -- **`VSCR[SAT]` is sticky-set** if *any* lane clamps. Once set, it stays set until explicit clear via [`mtvscr`](mtvscr.md). Xenia uses `crate::vmx::sat_add_i16` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)) which returns the per-lane saturation flag; the OR is written back via `ctx.set_vscr_sat(true)`. +- **`VSCR[SAT]` is sticky-set** if *any* lane clamps. Once set, it stays set until explicit clear via [`mtvscr`](mtvscr.md). Xenia uses `crate::vmx::sat_add_i16` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)) which returns the per-lane saturation flag; the OR is written back via `ctx.set_vscr_sat(true)`. - **The modulo counterpart is `vadduhm`.** Modulo add for signed and unsigned halves is bit-identical, so [`vadduhm`](vadduhm.md) covers both when wraparound is wanted; switch to `vaddshs` only when clipping with sign awareness is desired. - **Asymmetric clamp.** `+32767 + 1 = +32767`; `-32768 + (-1) = -32768`. - **Common 16-bit DSP idiom.** Audio mixing and fixed-point colour blending lean heavily on `vaddshs` to combine signed Q15 / Q1.15 quantities without wraparound artefacts. diff --git a/tools/ppc-manual/vmx/vaddsws.md b/tools/ppc-manual/vmx/vaddsws.md index 24ea801e..e692c9bc 100644 --- a/tools/ppc-manual/vmx/vaddsws.md +++ b/tools/ppc-manual/vmx/vaddsws.md @@ -58,28 +58,26 @@ vaddsws [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,20 @@ vaddsws [VD], [VA], [VB] ## Implementation References **`vaddsws`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddsws"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:364`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L364) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:89`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L89) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:512`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L512) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3354-3365`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3354-L3365) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddsws"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:364`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L364) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:300`](../../../crates/sylpheed-ppc/src/opcode.rs#L300) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:627`](../../../crates/sylpheed-ppc/src/decoder.rs#L627) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vaddsws => { - let a = crate::vmx::as_i32x4(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; let mut sat = false; - for i in 0..4 { - let (v, s) = crate::vmx::sat_add_i32(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vaddsws(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAdd(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, + ARITHMETIC_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -115,7 +107,7 @@ vaddsws [VD], [VA], [VB] ## Special Cases & Edge Conditions - **Four signed-word lanes, saturating.** Each `VD[i] = clamp(VA[i] + VB[i], INT32_MIN, INT32_MAX)` for `i = 0..3`. Lane 0 (`VD[0..3]` after `stvx`) is the most-significant word. -- **`VSCR[SAT]` is sticky-set** if any lane clamps. Xenia tracks this through `crate::vmx::sat_add_i32` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)) and ORs the flag into the architectural `VSCR[SAT]`. +- **`VSCR[SAT]` is sticky-set** if any lane clamps. Xenia tracks this through `crate::vmx::sat_add_i32` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)) and ORs the flag into the architectural `VSCR[SAT]`. - **No multi-precision carry.** Unlike [`vaddcuw`](vaddcuw.md), `vaddsws` does not expose a per-lane carry/borrow — a saturated lane simply clips; it does not overflow into the adjacent lane. - **Asymmetric clamp.** `INT32_MAX + 1 = INT32_MAX`; `INT32_MIN + (-1) = INT32_MIN`. - **The modulo sibling is `vadduwm`.** Modulo add for signed and unsigned words is bit-identical; switch to `vaddsws` only when clipping with sign awareness is desired. diff --git a/tools/ppc-manual/vmx/vaddubm.md b/tools/ppc-manual/vmx/vaddubm.md index cf708d57..72cc495e 100644 --- a/tools/ppc-manual/vmx/vaddubm.md +++ b/tools/ppc-manual/vmx/vaddubm.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vaddubm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddubm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:372`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L372) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:90`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L90) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:434`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L434) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3198-3205`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3198-L3205) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddubm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:372`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L372) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:301`](../../../crates/sylpheed-ppc/src/opcode.rs#L301) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:549`](../../../crates/sylpheed-ppc/src/decoder.rs#L549) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vaddubm => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = a[i].wrapping_add(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vaddubm(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAdd(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vaddubs.md b/tools/ppc-manual/vmx/vaddubs.md index e2eaa1d7..40ce79e6 100644 --- a/tools/ppc-manual/vmx/vaddubs.md +++ b/tools/ppc-manual/vmx/vaddubs.md @@ -58,28 +58,26 @@ vaddubs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,27 +85,20 @@ vaddubs [VD], [VA], [VB] ## Implementation References **`vaddubs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddubs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:379`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L379) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:90`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L90) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:475`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L475) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3233-3245`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3233-L3245) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vaddubs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:379`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L379) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:302`](../../../crates/sylpheed-ppc/src/opcode.rs#L302) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:590`](../../../crates/sylpheed-ppc/src/decoder.rs#L590) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vaddubs => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - let mut sat = false; - for i in 0..16 { - let (v, s) = crate::vmx::sat_add_u8(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vaddubs(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAdd(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE, + ARITHMETIC_UNSIGNED | ARITHMETIC_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -116,7 +107,7 @@ vaddubs [VD], [VA], [VB] ## Special Cases & Edge Conditions - **Sixteen unsigned-byte lanes, saturating.** Each `VD[i] = min(VA[i] + VB[i], 0xFF)` for `i = 0..15`. Lane 0 is the most-significant byte after `stvx`. -- **`VSCR[SAT]` is sticky-set** if any lane saturates. Once set, it stays set until [`mtvscr`](mtvscr.md) clears it. Xenia computes this with `crate::vmx::sat_add_u8` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)). +- **`VSCR[SAT]` is sticky-set** if any lane saturates. Once set, it stays set until [`mtvscr`](mtvscr.md) clears it. Xenia computes this with `crate::vmx::sat_add_u8` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)). - **One-sided clamp.** Only the upper bound applies (unsigned add cannot underflow). Distinct from [`vaddsbs`](vaddsbs.md), which clips at both `+127` and `-128`. - **Pixel-blend workhorse.** Common usage is to add two unsigned-byte colour vectors with clamp-to-white at `0xFF`. Saturation behaves the same way as `_mm_adds_epu8` on x86 SSE2 — making it a one-to-one host translation candidate. - **Versus modulo.** [`vaddubm`](vaddubm.md) wraps silently and never touches `VSCR[SAT]`. Use `vaddubs` when overflow indicates "too bright" / "out of range" and you want to flag it sticky. diff --git a/tools/ppc-manual/vmx/vadduhm.md b/tools/ppc-manual/vmx/vadduhm.md index 4f81fd29..eee681cc 100644 --- a/tools/ppc-manual/vmx/vadduhm.md +++ b/tools/ppc-manual/vmx/vadduhm.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vadduhm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vadduhm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:387`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L387) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:90`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L90) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:441`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L441) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3214-3221`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3214-L3221) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vadduhm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:387`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L387) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:303`](../../../crates/sylpheed-ppc/src/opcode.rs#L303) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:556`](../../../crates/sylpheed-ppc/src/decoder.rs#L556) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vadduhm => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = a[i].wrapping_add(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vadduhm(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAdd(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vadduhs.md b/tools/ppc-manual/vmx/vadduhs.md index 17bb1018..2f76297f 100644 --- a/tools/ppc-manual/vmx/vadduhs.md +++ b/tools/ppc-manual/vmx/vadduhs.md @@ -58,28 +58,26 @@ vadduhs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,20 @@ vadduhs [VD], [VA], [VB] ## Implementation References **`vadduhs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vadduhs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:394`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L394) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:90`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L90) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:482`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L482) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3282-3293`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3282-L3293) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vadduhs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:394`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L394) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:304`](../../../crates/sylpheed-ppc/src/opcode.rs#L304) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:597`](../../../crates/sylpheed-ppc/src/decoder.rs#L597) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vadduhs => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; let mut sat = false; - for i in 0..8 { - let (v, s) = crate::vmx::sat_add_u16(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vadduhs(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAdd(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE, + ARITHMETIC_UNSIGNED | ARITHMETIC_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -115,7 +107,7 @@ vadduhs [VD], [VA], [VB] ## Special Cases & Edge Conditions - **Eight unsigned-half lanes, saturating.** Each `VD[i] = min(VA[i] + VB[i], 0xFFFF)` for `i = 0..7`. Lane 0 (`VD[0..1]` after `stvx`) is the most-significant half. -- **`VSCR[SAT]` is sticky-set** if any lane clamps. Cleared only by [`mtvscr`](mtvscr.md). Xenia uses `crate::vmx::sat_add_u16` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)) and ORs the per-lane flag. +- **`VSCR[SAT]` is sticky-set** if any lane clamps. Cleared only by [`mtvscr`](mtvscr.md). Xenia uses `crate::vmx::sat_add_u16` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)) and ORs the per-lane flag. - **One-sided clamp.** Unsigned add cannot underflow, so only the upper bound `0xFFFF` ever clips. - **The modulo counterpart is `vadduhm`.** Use `vadduhs` when "too large to fit" must be flagged or clipped — typical for accumulating Q16 unsigned counters. - **No XER side effects.** diff --git a/tools/ppc-manual/vmx/vadduwm.md b/tools/ppc-manual/vmx/vadduwm.md index 363e1c5b..ec934eef 100644 --- a/tools/ppc-manual/vmx/vadduwm.md +++ b/tools/ppc-manual/vmx/vadduwm.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vadduwm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vadduwm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:402`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L402) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:90`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L90) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:448`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L448) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2396-2403`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2396-L2403) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vadduwm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:402`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L402) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:305`](../../../crates/sylpheed-ppc/src/opcode.rs#L305) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:563`](../../../crates/sylpheed-ppc/src/decoder.rs#L563) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vadduwm => { - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i].wrapping_add(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vadduwm(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAdd(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vadduws.md b/tools/ppc-manual/vmx/vadduws.md index cb20ad49..6290ea66 100644 --- a/tools/ppc-manual/vmx/vadduws.md +++ b/tools/ppc-manual/vmx/vadduws.md @@ -58,28 +58,26 @@ vadduws [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,20 @@ vadduws [VD], [VA], [VB] ## Implementation References **`vadduws`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vadduws"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:409`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L409) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:90`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L90) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:489`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L489) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3330-3341`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3330-L3341) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vadduws"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:409`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L409) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:306`](../../../crates/sylpheed-ppc/src/opcode.rs#L306) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:604`](../../../crates/sylpheed-ppc/src/decoder.rs#L604) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vadduws => { - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; let mut sat = false; - for i in 0..4 { - let (v, s) = crate::vmx::sat_add_u32(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vadduws(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAdd(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, + ARITHMETIC_UNSIGNED | ARITHMETIC_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -115,7 +107,7 @@ vadduws [VD], [VA], [VB] ## Special Cases & Edge Conditions - **Four unsigned-word lanes, saturating.** Each `VD[i] = min(VA[i] + VB[i], 0xFFFF_FFFF)` for `i = 0..3`. Lane 0 (`VD[0..3]` after `stvx`) is the most-significant word. -- **`VSCR[SAT]` is sticky-set** if any lane clamps. Cleared only via [`mtvscr`](mtvscr.md). Xenia uses `crate::vmx::sat_add_u32` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)). +- **`VSCR[SAT]` is sticky-set** if any lane clamps. Cleared only via [`mtvscr`](mtvscr.md). Xenia uses `crate::vmx::sat_add_u32` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)). - **One-sided clamp** at `UINT32_MAX`. There is no underflow path for unsigned add. - **The modulo counterpart is `vadduwm`.** Use `vadduws` only when overflow needs to be visible / clamped; otherwise the modulo form is one cycle and never touches the sticky bit. - **No XER side effects, no carry exposure.** Unlike `vadduwm + vaddcuw`, the saturating form does **not** make the carry available — it is fused into the clamp. diff --git a/tools/ppc-manual/vmx/vand.md b/tools/ppc-manual/vmx/vand.md index 42d3096b..d3af20f7 100644 --- a/tools/ppc-manual/vmx/vand.md +++ b/tools/ppc-manual/vmx/vand.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,44 +114,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vand`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vand"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:423`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L423) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:91`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L91) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:521`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L521) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2208-2216`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2208-L2216) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vand"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:423`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L423) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:307`](../../../crates/sylpheed-ppc/src/opcode.rs#L307) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:636`](../../../crates/sylpheed-ppc/src/decoder.rs#L636) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vand | PpcOpcode::vand128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i] & b[i]; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vand(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vand_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:417) ── +int InstrEmit_vand_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) & (VB) + Value* v = f.And(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
**`vand128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vand128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:426`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L426) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:91`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L91) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:619`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L619) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2208-2216`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2208-L2216) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vand128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:426`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L426) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:308`](../../../crates/sylpheed-ppc/src/opcode.rs#L308) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:734`](../../../crates/sylpheed-ppc/src/decoder.rs#L734) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vand | PpcOpcode::vand128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i] & b[i]; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vand128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vand_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:417) ── +int InstrEmit_vand_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) & (VB) + Value* v = f.And(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
@@ -166,7 +166,7 @@ _No condition-register or status-register effects._ - **Common usage with compares.** Compare ops produce per-lane all-ones / all-zero masks; `vand` with the mask selects the matching lanes (clearing the rest). For "select-by-mask" with a non-zero alternative use [`vsel`](vsel.md) instead. - **Idiom: clear lanes.** `vand VD, VD, vZero` zeroes a register; in practice [`vxor VD, VD, VD`](vxor.md) is preferred since it doesn't need a zero-vector source. - **Aliasing legal.** All three operands may overlap. -- **VMX128 sibling (`vand128`).** Identical semantics with the extended 128-register encoding; xenia reuses one match arm via the `vmx_reg_triple` helper (see [`crates/xenia-cpu/src/interpreter.rs`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs)). +- **VMX128 sibling (`vand128`).** Identical semantics with the extended 128-register encoding; xenia reuses one match arm via the `vmx_reg_triple` helper (see [`crates/xenia-cpu/src/interpreter.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). ## Related Instructions diff --git a/tools/ppc-manual/vmx/vandc.md b/tools/ppc-manual/vmx/vandc.md index 430a38a0..015fa54c 100644 --- a/tools/ppc-manual/vmx/vandc.md +++ b/tools/ppc-manual/vmx/vandc.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,44 +114,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vandc`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vandc"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:436`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L436) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:91`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L91) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:526`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L526) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2217-2225`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2217-L2225) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vandc"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:436`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L436) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:309`](../../../crates/sylpheed-ppc/src/opcode.rs#L309) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:641`](../../../crates/sylpheed-ppc/src/decoder.rs#L641) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vandc | PpcOpcode::vandc128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i] & !b[i]; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vandc(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vandc_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:430) ── +int InstrEmit_vandc_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) & ¬(VB) + Value* v = f.AndNot(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
**`vandc128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vandc128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:439`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L439) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:91`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L91) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:621`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L621) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2217-2225`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2217-L2225) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vandc128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:439`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L439) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:310`](../../../crates/sylpheed-ppc/src/opcode.rs#L310) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:736`](../../../crates/sylpheed-ppc/src/decoder.rs#L736) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vandc | PpcOpcode::vandc128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i] & !b[i]; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vandc128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vandc_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:430) ── +int InstrEmit_vandc_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) & ¬(VB) + Value* v = f.AndNot(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vavgsb.md b/tools/ppc-manual/vmx/vavgsb.md index 2a4db5a3..97402d92 100644 --- a/tools/ppc-manual/vmx/vavgsb.md +++ b/tools/ppc-manual/vmx/vavgsb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vavgsb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavgsb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:443`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L443) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:92`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L92) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:533`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L533) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3410-3417`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3410-L3417) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavgsb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:443`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L443) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:311`](../../../crates/sylpheed-ppc/src/opcode.rs#L311) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:648`](../../../crates/sylpheed-ppc/src/decoder.rs#L648) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vavgsb => { - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i8x16(ctx.vr[instr.rb()]); - let mut r = [0i8; 16]; - for i in 0..16 { r[i] = crate::vmx::avg_i8(a[i], b[i]); } - ctx.vr[instr.rd()] = crate::vmx::from_i8x16(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vavgsb(PPCHIRBuilder& f, const InstrData& i) { + Value* v = + f.VectorAverage(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE, 0); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -111,7 +106,7 @@ _No condition-register or status-register effects._ - **Sixteen signed-byte rounding averages.** Each `VD[i] = (VA[i] + VB[i] + 1) >> 1`, performed in arithmetic *wider* than 8 bits (so the `+1` cannot overflow). The result is then truncated back to `int8` — saturation never triggers because the average of two `int8` values fits in `int8`. Rounding is "round half up toward +∞". - **Big-endian byte lanes.** Lane 0 is the most-significant byte after `stvx`. -- **No `VSCR[SAT]` impact.** Mathematical impossibility — `(a + b + 1) / 2` for `a, b ∈ [-128, 127]` always lies in `[-128, 127]`. Xenia's `crate::vmx::avg_i8` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)) widens to `i16` before the add. +- **No `VSCR[SAT]` impact.** Mathematical impossibility — `(a + b + 1) / 2` for `a, b ∈ [-128, 127]` always lies in `[-128, 127]`. Xenia's `crate::vmx::avg_i8` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)) widens to `i16` before the add. - **No XER side effects.** - **Common usage.** Filtering / decimation passes, motion-compensation half-pel interpolation in older video codecs (the rounding-up bias matches MPEG/H.263 averaging conventions). - **Aliasing legal.** `vavgsb v3, v3, v4` is a typical lowpass-step idiom. diff --git a/tools/ppc-manual/vmx/vavgsh.md b/tools/ppc-manual/vmx/vavgsh.md index 8bfc6e76..302df52c 100644 --- a/tools/ppc-manual/vmx/vavgsh.md +++ b/tools/ppc-manual/vmx/vavgsh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vavgsh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavgsh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:450`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L450) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:92`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L92) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:535`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L535) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3426-3433`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3426-L3433) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavgsh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:450`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L450) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:312`](../../../crates/sylpheed-ppc/src/opcode.rs#L312) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:650`](../../../crates/sylpheed-ppc/src/decoder.rs#L650) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vavgsh => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let mut r = [0i16; 8]; - for i in 0..8 { r[i] = crate::vmx::avg_i16(a[i], b[i]); } - ctx.vr[instr.rd()] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vavgsh(PPCHIRBuilder& f, const InstrData& i) { + Value* v = + f.VectorAverage(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE, 0); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -111,7 +106,7 @@ _No condition-register or status-register effects._ - **Eight signed-half rounding averages.** Each `VD[i] = (VA[i] + VB[i] + 1) >> 1`, computed in 32-bit arithmetic to avoid overflow on the intermediate sum, then truncated back to `int16`. Rounding is half-up toward +∞. - **Big-endian half lanes.** Lane 0 (`VD[0..1]` after `stvx`) is the most-significant half. -- **No `VSCR[SAT]` impact.** The result is always representable in `int16`. Xenia's `crate::vmx::avg_i16` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)) widens to `i32` before adding. +- **No `VSCR[SAT]` impact.** The result is always representable in `int16`. Xenia's `crate::vmx::avg_i16` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)) widens to `i32` before adding. - **No XER side effects.** - **Common usage.** Audio sample interpolation, fixed-point Q15 midpoint filters, video upscaling at 16-bit precision. - **Aliasing legal.** `vavgsh v3, v3, v4` collapses two half-precision streams into one. diff --git a/tools/ppc-manual/vmx/vavgsw.md b/tools/ppc-manual/vmx/vavgsw.md index c5b968a0..d0569584 100644 --- a/tools/ppc-manual/vmx/vavgsw.md +++ b/tools/ppc-manual/vmx/vavgsw.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,23 @@ _No condition-register or status-register effects._ ## Implementation References **`vavgsw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavgsw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:457`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L457) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:92`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L92) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:537`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L537) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3442-3449`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3442-L3449) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavgsw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:457`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L457) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:313`](../../../crates/sylpheed-ppc/src/opcode.rs#L313) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:652`](../../../crates/sylpheed-ppc/src/decoder.rs#L652) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vavgsw => { - let a = crate::vmx::as_i32x4(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; - for i in 0..4 { r[i] = crate::vmx::avg_i32(a[i], b[i]); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vavgsw(PPCHIRBuilder& f, const InstrData& i) { + // do i = 0 to 127 by 32 + // aop = EXTS((VRA)i:i + 31) + // bop = EXTS((VRB)i:i + 31) + // VRTi:i + 31 = Chop((aop + int bop + int 1) >> 1, 32) + Value* v = + f.VectorAverage(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, 0); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -111,7 +110,7 @@ _No condition-register or status-register effects._ - **Four signed-word rounding averages.** Each `VD[i] = (VA[i] + VB[i] + 1) >> 1`, computed in 64-bit arithmetic to avoid intermediate overflow, then truncated back to `int32`. Rounding is half-up toward +∞. - **Big-endian word lanes.** Lane 0 (`VD[0..3]` after `stvx`) is the most-significant word. -- **No `VSCR[SAT]` impact.** The mathematical result always fits in `int32`. Xenia's `crate::vmx::avg_i32` widens to `i64` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)). +- **No `VSCR[SAT]` impact.** The mathematical result always fits in `int32`. Xenia's `crate::vmx::avg_i32` widens to `i64` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)). - **No XER side effects.** - **Aliasing legal.** - **No VMX128 sibling.** diff --git a/tools/ppc-manual/vmx/vavgub.md b/tools/ppc-manual/vmx/vavgub.md index a848a4d5..090765a6 100644 --- a/tools/ppc-manual/vmx/vavgub.md +++ b/tools/ppc-manual/vmx/vavgub.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vavgub`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavgub"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:468`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L468) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:92`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L92) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:520`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L520) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3402-3409`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3402-L3409) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavgub"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:468`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L468) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:314`](../../../crates/sylpheed-ppc/src/opcode.rs#L314) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:635`](../../../crates/sylpheed-ppc/src/decoder.rs#L635) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vavgub => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = crate::vmx::avg_u8(a[i], b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vavgub(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAverage(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -111,7 +106,7 @@ _No condition-register or status-register effects._ - **Sixteen unsigned-byte rounding averages.** Each `VD[i] = (VA[i] + VB[i] + 1) >> 1`, computed in 16-bit arithmetic so the `+1` cannot overflow, then truncated back to `u8`. Rounding is half-up. - **Big-endian byte lanes.** Lane 0 is the most-significant byte after `stvx`. -- **No `VSCR[SAT]` impact.** The result always fits in `u8` (the average of two `u8` values is at most `255`). Xenia uses `crate::vmx::avg_u8` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)). +- **No `VSCR[SAT]` impact.** The result always fits in `u8` (the average of two `u8` values is at most `255`). Xenia uses `crate::vmx::avg_u8` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)). - **Equivalent to `_mm_avg_epu8`** on x86 SSE2 — semantically identical (rounding mode and width match). - **Common usage.** Pixel-blend `(A + B + 1) / 2`, MPEG/H.264 half-pel motion-compensation averaging, downscale filters, alpha midpoint. - **Aliasing legal.** `vavgub v3, v3, v4`. diff --git a/tools/ppc-manual/vmx/vavguh.md b/tools/ppc-manual/vmx/vavguh.md index 7a312108..c37d11a5 100644 --- a/tools/ppc-manual/vmx/vavguh.md +++ b/tools/ppc-manual/vmx/vavguh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vavguh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavguh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:475`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L475) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:92`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L92) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:525`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L525) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3418-3425`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3418-L3425) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavguh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:475`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L475) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:315`](../../../crates/sylpheed-ppc/src/opcode.rs#L315) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:640`](../../../crates/sylpheed-ppc/src/decoder.rs#L640) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vavguh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = crate::vmx::avg_u16(a[i], b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vavguh(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAverage(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -111,7 +106,7 @@ _No condition-register or status-register effects._ - **Eight unsigned-half rounding averages.** Each `VD[i] = (VA[i] + VB[i] + 1) >> 1`, computed in 32-bit arithmetic to avoid the intermediate `+1` overflowing, then truncated to `u16`. Rounding is half-up. - **Big-endian half lanes.** Lane 0 (`VD[0..1]` after `stvx`) is the most-significant half. -- **No `VSCR[SAT]` impact.** The result always fits in `u16`. Xenia uses `crate::vmx::avg_u16` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)). +- **No `VSCR[SAT]` impact.** The result always fits in `u16`. Xenia uses `crate::vmx::avg_u16` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)). - **Equivalent to `_mm_avg_epu16`** on x86 SSE2 — same rounding, same width. - **Common usage.** Higher-precision pixel blending (e.g. RGB565 sums after widening), Q16 unsigned filters. - **Aliasing legal.** diff --git a/tools/ppc-manual/vmx/vavguw.md b/tools/ppc-manual/vmx/vavguw.md index c7264f03..65b77184 100644 --- a/tools/ppc-manual/vmx/vavguw.md +++ b/tools/ppc-manual/vmx/vavguw.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vavguw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavguw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:482`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L482) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:92`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L92) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:530`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L530) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3434-3441`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3434-L3441) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vavguw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:482`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L482) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:316`](../../../crates/sylpheed-ppc/src/opcode.rs#L316) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:645`](../../../crates/sylpheed-ppc/src/decoder.rs#L645) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vavguw => { - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = crate::vmx::avg_u32(a[i], b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vavguw(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorAverage(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
@@ -111,7 +106,7 @@ _No condition-register or status-register effects._ - **Four unsigned-word rounding averages.** Each `VD[i] = (VA[i] + VB[i] + 1) >> 1`, computed in 64-bit arithmetic to avoid intermediate overflow, then truncated to `u32`. Rounding is half-up. - **Big-endian word lanes.** Lane 0 (`VD[0..3]` after `stvx`) is the most-significant word. -- **No `VSCR[SAT]` impact.** The result always fits in `u32`. Xenia uses `crate::vmx::avg_u32` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)). +- **No `VSCR[SAT]` impact.** The result always fits in `u32`. Xenia uses `crate::vmx::avg_u32` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)). - **No SSE2 direct equivalent.** SSE2 only provides `_mm_avg_epu8` and `_mm_avg_epu16`; on x86 hosts xenia has to widen to 64-bit and do the average manually. - **Common usage.** Per-tile counters; midpoint of two 32-bit packed values. - **Aliasing legal.** diff --git a/tools/ppc-manual/vmx/vcfsx.md b/tools/ppc-manual/vmx/vcfsx.md index 17e5adbe..56964085 100644 --- a/tools/ppc-manual/vmx/vcfsx.md +++ b/tools/ppc-manual/vmx/vcfsx.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,29 @@ _No condition-register or status-register effects._ ## Implementation References **`vcfsx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcfsx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:500`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L500) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:93`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L93) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:509`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L509) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4306-4313`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4306-L4313) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcfsx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:500`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L500) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:319`](../../../crates/sylpheed-ppc/src/opcode.rs#L319) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:624`](../../../crates/sylpheed-ppc/src/decoder.rs#L624) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcfsx => { - let uimm = (instr.raw >> 16) & 0x1F; - let b = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = crate::vmx::cvt_i32_to_f32(b[i], uimm); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vcfsx(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcfsx_(f, i.VX.VD, i.VX.VB, i.VX.VA); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:489) ── +int InstrEmit_vcfsx_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb, + uint32_t uimm) { + // (VD) <- float(VB as signed) / 2^uimm + Value* v = f.VectorConvertI2F(f.LoadVR(vb)); + if (uimm) { + float fuimm = std::ldexp(1.0f, -int(uimm)); + v = f.Mul(v, f.Splat(f.LoadConstantFloat32(fuimm), VEC128_TYPE)); + } + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vcfux.md b/tools/ppc-manual/vmx/vcfux.md index e98a343a..15843e28 100644 --- a/tools/ppc-manual/vmx/vcfux.md +++ b/tools/ppc-manual/vmx/vcfux.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,29 @@ _No condition-register or status-register effects._ ## Implementation References **`vcfux`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcfux"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:518`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L518) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:93`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L93) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:502`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L502) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4314-4321`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4314-L4321) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcfux"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:518`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L518) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:320`](../../../crates/sylpheed-ppc/src/opcode.rs#L320) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:617`](../../../crates/sylpheed-ppc/src/decoder.rs#L617) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcfux => { - let uimm = (instr.raw >> 16) & 0x1F; - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = crate::vmx::cvt_u32_to_f32(b[i], uimm); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vcfux(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcfux_(f, i.VX.VD, i.VX.VB, i.VX.VA); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:507) ── +int InstrEmit_vcfux_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb, + uint32_t uimm) { + // (VD) <- float(VB as unsigned) / 2^uimm + Value* v = f.VectorConvertI2F(f.LoadVR(vb), ARITHMETIC_UNSIGNED); + if (uimm) { + float fuimm = std::ldexp(1.0f, -int(uimm)); + v = f.Mul(v, f.Splat(f.LoadConstantFloat32(fuimm), VEC128_TYPE)); + } + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vcmpbfp.md b/tools/ppc-manual/vmx/vcmpbfp.md index 59c2dc47..02b916a1 100644 --- a/tools/ppc-manual/vmx/vcmpbfp.md +++ b/tools/ppc-manual/vmx/vcmpbfp.md @@ -91,28 +91,26 @@ vcmpbfp128[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -120,78 +118,55 @@ vcmpbfp128[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpbfp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpbfp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:583`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L583) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:94`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L94) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:569`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L569) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3822-3847`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3822-L3847) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpbfp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:583`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L583) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:321`](../../../crates/sylpheed-ppc/src/opcode.rs#L321) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:684`](../../../crates/sylpheed-ppc/src/decoder.rs#L684) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpbfp | PpcOpcode::vcmpbfp128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vcmpbfp128); - let (ra, rb, rd) = if is_128 { - (instr.va128(), instr.vb128(), instr.vd128()) - } else { - (instr.ra(), instr.rb(), instr.rd()) - }; - let a = ctx.vr[ra].as_f32x4(); - let b = ctx.vr[rb].as_f32x4(); - let mut r = [0u32; 4]; - let mut any_out = false; - for i in 0..4 { - let mut lane: u32 = 0; - if a[i].is_nan() || b[i].is_nan() || a[i] > b[i] { lane |= 0x8000_0000; any_out = true; } - if a[i].is_nan() || b[i].is_nan() || a[i] < -b[i] { lane |= 0x4000_0000; any_out = true; } - r[i] = lane; - } - let rc = if is_128 { instr.vx128r_rc_bit() } else { instr.vc_rc_bit() }; - if rc { - ctx.cr[6] = crate::context::CrField { - lt: false, gt: false, eq: !any_out, so: false, - }; - } - ctx.vr[rd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpbfp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpbfp_(f, i, i.VXR.VD, i.VXR.VA, i.VXR.VB, i.VXR.Rc); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:561) ── +int InstrEmit_vcmpbfp_(PPCHIRBuilder& f, const InstrData& i, uint32_t vd, + uint32_t va, uint32_t vb, uint32_t rc) { + // if vA or vB are NaN, the 2 high-order bits are set (0xC0000000) + Value* va_value = f.LoadVR(va); + Value* vb_value = f.LoadVR(vb); + Value* gt = f.VectorCompareSGT(va_value, vb_value, FLOAT32_TYPE); + Value* lt = + f.Not(f.VectorCompareSGE(va_value, f.Neg(vb_value), FLOAT32_TYPE)); + Value* v = + f.Or(f.And(gt, f.LoadConstantVec128(vec128i(0x80000000, 0x80000000, + 0x80000000, 0x80000000))), + f.And(lt, f.LoadConstantVec128(vec128i(0x40000000, 0x40000000, + 0x40000000, 0x40000000)))); + f.StoreVR(vd, v); + if (rc) { + // CR0:4 = 0; CR0:5 = VT == 0; CR0:6 = CR0:7 = 0; + // If all of the elements are within bounds, CR6[2] is set + // FIXME: Does not affect CR6[0], but the following function does. + f.UpdateCR6(f.Or(gt, lt)); + } + return 0; +} ```
**`vcmpbfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpbfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:586`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L586) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:94`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L94) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:684`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L684) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3822-3847`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3822-L3847) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpbfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:586`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L586) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:322`](../../../crates/sylpheed-ppc/src/opcode.rs#L322) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:799`](../../../crates/sylpheed-ppc/src/decoder.rs#L799) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpbfp | PpcOpcode::vcmpbfp128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vcmpbfp128); - let (ra, rb, rd) = if is_128 { - (instr.va128(), instr.vb128(), instr.vd128()) - } else { - (instr.ra(), instr.rb(), instr.rd()) - }; - let a = ctx.vr[ra].as_f32x4(); - let b = ctx.vr[rb].as_f32x4(); - let mut r = [0u32; 4]; - let mut any_out = false; - for i in 0..4 { - let mut lane: u32 = 0; - if a[i].is_nan() || b[i].is_nan() || a[i] > b[i] { lane |= 0x8000_0000; any_out = true; } - if a[i].is_nan() || b[i].is_nan() || a[i] < -b[i] { lane |= 0x4000_0000; any_out = true; } - r[i] = lane; - } - let rc = if is_128 { instr.vx128r_rc_bit() } else { instr.vc_rc_bit() }; - if rc { - ctx.cr[6] = crate::context::CrField { - lt: false, gt: false, eq: !any_out, so: false, - }; - } - ctx.vr[rd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpbfp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpbfp_(f, i, VX128_R_VD128, VX128_R_VA128, VX128_R_VB128, + i.VX128_R.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vcmpeqfp.md b/tools/ppc-manual/vmx/vcmpeqfp.md index 7c69105d..d7176c7d 100644 --- a/tools/ppc-manual/vmx/vcmpeqfp.md +++ b/tools/ppc-manual/vmx/vcmpeqfp.md @@ -91,28 +91,26 @@ vcmpeqfp128[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -120,48 +118,32 @@ vcmpeqfp128[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpeqfp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpeqfp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:623`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L623) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:94`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L94) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:560`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L560) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2173-2183`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2173-L2183) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpeqfp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:623`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L623) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:323`](../../../crates/sylpheed-ppc/src/opcode.rs#L323) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:675`](../../../crates/sylpheed-ppc/src/decoder.rs#L675) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpeqfp | PpcOpcode::vcmpeqfp128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_f32x4(); - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] == b[i] { 0xFFFF_FFFF } else { 0 }; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - let rc = if matches!(instr.opcode, PpcOpcode::vcmpeqfp128) { instr.vx128r_rc_bit() } else { instr.vc_rc_bit() }; - if rc { update_cr6_from_vmask(&r, ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpeqfp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_eq, i.VXR.VD, i.VXR.VA, i.VXR.VB, + i.VXR.Rc); +} ```
**`vcmpeqfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpeqfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:627`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L627) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:94`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L94) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:681`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L681) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2173-2183`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2173-L2183) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpeqfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:627`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L627) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:324`](../../../crates/sylpheed-ppc/src/opcode.rs#L324) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:796`](../../../crates/sylpheed-ppc/src/decoder.rs#L796) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpeqfp | PpcOpcode::vcmpeqfp128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_f32x4(); - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] == b[i] { 0xFFFF_FFFF } else { 0 }; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - let rc = if matches!(instr.opcode, PpcOpcode::vcmpeqfp128) { instr.vx128r_rc_bit() } else { instr.vc_rc_bit() }; - if rc { update_cr6_from_vmask(&r, ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpeqfp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_eq, VX128_R_VD128, VX128_R_VA128, + VX128_R_VB128, i.VX128_R.Rc); +} ```
@@ -173,7 +155,7 @@ vcmpeqfp128[Rc] [VD], [VA], [VB] - **NaN handling is IEEE-754: never equal.** `NaN == anything` is false (including `NaN == NaN`), so the lane stays zero. This is the standard quiet-compare behaviour — no exception, no sticky flag. - **Sign of zero ignored.** `+0 == -0` per IEEE-754, so the lane is set to all-ones. - **`VSCR[NJ]` — denormals.** With `NJ = 1` (Xenon default), denormal inputs are flushed to `±0` *before* the comparison; `±denormal == ±0` then compares as true. This is one of the few VMX float ops where the NJ flag changes program-visible mask values. -- **CR6 update when `Rc=1`** (`vcmpeqfp.`). CR6 is `{any-true, 0, all-true, 0}` = `[lt = all-true, gt = 0, eq = all-false, so = 0]` in the standard mapping; xenia's `update_cr6_from_vmask` ([`crates/xenia-cpu/src/interpreter.rs`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs)) handles the bit packing. Use `bc 12,24` for "all-equal" branches and `bc 4,26` for "any-equal". +- **CR6 update when `Rc=1`** (`vcmpeqfp.`). CR6 is `{any-true, 0, all-true, 0}` = `[lt = all-true, gt = 0, eq = all-false, so = 0]` in the standard mapping; xenia's `update_cr6_from_vmask` ([`crates/xenia-cpu/src/interpreter.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)) handles the bit packing. Use `bc 12,24` for "all-equal" branches and `bc 4,26` for "any-equal". - **Compose with `vsel`.** Mask drives [`vsel`](vsel.md) to pick between two source vectors per lane. Or combine masks with [`vand`](vand.md) / [`vor`](vor.md) / [`vandc`](vandc.md) to express conjunctions. - **No `VSCR[SAT]`, no XER changes, no traps** — even on signaling NaNs (Altivec's quiet-compare semantics). - **VMX128 sibling (`vcmpeqfp128`).** Identical semantics with the extended 128-register encoding; xenia routes both opcodes to one match arm via `vmx_reg_triple`. diff --git a/tools/ppc-manual/vmx/vcmpequb.md b/tools/ppc-manual/vmx/vcmpequb.md index f7f83a08..c686f2c2 100644 --- a/tools/ppc-manual/vmx/vcmpequb.md +++ b/tools/ppc-manual/vmx/vcmpequb.md @@ -60,28 +60,26 @@ vcmpequb[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,27 +87,17 @@ vcmpequb[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpequb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpequb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:719`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L719) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:95`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L95) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:557`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L557) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3723-3735`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3723-L3735) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpequb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:719`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L719) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:325`](../../../crates/sylpheed-ppc/src/opcode.rs#L325) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:672`](../../../crates/sylpheed-ppc/src/decoder.rs#L672) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpequb => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = if a[i] == b[i] { 0xFF } else { 0 }; } - let v = xenia_types::Vec128::from_bytes(r); - if instr.vc_rc_bit() { - let (t, f) = crate::vmx::cr6_flags_from_mask(v); - ctx.cr[6] = crate::context::CrField { lt: t, gt: false, eq: f, so: false }; - } - ctx.vr[instr.rd()] = v; - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpequb(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_eq, 1, i.VXR.VD, i.VXR.VA, i.VXR.VB, + i.VXR.Rc); +} ```
@@ -119,7 +107,7 @@ vcmpequb[Rc] [VD], [VA], [VB] - **Per-byte mask: all-ones / all-zero.** Sixteen byte lanes; `VD[i] = (VA[i] == VB[i]) ? 0xFF : 0x00`. Lane 0 is the most-significant byte after `stvx`. - **Sign-agnostic.** Equality compare is identical for signed and unsigned bytes; there is no separate `vcmpeqsb`. -- **CR6 update when `Rc=1`** (`vcmpequb.`). CR6 = `[lt = all-true, gt = 0, eq = all-false, so = 0]` — built by xenia's `crate::vmx::cr6_flags_from_mask` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)). Standard SIMD-search idiom: `vcmpequb. vMask, vData, vNeedle` then `bc 12,26` to branch when *no* lane matched. +- **CR6 update when `Rc=1`** (`vcmpequb.`). CR6 = `[lt = all-true, gt = 0, eq = all-false, so = 0]` — built by xenia's `crate::vmx::cr6_flags_from_mask` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)). Standard SIMD-search idiom: `vcmpequb. vMask, vData, vNeedle` then `bc 12,26` to branch when *no* lane matched. - **Compose with `vsel`.** Mask drives [`vsel`](vsel.md) to pick per-byte between two source vectors. - **Common usage.** `memchr` / `strlen` / character classification — compare against a broadcast byte (often built with [`vspltisb`](vspltisb.md)) and inspect CR6 for early-out. - **No `VSCR` interaction, no XER, no traps.** diff --git a/tools/ppc-manual/vmx/vcmpequh.md b/tools/ppc-manual/vmx/vcmpequh.md index ad69a970..f38bf03e 100644 --- a/tools/ppc-manual/vmx/vcmpequh.md +++ b/tools/ppc-manual/vmx/vcmpequh.md @@ -60,28 +60,26 @@ vcmpequh[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,27 +87,17 @@ vcmpequh[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpequh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpequh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:723`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L723) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:95`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L95) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:558`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L558) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3736-3748`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3736-L3748) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpequh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:723`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L723) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:326`](../../../crates/sylpheed-ppc/src/opcode.rs#L326) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:673`](../../../crates/sylpheed-ppc/src/decoder.rs#L673) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpequh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = if a[i] == b[i] { 0xFFFF } else { 0 }; } - let v = xenia_types::Vec128::from_u16x8_array(r); - if instr.vc_rc_bit() { - let (t, f) = crate::vmx::cr6_flags_from_mask(v); - ctx.cr[6] = crate::context::CrField { lt: t, gt: false, eq: f, so: false }; - } - ctx.vr[instr.rd()] = v; - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpequh(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_eq, 2, i.VXR.VD, i.VXR.VA, i.VXR.VB, + i.VXR.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vcmpequw.md b/tools/ppc-manual/vmx/vcmpequw.md index 6c46fd3f..8a0dd496 100644 --- a/tools/ppc-manual/vmx/vcmpequw.md +++ b/tools/ppc-manual/vmx/vcmpequw.md @@ -91,28 +91,26 @@ vcmpequw128[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -120,48 +118,32 @@ vcmpequw128[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpequw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpequw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:727`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L727) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:95`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L95) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:559`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L559) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2542-2552`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2542-L2552) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpequw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:727`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L727) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:327`](../../../crates/sylpheed-ppc/src/opcode.rs#L327) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:674`](../../../crates/sylpheed-ppc/src/decoder.rs#L674) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpequw | PpcOpcode::vcmpequw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] == b[i] { 0xFFFF_FFFF } else { 0 }; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - let rc = if matches!(instr.opcode, PpcOpcode::vcmpequw128) { instr.vx128r_rc_bit() } else { instr.vc_rc_bit() }; - if rc { update_cr6_from_vmask(&r, ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpequw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_eq, 4, i.VXR.VD, i.VXR.VA, i.VXR.VB, + i.VXR.Rc); +} ```
**`vcmpequw128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpequw128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:731`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L731) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:95`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L95) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:685`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L685) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2542-2552`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2542-L2552) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpequw128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:731`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L731) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:328`](../../../crates/sylpheed-ppc/src/opcode.rs#L328) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:800`](../../../crates/sylpheed-ppc/src/decoder.rs#L800) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpequw | PpcOpcode::vcmpequw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] == b[i] { 0xFFFF_FFFF } else { 0 }; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - let rc = if matches!(instr.opcode, PpcOpcode::vcmpequw128) { instr.vx128r_rc_bit() } else { instr.vc_rc_bit() }; - if rc { update_cr6_from_vmask(&r, ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpequw128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_eq, 4, VX128_R_VD128, VX128_R_VA128, + VX128_R_VB128, i.VX128_R.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vcmpgefp.md b/tools/ppc-manual/vmx/vcmpgefp.md index d53b8a6a..a862dad6 100644 --- a/tools/ppc-manual/vmx/vcmpgefp.md +++ b/tools/ppc-manual/vmx/vcmpgefp.md @@ -91,28 +91,26 @@ vcmpgefp128[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -120,48 +118,32 @@ vcmpgefp128[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpgefp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgefp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:631`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L631) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:96`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L96) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:561`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L561) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2184-2194`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2184-L2194) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgefp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:631`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L631) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:329`](../../../crates/sylpheed-ppc/src/opcode.rs#L329) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:676`](../../../crates/sylpheed-ppc/src/decoder.rs#L676) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpgefp | PpcOpcode::vcmpgefp128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_f32x4(); - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] >= b[i] { 0xFFFF_FFFF } else { 0 }; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - let rc = if matches!(instr.opcode, PpcOpcode::vcmpgefp128) { instr.vx128r_rc_bit() } else { instr.vc_rc_bit() }; - if rc { update_cr6_from_vmask(&r, ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpgefp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_ge, i.VXR.VD, i.VXR.VA, i.VXR.VB, + i.VXR.Rc); +} ```
**`vcmpgefp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgefp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:635`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L635) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:96`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L96) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:682`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L682) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2184-2194`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2184-L2194) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgefp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:635`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L635) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:330`](../../../crates/sylpheed-ppc/src/opcode.rs#L330) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:797`](../../../crates/sylpheed-ppc/src/decoder.rs#L797) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpgefp | PpcOpcode::vcmpgefp128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_f32x4(); - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] >= b[i] { 0xFFFF_FFFF } else { 0 }; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - let rc = if matches!(instr.opcode, PpcOpcode::vcmpgefp128) { instr.vx128r_rc_bit() } else { instr.vc_rc_bit() }; - if rc { update_cr6_from_vmask(&r, ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpgefp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_ge, VX128_R_VD128, VX128_R_VA128, + VX128_R_VB128, i.VX128_R.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vcmpgtfp.md b/tools/ppc-manual/vmx/vcmpgtfp.md index f327d056..c96eb614 100644 --- a/tools/ppc-manual/vmx/vcmpgtfp.md +++ b/tools/ppc-manual/vmx/vcmpgtfp.md @@ -91,28 +91,26 @@ vcmpgtfp128[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -120,48 +118,32 @@ vcmpgtfp128[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpgtfp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtfp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:639`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L639) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:96`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L96) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:565`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L565) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2195-2205`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2195-L2205) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtfp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:639`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L639) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:331`](../../../crates/sylpheed-ppc/src/opcode.rs#L331) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:680`](../../../crates/sylpheed-ppc/src/decoder.rs#L680) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpgtfp | PpcOpcode::vcmpgtfp128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_f32x4(); - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] > b[i] { 0xFFFF_FFFF } else { 0 }; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - let rc = if matches!(instr.opcode, PpcOpcode::vcmpgtfp128) { instr.vx128r_rc_bit() } else { instr.vc_rc_bit() }; - if rc { update_cr6_from_vmask(&r, ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpgtfp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_gt, i.VXR.VD, i.VXR.VA, i.VXR.VB, + i.VXR.Rc); +} ```
**`vcmpgtfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:643`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L643) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:96`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L96) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:683`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L683) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2195-2205`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2195-L2205) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:643`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L643) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:332`](../../../crates/sylpheed-ppc/src/opcode.rs#L332) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:798`](../../../crates/sylpheed-ppc/src/decoder.rs#L798) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpgtfp | PpcOpcode::vcmpgtfp128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_f32x4(); - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] > b[i] { 0xFFFF_FFFF } else { 0 }; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - let rc = if matches!(instr.opcode, PpcOpcode::vcmpgtfp128) { instr.vx128r_rc_bit() } else { instr.vc_rc_bit() }; - if rc { update_cr6_from_vmask(&r, ctx); } - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpgtfp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxfp_(f, i, vcmpxxfp_gt, VX128_R_VD128, VX128_R_VA128, + VX128_R_VB128, i.VX128_R.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vcmpgtsb.md b/tools/ppc-manual/vmx/vcmpgtsb.md index 82784a40..11f0d923 100644 --- a/tools/ppc-manual/vmx/vcmpgtsb.md +++ b/tools/ppc-manual/vmx/vcmpgtsb.md @@ -60,28 +60,26 @@ vcmpgtsb[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,27 +87,17 @@ vcmpgtsb[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpgtsb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtsb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:735`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L735) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:97`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L97) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:566`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L566) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3762-3774`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3762-L3774) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtsb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:735`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L735) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:333`](../../../crates/sylpheed-ppc/src/opcode.rs#L333) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:681`](../../../crates/sylpheed-ppc/src/decoder.rs#L681) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpgtsb => { - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i8x16(ctx.vr[instr.rb()]); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = if a[i] > b[i] { 0xFF } else { 0 }; } - let v = xenia_types::Vec128::from_bytes(r); - if instr.vc_rc_bit() { - let (t, f) = crate::vmx::cr6_flags_from_mask(v); - ctx.cr[6] = crate::context::CrField { lt: t, gt: false, eq: f, so: false }; - } - ctx.vr[instr.rd()] = v; - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpgtsb(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_signed, 1, i.VXR.VD, i.VXR.VA, + i.VXR.VB, i.VXR.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vcmpgtsh.md b/tools/ppc-manual/vmx/vcmpgtsh.md index 4f805a03..58801da8 100644 --- a/tools/ppc-manual/vmx/vcmpgtsh.md +++ b/tools/ppc-manual/vmx/vcmpgtsh.md @@ -60,28 +60,26 @@ vcmpgtsh[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,27 +87,17 @@ vcmpgtsh[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpgtsh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtsh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:739`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L739) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:97`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L97) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:567`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L567) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3788-3800`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3788-L3800) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtsh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:739`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L739) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:334`](../../../crates/sylpheed-ppc/src/opcode.rs#L334) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:682`](../../../crates/sylpheed-ppc/src/decoder.rs#L682) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpgtsh => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = if a[i] > b[i] { 0xFFFF } else { 0 }; } - let v = xenia_types::Vec128::from_u16x8_array(r); - if instr.vc_rc_bit() { - let (t, f) = crate::vmx::cr6_flags_from_mask(v); - ctx.cr[6] = crate::context::CrField { lt: t, gt: false, eq: f, so: false }; - } - ctx.vr[instr.rd()] = v; - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpgtsh(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_signed, 2, i.VXR.VD, i.VXR.VA, + i.VXR.VB, i.VXR.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vcmpgtsw.md b/tools/ppc-manual/vmx/vcmpgtsw.md index f3713d71..ddf2d918 100644 --- a/tools/ppc-manual/vmx/vcmpgtsw.md +++ b/tools/ppc-manual/vmx/vcmpgtsw.md @@ -60,28 +60,26 @@ vcmpgtsw[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,24 +87,17 @@ vcmpgtsw[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpgtsw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtsw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:743`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L743) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:97`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L97) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:568`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L568) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3811-3820`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3811-L3820) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtsw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:743`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L743) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:335`](../../../crates/sylpheed-ppc/src/opcode.rs#L335) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:683`](../../../crates/sylpheed-ppc/src/decoder.rs#L683) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpgtsw => { - let a = crate::vmx::as_i32x4(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] > b[i] { 0xFFFFFFFF } else { 0 }; } - let v = xenia_types::Vec128::from_u32x4_array(r); - if instr.vc_rc_bit() { update_cr6_from_vmask(&r, ctx); } - ctx.vr[instr.rd()] = v; - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpgtsw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_signed, 4, i.VXR.VD, i.VXR.VA, + i.VXR.VB, i.VXR.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vcmpgtub.md b/tools/ppc-manual/vmx/vcmpgtub.md index 0db48830..7a128da2 100644 --- a/tools/ppc-manual/vmx/vcmpgtub.md +++ b/tools/ppc-manual/vmx/vcmpgtub.md @@ -60,28 +60,26 @@ vcmpgtub[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,27 +87,17 @@ vcmpgtub[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpgtub`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtub"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:747`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L747) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:97`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L97) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:562`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L562) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3749-3761`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3749-L3761) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtub"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:747`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L747) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:336`](../../../crates/sylpheed-ppc/src/opcode.rs#L336) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:677`](../../../crates/sylpheed-ppc/src/decoder.rs#L677) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpgtub => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = if a[i] > b[i] { 0xFF } else { 0 }; } - let v = xenia_types::Vec128::from_bytes(r); - if instr.vc_rc_bit() { - let (t, f) = crate::vmx::cr6_flags_from_mask(v); - ctx.cr[6] = crate::context::CrField { lt: t, gt: false, eq: f, so: false }; - } - ctx.vr[instr.rd()] = v; - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpgtub(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_unsigned, 1, i.VXR.VD, i.VXR.VA, + i.VXR.VB, i.VXR.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vcmpgtuh.md b/tools/ppc-manual/vmx/vcmpgtuh.md index 1e5c3e60..06ceb17d 100644 --- a/tools/ppc-manual/vmx/vcmpgtuh.md +++ b/tools/ppc-manual/vmx/vcmpgtuh.md @@ -60,28 +60,26 @@ vcmpgtuh[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,27 +87,17 @@ vcmpgtuh[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpgtuh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtuh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:751`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L751) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:97`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L97) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:563`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L563) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3775-3787`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3775-L3787) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtuh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:751`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L751) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:337`](../../../crates/sylpheed-ppc/src/opcode.rs#L337) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:678`](../../../crates/sylpheed-ppc/src/decoder.rs#L678) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpgtuh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = if a[i] > b[i] { 0xFFFF } else { 0 }; } - let v = xenia_types::Vec128::from_u16x8_array(r); - if instr.vc_rc_bit() { - let (t, f) = crate::vmx::cr6_flags_from_mask(v); - ctx.cr[6] = crate::context::CrField { lt: t, gt: false, eq: f, so: false }; - } - ctx.vr[instr.rd()] = v; - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpgtuh(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_unsigned, 2, i.VXR.VD, i.VXR.VA, + i.VXR.VB, i.VXR.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vcmpgtuw.md b/tools/ppc-manual/vmx/vcmpgtuw.md index a7dd19cf..94aea977 100644 --- a/tools/ppc-manual/vmx/vcmpgtuw.md +++ b/tools/ppc-manual/vmx/vcmpgtuw.md @@ -60,28 +60,26 @@ vcmpgtuw[Rc] [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,24 +87,17 @@ vcmpgtuw[Rc] [VD], [VA], [VB] ## Implementation References **`vcmpgtuw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtuw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:755`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L755) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:97`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L97) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:564`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L564) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3801-3810`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3801-L3810) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcmpgtuw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:755`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L755) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:338`](../../../crates/sylpheed-ppc/src/opcode.rs#L338) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:679`](../../../crates/sylpheed-ppc/src/decoder.rs#L679) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcmpgtuw => { - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] > b[i] { 0xFFFFFFFF } else { 0 }; } - let v = xenia_types::Vec128::from_u32x4_array(r); - if instr.vc_rc_bit() { update_cr6_from_vmask(&r, ctx); } - ctx.vr[instr.rd()] = v; - ctx.pc += 4; - } +```cpp +int InstrEmit_vcmpgtuw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcmpxxi_(f, i, vcmpxxi_gt_unsigned, 4, i.VXR.VD, i.VXR.VA, + i.VXR.VB, i.VXR.Rc); +} ```
diff --git a/tools/ppc-manual/vmx/vctsxs.md b/tools/ppc-manual/vmx/vctsxs.md index af958e8b..1edb1d51 100644 --- a/tools/ppc-manual/vmx/vctsxs.md +++ b/tools/ppc-manual/vmx/vctsxs.md @@ -58,28 +58,26 @@ vctsxs [VD], [VB], [UIMM] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,29 @@ vctsxs [VD], [VB], [UIMM] ## Implementation References **`vctsxs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vctsxs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:536`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L536) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:98`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L98) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:517`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L517) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4281-4292`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4281-L4292) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vctsxs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:536`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L536) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:340`](../../../crates/sylpheed-ppc/src/opcode.rs#L340) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:632`](../../../crates/sylpheed-ppc/src/decoder.rs#L632) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vctsxs => { - let uimm = (instr.raw >> 16) & 0x1F; - let b = ctx.vr[instr.rb()].as_f32x4(); - let mut r = [0i32; 4]; let mut sat = false; - for i in 0..4 { - let (v, s) = crate::vmx::cvt_f32_to_i32_sat(b[i], uimm); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vctsxs(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vctsxs_(f, i.VX.VD, i.VX.VB, i.VX.VA); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:525) ── +int InstrEmit_vctsxs_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb, + uint32_t uimm) { + // (VD) <- int_sat(VB as signed * 2^uimm) + float fuimm = static_cast(std::exp2(uimm)); + Value* v = + f.Mul(f.LoadVR(vb), f.Splat(f.LoadConstantFloat32(fuimm), VEC128_TYPE)); + v = f.VectorConvertF2I(v); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
@@ -115,8 +116,8 @@ vctsxs [VD], [VB], [UIMM] ## Special Cases & Edge Conditions - **Convert IEEE float lane to signed-Q `int32`, saturating.** For each of the four word lanes, `VD[i] = clamp(round_toward_zero(VB[i] * 2^UIMM), INT32_MIN, INT32_MAX)`. The 5-bit `UIMM` (bits 11..15) gives the Q-format fractional shift, in `0..31`. -- **Saturating, not wrapping.** Out-of-range floats clamp to `INT32_MIN` (negative overflow) or `INT32_MAX` (positive overflow) — *not* the wrap-around behaviour of x86 `cvttps2dq` (which produces `0x80000000` on overflow regardless of sign). Xenia's `crate::vmx::cvt_f32_to_i32_sat` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)) handles the difference. -- **NaN → 0.** A NaN input becomes `0` in the output lane and stickies `VSCR[SAT]`. (Many references state "NaN → INT32_MIN"; verify against [`vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs) for the canonical xenia behaviour, which differs from POWER ISA wording.) +- **Saturating, not wrapping.** Out-of-range floats clamp to `INT32_MIN` (negative overflow) or `INT32_MAX` (positive overflow) — *not* the wrap-around behaviour of x86 `cvttps2dq` (which produces `0x80000000` on overflow regardless of sign). Xenia's `crate::vmx::cvt_f32_to_i32_sat` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)) handles the difference. +- **NaN → 0.** A NaN input becomes `0` in the output lane and stickies `VSCR[SAT]`. (Many references state "NaN → INT32_MIN"; verify against [`vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs) for the canonical xenia behaviour, which differs from POWER ISA wording.) - **`VSCR[SAT]` is sticky-set** if any lane saturates (overflow or NaN). Cleared only by [`mtvscr`](mtvscr.md). - **Rounding is truncate-toward-zero.** Always; no per-instruction rounding control. - **`VSCR[NJ]` flushes denormal *inputs* to zero before scaling** (Xenon default). diff --git a/tools/ppc-manual/vmx/vctuxs.md b/tools/ppc-manual/vmx/vctuxs.md index c1ea0250..28cf7146 100644 --- a/tools/ppc-manual/vmx/vctuxs.md +++ b/tools/ppc-manual/vmx/vctuxs.md @@ -58,28 +58,26 @@ vctuxs [VD], [VB], [UIMM] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,29 @@ vctuxs [VD], [VB], [UIMM] ## Implementation References **`vctuxs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vctuxs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:554`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L554) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:98`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L98) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:515`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L515) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4293-4304`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4293-L4304) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vctuxs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:554`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L554) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:341`](../../../crates/sylpheed-ppc/src/opcode.rs#L341) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:630`](../../../crates/sylpheed-ppc/src/decoder.rs#L630) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vctuxs => { - let uimm = (instr.raw >> 16) & 0x1F; - let b = ctx.vr[instr.rb()].as_f32x4(); - let mut r = [0u32; 4]; let mut sat = false; - for i in 0..4 { - let (v, s) = crate::vmx::cvt_f32_to_u32_sat(b[i], uimm); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vctuxs(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vctuxs_(f, i.VX.VD, i.VX.VB, i.VX.VA); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:543) ── +int InstrEmit_vctuxs_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb, + uint32_t uimm) { + // (VD) <- int_sat(VB as unsigned * 2^uimm) + float fuimm = static_cast(std::exp2(uimm)); + Value* v = + f.Mul(f.LoadVR(vb), f.Splat(f.LoadConstantFloat32(fuimm), VEC128_TYPE)); + v = f.VectorConvertF2I(v, ARITHMETIC_UNSIGNED); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
@@ -115,7 +116,7 @@ vctuxs [VD], [VB], [UIMM] ## Special Cases & Edge Conditions - **Convert IEEE float lane to unsigned-Q `uint32`, saturating.** For each of the four word lanes, `VD[i] = clamp(round_toward_zero(VB[i] * 2^UIMM), 0, UINT32_MAX)`. The 5-bit `UIMM` (bits 11..15) gives the Q-format fractional shift, in `0..31`. -- **Saturating, not wrapping.** Negative inputs clamp to `0`; values above `2^32 − 1` clamp to `0xFFFF_FFFF`. NaN → `0`. All clamping events sticky-set `VSCR[SAT]`. Xenia's `crate::vmx::cvt_f32_to_u32_sat` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)) handles the boundaries. +- **Saturating, not wrapping.** Negative inputs clamp to `0`; values above `2^32 − 1` clamp to `0xFFFF_FFFF`. NaN → `0`. All clamping events sticky-set `VSCR[SAT]`. Xenia's `crate::vmx::cvt_f32_to_u32_sat` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)) handles the boundaries. - **`VSCR[SAT]` sticky.** Cleared only by [`mtvscr`](mtvscr.md). - **Rounding is truncate-toward-zero.** Always. - **`VSCR[NJ]` flushes denormal inputs to zero before scaling** (Xenon default). diff --git a/tools/ppc-manual/vmx/vexptefp.md b/tools/ppc-manual/vmx/vexptefp.md index 247c8963..c03ea765 100644 --- a/tools/ppc-manual/vmx/vexptefp.md +++ b/tools/ppc-manual/vmx/vexptefp.md @@ -82,28 +82,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -111,46 +109,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vexptefp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vexptefp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:766`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L766) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:99`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L99) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:469`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L469) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4367-4376`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4367-L4376) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vexptefp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:766`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L766) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:343`](../../../crates/sylpheed-ppc/src/opcode.rs#L343) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:584`](../../../crates/sylpheed-ppc/src/decoder.rs#L584) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vexptefp | PpcOpcode::vexptefp128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vexptefp128); - let (rb, rd) = if is_128 { (instr.vb128(), instr.vd128()) } - else { (instr.rb(), instr.rd()) }; - let b = ctx.vr[rb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].exp2(); } - ctx.vr[rd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vexptefp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vexptefp_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:760) ── +int InstrEmit_vexptefp_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- pow2(VB) + Value* v = f.Pow2(f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
**`vexptefp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vexptefp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:769`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L769) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:99`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L99) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:666`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L666) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4367-4376`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4367-L4376) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vexptefp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:769`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L769) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:344`](../../../crates/sylpheed-ppc/src/opcode.rs#L344) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:781`](../../../crates/sylpheed-ppc/src/decoder.rs#L781) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vexptefp | PpcOpcode::vexptefp128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vexptefp128); - let (rb, rd) = if is_128 { (instr.vb128(), instr.vd128()) } - else { (instr.rb(), instr.rd()) }; - let b = ctx.vr[rb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].exp2(); } - ctx.vr[rd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vexptefp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vexptefp_(f, VX128_3_VD128, VX128_3_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:760) ── +int InstrEmit_vexptefp_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- pow2(VB) + Value* v = f.Pow2(f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vlogefp.md b/tools/ppc-manual/vmx/vlogefp.md index 950ac4d4..c8595f30 100644 --- a/tools/ppc-manual/vmx/vlogefp.md +++ b/tools/ppc-manual/vmx/vlogefp.md @@ -82,28 +82,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -111,46 +109,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vlogefp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vlogefp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:779`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L779) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:99`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L99) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:473`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L473) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4377-4386`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4377-L4386) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vlogefp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:779`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L779) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:345`](../../../crates/sylpheed-ppc/src/opcode.rs#L345) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:588`](../../../crates/sylpheed-ppc/src/decoder.rs#L588) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vlogefp | PpcOpcode::vlogefp128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vlogefp128); - let (rb, rd) = if is_128 { (instr.vb128(), instr.vd128()) } - else { (instr.rb(), instr.rd()) }; - let b = ctx.vr[rb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].log2(); } - ctx.vr[rd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vlogefp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vlogefp_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:773) ── +int InstrEmit_vlogefp_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- log2(VB) + Value* v = f.Log2(f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
**`vlogefp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vlogefp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:782`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L782) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:99`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L99) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:667`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L667) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4377-4386`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4377-L4386) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vlogefp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:782`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L782) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:346`](../../../crates/sylpheed-ppc/src/opcode.rs#L346) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:782`](../../../crates/sylpheed-ppc/src/decoder.rs#L782) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vlogefp | PpcOpcode::vlogefp128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vlogefp128); - let (rb, rd) = if is_128 { (instr.vb128(), instr.vd128()) } - else { (instr.rb(), instr.rd()) }; - let b = ctx.vr[rb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].log2(); } - ctx.vr[rd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vlogefp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vlogefp_(f, VX128_3_VD128, VX128_3_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:773) ── +int InstrEmit_vlogefp_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- log2(VB) + Value* v = f.Log2(f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmaddfp.md b/tools/ppc-manual/vmx/vmaddfp.md index 72fc2312..fdd36e4f 100644 --- a/tools/ppc-manual/vmx/vmaddfp.md +++ b/tools/ppc-manual/vmx/vmaddfp.md @@ -96,13 +96,15 @@ for each 32-bit float lane i in 0..3: ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -110,62 +112,45 @@ for each 32-bit float lane i in 0..3: ## Implementation References **`vmaddfp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaddfp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:801`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L801) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:100`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L100) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:588`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L588) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2038-2054`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2038-L2054) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaddfp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:795`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L795) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:348`](../../../crates/sylpheed-ppc/src/opcode.rs#L348) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:703`](../../../crates/sylpheed-ppc/src/decoder.rs#L703) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaddfp => { - // vD = (vA * vC) + vB. AltiVec unconditionally flushes denormal - // *inputs* to 0 regardless of VSCR[NJ] (confirmed on POWER8 hw). - let a = ctx.vr[instr.ra()].as_f32x4(); - let b = ctx.vr[instr.rb()].as_f32x4(); - let c = ctx.vr[instr.rc()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { - let ai = vmx::flush_denorm(a[i]); - let bi = vmx::flush_denorm(b[i]); - let ci = vmx::flush_denorm(c[i]); - // PPCBUG-437: flush subnormal output too. - r[i] = vmx::flush_denorm(ai.mul_add(ci, bi)); - } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaddfp(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- ((VA) * (VC)) + (VB) + return InstrEmit_vmaddfp_(f, i.VXA.VD, i.VXA.VA, i.VXA.VB, i.VXA.VC); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:786) ── +int InstrEmit_vmaddfp_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb, + uint32_t vc) { + // POWER8 testing showed that vmaddfp flushes denormal inputs to zero + // regardless of NJM. + // (VD) <- ((VA) * (VC)) + (VB) + Value* v = f.MulAdd(f.LoadVR(va), f.LoadVR(vc), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
**`vmaddfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaddfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:805`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L805) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:100`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L100) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:613`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L613) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2055-2073`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2055-L2073) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaddfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:799`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L799) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:349`](../../../crates/sylpheed-ppc/src/opcode.rs#L349) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:728`](../../../crates/sylpheed-ppc/src/decoder.rs#L728) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaddfp128 => { - // ISA: (VD) <- (VA × VD) + VB. VD is both the second multiplicand and destination. - // Canary InstrEmit_vmaddfp128 (ppc_emit_altivec.cc:806-809): MulAdd(VA, VD, VB). - // Previous code computed ai.mul_add(bi, di) = VA×VB+VD — VB and VD roles swapped - // (PPCBUG-424). Fix: ai.mul_add(di, bi) = VA×VD+VB. - let a = ctx.vr[instr.va128()].as_f32x4(); - let b = ctx.vr[instr.vb128()].as_f32x4(); - let d = ctx.vr[instr.vd128()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { - let ai = vmx::flush_denorm(a[i]); - let bi = vmx::flush_denorm(b[i]); - let di = vmx::flush_denorm(d[i]); - // PPCBUG-437. - r[i] = vmx::flush_denorm(ai.mul_add(di, bi)); - } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaddfp128(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- ((VA) * (VB)) + (VD) + // NOTE: this resuses VD and swaps the arg order! + return InstrEmit_vmaddfp_(f, VX128_VD128, VX128_VA128, VX128_VD128, + VX128_VB128); +} ```
@@ -178,7 +163,7 @@ for each 32-bit float lane i in 0..3: - **NaN propagation, ±∞ arithmetic.** Standard IEEE-754: any NaN input yields NaN; `(+∞ * 0)` yields NaN; the sum of `+∞` and `-∞` (e.g. `(+∞ * 1) + -∞`) yields NaN. No trap, no sticky bit. - **`VSCR[NJ]` denormals.** With `NJ = 1` (Xenon default), denormal inputs and outputs are flushed to `±0`. - **No `VSCR[SAT]` change, no XER change, no exceptions.** -- **VMX128 sibling has surprising operand layout — `VD` is also a source.** Xenia's `vmaddfp128` reads `VA`, `VB`, *and `VD` itself* (as the accumulator), computing `VD = (VA * VB) + VD_prev` ([`crates/xenia-cpu/src/interpreter.rs`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs)). The standard `vmaddfp` keeps the canonical 4-operand `VA, VC, VB → VD` shape. **This is a real difference in operand encoding** (VX128_3 form vs. VA-form) that compilers must respect — VMX128 sacrifices the third source register slot for the extra register-file bits. +- **VMX128 sibling has surprising operand layout — `VD` is also a source.** Xenia's `vmaddfp128` reads `VA`, `VB`, *and `VD` itself* (as the accumulator), computing `VD = (VA * VB) + VD_prev` ([`crates/xenia-cpu/src/interpreter.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)). The standard `vmaddfp` keeps the canonical 4-operand `VA, VC, VB → VD` shape. **This is a real difference in operand encoding** (VX128_3 form vs. VA-form) that compilers must respect — VMX128 sacrifices the third source register slot for the extra register-file bits. - **Aliasing legal.** `vmaddfp v3, v3, v3, v3` works (squares + adds itself). - **Common usage.** Per-lane polynomial evaluation, dot-product accumulation, any matrix multiply inner loop. Pair four `vmaddfp` instructions to do a 4×4 × 4-vec multiply. diff --git a/tools/ppc-manual/vmx/vmaxfp.md b/tools/ppc-manual/vmx/vmaxfp.md index 0c188ac0..6f49cbfa 100644 --- a/tools/ppc-manual/vmx/vmaxfp.md +++ b/tools/ppc-manual/vmx/vmaxfp.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,42 +114,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vmaxfp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxfp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:831`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L831) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:101`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L101) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:522`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L522) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2121-2128`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2121-L2128) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxfp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:818`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L818) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:350`](../../../crates/sylpheed-ppc/src/opcode.rs#L350) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:637`](../../../crates/sylpheed-ppc/src/decoder.rs#L637) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaxfp => { - let a = ctx.vr[instr.ra()].as_f32x4(); - let b = ctx.vr[instr.rb()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = vmx::max_nan(a[i], b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaxfp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vmaxfp_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:812) ── +int InstrEmit_vmaxfp_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- max((VA), (VB)) + Value* v = f.Max(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
**`vmaxfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:834`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L834) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:101`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L101) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:696`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L696) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2129-2136`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2129-L2136) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:821`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L821) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:351`](../../../crates/sylpheed-ppc/src/opcode.rs#L351) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:811`](../../../crates/sylpheed-ppc/src/decoder.rs#L811) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaxfp128 => { - let a = ctx.vr[instr.va128()].as_f32x4(); - let b = ctx.vr[instr.vb128()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = vmx::max_nan(a[i], b[i]); } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaxfp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vmaxfp_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:812) ── +int InstrEmit_vmaxfp_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- max((VA), (VB)) + Value* v = f.Max(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmaxsb.md b/tools/ppc-manual/vmx/vmaxsb.md index b94ef148..d802896c 100644 --- a/tools/ppc-manual/vmx/vmaxsb.md +++ b/tools/ppc-manual/vmx/vmaxsb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vmaxsb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxsb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:838`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L838) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:101`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L101) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:454`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L454) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4407-4414`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4407-L4414) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxsb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:825`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L825) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:352`](../../../crates/sylpheed-ppc/src/opcode.rs#L352) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:569`](../../../crates/sylpheed-ppc/src/decoder.rs#L569) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaxsb => { - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i8x16(ctx.vr[instr.rb()]); - let mut r = [0i8; 16]; - for i in 0..16 { r[i] = a[i].max(b[i]); } - ctx.vr[instr.rd()] = crate::vmx::from_i8x16(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaxsb(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- max((VA), (VB)) (signed int8) + Value* v = f.VectorMax(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmaxsh.md b/tools/ppc-manual/vmx/vmaxsh.md index c2c997f3..07ce1fa2 100644 --- a/tools/ppc-manual/vmx/vmaxsh.md +++ b/tools/ppc-manual/vmx/vmaxsh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vmaxsh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxsh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:845`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L845) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:101`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L101) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:460`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L460) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4439-4446`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4439-L4446) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxsh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:832`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L832) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:353`](../../../crates/sylpheed-ppc/src/opcode.rs#L353) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:575`](../../../crates/sylpheed-ppc/src/decoder.rs#L575) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaxsh => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let mut r = [0i16; 8]; - for i in 0..8 { r[i] = a[i].max(b[i]); } - ctx.vr[instr.rd()] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaxsh(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- max((VA), (VB)) (signed int16) + Value* v = f.VectorMax(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmaxsw.md b/tools/ppc-manual/vmx/vmaxsw.md index 6be39fcd..46a220c4 100644 --- a/tools/ppc-manual/vmx/vmaxsw.md +++ b/tools/ppc-manual/vmx/vmaxsw.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vmaxsw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxsw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:852`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L852) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:101`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L101) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:467`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L467) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4471-4478`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4471-L4478) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxsw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:839`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L839) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:354`](../../../crates/sylpheed-ppc/src/opcode.rs#L354) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:582`](../../../crates/sylpheed-ppc/src/decoder.rs#L582) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaxsw => { - let a = crate::vmx::as_i32x4(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; - for i in 0..4 { r[i] = a[i].max(b[i]); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaxsw(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- max((VA), (VB)) (signed int32) + Value* v = f.VectorMax(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmaxub.md b/tools/ppc-manual/vmx/vmaxub.md index 7c145775..c1a60196 100644 --- a/tools/ppc-manual/vmx/vmaxub.md +++ b/tools/ppc-manual/vmx/vmaxub.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vmaxub`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxub"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:859`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L859) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:101`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L101) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:435`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L435) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4391-4398`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4391-L4398) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxub"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:846`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L846) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:355`](../../../crates/sylpheed-ppc/src/opcode.rs#L355) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:550`](../../../crates/sylpheed-ppc/src/decoder.rs#L550) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaxub => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = a[i].max(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaxub(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- max((VA), (VB)) (unsigned int8) + Value* v = f.VectorMax(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmaxuh.md b/tools/ppc-manual/vmx/vmaxuh.md index e6e02204..91494643 100644 --- a/tools/ppc-manual/vmx/vmaxuh.md +++ b/tools/ppc-manual/vmx/vmaxuh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vmaxuh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxuh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:867`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L867) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:101`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L101) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:442`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L442) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4423-4430`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4423-L4430) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxuh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:854`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L854) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:356`](../../../crates/sylpheed-ppc/src/opcode.rs#L356) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:557`](../../../crates/sylpheed-ppc/src/decoder.rs#L557) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaxuh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = a[i].max(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaxuh(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- max((VA), (VB)) (unsigned int16) + Value* v = f.VectorMax(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmaxuw.md b/tools/ppc-manual/vmx/vmaxuw.md index c44300f0..354f51d8 100644 --- a/tools/ppc-manual/vmx/vmaxuw.md +++ b/tools/ppc-manual/vmx/vmaxuw.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vmaxuw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxuw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:875`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L875) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:101`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L101) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:449`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L449) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4455-4462`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4455-L4462) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaxuw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:862`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L862) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:357`](../../../crates/sylpheed-ppc/src/opcode.rs#L357) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:564`](../../../crates/sylpheed-ppc/src/decoder.rs#L564) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaxuw => { - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i].max(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaxuw(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- max((VA), (VB)) (unsigned int32) + Value* v = f.VectorMax(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmhaddshs.md b/tools/ppc-manual/vmx/vmhaddshs.md index 9d1f62fa..d8bfd348 100644 --- a/tools/ppc-manual/vmx/vmhaddshs.md +++ b/tools/ppc-manual/vmx/vmhaddshs.md @@ -60,28 +60,26 @@ vmhaddshs [VD], [VA], [VB], [VC] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,29 +87,17 @@ vmhaddshs [VD], [VA], [VB], [VC] ## Implementation References **`vmhaddshs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmhaddshs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:883`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L883) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:102`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L102) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:576`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L576) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3519-3533`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3519-L3533) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmhaddshs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:870`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L870) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:358`](../../../crates/sylpheed-ppc/src/opcode.rs#L358) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:691`](../../../crates/sylpheed-ppc/src/decoder.rs#L691) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmhaddshs => { - // vD[i] = sat_i16((vA[i] * vB[i]) >> 15 + vC[i]) - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let c = crate::vmx::as_i16x8(ctx.vr[instr.rc()]); - let mut r = [0i16; 8]; let mut sat = false; - for i in 0..8 { - let prod = (a[i] as i32 * b[i] as i32) >> 15; - let (v, s) = crate::vmx::sat_i32_to_i16(prod + c[i] as i32); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmhaddshs(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
@@ -126,7 +112,7 @@ vmhaddshs [VD], [VA], [VB], [VC] ``` The "h" in the mnemonic is "high half" — only the upper 17 bits of the 32-bit signed product survive (after >>15), then the accumulator is added. - **Truncating, not rounding.** Bit 14 of the product is discarded silently. Use [`vmhraddshs`](vmhraddshs.md) when half-up rounding is needed (it adds `0x4000` to the product before the shift). The two are otherwise identical. -- **`VSCR[SAT]` is sticky-set** if `prod + VC[i]` overflows `int16`. Cleared only by [`mtvscr`](mtvscr.md). Xenia uses `crate::vmx::sat_i32_to_i16` ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)). +- **`VSCR[SAT]` is sticky-set** if `prod + VC[i]` overflows `int16`. Cleared only by [`mtvscr`](mtvscr.md). Xenia uses `crate::vmx::sat_i32_to_i16` ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)). - **Pathological case `0x8000 * 0x8000 >> 15`.** Equals `0x10000` in the un-saturated product = `+32768` after the shift, which overflows `int16` even before adding `VC`. The clamp then produces `+32767` and stickies SAT. This is the classic Q15 "minus-one-times-minus-one" gotcha. - **Big-endian half lanes.** Lane 0 is the most-significant half. - **No XER changes, no exceptions.** diff --git a/tools/ppc-manual/vmx/vmhraddshs.md b/tools/ppc-manual/vmx/vmhraddshs.md index 1396b82f..d35f4663 100644 --- a/tools/ppc-manual/vmx/vmhraddshs.md +++ b/tools/ppc-manual/vmx/vmhraddshs.md @@ -60,28 +60,26 @@ vmhraddshs [VD], [VA], [VB], [VC] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,29 +87,17 @@ vmhraddshs [VD], [VA], [VB], [VC] ## Implementation References **`vmhraddshs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmhraddshs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:888`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L888) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:102`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L102) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:577`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L577) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3534-3548`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3534-L3548) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmhraddshs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:875`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L875) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:359`](../../../crates/sylpheed-ppc/src/opcode.rs#L359) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:692`](../../../crates/sylpheed-ppc/src/decoder.rs#L692) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmhraddshs => { - // Rounded multiply-add: (vA[i]*vB[i] + 0x4000) >> 15 + vC[i], saturating. - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let c = crate::vmx::as_i16x8(ctx.vr[instr.rc()]); - let mut r = [0i16; 8]; let mut sat = false; - for i in 0..8 { - let prod = (a[i] as i32 * b[i] as i32 + 0x4000) >> 15; - let (v, s) = crate::vmx::sat_i32_to_i16(prod + c[i] as i32); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmhraddshs(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vminfp.md b/tools/ppc-manual/vmx/vminfp.md index 127aa61b..dcbbed97 100644 --- a/tools/ppc-manual/vmx/vminfp.md +++ b/tools/ppc-manual/vmx/vminfp.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,42 +114,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vminfp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminfp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:899`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L899) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:103`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L103) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:527`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L527) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2137-2144`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2137-L2144) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminfp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:886`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L886) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:360`](../../../crates/sylpheed-ppc/src/opcode.rs#L360) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:642`](../../../crates/sylpheed-ppc/src/decoder.rs#L642) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vminfp => { - let a = ctx.vr[instr.ra()].as_f32x4(); - let b = ctx.vr[instr.rb()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = vmx::min_nan(a[i], b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vminfp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vminfp_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:880) ── +int InstrEmit_vminfp_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- min((VA), (VB)) + Value* v = f.Min(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
**`vminfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:902`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L902) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:103`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L103) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:697`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L697) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2145-2152`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2145-L2152) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:889`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L889) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:361`](../../../crates/sylpheed-ppc/src/opcode.rs#L361) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:812`](../../../crates/sylpheed-ppc/src/decoder.rs#L812) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vminfp128 => { - let a = ctx.vr[instr.va128()].as_f32x4(); - let b = ctx.vr[instr.vb128()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = vmx::min_nan(a[i], b[i]); } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vminfp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vminfp_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:880) ── +int InstrEmit_vminfp_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- min((VA), (VB)) + Value* v = f.Min(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vminsb.md b/tools/ppc-manual/vmx/vminsb.md index bf4598a3..cab575da 100644 --- a/tools/ppc-manual/vmx/vminsb.md +++ b/tools/ppc-manual/vmx/vminsb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vminsb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminsb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:906`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L906) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:103`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L103) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:499`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L499) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4415-4422`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4415-L4422) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminsb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:893`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L893) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:362`](../../../crates/sylpheed-ppc/src/opcode.rs#L362) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:614`](../../../crates/sylpheed-ppc/src/decoder.rs#L614) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vminsb => { - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i8x16(ctx.vr[instr.rb()]); - let mut r = [0i8; 16]; - for i in 0..16 { r[i] = a[i].min(b[i]); } - ctx.vr[instr.rd()] = crate::vmx::from_i8x16(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vminsb(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- min((VA), (VB)) (signed int8) + Value* v = f.VectorMin(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vminsh.md b/tools/ppc-manual/vmx/vminsh.md index 44fa2199..7917d3d5 100644 --- a/tools/ppc-manual/vmx/vminsh.md +++ b/tools/ppc-manual/vmx/vminsh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vminsh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminsh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:913`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L913) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:103`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L103) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:506`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L506) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4447-4454`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4447-L4454) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminsh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:900`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L900) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:363`](../../../crates/sylpheed-ppc/src/opcode.rs#L363) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:621`](../../../crates/sylpheed-ppc/src/decoder.rs#L621) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vminsh => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let mut r = [0i16; 8]; - for i in 0..8 { r[i] = a[i].min(b[i]); } - ctx.vr[instr.rd()] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vminsh(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- min((VA), (VB)) (signed int16) + Value* v = f.VectorMin(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vminsw.md b/tools/ppc-manual/vmx/vminsw.md index 1bfe6efe..c1b55b52 100644 --- a/tools/ppc-manual/vmx/vminsw.md +++ b/tools/ppc-manual/vmx/vminsw.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vminsw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminsw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:920`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L920) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:103`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L103) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:513`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L513) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4479-4486`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4479-L4486) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminsw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:907`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L907) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:364`](../../../crates/sylpheed-ppc/src/opcode.rs#L364) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:628`](../../../crates/sylpheed-ppc/src/decoder.rs#L628) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vminsw => { - let a = crate::vmx::as_i32x4(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; - for i in 0..4 { r[i] = a[i].min(b[i]); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vminsw(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- min((VA), (VB)) (signed int32) + Value* v = f.VectorMin(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vminub.md b/tools/ppc-manual/vmx/vminub.md index 0007edd0..0175e2b6 100644 --- a/tools/ppc-manual/vmx/vminub.md +++ b/tools/ppc-manual/vmx/vminub.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vminub`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminub"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:927`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L927) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:103`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L103) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:476`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L476) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4399-4406`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4399-L4406) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminub"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:914`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L914) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:365`](../../../crates/sylpheed-ppc/src/opcode.rs#L365) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:591`](../../../crates/sylpheed-ppc/src/decoder.rs#L591) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vminub => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = a[i].min(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vminub(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- min((VA), (VB)) (unsigned int8) + Value* v = f.VectorMin(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vminuh.md b/tools/ppc-manual/vmx/vminuh.md index 0fe7632d..2be9adfe 100644 --- a/tools/ppc-manual/vmx/vminuh.md +++ b/tools/ppc-manual/vmx/vminuh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vminuh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminuh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:935`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L935) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:103`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L103) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:483`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L483) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4431-4438`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4431-L4438) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminuh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:922`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L922) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:366`](../../../crates/sylpheed-ppc/src/opcode.rs#L366) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:598`](../../../crates/sylpheed-ppc/src/decoder.rs#L598) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vminuh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = a[i].min(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vminuh(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- min((VA), (VB)) (unsigned int16) + Value* v = f.VectorMin(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vminuw.md b/tools/ppc-manual/vmx/vminuw.md index 2270f303..41f4678f 100644 --- a/tools/ppc-manual/vmx/vminuw.md +++ b/tools/ppc-manual/vmx/vminuw.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vminuw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminuw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:943`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L943) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:103`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L103) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:490`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L490) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4463-4470`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4463-L4470) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vminuw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:930`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L930) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:367`](../../../crates/sylpheed-ppc/src/opcode.rs#L367) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:605`](../../../crates/sylpheed-ppc/src/decoder.rs#L605) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vminuw => { - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i].min(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vminuw(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- min((VA), (VB)) (unsigned int32) + Value* v = f.VectorMin(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmladduhm.md b/tools/ppc-manual/vmx/vmladduhm.md index f8901b70..e65adb36 100644 --- a/tools/ppc-manual/vmx/vmladduhm.md +++ b/tools/ppc-manual/vmx/vmladduhm.md @@ -59,28 +59,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,26 +86,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmladduhm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmladduhm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:951`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L951) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:104`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L104) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:578`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L578) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3549-3560`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3549-L3560) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmladduhm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:938`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L938) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:368`](../../../crates/sylpheed-ppc/src/opcode.rs#L368) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:693`](../../../crates/sylpheed-ppc/src/decoder.rs#L693) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmladduhm => { - // Multiply-low add (modulo): vD[i] = u16(vA[i] * vB[i] + vC[i]). - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let c = ctx.vr[instr.rc()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { - r[i] = a[i].wrapping_mul(b[i]).wrapping_add(c[i]); - } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmladduhm(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmrghb.md b/tools/ppc-manual/vmx/vmrghb.md index 49c7d6c2..5831faad 100644 --- a/tools/ppc-manual/vmx/vmrghb.md +++ b/tools/ppc-manual/vmx/vmrghb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,24 @@ _No condition-register or status-register effects._ ## Implementation References **`vmrghb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrghb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:956`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L956) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:105`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L105) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:439`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L439) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3982-3989`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3982-L3989) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrghb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:943`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L943) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:369`](../../../crates/sylpheed-ppc/src/opcode.rs#L369) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:554`](../../../crates/sylpheed-ppc/src/decoder.rs#L554) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmrghb => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..8 { r[2*i] = a[i]; r[2*i+1] = b[i]; } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmrghb(PPCHIRBuilder& f, const InstrData& i) { + // (VD.b[i]) = (VA.b[i]) + // (VD.b[i+1]) = (VB.b[i+1]) + // ... + Value* v = + f.Permute(f.LoadConstantVec128(vec128b(0, 16, 1, 17, 2, 18, 3, 19, 4, 20, + 5, 21, 6, 22, 7, 23)), + f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmrghh.md b/tools/ppc-manual/vmx/vmrghh.md index d0e2fbd4..998b7623 100644 --- a/tools/ppc-manual/vmx/vmrghh.md +++ b/tools/ppc-manual/vmx/vmrghh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,22 @@ _No condition-register or status-register effects._ ## Implementation References **`vmrghh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrghh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:968`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L968) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:105`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L105) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:446`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L446) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3998-4005`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3998-L4005) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrghh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:955`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L955) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:370`](../../../crates/sylpheed-ppc/src/opcode.rs#L370) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:561`](../../../crates/sylpheed-ppc/src/decoder.rs#L561) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmrghh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..4 { r[2*i] = a[i]; r[2*i+1] = b[i]; } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmrghh(PPCHIRBuilder& f, const InstrData& i) { + // (VD.w[i]) = (VA.w[i]) + // (VD.w[i+1]) = (VB.w[i+1]) + // ... + Value* v = f.Permute(f.LoadConstantVec128(vec128s(0, 8, 1, 9, 2, 10, 3, 11)), + f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmrghw.md b/tools/ppc-manual/vmx/vmrghw.md index 515d6ade..2ed260ea 100644 --- a/tools/ppc-manual/vmx/vmrghw.md +++ b/tools/ppc-manual/vmx/vmrghw.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,42 +114,56 @@ _No condition-register or status-register effects._ ## Implementation References **`vmrghw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrghw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:989`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L989) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:105`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L105) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:451`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L451) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2378-2385`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2378-L2385) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrghw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:976`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L976) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:371`](../../../crates/sylpheed-ppc/src/opcode.rs#L371) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:566`](../../../crates/sylpheed-ppc/src/decoder.rs#L566) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmrghw | PpcOpcode::vmrghw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - // Merge high words: [a0, b0, a1, b1] - ctx.vr[vd] = xenia_types::Vec128::from_u32x4(a[0], b[0], a[1], b[1]); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmrghw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vmrghw_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:965) ── +int InstrEmit_vmrghw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD.x) = (VA.x) + // (VD.y) = (VB.x) + // (VD.z) = (VA.y) + // (VD.w) = (VB.y) + Value* v = + f.Permute(f.LoadConstantUint32(MakePermuteMask(0, 0, 1, 0, 0, 1, 1, 1)), + f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vmrghw128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrghw128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:992`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L992) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:105`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L105) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:698`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L698) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2378-2385`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2378-L2385) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrghw128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:979`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L979) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:372`](../../../crates/sylpheed-ppc/src/opcode.rs#L372) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:813`](../../../crates/sylpheed-ppc/src/decoder.rs#L813) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmrghw | PpcOpcode::vmrghw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - // Merge high words: [a0, b0, a1, b1] - ctx.vr[vd] = xenia_types::Vec128::from_u32x4(a[0], b[0], a[1], b[1]); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmrghw128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vmrghw_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:965) ── +int InstrEmit_vmrghw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD.x) = (VA.x) + // (VD.y) = (VB.x) + // (VD.z) = (VA.y) + // (VD.w) = (VB.y) + Value* v = + f.Permute(f.LoadConstantUint32(MakePermuteMask(0, 0, 1, 0, 0, 1, 1, 1)), + f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmrglb.md b/tools/ppc-manual/vmx/vmrglb.md index 61cfbe7b..5dd63983 100644 --- a/tools/ppc-manual/vmx/vmrglb.md +++ b/tools/ppc-manual/vmx/vmrglb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,24 @@ _No condition-register or status-register effects._ ## Implementation References **`vmrglb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrglb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:996`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L996) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:105`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L105) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:458`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L458) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3990-3997`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3990-L3997) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrglb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:983`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L983) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:373`](../../../crates/sylpheed-ppc/src/opcode.rs#L373) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:573`](../../../crates/sylpheed-ppc/src/decoder.rs#L573) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmrglb => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..8 { r[2*i] = a[8+i]; r[2*i+1] = b[8+i]; } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmrglb(PPCHIRBuilder& f, const InstrData& i) { + // (VD.b[i]) = (VA.b[i]) + // (VD.b[i+1]) = (VB.b[i+1]) + // ... + Value* v = + f.Permute(f.LoadConstantVec128(vec128b(8, 24, 9, 25, 10, 26, 11, 27, 12, + 28, 13, 29, 14, 30, 15, 31)), + f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmrglh.md b/tools/ppc-manual/vmx/vmrglh.md index 2be233f7..9e492fa7 100644 --- a/tools/ppc-manual/vmx/vmrglh.md +++ b/tools/ppc-manual/vmx/vmrglh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,23 @@ _No condition-register or status-register effects._ ## Implementation References **`vmrglh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrglh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1008`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1008) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:105`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L105) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:464`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L464) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4006-4013`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4006-L4013) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrglh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:995`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L995) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:374`](../../../crates/sylpheed-ppc/src/opcode.rs#L374) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:579`](../../../crates/sylpheed-ppc/src/decoder.rs#L579) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmrglh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..4 { r[2*i] = a[4+i]; r[2*i+1] = b[4+i]; } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmrglh(PPCHIRBuilder& f, const InstrData& i) { + // (VD.w[i]) = (VA.w[i]) + // (VD.w[i+1]) = (VB.w[i+1]) + // ... + Value* v = + f.Permute(f.LoadConstantVec128(vec128s(4, 12, 5, 13, 6, 14, 7, 15)), + f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmrglw.md b/tools/ppc-manual/vmx/vmrglw.md index 5b6d6d02..677305e7 100644 --- a/tools/ppc-manual/vmx/vmrglw.md +++ b/tools/ppc-manual/vmx/vmrglw.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,42 +114,56 @@ _No condition-register or status-register effects._ ## Implementation References **`vmrglw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrglw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1030`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1030) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:105`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L105) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:470`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L470) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2386-2393`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2386-L2393) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrglw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1017`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1017) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:375`](../../../crates/sylpheed-ppc/src/opcode.rs#L375) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:585`](../../../crates/sylpheed-ppc/src/decoder.rs#L585) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmrglw | PpcOpcode::vmrglw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - // Merge low words: [a2, b2, a3, b3] - ctx.vr[vd] = xenia_types::Vec128::from_u32x4(a[2], b[2], a[3], b[3]); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmrglw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vmrglw_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1006) ── +int InstrEmit_vmrglw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD.x) = (VA.z) + // (VD.y) = (VB.z) + // (VD.z) = (VA.w) + // (VD.w) = (VB.w) + Value* v = + f.Permute(f.LoadConstantUint32(MakePermuteMask(0, 2, 1, 2, 0, 3, 1, 3)), + f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vmrglw128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrglw128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1033`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1033) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:105`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L105) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:699`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L699) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2386-2393`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2386-L2393) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmrglw128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1020`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1020) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:376`](../../../crates/sylpheed-ppc/src/opcode.rs#L376) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:814`](../../../crates/sylpheed-ppc/src/decoder.rs#L814) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmrglw | PpcOpcode::vmrglw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - // Merge low words: [a2, b2, a3, b3] - ctx.vr[vd] = xenia_types::Vec128::from_u32x4(a[2], b[2], a[3], b[3]); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmrglw128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vmrglw_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1006) ── +int InstrEmit_vmrglw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD.x) = (VA.z) + // (VD.y) = (VB.z) + // (VD.z) = (VA.w) + // (VD.w) = (VB.w) + Value* v = + f.Permute(f.LoadConstantUint32(MakePermuteMask(0, 2, 1, 2, 0, 3, 1, 3)), + f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vmsummbm.md b/tools/ppc-manual/vmx/vmsummbm.md index 353879c2..7bd8e9ba 100644 --- a/tools/ppc-manual/vmx/vmsummbm.md +++ b/tools/ppc-manual/vmx/vmsummbm.md @@ -59,28 +59,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,30 +86,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmsummbm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsummbm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1037`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1037) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:107`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L107) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:580`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L580) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3579-3594`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3579-L3594) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsummbm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1024`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1024) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:379`](../../../crates/sylpheed-ppc/src/opcode.rs#L379) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:695`](../../../crates/sylpheed-ppc/src/decoder.rs#L695) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmsummbm => { - // signed bytes × unsigned bytes, signed accumulator - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let b = ctx.vr[instr.rb()].as_bytes(); - let c = crate::vmx::as_i32x4(ctx.vr[instr.rc()]); - let mut r = [0i32; 4]; - for i in 0..4 { - let mut s = c[i]; - for j in 0..4 { - s = s.wrapping_add(a[4*i+j] as i32 * b[4*i+j] as i32); - } - r[i] = s; - } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmsummbm(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmsumshm.md b/tools/ppc-manual/vmx/vmsumshm.md index 2ac9b6f1..4e09708e 100644 --- a/tools/ppc-manual/vmx/vmsumshm.md +++ b/tools/ppc-manual/vmx/vmsumshm.md @@ -59,28 +59,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,28 +86,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmsumshm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsumshm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1042`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1042) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:107`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L107) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:583`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L583) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3625-3638`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3625-L3638) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsumshm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1029`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1029) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:380`](../../../crates/sylpheed-ppc/src/opcode.rs#L380) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:698`](../../../crates/sylpheed-ppc/src/decoder.rs#L698) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmsumshm => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let c = crate::vmx::as_i32x4(ctx.vr[instr.rc()]); - let mut r = [0i32; 4]; - for i in 0..4 { - let s = (a[2*i] as i32 * b[2*i] as i32) - .wrapping_add(a[2*i+1] as i32 * b[2*i+1] as i32) - .wrapping_add(c[i]); - r[i] = s; - } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmsumshm(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmsumshs.md b/tools/ppc-manual/vmx/vmsumshs.md index 15de23db..9b4eb556 100644 --- a/tools/ppc-manual/vmx/vmsumshs.md +++ b/tools/ppc-manual/vmx/vmsumshs.md @@ -60,28 +60,26 @@ vmsumshs [VD], [VA], [VB], [VC] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,31 +87,17 @@ vmsumshs [VD], [VA], [VB], [VC] ## Implementation References **`vmsumshs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsumshs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1047`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1047) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:107`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L107) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:584`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L584) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3639-3655`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3639-L3655) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsumshs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1034`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1034) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:381`](../../../crates/sylpheed-ppc/src/opcode.rs#L381) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:699`](../../../crates/sylpheed-ppc/src/decoder.rs#L699) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmsumshs => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let c = crate::vmx::as_i32x4(ctx.vr[instr.rc()]); - let mut r = [0i32; 4]; let mut sat = false; - for i in 0..4 { - // Running-sum saturation: accumulate in i64, clamp once at end. - let s = (a[2*i] as i64 * b[2*i] as i64) - + (a[2*i+1] as i64 * b[2*i+1] as i64) - + c[i] as i64; - let (v, o) = crate::vmx::sat_i64_to_i32(s); - r[i] = v; sat |= o; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmsumshs(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
@@ -127,7 +111,7 @@ vmsumshs [VD], [VA], [VB], [VC] + int16(VA[2*i+1]) * int16(VB[2*i+1]), INT32_MIN, INT32_MAX) ``` Two signed-half × signed-half products plus a signed-word accumulator, clamped to `int32`. -- **Wide-then-clamp ordering.** Xenia accumulates into `i64` first and clamps the *final* sum to `int32`, exactly matching the IBM specification ([`crates/xenia-cpu/src/vmx.rs`](../../xenia-rs/crates/xenia-cpu/src/vmx.rs)). This avoids spurious mid-sum saturation that would happen if the products were clamped individually. +- **Wide-then-clamp ordering.** Xenia accumulates into `i64` first and clamps the *final* sum to `int32`, exactly matching the IBM specification ([`crates/xenia-cpu/src/vmx.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/vmx.rs)). This avoids spurious mid-sum saturation that would happen if the products were clamped individually. - **`VSCR[SAT]` is sticky-set** if any of the four lane sums saturates. Cleared only via [`mtvscr`](mtvscr.md). - **Big-endian half lanes.** Lane 0 is the most-significant half. - **No XER, no exceptions.** diff --git a/tools/ppc-manual/vmx/vmsumubm.md b/tools/ppc-manual/vmx/vmsumubm.md index c27bf253..e970418f 100644 --- a/tools/ppc-manual/vmx/vmsumubm.md +++ b/tools/ppc-manual/vmx/vmsumubm.md @@ -59,28 +59,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,29 +86,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmsumubm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsumubm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1052`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1052) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:107`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L107) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:579`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L579) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3564-3578`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3564-L3578) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsumubm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1039`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1039) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:382`](../../../crates/sylpheed-ppc/src/opcode.rs#L382) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:694`](../../../crates/sylpheed-ppc/src/decoder.rs#L694) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmsumubm => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let c = ctx.vr[instr.rc()].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let mut s = c[i]; - for j in 0..4 { - s = s.wrapping_add(a[4*i+j] as u32 * b[4*i+j] as u32); - } - r[i] = s; - } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmsumubm(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmsumuhm.md b/tools/ppc-manual/vmx/vmsumuhm.md index 8e6f1d2a..56808d2c 100644 --- a/tools/ppc-manual/vmx/vmsumuhm.md +++ b/tools/ppc-manual/vmx/vmsumuhm.md @@ -59,28 +59,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,28 +86,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmsumuhm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsumuhm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1057`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1057) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:107`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L107) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:581`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L581) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3595-3608`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3595-L3608) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsumuhm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1044`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1044) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:383`](../../../crates/sylpheed-ppc/src/opcode.rs#L383) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:696`](../../../crates/sylpheed-ppc/src/decoder.rs#L696) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmsumuhm => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let c = ctx.vr[instr.rc()].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let s = (a[2*i] as u32 * b[2*i] as u32) - .wrapping_add(a[2*i+1] as u32 * b[2*i+1] as u32) - .wrapping_add(c[i]); - r[i] = s; - } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmsumuhm(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmsumuhs.md b/tools/ppc-manual/vmx/vmsumuhs.md index 93508dec..eec597ef 100644 --- a/tools/ppc-manual/vmx/vmsumuhs.md +++ b/tools/ppc-manual/vmx/vmsumuhs.md @@ -60,28 +60,26 @@ vmsumuhs [VD], [VA], [VB], [VC] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,30 +87,17 @@ vmsumuhs [VD], [VA], [VB], [VC] ## Implementation References **`vmsumuhs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsumuhs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1062`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1062) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:107`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L107) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:582`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L582) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3609-3624`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3609-L3624) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsumuhs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1049`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1049) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:384`](../../../crates/sylpheed-ppc/src/opcode.rs#L384) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:697`](../../../crates/sylpheed-ppc/src/decoder.rs#L697) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmsumuhs => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let c = ctx.vr[instr.rc()].as_u32x4(); - let mut r = [0u32; 4]; let mut sat = false; - for i in 0..4 { - let s = (a[2*i] as u64 * b[2*i] as u64) - + (a[2*i+1] as u64 * b[2*i+1] as u64) - + c[i] as u64; - let (v, overflow) = if s > u32::MAX as u64 { (u32::MAX, true) } else { (s as u32, false) }; - r[i] = v; sat |= overflow; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmsumuhs(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
@@ -126,7 +111,7 @@ vmsumuhs [VD], [VA], [VB], [VC] + uint16(VA[2*i+1]) * uint16(VB[2*i+1]), 0, UINT32_MAX) ``` Two unsigned-half × unsigned-half products plus an unsigned-word accumulator, clamped to `uint32`. -- **Wide-then-clamp ordering.** Xenia accumulates into `u64` first and clamps the *final* sum to `u32` ([`crates/xenia-cpu/src/interpreter.rs`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs)) — matches the IBM spec. +- **Wide-then-clamp ordering.** Xenia accumulates into `u64` first and clamps the *final* sum to `u32` ([`crates/xenia-cpu/src/interpreter.rs`](https://git.mc02.dev/fabi/xenia-rs/src/commit/8401d4d5112849bf7b0f78f9d620f3620b1ce58d/crates/xenia-cpu/src/interpreter.rs)) — matches the IBM spec. - **`VSCR[SAT]` is sticky-set** if any lane clamps. Only the upper bound `0xFFFF_FFFF` ever triggers; unsigned overflow on the low side is impossible. - **Big-endian half lanes.** Lane 0 is the most-significant half. - **No XER, no exceptions.** diff --git a/tools/ppc-manual/vmx/vmulesb.md b/tools/ppc-manual/vmx/vmulesb.md index 73016053..e0acdb6a 100644 --- a/tools/ppc-manual/vmx/vmulesb.md +++ b/tools/ppc-manual/vmx/vmulesb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmulesb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulesb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1086`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1086) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:108`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L108) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:501`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L501) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3469-3476`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3469-L3476) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulesb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1071`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1071) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:385`](../../../crates/sylpheed-ppc/src/opcode.rs#L385) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:616`](../../../crates/sylpheed-ppc/src/decoder.rs#L616) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmulesb => { - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i8x16(ctx.vr[instr.rb()]); - let mut r = [0i16; 8]; - for i in 0..8 { r[i] = a[2 * i] as i16 * b[2 * i] as i16; } - ctx.vr[instr.rd()] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmulesb(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmulesh.md b/tools/ppc-manual/vmx/vmulesh.md index 9e00d6d7..9f607a38 100644 --- a/tools/ppc-manual/vmx/vmulesh.md +++ b/tools/ppc-manual/vmx/vmulesh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmulesh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulesh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1091`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1091) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:108`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L108) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:508`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L508) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3501-3508`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3501-L3508) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulesh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1076`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1076) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:386`](../../../crates/sylpheed-ppc/src/opcode.rs#L386) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:623`](../../../crates/sylpheed-ppc/src/decoder.rs#L623) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmulesh => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; - for i in 0..4 { r[i] = a[2 * i] as i32 * b[2 * i] as i32; } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmulesh(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmuleub.md b/tools/ppc-manual/vmx/vmuleub.md index 5e06b8b6..f7882b71 100644 --- a/tools/ppc-manual/vmx/vmuleub.md +++ b/tools/ppc-manual/vmx/vmuleub.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmuleub`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmuleub"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1096`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1096) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:108`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L108) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:478`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L478) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3453-3460`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3453-L3460) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmuleub"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1081`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1081) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:387`](../../../crates/sylpheed-ppc/src/opcode.rs#L387) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:593`](../../../crates/sylpheed-ppc/src/decoder.rs#L593) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmuleub => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = a[2 * i] as u16 * b[2 * i] as u16; } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmuleub(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmuleuh.md b/tools/ppc-manual/vmx/vmuleuh.md index 917fd613..ec76aa2e 100644 --- a/tools/ppc-manual/vmx/vmuleuh.md +++ b/tools/ppc-manual/vmx/vmuleuh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmuleuh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmuleuh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1101`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1101) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:108`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L108) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:485`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L485) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3485-3492`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3485-L3492) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmuleuh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1086`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1086) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:388`](../../../crates/sylpheed-ppc/src/opcode.rs#L388) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:600`](../../../crates/sylpheed-ppc/src/decoder.rs#L600) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmuleuh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[2 * i] as u32 * b[2 * i] as u32; } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmuleuh(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmulosb.md b/tools/ppc-manual/vmx/vmulosb.md index ac908fdc..f71293c6 100644 --- a/tools/ppc-manual/vmx/vmulosb.md +++ b/tools/ppc-manual/vmx/vmulosb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmulosb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulosb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1106`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1106) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:109`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L109) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:456`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L456) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3477-3484`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3477-L3484) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulosb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1091`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1091) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:390`](../../../crates/sylpheed-ppc/src/opcode.rs#L390) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:571`](../../../crates/sylpheed-ppc/src/decoder.rs#L571) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmulosb => { - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i8x16(ctx.vr[instr.rb()]); - let mut r = [0i16; 8]; - for i in 0..8 { r[i] = a[2 * i + 1] as i16 * b[2 * i + 1] as i16; } - ctx.vr[instr.rd()] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmulosb(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmulosh.md b/tools/ppc-manual/vmx/vmulosh.md index 164977cb..d74480ef 100644 --- a/tools/ppc-manual/vmx/vmulosh.md +++ b/tools/ppc-manual/vmx/vmulosh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmulosh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulosh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1111`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1111) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:109`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L109) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:462`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L462) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3509-3516`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3509-L3516) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulosh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1096`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1096) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:391`](../../../crates/sylpheed-ppc/src/opcode.rs#L391) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:577`](../../../crates/sylpheed-ppc/src/decoder.rs#L577) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmulosh => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; - for i in 0..4 { r[i] = a[2 * i + 1] as i32 * b[2 * i + 1] as i32; } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmulosh(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmuloub.md b/tools/ppc-manual/vmx/vmuloub.md index 8b3b527a..21a40bb8 100644 --- a/tools/ppc-manual/vmx/vmuloub.md +++ b/tools/ppc-manual/vmx/vmuloub.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmuloub`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmuloub"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1116`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1116) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:109`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L109) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:437`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L437) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3461-3468`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3461-L3468) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmuloub"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1101`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1101) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:392`](../../../crates/sylpheed-ppc/src/opcode.rs#L392) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:552`](../../../crates/sylpheed-ppc/src/decoder.rs#L552) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmuloub => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = a[2 * i + 1] as u16 * b[2 * i + 1] as u16; } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmuloub(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vmulouh.md b/tools/ppc-manual/vmx/vmulouh.md index 590154fe..d5879ef3 100644 --- a/tools/ppc-manual/vmx/vmulouh.md +++ b/tools/ppc-manual/vmx/vmulouh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vmulouh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulouh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1121`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1121) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:109`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L109) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:444`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L444) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3493-3500`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3493-L3500) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulouh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1106`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1106) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:393`](../../../crates/sylpheed-ppc/src/opcode.rs#L393) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:559`](../../../crates/sylpheed-ppc/src/decoder.rs#L559) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmulouh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[2 * i + 1] as u32 * b[2 * i + 1] as u32; } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmulouh(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vnmsubfp.md b/tools/ppc-manual/vmx/vnmsubfp.md index 34791175..9850ae96 100644 --- a/tools/ppc-manual/vmx/vnmsubfp.md +++ b/tools/ppc-manual/vmx/vnmsubfp.md @@ -96,13 +96,15 @@ for each 32-bit float lane i in 0..3: ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -110,60 +112,45 @@ for each 32-bit float lane i in 0..3: ## Implementation References **`vnmsubfp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vnmsubfp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1154`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1154) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:110`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L110) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:589`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L589) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2074-2089`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2074-L2089) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vnmsubfp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1130`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1130) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:394`](../../../crates/sylpheed-ppc/src/opcode.rs#L394) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:704`](../../../crates/sylpheed-ppc/src/decoder.rs#L704) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vnmsubfp => { - // vD = -(vA * vC - vB) = vB - vA * vC. Same denorm-flush rule as vmaddfp. - let a = ctx.vr[instr.ra()].as_f32x4(); - let b = ctx.vr[instr.rb()].as_f32x4(); - let c = ctx.vr[instr.rc()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { - let ai = vmx::flush_denorm(a[i]); - let bi = vmx::flush_denorm(b[i]); - let ci = vmx::flush_denorm(c[i]); - // PPCBUG-426: single FMA rounding instead of two-step (b - a*c). - r[i] = vmx::flush_denorm(-ai.mul_add(ci, -bi)); - } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vnmsubfp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vnmsubfp_(f, i.VXA.VD, i.VXA.VA, i.VXA.VB, i.VXA.VC); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1118) ── +int InstrEmit_vnmsubfp_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb, + uint32_t vc) { + // (VD) <- -(((VA) * (VC)) - (VB)) + // NOTE: only one rounding should take place, but that's hard... + // This really needs VFNMSUB132PS/VFNMSUB213PS/VFNMSUB231PS but that's AVX. + // NOTE2: we could make vnmsub a new opcode, and then do it in double + // precision, rounding after the neg + + Value* v = f.Neg(f.MulSub(f.LoadVR(va), f.LoadVR(vc), f.LoadVR(vb))); + f.StoreVR(vd, v); + return 0; +} ```
**`vnmsubfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vnmsubfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1157`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1157) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:110`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L110) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:615`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L615) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2090-2107`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2090-L2107) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vnmsubfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1133`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1133) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:395`](../../../crates/sylpheed-ppc/src/opcode.rs#L395) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:730`](../../../crates/sylpheed-ppc/src/decoder.rs#L730) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vnmsubfp128 => { - // VMX128 form: vD <- -((vA * vB) - vD) = vD - (vA * vB). Canary - // routes through `InstrEmit_vnmsubfp_` with the same arg-swap, - // which flushes all inputs unconditionally. - let a = ctx.vr[instr.va128()].as_f32x4(); - let b = ctx.vr[instr.vb128()].as_f32x4(); - let d = ctx.vr[instr.vd128()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { - let ai = vmx::flush_denorm(a[i]); - let bi = vmx::flush_denorm(b[i]); - let di = vmx::flush_denorm(d[i]); - // PPCBUG-427: single FMA rounding. - r[i] = vmx::flush_denorm(-ai.mul_add(bi, -di)); - } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vnmsubfp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vnmsubfp_(f, VX128_VD128, VX128_VA128, VX128_VD128, + VX128_VB128); +} ```
diff --git a/tools/ppc-manual/vmx/vnor.md b/tools/ppc-manual/vmx/vnor.md index a4fbbcf7..cb93a538 100644 --- a/tools/ppc-manual/vmx/vnor.md +++ b/tools/ppc-manual/vmx/vnor.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,44 +114,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vnor`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vnor"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1168`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1168) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:110`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L110) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:534`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L534) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2244-2252`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2244-L2252) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vnor"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1144`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1144) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:396`](../../../crates/sylpheed-ppc/src/opcode.rs#L396) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:649`](../../../crates/sylpheed-ppc/src/decoder.rs#L649) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vnor | PpcOpcode::vnor128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = !(a[i] | b[i]); } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vnor(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vnor_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1138) ── +int InstrEmit_vnor_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- ¬((VA) | (VB)) + Value* v = f.Not(f.Or(f.LoadVR(va), f.LoadVR(vb))); + f.StoreVR(vd, v); + return 0; +} ```
**`vnor128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vnor128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1171`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1171) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:110`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L110) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:623`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L623) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2244-2252`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2244-L2252) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vnor128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1147`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1147) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:397`](../../../crates/sylpheed-ppc/src/opcode.rs#L397) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:738`](../../../crates/sylpheed-ppc/src/decoder.rs#L738) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vnor | PpcOpcode::vnor128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = !(a[i] | b[i]); } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vnor128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vnor_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1138) ── +int InstrEmit_vnor_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- ¬((VA) | (VB)) + Value* v = f.Not(f.Or(f.LoadVR(va), f.LoadVR(vb))); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vor.md b/tools/ppc-manual/vmx/vor.md index 479c4a3f..fee03ec6 100644 --- a/tools/ppc-manual/vmx/vor.md +++ b/tools/ppc-manual/vmx/vor.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,44 +114,56 @@ _No condition-register or status-register effects._ ## Implementation References **`vor`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vor"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1186`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1186) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:111`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L111) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:531`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L531) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2226-2234`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2226-L2234) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vor"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1162`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1162) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:398`](../../../crates/sylpheed-ppc/src/opcode.rs#L398) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:646`](../../../crates/sylpheed-ppc/src/decoder.rs#L646) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vor | PpcOpcode::vor128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i] | b[i]; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vor(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vor_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1151) ── +int InstrEmit_vor_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) | (VB) + if (va == vb) { + // Copy VA==VB into VD. + f.StoreVR(vd, f.LoadVR(va)); + } else { + Value* v = f.Or(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + } + return 0; +} ```
**`vor128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vor128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1189`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1189) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:111`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L111) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:625`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L625) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2226-2234`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2226-L2234) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vor128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1165`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1165) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:399`](../../../crates/sylpheed-ppc/src/opcode.rs#L399) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:740`](../../../crates/sylpheed-ppc/src/decoder.rs#L740) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vor | PpcOpcode::vor128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i] | b[i]; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vor128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vor_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1151) ── +int InstrEmit_vor_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) | (VB) + if (va == vb) { + // Copy VA==VB into VD. + f.StoreVR(vd, f.LoadVR(va)); + } else { + Value* v = f.Or(f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + } + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vperm.md b/tools/ppc-manual/vmx/vperm.md index e13be409..12c5dec9 100644 --- a/tools/ppc-manual/vmx/vperm.md +++ b/tools/ppc-manual/vmx/vperm.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,76 +114,39 @@ _No condition-register or status-register effects._ ## Implementation References **`vperm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vperm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1199`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1199) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:112`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L112) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:586`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L586) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2278-2302`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2278-L2302) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vperm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1175`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1175) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:400`](../../../crates/sylpheed-ppc/src/opcode.rs#L400) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:701`](../../../crates/sylpheed-ppc/src/decoder.rs#L701) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vperm | PpcOpcode::vperm128 => { - let (va, vb, vd); - let vc; - if matches!(instr.opcode, PpcOpcode::vperm128) { - va = instr.va128(); - vb = instr.vb128(); - vd = instr.vd128(); - vc = instr.vc128_2(); - } else { - va = instr.ra(); - vb = instr.rb(); - vd = instr.rd(); - vc = instr.rc(); - } - let a_bytes = ctx.vr[va].as_bytes(); - let b_bytes = ctx.vr[vb].as_bytes(); - let c_bytes = ctx.vr[vc].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { - let idx = (c_bytes[i] & 0x1F) as usize; - r[i] = if idx < 16 { a_bytes[idx] } else { b_bytes[idx - 16] }; - } - ctx.vr[vd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vperm(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vperm_(f, i.VXA.VD, i.VXA.VA, i.VXA.VB, i.VXA.VC); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1169) ── +int InstrEmit_vperm_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb, + uint32_t vc) { + Value* v = f.Permute(f.LoadVR(vc), f.LoadVR(va), f.LoadVR(vb), INT8_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vperm128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vperm128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1202`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1202) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:112`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L112) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:605`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L605) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2278-2302`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2278-L2302) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vperm128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1178`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1178) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:401`](../../../crates/sylpheed-ppc/src/opcode.rs#L401) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:720`](../../../crates/sylpheed-ppc/src/decoder.rs#L720) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vperm | PpcOpcode::vperm128 => { - let (va, vb, vd); - let vc; - if matches!(instr.opcode, PpcOpcode::vperm128) { - va = instr.va128(); - vb = instr.vb128(); - vd = instr.vd128(); - vc = instr.vc128_2(); - } else { - va = instr.ra(); - vb = instr.rb(); - vd = instr.rd(); - vc = instr.rc(); - } - let a_bytes = ctx.vr[va].as_bytes(); - let b_bytes = ctx.vr[vb].as_bytes(); - let c_bytes = ctx.vr[vc].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { - let idx = (c_bytes[i] & 0x1F) as usize; - r[i] = if idx < 16 { a_bytes[idx] } else { b_bytes[idx - 16] }; - } - ctx.vr[vd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vperm128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vperm_(f, VX128_2_VD128, VX128_2_VA128, VX128_2_VB128, + VX128_2_VC); +} ```
diff --git a/tools/ppc-manual/vmx/vpkpx.md b/tools/ppc-manual/vmx/vpkpx.md index 28eb4a06..196d90ce 100644 --- a/tools/ppc-manual/vmx/vpkpx.md +++ b/tools/ppc-manual/vmx/vpkpx.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,23 +84,32 @@ _No condition-register or status-register effects._ ## Implementation References **`vpkpx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkpx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1810`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1810) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:113`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L113) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:504`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L504) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4123-4131`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4123-L4131) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkpx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1796`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1796) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:404`](../../../crates/sylpheed-ppc/src/opcode.rs#L404) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:619`](../../../crates/sylpheed-ppc/src/decoder.rs#L619) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkpx => { - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u16; 8]; - for i in 0..4 { r[i] = crate::vmx::pack_pixel_555(a[i]); } - for i in 0..4 { r[4 + i] = crate::vmx::pack_pixel_555(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkpx(PPCHIRBuilder& f, const InstrData& i) { + // I compared the results of this against over a million randomly generated + // sets of inputs and all compared equal + + Value* src1 = f.LoadVR(i.VX.VA); + + Value* src2 = f.LoadVR(i.VX.VB); + + Value* pck1 = vkpkx_in_low(f, src1); + Value* pck2 = vkpkx_in_low(f, src2); + + Value* result = f.Pack( + pck1, pck2, + PACK_TYPE_16_IN_32 | PACK_TYPE_IN_UNSIGNED | PACK_TYPE_OUT_UNSIGNED); + + f.StoreVR(i.VX.VD, result); + + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vpkshss.md b/tools/ppc-manual/vmx/vpkshss.md index b968c367..36588a0a 100644 --- a/tools/ppc-manual/vmx/vpkshss.md +++ b/tools/ppc-manual/vmx/vpkshss.md @@ -89,28 +89,26 @@ vpkshss128 [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -118,52 +116,64 @@ vpkshss128 [VD], [VA], [VB] ## Implementation References **`vpkshss`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkshss"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1845`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1845) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:113`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L113) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:471`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L471) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4070-4082`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4070-L4082) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkshss"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1831`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1831) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:405`](../../../crates/sylpheed-ppc/src/opcode.rs#L405) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:586`](../../../crates/sylpheed-ppc/src/decoder.rs#L586) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkshss | PpcOpcode::vpkshss128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkshss128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = crate::vmx::as_i16x8(ctx.vr[ra]); - let b = crate::vmx::as_i16x8(ctx.vr[rb]); - let mut r = [0i8; 16]; let mut sat = false; - for i in 0..8 { let (v, s) = crate::vmx::sat_i16_to_i8(a[i]); r[i] = v; sat |= s; } - for i in 0..8 { let (v, s) = crate::vmx::sat_i16_to_i8(b[i]); r[8 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = crate::vmx::from_i8x16(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkshss(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkshss_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1816) ── +int InstrEmit_vpkshss_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Signed Halfword Signed Saturate + // Convert VA and VB from signed words to signed saturated bytes then + // concat: + // for each i in VA + VB: + // i = int8_t(Clamp(EXTS(int16_t(t)), -128, 127)) + // dest = VA | VB (lower 8bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_8_IN_16 | PACK_TYPE_IN_SIGNED | + PACK_TYPE_OUT_SIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
**`vpkshss128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkshss128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1848`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1848) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:113`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L113) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:618`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L618) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4070-4082`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4070-L4082) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkshss128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1834`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1834) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:406`](../../../crates/sylpheed-ppc/src/opcode.rs#L406) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:733`](../../../crates/sylpheed-ppc/src/decoder.rs#L733) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkshss | PpcOpcode::vpkshss128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkshss128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = crate::vmx::as_i16x8(ctx.vr[ra]); - let b = crate::vmx::as_i16x8(ctx.vr[rb]); - let mut r = [0i8; 16]; let mut sat = false; - for i in 0..8 { let (v, s) = crate::vmx::sat_i16_to_i8(a[i]); r[i] = v; sat |= s; } - for i in 0..8 { let (v, s) = crate::vmx::sat_i16_to_i8(b[i]); r[8 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = crate::vmx::from_i8x16(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkshss128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkshss_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1816) ── +int InstrEmit_vpkshss_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Signed Halfword Signed Saturate + // Convert VA and VB from signed words to signed saturated bytes then + // concat: + // for each i in VA + VB: + // i = int8_t(Clamp(EXTS(int16_t(t)), -128, 127)) + // dest = VA | VB (lower 8bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_8_IN_16 | PACK_TYPE_IN_SIGNED | + PACK_TYPE_OUT_SIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vpkshus.md b/tools/ppc-manual/vmx/vpkshus.md index 64723f98..50370dd7 100644 --- a/tools/ppc-manual/vmx/vpkshus.md +++ b/tools/ppc-manual/vmx/vpkshus.md @@ -89,28 +89,26 @@ vpkshus128 [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -118,52 +116,64 @@ vpkshus128 [VD], [VA], [VB] ## Implementation References **`vpkshus`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkshus"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1953`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1953) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:113`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L113) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:459`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L459) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4057-4069`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4057-L4069) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkshus"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1939`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1939) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:407`](../../../crates/sylpheed-ppc/src/opcode.rs#L407) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:574`](../../../crates/sylpheed-ppc/src/decoder.rs#L574) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkshus | PpcOpcode::vpkshus128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkshus128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = crate::vmx::as_i16x8(ctx.vr[ra]); - let b = crate::vmx::as_i16x8(ctx.vr[rb]); - let mut r = [0u8; 16]; let mut sat = false; - for i in 0..8 { let (v, s) = crate::vmx::sat_i16_to_u8(a[i]); r[i] = v; sat |= s; } - for i in 0..8 { let (v, s) = crate::vmx::sat_i16_to_u8(b[i]); r[8 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkshus(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkshus_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1924) ── +int InstrEmit_vpkshus_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Signed Halfword Unsigned Saturate + // Convert VA and VB from signed shorts to unsigned saturated bytes then + // concat: + // for each i in VA + VB: + // i = uint8_t(Clamp(EXTS(int16_t(i)), 0, 255)) + // dest = VA | VB (lower 8bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_8_IN_16 | PACK_TYPE_IN_SIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
**`vpkshus128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkshus128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1956`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1956) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:113`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L113) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:620`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L620) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4057-4069`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4057-L4069) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkshus128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1942`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1942) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:408`](../../../crates/sylpheed-ppc/src/opcode.rs#L408) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:735`](../../../crates/sylpheed-ppc/src/decoder.rs#L735) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkshus | PpcOpcode::vpkshus128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkshus128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = crate::vmx::as_i16x8(ctx.vr[ra]); - let b = crate::vmx::as_i16x8(ctx.vr[rb]); - let mut r = [0u8; 16]; let mut sat = false; - for i in 0..8 { let (v, s) = crate::vmx::sat_i16_to_u8(a[i]); r[i] = v; sat |= s; } - for i in 0..8 { let (v, s) = crate::vmx::sat_i16_to_u8(b[i]); r[8 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkshus128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkshus_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1924) ── +int InstrEmit_vpkshus_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Signed Halfword Unsigned Saturate + // Convert VA and VB from signed shorts to unsigned saturated bytes then + // concat: + // for each i in VA + VB: + // i = uint8_t(Clamp(EXTS(int16_t(i)), 0, 255)) + // dest = VA | VB (lower 8bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_8_IN_16 | PACK_TYPE_IN_SIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vpkswss.md b/tools/ppc-manual/vmx/vpkswss.md index 0ae74c31..2ad2d0a2 100644 --- a/tools/ppc-manual/vmx/vpkswss.md +++ b/tools/ppc-manual/vmx/vpkswss.md @@ -89,28 +89,26 @@ vpkswss128 [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -118,52 +116,64 @@ vpkswss128 [VD], [VA], [VB] ## Implementation References **`vpkswss`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkswss"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1867`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1867) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:114`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L114) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:474`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L474) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4109-4121`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4109-L4121) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkswss"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1853`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1853) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:409`](../../../crates/sylpheed-ppc/src/opcode.rs#L409) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:589`](../../../crates/sylpheed-ppc/src/decoder.rs#L589) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkswss | PpcOpcode::vpkswss128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkswss128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = crate::vmx::as_i32x4(ctx.vr[ra]); - let b = crate::vmx::as_i32x4(ctx.vr[rb]); - let mut r = [0i16; 8]; let mut sat = false; - for i in 0..4 { let (v, s) = crate::vmx::sat_i32_to_i16(a[i]); r[i] = v; sat |= s; } - for i in 0..4 { let (v, s) = crate::vmx::sat_i32_to_i16(b[i]); r[4 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkswss(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkswss_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1838) ── +int InstrEmit_vpkswss_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Signed Word Signed Saturate + // Convert VA and VB from signed int words to signed saturated shorts then + // concat: + // for each i in VA + VB: + // i = int16_t(Clamp(EXTS(int32_t(t)), -2^15, 2^15-1)) + // dest = VA | VB (lower 16bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_16_IN_32 | PACK_TYPE_IN_SIGNED | + PACK_TYPE_OUT_SIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
**`vpkswss128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkswss128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1870`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1870) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:114`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L114) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:622`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L622) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4109-4121`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4109-L4121) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkswss128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1856`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1856) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:410`](../../../crates/sylpheed-ppc/src/opcode.rs#L410) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:737`](../../../crates/sylpheed-ppc/src/decoder.rs#L737) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkswss | PpcOpcode::vpkswss128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkswss128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = crate::vmx::as_i32x4(ctx.vr[ra]); - let b = crate::vmx::as_i32x4(ctx.vr[rb]); - let mut r = [0i16; 8]; let mut sat = false; - for i in 0..4 { let (v, s) = crate::vmx::sat_i32_to_i16(a[i]); r[i] = v; sat |= s; } - for i in 0..4 { let (v, s) = crate::vmx::sat_i32_to_i16(b[i]); r[4 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkswss128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkswss_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1838) ── +int InstrEmit_vpkswss_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Signed Word Signed Saturate + // Convert VA and VB from signed int words to signed saturated shorts then + // concat: + // for each i in VA + VB: + // i = int16_t(Clamp(EXTS(int32_t(t)), -2^15, 2^15-1)) + // dest = VA | VB (lower 16bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_16_IN_32 | PACK_TYPE_IN_SIGNED | + PACK_TYPE_OUT_SIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vpkswus.md b/tools/ppc-manual/vmx/vpkswus.md index e2863afc..51bdf87c 100644 --- a/tools/ppc-manual/vmx/vpkswus.md +++ b/tools/ppc-manual/vmx/vpkswus.md @@ -89,28 +89,26 @@ vpkswus128 [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -118,52 +116,64 @@ vpkswus128 [VD], [VA], [VB] ## Implementation References **`vpkswus`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkswus"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1889`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1889) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:114`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L114) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:465`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L465) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4096-4108`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4096-L4108) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkswus"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1875`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1875) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:411`](../../../crates/sylpheed-ppc/src/opcode.rs#L411) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:580`](../../../crates/sylpheed-ppc/src/decoder.rs#L580) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkswus | PpcOpcode::vpkswus128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkswus128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = crate::vmx::as_i32x4(ctx.vr[ra]); - let b = crate::vmx::as_i32x4(ctx.vr[rb]); - let mut r = [0u16; 8]; let mut sat = false; - for i in 0..4 { let (v, s) = crate::vmx::sat_i32_to_u16(a[i]); r[i] = v; sat |= s; } - for i in 0..4 { let (v, s) = crate::vmx::sat_i32_to_u16(b[i]); r[4 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkswus(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkswus_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1860) ── +int InstrEmit_vpkswus_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Signed Word Unsigned Saturate + // Convert VA and VB from signed int words to unsigned saturated shorts then + // concat: + // for each i in VA + VB: + // i = uint16_t(Clamp(EXTS(int32_t(t)), 0, 2^16-1)) + // dest = VA | VB (lower 16bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_16_IN_32 | PACK_TYPE_IN_SIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
**`vpkswus128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkswus128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1892`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1892) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:114`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L114) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:624`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L624) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4096-4108`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4096-L4108) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkswus128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1878`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1878) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:412`](../../../crates/sylpheed-ppc/src/opcode.rs#L412) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:739`](../../../crates/sylpheed-ppc/src/decoder.rs#L739) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkswus | PpcOpcode::vpkswus128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkswus128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = crate::vmx::as_i32x4(ctx.vr[ra]); - let b = crate::vmx::as_i32x4(ctx.vr[rb]); - let mut r = [0u16; 8]; let mut sat = false; - for i in 0..4 { let (v, s) = crate::vmx::sat_i32_to_u16(a[i]); r[i] = v; sat |= s; } - for i in 0..4 { let (v, s) = crate::vmx::sat_i32_to_u16(b[i]); r[4 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkswus128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkswus_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1860) ── +int InstrEmit_vpkswus_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Signed Word Unsigned Saturate + // Convert VA and VB from signed int words to unsigned saturated shorts then + // concat: + // for each i in VA + VB: + // i = uint16_t(Clamp(EXTS(int32_t(t)), 0, 2^16-1)) + // dest = VA | VB (lower 16bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_16_IN_32 | PACK_TYPE_IN_SIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vpkuhum.md b/tools/ppc-manual/vmx/vpkuhum.md index a6739799..9a7b112e 100644 --- a/tools/ppc-manual/vmx/vpkuhum.md +++ b/tools/ppc-manual/vmx/vpkuhum.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,50 +114,60 @@ _No condition-register or status-register effects._ ## Implementation References **`vpkuhum`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuhum"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1909`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1909) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:115`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L115) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:440`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L440) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4019-4030`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4019-L4030) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuhum"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1895`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1895) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:413`](../../../crates/sylpheed-ppc/src/opcode.rs#L413) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:555`](../../../crates/sylpheed-ppc/src/decoder.rs#L555) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkuhum | PpcOpcode::vpkuhum128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkuhum128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = ctx.vr[ra].as_u16x8(); - let b = ctx.vr[rb].as_u16x8(); - let mut r = [0u8; 16]; - for i in 0..8 { r[i] = a[i] as u8; } - for i in 0..8 { r[8 + i] = b[i] as u8; } - ctx.vr[rd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkuhum(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkuhum_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1882) ── +int InstrEmit_vpkuhum_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Unsigned Halfword Unsigned Modulo + // Convert VA and VB from unsigned shorts to unsigned bytes then concat: + // for each i in VA + VB: + // i = uint8_t(uint16_t(i)) + // dest = VA | VB (lower 8bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_8_IN_16 | PACK_TYPE_IN_UNSIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_UNSATURATE); + f.StoreVR(vd, v); + return 0; +} ```
**`vpkuhum128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuhum128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1912`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1912) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:115`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L115) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:626`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L626) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4019-4030`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4019-L4030) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuhum128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1898`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1898) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:414`](../../../crates/sylpheed-ppc/src/opcode.rs#L414) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:741`](../../../crates/sylpheed-ppc/src/decoder.rs#L741) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkuhum | PpcOpcode::vpkuhum128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkuhum128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = ctx.vr[ra].as_u16x8(); - let b = ctx.vr[rb].as_u16x8(); - let mut r = [0u8; 16]; - for i in 0..8 { r[i] = a[i] as u8; } - for i in 0..8 { r[8 + i] = b[i] as u8; } - ctx.vr[rd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkuhum128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkuhum_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1882) ── +int InstrEmit_vpkuhum_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Unsigned Halfword Unsigned Modulo + // Convert VA and VB from unsigned shorts to unsigned bytes then concat: + // for each i in VA + VB: + // i = uint8_t(uint16_t(i)) + // dest = VA | VB (lower 8bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_8_IN_16 | PACK_TYPE_IN_UNSIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_UNSATURATE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vpkuhus.md b/tools/ppc-manual/vmx/vpkuhus.md index d70d8d6f..86f7a4bd 100644 --- a/tools/ppc-manual/vmx/vpkuhus.md +++ b/tools/ppc-manual/vmx/vpkuhus.md @@ -89,28 +89,26 @@ vpkuhus128 [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -118,52 +116,64 @@ vpkuhus128 [VD], [VA], [VB] ## Implementation References **`vpkuhus`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuhus"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1931`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1931) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:115`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L115) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:452`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L452) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4044-4056`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4044-L4056) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuhus"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1917`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1917) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:415`](../../../crates/sylpheed-ppc/src/opcode.rs#L415) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:567`](../../../crates/sylpheed-ppc/src/decoder.rs#L567) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkuhus | PpcOpcode::vpkuhus128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkuhus128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = ctx.vr[ra].as_u16x8(); - let b = ctx.vr[rb].as_u16x8(); - let mut r = [0u8; 16]; let mut sat = false; - for i in 0..8 { let (v, s) = crate::vmx::sat_u16_to_u8(a[i]); r[i] = v; sat |= s; } - for i in 0..8 { let (v, s) = crate::vmx::sat_u16_to_u8(b[i]); r[8 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkuhus(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkuhus_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1902) ── +int InstrEmit_vpkuhus_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Unsigned Halfword Unsigned Saturate + // Convert VA and VB from unsigned shorts to unsigned saturated bytes then + // concat: + // for each i in VA + VB: + // i = uint8_t(Clamp(EXTZ(uint16_t(i)), 0, 255)) + // dest = VA | VB (lower 8bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_8_IN_16 | PACK_TYPE_IN_UNSIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
**`vpkuhus128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuhus128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1934`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1934) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:115`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L115) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:628`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L628) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4044-4056`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4044-L4056) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuhus128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1920`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1920) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:416`](../../../crates/sylpheed-ppc/src/opcode.rs#L416) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:743`](../../../crates/sylpheed-ppc/src/decoder.rs#L743) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkuhus | PpcOpcode::vpkuhus128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkuhus128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = ctx.vr[ra].as_u16x8(); - let b = ctx.vr[rb].as_u16x8(); - let mut r = [0u8; 16]; let mut sat = false; - for i in 0..8 { let (v, s) = crate::vmx::sat_u16_to_u8(a[i]); r[i] = v; sat |= s; } - for i in 0..8 { let (v, s) = crate::vmx::sat_u16_to_u8(b[i]); r[8 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkuhus128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkuhus_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1902) ── +int InstrEmit_vpkuhus_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Unsigned Halfword Unsigned Saturate + // Convert VA and VB from unsigned shorts to unsigned saturated bytes then + // concat: + // for each i in VA + VB: + // i = uint8_t(Clamp(EXTZ(uint16_t(i)), 0, 255)) + // dest = VA | VB (lower 8bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_8_IN_16 | PACK_TYPE_IN_UNSIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vpkuwum.md b/tools/ppc-manual/vmx/vpkuwum.md index 68747b4e..24963f17 100644 --- a/tools/ppc-manual/vmx/vpkuwum.md +++ b/tools/ppc-manual/vmx/vpkuwum.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,50 +114,60 @@ _No condition-register or status-register effects._ ## Implementation References **`vpkuwum`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuwum"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1973`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1973) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:116`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L116) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:447`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L447) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4031-4042`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4031-L4042) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuwum"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1959`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1959) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:417`](../../../crates/sylpheed-ppc/src/opcode.rs#L417) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:562`](../../../crates/sylpheed-ppc/src/decoder.rs#L562) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkuwum | PpcOpcode::vpkuwum128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkuwum128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = ctx.vr[ra].as_u32x4(); - let b = ctx.vr[rb].as_u32x4(); - let mut r = [0u16; 8]; - for i in 0..4 { r[i] = a[i] as u16; } - for i in 0..4 { r[4 + i] = b[i] as u16; } - ctx.vr[rd] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkuwum(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkuwum_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1946) ── +int InstrEmit_vpkuwum_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Unsigned Word Unsigned Modulo + // Concat low shorts from VA + VB: + // for each i in VA + VB: + // i = uint16_t(uint32_t(i)) + // dest = VA | VB (lower 16bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_16_IN_32 | PACK_TYPE_IN_UNSIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_UNSATURATE); + f.StoreVR(vd, v); + return 0; +} ```
**`vpkuwum128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuwum128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1976`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1976) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:116`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L116) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:630`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L630) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4031-4042`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4031-L4042) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuwum128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1962`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1962) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:418`](../../../crates/sylpheed-ppc/src/opcode.rs#L418) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:745`](../../../crates/sylpheed-ppc/src/decoder.rs#L745) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkuwum | PpcOpcode::vpkuwum128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkuwum128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = ctx.vr[ra].as_u32x4(); - let b = ctx.vr[rb].as_u32x4(); - let mut r = [0u16; 8]; - for i in 0..4 { r[i] = a[i] as u16; } - for i in 0..4 { r[4 + i] = b[i] as u16; } - ctx.vr[rd] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkuwum128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkuwum_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1946) ── +int InstrEmit_vpkuwum_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Unsigned Word Unsigned Modulo + // Concat low shorts from VA + VB: + // for each i in VA + VB: + // i = uint16_t(uint32_t(i)) + // dest = VA | VB (lower 16bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_16_IN_32 | PACK_TYPE_IN_UNSIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_UNSATURATE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vpkuwus.md b/tools/ppc-manual/vmx/vpkuwus.md index beef6846..c126b3be 100644 --- a/tools/ppc-manual/vmx/vpkuwus.md +++ b/tools/ppc-manual/vmx/vpkuwus.md @@ -89,28 +89,26 @@ vpkuwus128 [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -118,52 +116,64 @@ vpkuwus128 [VD], [VA], [VB] ## Implementation References **`vpkuwus`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuwus"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1995`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1995) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:116`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L116) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:453`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L453) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4083-4095`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4083-L4095) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuwus"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1981`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1981) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:419`](../../../crates/sylpheed-ppc/src/opcode.rs#L419) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:568`](../../../crates/sylpheed-ppc/src/decoder.rs#L568) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkuwus | PpcOpcode::vpkuwus128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkuwus128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = ctx.vr[ra].as_u32x4(); - let b = ctx.vr[rb].as_u32x4(); - let mut r = [0u16; 8]; let mut sat = false; - for i in 0..4 { let (v, s) = crate::vmx::sat_u32_to_u16(a[i]); r[i] = v; sat |= s; } - for i in 0..4 { let (v, s) = crate::vmx::sat_u32_to_u16(b[i]); r[4 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkuwus(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkuwus_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1966) ── +int InstrEmit_vpkuwus_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Unsigned Word Unsigned Saturate + // Convert VA and VB from unsigned int words to unsigned saturated shorts then + // concat: + // for each i in VA + VB: + // i = uint16_t(Clamp(EXTZ(uint32_t(t)), 0, 2^16-1)) + // dest = VA | VB (lower 16bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_16_IN_32 | PACK_TYPE_IN_UNSIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
**`vpkuwus128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuwus128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1998`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1998) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:116`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L116) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:632`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L632) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4083-4095`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4083-L4095) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkuwus128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1984`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1984) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:420`](../../../crates/sylpheed-ppc/src/opcode.rs#L420) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:747`](../../../crates/sylpheed-ppc/src/decoder.rs#L747) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkuwus | PpcOpcode::vpkuwus128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vpkuwus128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = ctx.vr[ra].as_u32x4(); - let b = ctx.vr[rb].as_u32x4(); - let mut r = [0u16; 8]; let mut sat = false; - for i in 0..4 { let (v, s) = crate::vmx::sat_u32_to_u16(a[i]); r[i] = v; sat |= s; } - for i in 0..4 { let (v, s) = crate::vmx::sat_u32_to_u16(b[i]); r[4 + i] = v; sat |= s; } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[rd] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkuwus128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vpkuwus_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1966) ── +int InstrEmit_vpkuwus_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, + uint32_t vb) { + // Vector Pack Unsigned Word Unsigned Saturate + // Convert VA and VB from unsigned int words to unsigned saturated shorts then + // concat: + // for each i in VA + VB: + // i = uint16_t(Clamp(EXTZ(uint32_t(t)), 0, 2^16-1)) + // dest = VA | VB (lower 16bit values) + Value* v = f.Pack(f.LoadVR(va), f.LoadVR(vb), + PACK_TYPE_16_IN_32 | PACK_TYPE_IN_UNSIGNED | + PACK_TYPE_OUT_UNSIGNED | PACK_TYPE_OUT_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vrefp.md b/tools/ppc-manual/vmx/vrefp.md index 15f9fec0..a0dee1b4 100644 --- a/tools/ppc-manual/vmx/vrefp.md +++ b/tools/ppc-manual/vmx/vrefp.md @@ -82,28 +82,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -111,44 +109,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vrefp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrefp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1227`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1227) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:117`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L117) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:457`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L457) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2153-2161`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2153-L2161) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrefp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1203`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1203) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:421`](../../../crates/sylpheed-ppc/src/opcode.rs#L421) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:572`](../../../crates/sylpheed-ppc/src/decoder.rs#L572) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrefp | PpcOpcode::vrefp128 => { - let vb = if matches!(instr.opcode, PpcOpcode::vrefp128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrefp128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = 1.0 / b[i]; } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrefp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrefp_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1197) ── +int InstrEmit_vrefp_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- 1/(VB) + Value* v = f.Recip(f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
**`vrefp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrefp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1230`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1230) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:117`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L117) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:664`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L664) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2153-2161`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2153-L2161) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrefp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1206`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1206) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:422`](../../../crates/sylpheed-ppc/src/opcode.rs#L422) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:779`](../../../crates/sylpheed-ppc/src/decoder.rs#L779) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrefp | PpcOpcode::vrefp128 => { - let vb = if matches!(instr.opcode, PpcOpcode::vrefp128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrefp128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = 1.0 / b[i]; } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrefp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrefp_(f, VX128_3_VD128, VX128_3_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1197) ── +int InstrEmit_vrefp_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- 1/(VB) + Value* v = f.Recip(f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vrfim.md b/tools/ppc-manual/vmx/vrfim.md index 47163e58..f9241d39 100644 --- a/tools/ppc-manual/vmx/vrfim.md +++ b/tools/ppc-manual/vmx/vrfim.md @@ -82,28 +82,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -111,44 +109,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vrfim`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfim"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1240`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1240) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:118`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L118) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:496`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L496) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2493-2501`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2493-L2501) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfim"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1216`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1216) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:423`](../../../crates/sylpheed-ppc/src/opcode.rs#L423) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:611`](../../../crates/sylpheed-ppc/src/decoder.rs#L611) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrfim | PpcOpcode::vrfim128 => { - let vb = if matches!(instr.opcode, PpcOpcode::vrfim128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrfim128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].floor(); } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrfim(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrfim_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1210) ── +int InstrEmit_vrfim_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- RndToFPInt32Floor(VB) + Value* v = f.Round(f.LoadVR(vb), ROUND_TO_MINUS_INFINITY); + f.StoreVR(vd, v); + return 0; +} ```
**`vrfim128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfim128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1243`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1243) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:118`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L118) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:660`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L660) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2493-2501`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2493-L2501) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfim128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1219`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1219) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:424`](../../../crates/sylpheed-ppc/src/opcode.rs#L424) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:775`](../../../crates/sylpheed-ppc/src/decoder.rs#L775) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrfim | PpcOpcode::vrfim128 => { - let vb = if matches!(instr.opcode, PpcOpcode::vrfim128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrfim128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].floor(); } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrfim128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrfim_(f, VX128_3_VD128, VX128_3_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1210) ── +int InstrEmit_vrfim_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- RndToFPInt32Floor(VB) + Value* v = f.Round(f.LoadVR(vb), ROUND_TO_MINUS_INFINITY); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vrfin.md b/tools/ppc-manual/vmx/vrfin.md index a30db051..4a6f4beb 100644 --- a/tools/ppc-manual/vmx/vrfin.md +++ b/tools/ppc-manual/vmx/vrfin.md @@ -82,28 +82,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -111,48 +109,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vrfin`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfin"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1253`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1253) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:118`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L118) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:479`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L479) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2473-2483`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2473-L2483) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfin"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1229`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1229) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:425`](../../../crates/sylpheed-ppc/src/opcode.rs#L425) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:594`](../../../crates/sylpheed-ppc/src/decoder.rs#L594) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrfin | PpcOpcode::vrfin128 => { - // PPCBUG-432: ISA round-to-nearest-even, NOT Rust's `round()` - // (which is round-half-away-from-zero). - let vb = if matches!(instr.opcode, PpcOpcode::vrfin128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrfin128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].round_ties_even(); } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrfin(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrfin_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1223) ── +int InstrEmit_vrfin_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- RoundToNearest(VB) + Value* v = f.Round(f.LoadVR(vb), ROUND_TO_NEAREST); + f.StoreVR(vd, v); + return 0; +} ```
**`vrfin128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfin128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1256`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1256) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:118`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L118) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:661`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L661) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2473-2483`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2473-L2483) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfin128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1232`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1232) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:426`](../../../crates/sylpheed-ppc/src/opcode.rs#L426) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:776`](../../../crates/sylpheed-ppc/src/decoder.rs#L776) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrfin | PpcOpcode::vrfin128 => { - // PPCBUG-432: ISA round-to-nearest-even, NOT Rust's `round()` - // (which is round-half-away-from-zero). - let vb = if matches!(instr.opcode, PpcOpcode::vrfin128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrfin128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].round_ties_even(); } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrfin128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrfin_(f, VX128_3_VD128, VX128_3_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1223) ── +int InstrEmit_vrfin_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- RoundToNearest(VB) + Value* v = f.Round(f.LoadVR(vb), ROUND_TO_NEAREST); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vrfip.md b/tools/ppc-manual/vmx/vrfip.md index 3c358b88..218a9092 100644 --- a/tools/ppc-manual/vmx/vrfip.md +++ b/tools/ppc-manual/vmx/vrfip.md @@ -82,28 +82,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -111,44 +109,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vrfip`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfip"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1266`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1266) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:118`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L118) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:492`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L492) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2484-2492`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2484-L2492) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfip"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1242`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1242) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:427`](../../../crates/sylpheed-ppc/src/opcode.rs#L427) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:607`](../../../crates/sylpheed-ppc/src/decoder.rs#L607) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrfip | PpcOpcode::vrfip128 => { - let vb = if matches!(instr.opcode, PpcOpcode::vrfip128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrfip128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].ceil(); } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrfip(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrfip_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1236) ── +int InstrEmit_vrfip_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- RndToFPInt32Ceil(VB) + Value* v = f.Round(f.LoadVR(vb), ROUND_TO_POSITIVE_INFINITY); + f.StoreVR(vd, v); + return 0; +} ```
**`vrfip128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfip128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1269`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1269) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:118`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L118) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:662`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L662) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2484-2492`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2484-L2492) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfip128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1245`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1245) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:428`](../../../crates/sylpheed-ppc/src/opcode.rs#L428) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:777`](../../../crates/sylpheed-ppc/src/decoder.rs#L777) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrfip | PpcOpcode::vrfip128 => { - let vb = if matches!(instr.opcode, PpcOpcode::vrfip128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrfip128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].ceil(); } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrfip128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrfip_(f, VX128_3_VD128, VX128_3_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1236) ── +int InstrEmit_vrfip_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- RndToFPInt32Ceil(VB) + Value* v = f.Round(f.LoadVR(vb), ROUND_TO_POSITIVE_INFINITY); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vrfiz.md b/tools/ppc-manual/vmx/vrfiz.md index 3e45e081..345d09b1 100644 --- a/tools/ppc-manual/vmx/vrfiz.md +++ b/tools/ppc-manual/vmx/vrfiz.md @@ -82,28 +82,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -111,44 +109,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vrfiz`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfiz"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1279`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1279) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:118`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L118) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:486`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L486) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2464-2472`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2464-L2472) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfiz"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1255`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1255) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:429`](../../../crates/sylpheed-ppc/src/opcode.rs#L429) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:601`](../../../crates/sylpheed-ppc/src/decoder.rs#L601) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrfiz | PpcOpcode::vrfiz128 => { - let vb = if matches!(instr.opcode, PpcOpcode::vrfiz128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrfiz128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].trunc(); } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrfiz(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrfiz_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1249) ── +int InstrEmit_vrfiz_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- RndToFPInt32Trunc(VB) + Value* v = f.Round(f.LoadVR(vb), ROUND_TO_ZERO); + f.StoreVR(vd, v); + return 0; +} ```
**`vrfiz128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfiz128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1282`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1282) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:118`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L118) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:663`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L663) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2464-2472`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2464-L2472) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrfiz128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1258`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1258) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:430`](../../../crates/sylpheed-ppc/src/opcode.rs#L430) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:778`](../../../crates/sylpheed-ppc/src/decoder.rs#L778) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrfiz | PpcOpcode::vrfiz128 => { - let vb = if matches!(instr.opcode, PpcOpcode::vrfiz128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrfiz128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = b[i].trunc(); } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrfiz128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrfiz_(f, VX128_3_VD128, VX128_3_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1249) ── +int InstrEmit_vrfiz_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- RndToFPInt32Trunc(VB) + Value* v = f.Round(f.LoadVR(vb), ROUND_TO_ZERO); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vrlb.md b/tools/ppc-manual/vmx/vrlb.md index 49e14402..430d20ad 100644 --- a/tools/ppc-manual/vmx/vrlb.md +++ b/tools/ppc-manual/vmx/vrlb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vrlb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrlb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1286`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1286) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:119`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L119) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:436`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L436) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3876-3883`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3876-L3883) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrlb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1262`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1262) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:431`](../../../crates/sylpheed-ppc/src/opcode.rs#L431) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:551`](../../../crates/sylpheed-ppc/src/decoder.rs#L551) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrlb => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = a[i].rotate_left((b[i] & 7) as u32); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrlb(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- ROTL((VA), (VB)&0x3) + Value* v = + f.VectorRotateLeft(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vrlh.md b/tools/ppc-manual/vmx/vrlh.md index 1688528f..3ef75955 100644 --- a/tools/ppc-manual/vmx/vrlh.md +++ b/tools/ppc-manual/vmx/vrlh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vrlh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrlh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1294`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1294) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:119`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L119) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:443`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L443) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3908-3915`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3908-L3915) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrlh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1270`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1270) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:432`](../../../crates/sylpheed-ppc/src/opcode.rs#L432) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:558`](../../../crates/sylpheed-ppc/src/decoder.rs#L558) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrlh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = a[i].rotate_left((b[i] & 0xF) as u32); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrlh(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- ROTL((VA), (VB)&0xF) + Value* v = + f.VectorRotateLeft(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vrlw.md b/tools/ppc-manual/vmx/vrlw.md index 73b65e96..13d6b7d7 100644 --- a/tools/ppc-manual/vmx/vrlw.md +++ b/tools/ppc-manual/vmx/vrlw.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,50 +114,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vrlw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrlw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1308`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1308) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:119`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L119) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:450`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L450) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2450-2461`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2450-L2461) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrlw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1284`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1284) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:434`](../../../crates/sylpheed-ppc/src/opcode.rs#L434) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:565`](../../../crates/sylpheed-ppc/src/decoder.rs#L565) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrlw | PpcOpcode::vrlw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let sh = b[i] & 0x1F; - r[i] = a[i].rotate_left(sh); - } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrlw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrlw_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1278) ── +int InstrEmit_vrlw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- ROTL((VA), (VB)&0x1F) + Value* v = f.VectorRotateLeft(f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vrlw128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrlw128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1311`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1311) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:119`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L119) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:692`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L692) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2450-2461`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2450-L2461) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrlw128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1287`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1287) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:435`](../../../crates/sylpheed-ppc/src/opcode.rs#L435) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:807`](../../../crates/sylpheed-ppc/src/decoder.rs#L807) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrlw | PpcOpcode::vrlw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let sh = b[i] & 0x1F; - r[i] = a[i].rotate_left(sh); - } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrlw128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrlw_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1278) ── +int InstrEmit_vrlw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- ROTL((VA), (VB)&0x1F) + Value* v = f.VectorRotateLeft(f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vrsqrtefp.md b/tools/ppc-manual/vmx/vrsqrtefp.md index 7a6173d4..d85c6395 100644 --- a/tools/ppc-manual/vmx/vrsqrtefp.md +++ b/tools/ppc-manual/vmx/vrsqrtefp.md @@ -82,28 +82,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -111,44 +109,52 @@ _No condition-register or status-register effects._ ## Implementation References **`vrsqrtefp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrsqrtefp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1371`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1371) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:120`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L120) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:463`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L463) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2162-2170`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2162-L2170) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrsqrtefp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1347`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1347) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:436`](../../../crates/sylpheed-ppc/src/opcode.rs#L436) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:578`](../../../crates/sylpheed-ppc/src/decoder.rs#L578) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrsqrtefp | PpcOpcode::vrsqrtefp128 => { - let vb = if matches!(instr.opcode, PpcOpcode::vrsqrtefp128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrsqrtefp128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = 1.0 / b[i].sqrt(); } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrsqrtefp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrsqrtefp_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1338) ── +int InstrEmit_vrsqrtefp_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- 1 / sqrt(VB) + // There are a lot of rules in the Altivec_PEM docs for handlings that + // result in nan/infinity/etc. They are ignored here. I hope games would + // never rely on them. + Value* v = f.RSqrt(f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
**`vrsqrtefp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrsqrtefp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1374`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1374) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:120`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L120) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:665`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L665) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2162-2170`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2162-L2170) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrsqrtefp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1350`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1350) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:437`](../../../crates/sylpheed-ppc/src/opcode.rs#L437) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:780`](../../../crates/sylpheed-ppc/src/decoder.rs#L780) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrsqrtefp | PpcOpcode::vrsqrtefp128 => { - let vb = if matches!(instr.opcode, PpcOpcode::vrsqrtefp128) { instr.vb128() } else { instr.rb() }; - let vd = if matches!(instr.opcode, PpcOpcode::vrsqrtefp128) { instr.vd128() } else { instr.rd() }; - let b = ctx.vr[vb].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = 1.0 / b[i].sqrt(); } - ctx.vr[vd] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrsqrtefp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vrsqrtefp_(f, VX128_3_VD128, VX128_3_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1338) ── +int InstrEmit_vrsqrtefp_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // (VD) <- 1 / sqrt(VB) + // There are a lot of rules in the Altivec_PEM docs for handlings that + // result in nan/infinity/etc. They are ignored here. I hope games would + // never rely on them. + Value* v = f.RSqrt(f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsel.md b/tools/ppc-manual/vmx/vsel.md index 01b23c70..cb3c3922 100644 --- a/tools/ppc-manual/vmx/vsel.md +++ b/tools/ppc-manual/vmx/vsel.md @@ -89,28 +89,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -118,72 +116,50 @@ _No condition-register or status-register effects._ ## Implementation References **`vsel`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsel"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1386`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1386) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:121`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L121) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:585`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L585) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2253-2275`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2253-L2275) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsel"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1362`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1362) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:438`](../../../crates/sylpheed-ppc/src/opcode.rs#L438) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:700`](../../../crates/sylpheed-ppc/src/decoder.rs#L700) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsel | PpcOpcode::vsel128 => { - // vD = (vA & ~vC) | (vB & vC) - let (va, vb, vd); - let vc; - if matches!(instr.opcode, PpcOpcode::vsel128) { - va = instr.va128(); - vb = instr.vb128(); - vd = instr.vd128(); - vc = vd; // for 128, vC is encoded in vD field - } else { - va = instr.ra(); - vb = instr.rb(); - vd = instr.rd(); - vc = instr.rc(); - } - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let c = ctx.vr[vc].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = (a[i] & !c[i]) | (b[i] & c[i]); } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsel(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsel_(f, i.VXA.VD, i.VXA.VA, i.VXA.VB, i.VXA.VC); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1354) ── +int InstrEmit_vsel_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb, + uint32_t vc) { + // For each bit: + // VRTi <- ((VRC)i=0) ? (VRA)i : (VRB)i + Value* v = f.Select(f.LoadVR(vc), f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
**`vsel128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsel128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1389`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1389) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:121`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L121) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:629`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L629) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2253-2275`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2253-L2275) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsel128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1365`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1365) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:439`](../../../crates/sylpheed-ppc/src/opcode.rs#L439) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:744`](../../../crates/sylpheed-ppc/src/decoder.rs#L744) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsel | PpcOpcode::vsel128 => { - // vD = (vA & ~vC) | (vB & vC) - let (va, vb, vd); - let vc; - if matches!(instr.opcode, PpcOpcode::vsel128) { - va = instr.va128(); - vb = instr.vb128(); - vd = instr.vd128(); - vc = vd; // for 128, vC is encoded in vD field - } else { - va = instr.ra(); - vb = instr.rb(); - vd = instr.rd(); - vc = instr.rc(); - } - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let c = ctx.vr[vc].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = (a[i] & !c[i]) | (b[i] & c[i]); } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsel128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsel_(f, VX128_VD128, VX128_VA128, VX128_VB128, VX128_VD128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1354) ── +int InstrEmit_vsel_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb, + uint32_t vc) { + // For each bit: + // VRTi <- ((VRC)i=0) ? (VRA)i : (VRB)i + Value* v = f.Select(f.LoadVR(vc), f.LoadVR(va), f.LoadVR(vb)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsl.md b/tools/ppc-manual/vmx/vsl.md index db5ffe01..0bb2faf7 100644 --- a/tools/ppc-manual/vmx/vsl.md +++ b/tools/ppc-manual/vmx/vsl.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,21 +84,23 @@ _No condition-register or status-register effects._ ## Implementation References **`vsl`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsl"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1402`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1402) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:122`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L122) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:472`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L472) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3920-3926`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3920-L3926) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsl"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1378`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1378) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:440`](../../../crates/sylpheed-ppc/src/opcode.rs#L440) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:587`](../../../crates/sylpheed-ppc/src/decoder.rs#L587) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsl => { - let a = u128::from_be_bytes(ctx.vr[instr.ra()].as_bytes()); - let shift = (ctx.vr[instr.rb()].as_bytes()[15] & 7) as u32; - let r = if shift == 0 { a } else { a << shift }; - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r.to_be_bytes()); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsl(PPCHIRBuilder& f, const InstrData& i) { + Value* va = f.LoadVR(i.VX.VA); + Value* vb = f.LoadVR(i.VX.VB); + + AssertShiftElementsOk(f, vb); + Value* v = + f.Shl(va, f.And(f.Extract(vb, 15, INT8_TYPE), f.LoadConstantInt8(0b111))); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vslb.md b/tools/ppc-manual/vmx/vslb.md index ee7c3343..d89c3a4a 100644 --- a/tools/ppc-manual/vmx/vslb.md +++ b/tools/ppc-manual/vmx/vslb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,18 @@ _No condition-register or status-register effects._ ## Implementation References **`vslb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1413`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1413) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:122`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L122) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:455`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L455) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3852-3859`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3852-L3859) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1389`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1389) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:441`](../../../crates/sylpheed-ppc/src/opcode.rs#L441) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:570`](../../../crates/sylpheed-ppc/src/decoder.rs#L570) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vslb => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = a[i] << (b[i] & 7); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vslb(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorShl(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsldoi.md b/tools/ppc-manual/vmx/vsldoi.md index 43f45f57..3ef75a7a 100644 --- a/tools/ppc-manual/vmx/vsldoi.md +++ b/tools/ppc-manual/vmx/vsldoi.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,51 +114,62 @@ _No condition-register or status-register effects._ ## Implementation References **`vsldoi`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsldoi"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1477`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1477) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:122`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L122) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:587`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L587) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2303-2314`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2303-L2314) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsldoi"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1463`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1463) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:442`](../../../crates/sylpheed-ppc/src/opcode.rs#L442) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:702`](../../../crates/sylpheed-ppc/src/decoder.rs#L702) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsldoi => { - let a_bytes = ctx.vr[instr.ra()].as_bytes(); - let b_bytes = ctx.vr[instr.rb()].as_bytes(); - let sh = ((instr.raw >> 6) & 0xF) as usize; // SH field bits 6-9 - let mut concat = [0u8; 32]; - concat[..16].copy_from_slice(&a_bytes); - concat[16..].copy_from_slice(&b_bytes); - let mut r = [0u8; 16]; - r.copy_from_slice(&concat[sh..sh + 16]); - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsldoi(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsldoi_(f, i.VXA.VD, i.VXA.VA, i.VXA.VB, i.VXA.VC & 0xF); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1434) ── +int InstrEmit_vsldoi_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb, + uint32_t sh) { + // (VD) <- ((VA) || (VB)) << (SH << 3) + if (!sh) { + f.StoreVR(vd, f.LoadVR(va)); + return 0; + } else if (sh == 16) { + f.StoreVR(vd, f.LoadVR(vb)); + return 0; + } + Value* v; + if (!(sh & 3)) { + // Word-aligned shifts can use the cheaper 32-bit permute. + uint32_t control = 0; + uint32_t source_word = sh >> 2; + for (uint32_t output_word = 0; output_word < 4; + ++output_word, ++source_word) { + control |= ((source_word & 3) | ((source_word & 4) ? 4 : 0)) + << (output_word * 8); + } + v = f.Permute(f.LoadConstantUint32(control), f.LoadVR(va), f.LoadVR(vb), + INT32_TYPE); + } else { + Value* control = f.LoadConstantVec128(__vsldoi_table[sh]); + v = f.Permute(control, f.LoadVR(va), f.LoadVR(vb), INT8_TYPE); + } + f.StoreVR(vd, v); + return 0; +} ```
**`vsldoi128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsldoi128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1480`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1480) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:122`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L122) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:595`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L595) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2315-2327`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2315-L2327) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsldoi128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1466`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1466) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:443`](../../../crates/sylpheed-ppc/src/opcode.rs#L443) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:710`](../../../crates/sylpheed-ppc/src/decoder.rs#L710) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsldoi128 => { - let a_bytes = ctx.vr[instr.va128()].as_bytes(); - let b_bytes = ctx.vr[instr.vb128()].as_bytes(); - let sh = instr.vx128_5_sh() as usize; - let mut concat = [0u8; 32]; - concat[..16].copy_from_slice(&a_bytes); - concat[16..].copy_from_slice(&b_bytes); - let mut r = [0u8; 16]; - let sh = sh.min(16); - r.copy_from_slice(&concat[sh..sh + 16]); - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsldoi128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsldoi_(f, VX128_5_VD128, VX128_5_VA128, VX128_5_VB128, + VX128_5_SH); +} ```
diff --git a/tools/ppc-manual/vmx/vslh.md b/tools/ppc-manual/vmx/vslh.md index 42a342c4..b39a320b 100644 --- a/tools/ppc-manual/vmx/vslh.md +++ b/tools/ppc-manual/vmx/vslh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,18 @@ _No condition-register or status-register effects._ ## Implementation References **`vslh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1419`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1419) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:122`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L122) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:461`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L461) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3884-3891`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3884-L3891) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1395`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1395) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:444`](../../../crates/sylpheed-ppc/src/opcode.rs#L444) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:576`](../../../crates/sylpheed-ppc/src/decoder.rs#L576) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vslh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = a[i] << (b[i] & 0xF); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vslh(PPCHIRBuilder& f, const InstrData& i) { + Value* v = f.VectorShl(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vslo.md b/tools/ppc-manual/vmx/vslo.md index 9cffe32b..e16f4abf 100644 --- a/tools/ppc-manual/vmx/vslo.md +++ b/tools/ppc-manual/vmx/vslo.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,46 +114,56 @@ _No condition-register or status-register effects._ ## Implementation References **`vslo`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslo"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1496`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1496) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:122`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L122) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:523`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L523) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3935-3944`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3935-L3944) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslo"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1482`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1482) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:445`](../../../crates/sylpheed-ppc/src/opcode.rs#L445) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:638`](../../../crates/sylpheed-ppc/src/decoder.rs#L638) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vslo | PpcOpcode::vslo128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vslo128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = u128::from_be_bytes(ctx.vr[ra].as_bytes()); - let nbytes = ((ctx.vr[rb].as_bytes()[15] >> 3) & 0xF) as u32; - let r = if nbytes == 0 { a } else { a << (nbytes * 8) }; - ctx.vr[rd] = xenia_types::Vec128::from_bytes(r.to_be_bytes()); - ctx.pc += 4; - } +```cpp +int InstrEmit_vslo(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vslo_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1471) ── +int InstrEmit_vslo_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) << (VB.b[F] & 0x78) (by octet) + // TODO(benvanik): flag for shift-by-octet as optimization. + Value* sh = f.Shr( + f.And(f.Extract(f.LoadVR(vb), 15, INT8_TYPE), f.LoadConstantInt8(0x78)), + 3); + Value* v = f.Permute(f.LoadVectorShl(sh), f.LoadVR(va), f.LoadZeroVec128(), + INT8_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vslo128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslo128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1499`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1499) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:122`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L122) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:631`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L631) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3935-3944`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3935-L3944) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslo128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1485`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1485) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:446`](../../../crates/sylpheed-ppc/src/opcode.rs#L446) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:746`](../../../crates/sylpheed-ppc/src/decoder.rs#L746) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vslo | PpcOpcode::vslo128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vslo128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = u128::from_be_bytes(ctx.vr[ra].as_bytes()); - let nbytes = ((ctx.vr[rb].as_bytes()[15] >> 3) & 0xF) as u32; - let r = if nbytes == 0 { a } else { a << (nbytes * 8) }; - ctx.vr[rd] = xenia_types::Vec128::from_bytes(r.to_be_bytes()); - ctx.pc += 4; - } +```cpp +int InstrEmit_vslo128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vslo_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1471) ── +int InstrEmit_vslo_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) << (VB.b[F] & 0x78) (by octet) + // TODO(benvanik): flag for shift-by-octet as optimization. + Value* sh = f.Shr( + f.And(f.Extract(f.LoadVR(vb), 15, INT8_TYPE), f.LoadConstantInt8(0x78)), + 3); + Value* v = f.Permute(f.LoadVectorShl(sh), f.LoadVR(va), f.LoadZeroVec128(), + INT8_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vslw.md b/tools/ppc-manual/vmx/vslw.md index b9363167..8b400ea8 100644 --- a/tools/ppc-manual/vmx/vslw.md +++ b/tools/ppc-manual/vmx/vslw.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,50 +114,50 @@ _No condition-register or status-register effects._ ## Implementation References **`vslw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1433`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1433) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:122`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L122) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:468`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L468) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2414-2425`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2414-L2425) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1409`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1409) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:447`](../../../crates/sylpheed-ppc/src/opcode.rs#L447) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:583`](../../../crates/sylpheed-ppc/src/decoder.rs#L583) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vslw | PpcOpcode::vslw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let sh = b[i] & 0x1F; - r[i] = a[i] << sh; - } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vslw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vslw_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1401) ── +int InstrEmit_vslw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VA = |xxxxx|yyyyy|zzzzz|wwwww| + // VB = |...sh|...sh|...sh|...sh| + // VD = |x< **`vslw128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslw128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1436`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1436) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:122`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L122) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:693`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L693) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2414-2425`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2414-L2425) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vslw128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1412`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1412) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:448`](../../../crates/sylpheed-ppc/src/opcode.rs#L448) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:808`](../../../crates/sylpheed-ppc/src/decoder.rs#L808) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vslw | PpcOpcode::vslw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let sh = b[i] & 0x1F; - r[i] = a[i] << sh; - } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vslw128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vslw_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1401) ── +int InstrEmit_vslw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VA = |xxxxx|yyyyy|zzzzz|wwwww| + // VB = |...sh|...sh|...sh|...sh| + // VD = |x< diff --git a/tools/ppc-manual/vmx/vspltb.md b/tools/ppc-manual/vmx/vspltb.md index 4ea9198c..6eee471b 100644 --- a/tools/ppc-manual/vmx/vspltb.md +++ b/tools/ppc-manual/vmx/vspltb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,21 +84,22 @@ _No condition-register or status-register effects._ ## Implementation References **`vspltb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1503`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1503) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:123`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L123) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:480`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L480) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2349-2355`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2349-L2355) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1489`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1489) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:449`](../../../crates/sylpheed-ppc/src/opcode.rs#L449) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:595`](../../../crates/sylpheed-ppc/src/decoder.rs#L595) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vspltb => { - let uimm = ((instr.raw >> 16) & 0xF) as usize; - let b = ctx.vr[instr.rb()].as_bytes(); - let val = b[uimm]; - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes([val; 16]); - ctx.pc += 4; - } +```cpp +int InstrEmit_vspltb(PPCHIRBuilder& f, const InstrData& i) { + // b <- UIMM*8 + // do i = 0 to 127 by 8 + // (VD)[i:i+7] <- (VB)[b:b+7] + Value* b = f.Extract(f.LoadVR(i.VX.VB), i.VX.VA & 0xF, INT8_TYPE); + Value* v = f.Splat(b, VEC128_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsplth.md b/tools/ppc-manual/vmx/vsplth.md index 857422f3..b3677adc 100644 --- a/tools/ppc-manual/vmx/vsplth.md +++ b/tools/ppc-manual/vmx/vsplth.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,21 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vsplth`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsplth"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1513`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1513) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:123`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L123) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:487`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L487) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2342-2348`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2342-L2348) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsplth"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1499`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1499) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:450`](../../../crates/sylpheed-ppc/src/opcode.rs#L450) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:602`](../../../crates/sylpheed-ppc/src/decoder.rs#L602) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsplth => { - let uimm = ((instr.raw >> 16) & 0x7) as usize; - let b = ctx.vr[instr.rb()].as_u16x8(); - let val = b[uimm]; - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array([val; 8]); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsplth(PPCHIRBuilder& f, const InstrData& i) { + // (VD.xyzw) <- (VB.uimm) + Value* h = f.Extract(f.LoadVR(i.VX.VB), i.VX.VA & 0x7, INT16_TYPE); + Value* v = f.Splat(h, VEC128_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vspltisb.md b/tools/ppc-manual/vmx/vspltisb.md index 8b2134bd..375a4e82 100644 --- a/tools/ppc-manual/vmx/vspltisb.md +++ b/tools/ppc-manual/vmx/vspltisb.md @@ -56,28 +56,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,20 +83,27 @@ _No condition-register or status-register effects._ ## Implementation References **`vspltisb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltisb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1536`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1536) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:123`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L123) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:503`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L503) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2364-2369`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2364-L2369) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltisb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1522`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1522) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:451`](../../../crates/sylpheed-ppc/src/opcode.rs#L451) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:618`](../../../crates/sylpheed-ppc/src/decoder.rs#L618) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vspltisb => { - let simm = ((instr.raw >> 16) & 0x1F) as i8; - let simm = if simm & 0x10 != 0 { simm | !0x1F } else { simm }; - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes([simm as u8; 16]); - ctx.pc += 4; - } +```cpp +int InstrEmit_vspltisb(PPCHIRBuilder& f, const InstrData& i) { + // (VD.xyzw) <- sign_extend(uimm) + Value* v; + if (i.VX.VA) { + // Sign extend from 5bits -> 8 and load. + int8_t simm = (i.VX.VA & 0x10) ? (i.VX.VA | 0xF0) : i.VX.VA; + v = f.Splat(f.LoadConstantInt8(simm), VEC128_TYPE); + } else { + // Zero out the register. + v = f.LoadZeroVec128(); + } + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vspltish.md b/tools/ppc-manual/vmx/vspltish.md index 82e009aa..1265ca60 100644 --- a/tools/ppc-manual/vmx/vspltish.md +++ b/tools/ppc-manual/vmx/vspltish.md @@ -56,28 +56,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,20 +83,27 @@ _No condition-register or status-register effects._ ## Implementation References **`vspltish`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltish"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1551`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1551) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:123`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L123) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:510`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L510) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2370-2375`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2370-L2375) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltish"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1537`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1537) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:452`](../../../crates/sylpheed-ppc/src/opcode.rs#L452) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:625`](../../../crates/sylpheed-ppc/src/decoder.rs#L625) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vspltish => { - let simm = ((instr.raw >> 16) & 0x1F) as i16; - let simm = if simm & 0x10 != 0 { simm | !0x1F } else { simm }; - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array([simm as u16; 8]); - ctx.pc += 4; - } +```cpp +int InstrEmit_vspltish(PPCHIRBuilder& f, const InstrData& i) { + // (VD.xyzw) <- sign_extend(uimm) + Value* v; + if (i.VX.VA) { + // Sign extend from 5bits -> 16 and load. + int16_t simm = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFF0) : i.VX.VA; + v = f.Splat(f.LoadConstantInt16(simm), VEC128_TYPE); + } else { + // Zero out the register. + v = f.LoadZeroVec128(); + } + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vspltisw.md b/tools/ppc-manual/vmx/vspltisw.md index 0aa243b4..d01b0148 100644 --- a/tools/ppc-manual/vmx/vspltisw.md +++ b/tools/ppc-manual/vmx/vspltisw.md @@ -82,28 +82,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -111,42 +109,62 @@ _No condition-register or status-register effects._ ## Implementation References **`vspltisw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltisw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1580`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1580) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:123`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L123) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:516`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L516) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2356-2363`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2356-L2363) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltisw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1566`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1566) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:453`](../../../crates/sylpheed-ppc/src/opcode.rs#L453) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:631`](../../../crates/sylpheed-ppc/src/decoder.rs#L631) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vspltisw | PpcOpcode::vspltisw128 => { - let simm = ((instr.raw >> 16) & 0x1F) as i32; - let simm = if simm & 0x10 != 0 { simm | !0x1F } else { simm }; // sign extend 5-bit - let val = simm as u32; - let vd = if matches!(instr.opcode, PpcOpcode::vspltisw128) { instr.vd128() } else { instr.rd() }; - ctx.vr[vd] = xenia_types::Vec128::from_u32x4(val, val, val, val); - ctx.pc += 4; - } +```cpp +int InstrEmit_vspltisw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vspltisw_(f, i.VX.VD, i.VX.VA); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1552) ── +int InstrEmit_vspltisw_(PPCHIRBuilder& f, uint32_t vd, uint32_t uimm) { + // (VD.xyzw) <- sign_extend(uimm) + Value* v; + if (uimm) { + // Sign extend from 5bits -> 32 and load. + int32_t simm = (uimm & 0x10) ? (uimm | 0xFFFFFFF0) : uimm; + v = f.Splat(f.LoadConstantInt32(simm), VEC128_TYPE); + } else { + // Zero out the register. + v = f.LoadZeroVec128(); + } + f.StoreVR(vd, v); + return 0; +} ```
**`vspltisw128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltisw128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1583`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1583) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:123`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L123) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:669`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L669) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2356-2363`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2356-L2363) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltisw128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1569`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1569) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:454`](../../../crates/sylpheed-ppc/src/opcode.rs#L454) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:784`](../../../crates/sylpheed-ppc/src/decoder.rs#L784) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vspltisw | PpcOpcode::vspltisw128 => { - let simm = ((instr.raw >> 16) & 0x1F) as i32; - let simm = if simm & 0x10 != 0 { simm | !0x1F } else { simm }; // sign extend 5-bit - let val = simm as u32; - let vd = if matches!(instr.opcode, PpcOpcode::vspltisw128) { instr.vd128() } else { instr.rd() }; - ctx.vr[vd] = xenia_types::Vec128::from_u32x4(val, val, val, val); - ctx.pc += 4; - } +```cpp +int InstrEmit_vspltisw128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vspltisw_(f, VX128_3_VD128, VX128_3_IMM); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1552) ── +int InstrEmit_vspltisw_(PPCHIRBuilder& f, uint32_t vd, uint32_t uimm) { + // (VD.xyzw) <- sign_extend(uimm) + Value* v; + if (uimm) { + // Sign extend from 5bits -> 32 and load. + int32_t simm = (uimm & 0x10) ? (uimm | 0xFFFFFFF0) : uimm; + v = f.Splat(f.LoadConstantInt32(simm), VEC128_TYPE); + } else { + // Zero out the register. + v = f.LoadZeroVec128(); + } + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vspltw.md b/tools/ppc-manual/vmx/vspltw.md index 5ff1a519..2e9323f0 100644 --- a/tools/ppc-manual/vmx/vspltw.md +++ b/tools/ppc-manual/vmx/vspltw.md @@ -83,28 +83,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -112,40 +110,50 @@ _No condition-register or status-register effects._ ## Implementation References **`vspltw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1529`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1529) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:123`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L123) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:493`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L493) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2328-2334`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2328-L2334) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1515`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1515) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:455`](../../../crates/sylpheed-ppc/src/opcode.rs#L455) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:608`](../../../crates/sylpheed-ppc/src/decoder.rs#L608) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vspltw => { - let uimm = ((instr.raw >> 16) & 0x3) as usize; // UIMM (2 bits for word index) - let b = ctx.vr[instr.rb()].as_u32x4(); - let val = b[uimm]; - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4(val, val, val, val); - ctx.pc += 4; - } +```cpp +int InstrEmit_vspltw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vspltw_(f, i.VX.VD, i.VX.VB, i.VX.VA); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1507) ── +int InstrEmit_vspltw_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb, + uint32_t uimm) { + // (VD.xyzw) <- (VB.uimm) + Value* w = f.Extract(f.LoadVR(vb), uimm & 0x3, INT32_TYPE); + Value* v = f.Splat(w, VEC128_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vspltw128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltw128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1532`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1532) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:123`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L123) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:668`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L668) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2335-2341`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2335-L2341) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vspltw128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1518`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1518) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:456`](../../../crates/sylpheed-ppc/src/opcode.rs#L456) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:783`](../../../crates/sylpheed-ppc/src/decoder.rs#L783) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vspltw128 => { - let uimm = ((instr.raw >> 16) & 0x3) as usize; - let b = ctx.vr[instr.vb128()].as_u32x4(); - let val = b[uimm]; - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_u32x4(val, val, val, val); - ctx.pc += 4; - } +```cpp +int InstrEmit_vspltw128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vspltw_(f, VX128_3_VD128, VX128_3_VB128, VX128_3_IMM); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1507) ── +int InstrEmit_vspltw_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb, + uint32_t uimm) { + // (VD.xyzw) <- (VB.uimm) + Value* w = f.Extract(f.LoadVR(vb), uimm & 0x3, INT32_TYPE); + Value* v = f.Splat(w, VEC128_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsr.md b/tools/ppc-manual/vmx/vsr.md index 4fc18dea..58ef8e2d 100644 --- a/tools/ppc-manual/vmx/vsr.md +++ b/tools/ppc-manual/vmx/vsr.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,21 +84,24 @@ _No condition-register or status-register effects._ ## Implementation References **`vsr`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsr"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1587`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1587) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:495`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L495) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3927-3933`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3927-L3933) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsr"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1573`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1573) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:457`](../../../crates/sylpheed-ppc/src/opcode.rs#L457) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:610`](../../../crates/sylpheed-ppc/src/decoder.rs#L610) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsr => { - let a = u128::from_be_bytes(ctx.vr[instr.ra()].as_bytes()); - let shift = (ctx.vr[instr.rb()].as_bytes()[15] & 7) as u32; - let r = if shift == 0 { a } else { a >> shift }; - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r.to_be_bytes()); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsr(PPCHIRBuilder& f, const InstrData& i) { + Value* va = f.LoadVR(i.VX.VA); + Value* vb = f.LoadVR(i.VX.VB); + + AssertShiftElementsOk(f, vb); + + Value* v = + f.Shr(va, f.And(f.Extract(vb, 15, INT8_TYPE), f.LoadConstantInt8(0b111))); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsrab.md b/tools/ppc-manual/vmx/vsrab.md index 3b5c2afa..d40e6b32 100644 --- a/tools/ppc-manual/vmx/vsrab.md +++ b/tools/ppc-manual/vmx/vsrab.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vsrab`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrab"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1599`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1599) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:500`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L500) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3868-3875`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3868-L3875) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrab"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1585`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1585) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:458`](../../../crates/sylpheed-ppc/src/opcode.rs#L458) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:615`](../../../crates/sylpheed-ppc/src/decoder.rs#L615) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsrab => { - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0i8; 16]; - for i in 0..16 { r[i] = a[i] >> (b[i] & 7); } - ctx.vr[instr.rd()] = crate::vmx::from_i8x16(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsrab(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- (VA) >>a (VB) by bytes + Value* v = f.VectorSha(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsrah.md b/tools/ppc-manual/vmx/vsrah.md index 576c6dc8..4ae6d332 100644 --- a/tools/ppc-manual/vmx/vsrah.md +++ b/tools/ppc-manual/vmx/vsrah.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vsrah`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrah"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1606`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1606) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:507`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L507) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3900-3907`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3900-L3907) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrah"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1592`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1592) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:459`](../../../crates/sylpheed-ppc/src/opcode.rs#L459) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:622`](../../../crates/sylpheed-ppc/src/decoder.rs#L622) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsrah => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0i16; 8]; - for i in 0..8 { r[i] = a[i] >> (b[i] & 0xF); } - ctx.vr[instr.rd()] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsrah(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- (VA) >>a (VB) by halfwords + Value* v = f.VectorSha(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsraw.md b/tools/ppc-manual/vmx/vsraw.md index 69b66ea6..a047e6c0 100644 --- a/tools/ppc-manual/vmx/vsraw.md +++ b/tools/ppc-manual/vmx/vsraw.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,50 +114,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vsraw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsraw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1619`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1619) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:514`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L514) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2438-2449`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2438-L2449) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsraw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1605`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1605) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:460`](../../../crates/sylpheed-ppc/src/opcode.rs#L460) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:629`](../../../crates/sylpheed-ppc/src/decoder.rs#L629) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsraw | PpcOpcode::vsraw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let sh = b[i] & 0x1F; - r[i] = (a[i] as i32 >> sh) as u32; - } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsraw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsraw_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1599) ── +int InstrEmit_vsraw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) >>a (VB) by words + Value* v = f.VectorSha(f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vsraw128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsraw128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1622`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1622) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:694`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L694) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2438-2449`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2438-L2449) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsraw128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1608`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1608) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:461`](../../../crates/sylpheed-ppc/src/opcode.rs#L461) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:809`](../../../crates/sylpheed-ppc/src/decoder.rs#L809) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsraw | PpcOpcode::vsraw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let sh = b[i] & 0x1F; - r[i] = (a[i] as i32 >> sh) as u32; - } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsraw128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsraw_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1599) ── +int InstrEmit_vsraw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) >>a (VB) by words + Value* v = f.VectorSha(f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsrb.md b/tools/ppc-manual/vmx/vsrb.md index bb9c41de..643c8aa5 100644 --- a/tools/ppc-manual/vmx/vsrb.md +++ b/tools/ppc-manual/vmx/vsrb.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vsrb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1626`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1626) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:477`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L477) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3860-3867`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3860-L3867) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1612`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1612) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:462`](../../../crates/sylpheed-ppc/src/opcode.rs#L462) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:592`](../../../crates/sylpheed-ppc/src/decoder.rs#L592) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsrb => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = a[i] >> (b[i] & 7); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsrb(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- (VA) >> (VB) by bytes + Value* v = f.VectorShr(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsrh.md b/tools/ppc-manual/vmx/vsrh.md index 821ab6cd..7181fb64 100644 --- a/tools/ppc-manual/vmx/vsrh.md +++ b/tools/ppc-manual/vmx/vsrh.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vsrh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1633`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1633) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:484`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L484) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3892-3899`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3892-L3899) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1619`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1619) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:463`](../../../crates/sylpheed-ppc/src/opcode.rs#L463) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:599`](../../../crates/sylpheed-ppc/src/decoder.rs#L599) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsrh => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = a[i] >> (b[i] & 0xF); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsrh(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- (VA) >> (VB) by halfwords + Value* v = f.VectorShr(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsro.md b/tools/ppc-manual/vmx/vsro.md index d0d74317..0b039f8f 100644 --- a/tools/ppc-manual/vmx/vsro.md +++ b/tools/ppc-manual/vmx/vsro.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,46 +114,56 @@ _No condition-register or status-register effects._ ## Implementation References **`vsro`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsro"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1651`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1651) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:528`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L528) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3945-3954`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3945-L3954) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsro"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1637`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1637) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:464`](../../../crates/sylpheed-ppc/src/opcode.rs#L464) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:643`](../../../crates/sylpheed-ppc/src/decoder.rs#L643) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsro | PpcOpcode::vsro128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vsro128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = u128::from_be_bytes(ctx.vr[ra].as_bytes()); - let nbytes = ((ctx.vr[rb].as_bytes()[15] >> 3) & 0xF) as u32; - let r = if nbytes == 0 { a } else { a >> (nbytes * 8) }; - ctx.vr[rd] = xenia_types::Vec128::from_bytes(r.to_be_bytes()); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsro(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsro_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1626) ── +int InstrEmit_vsro_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) >> (VB.b[F] & 0x78) (by octet) + // TODO(benvanik): flag for shift-by-octet as optimization. + Value* sh = f.Shr( + f.And(f.Extract(f.LoadVR(vb), 15, INT8_TYPE), f.LoadConstantInt8(0x78)), + 3); + Value* v = f.Permute(f.LoadVectorShr(sh), f.LoadZeroVec128(), f.LoadVR(va), + INT8_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vsro128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsro128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1654`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1654) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:633`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L633) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3945-3954`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3945-L3954) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsro128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1640`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1640) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:465`](../../../crates/sylpheed-ppc/src/opcode.rs#L465) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:748`](../../../crates/sylpheed-ppc/src/decoder.rs#L748) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsro | PpcOpcode::vsro128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vsro128); - let (ra, rb, rd) = if is_128 { (instr.va128(), instr.vb128(), instr.vd128()) } - else { (instr.ra(), instr.rb(), instr.rd()) }; - let a = u128::from_be_bytes(ctx.vr[ra].as_bytes()); - let nbytes = ((ctx.vr[rb].as_bytes()[15] >> 3) & 0xF) as u32; - let r = if nbytes == 0 { a } else { a >> (nbytes * 8) }; - ctx.vr[rd] = xenia_types::Vec128::from_bytes(r.to_be_bytes()); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsro128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsro_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1626) ── +int InstrEmit_vsro_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) >> (VB.b[F] & 0x78) (by octet) + // TODO(benvanik): flag for shift-by-octet as optimization. + Value* sh = f.Shr( + f.And(f.Extract(f.LoadVR(vb), 15, INT8_TYPE), f.LoadConstantInt8(0x78)), + 3); + Value* v = f.Permute(f.LoadVectorShr(sh), f.LoadZeroVec128(), f.LoadVR(va), + INT8_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsrw.md b/tools/ppc-manual/vmx/vsrw.md index 90f04683..45c2438f 100644 --- a/tools/ppc-manual/vmx/vsrw.md +++ b/tools/ppc-manual/vmx/vsrw.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,50 +114,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vsrw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1664`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1664) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:491`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L491) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2426-2437`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2426-L2437) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1650`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1650) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:466`](../../../crates/sylpheed-ppc/src/opcode.rs#L466) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:606`](../../../crates/sylpheed-ppc/src/decoder.rs#L606) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsrw | PpcOpcode::vsrw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let sh = b[i] & 0x1F; - r[i] = a[i] >> sh; - } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsrw(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsrw_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1644) ── +int InstrEmit_vsrw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) >> (VB) by words + Value* v = f.VectorShr(f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vsrw128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrw128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1667`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1667) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:124`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L124) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:695`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L695) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2426-2437`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2426-L2437) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsrw128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1653`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1653) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:467`](../../../crates/sylpheed-ppc/src/opcode.rs#L467) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:810`](../../../crates/sylpheed-ppc/src/decoder.rs#L810) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsrw | PpcOpcode::vsrw128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { - let sh = b[i] & 0x1F; - r[i] = a[i] >> sh; - } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsrw128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsrw_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1644) ── +int InstrEmit_vsrw_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) >> (VB) by words + Value* v = f.VectorShr(f.LoadVR(va), f.LoadVR(vb), INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsubcuw.md b/tools/ppc-manual/vmx/vsubcuw.md index cd1d8540..22f5d2c0 100644 --- a/tools/ppc-manual/vmx/vsubcuw.md +++ b/tools/ppc-manual/vmx/vsubcuw.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,23 +84,21 @@ _No condition-register or status-register effects._ ## Implementation References **`vsubcuw`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubcuw"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1671`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1671) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:125`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L125) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:536`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L536) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3391-3399`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3391-L3399) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubcuw"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1657`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1657) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:468`](../../../crates/sylpheed-ppc/src/opcode.rs#L468) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:651`](../../../crates/sylpheed-ppc/src/decoder.rs#L651) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsubcuw => { - // "Subtract Carryout": r = 1 if a >= b (no borrow), 0 otherwise. - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = if a[i] >= b[i] { 1 } else { 0 }; } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsubcuw(PPCHIRBuilder& f, const InstrData& i) { + Value* underflow = + f.VectorCompareUGE(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE); + Value* borrow = + f.VectorShr(underflow, f.LoadConstantVec128(vec128i(31)), INT32_TYPE); + f.StoreVR(i.VX.VD, borrow); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsubfp.md b/tools/ppc-manual/vmx/vsubfp.md index c473a8ef..3bd376e9 100644 --- a/tools/ppc-manual/vmx/vsubfp.md +++ b/tools/ppc-manual/vmx/vsubfp.md @@ -94,13 +94,15 @@ for each 32-bit float lane i in 0..3: ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -108,52 +110,46 @@ for each 32-bit float lane i in 0..3: ## Implementation References **`vsubfp`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubfp"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1686`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1686) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:125`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L125) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:445`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L445) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2012-2024`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2012-L2024) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubfp"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1672`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1672) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:469`](../../../crates/sylpheed-ppc/src/opcode.rs#L469) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:560`](../../../crates/sylpheed-ppc/src/decoder.rs#L560) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsubfp => { - // PPCBUG-435. - let a = ctx.vr[instr.ra()].as_f32x4(); - let b = ctx.vr[instr.rb()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { - let ai = vmx::flush_denorm(a[i]); - let bi = vmx::flush_denorm(b[i]); - r[i] = vmx::flush_denorm(ai - bi); - } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsubfp(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsubfp_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1666) ── +int InstrEmit_vsubfp_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) - (VB) (4 x fp) + Value* v = f.VectorSub(f.LoadVR(va), f.LoadVR(vb), FLOAT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
**`vsubfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1689`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1689) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:125`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L125) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:611`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L611) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2025-2037`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2025-L2037) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1675`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1675) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:470`](../../../crates/sylpheed-ppc/src/opcode.rs#L470) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:726`](../../../crates/sylpheed-ppc/src/decoder.rs#L726) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsubfp128 => { - // PPCBUG-435. - let a = ctx.vr[instr.va128()].as_f32x4(); - let b = ctx.vr[instr.vb128()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { - let ai = vmx::flush_denorm(a[i]); - let bi = vmx::flush_denorm(b[i]); - r[i] = vmx::flush_denorm(ai - bi); - } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsubfp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vsubfp_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1666) ── +int InstrEmit_vsubfp_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // (VD) <- (VA) - (VB) (4 x fp) + Value* v = f.VectorSub(f.LoadVR(va), f.LoadVR(vb), FLOAT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsubsbs.md b/tools/ppc-manual/vmx/vsubsbs.md index b645dd3a..bfdba8fb 100644 --- a/tools/ppc-manual/vmx/vsubsbs.md +++ b/tools/ppc-manual/vmx/vsubsbs.md @@ -58,28 +58,26 @@ vsubsbs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,21 @@ vsubsbs [VD], [VA], [VB] ## Implementation References **`vsubsbs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubsbs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1693`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1693) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:125`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L125) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:546`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L546) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3270-3281`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3270-L3281) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubsbs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1679`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1679) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:471`](../../../crates/sylpheed-ppc/src/opcode.rs#L471) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:661`](../../../crates/sylpheed-ppc/src/decoder.rs#L661) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsubsbs => { - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i8x16(ctx.vr[instr.rb()]); - let mut r = [0i8; 16]; let mut sat = false; - for i in 0..16 { - let (v, s) = crate::vmx::sat_sub_i8(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i8x16(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsubsbs(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- clamp(EXTS(VA) + ¬EXTS(VB) + 1, -128, 127) + Value* v = f.VectorSub(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE, + ARITHMETIC_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsubshs.md b/tools/ppc-manual/vmx/vsubshs.md index 58382e00..af28df1b 100644 --- a/tools/ppc-manual/vmx/vsubshs.md +++ b/tools/ppc-manual/vmx/vsubshs.md @@ -58,28 +58,26 @@ vsubshs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,21 @@ vsubshs [VD], [VA], [VB] ## Implementation References **`vsubshs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubshs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1702`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1702) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:125`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L125) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:548`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L548) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3318-3329`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3318-L3329) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubshs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1688`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1688) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:472`](../../../crates/sylpheed-ppc/src/opcode.rs#L472) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:663`](../../../crates/sylpheed-ppc/src/decoder.rs#L663) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsubshs => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let mut r = [0i16; 8]; let mut sat = false; - for i in 0..8 { - let (v, s) = crate::vmx::sat_sub_i16(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsubshs(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- clamp(EXTS(VA) + ¬EXTS(VB) + 1, -2^15, 2^15-1) + Value* v = f.VectorSub(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE, + ARITHMETIC_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsubsws.md b/tools/ppc-manual/vmx/vsubsws.md index e287432b..fcdd2933 100644 --- a/tools/ppc-manual/vmx/vsubsws.md +++ b/tools/ppc-manual/vmx/vsubsws.md @@ -58,28 +58,26 @@ vsubsws [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,21 @@ vsubsws [VD], [VA], [VB] ## Implementation References **`vsubsws`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubsws"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1711`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1711) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:125`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L125) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:549`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L549) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3366-3377`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3366-L3377) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubsws"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1697`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1697) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:473`](../../../crates/sylpheed-ppc/src/opcode.rs#L473) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:664`](../../../crates/sylpheed-ppc/src/decoder.rs#L664) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsubsws => { - let a = crate::vmx::as_i32x4(ctx.vr[instr.ra()]); - let b = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; let mut sat = false; - for i in 0..4 { - let (v, s) = crate::vmx::sat_sub_i32(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsubsws(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- clamp(EXTS(VA) + ¬EXTS(VB) + 1, -2^31, 2^31-1) + Value* v = f.VectorSub(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, + ARITHMETIC_SATURATE); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsububm.md b/tools/ppc-manual/vmx/vsububm.md index e5f84c8b..b7207a53 100644 --- a/tools/ppc-manual/vmx/vsububm.md +++ b/tools/ppc-manual/vmx/vsububm.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vsububm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsububm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1720`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1720) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:126`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L126) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:519`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L519) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3206-3213`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3206-L3213) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsububm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1706`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1706) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:474`](../../../crates/sylpheed-ppc/src/opcode.rs#L474) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:634`](../../../crates/sylpheed-ppc/src/decoder.rs#L634) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsububm => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; - for i in 0..16 { r[i] = a[i].wrapping_sub(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsububm(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- (EXTZ(VA) + ¬EXTZ(VB) + 1) % 256 + Value* v = f.VectorSub(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsububs.md b/tools/ppc-manual/vmx/vsububs.md index 896c003f..7ddbe531 100644 --- a/tools/ppc-manual/vmx/vsububs.md +++ b/tools/ppc-manual/vmx/vsububs.md @@ -58,28 +58,26 @@ vsububs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,21 @@ vsububs [VD], [VA], [VB] ## Implementation References **`vsububs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsububs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1744`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1744) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:126`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L126) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:538`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L538) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3246-3257`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3246-L3257) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsububs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1730`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1730) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:475`](../../../crates/sylpheed-ppc/src/opcode.rs#L475) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:653`](../../../crates/sylpheed-ppc/src/decoder.rs#L653) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsububs => { - let a = ctx.vr[instr.ra()].as_bytes(); - let b = ctx.vr[instr.rb()].as_bytes(); - let mut r = [0u8; 16]; let mut sat = false; - for i in 0..16 { - let (v, s) = crate::vmx::sat_sub_u8(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_bytes(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsububs(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- clamp(EXTZ(VA) + ¬EXTZ(VB) + 1, 0, 256) + Value* v = f.VectorSub(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT8_TYPE, + ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsubuhm.md b/tools/ppc-manual/vmx/vsubuhm.md index f1b09048..bf89a390 100644 --- a/tools/ppc-manual/vmx/vsubuhm.md +++ b/tools/ppc-manual/vmx/vsubuhm.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vsubuhm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubuhm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1728`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1728) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:126`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L126) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:524`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L524) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3222-3229`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3222-L3229) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubuhm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1714`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1714) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:476`](../../../crates/sylpheed-ppc/src/opcode.rs#L476) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:639`](../../../crates/sylpheed-ppc/src/decoder.rs#L639) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsubuhm => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; - for i in 0..8 { r[i] = a[i].wrapping_sub(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsubuhm(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- (EXTZ(VA) + ¬EXTZ(VB) + 1) % 2^16 + Value* v = f.VectorSub(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsubuhs.md b/tools/ppc-manual/vmx/vsubuhs.md index 7ee2438a..d9666e60 100644 --- a/tools/ppc-manual/vmx/vsubuhs.md +++ b/tools/ppc-manual/vmx/vsubuhs.md @@ -58,28 +58,26 @@ vsubuhs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,21 @@ vsubuhs [VD], [VA], [VB] ## Implementation References **`vsubuhs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubuhs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1753`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1753) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:126`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L126) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:541`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L541) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3294-3305`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3294-L3305) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubuhs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1739`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1739) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:477`](../../../crates/sylpheed-ppc/src/opcode.rs#L477) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:656`](../../../crates/sylpheed-ppc/src/decoder.rs#L656) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsubuhs => { - let a = ctx.vr[instr.ra()].as_u16x8(); - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u16; 8]; let mut sat = false; - for i in 0..8 { - let (v, s) = crate::vmx::sat_sub_u16(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u16x8_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsubuhs(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- clamp(EXTZ(VA) + ¬EXTZ(VB) + 1, 0, 2^16-1) + Value* v = f.VectorSub(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT16_TYPE, + ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsubuwm.md b/tools/ppc-manual/vmx/vsubuwm.md index 7284ea19..54a6d8da 100644 --- a/tools/ppc-manual/vmx/vsubuwm.md +++ b/tools/ppc-manual/vmx/vsubuwm.md @@ -57,28 +57,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -86,22 +84,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vsubuwm`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubuwm"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1736`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1736) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:126`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L126) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:529`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L529) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2404-2411`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2404-L2411) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubuwm"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1722`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1722) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:478`](../../../crates/sylpheed-ppc/src/opcode.rs#L478) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:644`](../../../crates/sylpheed-ppc/src/decoder.rs#L644) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsubuwm => { - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i].wrapping_sub(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsubuwm(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- (EXTZ(VA) + ¬EXTZ(VB) + 1) % 2^32 + Value* v = f.VectorSub(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, + ARITHMETIC_UNSIGNED); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsubuws.md b/tools/ppc-manual/vmx/vsubuws.md index d2abb513..332ed39a 100644 --- a/tools/ppc-manual/vmx/vsubuws.md +++ b/tools/ppc-manual/vmx/vsubuws.md @@ -58,28 +58,26 @@ vsubuws [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,21 @@ vsubuws [VD], [VA], [VB] ## Implementation References **`vsubuws`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubuws"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1762`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1762) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:126`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L126) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:544`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L544) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3342-3353`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3342-L3353) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsubuws"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1748`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1748) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:479`](../../../crates/sylpheed-ppc/src/opcode.rs#L479) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:659`](../../../crates/sylpheed-ppc/src/decoder.rs#L659) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsubuws => { - let a = ctx.vr[instr.ra()].as_u32x4(); - let b = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; let mut sat = false; - for i in 0..4 { - let (v, s) = crate::vmx::sat_sub_u32(a[i], b[i]); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsubuws(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- clamp(EXTZ(VA) + ¬EXTZ(VB) + 1, 0, 2^32-1) + Value* v = f.VectorSub(f.LoadVR(i.VX.VA), f.LoadVR(i.VX.VB), INT32_TYPE, + ARITHMETIC_SATURATE | ARITHMETIC_UNSIGNED); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(i.VX.VD, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vsum2sws.md b/tools/ppc-manual/vmx/vsum2sws.md index 07429948..4dea8eac 100644 --- a/tools/ppc-manual/vmx/vsum2sws.md +++ b/tools/ppc-manual/vmx/vsum2sws.md @@ -58,28 +58,26 @@ vsum2sws [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,26 +85,17 @@ vsum2sws [VD], [VA], [VB] ## Implementation References **`vsum2sws`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsum2sws"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1776`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1776) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:127`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L127) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:545`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L545) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3668-3679`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3668-L3679) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsum2sws"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1762`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1762) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:480`](../../../crates/sylpheed-ppc/src/opcode.rs#L480) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:660`](../../../crates/sylpheed-ppc/src/decoder.rs#L660) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsum2sws => { - // Two 2-word partial sums at lanes 1 and 3. - let a = crate::vmx::as_i32x4(ctx.vr[instr.ra()]); - let c = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let s0 = a[0] as i64 + a[1] as i64 + c[1] as i64; - let s1 = a[2] as i64 + a[3] as i64 + c[3] as i64; - let (v0, sat0) = crate::vmx::sat_i64_to_i32(s0); - let (v1, sat1) = crate::vmx::sat_i64_to_i32(s1); - if sat0 | sat1 { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4([0, v0, 0, v1]); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsum2sws(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vsum4sbs.md b/tools/ppc-manual/vmx/vsum4sbs.md index 06e5d2e3..7d4517fe 100644 --- a/tools/ppc-manual/vmx/vsum4sbs.md +++ b/tools/ppc-manual/vmx/vsum4sbs.md @@ -58,28 +58,26 @@ vsum4sbs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,27 +85,17 @@ vsum4sbs [VD], [VA], [VB] ## Implementation References **`vsum4sbs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsum4sbs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1781`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1781) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:127`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L127) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:547`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L547) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3680-3692`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3680-L3692) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsum4sbs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1767`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1767) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:481`](../../../crates/sylpheed-ppc/src/opcode.rs#L481) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:662`](../../../crates/sylpheed-ppc/src/decoder.rs#L662) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsum4sbs => { - let a = crate::vmx::as_i8x16(ctx.vr[instr.ra()]); - let c = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; let mut sat = false; - for i in 0..4 { - let s = a[4*i] as i64 + a[4*i+1] as i64 + a[4*i+2] as i64 + a[4*i+3] as i64 + c[i] as i64; - let (v, o) = crate::vmx::sat_i64_to_i32(s); - r[i] = v; sat |= o; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsum4sbs(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vsum4shs.md b/tools/ppc-manual/vmx/vsum4shs.md index d645e282..921de99f 100644 --- a/tools/ppc-manual/vmx/vsum4shs.md +++ b/tools/ppc-manual/vmx/vsum4shs.md @@ -58,28 +58,26 @@ vsum4shs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,27 +85,17 @@ vsum4shs [VD], [VA], [VB] ## Implementation References **`vsum4shs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsum4shs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1786`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1786) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:127`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L127) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:543`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L543) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3706-3718`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3706-L3718) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsum4shs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1772`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1772) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:482`](../../../crates/sylpheed-ppc/src/opcode.rs#L482) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:658`](../../../crates/sylpheed-ppc/src/decoder.rs#L658) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsum4shs => { - let a = crate::vmx::as_i16x8(ctx.vr[instr.ra()]); - let c = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; let mut sat = false; - for i in 0..4 { - let s = a[2*i] as i64 + a[2*i+1] as i64 + c[i] as i64; - let (v, o) = crate::vmx::sat_i64_to_i32(s); - r[i] = v; sat |= o; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsum4shs(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vsum4ubs.md b/tools/ppc-manual/vmx/vsum4ubs.md index c6499bab..fc129b85 100644 --- a/tools/ppc-manual/vmx/vsum4ubs.md +++ b/tools/ppc-manual/vmx/vsum4ubs.md @@ -58,28 +58,26 @@ vsum4ubs [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,27 +85,17 @@ vsum4ubs [VD], [VA], [VB] ## Implementation References **`vsum4ubs`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsum4ubs"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1791`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1791) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:127`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L127) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:540`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L540) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3693-3705`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3693-L3705) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsum4ubs"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1777`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1777) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:483`](../../../crates/sylpheed-ppc/src/opcode.rs#L483) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:655`](../../../crates/sylpheed-ppc/src/decoder.rs#L655) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsum4ubs => { - let a = ctx.vr[instr.ra()].as_bytes(); - let c = ctx.vr[instr.rb()].as_u32x4(); - let mut r = [0u32; 4]; let mut sat = false; - for i in 0..4 { - let s = a[4*i] as u64 + a[4*i+1] as u64 + a[4*i+2] as u64 + a[4*i+3] as u64 + c[i] as u64; - let (v, o) = if s > u32::MAX as u64 { (u32::MAX, true) } else { (s as u32, false) }; - r[i] = v; sat |= o; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsum4ubs(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vsumsws.md b/tools/ppc-manual/vmx/vsumsws.md index 169639f5..6bb7c362 100644 --- a/tools/ppc-manual/vmx/vsumsws.md +++ b/tools/ppc-manual/vmx/vsumsws.md @@ -58,28 +58,26 @@ vsumsws [VD], [VA], [VB] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,24 +85,17 @@ vsumsws [VD], [VA], [VB] ## Implementation References **`vsumsws`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsumsws"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1771`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1771) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:127`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L127) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:550`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L550) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3658-3667`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3658-L3667) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vsumsws"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1757`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1757) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:484`](../../../crates/sylpheed-ppc/src/opcode.rs#L484) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:665`](../../../crates/sylpheed-ppc/src/decoder.rs#L665) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vsumsws => { - // vD[3] = sat_i32(vC[3] + sum over i in 0..4 of vA[i]) - let a = crate::vmx::as_i32x4(ctx.vr[instr.ra()]); - let c = crate::vmx::as_i32x4(ctx.vr[instr.rb()]); - let s = a.iter().map(|&x| x as i64).sum::() + c[3] as i64; - let (v, sat) = crate::vmx::sat_i64_to_i32(s); - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4([0, 0, 0, v]); - ctx.pc += 4; - } +```cpp +int InstrEmit_vsumsws(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vupkhpx.md b/tools/ppc-manual/vmx/vupkhpx.md index bcead0a4..e96ac38d 100644 --- a/tools/ppc-manual/vmx/vupkhpx.md +++ b/tools/ppc-manual/vmx/vupkhpx.md @@ -56,28 +56,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,21 +83,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vupkhpx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupkhpx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2002`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2002) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:128`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L128) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:511`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L511) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4168-4174`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4168-L4174) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupkhpx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1988`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1988) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:486`](../../../crates/sylpheed-ppc/src/opcode.rs#L486) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:626`](../../../crates/sylpheed-ppc/src/decoder.rs#L626) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vupkhpx => { - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = crate::vmx::unpack_pixel_555(b[i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vupkhpx(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vupkhsb.md b/tools/ppc-manual/vmx/vupkhsb.md index 5bb90cad..7c96edac 100644 --- a/tools/ppc-manual/vmx/vupkhsb.md +++ b/tools/ppc-manual/vmx/vupkhsb.md @@ -86,28 +86,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -115,46 +113,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vupkhsb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupkhsb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2055`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2055) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:128`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L128) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:481`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L481) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4134-4143`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4134-L4143) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupkhsb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2041`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2041) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:487`](../../../crates/sylpheed-ppc/src/opcode.rs#L487) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:596`](../../../crates/sylpheed-ppc/src/decoder.rs#L596) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vupkhsb | PpcOpcode::vupkhsb128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vupkhsb128); - let (rb, rd) = if is_128 { (instr.vb128(), instr.vd128()) } - else { (instr.rb(), instr.rd()) }; - let b = crate::vmx::as_i8x16(ctx.vr[rb]); - let mut r = [0i16; 8]; - for i in 0..8 { r[i] = b[i] as i16; } - ctx.vr[rd] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vupkhsb(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vupkhsb_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:2032) ── +int InstrEmit_vupkhsb_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // Vector Unpack High Signed Byte + // bytes 0-7 expanded to halfwords 0-7 and sign extended + Value* v = + f.Unpack(f.LoadVR(vb), PACK_TYPE_TO_HI | PACK_TYPE_8_IN_16 | + PACK_TYPE_IN_SIGNED | PACK_TYPE_OUT_SIGNED); + f.StoreVR(vd, v); + return 0; +} ```
**`vupkhsb128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupkhsb128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2058`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2058) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:128`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L128) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:700`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L700) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4134-4143`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4134-L4143) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupkhsb128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2044`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2044) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:488`](../../../crates/sylpheed-ppc/src/opcode.rs#L488) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:815`](../../../crates/sylpheed-ppc/src/decoder.rs#L815) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vupkhsb | PpcOpcode::vupkhsb128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vupkhsb128); - let (rb, rd) = if is_128 { (instr.vb128(), instr.vd128()) } - else { (instr.rb(), instr.rd()) }; - let b = crate::vmx::as_i8x16(ctx.vr[rb]); - let mut r = [0i16; 8]; - for i in 0..8 { r[i] = b[i] as i16; } - ctx.vr[rd] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vupkhsb128(PPCHIRBuilder& f, const InstrData& i) { + uint32_t va = VX128_VA128; + if (va == 0x60) { + // Hrm, my instruction tables suck. + return InstrEmit_vupkhsh_(f, VX128_VD128, VX128_VB128); + } + return InstrEmit_vupkhsb_(f, VX128_VD128, VX128_VB128); +} ```
diff --git a/tools/ppc-manual/vmx/vupkhsh.md b/tools/ppc-manual/vmx/vupkhsh.md index 89966252..4a9b2976 100644 --- a/tools/ppc-manual/vmx/vupkhsh.md +++ b/tools/ppc-manual/vmx/vupkhsh.md @@ -56,28 +56,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,21 +83,27 @@ _No condition-register or status-register effects._ ## Implementation References **`vupkhsh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupkhsh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2021`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2021) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:128`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L128) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:488`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L488) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4154-4160`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4154-L4160) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupkhsh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2007`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2007) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:489`](../../../crates/sylpheed-ppc/src/opcode.rs#L489) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:603`](../../../crates/sylpheed-ppc/src/decoder.rs#L603) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vupkhsh => { - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; - for i in 0..4 { r[i] = b[i] as i32; } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vupkhsh(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vupkhsh_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:1998) ── +int InstrEmit_vupkhsh_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // Vector Unpack High Signed Halfword + // halfwords 0-3 expanded to words 0-3 and sign extended + Value* v = + f.Unpack(f.LoadVR(vb), PACK_TYPE_TO_HI | PACK_TYPE_16_IN_32 | + PACK_TYPE_IN_SIGNED | PACK_TYPE_OUT_SIGNED); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vupklpx.md b/tools/ppc-manual/vmx/vupklpx.md index fb5c3469..53fe00a1 100644 --- a/tools/ppc-manual/vmx/vupklpx.md +++ b/tools/ppc-manual/vmx/vupklpx.md @@ -56,28 +56,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,21 +83,17 @@ _No condition-register or status-register effects._ ## Implementation References **`vupklpx`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupklpx"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2007`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2007) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:129`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L129) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:518`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L518) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4175-4181`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4175-L4181) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupklpx"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1993`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1993) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:490`](../../../crates/sylpheed-ppc/src/opcode.rs#L490) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:633`](../../../crates/sylpheed-ppc/src/decoder.rs#L633) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vupklpx => { - let b = ctx.vr[instr.rb()].as_u16x8(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = crate::vmx::unpack_pixel_555(b[4 + i]); } - ctx.vr[instr.rd()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vupklpx(PPCHIRBuilder& f, const InstrData& i) { + XEINSTRNOTIMPLEMENTED(); + return 1; +} ```
diff --git a/tools/ppc-manual/vmx/vupklsb.md b/tools/ppc-manual/vmx/vupklsb.md index 06d87474..af800e76 100644 --- a/tools/ppc-manual/vmx/vupklsb.md +++ b/tools/ppc-manual/vmx/vupklsb.md @@ -86,28 +86,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -115,46 +113,46 @@ _No condition-register or status-register effects._ ## Implementation References **`vupklsb`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupklsb"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2076`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2076) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:129`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L129) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:494`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L494) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4144-4153`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4144-L4153) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupklsb"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2062`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2062) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:491`](../../../crates/sylpheed-ppc/src/opcode.rs#L491) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:609`](../../../crates/sylpheed-ppc/src/decoder.rs#L609) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vupklsb | PpcOpcode::vupklsb128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vupklsb128); - let (rb, rd) = if is_128 { (instr.vb128(), instr.vd128()) } - else { (instr.rb(), instr.rd()) }; - let b = crate::vmx::as_i8x16(ctx.vr[rb]); - let mut r = [0i16; 8]; - for i in 0..8 { r[i] = b[8 + i] as i16; } - ctx.vr[rd] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vupklsb(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vupklsb_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:2053) ── +int InstrEmit_vupklsb_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // Vector Unpack Low Signed Byte + // bytes 8-15 expanded to halfwords 0-7 and sign extended + Value* v = + f.Unpack(f.LoadVR(vb), PACK_TYPE_TO_LO | PACK_TYPE_8_IN_16 | + PACK_TYPE_IN_SIGNED | PACK_TYPE_OUT_SIGNED); + f.StoreVR(vd, v); + return 0; +} ```
**`vupklsb128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupklsb128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2079`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2079) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:129`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L129) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:701`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L701) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4144-4153`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4144-L4153) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupklsb128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2065`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2065) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:492`](../../../crates/sylpheed-ppc/src/opcode.rs#L492) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:816`](../../../crates/sylpheed-ppc/src/decoder.rs#L816) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vupklsb | PpcOpcode::vupklsb128 => { - let is_128 = matches!(instr.opcode, PpcOpcode::vupklsb128); - let (rb, rd) = if is_128 { (instr.vb128(), instr.vd128()) } - else { (instr.rb(), instr.rd()) }; - let b = crate::vmx::as_i8x16(ctx.vr[rb]); - let mut r = [0i16; 8]; - for i in 0..8 { r[i] = b[8 + i] as i16; } - ctx.vr[rd] = crate::vmx::from_i16x8(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vupklsb128(PPCHIRBuilder& f, const InstrData& i) { + uint32_t va = VX128_VA128; + if (va == 0x60) { + // Hrm, my instruction tables suck. + return InstrEmit_vupklsh_(f, VX128_VD128, VX128_VB128); + } + return InstrEmit_vupklsb_(f, VX128_VD128, VX128_VB128); +} ```
diff --git a/tools/ppc-manual/vmx/vupklsh.md b/tools/ppc-manual/vmx/vupklsh.md index a8659993..ce719fbe 100644 --- a/tools/ppc-manual/vmx/vupklsh.md +++ b/tools/ppc-manual/vmx/vupklsh.md @@ -56,28 +56,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -85,21 +83,27 @@ _No condition-register or status-register effects._ ## Implementation References **`vupklsh`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupklsh"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2038`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2038) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:129`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L129) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:497`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L497) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4161-4167`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4161-L4167) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupklsh"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2024`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2024) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:493`](../../../crates/sylpheed-ppc/src/opcode.rs#L493) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:612`](../../../crates/sylpheed-ppc/src/decoder.rs#L612) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vupklsh => { - let b = crate::vmx::as_i16x8(ctx.vr[instr.rb()]); - let mut r = [0i32; 4]; - for i in 0..4 { r[i] = b[4 + i] as i32; } - ctx.vr[instr.rd()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vupklsh(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vupklsh_(f, i.VX.VD, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:2015) ── +int InstrEmit_vupklsh_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb) { + // Vector Unpack Low Signed Halfword + // halfwords 4-7 expanded to words 0-3 and sign extended + Value* v = + f.Unpack(f.LoadVR(vb), PACK_TYPE_TO_LO | PACK_TYPE_16_IN_32 | + PACK_TYPE_IN_SIGNED | PACK_TYPE_OUT_SIGNED); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx/vxor.md b/tools/ppc-manual/vmx/vxor.md index acba949a..f641f16e 100644 --- a/tools/ppc-manual/vmx/vxor.md +++ b/tools/ppc-manual/vmx/vxor.md @@ -87,28 +87,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -116,44 +114,58 @@ _No condition-register or status-register effects._ ## Implementation References **`vxor`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vxor"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2246`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2246) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:130`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L130) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:532`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L532) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2235-2243`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2235-L2243) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vxor"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2232`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2232) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:494`](../../../crates/sylpheed-ppc/src/opcode.rs#L494) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:647`](../../../crates/sylpheed-ppc/src/decoder.rs#L647) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vxor | PpcOpcode::vxor128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i] ^ b[i]; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vxor(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vxor_(f, i.VX.VD, i.VX.VA, i.VX.VB); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:2220) ── +int InstrEmit_vxor_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) ^ (VB) + Value* v; + if (va == vb) { + // Fast clear. + v = f.LoadZeroVec128(); + } else { + v = f.Xor(f.LoadVR(va), f.LoadVR(vb)); + } + f.StoreVR(vd, v); + return 0; +} ```
**`vxor128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vxor128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2249`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2249) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:130`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L130) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:627`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L627) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2235-2243`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2235-L2243) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vxor128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2235`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2235) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:495`](../../../crates/sylpheed-ppc/src/opcode.rs#L495) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:742`](../../../crates/sylpheed-ppc/src/decoder.rs#L742) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vxor | PpcOpcode::vxor128 => { - let (va, vb, vd) = vmx_reg_triple(instr); - let a = ctx.vr[va].as_u32x4(); - let b = ctx.vr[vb].as_u32x4(); - let mut r = [0u32; 4]; - for i in 0..4 { r[i] = a[i] ^ b[i]; } - ctx.vr[vd] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vxor128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vxor_(f, VX128_VD128, VX128_VA128, VX128_VB128); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:2220) ── +int InstrEmit_vxor_(PPCHIRBuilder& f, uint32_t vd, uint32_t va, uint32_t vb) { + // VD <- (VA) ^ (VB) + Value* v; + if (va == vb) { + // Fast clear. + v = f.LoadZeroVec128(); + } else { + v = f.Xor(f.LoadVR(va), f.LoadVR(vb)); + } + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vcfpsxws128.md b/tools/ppc-manual/vmx128/vcfpsxws128.md index 8d62be8a..f46c9e6b 100644 --- a/tools/ppc-manual/vmx128/vcfpsxws128.md +++ b/tools/ppc-manual/vmx128/vcfpsxws128.md @@ -60,28 +60,26 @@ vcfpsxws128 [VD], [VB], [UIMM] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,26 +87,29 @@ vcfpsxws128 [VD], [VB], [UIMM] ## Implementation References **`vcfpsxws128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcfpsxws128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:539`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L539) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:93`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L93) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:656`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L656) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4323-4334`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4323-L4334) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcfpsxws128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:539`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L539) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:317`](../../../crates/sylpheed-ppc/src/opcode.rs#L317) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:771`](../../../crates/sylpheed-ppc/src/decoder.rs#L771) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcfpsxws128 => { - let uimm = (instr.raw >> 16) & 0x1F; - let b = ctx.vr[instr.vb128()].as_f32x4(); - let mut r = [0i32; 4]; let mut sat = false; - for i in 0..4 { - let (v, s) = crate::vmx::cvt_f32_to_i32_sat(b[i], uimm); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.vd128()] = crate::vmx::from_i32x4(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vcfpsxws128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vctsxs_(f, VX128_3_VD128, VX128_3_VB128, VX128_3_IMM); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:525) ── +int InstrEmit_vctsxs_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb, + uint32_t uimm) { + // (VD) <- int_sat(VB as signed * 2^uimm) + float fuimm = static_cast(std::exp2(uimm)); + Value* v = + f.Mul(f.LoadVR(vb), f.Splat(f.LoadConstantFloat32(fuimm), VEC128_TYPE)); + v = f.VectorConvertF2I(v); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vcfpuxws128.md b/tools/ppc-manual/vmx128/vcfpuxws128.md index dfc183ec..a84c6ecc 100644 --- a/tools/ppc-manual/vmx128/vcfpuxws128.md +++ b/tools/ppc-manual/vmx128/vcfpuxws128.md @@ -60,28 +60,26 @@ vcfpuxws128 [VD], [VB], [UIMM] ## 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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,26 +87,29 @@ vcfpuxws128 [VD], [VB], [UIMM] ## Implementation References **`vcfpuxws128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcfpuxws128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:557`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L557) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:93`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L93) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:657`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L657) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4335-4346`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4335-L4346) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcfpuxws128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:557`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L557) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:318`](../../../crates/sylpheed-ppc/src/opcode.rs#L318) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:772`](../../../crates/sylpheed-ppc/src/decoder.rs#L772) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcfpuxws128 => { - let uimm = (instr.raw >> 16) & 0x1F; - let b = ctx.vr[instr.vb128()].as_f32x4(); - let mut r = [0u32; 4]; let mut sat = false; - for i in 0..4 { - let (v, s) = crate::vmx::cvt_f32_to_u32_sat(b[i], uimm); - r[i] = v; sat |= s; - } - if sat { ctx.set_vscr_sat(true); } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vcfpuxws128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vctuxs_(f, VX128_3_VD128, VX128_3_VB128, VX128_3_IMM); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:543) ── +int InstrEmit_vctuxs_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb, + uint32_t uimm) { + // (VD) <- int_sat(VB as unsigned * 2^uimm) + float fuimm = static_cast(std::exp2(uimm)); + Value* v = + f.Mul(f.LoadVR(vb), f.Splat(f.LoadConstantFloat32(fuimm), VEC128_TYPE)); + v = f.VectorConvertF2I(v, ARITHMETIC_UNSIGNED); + f.StoreSAT(f.DidSaturate(v)); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vcsxwfp128.md b/tools/ppc-manual/vmx128/vcsxwfp128.md index 4eb13030..771de245 100644 --- a/tools/ppc-manual/vmx128/vcsxwfp128.md +++ b/tools/ppc-manual/vmx128/vcsxwfp128.md @@ -59,28 +59,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,22 +86,29 @@ _No condition-register or status-register effects._ ## Implementation References **`vcsxwfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcsxwfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:503`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L503) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:98`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L98) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:658`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L658) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4347-4354`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4347-L4354) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcsxwfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:503`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L503) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:339`](../../../crates/sylpheed-ppc/src/opcode.rs#L339) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:773`](../../../crates/sylpheed-ppc/src/decoder.rs#L773) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcsxwfp128 => { - let uimm = (instr.raw >> 16) & 0x1F; - let b = crate::vmx::as_i32x4(ctx.vr[instr.vb128()]); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = crate::vmx::cvt_i32_to_f32(b[i], uimm); } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vcsxwfp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcfsx_(f, VX128_3_VD128, VX128_3_VB128, VX128_3_IMM); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:489) ── +int InstrEmit_vcfsx_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb, + uint32_t uimm) { + // (VD) <- float(VB as signed) / 2^uimm + Value* v = f.VectorConvertI2F(f.LoadVR(vb)); + if (uimm) { + float fuimm = std::ldexp(1.0f, -int(uimm)); + v = f.Mul(v, f.Splat(f.LoadConstantFloat32(fuimm), VEC128_TYPE)); + } + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vcuxwfp128.md b/tools/ppc-manual/vmx128/vcuxwfp128.md index 99e15425..7a36b3c9 100644 --- a/tools/ppc-manual/vmx128/vcuxwfp128.md +++ b/tools/ppc-manual/vmx128/vcuxwfp128.md @@ -59,28 +59,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,22 +86,29 @@ _No condition-register or status-register effects._ ## Implementation References **`vcuxwfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcuxwfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:521`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L521) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:98`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L98) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:659`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L659) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4355-4362`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4355-L4362) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vcuxwfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:521`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L521) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:342`](../../../crates/sylpheed-ppc/src/opcode.rs#L342) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:774`](../../../crates/sylpheed-ppc/src/decoder.rs#L774) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vcuxwfp128 => { - let uimm = (instr.raw >> 16) & 0x1F; - let b = ctx.vr[instr.vb128()].as_u32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { r[i] = crate::vmx::cvt_u32_to_f32(b[i], uimm); } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vcuxwfp128(PPCHIRBuilder& f, const InstrData& i) { + return InstrEmit_vcfux_(f, VX128_3_VD128, VX128_3_VB128, VX128_3_IMM); +} + +// ── delegates to (src/xenia/cpu/ppc/ppc_emit_altivec.cc:507) ── +int InstrEmit_vcfux_(PPCHIRBuilder& f, uint32_t vd, uint32_t vb, + uint32_t uimm) { + // (VD) <- float(VB as unsigned) / 2^uimm + Value* v = f.VectorConvertI2F(f.LoadVR(vb), ARITHMETIC_UNSIGNED); + if (uimm) { + float fuimm = std::ldexp(1.0f, -int(uimm)); + v = f.Mul(v, f.Splat(f.LoadConstantFloat32(fuimm), VEC128_TYPE)); + } + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vmaddcfp128.md b/tools/ppc-manual/vmx128/vmaddcfp128.md index 1db1a621..31226042 100644 --- a/tools/ppc-manual/vmx128/vmaddcfp128.md +++ b/tools/ppc-manual/vmx128/vmaddcfp128.md @@ -63,28 +63,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,32 +90,18 @@ _No condition-register or status-register effects._ ## Implementation References **`vmaddcfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaddcfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:812`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L812) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:100`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L100) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:614`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L614) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4492-4509`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4492-L4509) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmaddcfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:806`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L806) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:347`](../../../crates/sylpheed-ppc/src/opcode.rs#L347) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:729`](../../../crates/sylpheed-ppc/src/decoder.rs#L729) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmaddcfp128 => { - // ISA: (VD) <- (VA × VD) + VB. Canary InstrEmit_vmaddcfp128 (cc:819): MulAdd(VA, VD, VB). - // Previous code computed di.mul_add(bi, ai) = VD×VB+VA — both operands wrong - // (PPCBUG-425). Fix: ai.mul_add(di, bi) = VA×VD+VB. - let a = ctx.vr[instr.va128()].as_f32x4(); - let b = ctx.vr[instr.vb128()].as_f32x4(); - let d = ctx.vr[instr.vd128()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { - let ai = vmx::flush_denorm(a[i]); - let bi = vmx::flush_denorm(b[i]); - let di = vmx::flush_denorm(d[i]); - // PPCBUG-437: flush subnormal output too. - r[i] = vmx::flush_denorm(ai.mul_add(di, bi)); - } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmaddcfp128(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- ((VA) * (VD)) + (VB) + return InstrEmit_vmaddfp_(f, VX128_VD128, VX128_VA128, VX128_VB128, + VX128_VD128); +} ```
diff --git a/tools/ppc-manual/vmx128/vmsum3fp128.md b/tools/ppc-manual/vmx128/vmsum3fp128.md index 66c50fc8..7ad8a9e1 100644 --- a/tools/ppc-manual/vmx128/vmsum3fp128.md +++ b/tools/ppc-manual/vmx128/vmsum3fp128.md @@ -63,28 +63,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,25 +90,21 @@ _No condition-register or status-register effects._ ## Implementation References **`vmsum3fp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsum3fp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1067`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1067) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:106`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L106) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:616`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L616) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4513-4523`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4513-L4523) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsum3fp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1054`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1054) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:377`](../../../crates/sylpheed-ppc/src/opcode.rs#L377) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:731`](../../../crates/sylpheed-ppc/src/decoder.rs#L731) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmsum3fp128 => { - // PPCBUG-436: flush per-product intermediates (not just the final sum). - let a = ctx.vr[instr.va128()].as_f32x4(); - let b = ctx.vr[instr.vb128()].as_f32x4(); - let p0 = vmx::flush_denorm(a[0] * b[0]); - let p1 = vmx::flush_denorm(a[1] * b[1]); - let p2 = vmx::flush_denorm(a[2] * b[2]); - let s = vmx::flush_denorm(p0 + p1 + p2); - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4(s, s, s, s); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmsum3fp128(PPCHIRBuilder& f, const InstrData& i) { + // Dot product XYZ. + // (VD.xyzw) = (VA.x * VB.x) + (VA.y * VB.y) + (VA.z * VB.z) + // chrispy: denormal outputs for Dot product are unconditionally made 0 + Value* v = f.DotProduct3(f.LoadVR(VX128_VA128), f.LoadVR(VX128_VB128)); + f.StoreVR(VX128_VD128, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vmsum4fp128.md b/tools/ppc-manual/vmx128/vmsum4fp128.md index 84638d53..28920796 100644 --- a/tools/ppc-manual/vmx128/vmsum4fp128.md +++ b/tools/ppc-manual/vmx128/vmsum4fp128.md @@ -63,28 +63,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,26 +90,20 @@ _No condition-register or status-register effects._ ## Implementation References **`vmsum4fp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsum4fp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1077`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1077) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:106`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L106) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:617`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L617) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4524-4535`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4524-L4535) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmsum4fp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1063`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1063) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:378`](../../../crates/sylpheed-ppc/src/opcode.rs#L378) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:732`](../../../crates/sylpheed-ppc/src/decoder.rs#L732) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmsum4fp128 => { - // PPCBUG-436. - let a = ctx.vr[instr.va128()].as_f32x4(); - let b = ctx.vr[instr.vb128()].as_f32x4(); - let p0 = vmx::flush_denorm(a[0] * b[0]); - let p1 = vmx::flush_denorm(a[1] * b[1]); - let p2 = vmx::flush_denorm(a[2] * b[2]); - let p3 = vmx::flush_denorm(a[3] * b[3]); - let s = vmx::flush_denorm(p0 + p1 + p2 + p3); - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4(s, s, s, s); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmsum4fp128(PPCHIRBuilder& f, const InstrData& i) { + // Dot product XYZW. + // (VD.xyzw) = (VA.x * VB.x) + (VA.y * VB.y) + (VA.z * VB.z) + (VA.w * VB.w) + Value* v = f.DotProduct4(f.LoadVR(VX128_VA128), f.LoadVR(VX128_VB128)); + f.StoreVR(VX128_VD128, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vmulfp128.md b/tools/ppc-manual/vmx128/vmulfp128.md index 1816a41e..3a8f9c47 100644 --- a/tools/ppc-manual/vmx128/vmulfp128.md +++ b/tools/ppc-manual/vmx128/vmulfp128.md @@ -63,28 +63,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -92,27 +90,19 @@ _No condition-register or status-register effects._ ## Implementation References **`vmulfp128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulfp128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1126`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1126) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:108`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L108) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:612`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L612) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:2108-2120`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L2108-L2120) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vmulfp128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1111`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1111) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:389`](../../../crates/sylpheed-ppc/src/opcode.rs#L389) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:727`](../../../crates/sylpheed-ppc/src/decoder.rs#L727) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vmulfp128 => { - // PPCBUG-435 + PPCBUG-437. - let a = ctx.vr[instr.va128()].as_f32x4(); - let b = ctx.vr[instr.vb128()].as_f32x4(); - let mut r = [0f32; 4]; - for i in 0..4 { - let ai = vmx::flush_denorm(a[i]); - let bi = vmx::flush_denorm(b[i]); - r[i] = vmx::flush_denorm(ai * bi); - } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_f32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vmulfp128(PPCHIRBuilder& f, const InstrData& i) { + // (VD) <- (VA) * (VB) (4 x fp) + Value* v = f.Mul(f.LoadVR(VX128_VA128), f.LoadVR(VX128_VB128)); + f.StoreVR(VX128_VD128, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vpermwi128.md b/tools/ppc-manual/vmx128/vpermwi128.md index d1b5a7cb..856e37df 100644 --- a/tools/ppc-manual/vmx128/vpermwi128.md +++ b/tools/ppc-manual/vmx128/vpermwi128.md @@ -60,28 +60,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -89,26 +87,26 @@ _No condition-register or status-register effects._ ## Implementation References **`vpermwi128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpermwi128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1207`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1207) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:112`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L112) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:642`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L642) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4537-4548`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4537-L4548) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpermwi128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1183`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1183) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:402`](../../../crates/sylpheed-ppc/src/opcode.rs#L402) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:757`](../../../crates/sylpheed-ppc/src/decoder.rs#L757) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpermwi128 => { - let imm = instr.vx128_p_perm(); - let b = ctx.vr[instr.vb128()].as_u32x4(); - let mut r = [0u32; 4]; - // Output lane i ← b[(imm >> (2 * (3-i))) & 3] - for i in 0..4 { - let sel = ((imm >> (2 * (3 - i))) & 3) as usize; - r[i] = b[sel]; - } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vpermwi128(PPCHIRBuilder& f, const InstrData& i) { + // (VD.x) = (VB.uimm[6-7]) + // (VD.y) = (VB.uimm[4-5]) + // (VD.z) = (VB.uimm[2-3]) + // (VD.w) = (VB.uimm[0-1]) + const uint32_t vd = i.VX128_P.VD128l | (i.VX128_P.VD128h << 5); + const uint32_t vb = i.VX128_P.VB128l | (i.VX128_P.VB128h << 5); + uint32_t uimm = i.VX128_P.PERMl | (i.VX128_P.PERMh << 5); + uint32_t mask = MakeSwizzleMask(uimm >> 6, uimm >> 4, uimm >> 2, uimm >> 0); + Value* v = f.Swizzle(f.LoadVR(vb), INT32_TYPE, mask); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vpkd3d128.md b/tools/ppc-manual/vmx128/vpkd3d128.md index d3e232ea..d4e6c2d5 100644 --- a/tools/ppc-manual/vmx128/vpkd3d128.md +++ b/tools/ppc-manual/vmx128/vpkd3d128.md @@ -59,28 +59,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,72 +86,118 @@ _No condition-register or status-register effects._ ## Implementation References **`vpkd3d128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkd3d128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2088`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2088) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:112`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L112) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:648`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L648) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4191-4248`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4191-L4248) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vpkd3d128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2074`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2074) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:403`](../../../crates/sylpheed-ppc/src/opcode.rs#L403) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:763`](../../../crates/sylpheed-ppc/src/decoder.rs#L763) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vpkd3d128 => { - use crate::vmx::D3dPackType; - let uimm = crate::decoder::extract_vx128_uimm5(instr.raw); - let pack = (uimm & 3) as usize; - let shift = instr.vx128_4_z() as usize; - let ty = D3dPackType::from_immediate(uimm >> 2); - let src = ctx.vr[instr.vb128()]; - let out = match ty { - D3dPackType::D3dColor => crate::vmx::pack_d3dcolor(src), - D3dPackType::NormShort2 => crate::vmx::pack_normshort2(src), - D3dPackType::NormPacked32 => crate::vmx::pack_normpacked32(src), - D3dPackType::Float16_2 => crate::vmx::pack_float16_2(src), - D3dPackType::NormShort4 => crate::vmx::pack_normshort4(src), - D3dPackType::Float16_4 => crate::vmx::pack_float16_4(src), - D3dPackType::NormPacked64 => crate::vmx::pack_normpacked64(src), - D3dPackType::Other(t) => { - tracing::warn!( - raw = format_args!("{:#010x}", instr.raw), - uimm, - ty = t, - "vpkd3d128: unhandled pack type at {:#010x}", - ctx.pc, - ); - src - } - }; - // Post-pack permutation: merge packed `out` into previous `vd` - // per canary ppc_emit_altivec.cc:2126-2188 MakePermuteMask tables. - // MakePermuteMask(r0,l0, r1,l1, r2,l2, r3,l3): result[i] = if ri==0 { prev[li] } else { out[li] } - let result = if pack == 0 { - out - } else { - // (source_reg, lane): 0=prev vd, 1=packed out - const PERM: [[[(u8, u8); 4]; 4]; 3] = [ - // pack=1 (VPACK_32): places out[3] at lane (3-shift) - [[(0,0),(0,1),(0,2),(1,3)], [(0,0),(0,1),(1,3),(0,3)], - [(0,0),(1,3),(0,2),(0,3)], [(1,3),(0,1),(0,2),(0,3)]], - // pack=2 (64-bit): places out[2..3] at lanes (2-shift)..(3-shift) - [[(0,0),(0,1),(1,2),(1,3)], [(0,0),(1,2),(1,3),(0,3)], - [(1,2),(1,3),(0,2),(0,3)], [(1,3),(0,1),(0,2),(0,3)]], - // pack=3 (64-bit): same as pack=2 except shift=3 selects out[2] at lane 3 - [[(0,0),(0,1),(1,2),(1,3)], [(0,0),(1,2),(1,3),(0,3)], - [(1,2),(1,3),(0,2),(0,3)], [(0,0),(0,1),(0,2),(1,2)]], - ]; - let prev = ctx.vr[instr.vd128()]; - let pw = prev.as_u32x4(); - let ow = out.as_u32x4(); - let sel = PERM[pack - 1][shift]; - xenia_types::Vec128::from_u32x4_array([ - if sel[0].0 == 0 { pw[sel[0].1 as usize] } else { ow[sel[0].1 as usize] }, - if sel[1].0 == 0 { pw[sel[1].1 as usize] } else { ow[sel[1].1 as usize] }, - if sel[2].0 == 0 { pw[sel[2].1 as usize] } else { ow[sel[2].1 as usize] }, - if sel[3].0 == 0 { pw[sel[3].1 as usize] } else { ow[sel[3].1 as usize] }, - ]) - }; - ctx.vr[instr.vd128()] = result; - ctx.pc += 4; - } +```cpp +int InstrEmit_vpkd3d128(PPCHIRBuilder& f, const InstrData& i) { + const uint32_t vd = i.VX128_4.VD128l | (i.VX128_4.VD128h << 5); + const uint32_t vb = i.VX128_4.VB128l | (i.VX128_4.VB128h << 5); + uint32_t type = i.VX128_4.IMM >> 2; + uint32_t pack = i.VX128_4.IMM & 0x3; + uint32_t shift = i.VX128_4.z; + Value* v = f.LoadVR(vb); + switch (type) { + case 0: // VPACK_D3DCOLOR + v = f.Pack(v, PACK_TYPE_D3DCOLOR); + break; + case 1: // VPACK_NORMSHORT2 + v = f.Pack(v, PACK_TYPE_SHORT_2); + break; + case 2: // VPACK_NORMPACKED32 2_10_10_10 w_z_y_x + v = f.Pack(v, PACK_TYPE_UINT_2101010); + break; + case 3: // VPACK_FLOAT16_2 DXGI_FORMAT_R16G16_FLOAT + v = f.Pack(v, PACK_TYPE_FLOAT16_2); + break; + case 4: // VPACK_NORMSHORT4 + v = f.Pack(v, PACK_TYPE_SHORT_4); + break; + case 5: // VPACK_FLOAT16_4 DXGI_FORMAT_R16G16B16A16_FLOAT + v = f.Pack(v, PACK_TYPE_FLOAT16_4); + break; + case 6: // VPACK_NORMPACKED64 4_20_20_20 w_z_y_x + // Used in 54540829 and other installments in the series, pretty rarely in + // general. + v = f.Pack(v, PACK_TYPE_ULONG_4202020); + break; + default: + assert_unhandled_case(type); + return 1; + } + // https://hlssmod.net/he_code/public/pixelwriter.h + // control = prev:0123 | new:4567 + uint32_t control = kIdentityPermuteMask; // original + switch (pack) { + case 1: // VPACK_32 + // VPACK_32 & shift = 3 puts lower 32 bits in x (leftmost slot). + switch (shift) { + case 0: + control = MakePermuteMask(0, 0, 0, 1, 0, 2, 1, 3); + break; + case 1: + control = MakePermuteMask(0, 0, 0, 1, 1, 3, 0, 3); + break; + case 2: + control = MakePermuteMask(0, 0, 1, 3, 0, 2, 0, 3); + break; + case 3: + control = MakePermuteMask(1, 3, 0, 1, 0, 2, 0, 3); + break; + default: + assert_unhandled_case(shift); + return 1; + } + break; + case 2: // 64bit + switch (shift) { + case 0: + control = MakePermuteMask(0, 0, 0, 1, 1, 2, 1, 3); + break; + case 1: + control = MakePermuteMask(0, 0, 1, 2, 1, 3, 0, 3); + break; + case 2: + control = MakePermuteMask(1, 2, 1, 3, 0, 2, 0, 3); + break; + case 3: + control = MakePermuteMask(1, 3, 0, 1, 0, 2, 0, 3); + break; + default: + assert_unhandled_case(shift); + return 1; + } + break; + case 3: // 64bit + switch (shift) { + case 0: + control = MakePermuteMask(0, 0, 0, 1, 1, 2, 1, 3); + break; + case 1: + control = MakePermuteMask(0, 0, 1, 2, 1, 3, 0, 3); + break; + case 2: + control = MakePermuteMask(1, 2, 1, 3, 0, 2, 0, 3); + break; + case 3: + control = MakePermuteMask(0, 0, 0, 1, 0, 2, 1, 2); + break; + default: + assert_unhandled_case(shift); + return 1; + } + break; + default: + assert_unhandled_case(pack); + return 1; + } + v = f.Permute(f.LoadConstantUint32(control), f.LoadVR(vd), v, INT32_TYPE); + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vrlimi128.md b/tools/ppc-manual/vmx128/vrlimi128.md index b5fdfbae..9a047115 100644 --- a/tools/ppc-manual/vmx128/vrlimi128.md +++ b/tools/ppc-manual/vmx128/vrlimi128.md @@ -59,28 +59,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -88,30 +86,59 @@ _No condition-register or status-register effects._ ## Implementation References **`vrlimi128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrlimi128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1315`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1315) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:119`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L119) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:649`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L649) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:3962-3977`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L3962-L3977) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vrlimi128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:1291`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L1291) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:433`](../../../crates/sylpheed-ppc/src/opcode.rs#L433) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:764`](../../../crates/sylpheed-ppc/src/decoder.rs#L764) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vrlimi128 => { - let shift = instr.vx128_4_z() as usize; - let mask = instr.vx128_4_imm(); - let b = ctx.vr[instr.vb128()].as_u32x4(); - let d = ctx.vr[instr.vd128()].as_u32x4(); - let rot = [b[shift % 4], b[(shift + 1) % 4], b[(shift + 2) % 4], b[(shift + 3) % 4]]; - let mut r = [0u32; 4]; - for i in 0..4 { - // mask bit 3 corresponds to word 0 (BE-first). Use rot when - // the corresponding mask bit is set. - let use_rot = (mask >> (3 - i)) & 1 == 1; - r[i] = if use_rot { rot[i] } else { d[i] }; - } - ctx.vr[instr.vd128()] = xenia_types::Vec128::from_u32x4_array(r); - ctx.pc += 4; - } +```cpp +int InstrEmit_vrlimi128(PPCHIRBuilder& f, const InstrData& i) { + const uint32_t vd = i.VX128_4.VD128l | (i.VX128_4.VD128h << 5); + const uint32_t vb = i.VX128_4.VB128l | (i.VX128_4.VB128h << 5); + uint32_t blend_mask_src = i.VX128_4.IMM; + uint32_t blend_mask = 0; + blend_mask |= (((blend_mask_src >> 3) & 0x1) ? 0 : 4) << 0; + blend_mask |= (((blend_mask_src >> 2) & 0x1) ? 1 : 5) << 8; + blend_mask |= (((blend_mask_src >> 1) & 0x1) ? 2 : 6) << 16; + blend_mask |= (((blend_mask_src >> 0) & 0x1) ? 3 : 7) << 24; + uint32_t rotate = i.VX128_4.z; + // This is just a fancy permute. + // X Y Z W, rotated left by 2 = Z W X Y + // Then mask select the results into the dest. + // Sometimes rotation is zero, so fast path. + Value* v; + if (rotate) { + // TODO(benvanik): constants need conversion. + uint32_t swizzle_mask; + switch (rotate) { + case 1: + // X Y Z W -> Y Z W X + swizzle_mask = SWIZZLE_XYZW_TO_YZWX; + break; + case 2: + // X Y Z W -> Z W X Y + swizzle_mask = SWIZZLE_XYZW_TO_ZWXY; + break; + case 3: + // X Y Z W -> W X Y Z + swizzle_mask = SWIZZLE_XYZW_TO_WXYZ; + break; + default: + XEINSTRNOTIMPLEMENTED(); + return 1; + } + v = f.Swizzle(f.LoadVR(vb), FLOAT32_TYPE, swizzle_mask); + } else { + v = f.LoadVR(vb); + } + if (blend_mask != kIdentityPermuteMask) { + v = f.Permute(f.LoadConstantUint32(blend_mask), v, f.LoadVR(vd), + INT32_TYPE); + } + f.StoreVR(vd, v); + return 0; +} ```
diff --git a/tools/ppc-manual/vmx128/vupkd3d128.md b/tools/ppc-manual/vmx128/vupkd3d128.md index e8c4aeb9..4bd9467d 100644 --- a/tools/ppc-manual/vmx128/vupkd3d128.md +++ b/tools/ppc-manual/vmx128/vupkd3d128.md @@ -58,28 +58,26 @@ _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. +; No hand-written pseudocode for this instruction yet. +; The authoritative semantics are the Canary emitter snapshot under +; Implementation References; about half of Canary's emitters open +; with the PPC-style definition as a comment (`RD <- (RA) + (RB)`). +; Every side effect is also enumerated in the Register Effects and +; Status-Register Effects tables above. ``` ## 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 */ +/* No hand-written C yet. Translate the Canary emitter snapshot */ +/* under Implementation References; its HIR maps directly: */ +/* f.LoadGPR(n) / f.StoreGPR(n, v) -> r[n] / r[n] = v */ +/* f.LoadFPR / StoreFPR, f.LoadVR / StoreVR -> f[n], v[n] */ +/* f.Load(ea, T), f.Store(ea, v) -> raw read / write; emitters */ +/* wrap them in f.ByteSwap for the big-endian guest value */ +/* f.UpdateCR(n, v) -> CR field n from v's LOW 32 BITS vs 0 */ +/* f.LoadCA / f.StoreCA -> xer.CA; f.StoreSAT -> vscr.SAT */ +/* i.XO.RA, i.D.DS, ... -> the bit-fields listed under Operands */ /* The Register Effects and Status-Register Effects tables above */ /* enumerate every side effect a faithful translation must emit. */ ``` @@ -87,41 +85,52 @@ _No condition-register or status-register effects._ ## Implementation References **`vupkd3d128`** -- xenia-canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupkd3d128"`](../../xenia-canary/tools/ppc-instructions.xml) -- xenia-canary emit: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2194`](../../xenia-canary/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2194) -- xenia-rs opcode: [`crates/xenia-cpu/src/opcode.rs:128`](../../xenia-rs/crates/xenia-cpu/src/opcode.rs#L128) -- xenia-rs decoder: [`crates/xenia-cpu/src/decoder.rs:670`](../../xenia-rs/crates/xenia-cpu/src/decoder.rs#L670) -- xenia-rs interpreter: [`crates/xenia-cpu/src/interpreter.rs:4249-4275`](../../xenia-rs/crates/xenia-cpu/src/interpreter.rs#L4249-L4275) -
xenia-rs interpreter body (frozen snapshot) +- Canary XML: [`tools/ppc-instructions.xml` — search for `mnem="vupkd3d128"`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/tools/ppc-instructions.xml) +- Canary emitter: [`src/xenia/cpu/ppc/ppc_emit_altivec.cc:2180`](https://github.com/xenia-canary/xenia-canary/blob/f21ebd49e979e44f081f474df78c3fbfee9cb3f2/src/xenia/cpu/ppc/ppc_emit_altivec.cc#L2180) +- Sylpheed opcode: [`crates/sylpheed-ppc/src/opcode.rs:485`](../../../crates/sylpheed-ppc/src/opcode.rs#L485) +- Sylpheed decoder: [`crates/sylpheed-ppc/src/decoder.rs:785`](../../../crates/sylpheed-ppc/src/decoder.rs#L785) +
Canary emitter (frozen snapshot @ f21ebd49e9) -```rust - PpcOpcode::vupkd3d128 => { - use crate::vmx::D3dPackType; - let uimm = crate::decoder::extract_vx128_uimm5(instr.raw); - let ty = D3dPackType::from_immediate(uimm >> 2); - let src = ctx.vr[instr.vb128()]; - let out = match ty { - D3dPackType::D3dColor => crate::vmx::unpack_d3dcolor(src), - D3dPackType::NormShort2 => crate::vmx::unpack_normshort2(src), - D3dPackType::NormPacked32 => crate::vmx::unpack_normpacked32(src), - D3dPackType::Float16_2 => crate::vmx::unpack_float16_2(src), - D3dPackType::NormShort4 => crate::vmx::unpack_normshort4(src), - D3dPackType::Float16_4 => crate::vmx::unpack_float16_4(src), - D3dPackType::NormPacked64 => crate::vmx::unpack_normpacked64(src), - D3dPackType::Other(t) => { - tracing::warn!( - raw = format_args!("{:#010x}", instr.raw), - uimm, - ty = t, - "vupkd3d128: unhandled pack type at {:#010x}", - ctx.pc, - ); - src - } - }; - ctx.vr[instr.vd128()] = out; - ctx.pc += 4; - } +```cpp +int InstrEmit_vupkd3d128(PPCHIRBuilder& f, const InstrData& i) { + // Can't find many docs on this. Best reference is + // https://code.google.com/archive/p/worldcraft/source/default/source?page=4 + // (qylib/math/xmmatrix.inl) + // which shows how it's used in some cases. Since it's all intrinsics, + // finding it in code is pretty easy. + const uint32_t vd = i.VX128_3.VD128l | (i.VX128_3.VD128h << 5); + const uint32_t vb = i.VX128_3.VB128l | (i.VX128_3.VB128h << 5); + const uint32_t type = i.VX128_3.IMM >> 2; + Value* v = f.LoadVR(vb); + switch (type) { + case 0: // VPACK_D3DCOLOR + v = f.Unpack(v, PACK_TYPE_D3DCOLOR); + break; + case 1: // VPACK_NORMSHORT2 + v = f.Unpack(v, PACK_TYPE_SHORT_2); + break; + case 2: // VPACK_NORMPACKED32 2_10_10_10 w_z_y_x + v = f.Unpack(v, PACK_TYPE_UINT_2101010); + break; + case 3: // VPACK_FLOAT16_2 DXGI_FORMAT_R16G16_FLOAT + v = f.Unpack(v, PACK_TYPE_FLOAT16_2); + break; + case 4: // VPACK_NORMSHORT4 + v = f.Unpack(v, PACK_TYPE_SHORT_4); + break; + case 5: // VPACK_FLOAT16_4 DXGI_FORMAT_R16G16B16A16_FLOAT + v = f.Unpack(v, PACK_TYPE_FLOAT16_4); + break; + case 6: // VPACK_NORMPACKED64 4_20_20_20 w_z_y_x + v = f.Unpack(v, PACK_TYPE_ULONG_4202020); + break; + default: + assert_unhandled_case(type); + return 1; + } + f.StoreVR(vd, v); + return 0; +} ```
-- 2.49.1