mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2024-12-23 20:51:31 +11:00
Add intrinsics for the hardware divider
Implement intrinsic functions so basic operators use the hardware divider.
This commit is contained in:
parent
35704d9799
commit
f279945315
|
@ -230,45 +230,141 @@ fn divider_delay() {
|
||||||
cortex_m::asm::nop();
|
cortex_m::asm::nop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn divider_unsigned(dividend: u32, divisor: u32) -> DivResult<u32> {
|
||||||
|
save_divider(|sio| {
|
||||||
|
sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
|
||||||
|
sio.div_udivisor.write(|w| unsafe { w.bits(divisor) });
|
||||||
|
|
||||||
|
divider_delay();
|
||||||
|
|
||||||
|
// Note: quotient must be read last
|
||||||
|
let remainder = sio.div_remainder.read().bits();
|
||||||
|
let quotient = sio.div_quotient.read().bits();
|
||||||
|
|
||||||
|
DivResult {
|
||||||
|
remainder,
|
||||||
|
quotient,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn divider_signed(dividend: i32, divisor: i32) -> DivResult<i32> {
|
||||||
|
save_divider(|sio| {
|
||||||
|
sio.div_sdividend
|
||||||
|
.write(|w| unsafe { w.bits(dividend as u32) });
|
||||||
|
sio.div_sdivisor
|
||||||
|
.write(|w| unsafe { w.bits(divisor as u32) });
|
||||||
|
|
||||||
|
divider_delay();
|
||||||
|
|
||||||
|
// Note: quotient must be read last
|
||||||
|
let remainder = sio.div_remainder.read().bits() as i32;
|
||||||
|
let quotient = sio.div_quotient.read().bits() as i32;
|
||||||
|
|
||||||
|
DivResult {
|
||||||
|
remainder,
|
||||||
|
quotient,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl HwDivider {
|
impl HwDivider {
|
||||||
/// Perform hardware unsigned divide/modulo operation
|
/// Perform hardware unsigned divide/modulo operation
|
||||||
pub fn unsigned(&self, dividend: u32, divisor: u32) -> DivResult<u32> {
|
pub fn unsigned(&self, dividend: u32, divisor: u32) -> DivResult<u32> {
|
||||||
save_divider(|sio| {
|
divider_unsigned(dividend, divisor)
|
||||||
sio.div_udividend.write(|w| unsafe { w.bits(dividend) });
|
|
||||||
sio.div_udivisor.write(|w| unsafe { w.bits(divisor) });
|
|
||||||
|
|
||||||
divider_delay();
|
|
||||||
|
|
||||||
// Note: quotient must be read last
|
|
||||||
let remainder = sio.div_remainder.read().bits();
|
|
||||||
let quotient = sio.div_quotient.read().bits();
|
|
||||||
|
|
||||||
DivResult {
|
|
||||||
remainder,
|
|
||||||
quotient,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Perform hardware signed divide/modulo operation
|
/// Perform hardware signed divide/modulo operation
|
||||||
pub fn signed(&self, dividend: i32, divisor: i32) -> DivResult<i32> {
|
pub fn signed(&self, dividend: i32, divisor: i32) -> DivResult<i32> {
|
||||||
save_divider(|sio| {
|
divider_signed(dividend, divisor)
|
||||||
sio.div_sdividend
|
}
|
||||||
.write(|w| unsafe { w.bits(dividend as u32) });
|
}
|
||||||
sio.div_sdivisor
|
|
||||||
.write(|w| unsafe { w.bits(divisor as u32) });
|
|
||||||
|
|
||||||
divider_delay();
|
macro_rules! divider_intrinsics {
|
||||||
|
() => ();
|
||||||
|
|
||||||
// Note: quotient must be read last
|
(
|
||||||
let remainder = sio.div_remainder.read().bits() as i32;
|
#[arm_aeabi_alias = $alias:ident]
|
||||||
let quotient = sio.div_quotient.read().bits() as i32;
|
pub extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||||||
|
$($body:tt)*
|
||||||
|
}
|
||||||
|
|
||||||
DivResult {
|
$($rest:tt)*
|
||||||
remainder,
|
) => (
|
||||||
quotient,
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue