mirror of
https://github.com/italicsjenga/rp-hal-boards.git
synced 2025-01-11 04:51:31 +11:00
Add basic ROM intrinsics
Add a standardized macro for intrinsics export and connect the simple ROM functions to intrinsics.
This commit is contained in:
parent
81ab38fd71
commit
a70eb89799
|
@ -54,3 +54,5 @@ rt = ["rp2040-pac/rt"]
|
|||
# embassy-traits = ["embassy_traits", "futures"]
|
||||
alloc = []
|
||||
rom-func-cache = []
|
||||
disable-intrinsics = []
|
||||
rom-v2-intrinsics = []
|
||||
|
|
271
rp2040-hal/src/intrinsics.rs
Normal file
271
rp2040-hal/src/intrinsics.rs
Normal file
|
@ -0,0 +1,271 @@
|
|||
/// Generate a series of aliases for an intrinsic function.
|
||||
macro_rules! intrinsics_aliases {
|
||||
(
|
||||
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
|
||||
) => {};
|
||||
(
|
||||
unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
|
||||
) => {};
|
||||
|
||||
(
|
||||
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
|
||||
$alias:ident
|
||||
$($rest:ident)*
|
||||
) => {
|
||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||
intrinsics! {
|
||||
extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
||||
$name($($argname),*)
|
||||
}
|
||||
}
|
||||
|
||||
intrinsics_aliases! {
|
||||
extern $abi fn $name( $($argname: $ty),* ) -> $ret,
|
||||
$($rest)*
|
||||
}
|
||||
};
|
||||
|
||||
(
|
||||
unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty,
|
||||
$alias:ident
|
||||
$($rest:ident)*
|
||||
) => {
|
||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||
intrinsics! {
|
||||
unsafe extern $abi fn $alias( $($argname: $ty),* ) -> $ret {
|
||||
$name($($argname),*)
|
||||
}
|
||||
}
|
||||
|
||||
intrinsics_aliases! {
|
||||
unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret,
|
||||
$($rest)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// The macro used to define overridden intrinsics.
|
||||
///
|
||||
/// This is heavily inspired by the macro used by compiler-builtins. The idea
|
||||
/// is to abstract anything special that needs to be done to override an
|
||||
/// intrinsic function. Intrinsic generation is disabled for non-ARM targets
|
||||
/// so things like CI and docs generation do not have problems. Additionally
|
||||
/// they can be disabled with the crate feature `disable-intrinsics` for
|
||||
/// testing or comparing performance.
|
||||
///
|
||||
/// Like the compiler-builtins macro, it accepts a series of functions that
|
||||
/// looks like normal Rust code:
|
||||
///
|
||||
/// intrinsics! {
|
||||
/// extern "C" fn foo(a: i32) -> u32 {
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// #[nonstandard_attribute]
|
||||
/// extern "C" fn bar(a: i32) -> u32 {
|
||||
/// // ...
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// Each function can also be decorated with nonstandard attributes to control
|
||||
/// additional behaviour:
|
||||
///
|
||||
/// * `slower_than_default` - indicates that the override is slower than the
|
||||
/// default implementation. Currently this just disables the override
|
||||
/// entirely.
|
||||
/// * `bootrom_v2` - indicates that the override is only available
|
||||
/// on a V2 bootrom or higher. Only enabled when the feature
|
||||
/// `rom-v2-intrinsics` is set.
|
||||
/// * `alias` - accepts a list of names to alias the intrinsic to.
|
||||
/// * `aeabi` - accepts a list of ARM EABI names to alias to.
|
||||
///
|
||||
macro_rules! intrinsics {
|
||||
() => {};
|
||||
|
||||
(
|
||||
#[slower_than_default]
|
||||
$(#[$($attr:tt)*])*
|
||||
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||||
$($body:tt)*
|
||||
}
|
||||
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
// Not exported, but defined so the actual implementation is
|
||||
// considered used
|
||||
#[allow(dead_code)]
|
||||
fn $name( $($argname: $ty),* ) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
|
||||
intrinsics!($($rest)*);
|
||||
};
|
||||
|
||||
(
|
||||
#[bootrom_v2]
|
||||
$(#[$($attr:tt)*])*
|
||||
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||||
$($body:tt)*
|
||||
}
|
||||
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
// Not exported, but defined so the actual implementation is
|
||||
// considered used
|
||||
#[cfg(not(feature = "rom-v2-intrinsics"))]
|
||||
#[allow(dead_code)]
|
||||
fn $name( $($argname: $ty),* ) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
|
||||
#[cfg(feature = "rom-v2-intrinsics")]
|
||||
intrinsics! {
|
||||
$(#[$($attr)*])*
|
||||
extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
}
|
||||
|
||||
intrinsics!($($rest)*);
|
||||
};
|
||||
|
||||
(
|
||||
#[alias = $($alias:ident),*]
|
||||
$(#[$($attr:tt)*])*
|
||||
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||||
$($body:tt)*
|
||||
}
|
||||
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
intrinsics! {
|
||||
$(#[$($attr)*])*
|
||||
extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
}
|
||||
|
||||
intrinsics_aliases! {
|
||||
extern $abi fn $name( $($argname: $ty),* ) -> $ret,
|
||||
$($alias) *
|
||||
}
|
||||
|
||||
intrinsics!($($rest)*);
|
||||
};
|
||||
|
||||
(
|
||||
#[alias = $($alias:ident),*]
|
||||
$(#[$($attr:tt)*])*
|
||||
unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||||
$($body:tt)*
|
||||
}
|
||||
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
intrinsics! {
|
||||
$(#[$($attr)*])*
|
||||
unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
}
|
||||
|
||||
intrinsics_aliases! {
|
||||
unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret,
|
||||
$($alias) *
|
||||
}
|
||||
|
||||
intrinsics!($($rest)*);
|
||||
};
|
||||
|
||||
(
|
||||
#[aeabi = $($alias:ident),*]
|
||||
$(#[$($attr:tt)*])*
|
||||
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||||
$($body:tt)*
|
||||
}
|
||||
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
intrinsics! {
|
||||
$(#[$($attr)*])*
|
||||
extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
}
|
||||
|
||||
intrinsics_aliases! {
|
||||
extern "aapcs" fn $name( $($argname: $ty),* ) -> $ret,
|
||||
$($alias) *
|
||||
}
|
||||
|
||||
intrinsics!($($rest)*);
|
||||
};
|
||||
|
||||
(
|
||||
$(#[$($attr:tt)*])*
|
||||
extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||||
$($body:tt)*
|
||||
}
|
||||
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||
$(#[$($attr)*])*
|
||||
extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||
mod $name {
|
||||
#[no_mangle]
|
||||
$(#[$($attr)*])*
|
||||
pub extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||||
super::$name($($argname),*)
|
||||
}
|
||||
}
|
||||
|
||||
// Not exported, but defined so the actual implementation is
|
||||
// considered used
|
||||
#[cfg(not(all(target_arch = "arm", not(feature = "disable-intrinsics"))))]
|
||||
#[allow(dead_code)]
|
||||
fn $name( $($argname: $ty),* ) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
|
||||
intrinsics!($($rest)*);
|
||||
};
|
||||
|
||||
(
|
||||
$(#[$($attr:tt)*])*
|
||||
unsafe extern $abi:tt fn $name:ident( $($argname:ident: $ty:ty),* ) -> $ret:ty {
|
||||
$($body:tt)*
|
||||
}
|
||||
|
||||
$($rest:tt)*
|
||||
) => {
|
||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||
$(#[$($attr)*])*
|
||||
unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "arm", not(feature = "disable-intrinsics")))]
|
||||
mod $name {
|
||||
#[no_mangle]
|
||||
$(#[$($attr)*])*
|
||||
pub unsafe extern $abi fn $name( $($argname: $ty),* ) -> $ret {
|
||||
super::$name($($argname),*)
|
||||
}
|
||||
}
|
||||
|
||||
// Not exported, but defined so the actual implementation is
|
||||
// considered used
|
||||
#[cfg(not(all(target_arch = "arm", not(feature = "disable-intrinsics"))))]
|
||||
#[allow(dead_code)]
|
||||
unsafe fn $name( $($argname: $ty),* ) -> $ret {
|
||||
$($body)*
|
||||
}
|
||||
|
||||
intrinsics!($($rest)*);
|
||||
};
|
||||
}
|
|
@ -15,6 +15,9 @@ pub use paste;
|
|||
|
||||
pub extern crate rp2040_pac as pac;
|
||||
|
||||
#[macro_use]
|
||||
mod intrinsics;
|
||||
|
||||
pub mod adc;
|
||||
pub(crate) mod atomic_register_access;
|
||||
pub mod clocks;
|
||||
|
|
|
@ -279,6 +279,60 @@ rom_functions! {
|
|||
b"WV" unsafe fn wait_for_vector() -> !;
|
||||
}
|
||||
|
||||
// Various C intrinsics in the ROM
|
||||
intrinsics! {
|
||||
#[alias = __popcountdi2]
|
||||
extern "C" fn __popcountsi2(x: u32) -> u32 {
|
||||
popcount32(x)
|
||||
}
|
||||
|
||||
#[alias = __clzdi2]
|
||||
extern "C" fn __clzsi2(x: u32) -> u32 {
|
||||
clz32(x)
|
||||
}
|
||||
|
||||
#[alias = __ctzdi2]
|
||||
extern "C" fn __ctzsi2(x: u32) -> u32 {
|
||||
ctz32(x)
|
||||
}
|
||||
|
||||
// __rbit is only unofficial, but it show up in the ARM documentation,
|
||||
// so may as well hook it up.
|
||||
#[alias = __rbitl]
|
||||
extern "C" fn __rbit(x: u32) -> u32 {
|
||||
reverse32(x)
|
||||
}
|
||||
|
||||
unsafe extern "aapcs" fn __aeabi_memset(dest: *mut u8, n: usize, c: i32) -> () {
|
||||
// Different argument order
|
||||
memset(dest, c as u8, n as u32);
|
||||
}
|
||||
|
||||
#[alias = __aeabi_memset8]
|
||||
unsafe extern "aapcs" fn __aeabi_memset4(dest: *mut u8, n: usize, c: i32) -> () {
|
||||
// Different argument order
|
||||
memset4(dest as *mut u32, c as u8, n as u32);
|
||||
}
|
||||
|
||||
unsafe extern "aapcs" fn __aeabi_memclr(dest: *mut u8, n: usize) -> () {
|
||||
memset(dest, 0, n as u32);
|
||||
}
|
||||
|
||||
#[alias = __aeabi_memclr8]
|
||||
unsafe extern "aapcs" fn __aeabi_memclr4(dest: *mut u8, n: usize) -> () {
|
||||
memset4(dest as *mut u32, 0, n as u32);
|
||||
}
|
||||
|
||||
unsafe extern "aapcs" fn __aeabi_memcpy(dest: *mut u8, src: *const u8, n: usize) -> () {
|
||||
memcpy(dest, src, n as u32);
|
||||
}
|
||||
|
||||
#[alias = __aeabi_memcpy8]
|
||||
unsafe extern "aapcs" fn __aeabi_memcpy4(dest: *mut u8, src: *const u8, n: usize) -> () {
|
||||
memcpy44(dest as *mut u32, src as *const u32, n as u32);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn convert_str(s: *const u8) -> &'static str {
|
||||
let mut end = s;
|
||||
while *end != 0 {
|
||||
|
|
Loading…
Reference in a new issue