fix(cpu): PPCBUG-315 PPCBUG-563 fix vrlimi128 z and IMM field extraction

PPCBUG-563: Add vx128_4_imm() (PPC bits 11-15) and vx128_4_z() (PPC bits
24-25) accessors to decoder.rs for VX128_4-form instructions.

PPCBUG-315: vrlimi128 was reading z from host bits 16-17 (a subset of IMM)
and mask from host bits 2-5 (a reserved/XO region). Replace with the
correct accessors: z selects which word-lane to start the rotation from
(0-3); IMM is the 5-bit per-lane blend mask.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-05-01 21:26:26 +02:00
parent d51b9346df
commit 197d76c44e
2 changed files with 112 additions and 7 deletions

View File

@@ -2141,9 +2141,7 @@ fn execute(ctx: &mut PpcContext, mem: &dyn MemoryAccess, instr: &DecodedInstr) -
va = instr.va128();
vb = instr.vb128();
vd = instr.vd128();
// For vperm128, the permutation control is in vC (third source)
// which is typically encoded via a different field
vc = instr.vd128(); // vperm128 uses vD as permute mask
vc = instr.vc128_2();
} else {
va = instr.ra();
vb = instr.rb();
@@ -2176,7 +2174,7 @@ fn execute(ctx: &mut PpcContext, mem: &dyn MemoryAccess, instr: &DecodedInstr) -
PpcOpcode::vsldoi128 => {
let a_bytes = ctx.vr[instr.va128()].as_bytes();
let b_bytes = ctx.vr[instr.vb128()].as_bytes();
let sh = ((instr.raw >> 6) & 0x7) as usize | (((instr.raw >> 4) & 0x1) as usize) << 3; // extract shift
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);
@@ -3766,8 +3764,8 @@ fn execute(ctx: &mut PpcContext, mem: &dyn MemoryAccess, instr: &DecodedInstr) -
// use rotated[N]). Titles generally use mask=0xF (copy-all) which
// makes this behave like a plain word rotate.
PpcOpcode::vrlimi128 => {
let shift = ((instr.raw >> 16) & 0x3) as usize;
let mask = (instr.raw >> 2) & 0xF; // VX128_4 "fmask"
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]];
@@ -4304,7 +4302,7 @@ fn execute(ctx: &mut PpcContext, mem: &dyn MemoryAccess, instr: &DecodedInstr) -
}
// vpermwi128: permute words of vB using an 8-bit immediate (2 bits per output lane).
PpcOpcode::vpermwi128 => {
let imm = (instr.raw >> 16) & 0xFF;
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]