701 lines
26 KiB
Rust
701 lines
26 KiB
Rust
use crate::device;
|
|
|
|
pub fn fs(opcode: u32) -> u32 {
|
|
return (opcode >> 11) & 0x1F;
|
|
}
|
|
|
|
pub fn ft(opcode: u32) -> u32 {
|
|
return (opcode >> 16) & 0x1F;
|
|
}
|
|
|
|
pub fn fd(opcode: u32) -> u32 {
|
|
return (opcode >> 6) & 0x1F;
|
|
}
|
|
|
|
pub fn bc1f(device: &mut device::Device, opcode: u32) {
|
|
if device.cpu.cop1.fcr31 & device::cop1::FCR31_CMP_BIT == 0 {
|
|
device::cpu_instructions::check_relative_idle_loop(device, opcode);
|
|
device.cpu.branch_state.state = device::cpu::State::Take;
|
|
device.cpu.branch_state.pc = device.cpu.pc.wrapping_add(device::cpu_instructions::se16(
|
|
device::cpu_instructions::imm(opcode << 2) as i16,
|
|
)) + 4;
|
|
} else {
|
|
device.cpu.branch_state.state = device::cpu::State::NotTaken;
|
|
}
|
|
}
|
|
|
|
pub fn bc1t(device: &mut device::Device, opcode: u32) {
|
|
if device.cpu.cop1.fcr31 & device::cop1::FCR31_CMP_BIT != 0 {
|
|
device::cpu_instructions::check_relative_idle_loop(device, opcode);
|
|
device.cpu.branch_state.state = device::cpu::State::Take;
|
|
device.cpu.branch_state.pc = device.cpu.pc.wrapping_add(device::cpu_instructions::se16(
|
|
device::cpu_instructions::imm(opcode << 2) as i16,
|
|
)) + 4;
|
|
} else {
|
|
device.cpu.branch_state.state = device::cpu::State::NotTaken;
|
|
}
|
|
}
|
|
|
|
pub fn bc1fl(device: &mut device::Device, opcode: u32) {
|
|
if device.cpu.cop1.fcr31 & device::cop1::FCR31_CMP_BIT == 0 {
|
|
device::cpu_instructions::check_relative_idle_loop(device, opcode);
|
|
device.cpu.branch_state.state = device::cpu::State::Take;
|
|
device.cpu.branch_state.pc = device.cpu.pc.wrapping_add(device::cpu_instructions::se16(
|
|
device::cpu_instructions::imm(opcode << 2) as i16,
|
|
)) + 4;
|
|
} else {
|
|
device.cpu.branch_state.state = device::cpu::State::Discard;
|
|
}
|
|
}
|
|
|
|
pub fn bc1tl(device: &mut device::Device, opcode: u32) {
|
|
if device.cpu.cop1.fcr31 & device::cop1::FCR31_CMP_BIT != 0 {
|
|
device::cpu_instructions::check_relative_idle_loop(device, opcode);
|
|
device.cpu.branch_state.state = device::cpu::State::Take;
|
|
device.cpu.branch_state.pc = device.cpu.pc.wrapping_add(device::cpu_instructions::se16(
|
|
device::cpu_instructions::imm(opcode << 2) as i16,
|
|
)) + 4;
|
|
} else {
|
|
device.cpu.branch_state.state = device::cpu::State::Discard;
|
|
}
|
|
}
|
|
|
|
pub fn add_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, fs + ft, true);
|
|
device::cop0::add_cycles(device, 2)
|
|
}
|
|
|
|
pub fn sub_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, fs - ft, true);
|
|
device::cop0::add_cycles(device, 2)
|
|
}
|
|
|
|
pub fn mul_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, fs * ft, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn div_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, fs / ft, true);
|
|
device::cop0::add_cycles(device, 28)
|
|
}
|
|
|
|
pub fn sqrt_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, fs.sqrt(), true);
|
|
device::cop0::add_cycles(device, 28)
|
|
}
|
|
|
|
pub fn abs_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, fs.abs(), true);
|
|
device::cop0::add_cycles(device, 2)
|
|
}
|
|
|
|
pub fn mov_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs);
|
|
}
|
|
|
|
pub fn neg_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, -fs, true);
|
|
}
|
|
|
|
pub fn round_l_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let value = f64::from_ne_bytes((fs.round_ties_even() as i64).to_ne_bytes());
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, value);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn trunc_l_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let value = f64::from_ne_bytes((fs.trunc() as i64).to_ne_bytes());
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, value);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn ceil_l_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let value = f64::from_ne_bytes((fs.ceil() as i64).to_ne_bytes());
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, value);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn floor_l_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let value = f64::from_ne_bytes((fs.floor() as i64).to_ne_bytes());
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, value);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn round_w_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let value = f32::from_ne_bytes((fs.round_ties_even() as i32).to_ne_bytes());
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, value, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn trunc_w_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let value = f32::from_ne_bytes((fs.trunc() as i32).to_ne_bytes());
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, value, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn ceil_w_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let value = f32::from_ne_bytes((fs.ceil() as i32).to_ne_bytes());
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, value, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn floor_w_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let value = f32::from_ne_bytes((fs.floor() as i32).to_ne_bytes());
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, value, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn cvt_d_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs as f64);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn cvt_w_s(device: &mut device::Device, opcode: u32) {
|
|
match device.cpu.cop1.fcr31 & 3 {
|
|
0 => round_w_s(device, opcode),
|
|
1 => trunc_w_s(device, opcode),
|
|
2 => ceil_w_s(device, opcode),
|
|
3 => floor_w_s(device, opcode),
|
|
_ => panic!("unknown cvt_w_s"),
|
|
}
|
|
}
|
|
|
|
pub fn cvt_l_s(device: &mut device::Device, opcode: u32) {
|
|
match device.cpu.cop1.fcr31 & 3 {
|
|
0 => round_l_s(device, opcode),
|
|
1 => trunc_l_s(device, opcode),
|
|
2 => ceil_l_s(device, opcode),
|
|
3 => floor_l_s(device, opcode),
|
|
_ => panic!("unknown cvt_l_s"),
|
|
}
|
|
}
|
|
|
|
pub fn c_f_s(device: &mut device::Device, _opcode: u32) {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT
|
|
}
|
|
|
|
pub fn c_un_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_eq_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs == ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ueq_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs == ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_olt_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs < ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ult_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs < ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ole_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs <= ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ule_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs <= ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_sf_s(device: &mut device::Device, _opcode: u32) {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
|
|
pub fn c_ngle_s(device: &mut device::Device, _opcode: u32) {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
|
|
pub fn c_seq_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
|
|
if fs == ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ngl_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
|
|
if fs == ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_lt_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
|
|
if fs < ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_nge_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
|
|
if fs < ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_le_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
|
|
if fs <= ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ngt_s(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_single(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_single(device, ft(opcode) as usize);
|
|
|
|
if fs <= ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn add_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs + ft);
|
|
device::cop0::add_cycles(device, 2)
|
|
}
|
|
|
|
pub fn sub_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs - ft);
|
|
device::cop0::add_cycles(device, 2)
|
|
}
|
|
|
|
pub fn mul_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs * ft);
|
|
device::cop0::add_cycles(device, 7)
|
|
}
|
|
|
|
pub fn div_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs / ft);
|
|
device::cop0::add_cycles(device, 57)
|
|
}
|
|
|
|
pub fn sqrt_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs.sqrt());
|
|
device::cop0::add_cycles(device, 57)
|
|
}
|
|
|
|
pub fn abs_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs.abs());
|
|
device::cop0::add_cycles(device, 2)
|
|
}
|
|
|
|
pub fn mov_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs);
|
|
}
|
|
|
|
pub fn neg_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, -fs);
|
|
}
|
|
|
|
pub fn round_l_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let value = f64::from_ne_bytes((fs.round_ties_even() as i64).to_ne_bytes());
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, value);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn trunc_l_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let value = f64::from_ne_bytes((fs.trunc() as i64).to_ne_bytes());
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, value);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn ceil_l_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let value = f64::from_ne_bytes((fs.ceil() as i64).to_ne_bytes());
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, value);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn floor_l_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let value = f64::from_ne_bytes((fs.floor() as i64).to_ne_bytes());
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, value);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn round_w_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let value = f32::from_ne_bytes((fs.round_ties_even() as i32).to_ne_bytes());
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, value, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn trunc_w_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let value = f32::from_ne_bytes((fs.trunc() as i32).to_ne_bytes());
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, value, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn ceil_w_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let value = f32::from_ne_bytes((fs.ceil() as i32).to_ne_bytes());
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, value, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn floor_w_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let value = f32::from_ne_bytes((fs.floor() as i32).to_ne_bytes());
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, value, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn cvt_s_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, fs as f32, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn cvt_w_d(device: &mut device::Device, opcode: u32) {
|
|
match device.cpu.cop1.fcr31 & 3 {
|
|
0 => round_w_d(device, opcode),
|
|
1 => trunc_w_d(device, opcode),
|
|
2 => ceil_w_d(device, opcode),
|
|
3 => floor_w_d(device, opcode),
|
|
_ => panic!("unknown cvt_w_d"),
|
|
}
|
|
}
|
|
|
|
pub fn cvt_l_d(device: &mut device::Device, opcode: u32) {
|
|
match device.cpu.cop1.fcr31 & 3 {
|
|
0 => round_l_d(device, opcode),
|
|
1 => trunc_l_d(device, opcode),
|
|
2 => ceil_l_d(device, opcode),
|
|
3 => floor_l_d(device, opcode),
|
|
_ => panic!("unknown cvt_l_d"),
|
|
}
|
|
}
|
|
|
|
pub fn c_f_d(device: &mut device::Device, _opcode: u32) {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
|
|
pub fn c_un_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_eq_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs == ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ueq_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs == ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_olt_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs < ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ult_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs < ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ole_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs <= ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ule_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
if fs.is_nan() || ft.is_nan() {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
return;
|
|
}
|
|
if fs <= ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_sf_d(device: &mut device::Device, _opcode: u32) {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
|
|
pub fn c_ngle_d(device: &mut device::Device, _opcode: u32) {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
|
|
pub fn c_seq_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
|
|
if fs == ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ngl_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
|
|
if fs == ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_lt_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
|
|
if fs < ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_nge_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
|
|
if fs < ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_le_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
|
|
if fs <= ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn c_ngt_d(device: &mut device::Device, opcode: u32) {
|
|
let fs = device::cop1::get_fpr_double(device, fs(opcode) as usize);
|
|
let ft = device::cop1::get_fpr_double(device, ft(opcode) as usize);
|
|
|
|
if fs <= ft {
|
|
device.cpu.cop1.fcr31 |= device::cop1::FCR31_CMP_BIT;
|
|
} else {
|
|
device.cpu.cop1.fcr31 &= !device::cop1::FCR31_CMP_BIT;
|
|
}
|
|
}
|
|
|
|
pub fn cvt_s_l(device: &mut device::Device, opcode: u32) {
|
|
let fs =
|
|
i64::from_ne_bytes(device::cop1::get_fpr_double(device, fs(opcode) as usize).to_ne_bytes());
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, fs as f32, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn cvt_d_l(device: &mut device::Device, opcode: u32) {
|
|
let fs =
|
|
i64::from_ne_bytes(device::cop1::get_fpr_double(device, fs(opcode) as usize).to_ne_bytes());
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs as f64);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn cvt_s_w(device: &mut device::Device, opcode: u32) {
|
|
let fs =
|
|
i32::from_ne_bytes(device::cop1::get_fpr_single(device, fs(opcode) as usize).to_ne_bytes());
|
|
device::cop1::set_fpr_single(device, fd(opcode) as usize, fs as f32, true);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|
|
|
|
pub fn cvt_d_w(device: &mut device::Device, opcode: u32) {
|
|
let fs = i32::from_ne_bytes(
|
|
device::cop1::get_fpr_double(device, fs(opcode) as usize).to_ne_bytes()[0..4]
|
|
.try_into()
|
|
.unwrap(),
|
|
);
|
|
device::cop1::set_fpr_double(device, fd(opcode) as usize, fs as f64);
|
|
device::cop0::add_cycles(device, 4)
|
|
}
|