Add intrinsics for the hardware divider

Implement intrinsic functions so basic operators use the hardware divider.
This commit is contained in:
Derek Hageman 2022-01-26 06:51:10 -07:00
parent 35704d9799
commit f279945315

View file

@ -230,9 +230,7 @@ fn divider_delay() {
cortex_m::asm::nop(); cortex_m::asm::nop();
} }
impl HwDivider { fn divider_unsigned(dividend: u32, divisor: u32) -> DivResult<u32> {
/// Perform hardware unsigned divide/modulo operation
pub fn unsigned(&self, dividend: u32, divisor: u32) -> DivResult<u32> {
save_divider(|sio| { save_divider(|sio| {
sio.div_udividend.write(|w| unsafe { w.bits(dividend) }); sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
sio.div_udivisor.write(|w| unsafe { w.bits(divisor) }); sio.div_udivisor.write(|w| unsafe { w.bits(divisor) });
@ -248,10 +246,9 @@ impl HwDivider {
quotient, quotient,
} }
}) })
} }
/// Perform hardware signed divide/modulo operation fn divider_signed(dividend: i32, divisor: i32) -> DivResult<i32> {
pub fn signed(&self, dividend: i32, divisor: i32) -> DivResult<i32> {
save_divider(|sio| { save_divider(|sio| {
sio.div_sdividend sio.div_sdividend
.write(|w| unsafe { w.bits(dividend as u32) }); .write(|w| unsafe { w.bits(dividend as u32) });
@ -269,6 +266,105 @@ impl HwDivider {
quotient, quotient,
} }
}) })
}
impl HwDivider {
/// Perform hardware unsigned divide/modulo operation
pub fn unsigned(&self, dividend: u32, divisor: u32) -> DivResult<u32> {
divider_unsigned(dividend, divisor)
}
/// Perform hardware signed divide/modulo operation
pub fn signed(&self, dividend: i32, divisor: i32) -> DivResult<i32> {
divider_signed(dividend, divisor)
}
}
macro_rules! divider_intrinsics {
() => ();
(
#[arm_aeabi_alias = $alias:ident]
pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
$($body:tt)*
}
$($rest:tt)*
) => (
extern $abi fn $name( $($argname: $ty),* ) -> $ret {
$($body)*
}
mod $name {
#[no_mangle]
pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
super::$name($($argname),*)
}
}
mod $alias {
#[no_mangle]
pub extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
super::$name($($argname),*)
}
}
divider_intrinsics!($($rest)*);
);
(
pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
$($body:tt)*
}
$($rest:tt)*
) => (
extern $abi fn $name( $($argname: $ty),* ) -> $ret {
$($body)*
}
mod $name {
#[no_mangle]
pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
super::$name($($argname),*)
}
}
divider_intrinsics!($($rest)*);
);
}
divider_intrinsics! {
#[arm_aeabi_alias = __aeabi_uidiv]
pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
divider_unsigned(n, d).quotient
}
pub extern "C" fn __umodsi3(n: u32, d: u32) -> u32 {
divider_unsigned(n, d).remainder
}
pub extern "C" fn __udivmodsi4(n: u32, d: u32, rem: Option<&mut u32>) -> u32 {
let quo_rem = divider_unsigned(n, d);
if let Some(rem) = rem {
*rem = quo_rem.remainder;
}
quo_rem.quotient
}
#[arm_aeabi_alias = __aeabi_idiv]
pub extern "C" fn __divsi3(n: i32, d: i32) -> i32 {
divider_signed(n, d).quotient
}
pub extern "C" fn __modsi3(n: i32, d: i32) -> i32 {
divider_signed(n, d).remainder
}
pub extern "C" fn __divmodsi4(n: i32, d: i32, rem: &mut i32) -> i32 {
let quo_rem = divider_signed(n, d);
*rem = quo_rem.remainder;
quo_rem.quotient
} }
} }