use crate::*;
#[test]
fn test_cmp_al_imm8_equal() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3c, 0x0a, 0xf4];
emu.regs_mut().rax = 10;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 10, "CMP should not modify operands");
assert!(emu.flags().f_zf, "ZF should be set (equal)");
assert!(!emu.flags().f_cf, "CF should be clear (no borrow)");
}
#[test]
fn test_cmp_al_imm8_greater() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3c, 0x05, 0xf4];
emu.regs_mut().rax = 10;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(!emu.flags().f_zf, "ZF should be clear (not equal)");
assert!(!emu.flags().f_cf, "CF should be clear (no borrow, first >= second)");
assert!(!emu.flags().f_sf, "SF should be clear (positive result)");
}
#[test]
fn test_cmp_al_imm8_less() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3c, 0x0f, 0xf4];
emu.regs_mut().rax = 10;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(!emu.flags().f_zf, "ZF should be clear (not equal)");
assert!(emu.flags().f_cf, "CF should be set (borrow, first < second)");
assert!(emu.flags().f_sf, "SF should be set (negative result)");
}
#[test]
fn test_cmp_al_imm8_signed_overflow() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3c, 0x01, 0xf4];
emu.regs_mut().rax = 0x80;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_of, "OF should be set (signed overflow)");
}
#[test]
fn test_cmp_al_imm8_preserves_register() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3c, 0x42, 0xf4];
emu.regs_mut().rax = 0xDEADBEEF_12345678;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0xDEADBEEF_12345678, "CMP should not modify RAX");
}
#[test]
fn test_cmp_ax_imm16_equal() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x66, 0x3d, 0x34, 0x12, 0xf4];
emu.regs_mut().rax = 0x1234;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_zf, "ZF should be set (equal)");
}
#[test]
fn test_cmp_eax_imm32_greater() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3d, 0x78, 0x56, 0x34, 0x12, 0xf4];
emu.regs_mut().rax = 0x23456789;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(!emu.flags().f_zf, "ZF should be clear (not equal)");
assert!(!emu.flags().f_cf, "CF should be clear (first > second)");
}
#[test]
fn test_cmp_rax_imm32_sign_extended() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xf4];
emu.regs_mut().rax = 0xFFFFFFFFFFFFFFFF;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_zf, "ZF should be set (equal to -1)");
}
#[test]
fn test_cmp_rm8_imm8_register() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x80, 0xf9, 0x0a, 0xf4];
emu.regs_mut().rcx = 10;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rcx, 10, "CMP should not modify CL");
assert!(emu.flags().f_zf, "ZF should be set");
}
#[test]
fn test_cmp_rm8_imm8_memory() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x80, 0x3b, 0x19, 0xf4];
emu.regs_mut().rbx = DATA_ADDR;
emu.load_code_bytes(&code);
emu.maps.write_byte(DATA_ADDR, 25);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_byte(DATA_ADDR).unwrap(), 25, "CMP should not modify memory");
}
#[test]
fn test_cmp_rm32_imm32_register() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x81, 0xf9, 0x78, 0x56, 0x34, 0x12, 0xf4];
emu.regs_mut().rcx = 0x12345678;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_zf, "ZF should be set (equal)");
}
#[test]
fn test_cmp_rm64_imm32_register() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x81, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xf4];
emu.regs_mut().rcx = 0xFFFFFFFFFFFFFFFF;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_zf, "ZF should be set");
}
#[test]
fn test_cmp_rm32_imm8_positive() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x83, 0xf9, 0x0a, 0xf4];
emu.regs_mut().rcx = 100;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(!emu.flags().f_cf, "CF should be clear (100 > 10)");
}
#[test]
fn test_cmp_rm32_imm8_negative() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x83, 0xf9, 0xf6, 0xf4];
emu.regs_mut().rcx = 100;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_cf, "CF should be set (100 < 0xFFFFFFF6 unsigned)");
}
#[test]
fn test_cmp_rm8_r8_register_equal() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x38, 0xc8, 0xf4];
emu.regs_mut().rax = 10;
emu.regs_mut().rcx = 10;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 10, "AL should not change");
assert_eq!(emu.regs().rcx, 10, "CL should not change");
assert!(emu.flags().f_zf, "ZF should be set (equal)");
}
#[test]
fn test_cmp_rm8_r8_register_greater() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x38, 0xc8, 0xf4];
emu.regs_mut().rax = 15;
emu.regs_mut().rcx = 10;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(!emu.flags().f_cf, "CF should be clear (AL > CL)");
assert!(!emu.flags().f_sf, "SF should be clear");
}
#[test]
fn test_cmp_rm8_r8_memory() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x38, 0x0b, 0xf4];
emu.regs_mut().rbx = DATA_ADDR;
emu.regs_mut().rcx = 30;
emu.load_code_bytes(&code);
emu.maps.write_byte(DATA_ADDR, 30);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_byte(DATA_ADDR).unwrap(), 30, "Memory should not change");
}
#[test]
fn test_cmp_rm32_r32_register() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x39, 0xc8, 0xf4];
emu.regs_mut().rax = 0x12345678;
emu.regs_mut().rcx = 0x12345678;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_zf, "ZF should be set (equal)");
}
#[test]
fn test_cmp_rm64_r64_register() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x39, 0xc8, 0xf4];
emu.regs_mut().rax = 0xFFFFFFFF_00000000;
emu.regs_mut().rcx = 0x00000000_FFFFFFFF;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(!emu.flags().f_cf, "CF should be clear (RAX > RCX unsigned)");
}
#[test]
fn test_cmp_r8_rm8_register() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3a, 0xc8, 0xf4];
emu.regs_mut().rax = 10;
emu.regs_mut().rcx = 10;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_zf, "ZF should be set (equal)");
}
#[test]
fn test_cmp_r8_rm8_memory() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3a, 0x0b, 0xf4];
emu.regs_mut().rbx = DATA_ADDR;
emu.regs_mut().rcx = 50;
emu.load_code_bytes(&code);
emu.maps.write_byte(DATA_ADDR, 30);
emu.run(None).unwrap();
assert!(!emu.flags().f_cf, "CF should be clear (50 > 30)");
}
#[test]
fn test_cmp_r32_rm32_register() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3b, 0xc8, 0xf4];
emu.regs_mut().rax = 0x11111111;
emu.regs_mut().rcx = 0x22222222;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(!emu.flags().f_cf, "CF should be clear (ECX > EAX)");
}
#[test]
fn test_cmp_r64_rm64_register() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x3b, 0xc8, 0xf4];
emu.regs_mut().rax = 0xFFFFFFFFFFFFFFFF;
emu.regs_mut().rcx = 0x1111111111111111;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_cf, "CF should be set (RCX < RAX)");
}
#[test]
fn test_cmp_for_je_condition() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3d, 0x2a, 0x00, 0x00, 0x00, 0xf4];
emu.regs_mut().rax = 42;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_zf, "ZF=1 for JE condition");
}
#[test]
fn test_cmp_for_jne_condition() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3d, 0x2a, 0x00, 0x00, 0x00, 0xf4];
emu.regs_mut().rax = 50;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(!emu.flags().f_zf, "ZF=0 for JNE condition");
}
#[test]
fn test_cmp_for_jb_condition() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3d, 0x64, 0x00, 0x00, 0x00, 0xf4];
emu.regs_mut().rax = 50;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_cf, "CF=1 for JB condition (50 < 100)");
}
#[test]
fn test_cmp_for_jae_condition() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3d, 0x32, 0x00, 0x00, 0x00, 0xf4];
emu.regs_mut().rax = 100;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(!emu.flags().f_cf, "CF=0 for JAE condition (100 >= 50)");
}
#[test]
fn test_cmp_for_jl_condition() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3d, 0x00, 0x00, 0x00, 0x00, 0xf4];
emu.regs_mut().rax = 0xFFFFFFF6; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_sf, "SF=1");
assert!(!emu.flags().f_of, "OF=0");
}
#[test]
fn test_cmp_for_jg_condition() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3d, 0x00, 0x00, 0x00, 0x00, 0xf4];
emu.regs_mut().rax = 10;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(!emu.flags().f_zf, "ZF=0 (not equal)");
assert!(!emu.flags().f_sf, "SF=0 (positive result)");
assert!(!emu.flags().f_of, "OF=0 (no overflow)");
}
#[test]
fn test_cmp_zero_with_zero() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3d, 0x00, 0x00, 0x00, 0x00, 0xf4];
emu.regs_mut().rax = 0;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_zf, "ZF should be set");
assert!(!emu.flags().f_cf, "CF should be clear");
assert!(!emu.flags().f_sf, "SF should be clear");
assert!(!emu.flags().f_of, "OF should be clear");
}
#[test]
fn test_cmp_max_with_max() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3d, 0xff, 0xff, 0xff, 0xff, 0xf4];
emu.regs_mut().rax = 0xFFFFFFFF;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_zf, "ZF should be set (equal)");
}
#[test]
fn test_cmp_parity_flag() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3c, 0x03, 0xf4];
emu.regs_mut().rax = 0x0F;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_pf, "PF should be set (even parity)");
}
#[test]
fn test_cmp_auxiliary_flag() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x3c, 0x01, 0xf4];
emu.regs_mut().rax = 0x10;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!(emu.flags().f_af, "AF should be set (borrow from bit 4)");
}
#[test]
fn test_cmp_r8_extended() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x41, 0x83, 0xf8, 0x64, 0xf4];
emu.regs_mut().r8 = 150;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().r8, 150, "R8 should not change");
assert!(!emu.flags().f_cf, "CF should be clear (150 > 100)");
}
#[test]
fn test_cmp_r15_extended() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x49, 0x39, 0xc7, 0xf4];
emu.regs_mut().rax = 0x1000;
emu.regs_mut().r15 = 0x1000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().r15, 0x1000, "R15 should not change");
assert!(emu.flags().f_zf, "ZF should be set (equal)");
}