use crate::exec::compute::amo::atomic_alu;
use crate::isa::op::{AtomicOp, MemWidth};
const I64_MAX: u64 = i64::MAX as u64; const I64_MIN: u64 = i64::MIN as u64; const U64_MAX: u64 = u64::MAX;
const I32_MAX: u64 = i32::MAX as u64; const U32_MAX: u64 = u32::MAX as u64; const I32_MIN_ZEXT: u64 = 0x8000_0000u64;
fn sext32(val: u32) -> u64 {
val as i32 as i64 as u64
}
#[test]
fn swap_word_returns_reg_val_sign_extended() {
assert_eq!(atomic_alu(AtomicOp::Swap, 0xDEAD, 42, MemWidth::Word), sext32(42));
assert_eq!(atomic_alu(AtomicOp::Swap, 0, 0x8000_0000, MemWidth::Word), sext32(0x8000_0000u32));
}
#[test]
fn swap_double_returns_reg_val() {
assert_eq!(
atomic_alu(AtomicOp::Swap, 0xDEAD, 0x1234_5678_9ABC_DEF0, MemWidth::Double),
0x1234_5678_9ABC_DEF0
);
}
#[test]
fn add_word_basic() {
assert_eq!(atomic_alu(AtomicOp::Add, 10, 20, MemWidth::Word), sext32(30));
}
#[test]
fn add_word_wrapping_overflow() {
let result = atomic_alu(AtomicOp::Add, I32_MAX, 1, MemWidth::Word);
assert_eq!(result, sext32(0x8000_0000u32));
assert_ne!(result & (1 << 63), 0);
}
#[test]
fn add_word_wrapping_underflow() {
let result = atomic_alu(AtomicOp::Add, I32_MIN_ZEXT, U32_MAX, MemWidth::Word);
assert_eq!(result, sext32(0x7FFF_FFFFu32));
}
#[test]
fn add_word_zero() {
assert_eq!(atomic_alu(AtomicOp::Add, 42, 0, MemWidth::Word), sext32(42));
}
#[test]
fn add_double_basic() {
assert_eq!(atomic_alu(AtomicOp::Add, 100, 200, MemWidth::Double), 300);
}
#[test]
fn add_double_wrapping_overflow() {
let result = atomic_alu(AtomicOp::Add, I64_MAX, 1, MemWidth::Double);
assert_eq!(result, I64_MIN); }
#[test]
fn add_double_neg1() {
assert_eq!(atomic_alu(AtomicOp::Add, 1, U64_MAX, MemWidth::Double), 0);
}
#[test]
fn xor_word() {
assert_eq!(
atomic_alu(AtomicOp::Xor, 0xFF00_FF00, 0x0F0F_0F0F, MemWidth::Word),
sext32(0xF00F_F00Fu32)
);
}
#[test]
fn xor_double() {
assert_eq!(
atomic_alu(AtomicOp::Xor, 0xAAAA_AAAA_AAAA_AAAA, 0x5555_5555_5555_5555, MemWidth::Double),
U64_MAX
);
}
#[test]
fn xor_self_is_zero() {
assert_eq!(atomic_alu(AtomicOp::Xor, 0x1234_5678, 0x1234_5678, MemWidth::Word), sext32(0));
}
#[test]
fn and_word() {
assert_eq!(
atomic_alu(AtomicOp::And, 0xFF00_FF00, 0x0F0F_0F0F, MemWidth::Word),
sext32(0x0F00_0F00u32)
);
}
#[test]
fn and_double() {
assert_eq!(
atomic_alu(AtomicOp::And, U64_MAX, 0x0000_FFFF_0000_FFFF, MemWidth::Double),
0x0000_FFFF_0000_FFFF
);
}
#[test]
fn and_with_zero() {
assert_eq!(atomic_alu(AtomicOp::And, U64_MAX, 0, MemWidth::Double), 0);
}
#[test]
fn or_word() {
assert_eq!(
atomic_alu(AtomicOp::Or, 0xF000_0000, 0x000F_0000, MemWidth::Word),
sext32(0xF00F_0000u32)
);
}
#[test]
fn or_double() {
assert_eq!(
atomic_alu(AtomicOp::Or, 0xAAAA_0000_0000_0000, 0x0000_0000_0000_5555, MemWidth::Double),
0xAAAA_0000_0000_5555
);
}
#[test]
fn or_with_zero() {
assert_eq!(atomic_alu(AtomicOp::Or, 42, 0, MemWidth::Double), 42);
}
#[test]
fn min_word_positive() {
assert_eq!(atomic_alu(AtomicOp::Min, 10, 20, MemWidth::Word), sext32(10));
}
#[test]
fn min_word_negative_values() {
let neg1 = (-1i32 as u32) as u64;
let neg2 = (-2i32 as u32) as u64;
assert_eq!(atomic_alu(AtomicOp::Min, neg1, neg2, MemWidth::Word), sext32(-2i32 as u32));
}
#[test]
fn min_word_mixed_sign() {
let neg1 = (-1i32 as u32) as u64;
assert_eq!(atomic_alu(AtomicOp::Min, 1, neg1, MemWidth::Word), sext32(-1i32 as u32));
}
#[test]
fn min_double_negative() {
let neg1 = (-1i64) as u64;
let neg100 = (-100i64) as u64;
assert_eq!(atomic_alu(AtomicOp::Min, neg1, neg100, MemWidth::Double), neg100);
}
#[test]
fn min_word_edge_i32_min_max() {
assert_eq!(
atomic_alu(AtomicOp::Min, I32_MAX, I32_MIN_ZEXT, MemWidth::Word),
sext32(i32::MIN as u32)
);
}
#[test]
fn min_double_edge_i64_min_max() {
assert_eq!(atomic_alu(AtomicOp::Min, I64_MAX, I64_MIN, MemWidth::Double), I64_MIN);
}
#[test]
fn max_word_positive() {
assert_eq!(atomic_alu(AtomicOp::Max, 10, 20, MemWidth::Word), sext32(20));
}
#[test]
fn max_word_negative_values() {
let neg1 = (-1i32 as u32) as u64;
let neg2 = (-2i32 as u32) as u64;
assert_eq!(atomic_alu(AtomicOp::Max, neg1, neg2, MemWidth::Word), sext32(-1i32 as u32));
}
#[test]
fn max_word_mixed_sign() {
let neg1 = (-1i32 as u32) as u64;
assert_eq!(atomic_alu(AtomicOp::Max, 1, neg1, MemWidth::Word), sext32(1));
}
#[test]
fn max_double_negative() {
let neg1 = (-1i64) as u64;
let neg100 = (-100i64) as u64;
assert_eq!(atomic_alu(AtomicOp::Max, neg1, neg100, MemWidth::Double), neg1);
}
#[test]
fn max_double_edge_i64_min_max() {
assert_eq!(atomic_alu(AtomicOp::Max, I64_MAX, I64_MIN, MemWidth::Double), I64_MAX);
}
#[test]
fn minu_word_basic() {
assert_eq!(atomic_alu(AtomicOp::MinU, 10, 20, MemWidth::Word), sext32(10));
}
#[test]
fn minu_word_large_unsigned() {
assert_eq!(atomic_alu(AtomicOp::MinU, U32_MAX, 1, MemWidth::Word), sext32(1));
}
#[test]
fn minu_word_high_bit_set_is_large() {
assert_eq!(
atomic_alu(AtomicOp::MinU, I32_MIN_ZEXT, I32_MAX, MemWidth::Word),
sext32(I32_MAX as u32)
);
}
#[test]
fn minu_double_basic() {
assert_eq!(atomic_alu(AtomicOp::MinU, 100, 200, MemWidth::Double), 100);
}
#[test]
fn minu_double_large_unsigned() {
assert_eq!(atomic_alu(AtomicOp::MinU, U64_MAX, 1, MemWidth::Double), 1);
}
#[test]
fn minu_double_zero_is_minimum() {
assert_eq!(atomic_alu(AtomicOp::MinU, 0, U64_MAX, MemWidth::Double), 0);
}
#[test]
fn maxu_word_basic() {
assert_eq!(atomic_alu(AtomicOp::MaxU, 10, 20, MemWidth::Word), sext32(20));
}
#[test]
fn maxu_word_large_unsigned() {
assert_eq!(atomic_alu(AtomicOp::MaxU, U32_MAX, 1, MemWidth::Word), sext32(U32_MAX as u32));
}
#[test]
fn maxu_word_high_bit_set_is_large() {
assert_eq!(
atomic_alu(AtomicOp::MaxU, I32_MIN_ZEXT, I32_MAX, MemWidth::Word),
sext32(0x8000_0000u32)
);
}
#[test]
fn maxu_double_large_unsigned() {
assert_eq!(atomic_alu(AtomicOp::MaxU, U64_MAX, 1, MemWidth::Double), U64_MAX);
}
#[test]
fn maxu_double_zero_and_max() {
assert_eq!(atomic_alu(AtomicOp::MaxU, 0, U64_MAX, MemWidth::Double), U64_MAX);
}
#[test]
fn word_sign_extension_positive_result() {
let result = atomic_alu(AtomicOp::Add, 1, 1, MemWidth::Word);
assert_eq!(result, 2);
assert_eq!(result >> 32, 0, "Upper 32 bits should be 0 for positive result");
}
#[test]
fn word_sign_extension_negative_result() {
let result = atomic_alu(AtomicOp::Add, 0, U32_MAX, MemWidth::Word);
assert_eq!(result, U64_MAX, "0 + (-1 as i32) should sign-extend to all-ones");
}
#[test]
fn word_sign_extension_from_xor() {
let result = atomic_alu(AtomicOp::Xor, 0x7000_0000, 0xF000_0000, MemWidth::Word);
assert_eq!(result, sext32(0x8000_0000u32));
assert_eq!(result >> 32, 0xFFFF_FFFF);
}
#[test]
fn word_sign_extension_from_or() {
let result = atomic_alu(AtomicOp::Or, 0x8000_0000, 0, MemWidth::Word);
assert_eq!(result, sext32(0x8000_0000u32));
}
#[test]
fn add_word_zero_plus_zero() {
assert_eq!(atomic_alu(AtomicOp::Add, 0, 0, MemWidth::Word), 0);
}
#[test]
fn add_double_zero_plus_zero() {
assert_eq!(atomic_alu(AtomicOp::Add, 0, 0, MemWidth::Double), 0);
}
#[test]
fn swap_word_zero() {
assert_eq!(atomic_alu(AtomicOp::Swap, U64_MAX, 0, MemWidth::Word), 0);
}
#[test]
fn swap_double_zero() {
assert_eq!(atomic_alu(AtomicOp::Swap, U64_MAX, 0, MemWidth::Double), 0);
}
#[test]
fn min_word_equal_values() {
assert_eq!(atomic_alu(AtomicOp::Min, 42, 42, MemWidth::Word), sext32(42));
}
#[test]
fn max_word_equal_values() {
assert_eq!(atomic_alu(AtomicOp::Max, 42, 42, MemWidth::Word), sext32(42));
}
#[test]
fn minu_word_equal_values() {
assert_eq!(atomic_alu(AtomicOp::MinU, 42, 42, MemWidth::Word), sext32(42));
}
#[test]
fn maxu_word_equal_values() {
assert_eq!(atomic_alu(AtomicOp::MaxU, 42, 42, MemWidth::Word), sext32(42));
}
#[test]
fn and_word_all_ones() {
assert_eq!(atomic_alu(AtomicOp::And, U32_MAX, U32_MAX, MemWidth::Word), sext32(U32_MAX as u32));
}
#[test]
fn or_double_zero_or_zero() {
assert_eq!(atomic_alu(AtomicOp::Or, 0, 0, MemWidth::Double), 0);
}