fix(cpu): PPCBUG-275 276 420 421 422 423 562 600 fix vcmp Rc bit + decode dot forms
PPCBUG-562: Add vc_rc_bit() (PPC bit 21) and vx128r_rc_bit() (PPC bit 27) to decoder.rs. The generic rc_bit() reads bit 0 (PPC bit 31); all vcmp XO values are even so bit 0 is always 0, making CR6 permanently dead. PPCBUG-275/276/420/421: Replace rc_bit() with vc_rc_bit() at all 8 pure VC-form vcmp arms (vcmpequb, vcmpequh, vcmpgtub, vcmpgtsb, vcmpgtuh, vcmpgtsh, vcmpgtuw, vcmpgtsw) and with the correct per-form accessor at the 4 combined arms (vcmpeqfp|128, vcmpgefp|128, vcmpgtfp|128, vcmpequw|128) and vcmpbfp|128. PPCBUG-422: VX128_R-form 128-variants in combined arms now use vx128r_rc_bit() instead of vc_rc_bit(). PPCBUG-423/600: Add 5 dot-form key entries to decode_op6 so vcmp*fp128./vcmpequw128. decode as the correct opcode instead of Invalid. Uses a 5-bit key (bits22-24 + bit25 + bit27) for dot-forms to avoid aliasing against the shift/merge group (which sets bit25=1 when bit27=1). Interpreter uses vx128r_rc_bit() to conditionally update CR6. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -74,6 +74,11 @@ impl DecodedInstr {
|
||||
/// Rc bit (bit 31) - record CR0
|
||||
#[inline] pub fn rc_bit(&self) -> bool { self.raw & 1 != 0 }
|
||||
|
||||
/// Rc for VC-form vector compare instructions — PPC bit 21 = host bit 10.
|
||||
#[inline] pub fn vc_rc_bit(&self) -> bool { (self.raw >> 10) & 1 != 0 }
|
||||
/// Rc for VX128_R-form vector compare instructions — PPC bit 27 = host bit 4.
|
||||
#[inline] pub fn vx128r_rc_bit(&self) -> bool { (self.raw >> 4) & 1 != 0 }
|
||||
|
||||
/// OE bit (bit 21) - overflow enable
|
||||
#[inline] pub fn oe(&self) -> bool { extract_bits(self.raw, 21, 21) != 0 }
|
||||
|
||||
@@ -642,9 +647,13 @@ fn decode_op6(code: u32) -> PpcOpcode {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// VMX128 compare
|
||||
let key4 = (extract_bits(code, 22, 24) << 3) | extract_bits(code, 27, 27);
|
||||
match key4 {
|
||||
// VMX128 compare (non-dot and dot forms).
|
||||
// Non-dot: bit 27 = 0. Dot: bit 27 = 1, but bit 25 must also be 0 to
|
||||
// distinguish from the shift/merge group (which has bit 25 = 1 when bit 27 = 1).
|
||||
// key4_nd uses bits 22-24 + bit 27 (same as original, covers non-dot).
|
||||
// key4_dt uses bits 22-24 + bit 25 + bit 27 (narrower, covers dot-only).
|
||||
let key4_nd = (extract_bits(code, 22, 24) << 3) | extract_bits(code, 27, 27);
|
||||
match key4_nd {
|
||||
0b000000 => return PpcOpcode::vcmpeqfp128,
|
||||
0b001000 => return PpcOpcode::vcmpgefp128,
|
||||
0b010000 => return PpcOpcode::vcmpgtfp128,
|
||||
@@ -652,6 +661,16 @@ fn decode_op6(code: u32) -> PpcOpcode {
|
||||
0b100000 => return PpcOpcode::vcmpequw128,
|
||||
_ => {}
|
||||
}
|
||||
// Dot forms: bit 27 = 1, bit 25 = 0 (key = bits22-24 + bit25 + bit27, low 3 bits)
|
||||
let key4_dt = (extract_bits(code, 22, 24) << 2) | (extract_bits(code, 25, 25) << 1) | extract_bits(code, 27, 27);
|
||||
match key4_dt {
|
||||
0b00001 => return PpcOpcode::vcmpeqfp128, // bits22-24=000, bit25=0, bit27=1
|
||||
0b00101 => return PpcOpcode::vcmpgefp128, // bits22-24=001, bit25=0, bit27=1
|
||||
0b01001 => return PpcOpcode::vcmpgtfp128, // bits22-24=010, bit25=0, bit27=1
|
||||
0b01101 => return PpcOpcode::vcmpbfp128, // bits22-24=011, bit25=0, bit27=1
|
||||
0b10001 => return PpcOpcode::vcmpequw128, // bits22-24=100, bit25=0, bit27=1
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// VMX128 shift/merge
|
||||
let key5 = (extract_bits(code, 22, 25) << 2) | extract_bits(code, 27, 27);
|
||||
|
||||
Reference in New Issue
Block a user