use crate::*;
#[test]
fn test_adc_carry_chain_8bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x14, 0x01, 0xf4,
];
emu.regs_mut().rax = 0xFF;
emu.flags_mut().load(0x2 | flags::F_CF); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x01, "AL should be 0x01");
assert!(emu.flags().f_cf, "CF should be set (overflow)");
}
#[test]
fn test_adc_no_carry_in_no_carry_out() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0x01, 0xf4]; emu.regs_mut().rax = 0x10;
emu.flags_mut().load(0x2); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x11, "0x10 + 0x01 = 0x11");
assert!(!emu.flags().f_cf, "No carry out");
}
#[test]
fn test_adc_32bit_max_boundary() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x15, 0x00, 0x00, 0x00, 0x00, 0xf4,
];
emu.regs_mut().rax = 0xFFFFFFFF;
emu.flags_mut().load(0x2 | flags::F_CF);
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x00000000, "0xFFFFFFFF + 0 + 1 = 0");
assert!(emu.flags().f_cf, "CF should be set");
assert!(emu.flags().f_zf, "ZF should be set (result is 0)");
}
#[test]
fn test_adc_64bit_carry_propagation() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0x15, 0x00, 0x00, 0x00, 0x00, 0xf4,
];
emu.regs_mut().rax = 0xFFFFFFFFFFFFFFFF;
emu.flags_mut().load(0x2 | flags::F_CF);
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x0000000000000000, "0xFFFFFFFFFFFFFFFF + 0 + 1 = 0");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_adc_signed_overflow() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0x01, 0xf4]; emu.regs_mut().rax = 0x7F;
emu.flags_mut().load(0x2); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x80, "0x7F + 0x01 = 0x80");
assert!(emu.flags().f_of, "OF should be set (signed overflow)");
assert!(!emu.flags().f_cf, "CF should be clear (no unsigned overflow)");
assert!(emu.flags().f_sf, "SF should be set (result is negative)");
}
#[test]
fn test_adc_auxiliary_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0x01, 0xf4]; emu.regs_mut().rax = 0x0F;
emu.flags_mut().load(0x2);
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x10, "0x0F + 0x01 = 0x10");
assert!(emu.flags().f_af, "AF should be set");
}
#[test]
fn test_add_zero_preservation() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x04, 0x00, 0xf4]; emu.regs_mut().rax = 0x00;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x00, "0 + 0 = 0");
assert!(emu.flags().f_zf, "ZF should be set");
}
#[test]
fn test_add_parity_even() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x04, 0x02, 0xf4]; emu.regs_mut().rax = 0x01;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x03, "0x01 + 0x02 = 0x03");
assert!(emu.flags().f_pf, "PF should be set (even parity)");
}
#[test]
fn test_add_parity_odd() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x04, 0x01, 0xf4]; emu.regs_mut().rax = 0x00;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x01, "0x00 + 0x01 = 0x01");
assert!(!emu.flags().f_pf, "PF should be clear (odd parity)");
}
#[test]
fn test_add_register_to_register_32bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x01, 0xd8, 0xf4]; emu.regs_mut().rax = 0x12345678;
emu.regs_mut().rbx = 0x11111111;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x23456789, "0x12345678 + 0x11111111 = 0x23456789");
assert_eq!(emu.regs().rbx & 0xFFFFFFFF, 0x11111111, "EBX unchanged");
}
#[test]
fn test_add_64bit_large_values() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x01, 0xd8, 0xf4]; emu.regs_mut().rax = 0x7FFFFFFFFFFFFFFF; emu.regs_mut().rbx = 0x0000000000000001;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x8000000000000000, "Max i64 + 1 wraps to min");
assert!(emu.flags().f_of, "OF should be set (signed overflow)");
assert!(emu.flags().f_sf, "SF should be set");
}
#[test]
fn test_add_memory_operand() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x03, 0x05, 0xfa, 0x0f, 0x00, 0x00, 0xf4,
];
emu.regs_mut().rax = 0x00000001;
emu.load_code_bytes(&code);
emu.maps.write_dword(DATA_ADDR, 0x00000002);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x00000003, "1 + 2 = 3");
}
#[test]
fn test_sub_zero_result() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x2c, 0x05, 0xf4]; emu.regs_mut().rax = 0x05;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x00, "5 - 5 = 0");
assert!(emu.flags().f_zf, "ZF should be set");
assert!(!emu.flags().f_cf, "CF should be clear (no borrow)");
}
#[test]
fn test_sub_borrow_required() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x2c, 0x01, 0xf4]; emu.regs_mut().rax = 0x00;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0xFF, "0 - 1 = 0xFF (underflow)");
assert!(emu.flags().f_cf, "CF should be set (borrow)");
assert!(emu.flags().f_sf, "SF should be set (negative result)");
}
#[test]
fn test_sub_signed_overflow() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x2c, 0x01, 0xf4]; emu.regs_mut().rax = 0x80; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x7F, "-128 - 1 = 127 (overflow)");
assert!(emu.flags().f_of, "OF should be set (signed overflow)");
assert!(!emu.flags().f_sf, "SF should be clear (positive result)");
}
#[test]
fn test_sub_32bit_underflow() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x2d, 0x01, 0x00, 0x00, 0x00, 0xf4,
];
emu.regs_mut().rax = 0x00000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0xFFFFFFFF, "0 - 1 = 0xFFFFFFFF");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_sub_64bit_large_values() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0x2d, 0x01, 0x00, 0x00, 0x00, 0xf4,
];
emu.regs_mut().rax = 0x8000000000000000; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x7FFFFFFFFFFFFFFF, "Min i64 - 1 wraps to max");
assert!(emu.flags().f_of, "OF should be set (signed overflow)");
}
#[test]
fn test_sbb_with_borrow_in() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x1c, 0x01, 0xf4]; emu.regs_mut().rax = 0x10;
emu.flags_mut().load(0x2 | flags::F_CF); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x0E, "0x10 - 0x01 - 1 = 0x0E");
assert!(!emu.flags().f_cf, "No borrow out");
}
#[test]
fn test_sbb_borrow_chain() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x1c, 0x00, 0xf4]; emu.regs_mut().rax = 0x00;
emu.flags_mut().load(0x2 | flags::F_CF);
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0xFF, "0x00 - 0x00 - 1 = 0xFF");
assert!(emu.flags().f_cf, "CF should be set (borrow)");
}
#[test]
fn test_sbb_multiprecision_subtraction() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x2d, 0x01, 0x00, 0x00, 0x00, 0x19, 0xca, 0xf4,
];
emu.regs_mut().rax = 0x00000000; emu.regs_mut().rdx = 0x00000001; emu.regs_mut().rcx = 0x00000000; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0xFFFFFFFF, "Low dword underflowed");
assert_eq!(emu.regs().rdx & 0xFFFFFFFF, 0x00000000, "High dword decremented by borrow");
}
#[test]
fn test_inc_basic_8bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xfe, 0xc0, 0xf4]; emu.regs_mut().rax = 0x00;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x01, "0 + 1 = 1");
}
#[test]
fn test_inc_overflow_8bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xfe, 0xc0, 0xf4]; emu.regs_mut().rax = 0xFF;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x00, "0xFF + 1 = 0x00 (wrap)");
assert!(emu.flags().f_zf, "ZF should be set");
}
#[test]
fn test_inc_signed_overflow() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xfe, 0xc0, 0xf4]; emu.regs_mut().rax = 0x7F; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x80, "127 + 1 = -128 (signed overflow)");
assert!(emu.flags().f_of, "OF should be set");
assert!(emu.flags().f_sf, "SF should be set");
}
#[test]
fn test_inc_preserves_cf() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xfe, 0xc0, 0xf4]; emu.regs_mut().rax = 0xFF;
emu.flags_mut().load(0x2 | flags::F_CF); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_cf, "CF should be preserved by INC");
}
#[test]
fn test_dec_basic_8bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xfe, 0xc8, 0xf4]; emu.regs_mut().rax = 0x01;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x00, "1 - 1 = 0");
assert!(emu.flags().f_zf, "ZF should be set");
}
#[test]
fn test_dec_underflow_8bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xfe, 0xc8, 0xf4]; emu.regs_mut().rax = 0x00;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0xFF, "0 - 1 = 0xFF (underflow)");
assert!(emu.flags().f_sf, "SF should be set");
}
#[test]
fn test_dec_signed_overflow() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xfe, 0xc8, 0xf4]; emu.regs_mut().rax = 0x80; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x7F, "-128 - 1 = 127 (signed overflow)");
assert!(emu.flags().f_of, "OF should be set");
assert!(!emu.flags().f_sf, "SF should be clear");
}
#[test]
fn test_inc_32bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xff, 0xc0, 0xf4]; emu.regs_mut().rax = 0xFFFFFFFF;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x00000000, "0xFFFFFFFF + 1 = 0");
assert!(emu.flags().f_zf, "ZF should be set");
}
#[test]
fn test_inc_64bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0xff, 0xc0, 0xf4]; emu.regs_mut().rax = 0xFFFFFFFFFFFFFFFF;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x0000000000000000, "Max u64 + 1 = 0");
assert!(emu.flags().f_zf, "ZF should be set");
}
#[test]
fn test_neg_positive_to_negative() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xd8, 0xf4]; emu.regs_mut().rax = 0x05; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0xFB, "NEG 5 = -5 (0xFB)");
assert!(emu.flags().f_cf, "CF set when operand non-zero");
assert!(emu.flags().f_sf, "SF should be set");
}
#[test]
fn test_neg_negative_to_positive() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xd8, 0xf4]; emu.regs_mut().rax = 0xFB; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x05, "NEG -5 = 5");
assert!(emu.flags().f_cf, "CF set when operand non-zero");
assert!(!emu.flags().f_sf, "SF should be clear");
}
#[test]
fn test_neg_zero() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xd8, 0xf4]; emu.regs_mut().rax = 0x00;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x00, "NEG 0 = 0");
assert!(!emu.flags().f_cf, "CF clear when operand is zero");
assert!(emu.flags().f_zf, "ZF should be set");
}
#[test]
fn test_neg_min_value_overflow() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xd8, 0xf4]; emu.regs_mut().rax = 0x80; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x80, "NEG -128 = -128 (overflow, stays same)");
assert!(emu.flags().f_of, "OF should be set (signed overflow)");
assert!(emu.flags().f_cf, "CF should be set (non-zero operand)");
}
#[test]
fn test_neg_32bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf7, 0xd8, 0xf4]; emu.regs_mut().rax = 0x00000001;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0xFFFFFFFF, "NEG 1 = -1");
}
#[test]
fn test_neg_64bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0xf7, 0xd8, 0xf4]; emu.regs_mut().rax = 0x0000000000000001;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0xFFFFFFFFFFFFFFFF, "NEG 1 = -1");
}
#[test]
fn test_mul_8bit_basic() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xe3, 0xf4]; emu.regs_mut().rax = 0x05; emu.regs_mut().rbx = 0x03; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0x000F, "5 * 3 = 15");
assert!(!emu.flags().f_cf, "CF clear (fits in AL)");
assert!(!emu.flags().f_of, "OF clear");
}
#[test]
fn test_mul_8bit_overflow() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xe3, 0xf4]; emu.regs_mut().rax = 16;
emu.regs_mut().rbx = 16;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0x0100, "16 * 16 = 256");
assert!(emu.flags().f_cf, "CF set (overflow into AH)");
assert!(emu.flags().f_of, "OF set");
}
#[test]
fn test_mul_8bit_max() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xe3, 0xf4]; emu.regs_mut().rax = 0xFF;
emu.regs_mut().rbx = 0xFF;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0xFE01, "255 * 255 = 65025");
assert!(emu.flags().f_cf, "CF set");
}
#[test]
fn test_mul_32bit_basic() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf7, 0xe3, 0xf4]; emu.regs_mut().rax = 0x00001000;
emu.regs_mut().rbx = 0x00001000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x01000000, "Low 32 bits");
assert_eq!(emu.regs().rdx & 0xFFFFFFFF, 0x00000000, "High 32 bits");
assert!(!emu.flags().f_cf, "CF clear (fits in EAX)");
}
#[test]
fn test_mul_32bit_overflow() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf7, 0xe3, 0xf4]; emu.regs_mut().rax = 0x80000000;
emu.regs_mut().rbx = 0x00000002;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x00000000, "Low 32 bits");
assert_eq!(emu.regs().rdx & 0xFFFFFFFF, 0x00000001, "High 32 bits");
assert!(emu.flags().f_cf, "CF set (overflow into EDX)");
}
#[test]
fn test_mul_64bit_basic() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0xf7, 0xe3, 0xf4]; emu.regs_mut().rax = 0x0000000100000000;
emu.regs_mut().rbx = 0x0000000000000002;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x0000000200000000, "Low 64 bits");
assert_eq!(emu.regs().rdx, 0x0000000000000000, "High 64 bits");
assert!(!emu.flags().f_cf, "CF clear");
}
#[test]
fn test_mul_by_zero() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xe3, 0xf4]; emu.regs_mut().rax = 0xFF;
emu.regs_mut().rbx = 0x00;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0x0000, "Anything * 0 = 0");
assert!(!emu.flags().f_cf, "CF clear (no overflow)");
}
#[test]
fn test_mul_by_one() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xe3, 0xf4]; emu.regs_mut().rax = 0xAB;
emu.regs_mut().rbx = 0x01;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0x00AB, "Anything * 1 = itself");
assert!(!emu.flags().f_cf, "CF clear");
}
#[test]
fn test_div_8bit_basic() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xf3, 0xf4]; emu.regs_mut().rax = 0x0011; emu.regs_mut().rbx = 0x05; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x03, "17 / 5 = 3 (quotient in AL)");
assert_eq!((emu.regs().rax >> 8) & 0xFF, 0x02, "17 % 5 = 2 (remainder in AH)");
}
#[test]
fn test_div_8bit_exact() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xf3, 0xf4]; emu.regs_mut().rax = 0x000F; emu.regs_mut().rbx = 0x05; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x03, "15 / 5 = 3");
assert_eq!((emu.regs().rax >> 8) & 0xFF, 0x00, "15 % 5 = 0");
}
#[test]
fn test_div_32bit_basic() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf7, 0xf3, 0xf4]; emu.regs_mut().rax = 0x00000064; emu.regs_mut().rdx = 0x00000000; emu.regs_mut().rbx = 0x00000007; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x0000000E, "100 / 7 = 14");
assert_eq!(emu.regs().rdx & 0xFFFFFFFF, 0x00000002, "100 % 7 = 2");
}
#[test]
fn test_div_64bit_basic() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0xf7, 0xf3, 0xf4]; emu.regs_mut().rax = 0x0000000000000064; emu.regs_mut().rdx = 0x0000000000000000;
emu.regs_mut().rbx = 0x0000000000000007; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x000000000000000E, "100 / 7 = 14");
assert_eq!(emu.regs().rdx, 0x0000000000000002, "100 % 7 = 2");
}
#[test]
fn test_div_by_one() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xf3, 0xf4]; emu.regs_mut().rax = 0x00FF; emu.regs_mut().rbx = 0x01; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0xFF, "255 / 1 = 255");
assert_eq!((emu.regs().rax >> 8) & 0xFF, 0x00, "255 % 1 = 0");
}
#[test]
fn test_div_large_dividend() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xf3, 0xf4]; emu.regs_mut().rax = 0x0100; emu.regs_mut().rbx = 0x02; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x80, "256 / 2 = 128");
assert_eq!((emu.regs().rax >> 8) & 0xFF, 0x00, "256 % 2 = 0");
}
#[test]
fn test_idiv_positive_by_positive() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xfb, 0xf4]; emu.regs_mut().rax = 0x0011; emu.regs_mut().rbx = 0x05; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x03, "17 / 5 = 3");
assert_eq!((emu.regs().rax >> 8) & 0xFF, 0x02, "17 % 5 = 2");
}
#[test]
fn test_idiv_negative_by_positive() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xfb, 0xf4]; emu.regs_mut().rax = 0xFFEF; emu.regs_mut().rbx = 0x05; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0xFD, "-17 / 5 = -3 (0xFD)");
assert_eq!((emu.regs().rax >> 8) & 0xFF, 0xFE, "-17 % 5 = -2 (0xFE)");
}
#[test]
fn test_idiv_positive_by_negative() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xfb, 0xf4]; emu.regs_mut().rax = 0x0011; emu.regs_mut().rbx = 0xFB; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0xFD, "17 / -5 = -3 (0xFD)");
assert_eq!((emu.regs().rax >> 8) & 0xFF, 0x02, "17 % -5 = 2");
}
#[test]
fn test_idiv_negative_by_negative() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf6, 0xfb, 0xf4]; emu.regs_mut().rax = 0xFFEF; emu.regs_mut().rbx = 0xFB; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x03, "-17 / -5 = 3");
assert_eq!((emu.regs().rax >> 8) & 0xFF, 0xFE, "-17 % -5 = -2 (0xFE)");
}
#[test]
fn test_idiv_32bit_signed() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0xf7, 0xfb, 0xf4]; emu.regs_mut().rax = 0xFFFFFF9C; emu.regs_mut().rdx = 0xFFFFFFFF; emu.regs_mut().rbx = 0x00000007; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0xFFFFFFF2, "-100 / 7 = -14 (0xFFFFFFF2)");
assert_eq!(emu.regs().rdx & 0xFFFFFFFF, 0xFFFFFFFE, "-100 % 7 = -2 (0xFFFFFFFE)");
}
#[test]
fn test_cbw_positive() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x66, 0x98, 0xf4]; emu.regs_mut().rax = 0x7F; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0x007F, "127 sign-extended to word");
}
#[test]
fn test_cbw_negative() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x66, 0x98, 0xf4]; emu.regs_mut().rax = 0x80; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0xFF80, "-128 sign-extended to word");
}
#[test]
fn test_cwde_positive() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x98, 0xf4]; emu.regs_mut().rax = 0x7FFF; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x00007FFF, "32767 sign-extended");
}
#[test]
fn test_cwde_negative() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x98, 0xf4]; emu.regs_mut().rax = 0x8000; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0xFFFF8000, "-32768 sign-extended");
}
#[test]
fn test_cdqe_positive() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x98, 0xf4]; emu.regs_mut().rax = 0x7FFFFFFF; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x000000007FFFFFFF, "Max i32 sign-extended");
}
#[test]
fn test_cdqe_negative() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x98, 0xf4]; emu.regs_mut().rax = 0x80000000; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0xFFFFFFFF80000000, "Min i32 sign-extended");
}
#[test]
fn test_cwd_positive() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x66, 0x99, 0xf4]; emu.regs_mut().rax = 0x7FFF; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rdx & 0xFFFF, 0x0000, "DX = 0 for positive");
}
#[test]
fn test_cwd_negative() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x66, 0x99, 0xf4]; emu.regs_mut().rax = 0x8000; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rdx & 0xFFFF, 0xFFFF, "DX = 0xFFFF for negative");
}
#[test]
fn test_cdq_positive() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x99, 0xf4]; emu.regs_mut().rax = 0x7FFFFFFF;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rdx & 0xFFFFFFFF, 0x00000000, "EDX = 0 for positive");
}
#[test]
fn test_cdq_negative() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x99, 0xf4]; emu.regs_mut().rax = 0x80000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rdx & 0xFFFFFFFF, 0xFFFFFFFF, "EDX = 0xFFFFFFFF for negative");
}
#[test]
fn test_cqo_positive() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x99, 0xf4]; emu.regs_mut().rax = 0x7FFFFFFFFFFFFFFF;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rdx, 0x0000000000000000, "RDX = 0 for positive");
}
#[test]
fn test_cqo_negative() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x99, 0xf4]; emu.regs_mut().rax = 0x8000000000000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rdx, 0xFFFFFFFFFFFFFFFF, "RDX = -1 for negative");
}
#[test]
fn test_adcx_basic() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x66, 0x0f, 0x38, 0xf6, 0xc3, 0xf4,
];
emu.regs_mut().rax = 0x00000001;
emu.regs_mut().rbx = 0x00000002;
emu.flags_mut().load(0x2 | flags::F_CF); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x00000004, "1 + 2 + 1(CF) = 4");
}
#[test]
fn test_adcx_ignores_of() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x66, 0x0f, 0x38, 0xf6, 0xc3, 0xf4,
];
emu.regs_mut().rax = 0x00000001;
emu.regs_mut().rbx = 0x00000002;
emu.flags_mut().load(0x2 | flags::F_OF); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x00000003, "1 + 2 + 0 = 3 (OF ignored)");
}
#[test]
fn test_adox_basic() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0xf3, 0x0f, 0x38, 0xf6, 0xc3, 0xf4,
];
emu.regs_mut().rax = 0x00000001;
emu.regs_mut().rbx = 0x00000002;
emu.flags_mut().load(0x2 | flags::F_OF); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x00000004, "1 + 2 + 1(OF) = 4");
}
#[test]
fn test_adox_ignores_cf() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0xf3, 0x0f, 0x38, 0xf6, 0xc3, 0xf4,
];
emu.regs_mut().rax = 0x00000001;
emu.regs_mut().rbx = 0x00000002;
emu.flags_mut().load(0x2 | flags::F_CF); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x00000003, "1 + 2 + 0 = 3 (CF ignored)");
}
#[test]
fn test_adcx_adox_parallel() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x66, 0x0f, 0x38, 0xf6, 0xc3, 0xf3, 0x0f, 0x38, 0xf6, 0xca, 0xf4,
];
emu.regs_mut().rax = 0x00000001;
emu.regs_mut().rbx = 0x00000001;
emu.regs_mut().rcx = 0x00000002;
emu.regs_mut().rdx = 0x00000002;
emu.flags_mut().load(0x2 | flags::F_CF | flags::F_OF); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFFFFFF, 0x00000003, "ADCX: 1 + 1 + 1 = 3");
assert_eq!(emu.regs().rcx & 0xFFFFFFFF, 0x00000005, "ADOX: 2 + 2 + 1 = 5");
}
#[test]
fn test_multiprecision_addition_128bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0x01, 0xd8, 0x48, 0x11, 0xca, 0xf4,
];
emu.regs_mut().rax = 0xFFFFFFFFFFFFFFFF; emu.regs_mut().rdx = 0x0000000000000001; emu.regs_mut().rbx = 0x0000000000000001; emu.regs_mut().rcx = 0x0000000000000000; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x0000000000000000, "Low 64 bits");
assert_eq!(emu.regs().rdx, 0x0000000000000002, "High 64 bits");
}
#[test]
fn test_multiprecision_subtraction_128bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0x29, 0xd8, 0x48, 0x19, 0xca, 0xf4,
];
emu.regs_mut().rax = 0x0000000000000000;
emu.regs_mut().rdx = 0x0000000000000001;
emu.regs_mut().rbx = 0x0000000000000001;
emu.regs_mut().rcx = 0x0000000000000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0xFFFFFFFFFFFFFFFF, "Low 64 bits");
assert_eq!(emu.regs().rdx, 0x0000000000000000, "High 64 bits");
}
#[test]
fn test_increment_loop_pattern() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0xff, 0xc0, 0x48, 0x83, 0xf8, 0x05, 0x75, 0xf7, 0xf4,
];
emu.regs_mut().rax = 0;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 5, "Should have incremented to 5");
}
#[test]
fn test_decrement_loop_pattern() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0xff, 0xc8, 0x75, 0xfb, 0xf4,
];
emu.regs_mut().rax = 5;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0, "Should have decremented to 0");
}
#[test]
fn test_add_r8_r9() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x4d, 0x01, 0xc8, 0xf4,
];
emu.regs_mut().r8 = 0x1111111111111111;
emu.regs_mut().r9 = 0x2222222222222222;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().r8, 0x3333333333333333, "R8 + R9");
assert_eq!(emu.regs().r9, 0x2222222222222222, "R9 unchanged");
}
#[test]
fn test_sub_r10_r11() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x4d, 0x29, 0xda, 0xf4,
];
emu.regs_mut().r10 = 0x5555555555555555;
emu.regs_mut().r11 = 0x1111111111111111;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().r10, 0x4444444444444444, "R10 - R11");
}
#[test]
fn test_inc_r15() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x49, 0xff, 0xc7, 0xf4,
];
emu.regs_mut().r15 = 0xFFFFFFFFFFFFFFFE;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().r15, 0xFFFFFFFFFFFFFFFF, "R15 incremented");
}
#[test]
fn test_neg_r12() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x49, 0xf7, 0xdc, 0xf4,
];
emu.regs_mut().r12 = 0x0000000000000005;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().r12, 0xFFFFFFFFFFFFFFFB, "NEG 5 = -5");
}