use crate::*;
const DATA_ADDR: u64 = 0x2000;
fn write_f64(mem: u64, addr: u64, value: f64) {
let mut emu = emu64(); emu.maps.write_bytes_slice(addr, &value.to_le_bytes());
}
fn read_f32(mem: u64, addr: u64) -> f32 {
let emu = emu64(); let mut buf = [0u8; 4];
emu.maps.read_bytes_buff(&mut buf, addr);
f32::from_le_bytes(buf)
}
fn read_f64(mem: u64, addr: u64) -> f64 {
let emu = emu64(); let mut buf = [0u8; 8];
emu.maps.read_bytes_buff(&mut buf, addr);
f64::from_le_bytes(buf)
}
#[test]
fn test_fst_m32fp_positive_one() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert_eq!(result, 1.0);
}
#[test]
fn test_fst_m32fp_zero() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 0.0);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert_eq!(result, 0.0);
}
#[test]
fn test_fst_m32fp_negative_zero() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -0.0);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert!(result.is_sign_negative() && result == 0.0);
}
#[test]
fn test_fst_m32fp_negative_one() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -1.0);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert_eq!(result, -1.0);
}
#[test]
fn test_fst_m32fp_infinity_positive() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, f64::INFINITY);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert!(result.is_infinite() && result.is_sign_positive());
}
#[test]
fn test_fst_m32fp_infinity_negative() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, f64::NEG_INFINITY);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert!(result.is_infinite() && result.is_sign_negative());
}
#[test]
fn test_fst_m32fp_nan() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, f64::NAN);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert!(result.is_nan());
}
#[test]
fn test_fst_m32fp_no_pop() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x04, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f32(0x3000).unwrap(), 1.0);
assert_eq!(emu.maps.read_f32(0x3004).unwrap(), 1.0);
}
#[test]
fn test_fst_m64fp_positive_one() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.run(None).unwrap();
let result = emu.maps.read_f64(0x3000).unwrap();
assert_eq!(result, 1.0);
}
#[test]
fn test_fst_m64fp_zero() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 0.0);
emu.run(None).unwrap();
let result = emu.maps.read_f64(0x3000).unwrap();
assert_eq!(result, 0.0);
}
#[test]
fn test_fst_m64fp_negative_zero() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -0.0);
emu.run(None).unwrap();
let result = emu.maps.read_f64(0x3000).unwrap();
assert!(result.is_sign_negative() && result == 0.0);
}
#[test]
fn test_fst_m64fp_pi() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, std::f64::consts::PI);
emu.run(None).unwrap();
let result = emu.maps.read_f64(0x3000).unwrap();
assert_eq!(result, std::f64::consts::PI);
}
#[test]
fn test_fst_m64fp_no_pop() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDD, 0x14, 0x25, 0x08, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, std::f64::consts::E);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f64(0x3000).unwrap(), std::f64::consts::E);
assert_eq!(emu.maps.read_f64(0x3008).unwrap(), std::f64::consts::E);
}
#[test]
fn test_fstp_m32fp_positive_one() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert_eq!(result, 1.0);
}
#[test]
fn test_fstp_m32fp_large_value() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 123456.78);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert!((result - 123456.78).abs() < 0.01);
}
#[test]
fn test_fstp_m32fp_with_pop() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xD9, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xD9, 0x1C, 0x25, 0x04, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.maps.write_f64(DATA_ADDR + 8, 2.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f32(0x3000).unwrap(), 2.0);
assert_eq!(emu.maps.read_f32(0x3004).unwrap(), 1.0);
}
#[test]
fn test_fstp_m64fp_positive_one() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.run(None).unwrap();
let result = emu.maps.read_f64(0x3000).unwrap();
assert_eq!(result, 1.0);
}
#[test]
fn test_fstp_m64fp_zero() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 0.0);
emu.run(None).unwrap();
let result = emu.maps.read_f64(0x3000).unwrap();
assert_eq!(result, 0.0);
}
#[test]
fn test_fstp_m64fp_negative_value() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -12345.6789);
emu.run(None).unwrap();
let result = emu.maps.read_f64(0x3000).unwrap();
assert_eq!(result, -12345.6789);
}
#[test]
fn test_fstp_m64fp_with_pop() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x08, 0x30, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x10, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.maps.write_f64(DATA_ADDR + 8, 2.0);
emu.maps.write_f64(DATA_ADDR + 16, 3.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f64(0x3000).unwrap(), 3.0);
assert_eq!(emu.maps.read_f64(0x3008).unwrap(), 2.0);
assert_eq!(emu.maps.read_f64(0x3010).unwrap(), 1.0);
}
#[test]
fn test_fst_st1() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xDD, 0xD1, 0xDD, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x08, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.maps.write_f64(DATA_ADDR + 8, 2.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f64(0x3000).unwrap(), 2.0);
assert_eq!(emu.maps.read_f64(0x3008).unwrap(), 2.0);
}
#[test]
fn test_fst_st2() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00, 0xDD, 0xD2, 0xDD, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x08, 0x30, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x10, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.maps.write_f64(DATA_ADDR + 8, 2.0);
emu.maps.write_f64(DATA_ADDR + 16, 3.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f64(0x3000).unwrap(), 3.0);
assert_eq!(emu.maps.read_f64(0x3008).unwrap(), 2.0);
assert_eq!(emu.maps.read_f64(0x3010).unwrap(), 3.0);
}
#[test]
fn test_fstp_st1() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xDD, 0xD9, 0xDD, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.maps.write_f64(DATA_ADDR + 8, 2.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f64(0x3000).unwrap(), 2.0);
}
#[test]
fn test_fstp_st2() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00, 0xDD, 0xDA, 0xDD, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x08, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.maps.write_f64(DATA_ADDR + 8, 2.0);
emu.maps.write_f64(DATA_ADDR + 16, 3.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f64(0x3000).unwrap(), 2.0);
assert_eq!(emu.maps.read_f64(0x3008).unwrap(), 3.0);
}
#[test]
fn test_fst_m32fp_precision_loss() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.2345678901234567);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert!((result - 1.234568).abs() < 0.0001);
}
#[test]
fn test_fstp_m32fp_very_small() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0e-40);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert!(result > 0.0 && result < 1.0e-38);
}
#[test]
fn test_fstp_m32fp_very_large() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0e38);
emu.run(None).unwrap();
let result = emu.maps.read_f32(0x3000).unwrap();
assert!(result > 1.0e37);
}
#[test]
fn test_mixed_fst_fstp() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x08, 0x30, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x10, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.0);
emu.maps.write_f64(DATA_ADDR + 8, 2.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f32(0x3000).unwrap(), 2.0);
assert_eq!(emu.maps.read_f64(0x3008).unwrap(), 2.0);
assert_eq!(emu.maps.read_f64(0x3010).unwrap(), 1.0);
}
#[test]
fn test_fst_multiple_formats() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDD, 0x14, 0x25, 0x08, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, std::f64::consts::PI);
emu.run(None).unwrap();
let result_f32 = emu.maps.read_f32(0x3000).unwrap();
let result_f64 = emu.maps.read_f64(0x3008).unwrap();
assert!((result_f32 as f64 - std::f64::consts::PI).abs() < 1e-6);
assert_eq!(result_f64, std::f64::consts::PI);
}
#[test]
fn test_fstp_special_values_sequence() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x10, 0x20, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x08, 0x30, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x10, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 0.0);
emu.maps.write_f64(DATA_ADDR + 8, -0.0);
emu.maps.write_f64(DATA_ADDR + 16, f64::INFINITY);
emu.run(None).unwrap();
let r1 = emu.maps.read_f64(0x3000).unwrap();
let r2 = emu.maps.read_f64(0x3008).unwrap();
let r3 = emu.maps.read_f64(0x3010).unwrap();
assert!(r1.is_infinite() && r1.is_sign_positive());
assert!(r2.is_sign_negative() && r2 == 0.0);
assert_eq!(r3, 0.0);
}
#[test]
fn test_fst_preserves_nan() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x14, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDD, 0x14, 0x25, 0x08, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, f64::NAN);
emu.run(None).unwrap();
assert!(emu.maps.read_f64(0x3000).unwrap().is_nan());
assert!(emu.maps.read_f64(0x3008).unwrap().is_nan());
}
#[test]
fn test_fstp_extreme_values() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x1C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, f64::MAX);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f64(0x3000).unwrap(), f64::MAX);
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, f64::MIN_POSITIVE);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_f64(0x3000).unwrap(), f64::MIN_POSITIVE);
}