fix(xexdb): clear the lint gate on the imported crates

rustfmt, then clippy -D warnings across the three new crates. Mechanical,
except three decisions that are stated rather than silently allowed:

  * lzx.rs gets file-scoped needless_range_loop/explicit_counter_loop allows.
    Index arithmetic IS the algorithm -- LZX is defined over symbol indices,
    Huffman slots and window positions, and a decompressor that is merely
    idiomatic is worth nothing if it is not bit-exact.
  * sylpheed-xexdb gets crate-scoped allows for needless_range_loop (nine
    sites index reg[r] where r is the PowerPC register number -- the index is
    the meaning), too_many_arguments and type_complexity. This code arrived
    whole from a retired repository; a refactor here would be an unreviewed
    edit dressed as a lint fix.
  * Everything else clippy asked for is FIXED, including all 14 doc-indent
    sites, the let-else, and a Prepared type alias in the binary.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-09-13 20:25:44 +02:00
parent 62b0f79590
commit c9dd2cb705
37 changed files with 5308 additions and 2198 deletions

View File

@@ -18,34 +18,68 @@ impl DecodedInstr {
// Common field extractors (PPC bit numbering)
/// Primary opcode (bits 0-5)
#[inline] pub fn op(&self) -> u32 { extract_bits(self.raw, 0, 5) }
#[inline]
pub fn op(&self) -> u32 {
extract_bits(self.raw, 0, 5)
}
/// rD/rS/rT (bits 6-10) - destination/source register
#[inline] pub fn rd(&self) -> usize { extract_bits(self.raw, 6, 10) as usize }
#[inline] pub fn rs(&self) -> usize { self.rd() }
#[inline] pub fn rt(&self) -> usize { self.rd() }
#[inline]
pub fn rd(&self) -> usize {
extract_bits(self.raw, 6, 10) as usize
}
#[inline]
pub fn rs(&self) -> usize {
self.rd()
}
#[inline]
pub fn rt(&self) -> usize {
self.rd()
}
/// rA (bits 11-15)
#[inline] pub fn ra(&self) -> usize { extract_bits(self.raw, 11, 15) as usize }
#[inline]
pub fn ra(&self) -> usize {
extract_bits(self.raw, 11, 15) as usize
}
/// rB (bits 16-20)
#[inline] pub fn rb(&self) -> usize { extract_bits(self.raw, 16, 20) as usize }
#[inline]
pub fn rb(&self) -> usize {
extract_bits(self.raw, 16, 20) as usize
}
/// rC (bits 21-25) - for 4-operand instructions
#[inline] pub fn rc(&self) -> usize { extract_bits(self.raw, 21, 25) as usize }
#[inline]
pub fn rc(&self) -> usize {
extract_bits(self.raw, 21, 25) as usize
}
/// SIMM/UIMM (bits 16-31) - signed/unsigned immediate
#[inline] pub fn simm16(&self) -> i16 { (self.raw & 0xFFFF) as i16 }
#[inline] pub fn uimm16(&self) -> u16 { (self.raw & 0xFFFF) as u16 }
#[inline]
pub fn simm16(&self) -> i16 {
(self.raw & 0xFFFF) as i16
}
#[inline]
pub fn uimm16(&self) -> u16 {
(self.raw & 0xFFFF) as u16
}
/// D-form displacement (signed, bits 16-31)
#[inline] pub fn d(&self) -> i32 { self.simm16() as i32 }
#[inline]
pub fn d(&self) -> i32 {
self.simm16() as i32
}
/// DS-form displacement (signed, bits 16-29, shifted left 2)
#[inline] pub fn ds(&self) -> i32 { (self.raw & 0xFFFC) as i16 as i32 }
#[inline]
pub fn ds(&self) -> i32 {
(self.raw & 0xFFFC) as i16 as i32
}
/// LI field for branch (bits 6-29, sign-extended, shifted left 2)
#[inline] pub fn li(&self) -> i32 {
#[inline]
pub fn li(&self) -> i32 {
let li = extract_bits(self.raw, 6, 29);
// Sign-extend from 24 bits, then shift left 2
let sign_extended = ((li as i32) << 8) >> 8;
@@ -53,87 +87,154 @@ impl DecodedInstr {
}
/// BD field for conditional branch (bits 16-29, sign-extended, shifted left 2)
#[inline] pub fn bd(&self) -> i32 {
#[inline]
pub fn bd(&self) -> i32 {
let bd = extract_bits(self.raw, 16, 29);
let sign_extended = ((bd as i32) << 18) >> 18;
sign_extended << 2
}
/// BO field (bits 6-10) - branch options
#[inline] pub fn bo(&self) -> u32 { extract_bits(self.raw, 6, 10) }
#[inline]
pub fn bo(&self) -> u32 {
extract_bits(self.raw, 6, 10)
}
/// BI field (bits 11-15) - branch condition
#[inline] pub fn bi(&self) -> u32 { extract_bits(self.raw, 11, 15) }
#[inline]
pub fn bi(&self) -> u32 {
extract_bits(self.raw, 11, 15)
}
/// AA bit (bit 30) - absolute address
#[inline] pub fn aa(&self) -> bool { (self.raw >> 1) & 1 != 0 }
#[inline]
pub fn aa(&self) -> bool {
(self.raw >> 1) & 1 != 0
}
/// LK bit (bit 31) - link (update LR)
#[inline] pub fn lk(&self) -> bool { self.raw & 1 != 0 }
#[inline]
pub fn lk(&self) -> bool {
self.raw & 1 != 0
}
/// Rc bit (bit 31) - record CR0
#[inline] pub fn rc_bit(&self) -> bool { self.raw & 1 != 0 }
#[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 }
#[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.
/// VX128_R Rc bit — PPC bit 25 (host bit 6) per canary's FormatVX128_R
/// bitfield layout. PPCBUG-700.
#[inline] pub fn vx128r_rc_bit(&self) -> bool { (self.raw >> 6) & 1 != 0 }
#[inline]
pub fn vx128r_rc_bit(&self) -> bool {
(self.raw >> 6) & 1 != 0
}
/// IMM field for VX128_4-form instructions (vrlimi128) — 5-bit blend mask at PPC bits 11-15.
#[inline] pub fn vx128_4_imm(&self) -> u32 { extract_bits(self.raw, 11, 15) }
#[inline]
pub fn vx128_4_imm(&self) -> u32 {
extract_bits(self.raw, 11, 15)
}
/// z field for VX128_4-form instructions (vrlimi128) — 2-bit rotation index at PPC bits 24-25.
#[inline] pub fn vx128_4_z(&self) -> u32 { extract_bits(self.raw, 24, 25) }
#[inline]
pub fn vx128_4_z(&self) -> u32 {
extract_bits(self.raw, 24, 25)
}
/// OE bit (bit 21) - overflow enable
#[inline] pub fn oe(&self) -> bool { extract_bits(self.raw, 21, 21) != 0 }
#[inline]
pub fn oe(&self) -> bool {
extract_bits(self.raw, 21, 21) != 0
}
/// TO field (bits 6-10) for tw/twi/td/tdi trap instructions.
#[inline] pub fn to(&self) -> u32 { extract_bits(self.raw, 6, 10) }
#[inline]
pub fn to(&self) -> u32 {
extract_bits(self.raw, 6, 10)
}
/// MB, ME fields for rotate instructions
#[inline] pub fn mb(&self) -> u32 { extract_bits(self.raw, 21, 25) }
#[inline] pub fn me(&self) -> u32 { extract_bits(self.raw, 26, 30) }
#[inline]
pub fn mb(&self) -> u32 {
extract_bits(self.raw, 21, 25)
}
#[inline]
pub fn me(&self) -> u32 {
extract_bits(self.raw, 26, 30)
}
/// SH field (bits 16-20) for shift instructions
#[inline] pub fn sh(&self) -> u32 { extract_bits(self.raw, 16, 20) }
#[inline]
pub fn sh(&self) -> u32 {
extract_bits(self.raw, 16, 20)
}
/// SH field for 64-bit shifts (bits 16-20 + bit 30)
#[inline] pub fn sh64(&self) -> u32 {
#[inline]
pub fn sh64(&self) -> u32 {
(extract_bits(self.raw, 30, 30) << 5) | extract_bits(self.raw, 16, 20)
}
/// MB/ME field for MD-form and MDS-form instructions (6-bit field, split encoding).
/// MB[4:0] at PPC bits 21-25; MB[5] at PPC bit 26.
#[inline] pub fn mb_md(&self) -> u32 {
#[inline]
pub fn mb_md(&self) -> u32 {
extract_bits(self.raw, 21, 25) | (extract_bits(self.raw, 26, 26) << 5)
}
/// SPR field (bits 11-20, swapped halves)
#[inline] pub fn spr(&self) -> u32 {
#[inline]
pub fn spr(&self) -> u32 {
let spr_raw = extract_bits(self.raw, 11, 20);
((spr_raw & 0x1F) << 5) | ((spr_raw >> 5) & 0x1F)
}
/// CRM field (bits 12-19) for mtcrf
#[inline] pub fn crm(&self) -> u32 { extract_bits(self.raw, 12, 19) }
#[inline]
pub fn crm(&self) -> u32 {
extract_bits(self.raw, 12, 19)
}
/// crfD (bits 6-8) - condition register field destination
#[inline] pub fn crfd(&self) -> usize { extract_bits(self.raw, 6, 8) as usize }
#[inline]
pub fn crfd(&self) -> usize {
extract_bits(self.raw, 6, 8) as usize
}
/// crfS (bits 11-13)
#[inline] pub fn crfs(&self) -> usize { extract_bits(self.raw, 11, 13) as usize }
#[inline]
pub fn crfs(&self) -> usize {
extract_bits(self.raw, 11, 13) as usize
}
/// L bit (bit 10) - 64-bit compare
#[inline] pub fn l(&self) -> bool { extract_bits(self.raw, 10, 10) != 0 }
#[inline]
pub fn l(&self) -> bool {
extract_bits(self.raw, 10, 10) != 0
}
/// crbD (bits 6-10)
#[inline] pub fn crbd(&self) -> u32 { extract_bits(self.raw, 6, 10) }
#[inline]
pub fn crbd(&self) -> u32 {
extract_bits(self.raw, 6, 10)
}
/// crbA (bits 11-15)
#[inline] pub fn crba(&self) -> u32 { extract_bits(self.raw, 11, 15) }
#[inline]
pub fn crba(&self) -> u32 {
extract_bits(self.raw, 11, 15)
}
/// crbB (bits 16-20)
#[inline] pub fn crbb(&self) -> u32 { extract_bits(self.raw, 16, 20) }
#[inline]
pub fn crbb(&self) -> u32 {
extract_bits(self.raw, 16, 20)
}
// VMX128 field extractors — bit positions match canary's
// FormatVX128/VX128_2/VX128_4/VX128_5/VX128_R bitfield layout
@@ -141,7 +242,8 @@ impl DecodedInstr {
/// VA128 = VA128l(5) | VA128h(1) << 5 | VA128H(1) << 6.
/// Canonical 7-bit register selector: PPC 11-15 (low), PPC 26 (mid), PPC 21 (high).
#[inline] pub fn va128(&self) -> usize {
#[inline]
pub fn va128(&self) -> usize {
(extract_bits(self.raw, 11, 15)
| (extract_bits(self.raw, 26, 26) << 5)
| (extract_bits(self.raw, 21, 21) << 6)) as usize
@@ -149,35 +251,48 @@ impl DecodedInstr {
/// VB128 = VB128l(5) | VB128h(2) << 5. Canary's VB128h is a 2-bit
/// contiguous field at PPC 30-31 (host bits 0-1).
#[inline] pub fn vb128(&self) -> usize {
(extract_bits(self.raw, 16, 20)
| (extract_bits(self.raw, 30, 31) << 5)) as usize
#[inline]
pub fn vb128(&self) -> usize {
(extract_bits(self.raw, 16, 20) | (extract_bits(self.raw, 30, 31) << 5)) as usize
}
/// VD128 = VD128l(5) | VD128h(2) << 5. Canary's VD128h is a 2-bit
/// contiguous field at PPC 28-29 (host bits 2-3).
#[inline] pub fn vd128(&self) -> usize {
(extract_bits(self.raw, 6, 10)
| (extract_bits(self.raw, 28, 29) << 5)) as usize
#[inline]
pub fn vd128(&self) -> usize {
(extract_bits(self.raw, 6, 10) | (extract_bits(self.raw, 28, 29) << 5)) as usize
}
/// VS128 - same encoding as VD128
#[inline] pub fn vs128(&self) -> usize { self.vd128() }
#[inline]
pub fn vs128(&self) -> usize {
self.vd128()
}
/// VC register for VX128_2-form instructions (vperm128) — 3-bit at PPC bits 23-25.
#[inline] pub fn vc128_2(&self) -> usize { extract_bits(self.raw, 23, 25) as usize }
#[inline]
pub fn vc128_2(&self) -> usize {
extract_bits(self.raw, 23, 25) as usize
}
/// NB field (bits 16-20) for lswi/stswi
#[inline] pub fn nb(&self) -> u32 { extract_bits(self.raw, 16, 20) }
#[inline]
pub fn nb(&self) -> u32 {
extract_bits(self.raw, 16, 20)
}
/// PERM field for VX128_P-form instructions (vpermwi128) — 8-bit split encoding.
/// PERMl (5 bits) at PPC bits 11-15; PERMh (3 bits) at PPC bits 23-25.
#[inline] pub fn vx128_p_perm(&self) -> u32 {
#[inline]
pub fn vx128_p_perm(&self) -> u32 {
extract_bits(self.raw, 11, 15) | (extract_bits(self.raw, 23, 25) << 5)
}
/// SH field for VX128_5-form instructions (vsldoi128) — 4-bit shift at PPC bits 22-25.
#[inline] pub fn vx128_5_sh(&self) -> u32 { extract_bits(self.raw, 22, 25) }
#[inline]
pub fn vx128_5_sh(&self) -> u32 {
extract_bits(self.raw, 22, 25)
}
}
/// Extract the 5-bit `UIMM` (`VX128_3`) / `IMM` (`VX128_4`) field. Canary
@@ -1057,8 +1172,15 @@ mod tests {
/// vd_hi is 2 bits (PPC 28-29). Same shape for vb128 (vb_lo at PPC 16-20,
/// vb_hi 2 bits at PPC 30-31). va128 = va_lo | (va_h26<<5) | (va_h21<<6)
/// per canary's 7-bit VA selector.
fn vmx128_test_word(vd_lo: u32, vd_hi: u32, va_lo: u32, va_h26: u32, va_h21: u32,
vb_lo: u32, vb_hi: u32) -> u32 {
fn vmx128_test_word(
vd_lo: u32,
vd_hi: u32,
va_lo: u32,
va_h26: u32,
va_h21: u32,
vb_lo: u32,
vb_hi: u32,
) -> u32 {
// PPC bit i -> host bit (31-i).
(vd_lo << (31 - 10)) // VD128l: PPC 6-10 = host 21-25
| (vd_hi << (31 - 29)) // VD128h: PPC 28-29 = host 2-3 (LSB at host 2)
@@ -1066,15 +1188,19 @@ mod tests {
| (va_h26 << (31 - 26)) // VA128h: PPC 26 = host 5
| (va_h21 << (31 - 21)) // VA128H: PPC 21 = host 10
| (vb_lo << (31 - 20)) // VB128l: PPC 16-20 = host 11-15
| (vb_hi << (31 - 31)) // VB128h: PPC 30-31 = host 0-1 (LSB at host 0)
| vb_hi // VB128h: PPC 30-31 = host 0-1 (LSB at host 0)
}
#[test]
fn vmx128_vd128_low_5_bits_only() {
// vd_lo = 0..31, vd_hi = 0 → vd128 = vd_lo
for r in 0..32u32 {
let raw = (r as u32) << (31 - 10);
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let raw = r << (31 - 10);
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vd128(), r as usize, "vd_lo={r}");
}
}
@@ -1082,26 +1208,36 @@ mod tests {
#[test]
fn vmx128_vd128_high_low_bit_adds_32() {
// vd_lo = 0, VD128h = 0b01 (LSB only at host bit 2 = PPC 29) → vd128 = 32
let raw = (1u32 << (31 - 29));
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let raw = 1u32 << (31 - 29);
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vd128(), 32);
}
#[test]
fn vmx128_vd128_high_high_bit_adds_64() {
// vd_lo = 0, VD128h = 0b10 (MSB only at host bit 3 = PPC 28) → vd128 = 64
let raw = (1u32 << (31 - 28));
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let raw = 1u32 << (31 - 28);
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vd128(), 64);
}
#[test]
fn vmx128_vd128_full_127() {
// vd_lo = 31, VD128h = 0b11 → vd128 = 127
let raw = (31u32 << (31 - 10))
| (1u32 << (31 - 28))
| (1u32 << (31 - 29));
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let raw = (31u32 << (31 - 10)) | (1u32 << (31 - 28)) | (1u32 << (31 - 29));
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vd128(), 127);
}
@@ -1109,11 +1245,19 @@ mod tests {
fn vmx128_va128_canary_layout() {
// va_lo = 7 at PPC 11-15, VA128h = 1 at PPC 26 → va128 = 7 | 32 = 39
let raw = (7u32 << (31 - 15)) | (1u32 << (31 - 26));
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.va128(), 39);
// VA128H = 1 at PPC 21 → va128 += 64 = 103
let raw = raw | (1u32 << (31 - 21));
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.va128(), 7 | 32 | 64);
}
@@ -1122,10 +1266,18 @@ mod tests {
// vb_lo = 5 at PPC 16-20. VB128h = 0b01 (LSB at PPC 31 = host 0) → +32.
// VB128h = 0b11 → +96.
let raw = (5u32 << (31 - 20)) | (1u32 << (31 - 31));
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vb128(), 5 | 32);
let raw = raw | (1u32 << (31 - 30));
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vb128(), 5 | 32 | 64);
}
@@ -1135,9 +1287,12 @@ mod tests {
for r in [0u32, 31, 32, 64, 96, 127] {
let lo = r & 0x1F;
let hi = (r >> 5) & 0x3;
let raw = (lo << (31 - 10))
| (hi << (31 - 29));
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let raw = (lo << (31 - 10)) | (hi << (31 - 29));
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vd128(), r as usize, "vd128 mismatch for r={r}");
assert_eq!(d.vs128(), r as usize, "vs128 mismatch for r={r}");
assert_eq!(d.vd128(), d.vs128());
@@ -1150,7 +1305,11 @@ mod tests {
// Keep the helper validated against the real accessor.
// vd_lo=5, vd_hi=0b11 → vd128 = 5 | 96 = 101
let raw = vmx128_test_word(5, 3, 0, 0, 0, 0, 0);
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vd128(), 5 | 32 | 64);
}
@@ -1160,21 +1319,37 @@ mod tests {
// Host bit 9 = 1 (PPC bit 22), host bits 6-8 = 0.
// So raw bit 9 set = raw |= 1 << 9 = 0x200
let raw = 0x200u32; // host bit 9 set only
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vx128_5_sh(), 8, "SH=8: MSB at PPC bit 22");
// SH=1 (binary 0001): host bit 6 set = raw |= 1 << 6 = 0x40
let raw = 0x40u32;
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vx128_5_sh(), 1, "SH=1: LSB at PPC bit 25");
// SH=15 (binary 1111): host bits 6-9 all set = raw |= 0xF << 6 = 0x3C0
let raw = 0x3C0u32;
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vx128_5_sh(), 15, "SH=15: all 4 bits set");
// SH=0: raw=0
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw: 0, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw: 0,
addr: 0,
};
assert_eq!(d.vx128_5_sh(), 0, "SH=0");
}
@@ -1182,23 +1357,39 @@ mod tests {
fn vx128_4_accessors_correct_bit_positions() {
// z=3 (binary 11) at PPC bits 24-25 = host bits 6-7
let raw = 0b11u32 << 6;
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vx128_4_z(), 3, "z=3 from host bits 6-7");
// IMM=0x15 (binary 10101) at PPC bits 11-15 = host bits 16-20
let raw2 = 0x15u32 << 16;
let d2 = DecodedInstr { opcode: PpcOpcode::Invalid, raw: raw2, addr: 0 };
let d2 = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw: raw2,
addr: 0,
};
assert_eq!(d2.vx128_4_imm(), 0x15, "IMM=0x15 from host bits 16-20");
// Combined: z=1, IMM=0xA — fields must not bleed into each other
let raw3 = (0x1u32 << 6) | (0xAu32 << 16);
let d3 = DecodedInstr { opcode: PpcOpcode::Invalid, raw: raw3, addr: 0 };
let d3 = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw: raw3,
addr: 0,
};
assert_eq!(d3.vx128_4_z(), 1, "z=1 combined");
assert_eq!(d3.vx128_4_imm(), 0xA, "IMM=0xA combined");
// z=2, IMM=0xF — max 4-bit blend mask, exercises the full lower nibble
let raw4 = (0b10u32 << 6) | (0xFu32 << 16);
let d4 = DecodedInstr { opcode: PpcOpcode::Invalid, raw: raw4, addr: 0 };
let d4 = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw: raw4,
addr: 0,
};
assert_eq!(d4.vx128_4_z(), 2, "z=2 from binary 10");
assert_eq!(d4.vx128_4_imm(), 0xF, "IMM=0xF all-ones nibble");
}
@@ -1208,16 +1399,32 @@ mod tests {
// VC=5 (binary 101) at PPC bits 23-25 = host bits 6-8
// extract_bits(raw, 23, 25) = (raw >> (31-25)) & 0x7 = (raw >> 6) & 0x7
let raw = 5u32 << 6; // host bits 6-8 = 5
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vc128_2(), 5);
let d0 = DecodedInstr { opcode: PpcOpcode::Invalid, raw: 0, addr: 0 };
let d0 = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw: 0,
addr: 0,
};
assert_eq!(d0.vc128_2(), 0);
let d7 = DecodedInstr { opcode: PpcOpcode::Invalid, raw: 7u32 << 6, addr: 0 };
let d7 = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw: 7u32 << 6,
addr: 0,
};
assert_eq!(d7.vc128_2(), 7);
let d1 = DecodedInstr { opcode: PpcOpcode::Invalid, raw: 1u32 << 6, addr: 0 };
let d1 = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw: 1u32 << 6,
addr: 0,
};
assert_eq!(d1.vc128_2(), 1);
}
@@ -1225,21 +1432,37 @@ mod tests {
fn vx128_p_perm_assembles_correctly() {
// PERMl=0x1F (all 5 bits set) at host bits 16-20: raw = 0x1F << 16
let raw = 0x1Fu32 << 16;
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vx128_p_perm(), 0x1F, "PERMl only");
// PERMh=0x7 (all 3 bits set) at host bits 6-8: raw = 0x7 << 6 = 0x1C0
let raw = 0x7u32 << 6;
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vx128_p_perm(), 0x7 << 5, "PERMh only: bits 5-7");
// PERMl=0xA, PERMh=0x5: raw = (0xA << 16) | (0x5 << 6)
let raw = (0xAu32 << 16) | (0x5u32 << 6);
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw,
addr: 0,
};
assert_eq!(d.vx128_p_perm(), 0xA | (0x5 << 5));
// PERMl and PERMh bits must not bleed into each other
let d = DecodedInstr { opcode: PpcOpcode::Invalid, raw: 0, addr: 0 };
let d = DecodedInstr {
opcode: PpcOpcode::Invalid,
raw: 0,
addr: 0,
};
assert_eq!(d.vx128_p_perm(), 0);
}
}