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_pmullw_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, 0xd5, 0xc1, 0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x0004000300020001);
emu.maps.write_qword(0x2008, 0x0005000400030002);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0014000C00060002, "PMULLW: basic multiplication");
}
#[test]
fn test_pmullw_low_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, 0xd5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x03E8006403E80064);
emu.maps.write_qword(0x2008, 0x03E8006403E80064);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x4240271042402710, "PMULLW: low 16 bits only");
}
#[test]
fn test_pmullw_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, 0xd5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x7FFF00017FFF0001);
emu.maps.write_qword(0x2008, 0x0002000200020002);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0xFFFE0002FFFE0002, "PMULLW: signed positive");
}
#[test]
fn test_pmullw_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, 0xd5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0xFFFEFFFFFFFFFFFE);
emu.maps.write_qword(0x2008, 0x0003000200030002);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0xFFFAFFFEFFFDFFFC, "PMULLW: negative values");
}
#[test]
fn test_pmullw_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, 0xd5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0xFFFEFFFFFFFEFFFF);
emu.maps.write_qword(0x2008, 0xFFFEFFFFFFFEFFFF);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0004000100040001, "PMULLW: negative * negative");
}
#[test]
fn test_pmullw_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, 0xd5, 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, "PMULLW: multiply by zero");
}
#[test]
fn test_pmullw_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, 0xd5, 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, 0x1234567890ABCDEF, "PMULLW: multiply by one");
}
#[test]
fn test_pmullw_overflow_discarded() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xd5, 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, 0x0000000000000000, "PMULLW: overflow discarded");
}
#[test]
fn test_pmullw_mm_m64() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x14, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0xd5, 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, 0x000A000A000A000A);
emu.maps.write_qword(0x2008, 0x000A000A000A000A);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0064006400640064, "PMULLW: memory operand");
}
#[test]
fn test_pmullw_large_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, 0xd5, 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, 0xFFFEFFFEFFFEFFFE, "PMULLW: large positive");
}
#[test]
fn test_pmullw_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, 0xd5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x7FFFFFFFFFFF8000);
emu.maps.write_qword(0x2008, 0x000200020002FFFE);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0xFFFEFFFEFFFE0000, "PMULLW: mixed signs");
}
#[test]
fn test_pmullw_mm3_mm4() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x1c, 0x25, 0x00, 0x20, 0x00, 0x00, 0x0f, 0x6f, 0x24, 0x25, 0x08, 0x20, 0x00, 0x00, 0x0f, 0xd5, 0xdc, 0x0f, 0x7f, 0x1c, 0x25, 0x10, 0x20, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x0005000400030002);
emu.maps.write_qword(0x2008, 0x0006000700080009);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x001E001C00180012, "PMULLW: MM3 * MM4");
}
#[test]
fn test_pmullw_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, 0xd5, 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, 0x0002000200020002);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0200010000800040, "PMULLW: powers of two");
}
#[test]
fn test_pmullw_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, 0xd5, 0xc1, 0x0f, 0xd5, 0xc1, 0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x0002000200020002);
emu.maps.write_qword(0x2008, 0x0003000300030003);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0012001200120012, "PMULLW: sequential");
}
#[test]
fn test_pmullw_small_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, 0xd5, 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, 0x0004000300020001);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0004000600060004, "PMULLW: small values");
}
#[test]
fn test_pmullw_max_positive_value() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xd5, 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, 0x0001000100010001, "PMULLW: max positive squared");
}
#[test]
fn test_pmullw_min_negative_value() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xd5, 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, 0x0000000000000000, "PMULLW: min negative squared");
}
#[test]
fn test_pmullw_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, 0xd5, 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, 0xFFFFFFFEFFFDFFFC, "PMULLW: multiply by -1");
}
#[test]
fn test_pmullw_asymmetric_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, 0xd5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x0064000A00640002);
emu.maps.write_qword(0x2008, 0x000100640002000A);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x006403E800C80014, "PMULLW: asymmetric values");
}
#[test]
fn test_pmullw_all_mm_registers() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x2c, 0x25, 0x00, 0x20, 0x00, 0x00, 0x0f, 0x6f, 0x34, 0x25, 0x08, 0x20, 0x00, 0x00, 0x0f, 0xd5, 0xee, 0x0f, 0x6f, 0x3c, 0x25, 0x10, 0x20, 0x00, 0x00, 0x0f, 0xd5, 0xef, 0x0f, 0x7f, 0x2c, 0x25, 0x18, 0x20, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x0002000200020002);
emu.maps.write_qword(0x2008, 0x0003000300030003);
emu.maps.write_qword(0x2010, 0x0004000400040004);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2018).unwrap();
assert_eq!(result, 0x0018001800180018, "PMULLW: all MM registers");
}
#[test]
fn test_pmullw_alternating_pattern() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xd5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0xAAAA5555AAAA5555);
emu.maps.write_qword(0x2008, 0x0002000200020002);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x5554AAAA5554AAAA, "PMULLW: alternating pattern");
}
#[test]
fn test_pmullw_ten_times_ten() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xd5, 0xc1,
0x0f, 0x7f, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_qword(0x2000, 0x000A000A000A000A);
emu.maps.write_qword(0x2008, 0x000A000A000A000A);
emu.run(None).unwrap();
let result = emu.maps.read_qword(0x2010).unwrap();
assert_eq!(result, 0x0064006400640064, "PMULLW: 10 * 10");
}
#[test]
fn test_pmullw_overflow_patterns() {
let mut emu = emu64();
let code = vec![
0x0f, 0x6f, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0x0f, 0x6f, 0x0c, 0x25, 0x08, 0x20, 0x00, 0x00,
0x0f, 0xd5, 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, 0x0000000000000000, "PMULLW: overflow patterns");
}