diff --git a/raltool/src/generate/device.rs b/raltool/src/generate/device.rs index e4365ffaa508..9a5784d26b1a 100644 --- a/raltool/src/generate/device.rs +++ b/raltool/src/generate/device.rs @@ -115,6 +115,12 @@ pub fn render(_opts: &super::Options, _ir: &IR, d: &Device) -> Result Self { Instance::new(#name) } @@ -152,6 +158,12 @@ name."# impl crate::private::Sealed for #name {} impl crate::Valid for #name {} impl #name { + /// Acquire a vaild, but possibly aliased, instance. + /// + /// # Safety + /// + /// See [the struct-level safety documentation](crate::Instance). + #[inline] pub const unsafe fn instance() -> Self { Instance::new(#name) } diff --git a/raltool/src/generate/mod.rs b/raltool/src/generate/mod.rs index 658428acf735..c029c8e49ff2 100644 --- a/raltool/src/generate/mod.rs +++ b/raltool/src/generate/mod.rs @@ -141,33 +141,96 @@ pub fn render(ir: &IR, opts: &Options) -> Result<()> { root.items.extend(quote!( #![no_std] - #![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] + #![allow(non_camel_case_types, non_snake_case, non_upper_case_globals, clippy::self_named_constructors, clippy::module_inception)] pub use ral_registers::{RWRegister, RORegister, WORegister, read_reg, write_reg, modify_reg}; + /// An owned peripheral of type `T`, instance `N`. + /// + /// Fabricating an `Instance` is always `unsafe`. An owner of an + /// `Instance` may assume that + /// + /// - the underlying pointer points to a static register block of type `T`. + /// - the instance number `N` properly describes the peripheral instance. + /// - they own _all_ registers pointed at by `T`. + /// + /// Owners use this guarantee to safely access the peripheral registers. + /// However, nothing guarantees any of these except for your diligence. + /// + /// Constructing an `Instance` is zero cost. Additionally, `Instance` is transparent + /// and amenable to null-pointer optimizations. + /// + /// See the package-level documentation for more information on fabricating + /// instances. + /// + /// # Safety of `new()`. + /// + /// By calling `new()`, you claim + /// + /// 1. `ptr` points to static memory that can be described by a type `T`. + /// 2. The instance number `N` correctly describes `ptr`. + /// 3. You are becoming the sole owner of this instance. + /// + /// # Safety of `instance()` + /// + /// The various `instance()` methods handle safety concerns 1 and 2 from `new()`. + /// By their construction, each `instance()` implementation provides a pointer to valid + /// peripheral memory, and associates the correct `N` with that pointer. Therefore, + /// you're only responsible for ensuring safety concern 3 from `new()`. + #[repr(transparent)] pub struct Instance { - ptr: *const T, + ptr: core::ptr::NonNull, } impl core::ops::Deref for Instance { type Target = T; + #[inline] fn deref(&self) -> &Self::Target { - unsafe { &*self.ptr } + // Safety: User provided a pointer that points to static MMIO. + // This implies non-null, initialized, aligned, and dereferenceable. + unsafe { self.ptr.as_ref() } } } impl Instance { + /// Create an arbitrary `Instance` from a pointer to `T`. + /// + /// # Safety + /// + /// See [the struct docs](Instance) for the safety contract. + #[inline] pub const unsafe fn new(ptr: *const T) -> Self { - Self { ptr } + // Casting *const _ to *mut _ is OK. The mutable pointer never + // escapes Instance. + Self { ptr: core::ptr::NonNull::new_unchecked(ptr as *mut _) } } } unsafe impl Send for Instance {} + /// The instance number for a peripheral singleton. + /// + /// If your peripheral only has one instance, it's given + /// this number. The CCM peripheral is a good example of + /// a peripheral that uses this constant. + /// + /// See the package documentation for more information on + /// this constant. pub const SOLE_INSTANCE: u8 = 0u8; mod private { pub trait Sealed {} } + + /// Vouches for an `Instance`'s validity. + /// + /// This trait is implemented for all `Instance` supported + /// by your chip. Note that the implementation may change when + /// selecting new chip features. For instance, i.MX RT 1011 chips + /// do not have LPUART 4 through 8. So, `Valid` is _not_ implemented + /// for `lpuart::Instance<4>` through `lpuart::Instance<8>`. + /// + /// See the package documentation for more information on how + /// to use this trait in your APIs. pub trait Valid : private::Sealed {} ));