use crate::exec::compute::fpu;
use crate::exec::compute::fpu::nan_handling::box_f32;
use crate::isa::fp::FpFlags;
use crate::isa::op::AluOp;
#[test]
fn test_exception_dz() {
let one = box_f32(1.0);
let zero = box_f32(0.0);
let (result, flags) = fpu::execute_full(AluOp::FDiv, one, zero, 0, true);
let res_f32 = f32::from_bits(result as u32);
assert!(res_f32.is_infinite(), "1.0 / 0.0 should produce infinity");
assert!(res_f32.is_sign_positive());
assert!(flags.contains(FpFlags::DZ), "DZ flag must be set for x/0");
assert!(!flags.contains(FpFlags::NV), "NV should NOT be set for x/0 (x != 0)");
}
#[test]
fn test_exception_nv() {
let neg_one = box_f32(-1.0);
let (_result, flags) = fpu::execute_full(AluOp::FSqrt, neg_one, 0, 0, true);
assert!(flags.contains(FpFlags::NV), "NV flag must be set for sqrt(-1.0)");
}
#[test]
fn test_exception_of_nx() {
let large = box_f32(f32::MAX);
let two = box_f32(2.0);
let (result, flags) = fpu::execute_full(AluOp::FMul, large, two, 0, true);
let res_f32 = f32::from_bits(result as u32);
assert!(res_f32.is_infinite(), "MAX * 2 should overflow to infinity");
assert!(flags.contains(FpFlags::OF), "OF flag must be set on overflow");
assert!(flags.contains(FpFlags::NX), "NX flag must be set on overflow (inexact)");
}
#[test]
fn test_exception_nv_zero_div_zero() {
let zero = box_f32(0.0);
let (_result, flags) = fpu::execute_full(AluOp::FDiv, zero, zero, 0, true);
assert!(flags.contains(FpFlags::NV), "0/0 should set NV (invalid operation)");
assert!(!flags.contains(FpFlags::DZ), "0/0 should NOT set DZ");
}
#[test]
fn test_no_exception_normal_add() {
let a = box_f32(1.0);
let b = box_f32(2.0);
let (_result, flags) = fpu::execute_full(AluOp::FAdd, a, b, 0, true);
assert!(flags.is_empty(), "Normal addition should raise no flags");
}
#[test]
fn test_exception_snan_input_sets_nv() {
let snan_bits = 0x7f800001u32; let snan = box_f32(f32::from_bits(snan_bits));
let one = box_f32(1.0);
let (_result, flags) = fpu::execute_full(AluOp::FAdd, snan, one, 0, true);
assert!(flags.contains(FpFlags::NV), "sNaN input must raise NV");
}
#[test]
fn test_exception_dz_f64() {
let one = f64::to_bits(1.0);
let zero = f64::to_bits(0.0);
let (result, flags) = fpu::execute_full(AluOp::FDiv, one, zero, 0, false);
let res_f64 = f64::from_bits(result);
assert!(res_f64.is_infinite());
assert!(flags.contains(FpFlags::DZ));
}
#[test]
fn test_exception_nv_sqrt_neg_f64() {
let neg_one = f64::to_bits(-1.0);
let (_result, flags) = fpu::execute_full(AluOp::FSqrt, neg_one, 0, 0, false);
assert!(flags.contains(FpFlags::NV));
}
#[test]
fn test_fpflags_bitor() {
let combined = FpFlags::NV | FpFlags::DZ;
assert!(combined.contains(FpFlags::NV));
assert!(combined.contains(FpFlags::DZ));
assert!(!combined.contains(FpFlags::OF));
}
#[test]
fn test_fpflags_bits() {
assert_eq!(FpFlags::NV.bits(), 0b10000);
assert_eq!(FpFlags::DZ.bits(), 0b01000);
assert_eq!(FpFlags::OF.bits(), 0b00100);
assert_eq!(FpFlags::UF.bits(), 0b00010);
assert_eq!(FpFlags::NX.bits(), 0b00001);
assert_eq!(FpFlags::NONE.bits(), 0);
}