use crate::*;
#[test]
fn test_shld_all_counts_16bit() {
for count in [0, 1, 4, 8, 12, 15, 16].iter() {
let code = [0x66, 0x0f, 0xa4, 0xd8, *count, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0xAAAA; emu.regs_mut().rbx = 0x5555; emu.load_code_bytes(&code);
emu.run(None).unwrap();
if *count == 0 {
assert_eq!(emu.regs().rax & 0xFFFF, 0xAAAA, "SHLD AX by 0");
} else if *count == 16 {
assert_eq!(emu.regs().rax & 0xFFFF, 0x5555, "SHLD AX by 16 (full replacement)");
}
}
}
#[test]
fn test_shrd_all_counts_16bit() {
for count in [0, 1, 4, 8, 12, 15, 16].iter() {
let code = [0x66, 0x0f, 0xac, 0xd8, *count, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0xAAAA;
emu.regs_mut().rbx = 0x5555;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
if *count == 0 {
assert_eq!(emu.regs().rax & 0xFFFF, 0xAAAA, "SHRD AX by 0");
} else if *count == 16 {
assert_eq!(emu.regs().rax & 0xFFFF, 0x5555, "SHRD AX by 16 (full replacement)");
}
}
}
#[test]
fn test_shld_all_counts_32bit() {
for count in [0, 1, 4, 8, 16, 24, 31, 32].iter() {
let code = [0x0f, 0xa4, 0xd8, *count, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0xAAAAAAAA;
emu.regs_mut().rbx = 0x55555555;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
if *count == 0 {
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0xAAAAAAAA, "SHLD EAX by 0");
} else if *count == 32 {
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0xAAAAAAAA, "SHLD EAX by 32 (count masked to 0)");
}
}
}
#[test]
fn test_shrd_all_counts_32bit() {
for count in [0, 1, 4, 8, 16, 24, 31, 32].iter() {
let code = [0x0f, 0xac, 0xd8, *count, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0xAAAAAAAA;
emu.regs_mut().rbx = 0x55555555;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
if *count == 0 {
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0xAAAAAAAA, "SHRD EAX by 0");
} else if *count == 32 {
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0xAAAAAAAA, "SHRD EAX by 32 (count masked to 0)");
}
}
}
#[test]
fn test_shld_all_counts_64bit() {
for count in [0, 1, 8, 16, 32, 48, 63, 64].iter() {
let code = [0x48, 0x0f, 0xa4, 0xd8, *count, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0xAAAAAAAAAAAAAAAA;
emu.regs_mut().rbx = 0x5555555555555555;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
if *count == 0 {
assert_eq!(emu.regs().rax, 0xAAAAAAAAAAAAAAAA, "SHLD RAX by 0");
} else if *count == 64 {
assert_eq!(emu.regs().rax, 0xAAAAAAAAAAAAAAAA, "SHLD RAX by 64 (count masked to 0)");
}
}
}
#[test]
fn test_shrd_all_counts_64bit() {
for count in [0, 1, 8, 16, 32, 48, 63, 64].iter() {
let code = [0x48, 0x0f, 0xac, 0xd8, *count, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0xAAAAAAAAAAAAAAAA;
emu.regs_mut().rbx = 0x5555555555555555;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
if *count == 0 {
assert_eq!(emu.regs().rax, 0xAAAAAAAAAAAAAAAA, "SHRD RAX by 0");
} else if *count == 64 {
assert_eq!(emu.regs().rax, 0xAAAAAAAAAAAAAAAA, "SHRD RAX by 64 (count masked to 0)");
}
}
}
#[test]
fn test_shld_boundary_values_32bit() {
let test_cases = [
(0x00000000, 0x00000000),
(0xFFFFFFFF, 0xFFFFFFFF),
(0x00000000, 0xFFFFFFFF),
(0xFFFFFFFF, 0x00000000),
(0x80000000, 0x00000001),
(0x00000001, 0x80000000),
];
for (dest, src) in &test_cases {
let code = [0x0f, 0xa4, 0xd8, 0x10, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = *dest;
emu.regs_mut().rbx = *src;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
let expected = ((*dest << 16) | (*src >> 16)) & 0xFFFFFFFF;
assert_eq!(emu.regs().rax & 0xFFFFFFFF, expected, "SHLD 0x{:08X} with 0x{:08X}", dest, src);
}
}
#[test]
fn test_shrd_boundary_values_32bit() {
let test_cases = [
(0x00000000, 0x00000000),
(0xFFFFFFFF, 0xFFFFFFFF),
(0x00000000, 0xFFFFFFFF),
(0xFFFFFFFF, 0x00000000),
(0x80000000, 0x00000001),
(0x00000001, 0x80000000),
];
for (dest, src) in &test_cases {
let code = [0x0f, 0xac, 0xd8, 0x10, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = *dest;
emu.regs_mut().rbx = *src;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
let expected = ((*dest >> 16) | (*src << 16)) & 0xFFFFFFFF;
assert_eq!(emu.regs().rax & 0xFFFFFFFF, expected, "SHRD 0x{:08X} with 0x{:08X}", dest, src);
}
}
#[test]
fn test_shld_boundary_values_64bit() {
let test_cases = [
(0x0000000000000000, 0x0000000000000000),
(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF),
(0x0000000000000000, 0xFFFFFFFFFFFFFFFF),
(0xFFFFFFFFFFFFFFFF, 0x0000000000000000),
];
for (dest, src) in &test_cases {
let code = [0x48, 0x0f, 0xa4, 0xd8, 0x20, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = *dest;
emu.regs_mut().rbx = *src;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
let expected = (*dest << 32) | (*src >> 32);
assert_eq!(emu.regs().rax, expected, "SHLD 0x{:016X} with 0x{:016X}", dest, src);
}
}
#[test]
fn test_shrd_boundary_values_64bit() {
let test_cases = [
(0x0000000000000000, 0x0000000000000000),
(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF),
(0x0000000000000000, 0xFFFFFFFFFFFFFFFF),
(0xFFFFFFFFFFFFFFFF, 0x0000000000000000),
];
for (dest, src) in &test_cases {
let code = [0x48, 0x0f, 0xac, 0xd8, 0x20, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = *dest;
emu.regs_mut().rbx = *src;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
let expected = (*dest >> 32) | (*src << 32);
assert_eq!(emu.regs().rax, expected, "SHRD 0x{:016X} with 0x{:016X}", dest, src);
}
}
#[test]
fn test_shld_count_masking_32bit() {
let code = [0x0f, 0xa5, 0xd8, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x12345678;
emu.regs_mut().rbx = 0xABCDEF01;
emu.regs_mut().rcx = 0x24; emu.load_code_bytes(&code);
emu.run(None).unwrap();
let rax = emu.regs().rax;
let code2 = [0x0f, 0xa4, 0xd8, 0x04, 0xf4];
let mut emu = emu64();
emu.load_code_bytes(&code2);
emu.regs_mut().rax = 0x12345678;
emu.regs_mut().rbx = 0xABCDEF01;
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, rax & 0xFFFFFFFF, "Count masking for 32-bit SHLD");
}
#[test]
fn test_shrd_count_masking_32bit() {
let code = [0x0f, 0xad, 0xd8, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x12345678;
emu.regs_mut().rbx = 0xABCDEF01;
emu.regs_mut().rcx = 0x24; emu.load_code_bytes(&code);
emu.run(None).unwrap();
let rax = emu.regs().rax;
let code2 = [0x0f, 0xac, 0xd8, 0x04, 0xf4];
let mut emu = emu64();
emu.regs_mut().rax = 0x12345678;
emu.regs_mut().rbx = 0xABCDEF01;
emu.load_code_bytes(&code2);
emu.run(None).unwrap();
assert_eq!(rax & 0xFFFFFFFF, emu.regs().rax & 0xFFFFFFFF, "Count masking for 32-bit SHRD");
}
#[test]
fn test_shld_count_masking_64bit() {
let code = [0x48, 0x0f, 0xa5, 0xd8, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x123456789ABCDEF0;
emu.regs_mut().rbx = 0xFEDCBA9876543210;
emu.regs_mut().rcx = 0x48; emu.load_code_bytes(&code);
emu.run(None).unwrap();
let rax = emu.regs().rax;
let code2 = [0x48, 0x0f, 0xa4, 0xd8, 0x08, 0xf4];
let mut emu = emu64();
emu.regs_mut().rax = 0x123456789ABCDEF0;
emu.regs_mut().rbx = 0xFEDCBA9876543210;
emu.load_code_bytes(&code2);
emu.run(None).unwrap();
assert_eq!(rax, emu.regs().rax, "Count masking for 64-bit SHLD");
}
#[test]
fn test_shrd_count_masking_64bit() {
let code = [0x48, 0x0f, 0xad, 0xd8, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x123456789ABCDEF0;
emu.regs_mut().rbx = 0xFEDCBA9876543210;
emu.regs_mut().rcx = 0x48; emu.load_code_bytes(&code);
emu.run(None).unwrap();
let rax = emu.regs().rax;
let code2 = [0x48, 0x0f, 0xac, 0xd8, 0x08, 0xf4];
let mut emu = emu64();
emu.regs_mut().rax = 0x123456789ABCDEF0;
emu.regs_mut().rbx = 0xFEDCBA9876543210;
emu.load_code_bytes(&code2);
emu.run(None).unwrap();
assert_eq!(rax, emu.regs().rax, "Count masking for 64-bit SHRD");
}
#[test]
fn test_shld_cf_edge_cases() {
let test_cases = [
(0x00000000, 8, false), (0xFF000000, 8, true), (0x80000000, 1, true), (0x7FFFFFFF, 1, false), ];
for (value, count, expected_cf) in &test_cases {
let code = [0x0f, 0xa4, 0xd8, *count, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = *value;
emu.regs_mut().rbx = 0x00000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.flags().f_cf, *expected_cf, "CF for SHLD 0x{:08X} by {}", value, count);
}
}
#[test]
fn test_shrd_cf_edge_cases() {
let test_cases = [
(0x00000000, 8, false), (0x000000FF, 8, true), (0x00000001, 1, true), (0xFFFFFFFE, 1, false), ];
for (value, count, expected_cf) in &test_cases {
let code = [0x0f, 0xac, 0xd8, *count, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = *value;
emu.regs_mut().rbx = 0x00000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.flags().f_cf, *expected_cf, "CF for SHRD 0x{:08X} by {}", value, count);
}
}
#[test]
fn test_shld_of_1bit_shift() {
let code = [0x0f, 0xa4, 0xd8, 0x01, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x40000000; emu.regs_mut().rbx = 0x00000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_of, "OF should be set for sign change");
}
#[test]
fn test_shrd_of_1bit_shift() {
let code = [0x0f, 0xac, 0xd8, 0x01, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x00000002;
emu.regs_mut().rbx = 0x00000001; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_of, "OF should be set for sign change");
}
#[test]
fn test_shld_sf_zf_flags() {
let code = [0x0f, 0xa4, 0xd8, 0x01, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x40000000;
emu.regs_mut().rbx = 0x00000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_sf, "SF should be set (result is negative)");
assert!(!emu.flags().f_zf, "ZF should be clear (result is non-zero)");
}
#[test]
fn test_shrd_sf_zf_flags() {
let code = [0x0f, 0xac, 0xd8, 0x01, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x00000002;
emu.regs_mut().rbx = 0x00000001;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_sf, "SF should be set (result is negative)");
assert!(!emu.flags().f_zf, "ZF should be clear (result is non-zero)");
}
#[test]
fn test_shld_zero_result() {
let code = [0x0f, 0xa4, 0xd8, 0x10, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x00000000;
emu.regs_mut().rbx = 0x00000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0, "Result should be zero");
assert!(emu.flags().f_zf, "ZF should be set");
}
#[test]
fn test_shrd_zero_result() {
let code = [0x0f, 0xac, 0xd8, 0x10, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x00000000;
emu.regs_mut().rbx = 0x00000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0, "Result should be zero");
assert!(emu.flags().f_zf, "ZF should be set");
}
#[test]
fn test_shld_128bit_simulation() {
let code = [
0x48, 0x0f, 0xa4, 0xd0, 0x10, 0x48, 0xc1, 0xe2, 0x10, 0xf4,
];
let mut emu = emu64();
emu.regs_mut().rax = 0x123456789ABCDEF0; emu.regs_mut().rdx = 0xFEDCBA9876543210; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x56789ABCDEF0FEDC, "High 64 bits after SHLD");
assert_eq!(emu.regs().rdx, 0xBA98765432100000, "Low 64 bits after SHL");
}
#[test]
fn test_shrd_128bit_simulation() {
let code = [
0x48, 0x0f, 0xac, 0xd0, 0x10, 0x48, 0xc1, 0xea, 0x10, 0xf4,
];
let mut emu = emu64();
emu.regs_mut().rax = 0xFEDCBA9876543210; emu.regs_mut().rdx = 0x123456789ABCDEF0; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0xDEF0FEDCBA987654, "Low 64 bits after SHRD");
assert_eq!(emu.regs().rdx, 0x0000123456789ABC, "High 64 bits after SHR");
}
#[test]
fn test_shld_alternating_pattern() {
let code = [0x0f, 0xa4, 0xd8, 0x10, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0xAAAAAAAA; emu.regs_mut().rbx = 0x55555555; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0xAAAA5555, "Alternating pattern SHLD");
}
#[test]
fn test_shrd_alternating_pattern() {
let code = [0x0f, 0xac, 0xd8, 0x10, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0xAAAAAAAA;
emu.regs_mut().rbx = 0x55555555;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x5555AAAA, "Alternating pattern SHRD");
}
#[test]
fn test_shld_shrd_complementary() {
let code = [0x0f, 0xa4, 0xd8, 0x0C, 0xf4]; let mut emu = emu64();
emu.regs_mut().rax = 0x12345678;
emu.regs_mut().rbx = 0xABCDEF01;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
let regs_shld = emu.regs();
let mut emu = emu64();
let code2 = [0x0f, 0xac, 0xd8, 0x14, 0xf4]; emu.load_code_bytes(&code2);
emu.regs_mut().rax = 0x12345678;
emu.regs_mut().rbx = 0xABCDEF01;
emu.run(None).unwrap();
let regs_shrd = emu.regs();
let combined_shld = ((regs_shld.rax & 0xFFFFFFFF) as u64) << 20;
let combined_shrd = (regs_shrd.rax & 0xFFFFFFFF) as u64;
let original = (0x12345678u64 << 32) | 0xABCDEF01;
let _ = combined_shld | combined_shrd;
let _ = original;
}