use crate::*;
fn write_mm_via_mem(mem: u64, addr: u64, value: u64) {
let mut emu = emu64();
emu.maps.write_qword(addr, value);
}
#[test]
fn test_pmulhw_mm_mm_basic() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1, 0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x1000100010001000);
emu.maps.write_qword(0x2008, 0x1000100010001000);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0100010001000100, "PMULHW: basic multiplication");
}
#[test]
fn test_pmulhw_high_16_bits() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x7FFF7FFF7FFF7FFF);
emu.maps.write_qword(0x2008, 0x7FFF7FFF7FFF7FFF);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x3FFF3FFF3FFF3FFF, "PMULHW: high 16 bits");
}
#[test]
fn test_pmulhw_signed_positive() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x4000400040004000);
emu.maps.write_qword(0x2008, 0x0002000200020002);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0000000000000000, "PMULHW: signed positive");
}
#[test]
fn test_pmulhw_signed_negative() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0xFFFFFFFFFFFFFFFF);
emu.maps.write_qword(0x2008, 0x0002000200020002);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0xFFFFFFFFFFFFFFFF, "PMULHW: negative * positive");
}
#[test]
fn test_pmulhw_negative_negative() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x8000800080008000);
emu.maps.write_qword(0x2008, 0x8000800080008000);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x4000400040004000, "PMULHW: negative * negative");
}
#[test]
fn test_pmulhw_zero() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x1234567890ABCDEF);
emu.maps.write_qword(0x2008, 0x0000000000000000);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0000000000000000, "PMULHW: multiply by zero");
}
#[test]
fn test_pmulhw_by_one() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x1234567890ABCDEF);
emu.maps.write_qword(0x2008, 0x0001000100010001);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x00000000FFFFFFFF, "PMULHW: multiply by 1 preserves sign in high bits");
}
#[test]
fn test_pmulhw_mm_m64() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x14, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0x14, 0x25, 0x08, 0x20, 0x00, 0x00, 0x0f, 0x7f, 0x14, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x2000200020002000);
emu.maps.write_qword(0x2008, 0x2000200020002000);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0400040004000400, "PMULHW: memory operand");
}
#[test]
fn test_pmulhw_large_values() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x7FFF7FFF7FFF7FFF);
emu.maps.write_qword(0x2008, 0x0002000200020002);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0000000000000000, "PMULHW: large positive");
}
#[test]
fn test_pmulhw_mixed_signs() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x80007FFF80007FFF);
emu.maps.write_qword(0x2008, 0x0002000200020002);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0xFFFF0000FFFF0000, "PMULHW: mixed signs");
}
#[test]
fn test_pmulhw_mm5_mm6() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x2c, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x34, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xee, 0x0f, 0x7f, 0x2c, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x4000400040004000);
emu.maps.write_qword(0x2008, 0x4000400040004000);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x1000100010001000, "PMULHW: MM5 * MM6");
}
#[test]
fn test_pmulhw_powers_of_two() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x0100008000400020);
emu.maps.write_qword(0x2008, 0x0100008000400020);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0001000000000000, "PMULHW: powers of two");
}
#[test]
fn test_pmulhw_sequential() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x1000100010001000);
emu.maps.write_qword(0x2008, 0x0100010001000100);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0000000000000000, "PMULHW: sequential");
}
#[test]
fn test_pmulhw_small_results() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x0010001000100010);
emu.maps.write_qword(0x2008, 0x0010001000100010);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0000000000000000, "PMULHW: small results");
}
#[test]
fn test_pmulhw_by_negative_one() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x0001000200030004);
emu.maps.write_qword(0x2008, 0xFFFFFFFFFFFFFFFF);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0xFFFFFFFFFFFFFFFF, "PMULHW: multiply by -1");
}
#[test]
fn test_pmulhw_asymmetric() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x1000200030004000);
emu.maps.write_qword(0x2008, 0x4000300020001000);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0400060006000400, "PMULHW: asymmetric values");
}
#[test]
fn test_pmulhw_max_positive() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x7FFF7FFF7FFF7FFF);
emu.maps.write_qword(0x2008, 0x7FFF7FFF7FFF7FFF);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x3FFF3FFF3FFF3FFF, "PMULHW: max positive");
}
#[test]
fn test_pmulhw_combined_operations() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x14, 0x25, 0x10, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1, 0x0f, 0xe5, 0xca, 0x0f, 0x7f, 0x04, 0x25, 0x18, 0x20, 0x00, 0x00,
0x0f, 0x7f, 0x0c, 0x25, 0x20, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x2000200020002000);
emu.maps.write_qword(0x2008, 0x2000200020002000);
emu.maps.write_qword(0x2010, 0x2000200020002000);
emu.run(None).unwrap();
let mm0_result = emu.maps.read_qword(0x2018).unwrap();
let mm1_result = emu.maps.read_qword(0x2020).unwrap();
assert_eq!(mm0_result, 0x0400040004000400, "PMULHW: MM0 result");
assert_eq!(mm1_result, 0x0400040004000400, "PMULHW: MM1 result");
}
#[test]
fn test_pmulhw_all_mm_registers() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x3c, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xf8, 0x0f, 0x7f, 0x3c, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x8000800080008000);
emu.maps.write_qword(0x2008, 0x0002000200020002);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0xFFFFFFFFFFFFFFFF, "PMULHW: MM7 * MM0");
}
#[test]
fn test_pmulhw_compare_with_pmullw() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x14, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x1c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1, 0x0f, 0xd5, 0xd3, 0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0x0f, 0x7f, 0x14, 0x25, 0x18, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x1000100010001000);
emu.maps.write_qword(0x2008, 0x1000100010001000);
emu.run(None).unwrap();
let high = emu.maps.read_qword(0x2010).unwrap();
let low = emu.maps.read_qword(0x2018).unwrap();
assert_eq!(high, 0x0100010001000100, "PMULHW: high bits");
assert_eq!(low, 0x0000000000000000, "PMULLW: low bits");
}
#[test]
fn test_pmulhw_boundary_values() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xe5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x80007FFF00018000);
emu.maps.write_qword(0x2008, 0x80007FFF80007FFF);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x40003FFFFFFFC000, "PMULHW: boundary values");
}