use crate::*;
#[test]
fn test_adc_al_imm8_no_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x14, 0x05, 0xf4, ];
emu.regs_mut().rax = 0x0A;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x0F, "AL should be 15 (10 + 5)");
assert!(!emu.flags().f_cf, "CF should be clear");
}
#[test]
fn test_adc_al_imm8_with_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0x05, 0xf4]; emu.regs_mut().rax = 0x0A;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x10, "AL should be 16 (10 + 5 + 1)");
assert!(!emu.flags().f_cf, "CF should be clear");
}
#[test]
fn test_adc_al_overflow() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0xFF, 0xf4]; emu.regs_mut().rax = 0x02;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x02, "AL should wrap to 0x02");
assert!(emu.flags().f_cf, "CF should be set (overflow)");
}
#[test]
fn test_adc_r8_r8_no_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x10, 0xd8, 0xf4, ];
emu.regs_mut().rax = 0x20;
emu.regs_mut().rbx = 0x15;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x35, "AL should be 0x35 (32 + 21)");
}
#[test]
fn test_adc_r8_r8_with_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x10, 0xc8, 0xf4]; emu.regs_mut().rax = 0x7F;
emu.regs_mut().rcx = 0x01;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(
emu.regs().rax & 0xFF,
0x81,
"AL should be 0x81 (127 + 1 + 1)"
);
assert!(emu.flags().f_sf, "SF should be set");
assert!(emu.flags().f_of, "OF should be set (signed overflow)");
}
#[test]
fn test_adc_all_8bit_registers() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let test_cases = vec![
(0xd8, "AL"), (0xc8, "AL"), (0xd0, "AL"), ];
for (modrm, _name) in test_cases {
let code = [0x10, modrm, 0xf4]; emu.regs_mut().rax = 0x10;
emu.regs_mut().rbx = 0x05;
emu.regs_mut().rcx = 0x06;
emu.regs_mut().rdx = 0x07;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert!((emu.regs().rax & 0xFF) > 0x10, "ADC should add carry");
}
}
#[test]
fn test_adc_extended_r8_registers() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x45, 0x10, 0xc8, 0xf4, ];
emu.regs_mut().r8 = 0x40;
emu.regs_mut().r9 = 0x30;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(
emu.regs().r8 & 0xFF,
0x71,
"R8B should be 0x71 (64 + 48 + 1)"
);
}
#[test]
fn test_adc_ax_imm16_no_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x66, 0x15, 0x34, 0x12, 0xf4, ];
emu.regs_mut().rax = 0x5678;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0x68AC, "AX should be 0x68AC");
assert!(!emu.flags().f_cf, "CF should be clear");
}
#[test]
fn test_adc_ax_imm16_with_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x66, 0x15, 0xFF, 0xFF, 0xf4]; emu.regs_mut().rax = 0x0002;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0x0002, "AX should wrap to 0x0002");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_adc_r16_r16() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x66, 0x11, 0xd8, 0xf4, ];
emu.regs_mut().rax = 0x1000;
emu.regs_mut().rbx = 0x2000;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0x3001, "AX should be 0x3001");
}
#[test]
fn test_adc_r16_imm8_sign_extended() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x66, 0x83, 0xd0, 0xFF, 0xf4, ];
emu.regs_mut().rax = 0x1000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFFFF, 0x0FFF, "AX should be 0x0FFF");
}
#[test]
fn test_adc_extended_r16_registers() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x66, 0x45, 0x11, 0xda, 0xf4, ];
emu.regs_mut().r10 = 0x8000;
emu.regs_mut().r11 = 0x7FFF;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().r10 & 0xFFFF, 0x0000, "R10W should wrap to 0");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_adc_eax_imm32_no_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x15, 0x78, 0x56, 0x34, 0x12, 0xf4, ];
emu.regs_mut().rax = 0x11111111;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x23456789, "EAX should be 0x23456789");
assert!(!emu.flags().f_cf, "CF should be clear");
}
#[test]
fn test_adc_eax_imm32_with_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0xf4]; emu.regs_mut().rax = 0x00000001;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x00000001, "EAX should wrap to 0x00000001");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_adc_r32_r32() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x11, 0xd8, 0xf4, ];
emu.regs_mut().rax = 0x80000000;
emu.regs_mut().rbx = 0x7FFFFFFF;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x00000000, "EAX should wrap to 0");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_adc_r32_imm8_sign_extended() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x83, 0xd0, 0xFF, 0xf4, ];
emu.regs_mut().rax = 0x10000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x0FFFFFFF, "EAX should be 0x0FFFFFFF");
}
#[test]
fn test_adc_extended_r32_registers() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x45, 0x11, 0xec, 0xf4, ];
emu.regs_mut().r12 = 0xFFFFFFFF;
emu.regs_mut().r13 = 0x00000001;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().r12, 0x00000001, "R12D should wrap to 1");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_adc_rax_imm32_no_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0x15, 0x78, 0x56, 0x34, 0x12, 0xf4, ];
emu.regs_mut().rax = 0x1111111111111111;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x1111111123456789, "RAX should be correct");
assert!(!emu.flags().f_cf, "CF should be clear");
}
#[test]
fn test_adc_rax_imm32_with_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x15, 0xFF, 0xFF, 0xFF, 0x7F, 0xf4]; emu.regs_mut().rax = 0x0000000000000001;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(
emu.regs().rax,
0x0000000080000001,
"RAX should be 0x80000001"
);
}
#[test]
fn test_adc_r64_r64() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0x11, 0xd8, 0xf4, ];
emu.regs_mut().rax = 0xFFFFFFFFFFFFFFFF;
emu.regs_mut().rbx = 0x0000000000000001;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0x0000000000000001, "RAX should wrap to 1");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_adc_r64_imm8_sign_extended() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0x83, 0xd0, 0xFF, 0xf4, ];
emu.regs_mut().rax = 0x1000000000000000;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(
emu.regs().rax,
0x0FFFFFFFFFFFFFFF,
"RAX should be decremented"
);
}
#[test]
fn test_adc_extended_r64_registers() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x4d, 0x11, 0xfe, 0xf4, ];
emu.regs_mut().r14 = 0x8000000000000000;
emu.regs_mut().r15 = 0x7FFFFFFFFFFFFFFF;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().r14, 0x0000000000000000, "R14 should wrap to 0");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_adc_byte_ptr_imm8() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x80, 0x15, 0xF9, 0x0F, 0x00, 0x00, 0x10, 0xf4, ];
emu.load_code_bytes(&code);
emu.maps.write_byte(DATA_ADDR, 0x20);
emu.flags_mut().f_cf = true;
emu.run(None).unwrap();
let result = emu.maps.read_byte(DATA_ADDR).unwrap();
assert_eq!(result, 0x31, "Memory should be 0x31 (32 + 16 + 1)");
assert!(!emu.flags().f_cf, "CF should be clear");
}
#[test]
fn test_adc_word_ptr_imm16() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x66, 0x81, 0x15, 0xF7, 0x0F, 0x00, 0x00, 0x00,
0x10, 0xf4, ];
emu.load_code_bytes(&code);
emu.maps.write_word(DATA_ADDR, 0x2000);
emu.flags_mut().f_cf = true;
emu.run(None).unwrap();
let result = emu.maps.read_word(DATA_ADDR).unwrap();
assert_eq!(result, 0x3001, "Memory should be 0x3001");
}
#[test]
fn test_adc_dword_ptr_r32() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x11, 0x1d, 0xFA, 0x0F, 0x00,
0x00, 0xf4, ];
emu.regs_mut().rbx = 0x30000000;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.maps.write_dword(DATA_ADDR, 0x40000000);
emu.run(None).unwrap();
let result = emu.maps.read_dword(DATA_ADDR).unwrap();
assert_eq!(result, 0x70000001, "Memory should be 0x70000001");
}
#[test]
fn test_adc_qword_ptr_r64() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0x11, 0x1d, 0xF9, 0x0F, 0x00,
0x00, 0xf4, ];
emu.load_code_bytes(&code);
emu.maps.write_qword(DATA_ADDR, 0x1000000000000000);
emu.regs_mut().rbx = 0x2000000000000000;
emu.flags_mut().f_cf = true;
emu.run(None).unwrap();
let result = emu.maps.read_qword(DATA_ADDR).unwrap();
assert_eq!(result, 0x3000000000000001, "Memory should include carry");
}
#[test]
fn test_adc_r64_from_memory() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0x13, 0x05, 0xF9, 0x0F, 0x00, 0x00, 0xf4, ];
emu.load_code_bytes(&code);
emu.maps.write_qword(DATA_ADDR, 0x0FFFFFFFFFFFFFFF);
emu.regs_mut().rax = 0x1000000000000000;
emu.flags_mut().f_cf = true;
emu.run(None).unwrap();
assert_eq!(
emu.regs().rax,
0x2000000000000000,
"RAX should be correct sum"
);
}
#[test]
fn test_adc_zero_flag() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0xFF, 0xf4]; emu.regs_mut().rax = 0x00;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x00, "AL should be 0");
assert!(emu.flags().f_zf, "ZF should be set");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_adc_sign_flag() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0x7F, 0xf4]; emu.regs_mut().rax = 0x01;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x80, "AL should be 0x80");
assert!(emu.flags().f_sf, "SF should be set");
}
#[test]
fn test_adc_overflow_flag() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0x01, 0xf4]; emu.regs_mut().rax = 0x7F; emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x81, "AL should be 0x81");
assert!(emu.flags().f_of, "OF should be set");
assert!(emu.flags().f_sf, "SF should be set");
}
#[test]
fn test_adc_parity_flag() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0x02, 0xf4]; emu.regs_mut().rax = 0x01;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x03, "AL should be 3");
assert!(emu.flags().f_pf, "PF should be set (even parity)");
}
#[test]
fn test_adc_auxiliary_carry_flag() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0x0A, 0xf4]; emu.regs_mut().rax = 0x08;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x12, "AL should be 0x12");
assert!(emu.flags().f_af, "AF should be set");
}
#[test]
fn test_adc_chain_64bit_addition() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [
0x48, 0x01, 0xd8, 0x49, 0x11, 0xc8, 0xf4, ];
emu.regs_mut().rax = 0xFFFFFFFFFFFFFFFF; emu.regs_mut().r8 = 0x0000000000000001; emu.regs_mut().rbx = 0x0000000000000002; emu.regs_mut().rcx = 0x0000000000000000; emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(
emu.regs().rax,
0x0000000000000001,
"Low 64 bits should be 1"
);
assert_eq!(
emu.regs().r8,
0x0000000000000002,
"High 64 bits should be 2 (with carry)"
);
}
#[test]
fn test_adc_preserves_high_bits_8bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0x05, 0xf4]; emu.regs_mut().rax = 0xDEADBEEF12345678;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(
emu.regs().rax >> 8,
0xDEADBEEF123456,
"High bits should be preserved"
);
}
#[test]
fn test_adc_preserves_high_bits_16bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x66, 0x15, 0x00, 0x10, 0xf4]; emu.regs_mut().rax = 0xDEADBEEF12345678;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(
emu.regs().rax >> 16,
0xDEADBEEF1234,
"High bits should be preserved"
);
}
#[test]
fn test_adc_preserves_high_bits_32bit() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x15, 0x00, 0x00, 0x00, 0x10, 0xf4]; emu.regs_mut().rax = 0xDEADBEEF12345678;
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(
emu.regs().rax >> 32,
0,
"High 32 bits should be zeroed for 32-bit op"
);
}
#[test]
fn test_adc_all_ones() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x48, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0xf4]; emu.regs_mut().rax = 0xFFFFFFFFFFFFFFFF;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax, 0xFFFFFFFFFFFFFFFF, "RAX should be all ones");
assert!(emu.flags().f_cf, "CF should be set");
}
#[test]
fn test_adc_zero_plus_zero_plus_carry() {
let DATA_ADDR = 0x7000;
let mut emu = emu64();
let code = [0x14, 0x00, 0xf4]; emu.regs_mut().rax = 0x00;
emu.flags_mut().load(0x01); emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.regs().rax & 0xFF, 0x01, "AL should be 1");
assert!(!emu.flags().f_zf, "ZF should be clear");
}