use super::Float;
use crate::rom_data;
#[inline(never)]
#[cold]
fn save_divider_and_call<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
let sio = rp_pac::SIO;
while !sio.div().csr().read().ready() {}
let dividend = sio.div().udividend().read();
let divisor = sio.div().udivisor().read();
let remainder = sio.div().remainder().read();
let quotient = sio.div().quotient().read();
let result = f();
sio.div().udividend().write_value(dividend);
sio.div().udivisor().write_value(divisor);
sio.div().remainder().write_value(remainder);
sio.div().quotient().write_value(quotient);
result
}
fn save_divider<F, R>(f: F) -> R
where
F: FnOnce() -> R,
{
let sio = rp_pac::SIO;
if !sio.div().csr().read().dirty() {
f()
} else {
save_divider_and_call(f)
}
}
trait ROMDiv {
fn rom_div(self, b: Self) -> Self;
}
impl ROMDiv for f32 {
fn rom_div(self, b: Self) -> Self {
save_divider(|| rom_data::float_funcs::fdiv(self, b))
}
}
impl ROMDiv for f64 {
fn rom_div(self, b: Self) -> Self {
save_divider(|| rom_data::double_funcs::ddiv(self, b))
}
}
fn div<F: Float + ROMDiv>(a: F, b: F) -> F {
if a.is_not_finite() {
if b.is_not_finite() {
return F::NAN;
}
if b.is_zero() {
return F::NAN;
}
return if b.is_sign_negative() {
a.negate()
} else {
a
};
}
if b.is_nan() {
return b;
}
if b.is_zero() && a.is_zero() {
return F::NAN;
}
a.rom_div(b)
}
intrinsics! {
#[alias = __divsf3vfp]
#[aeabi = __aeabi_fdiv]
extern "C" fn __divsf3(a: f32, b: f32) -> f32 {
div(a, b)
}
#[bootrom_v2]
#[alias = __divdf3vfp]
#[aeabi = __aeabi_ddiv]
extern "C" fn __divdf3(a: f64, b: f64) -> f64 {
div(a, b)
}
}