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_i16(mem: u64, addr: u64) -> i16 {
let mut emu = emu64(); let mut buf = [0u8; 2];
emu.maps.read_bytes_buff(&mut buf, addr);
i16::from_le_bytes(buf)
}
fn read_i32(mem: u64, addr: u64) -> i32 {
let mut emu = emu64(); let mut buf = [0u8; 4];
emu.maps.read_bytes_buff(&mut buf, addr);
i32::from_le_bytes(buf)
}
fn read_i64(mem: u64, addr: u64) -> i64 {
let mut emu = emu64(); let mut buf = [0u8; 8];
emu.maps.read_bytes_buff(&mut buf, addr);
i64::from_le_bytes(buf)
}
#[test]
fn test_fisttp_m16int_zero() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 0.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, 0);
}
#[test]
fn test_fisttp_m16int_positive_one() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 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_word(0x3000).unwrap() as i16, 1);
}
#[test]
fn test_fisttp_m16int_negative_one() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 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_word(0x3000).unwrap() as i16, -1);
}
#[test]
fn test_fisttp_m16int_truncate_positive() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 2.9);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, 2);
}
#[test]
fn test_fisttp_m16int_truncate_negative() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -2.9);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, -2);
}
#[test]
fn test_fisttp_m16int_truncate_half() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 2.5);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, 2);
}
#[test]
fn test_fisttp_m16int_truncate_negative_half() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -2.5);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, -2);
}
#[test]
fn test_fisttp_m16int_truncate_small_fraction() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 99.1);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, 99);
}
#[test]
fn test_fisttp_m16int_truncate_large_fraction() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 99.9);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, 99);
}
#[test]
fn test_fisttp_m16int_max() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, i16::MAX as f64);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, i16::MAX);
}
#[test]
fn test_fisttp_m16int_min() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, i16::MIN as f64);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, i16::MIN);
}
#[test]
fn test_fisttp_m32int_zero() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 0.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 0);
}
#[test]
fn test_fisttp_m32int_positive() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 12345.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 12345);
}
#[test]
fn test_fisttp_m32int_negative() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -67890.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, -67890);
}
#[test]
fn test_fisttp_m32int_truncate_positive() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1234.99);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 1234);
}
#[test]
fn test_fisttp_m32int_truncate_negative() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -1234.99);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, -1234);
}
#[test]
fn test_fisttp_m32int_truncate_half() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 999.5);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 999);
}
#[test]
fn test_fisttp_m32int_large() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1000000.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 1000000);
}
#[test]
fn test_fisttp_m32int_max() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, i32::MAX as f64);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, i32::MAX);
}
#[test]
fn test_fisttp_m32int_min() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, i32::MIN as f64);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, i32::MIN);
}
#[test]
fn test_fisttp_m64int_zero() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDD, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 0.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_qword(0x3000).unwrap() as i64, 0);
}
#[test]
fn test_fisttp_m64int_positive() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDD, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 123456789.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_qword(0x3000).unwrap() as i64, 123456789);
}
#[test]
fn test_fisttp_m64int_negative() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDD, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -987654321.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_qword(0x3000).unwrap() as i64, -987654321);
}
#[test]
fn test_fisttp_m64int_truncate_positive() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDD, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 999999.999);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_qword(0x3000).unwrap() as i64, 999999);
}
#[test]
fn test_fisttp_m64int_truncate_negative() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDD, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -999999.999);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_qword(0x3000).unwrap() as i64, -999999);
}
#[test]
fn test_fisttp_m64int_large() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDD, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1_000_000_000_000.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_qword(0x3000).unwrap() as i64, 1_000_000_000_000);
}
#[test]
fn test_fisttp_m64int_max_safe() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDD, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
let max_safe = (1i64 << 53) - 1;
emu.maps.write_f64(DATA_ADDR, max_safe as f64);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_qword(0x3000).unwrap() as i64, max_safe);
}
#[test]
fn test_fisttp_m64int_min_safe() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDD, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
let min_safe = -((1i64 << 53) - 1);
emu.maps.write_f64(DATA_ADDR, min_safe as f64);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_qword(0x3000).unwrap() as i64, min_safe);
}
#[test]
fn test_fisttp_truncation_positive_values() {
let mut emu = emu64(); let test_cases = vec![
(0.1, 0),
(0.9, 0),
(1.1, 1),
(1.9, 1),
(2.5, 2),
(3.5, 3),
(99.99, 99),
];
for (input, expected) in test_cases {
let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, input);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, expected, "Failed for input {}", input);
}
}
#[test]
fn test_fisttp_truncation_negative_values() {
let mut emu = emu64(); let test_cases = vec![
(-0.1, 0),
(-0.9, 0),
(-1.1, -1),
(-1.9, -1),
(-2.5, -2),
(-3.5, -3),
(-99.99, -99),
];
for (input, expected) in test_cases {
let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, input);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, expected, "Failed for input {}", input);
}
}
#[test]
fn test_fisttp_pops_stack() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDB, 0x0C, 0x25, 0x04, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 100.5);
emu.maps.write_f64(DATA_ADDR + 8, 200.5);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 200);
assert_eq!(emu.maps.read_dword(0x3004).unwrap() as i32, 100);
}
#[test]
fn test_fisttp_sequential() {
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, 0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDB, 0x0C, 0x25, 0x04, 0x30, 0x00, 0x00, 0xDD, 0x0C, 0x25, 0x08, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1.7);
emu.maps.write_f64(DATA_ADDR + 8, 2.7);
emu.maps.write_f64(DATA_ADDR + 16, 3.7);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, 3);
assert_eq!(emu.maps.read_dword(0x3004).unwrap() as i32, 2);
assert_eq!(emu.maps.read_qword(0x3008).unwrap() as i64, 1);
}
#[test]
fn test_fisttp_after_arithmetic() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xDE, 0xC1, 0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 10.7);
emu.maps.write_f64(DATA_ADDR + 8, 20.3);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 31);
}
#[test]
fn test_fisttp_division_truncate() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDD, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00, 0xDE, 0xF9, 0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 10.0);
emu.maps.write_f64(DATA_ADDR + 8, 3.0);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 3);
}
#[test]
fn test_fisttp_very_small_positive() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 0.00001);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 0);
}
#[test]
fn test_fisttp_very_small_negative() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -0.00001);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 0);
}
#[test]
fn test_fisttp_almost_one() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 0.99999);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 0);
}
#[test]
fn test_fisttp_almost_minus_one() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00,
0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, -0.99999);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 0);
}
#[test]
fn test_fisttp_all_sizes_same_value() {
let mut emu = emu64(); let code = [
0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xD9, 0xC0, 0xD9, 0xC0, 0xDF, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00, 0xDB, 0x0C, 0x25, 0x04, 0x30, 0x00, 0x00, 0xDD, 0x0C, 0x25, 0x08, 0x30, 0x00, 0x00, 0xf4,
];
emu.load_code_bytes(&code);
emu.maps.write_f64(DATA_ADDR, 1234.9);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_word(0x3000).unwrap() as i16, 1234);
assert_eq!(emu.maps.read_dword(0x3004).unwrap() as i32, 1234);
assert_eq!(emu.maps.read_qword(0x3008).unwrap() as i64, 1234);
}
#[test]
fn test_fisttp_pi() {
let mut emu = emu64(); let code = [
0xD9, 0xEB, 0xDB, 0x0C, 0x25, 0x00, 0x30, 0x00, 0x00,
0xf4,
];
emu.load_code_bytes(&code);
emu.run(None).unwrap();
assert_eq!(emu.maps.read_dword(0x3000).unwrap() as i32, 3);
}
#[test]
fn test_fisttp_e() {
let mut emu = emu64(); let code = [
0xD9, 0xE8, 0xD9, 0xEA, 0xD9, 0xED, 0xDE, 0xC9, 0xDE, 0xC1, 0xD9, 0xE8, 0xDE, 0xC1, 0xDD, 0xD8, 0xDD, 0x04, 0x25, 0x00, 0x20, 0x00, 0x00, 0xDB, 0x0C, 0x25, 0x00, 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_dword(0x3000).unwrap() as i32, 2);
}