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; +} ```