120ba6a1dSAlexandre Courbot // SPDX-License-Identifier: GPL-2.0 220ba6a1dSAlexandre Courbot 320ba6a1dSAlexandre Courbot //! Macro to define register layout and accessors. 420ba6a1dSAlexandre Courbot //! 520ba6a1dSAlexandre Courbot //! The [`register!`](kernel::io::register!) macro provides an intuitive and readable syntax for 620ba6a1dSAlexandre Courbot //! defining a dedicated type for each register and accessing it using [`Io`](super::Io). Each such 720ba6a1dSAlexandre Courbot //! type comes with its own field accessors that can return an error if a field's value is invalid. 820ba6a1dSAlexandre Courbot //! 920ba6a1dSAlexandre Courbot //! Note: most of the items in this module are public so they can be referenced by the macro, but 1020ba6a1dSAlexandre Courbot //! most are not to be used directly by users. Outside of the `register!` macro itself, the only 1120ba6a1dSAlexandre Courbot //! items you might want to import from this module are [`WithBase`] and [`Array`]. 1220ba6a1dSAlexandre Courbot //! 1320ba6a1dSAlexandre Courbot //! # Simple example 1420ba6a1dSAlexandre Courbot //! 1520ba6a1dSAlexandre Courbot //! ```no_run 1620ba6a1dSAlexandre Courbot //! use kernel::io::register; 1720ba6a1dSAlexandre Courbot //! 1820ba6a1dSAlexandre Courbot //! register! { 1920ba6a1dSAlexandre Courbot //! /// Basic information about the chip. 2020ba6a1dSAlexandre Courbot //! pub BOOT_0(u32) @ 0x00000100 { 2120ba6a1dSAlexandre Courbot //! /// Vendor ID. 2220ba6a1dSAlexandre Courbot //! 15:8 vendor_id; 2320ba6a1dSAlexandre Courbot //! /// Major revision of the chip. 2420ba6a1dSAlexandre Courbot //! 7:4 major_revision; 2520ba6a1dSAlexandre Courbot //! /// Minor revision of the chip. 2620ba6a1dSAlexandre Courbot //! 3:0 minor_revision; 2720ba6a1dSAlexandre Courbot //! } 2820ba6a1dSAlexandre Courbot //! } 2920ba6a1dSAlexandre Courbot //! ``` 3020ba6a1dSAlexandre Courbot //! 3120ba6a1dSAlexandre Courbot //! This defines a 32-bit `BOOT_0` type which can be read from or written to offset `0x100` of an 3220ba6a1dSAlexandre Courbot //! `Io` region, with the described bitfields. For instance, `minor_revision` consists of the 4 3320ba6a1dSAlexandre Courbot //! least significant bits of the type. 3420ba6a1dSAlexandre Courbot //! 3520ba6a1dSAlexandre Courbot //! Fields are instances of [`Bounded`](kernel::num::Bounded) and can be read by calling their 3620ba6a1dSAlexandre Courbot //! getter method, which is named after them. They also have setter methods prefixed with `with_` 3720ba6a1dSAlexandre Courbot //! for runtime values and `with_const_` for constant values. All setters return the updated 3820ba6a1dSAlexandre Courbot //! register value. 3920ba6a1dSAlexandre Courbot //! 4020ba6a1dSAlexandre Courbot //! Fields can also be transparently converted from/to an arbitrary type by using the `=>` and 4120ba6a1dSAlexandre Courbot //! `?=>` syntaxes. 4220ba6a1dSAlexandre Courbot //! 4320ba6a1dSAlexandre Courbot //! If present, doc comments above register or fields definitions are added to the relevant item 4420ba6a1dSAlexandre Courbot //! they document (the register type itself, or the field's setter and getter methods). 4520ba6a1dSAlexandre Courbot //! 4620ba6a1dSAlexandre Courbot //! Note that multiple registers can be defined in a single `register!` invocation. This can be 4720ba6a1dSAlexandre Courbot //! useful to group related registers together. 4820ba6a1dSAlexandre Courbot //! 4920ba6a1dSAlexandre Courbot //! Here is how the register defined above can be used in code: 5020ba6a1dSAlexandre Courbot //! 5120ba6a1dSAlexandre Courbot //! 5220ba6a1dSAlexandre Courbot //! ```no_run 5320ba6a1dSAlexandre Courbot //! use kernel::{ 5420ba6a1dSAlexandre Courbot //! io::{ 5520ba6a1dSAlexandre Courbot //! register, 5620ba6a1dSAlexandre Courbot //! Io, 5720ba6a1dSAlexandre Courbot //! IoLoc, 5820ba6a1dSAlexandre Courbot //! }, 5920ba6a1dSAlexandre Courbot //! num::Bounded, 6020ba6a1dSAlexandre Courbot //! }; 6120ba6a1dSAlexandre Courbot //! # use kernel::io::Mmio; 6220ba6a1dSAlexandre Courbot //! # register! { 6320ba6a1dSAlexandre Courbot //! # pub BOOT_0(u32) @ 0x00000100 { 6420ba6a1dSAlexandre Courbot //! # 15:8 vendor_id; 6520ba6a1dSAlexandre Courbot //! # 7:4 major_revision; 6620ba6a1dSAlexandre Courbot //! # 3:0 minor_revision; 6720ba6a1dSAlexandre Courbot //! # } 6820ba6a1dSAlexandre Courbot //! # } 6920ba6a1dSAlexandre Courbot //! # fn test(io: &Mmio<0x1000>) { 7020ba6a1dSAlexandre Courbot //! # fn obtain_vendor_id() -> u8 { 0xff } 7120ba6a1dSAlexandre Courbot //! 7220ba6a1dSAlexandre Courbot //! // Read from the register's defined offset (0x100). 7320ba6a1dSAlexandre Courbot //! let boot0 = io.read(BOOT_0); 7420ba6a1dSAlexandre Courbot //! pr_info!("chip revision: {}.{}", boot0.major_revision().get(), boot0.minor_revision().get()); 7520ba6a1dSAlexandre Courbot //! 7620ba6a1dSAlexandre Courbot //! // Update some fields and write the new value back. 7720ba6a1dSAlexandre Courbot //! let new_boot0 = boot0 7820ba6a1dSAlexandre Courbot //! // Constant values. 7920ba6a1dSAlexandre Courbot //! .with_const_major_revision::<3>() 8020ba6a1dSAlexandre Courbot //! .with_const_minor_revision::<10>() 8120ba6a1dSAlexandre Courbot //! // Runtime value. 8220ba6a1dSAlexandre Courbot //! .with_vendor_id(obtain_vendor_id()); 83*9a52a8f5SAlexandre Courbot //! io.write_reg(new_boot0); 8420ba6a1dSAlexandre Courbot //! 8520ba6a1dSAlexandre Courbot //! // Or, build a new value from zero and write it: 86*9a52a8f5SAlexandre Courbot //! io.write_reg(BOOT_0::zeroed() 8720ba6a1dSAlexandre Courbot //! .with_const_major_revision::<3>() 8820ba6a1dSAlexandre Courbot //! .with_const_minor_revision::<10>() 8920ba6a1dSAlexandre Courbot //! .with_vendor_id(obtain_vendor_id()) 9020ba6a1dSAlexandre Courbot //! ); 9120ba6a1dSAlexandre Courbot //! 9220ba6a1dSAlexandre Courbot //! // Or, read and update the register in a single step. 9320ba6a1dSAlexandre Courbot //! io.update(BOOT_0, |r| r 9420ba6a1dSAlexandre Courbot //! .with_const_major_revision::<3>() 9520ba6a1dSAlexandre Courbot //! .with_const_minor_revision::<10>() 9620ba6a1dSAlexandre Courbot //! .with_vendor_id(obtain_vendor_id()) 9720ba6a1dSAlexandre Courbot //! ); 9820ba6a1dSAlexandre Courbot //! 9920ba6a1dSAlexandre Courbot //! // Constant values can also be built using the const setters. 10020ba6a1dSAlexandre Courbot //! const V: BOOT_0 = pin_init::zeroed::<BOOT_0>() 10120ba6a1dSAlexandre Courbot //! .with_const_major_revision::<3>() 10220ba6a1dSAlexandre Courbot //! .with_const_minor_revision::<10>(); 10320ba6a1dSAlexandre Courbot //! # } 10420ba6a1dSAlexandre Courbot //! ``` 10520ba6a1dSAlexandre Courbot //! 10620ba6a1dSAlexandre Courbot //! For more extensive documentation about how to define registers, see the 10720ba6a1dSAlexandre Courbot //! [`register!`](kernel::io::register!) macro. 10820ba6a1dSAlexandre Courbot 10920ba6a1dSAlexandre Courbot use core::marker::PhantomData; 11020ba6a1dSAlexandre Courbot 11120ba6a1dSAlexandre Courbot use crate::io::IoLoc; 11220ba6a1dSAlexandre Courbot 11320ba6a1dSAlexandre Courbot use kernel::build_assert; 11420ba6a1dSAlexandre Courbot 11520ba6a1dSAlexandre Courbot /// Trait implemented by all registers. 11620ba6a1dSAlexandre Courbot pub trait Register: Sized { 11720ba6a1dSAlexandre Courbot /// Backing primitive type of the register. 11820ba6a1dSAlexandre Courbot type Storage: Into<Self> + From<Self>; 11920ba6a1dSAlexandre Courbot 12020ba6a1dSAlexandre Courbot /// Start offset of the register. 12120ba6a1dSAlexandre Courbot /// 12220ba6a1dSAlexandre Courbot /// The interpretation of this offset depends on the type of the register. 12320ba6a1dSAlexandre Courbot const OFFSET: usize; 12420ba6a1dSAlexandre Courbot } 12520ba6a1dSAlexandre Courbot 12620ba6a1dSAlexandre Courbot /// Trait implemented by registers with a fixed offset. 12720ba6a1dSAlexandre Courbot pub trait FixedRegister: Register {} 12820ba6a1dSAlexandre Courbot 12920ba6a1dSAlexandre Courbot /// Allows `()` to be used as the `location` parameter of [`Io::write`](super::Io::write) when 13020ba6a1dSAlexandre Courbot /// passing a [`FixedRegister`] value. 13120ba6a1dSAlexandre Courbot impl<T> IoLoc<T> for () 13220ba6a1dSAlexandre Courbot where 13320ba6a1dSAlexandre Courbot T: FixedRegister, 13420ba6a1dSAlexandre Courbot { 13520ba6a1dSAlexandre Courbot type IoType = T::Storage; 13620ba6a1dSAlexandre Courbot 13720ba6a1dSAlexandre Courbot #[inline(always)] 13820ba6a1dSAlexandre Courbot fn offset(self) -> usize { 13920ba6a1dSAlexandre Courbot T::OFFSET 14020ba6a1dSAlexandre Courbot } 14120ba6a1dSAlexandre Courbot } 14220ba6a1dSAlexandre Courbot 14320ba6a1dSAlexandre Courbot /// A [`FixedRegister`] carries its location in its type. Thus `FixedRegister` values can be used 14420ba6a1dSAlexandre Courbot /// as an [`IoLoc`]. 14520ba6a1dSAlexandre Courbot impl<T> IoLoc<T> for T 14620ba6a1dSAlexandre Courbot where 14720ba6a1dSAlexandre Courbot T: FixedRegister, 14820ba6a1dSAlexandre Courbot { 14920ba6a1dSAlexandre Courbot type IoType = T::Storage; 15020ba6a1dSAlexandre Courbot 15120ba6a1dSAlexandre Courbot #[inline(always)] 15220ba6a1dSAlexandre Courbot fn offset(self) -> usize { 15320ba6a1dSAlexandre Courbot T::OFFSET 15420ba6a1dSAlexandre Courbot } 15520ba6a1dSAlexandre Courbot } 15620ba6a1dSAlexandre Courbot 15720ba6a1dSAlexandre Courbot /// Location of a fixed register. 15820ba6a1dSAlexandre Courbot pub struct FixedRegisterLoc<T: FixedRegister>(PhantomData<T>); 15920ba6a1dSAlexandre Courbot 16020ba6a1dSAlexandre Courbot impl<T: FixedRegister> FixedRegisterLoc<T> { 16120ba6a1dSAlexandre Courbot /// Returns the location of `T`. 16220ba6a1dSAlexandre Courbot #[inline(always)] 16320ba6a1dSAlexandre Courbot // We do not implement `Default` so we can be const. 16420ba6a1dSAlexandre Courbot #[expect(clippy::new_without_default)] 16520ba6a1dSAlexandre Courbot pub const fn new() -> Self { 16620ba6a1dSAlexandre Courbot Self(PhantomData) 16720ba6a1dSAlexandre Courbot } 16820ba6a1dSAlexandre Courbot } 16920ba6a1dSAlexandre Courbot 17020ba6a1dSAlexandre Courbot impl<T> IoLoc<T> for FixedRegisterLoc<T> 17120ba6a1dSAlexandre Courbot where 17220ba6a1dSAlexandre Courbot T: FixedRegister, 17320ba6a1dSAlexandre Courbot { 17420ba6a1dSAlexandre Courbot type IoType = T::Storage; 17520ba6a1dSAlexandre Courbot 17620ba6a1dSAlexandre Courbot #[inline(always)] 17720ba6a1dSAlexandre Courbot fn offset(self) -> usize { 17820ba6a1dSAlexandre Courbot T::OFFSET 17920ba6a1dSAlexandre Courbot } 18020ba6a1dSAlexandre Courbot } 18120ba6a1dSAlexandre Courbot 18220ba6a1dSAlexandre Courbot /// Trait providing a base address to be added to the offset of a relative register to obtain 18320ba6a1dSAlexandre Courbot /// its actual offset. 18420ba6a1dSAlexandre Courbot /// 18520ba6a1dSAlexandre Courbot /// The `T` generic argument is used to distinguish which base to use, in case a type provides 18620ba6a1dSAlexandre Courbot /// several bases. It is given to the `register!` macro to restrict the use of the register to 18720ba6a1dSAlexandre Courbot /// implementors of this particular variant. 18820ba6a1dSAlexandre Courbot pub trait RegisterBase<T> { 18920ba6a1dSAlexandre Courbot /// Base address to which register offsets are added. 19020ba6a1dSAlexandre Courbot const BASE: usize; 19120ba6a1dSAlexandre Courbot } 19220ba6a1dSAlexandre Courbot 19320ba6a1dSAlexandre Courbot /// Trait implemented by all registers that are relative to a base. 19420ba6a1dSAlexandre Courbot pub trait WithBase { 19520ba6a1dSAlexandre Courbot /// Family of bases applicable to this register. 19620ba6a1dSAlexandre Courbot type BaseFamily; 19720ba6a1dSAlexandre Courbot 19820ba6a1dSAlexandre Courbot /// Returns the absolute location of this type when using `B` as its base. 19920ba6a1dSAlexandre Courbot #[inline(always)] 20020ba6a1dSAlexandre Courbot fn of<B: RegisterBase<Self::BaseFamily>>() -> RelativeRegisterLoc<Self, B> 20120ba6a1dSAlexandre Courbot where 20220ba6a1dSAlexandre Courbot Self: Register, 20320ba6a1dSAlexandre Courbot { 20420ba6a1dSAlexandre Courbot RelativeRegisterLoc::new() 20520ba6a1dSAlexandre Courbot } 20620ba6a1dSAlexandre Courbot } 20720ba6a1dSAlexandre Courbot 20820ba6a1dSAlexandre Courbot /// Trait implemented by relative registers. 20920ba6a1dSAlexandre Courbot pub trait RelativeRegister: Register + WithBase {} 21020ba6a1dSAlexandre Courbot 21120ba6a1dSAlexandre Courbot /// Location of a relative register. 21220ba6a1dSAlexandre Courbot /// 21320ba6a1dSAlexandre Courbot /// This can either be an immediately accessible regular [`RelativeRegister`], or a 21420ba6a1dSAlexandre Courbot /// [`RelativeRegisterArray`] that needs one additional resolution through 21520ba6a1dSAlexandre Courbot /// [`RelativeRegisterLoc::at`]. 21620ba6a1dSAlexandre Courbot pub struct RelativeRegisterLoc<T: WithBase, B: ?Sized>(PhantomData<T>, PhantomData<B>); 21720ba6a1dSAlexandre Courbot 21820ba6a1dSAlexandre Courbot impl<T, B> RelativeRegisterLoc<T, B> 21920ba6a1dSAlexandre Courbot where 22020ba6a1dSAlexandre Courbot T: Register + WithBase, 22120ba6a1dSAlexandre Courbot B: RegisterBase<T::BaseFamily> + ?Sized, 22220ba6a1dSAlexandre Courbot { 22320ba6a1dSAlexandre Courbot /// Returns the location of a relative register or register array. 22420ba6a1dSAlexandre Courbot #[inline(always)] 22520ba6a1dSAlexandre Courbot // We do not implement `Default` so we can be const. 22620ba6a1dSAlexandre Courbot #[expect(clippy::new_without_default)] 22720ba6a1dSAlexandre Courbot pub const fn new() -> Self { 22820ba6a1dSAlexandre Courbot Self(PhantomData, PhantomData) 22920ba6a1dSAlexandre Courbot } 23020ba6a1dSAlexandre Courbot 23120ba6a1dSAlexandre Courbot // Returns the absolute offset of the relative register using base `B`. 23220ba6a1dSAlexandre Courbot // 23320ba6a1dSAlexandre Courbot // This is implemented as a private const method so it can be reused by the [`IoLoc`] 23420ba6a1dSAlexandre Courbot // implementations of both [`RelativeRegisterLoc`] and [`RelativeRegisterArrayLoc`]. 23520ba6a1dSAlexandre Courbot #[inline] 23620ba6a1dSAlexandre Courbot const fn offset(self) -> usize { 23720ba6a1dSAlexandre Courbot B::BASE + T::OFFSET 23820ba6a1dSAlexandre Courbot } 23920ba6a1dSAlexandre Courbot } 24020ba6a1dSAlexandre Courbot 24120ba6a1dSAlexandre Courbot impl<T, B> IoLoc<T> for RelativeRegisterLoc<T, B> 24220ba6a1dSAlexandre Courbot where 24320ba6a1dSAlexandre Courbot T: RelativeRegister, 24420ba6a1dSAlexandre Courbot B: RegisterBase<T::BaseFamily> + ?Sized, 24520ba6a1dSAlexandre Courbot { 24620ba6a1dSAlexandre Courbot type IoType = T::Storage; 24720ba6a1dSAlexandre Courbot 24820ba6a1dSAlexandre Courbot #[inline(always)] 24920ba6a1dSAlexandre Courbot fn offset(self) -> usize { 25020ba6a1dSAlexandre Courbot RelativeRegisterLoc::offset(self) 25120ba6a1dSAlexandre Courbot } 25220ba6a1dSAlexandre Courbot } 25320ba6a1dSAlexandre Courbot 25420ba6a1dSAlexandre Courbot /// Trait implemented by arrays of registers. 25520ba6a1dSAlexandre Courbot pub trait RegisterArray: Register { 25620ba6a1dSAlexandre Courbot /// Number of elements in the registers array. 25720ba6a1dSAlexandre Courbot const SIZE: usize; 25820ba6a1dSAlexandre Courbot /// Number of bytes between the start of elements in the registers array. 25920ba6a1dSAlexandre Courbot const STRIDE: usize; 26020ba6a1dSAlexandre Courbot } 26120ba6a1dSAlexandre Courbot 26220ba6a1dSAlexandre Courbot /// Location of an array register. 26320ba6a1dSAlexandre Courbot pub struct RegisterArrayLoc<T: RegisterArray>(usize, PhantomData<T>); 26420ba6a1dSAlexandre Courbot 26520ba6a1dSAlexandre Courbot impl<T: RegisterArray> RegisterArrayLoc<T> { 26620ba6a1dSAlexandre Courbot /// Returns the location of register `T` at position `idx`, with build-time validation. 26720ba6a1dSAlexandre Courbot #[inline(always)] 26820ba6a1dSAlexandre Courbot pub fn new(idx: usize) -> Self { 26920ba6a1dSAlexandre Courbot build_assert!(idx < T::SIZE); 27020ba6a1dSAlexandre Courbot 27120ba6a1dSAlexandre Courbot Self(idx, PhantomData) 27220ba6a1dSAlexandre Courbot } 27320ba6a1dSAlexandre Courbot 27420ba6a1dSAlexandre Courbot /// Attempts to return the location of register `T` at position `idx`, with runtime validation. 27520ba6a1dSAlexandre Courbot #[inline(always)] 27620ba6a1dSAlexandre Courbot pub fn try_new(idx: usize) -> Option<Self> { 27720ba6a1dSAlexandre Courbot if idx < T::SIZE { 27820ba6a1dSAlexandre Courbot Some(Self(idx, PhantomData)) 27920ba6a1dSAlexandre Courbot } else { 28020ba6a1dSAlexandre Courbot None 28120ba6a1dSAlexandre Courbot } 28220ba6a1dSAlexandre Courbot } 28320ba6a1dSAlexandre Courbot } 28420ba6a1dSAlexandre Courbot 28520ba6a1dSAlexandre Courbot impl<T> IoLoc<T> for RegisterArrayLoc<T> 28620ba6a1dSAlexandre Courbot where 28720ba6a1dSAlexandre Courbot T: RegisterArray, 28820ba6a1dSAlexandre Courbot { 28920ba6a1dSAlexandre Courbot type IoType = T::Storage; 29020ba6a1dSAlexandre Courbot 29120ba6a1dSAlexandre Courbot #[inline(always)] 29220ba6a1dSAlexandre Courbot fn offset(self) -> usize { 29320ba6a1dSAlexandre Courbot T::OFFSET + self.0 * T::STRIDE 29420ba6a1dSAlexandre Courbot } 29520ba6a1dSAlexandre Courbot } 29620ba6a1dSAlexandre Courbot 29720ba6a1dSAlexandre Courbot /// Trait providing location builders for [`RegisterArray`]s. 29820ba6a1dSAlexandre Courbot pub trait Array { 29920ba6a1dSAlexandre Courbot /// Returns the location of the register at position `idx`, with build-time validation. 30020ba6a1dSAlexandre Courbot #[inline(always)] 30120ba6a1dSAlexandre Courbot fn at(idx: usize) -> RegisterArrayLoc<Self> 30220ba6a1dSAlexandre Courbot where 30320ba6a1dSAlexandre Courbot Self: RegisterArray, 30420ba6a1dSAlexandre Courbot { 30520ba6a1dSAlexandre Courbot RegisterArrayLoc::new(idx) 30620ba6a1dSAlexandre Courbot } 30720ba6a1dSAlexandre Courbot 30820ba6a1dSAlexandre Courbot /// Returns the location of the register at position `idx`, with runtime validation. 30920ba6a1dSAlexandre Courbot #[inline(always)] 31020ba6a1dSAlexandre Courbot fn try_at(idx: usize) -> Option<RegisterArrayLoc<Self>> 31120ba6a1dSAlexandre Courbot where 31220ba6a1dSAlexandre Courbot Self: RegisterArray, 31320ba6a1dSAlexandre Courbot { 31420ba6a1dSAlexandre Courbot RegisterArrayLoc::try_new(idx) 31520ba6a1dSAlexandre Courbot } 31620ba6a1dSAlexandre Courbot } 31720ba6a1dSAlexandre Courbot 31820ba6a1dSAlexandre Courbot /// Trait implemented by arrays of relative registers. 31920ba6a1dSAlexandre Courbot pub trait RelativeRegisterArray: RegisterArray + WithBase {} 32020ba6a1dSAlexandre Courbot 32120ba6a1dSAlexandre Courbot /// Location of a relative array register. 32220ba6a1dSAlexandre Courbot pub struct RelativeRegisterArrayLoc< 32320ba6a1dSAlexandre Courbot T: RelativeRegisterArray, 32420ba6a1dSAlexandre Courbot B: RegisterBase<T::BaseFamily> + ?Sized, 32520ba6a1dSAlexandre Courbot >(RelativeRegisterLoc<T, B>, usize); 32620ba6a1dSAlexandre Courbot 32720ba6a1dSAlexandre Courbot impl<T, B> RelativeRegisterArrayLoc<T, B> 32820ba6a1dSAlexandre Courbot where 32920ba6a1dSAlexandre Courbot T: RelativeRegisterArray, 33020ba6a1dSAlexandre Courbot B: RegisterBase<T::BaseFamily> + ?Sized, 33120ba6a1dSAlexandre Courbot { 33220ba6a1dSAlexandre Courbot /// Returns the location of register `T` from the base `B` at index `idx`, with build-time 33320ba6a1dSAlexandre Courbot /// validation. 33420ba6a1dSAlexandre Courbot #[inline(always)] 33520ba6a1dSAlexandre Courbot pub fn new(idx: usize) -> Self { 33620ba6a1dSAlexandre Courbot build_assert!(idx < T::SIZE); 33720ba6a1dSAlexandre Courbot 33820ba6a1dSAlexandre Courbot Self(RelativeRegisterLoc::new(), idx) 33920ba6a1dSAlexandre Courbot } 34020ba6a1dSAlexandre Courbot 34120ba6a1dSAlexandre Courbot /// Attempts to return the location of register `T` from the base `B` at index `idx`, with 34220ba6a1dSAlexandre Courbot /// runtime validation. 34320ba6a1dSAlexandre Courbot #[inline(always)] 34420ba6a1dSAlexandre Courbot pub fn try_new(idx: usize) -> Option<Self> { 34520ba6a1dSAlexandre Courbot if idx < T::SIZE { 34620ba6a1dSAlexandre Courbot Some(Self(RelativeRegisterLoc::new(), idx)) 34720ba6a1dSAlexandre Courbot } else { 34820ba6a1dSAlexandre Courbot None 34920ba6a1dSAlexandre Courbot } 35020ba6a1dSAlexandre Courbot } 35120ba6a1dSAlexandre Courbot } 35220ba6a1dSAlexandre Courbot 35320ba6a1dSAlexandre Courbot /// Methods exclusive to [`RelativeRegisterLoc`]s created with a [`RelativeRegisterArray`]. 35420ba6a1dSAlexandre Courbot impl<T, B> RelativeRegisterLoc<T, B> 35520ba6a1dSAlexandre Courbot where 35620ba6a1dSAlexandre Courbot T: RelativeRegisterArray, 35720ba6a1dSAlexandre Courbot B: RegisterBase<T::BaseFamily> + ?Sized, 35820ba6a1dSAlexandre Courbot { 35920ba6a1dSAlexandre Courbot /// Returns the location of the register at position `idx`, with build-time validation. 36020ba6a1dSAlexandre Courbot #[inline(always)] 36120ba6a1dSAlexandre Courbot pub fn at(self, idx: usize) -> RelativeRegisterArrayLoc<T, B> { 36220ba6a1dSAlexandre Courbot RelativeRegisterArrayLoc::new(idx) 36320ba6a1dSAlexandre Courbot } 36420ba6a1dSAlexandre Courbot 36520ba6a1dSAlexandre Courbot /// Returns the location of the register at position `idx`, with runtime validation. 36620ba6a1dSAlexandre Courbot #[inline(always)] 36720ba6a1dSAlexandre Courbot pub fn try_at(self, idx: usize) -> Option<RelativeRegisterArrayLoc<T, B>> { 36820ba6a1dSAlexandre Courbot RelativeRegisterArrayLoc::try_new(idx) 36920ba6a1dSAlexandre Courbot } 37020ba6a1dSAlexandre Courbot } 37120ba6a1dSAlexandre Courbot 37220ba6a1dSAlexandre Courbot impl<T, B> IoLoc<T> for RelativeRegisterArrayLoc<T, B> 37320ba6a1dSAlexandre Courbot where 37420ba6a1dSAlexandre Courbot T: RelativeRegisterArray, 37520ba6a1dSAlexandre Courbot B: RegisterBase<T::BaseFamily> + ?Sized, 37620ba6a1dSAlexandre Courbot { 37720ba6a1dSAlexandre Courbot type IoType = T::Storage; 37820ba6a1dSAlexandre Courbot 37920ba6a1dSAlexandre Courbot #[inline(always)] 38020ba6a1dSAlexandre Courbot fn offset(self) -> usize { 38120ba6a1dSAlexandre Courbot self.0.offset() + self.1 * T::STRIDE 38220ba6a1dSAlexandre Courbot } 38320ba6a1dSAlexandre Courbot } 38420ba6a1dSAlexandre Courbot 385*9a52a8f5SAlexandre Courbot /// Trait implemented by items that contain both a register value and the absolute I/O location at 386*9a52a8f5SAlexandre Courbot /// which to write it. 387*9a52a8f5SAlexandre Courbot /// 388*9a52a8f5SAlexandre Courbot /// Implementors can be used with [`Io::write_reg`](super::Io::write_reg). 389*9a52a8f5SAlexandre Courbot pub trait LocatedRegister { 390*9a52a8f5SAlexandre Courbot /// Register value to write. 391*9a52a8f5SAlexandre Courbot type Value: Register; 392*9a52a8f5SAlexandre Courbot /// Full location information at which to write the value. 393*9a52a8f5SAlexandre Courbot type Location: IoLoc<Self::Value>; 394*9a52a8f5SAlexandre Courbot 395*9a52a8f5SAlexandre Courbot /// Consumes `self` and returns a `(location, value)` tuple describing a valid I/O write 396*9a52a8f5SAlexandre Courbot /// operation. 397*9a52a8f5SAlexandre Courbot fn into_io_op(self) -> (Self::Location, Self::Value); 398*9a52a8f5SAlexandre Courbot } 399*9a52a8f5SAlexandre Courbot 400*9a52a8f5SAlexandre Courbot impl<T> LocatedRegister for T 401*9a52a8f5SAlexandre Courbot where 402*9a52a8f5SAlexandre Courbot T: FixedRegister, 403*9a52a8f5SAlexandre Courbot { 404*9a52a8f5SAlexandre Courbot type Location = FixedRegisterLoc<Self::Value>; 405*9a52a8f5SAlexandre Courbot type Value = T; 406*9a52a8f5SAlexandre Courbot 407*9a52a8f5SAlexandre Courbot #[inline(always)] 408*9a52a8f5SAlexandre Courbot fn into_io_op(self) -> (FixedRegisterLoc<T>, T) { 409*9a52a8f5SAlexandre Courbot (FixedRegisterLoc::new(), self) 410*9a52a8f5SAlexandre Courbot } 411*9a52a8f5SAlexandre Courbot } 412*9a52a8f5SAlexandre Courbot 41320ba6a1dSAlexandre Courbot /// Defines a dedicated type for a register, including getter and setter methods for its fields and 41420ba6a1dSAlexandre Courbot /// methods to read and write it from an [`Io`](kernel::io::Io) region. 41520ba6a1dSAlexandre Courbot /// 41620ba6a1dSAlexandre Courbot /// This documentation focuses on how to declare registers. See the [module-level 41720ba6a1dSAlexandre Courbot /// documentation](mod@kernel::io::register) for examples of how to access them. 41820ba6a1dSAlexandre Courbot /// 41920ba6a1dSAlexandre Courbot /// There are 4 possible kinds of registers: fixed offset registers, relative registers, arrays of 42020ba6a1dSAlexandre Courbot /// registers, and relative arrays of registers. 42120ba6a1dSAlexandre Courbot /// 42220ba6a1dSAlexandre Courbot /// ## Fixed offset registers 42320ba6a1dSAlexandre Courbot /// 42420ba6a1dSAlexandre Courbot /// These are the simplest kind of registers. Their location is simply an offset inside the I/O 42520ba6a1dSAlexandre Courbot /// region. For instance: 42620ba6a1dSAlexandre Courbot /// 42720ba6a1dSAlexandre Courbot /// ```ignore 42820ba6a1dSAlexandre Courbot /// register! { 42920ba6a1dSAlexandre Courbot /// pub FIXED_REG(u16) @ 0x80 { 43020ba6a1dSAlexandre Courbot /// ... 43120ba6a1dSAlexandre Courbot /// } 43220ba6a1dSAlexandre Courbot /// } 43320ba6a1dSAlexandre Courbot /// ``` 43420ba6a1dSAlexandre Courbot /// 43520ba6a1dSAlexandre Courbot /// This creates a 16-bit register named `FIXED_REG` located at offset `0x80` of an I/O region. 43620ba6a1dSAlexandre Courbot /// 43720ba6a1dSAlexandre Courbot /// These registers' location can be built simply by referencing their name: 43820ba6a1dSAlexandre Courbot /// 43920ba6a1dSAlexandre Courbot /// ```no_run 44020ba6a1dSAlexandre Courbot /// use kernel::{ 44120ba6a1dSAlexandre Courbot /// io::{ 44220ba6a1dSAlexandre Courbot /// register, 44320ba6a1dSAlexandre Courbot /// Io, 44420ba6a1dSAlexandre Courbot /// }, 44520ba6a1dSAlexandre Courbot /// }; 44620ba6a1dSAlexandre Courbot /// # use kernel::io::Mmio; 44720ba6a1dSAlexandre Courbot /// 44820ba6a1dSAlexandre Courbot /// register! { 44920ba6a1dSAlexandre Courbot /// FIXED_REG(u32) @ 0x100 { 45020ba6a1dSAlexandre Courbot /// 16:8 high_byte; 45120ba6a1dSAlexandre Courbot /// 7:0 low_byte; 45220ba6a1dSAlexandre Courbot /// } 45320ba6a1dSAlexandre Courbot /// } 45420ba6a1dSAlexandre Courbot /// 45520ba6a1dSAlexandre Courbot /// # fn test(io: &Mmio<0x1000>) { 45620ba6a1dSAlexandre Courbot /// let val = io.read(FIXED_REG); 45720ba6a1dSAlexandre Courbot /// 45820ba6a1dSAlexandre Courbot /// // Write from an already-existing value. 45920ba6a1dSAlexandre Courbot /// io.write(FIXED_REG, val.with_low_byte(0xff)); 46020ba6a1dSAlexandre Courbot /// 46120ba6a1dSAlexandre Courbot /// // Create a register value from scratch. 46220ba6a1dSAlexandre Courbot /// let val2 = FIXED_REG::zeroed().with_high_byte(0x80); 46320ba6a1dSAlexandre Courbot /// 46420ba6a1dSAlexandre Courbot /// // The location of fixed offset registers is already contained in their type. Thus, the 46520ba6a1dSAlexandre Courbot /// // `location` argument of `Io::write` is technically redundant and can be replaced by `()`. 46620ba6a1dSAlexandre Courbot /// io.write((), val2); 467*9a52a8f5SAlexandre Courbot /// 468*9a52a8f5SAlexandre Courbot /// // Or, the single-argument `Io::write_reg` can be used. 469*9a52a8f5SAlexandre Courbot /// io.write_reg(val2); 47020ba6a1dSAlexandre Courbot /// # } 47120ba6a1dSAlexandre Courbot /// 47220ba6a1dSAlexandre Courbot /// ``` 47320ba6a1dSAlexandre Courbot /// 47420ba6a1dSAlexandre Courbot /// It is possible to create an alias of an existing register with new field definitions by using 47520ba6a1dSAlexandre Courbot /// the `=> ALIAS` syntax. This is useful for cases where a register's interpretation depends on 47620ba6a1dSAlexandre Courbot /// the context: 47720ba6a1dSAlexandre Courbot /// 47820ba6a1dSAlexandre Courbot /// ```no_run 47920ba6a1dSAlexandre Courbot /// use kernel::io::register; 48020ba6a1dSAlexandre Courbot /// 48120ba6a1dSAlexandre Courbot /// register! { 48220ba6a1dSAlexandre Courbot /// /// Scratch register. 48320ba6a1dSAlexandre Courbot /// pub SCRATCH(u32) @ 0x00000200 { 48420ba6a1dSAlexandre Courbot /// 31:0 value; 48520ba6a1dSAlexandre Courbot /// } 48620ba6a1dSAlexandre Courbot /// 48720ba6a1dSAlexandre Courbot /// /// Boot status of the firmware. 48820ba6a1dSAlexandre Courbot /// pub SCRATCH_BOOT_STATUS(u32) => SCRATCH { 48920ba6a1dSAlexandre Courbot /// 0:0 completed; 49020ba6a1dSAlexandre Courbot /// } 49120ba6a1dSAlexandre Courbot /// } 49220ba6a1dSAlexandre Courbot /// ``` 49320ba6a1dSAlexandre Courbot /// 49420ba6a1dSAlexandre Courbot /// In this example, `SCRATCH_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while providing 49520ba6a1dSAlexandre Courbot /// its own `completed` field. 49620ba6a1dSAlexandre Courbot /// 49720ba6a1dSAlexandre Courbot /// ## Relative registers 49820ba6a1dSAlexandre Courbot /// 49920ba6a1dSAlexandre Courbot /// Relative registers can be instantiated several times at a relative offset of a group of bases. 50020ba6a1dSAlexandre Courbot /// For instance, imagine the following I/O space: 50120ba6a1dSAlexandre Courbot /// 50220ba6a1dSAlexandre Courbot /// ```text 50320ba6a1dSAlexandre Courbot /// +-----------------------------+ 50420ba6a1dSAlexandre Courbot /// | ... | 50520ba6a1dSAlexandre Courbot /// | | 50620ba6a1dSAlexandre Courbot /// 0x100--->+------------CPU0-------------+ 50720ba6a1dSAlexandre Courbot /// | | 50820ba6a1dSAlexandre Courbot /// 0x110--->+-----------------------------+ 50920ba6a1dSAlexandre Courbot /// | CPU_CTL | 51020ba6a1dSAlexandre Courbot /// +-----------------------------+ 51120ba6a1dSAlexandre Courbot /// | ... | 51220ba6a1dSAlexandre Courbot /// | | 51320ba6a1dSAlexandre Courbot /// | | 51420ba6a1dSAlexandre Courbot /// 0x200--->+------------CPU1-------------+ 51520ba6a1dSAlexandre Courbot /// | | 51620ba6a1dSAlexandre Courbot /// 0x210--->+-----------------------------+ 51720ba6a1dSAlexandre Courbot /// | CPU_CTL | 51820ba6a1dSAlexandre Courbot /// +-----------------------------+ 51920ba6a1dSAlexandre Courbot /// | ... | 52020ba6a1dSAlexandre Courbot /// +-----------------------------+ 52120ba6a1dSAlexandre Courbot /// ``` 52220ba6a1dSAlexandre Courbot /// 52320ba6a1dSAlexandre Courbot /// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O 52420ba6a1dSAlexandre Courbot /// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define 52520ba6a1dSAlexandre Courbot /// them twice and would prefer a way to select which one to use from a single definition. 52620ba6a1dSAlexandre Courbot /// 52720ba6a1dSAlexandre Courbot /// This can be done using the `Base + Offset` syntax when specifying the register's address: 52820ba6a1dSAlexandre Courbot /// 52920ba6a1dSAlexandre Courbot /// ```ignore 53020ba6a1dSAlexandre Courbot /// register! { 53120ba6a1dSAlexandre Courbot /// pub RELATIVE_REG(u32) @ Base + 0x80 { 53220ba6a1dSAlexandre Courbot /// ... 53320ba6a1dSAlexandre Courbot /// } 53420ba6a1dSAlexandre Courbot /// } 53520ba6a1dSAlexandre Courbot /// ``` 53620ba6a1dSAlexandre Courbot /// 53720ba6a1dSAlexandre Courbot /// This creates a register with an offset of `0x80` from a given base. 53820ba6a1dSAlexandre Courbot /// 53920ba6a1dSAlexandre Courbot /// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the 54020ba6a1dSAlexandre Courbot /// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for 54120ba6a1dSAlexandre Courbot /// this register needs to implement `RegisterBase<Base>`. 54220ba6a1dSAlexandre Courbot /// 54320ba6a1dSAlexandre Courbot /// The location of relative registers can be built using the [`WithBase::of`] method to specify 54420ba6a1dSAlexandre Courbot /// its base. All relative registers implement [`WithBase`]. 54520ba6a1dSAlexandre Courbot /// 54620ba6a1dSAlexandre Courbot /// Here is the above layout translated into code: 54720ba6a1dSAlexandre Courbot /// 54820ba6a1dSAlexandre Courbot /// ```no_run 54920ba6a1dSAlexandre Courbot /// use kernel::{ 55020ba6a1dSAlexandre Courbot /// io::{ 55120ba6a1dSAlexandre Courbot /// register, 55220ba6a1dSAlexandre Courbot /// register::{ 55320ba6a1dSAlexandre Courbot /// RegisterBase, 55420ba6a1dSAlexandre Courbot /// WithBase, 55520ba6a1dSAlexandre Courbot /// }, 55620ba6a1dSAlexandre Courbot /// Io, 55720ba6a1dSAlexandre Courbot /// }, 55820ba6a1dSAlexandre Courbot /// }; 55920ba6a1dSAlexandre Courbot /// # use kernel::io::Mmio; 56020ba6a1dSAlexandre Courbot /// 56120ba6a1dSAlexandre Courbot /// // Type used to identify the base. 56220ba6a1dSAlexandre Courbot /// pub struct CpuCtlBase; 56320ba6a1dSAlexandre Courbot /// 56420ba6a1dSAlexandre Courbot /// // ZST describing `CPU0`. 56520ba6a1dSAlexandre Courbot /// struct Cpu0; 56620ba6a1dSAlexandre Courbot /// impl RegisterBase<CpuCtlBase> for Cpu0 { 56720ba6a1dSAlexandre Courbot /// const BASE: usize = 0x100; 56820ba6a1dSAlexandre Courbot /// } 56920ba6a1dSAlexandre Courbot /// 57020ba6a1dSAlexandre Courbot /// // ZST describing `CPU1`. 57120ba6a1dSAlexandre Courbot /// struct Cpu1; 57220ba6a1dSAlexandre Courbot /// impl RegisterBase<CpuCtlBase> for Cpu1 { 57320ba6a1dSAlexandre Courbot /// const BASE: usize = 0x200; 57420ba6a1dSAlexandre Courbot /// } 57520ba6a1dSAlexandre Courbot /// 57620ba6a1dSAlexandre Courbot /// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`. 57720ba6a1dSAlexandre Courbot /// register! { 57820ba6a1dSAlexandre Courbot /// /// CPU core control. 57920ba6a1dSAlexandre Courbot /// pub CPU_CTL(u32) @ CpuCtlBase + 0x10 { 58020ba6a1dSAlexandre Courbot /// 0:0 start; 58120ba6a1dSAlexandre Courbot /// } 58220ba6a1dSAlexandre Courbot /// } 58320ba6a1dSAlexandre Courbot /// 58420ba6a1dSAlexandre Courbot /// # fn test(io: Mmio<0x1000>) { 58520ba6a1dSAlexandre Courbot /// // Read the status of `Cpu0`. 58620ba6a1dSAlexandre Courbot /// let cpu0_started = io.read(CPU_CTL::of::<Cpu0>()); 58720ba6a1dSAlexandre Courbot /// 58820ba6a1dSAlexandre Courbot /// // Stop `Cpu0`. 58920ba6a1dSAlexandre Courbot /// io.write(WithBase::of::<Cpu0>(), CPU_CTL::zeroed()); 59020ba6a1dSAlexandre Courbot /// # } 59120ba6a1dSAlexandre Courbot /// 59220ba6a1dSAlexandre Courbot /// // Aliases can also be defined for relative register. 59320ba6a1dSAlexandre Courbot /// register! { 59420ba6a1dSAlexandre Courbot /// /// Alias to CPU core control. 59520ba6a1dSAlexandre Courbot /// pub CPU_CTL_ALIAS(u32) => CpuCtlBase + CPU_CTL { 59620ba6a1dSAlexandre Courbot /// /// Start the aliased CPU core. 59720ba6a1dSAlexandre Courbot /// 1:1 alias_start; 59820ba6a1dSAlexandre Courbot /// } 59920ba6a1dSAlexandre Courbot /// } 60020ba6a1dSAlexandre Courbot /// 60120ba6a1dSAlexandre Courbot /// # fn test2(io: Mmio<0x1000>) { 60220ba6a1dSAlexandre Courbot /// // Start the aliased `CPU0`, leaving its other fields untouched. 60320ba6a1dSAlexandre Courbot /// io.update(CPU_CTL_ALIAS::of::<Cpu0>(), |r| r.with_alias_start(true)); 60420ba6a1dSAlexandre Courbot /// # } 60520ba6a1dSAlexandre Courbot /// ``` 60620ba6a1dSAlexandre Courbot /// 60720ba6a1dSAlexandre Courbot /// ## Arrays of registers 60820ba6a1dSAlexandre Courbot /// 60920ba6a1dSAlexandre Courbot /// Some I/O areas contain consecutive registers that share the same field layout. These areas can 61020ba6a1dSAlexandre Courbot /// be defined as an array of identical registers, allowing them to be accessed by index with 61120ba6a1dSAlexandre Courbot /// compile-time or runtime bound checking: 61220ba6a1dSAlexandre Courbot /// 61320ba6a1dSAlexandre Courbot /// ```ignore 61420ba6a1dSAlexandre Courbot /// register! { 61520ba6a1dSAlexandre Courbot /// pub REGISTER_ARRAY(u8)[10, stride = 4] @ 0x100 { 61620ba6a1dSAlexandre Courbot /// ... 61720ba6a1dSAlexandre Courbot /// } 61820ba6a1dSAlexandre Courbot /// } 61920ba6a1dSAlexandre Courbot /// ``` 62020ba6a1dSAlexandre Courbot /// 62120ba6a1dSAlexandre Courbot /// This defines `REGISTER_ARRAY`, an array of 10 byte registers starting at offset `0x100`. Each 62220ba6a1dSAlexandre Courbot /// register is separated from its neighbor by 4 bytes. 62320ba6a1dSAlexandre Courbot /// 62420ba6a1dSAlexandre Courbot /// The `stride` parameter is optional; if unspecified, the registers are placed consecutively from 62520ba6a1dSAlexandre Courbot /// each other. 62620ba6a1dSAlexandre Courbot /// 62720ba6a1dSAlexandre Courbot /// A location for a register in a register array is built using the [`Array::at`] trait method. 62820ba6a1dSAlexandre Courbot /// All arrays of registers implement [`Array`]. 62920ba6a1dSAlexandre Courbot /// 63020ba6a1dSAlexandre Courbot /// ```no_run 63120ba6a1dSAlexandre Courbot /// use kernel::{ 63220ba6a1dSAlexandre Courbot /// io::{ 63320ba6a1dSAlexandre Courbot /// register, 63420ba6a1dSAlexandre Courbot /// register::Array, 63520ba6a1dSAlexandre Courbot /// Io, 63620ba6a1dSAlexandre Courbot /// }, 63720ba6a1dSAlexandre Courbot /// }; 63820ba6a1dSAlexandre Courbot /// # use kernel::io::Mmio; 63920ba6a1dSAlexandre Courbot /// # fn get_scratch_idx() -> usize { 64020ba6a1dSAlexandre Courbot /// # 0x15 64120ba6a1dSAlexandre Courbot /// # } 64220ba6a1dSAlexandre Courbot /// 64320ba6a1dSAlexandre Courbot /// // Array of 64 consecutive registers with the same layout starting at offset `0x80`. 64420ba6a1dSAlexandre Courbot /// register! { 64520ba6a1dSAlexandre Courbot /// /// Scratch registers. 64620ba6a1dSAlexandre Courbot /// pub SCRATCH(u32)[64] @ 0x00000080 { 64720ba6a1dSAlexandre Courbot /// 31:0 value; 64820ba6a1dSAlexandre Courbot /// } 64920ba6a1dSAlexandre Courbot /// } 65020ba6a1dSAlexandre Courbot /// 65120ba6a1dSAlexandre Courbot /// # fn test(io: &Mmio<0x1000>) 65220ba6a1dSAlexandre Courbot /// # -> Result<(), Error>{ 65320ba6a1dSAlexandre Courbot /// // Read scratch register 0, i.e. I/O address `0x80`. 65420ba6a1dSAlexandre Courbot /// let scratch_0 = io.read(SCRATCH::at(0)).value(); 65520ba6a1dSAlexandre Courbot /// 65620ba6a1dSAlexandre Courbot /// // Write scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. 65720ba6a1dSAlexandre Courbot /// io.write(Array::at(15), SCRATCH::from(0xffeeaabb)); 65820ba6a1dSAlexandre Courbot /// 65920ba6a1dSAlexandre Courbot /// // This is out of bounds and won't build. 66020ba6a1dSAlexandre Courbot /// // let scratch_128 = io.read(SCRATCH::at(128)).value(); 66120ba6a1dSAlexandre Courbot /// 66220ba6a1dSAlexandre Courbot /// // Runtime-obtained array index. 66320ba6a1dSAlexandre Courbot /// let idx = get_scratch_idx(); 66420ba6a1dSAlexandre Courbot /// // Access on a runtime index returns an error if it is out-of-bounds. 66520ba6a1dSAlexandre Courbot /// let some_scratch = io.read(SCRATCH::try_at(idx).ok_or(EINVAL)?).value(); 66620ba6a1dSAlexandre Courbot /// 66720ba6a1dSAlexandre Courbot /// // Alias to a specific register in an array. 66820ba6a1dSAlexandre Courbot /// // Here `SCRATCH[8]` is used to convey the firmware exit code. 66920ba6a1dSAlexandre Courbot /// register! { 67020ba6a1dSAlexandre Courbot /// /// Firmware exit status code. 67120ba6a1dSAlexandre Courbot /// pub FIRMWARE_STATUS(u32) => SCRATCH[8] { 67220ba6a1dSAlexandre Courbot /// 7:0 status; 67320ba6a1dSAlexandre Courbot /// } 67420ba6a1dSAlexandre Courbot /// } 67520ba6a1dSAlexandre Courbot /// 67620ba6a1dSAlexandre Courbot /// let status = io.read(FIRMWARE_STATUS).status(); 67720ba6a1dSAlexandre Courbot /// 67820ba6a1dSAlexandre Courbot /// // Non-contiguous register arrays can be defined by adding a stride parameter. 67920ba6a1dSAlexandre Courbot /// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the 68020ba6a1dSAlexandre Courbot /// // registers of the two declarations below are interleaved. 68120ba6a1dSAlexandre Courbot /// register! { 68220ba6a1dSAlexandre Courbot /// /// Scratch registers bank 0. 68320ba6a1dSAlexandre Courbot /// pub SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ 0x000000c0 { 68420ba6a1dSAlexandre Courbot /// 31:0 value; 68520ba6a1dSAlexandre Courbot /// } 68620ba6a1dSAlexandre Courbot /// 68720ba6a1dSAlexandre Courbot /// /// Scratch registers bank 1. 68820ba6a1dSAlexandre Courbot /// pub SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ 0x000000c4 { 68920ba6a1dSAlexandre Courbot /// 31:0 value; 69020ba6a1dSAlexandre Courbot /// } 69120ba6a1dSAlexandre Courbot /// } 69220ba6a1dSAlexandre Courbot /// # Ok(()) 69320ba6a1dSAlexandre Courbot /// # } 69420ba6a1dSAlexandre Courbot /// ``` 69520ba6a1dSAlexandre Courbot /// 69620ba6a1dSAlexandre Courbot /// ## Relative arrays of registers 69720ba6a1dSAlexandre Courbot /// 69820ba6a1dSAlexandre Courbot /// Combining the two features described in the sections above, arrays of registers accessible from 69920ba6a1dSAlexandre Courbot /// a base can also be defined: 70020ba6a1dSAlexandre Courbot /// 70120ba6a1dSAlexandre Courbot /// ```ignore 70220ba6a1dSAlexandre Courbot /// register! { 70320ba6a1dSAlexandre Courbot /// pub RELATIVE_REGISTER_ARRAY(u8)[10, stride = 4] @ Base + 0x100 { 70420ba6a1dSAlexandre Courbot /// ... 70520ba6a1dSAlexandre Courbot /// } 70620ba6a1dSAlexandre Courbot /// } 70720ba6a1dSAlexandre Courbot /// ``` 70820ba6a1dSAlexandre Courbot /// 70920ba6a1dSAlexandre Courbot /// Like relative registers, they implement the [`WithBase`] trait. However the return value of 71020ba6a1dSAlexandre Courbot /// [`WithBase::of`] cannot be used directly as a location and must be further specified using the 71120ba6a1dSAlexandre Courbot /// [`at`](RelativeRegisterLoc::at) method. 71220ba6a1dSAlexandre Courbot /// 71320ba6a1dSAlexandre Courbot /// ```no_run 71420ba6a1dSAlexandre Courbot /// use kernel::{ 71520ba6a1dSAlexandre Courbot /// io::{ 71620ba6a1dSAlexandre Courbot /// register, 71720ba6a1dSAlexandre Courbot /// register::{ 71820ba6a1dSAlexandre Courbot /// RegisterBase, 71920ba6a1dSAlexandre Courbot /// WithBase, 72020ba6a1dSAlexandre Courbot /// }, 72120ba6a1dSAlexandre Courbot /// Io, 72220ba6a1dSAlexandre Courbot /// }, 72320ba6a1dSAlexandre Courbot /// }; 72420ba6a1dSAlexandre Courbot /// # use kernel::io::Mmio; 72520ba6a1dSAlexandre Courbot /// # fn get_scratch_idx() -> usize { 72620ba6a1dSAlexandre Courbot /// # 0x15 72720ba6a1dSAlexandre Courbot /// # } 72820ba6a1dSAlexandre Courbot /// 72920ba6a1dSAlexandre Courbot /// // Type used as parameter of `RegisterBase` to specify the base. 73020ba6a1dSAlexandre Courbot /// pub struct CpuCtlBase; 73120ba6a1dSAlexandre Courbot /// 73220ba6a1dSAlexandre Courbot /// // ZST describing `CPU0`. 73320ba6a1dSAlexandre Courbot /// struct Cpu0; 73420ba6a1dSAlexandre Courbot /// impl RegisterBase<CpuCtlBase> for Cpu0 { 73520ba6a1dSAlexandre Courbot /// const BASE: usize = 0x100; 73620ba6a1dSAlexandre Courbot /// } 73720ba6a1dSAlexandre Courbot /// 73820ba6a1dSAlexandre Courbot /// // ZST describing `CPU1`. 73920ba6a1dSAlexandre Courbot /// struct Cpu1; 74020ba6a1dSAlexandre Courbot /// impl RegisterBase<CpuCtlBase> for Cpu1 { 74120ba6a1dSAlexandre Courbot /// const BASE: usize = 0x200; 74220ba6a1dSAlexandre Courbot /// } 74320ba6a1dSAlexandre Courbot /// 74420ba6a1dSAlexandre Courbot /// // 64 per-cpu scratch registers, arranged as a contiguous array. 74520ba6a1dSAlexandre Courbot /// register! { 74620ba6a1dSAlexandre Courbot /// /// Per-CPU scratch registers. 74720ba6a1dSAlexandre Courbot /// pub CPU_SCRATCH(u32)[64] @ CpuCtlBase + 0x00000080 { 74820ba6a1dSAlexandre Courbot /// 31:0 value; 74920ba6a1dSAlexandre Courbot /// } 75020ba6a1dSAlexandre Courbot /// } 75120ba6a1dSAlexandre Courbot /// 75220ba6a1dSAlexandre Courbot /// # fn test(io: &Mmio<0x1000>) -> Result<(), Error> { 75320ba6a1dSAlexandre Courbot /// // Read scratch register 0 of CPU0. 75420ba6a1dSAlexandre Courbot /// let scratch = io.read(CPU_SCRATCH::of::<Cpu0>().at(0)); 75520ba6a1dSAlexandre Courbot /// 75620ba6a1dSAlexandre Courbot /// // Write the retrieved value into scratch register 15 of CPU1. 75720ba6a1dSAlexandre Courbot /// io.write(WithBase::of::<Cpu1>().at(15), scratch); 75820ba6a1dSAlexandre Courbot /// 75920ba6a1dSAlexandre Courbot /// // This won't build. 76020ba6a1dSAlexandre Courbot /// // let cpu0_scratch_128 = io.read(CPU_SCRATCH::of::<Cpu0>().at(128)).value(); 76120ba6a1dSAlexandre Courbot /// 76220ba6a1dSAlexandre Courbot /// // Runtime-obtained array index. 76320ba6a1dSAlexandre Courbot /// let scratch_idx = get_scratch_idx(); 76420ba6a1dSAlexandre Courbot /// // Access on a runtime index returns an error if it is out-of-bounds. 76520ba6a1dSAlexandre Courbot /// let cpu0_scratch = io.read( 76620ba6a1dSAlexandre Courbot /// CPU_SCRATCH::of::<Cpu0>().try_at(scratch_idx).ok_or(EINVAL)? 76720ba6a1dSAlexandre Courbot /// ).value(); 76820ba6a1dSAlexandre Courbot /// # Ok(()) 76920ba6a1dSAlexandre Courbot /// # } 77020ba6a1dSAlexandre Courbot /// 77120ba6a1dSAlexandre Courbot /// // Alias to `SCRATCH[8]` used to convey the firmware exit code. 77220ba6a1dSAlexandre Courbot /// register! { 77320ba6a1dSAlexandre Courbot /// /// Per-CPU firmware exit status code. 77420ba6a1dSAlexandre Courbot /// pub CPU_FIRMWARE_STATUS(u32) => CpuCtlBase + CPU_SCRATCH[8] { 77520ba6a1dSAlexandre Courbot /// 7:0 status; 77620ba6a1dSAlexandre Courbot /// } 77720ba6a1dSAlexandre Courbot /// } 77820ba6a1dSAlexandre Courbot /// 77920ba6a1dSAlexandre Courbot /// // Non-contiguous relative register arrays can be defined by adding a stride parameter. 78020ba6a1dSAlexandre Courbot /// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the 78120ba6a1dSAlexandre Courbot /// // registers of the two declarations below are interleaved. 78220ba6a1dSAlexandre Courbot /// register! { 78320ba6a1dSAlexandre Courbot /// /// Scratch registers bank 0. 78420ba6a1dSAlexandre Courbot /// pub CPU_SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d00 { 78520ba6a1dSAlexandre Courbot /// 31:0 value; 78620ba6a1dSAlexandre Courbot /// } 78720ba6a1dSAlexandre Courbot /// 78820ba6a1dSAlexandre Courbot /// /// Scratch registers bank 1. 78920ba6a1dSAlexandre Courbot /// pub CPU_SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d04 { 79020ba6a1dSAlexandre Courbot /// 31:0 value; 79120ba6a1dSAlexandre Courbot /// } 79220ba6a1dSAlexandre Courbot /// } 79320ba6a1dSAlexandre Courbot /// 79420ba6a1dSAlexandre Courbot /// # fn test2(io: &Mmio<0x1000>) -> Result<(), Error> { 79520ba6a1dSAlexandre Courbot /// let cpu0_status = io.read(CPU_FIRMWARE_STATUS::of::<Cpu0>()).status(); 79620ba6a1dSAlexandre Courbot /// # Ok(()) 79720ba6a1dSAlexandre Courbot /// # } 79820ba6a1dSAlexandre Courbot /// ``` 79920ba6a1dSAlexandre Courbot #[macro_export] 80020ba6a1dSAlexandre Courbot macro_rules! register { 80120ba6a1dSAlexandre Courbot // Entry point for the macro, allowing multiple registers to be defined in one call. 80220ba6a1dSAlexandre Courbot // It matches all possible register declaration patterns to dispatch them to corresponding 80320ba6a1dSAlexandre Courbot // `@reg` rule that defines a single register. 80420ba6a1dSAlexandre Courbot ( 80520ba6a1dSAlexandre Courbot $( 80620ba6a1dSAlexandre Courbot $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 80720ba6a1dSAlexandre Courbot $([ $size:expr $(, stride = $stride:expr)? ])? 80820ba6a1dSAlexandre Courbot $(@ $($base:ident +)? $offset:literal)? 80920ba6a1dSAlexandre Courbot $(=> $alias:ident $(+ $alias_offset:ident)? $([$alias_idx:expr])? )? 81020ba6a1dSAlexandre Courbot { $($fields:tt)* } 81120ba6a1dSAlexandre Courbot )* 81220ba6a1dSAlexandre Courbot ) => { 81320ba6a1dSAlexandre Courbot $( 81420ba6a1dSAlexandre Courbot $crate::register!( 81520ba6a1dSAlexandre Courbot @reg $(#[$attr])* $vis $name ($storage) $([$size $(, stride = $stride)?])? 81620ba6a1dSAlexandre Courbot $(@ $($base +)? $offset)? 81720ba6a1dSAlexandre Courbot $(=> $alias $(+ $alias_offset)? $([$alias_idx])? )? 81820ba6a1dSAlexandre Courbot { $($fields)* } 81920ba6a1dSAlexandre Courbot ); 82020ba6a1dSAlexandre Courbot )* 82120ba6a1dSAlexandre Courbot }; 82220ba6a1dSAlexandre Courbot 82320ba6a1dSAlexandre Courbot // All the rules below are private helpers. 82420ba6a1dSAlexandre Courbot 82520ba6a1dSAlexandre Courbot // Creates a register at a fixed offset of the MMIO space. 82620ba6a1dSAlexandre Courbot ( 82720ba6a1dSAlexandre Courbot @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $offset:literal 82820ba6a1dSAlexandre Courbot { $($fields:tt)* } 82920ba6a1dSAlexandre Courbot ) => { 83020ba6a1dSAlexandre Courbot $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 83120ba6a1dSAlexandre Courbot $crate::register!(@io_base $name($storage) @ $offset); 83220ba6a1dSAlexandre Courbot $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); 83320ba6a1dSAlexandre Courbot }; 83420ba6a1dSAlexandre Courbot 83520ba6a1dSAlexandre Courbot // Creates an alias register of fixed offset register `alias` with its own fields. 83620ba6a1dSAlexandre Courbot ( 83720ba6a1dSAlexandre Courbot @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident 83820ba6a1dSAlexandre Courbot { $($fields:tt)* } 83920ba6a1dSAlexandre Courbot ) => { 84020ba6a1dSAlexandre Courbot $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 84120ba6a1dSAlexandre Courbot $crate::register!( 84220ba6a1dSAlexandre Courbot @io_base $name($storage) @ 84320ba6a1dSAlexandre Courbot <$alias as $crate::io::register::Register>::OFFSET 84420ba6a1dSAlexandre Courbot ); 84520ba6a1dSAlexandre Courbot $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); 84620ba6a1dSAlexandre Courbot }; 84720ba6a1dSAlexandre Courbot 84820ba6a1dSAlexandre Courbot // Creates a register at a relative offset from a base address provider. 84920ba6a1dSAlexandre Courbot ( 85020ba6a1dSAlexandre Courbot @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $base:ident + $offset:literal 85120ba6a1dSAlexandre Courbot { $($fields:tt)* } 85220ba6a1dSAlexandre Courbot ) => { 85320ba6a1dSAlexandre Courbot $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 85420ba6a1dSAlexandre Courbot $crate::register!(@io_base $name($storage) @ $offset); 85520ba6a1dSAlexandre Courbot $crate::register!(@io_relative $vis $name($storage) @ $base); 85620ba6a1dSAlexandre Courbot }; 85720ba6a1dSAlexandre Courbot 85820ba6a1dSAlexandre Courbot // Creates an alias register of relative offset register `alias` with its own fields. 85920ba6a1dSAlexandre Courbot ( 86020ba6a1dSAlexandre Courbot @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $base:ident + $alias:ident 86120ba6a1dSAlexandre Courbot { $($fields:tt)* } 86220ba6a1dSAlexandre Courbot ) => { 86320ba6a1dSAlexandre Courbot $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 86420ba6a1dSAlexandre Courbot $crate::register!( 86520ba6a1dSAlexandre Courbot @io_base $name($storage) @ <$alias as $crate::io::register::Register>::OFFSET 86620ba6a1dSAlexandre Courbot ); 86720ba6a1dSAlexandre Courbot $crate::register!(@io_relative $vis $name($storage) @ $base); 86820ba6a1dSAlexandre Courbot }; 86920ba6a1dSAlexandre Courbot 87020ba6a1dSAlexandre Courbot // Creates an array of registers at a fixed offset of the MMIO space. 87120ba6a1dSAlexandre Courbot ( 87220ba6a1dSAlexandre Courbot @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 87320ba6a1dSAlexandre Courbot [ $size:expr, stride = $stride:expr ] @ $offset:literal { $($fields:tt)* } 87420ba6a1dSAlexandre Courbot ) => { 87520ba6a1dSAlexandre Courbot ::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride); 87620ba6a1dSAlexandre Courbot 87720ba6a1dSAlexandre Courbot $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 87820ba6a1dSAlexandre Courbot $crate::register!(@io_base $name($storage) @ $offset); 87920ba6a1dSAlexandre Courbot $crate::register!(@io_array $vis $name($storage) [ $size, stride = $stride ]); 88020ba6a1dSAlexandre Courbot }; 88120ba6a1dSAlexandre Courbot 88220ba6a1dSAlexandre Courbot // Shortcut for contiguous array of registers (stride == size of element). 88320ba6a1dSAlexandre Courbot ( 88420ba6a1dSAlexandre Courbot @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ] @ $offset:literal 88520ba6a1dSAlexandre Courbot { $($fields:tt)* } 88620ba6a1dSAlexandre Courbot ) => { 88720ba6a1dSAlexandre Courbot $crate::register!( 88820ba6a1dSAlexandre Courbot $(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ] 88920ba6a1dSAlexandre Courbot @ $offset { $($fields)* } 89020ba6a1dSAlexandre Courbot ); 89120ba6a1dSAlexandre Courbot }; 89220ba6a1dSAlexandre Courbot 89320ba6a1dSAlexandre Courbot // Creates an alias of register `idx` of array of registers `alias` with its own fields. 89420ba6a1dSAlexandre Courbot ( 89520ba6a1dSAlexandre Courbot @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident [ $idx:expr ] 89620ba6a1dSAlexandre Courbot { $($fields:tt)* } 89720ba6a1dSAlexandre Courbot ) => { 89820ba6a1dSAlexandre Courbot ::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE); 89920ba6a1dSAlexandre Courbot 90020ba6a1dSAlexandre Courbot $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 90120ba6a1dSAlexandre Courbot $crate::register!( 90220ba6a1dSAlexandre Courbot @io_base $name($storage) @ 90320ba6a1dSAlexandre Courbot <$alias as $crate::io::register::Register>::OFFSET 90420ba6a1dSAlexandre Courbot + $idx * <$alias as $crate::io::register::RegisterArray>::STRIDE 90520ba6a1dSAlexandre Courbot ); 90620ba6a1dSAlexandre Courbot $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); 90720ba6a1dSAlexandre Courbot }; 90820ba6a1dSAlexandre Courbot 90920ba6a1dSAlexandre Courbot // Creates an array of registers at a relative offset from a base address provider. 91020ba6a1dSAlexandre Courbot ( 91120ba6a1dSAlexandre Courbot @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 91220ba6a1dSAlexandre Courbot [ $size:expr, stride = $stride:expr ] 91320ba6a1dSAlexandre Courbot @ $base:ident + $offset:literal { $($fields:tt)* } 91420ba6a1dSAlexandre Courbot ) => { 91520ba6a1dSAlexandre Courbot ::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride); 91620ba6a1dSAlexandre Courbot 91720ba6a1dSAlexandre Courbot $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 91820ba6a1dSAlexandre Courbot $crate::register!(@io_base $name($storage) @ $offset); 91920ba6a1dSAlexandre Courbot $crate::register!( 92020ba6a1dSAlexandre Courbot @io_relative_array $vis $name($storage) [ $size, stride = $stride ] @ $base + $offset 92120ba6a1dSAlexandre Courbot ); 92220ba6a1dSAlexandre Courbot }; 92320ba6a1dSAlexandre Courbot 92420ba6a1dSAlexandre Courbot // Shortcut for contiguous array of relative registers (stride == size of element). 92520ba6a1dSAlexandre Courbot ( 92620ba6a1dSAlexandre Courbot @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ] 92720ba6a1dSAlexandre Courbot @ $base:ident + $offset:literal { $($fields:tt)* } 92820ba6a1dSAlexandre Courbot ) => { 92920ba6a1dSAlexandre Courbot $crate::register!( 93020ba6a1dSAlexandre Courbot $(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ] 93120ba6a1dSAlexandre Courbot @ $base + $offset { $($fields)* } 93220ba6a1dSAlexandre Courbot ); 93320ba6a1dSAlexandre Courbot }; 93420ba6a1dSAlexandre Courbot 93520ba6a1dSAlexandre Courbot // Creates an alias of register `idx` of relative array of registers `alias` with its own 93620ba6a1dSAlexandre Courbot // fields. 93720ba6a1dSAlexandre Courbot ( 93820ba6a1dSAlexandre Courbot @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 93920ba6a1dSAlexandre Courbot => $base:ident + $alias:ident [ $idx:expr ] { $($fields:tt)* } 94020ba6a1dSAlexandre Courbot ) => { 94120ba6a1dSAlexandre Courbot ::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE); 94220ba6a1dSAlexandre Courbot 94320ba6a1dSAlexandre Courbot $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 94420ba6a1dSAlexandre Courbot $crate::register!( 94520ba6a1dSAlexandre Courbot @io_base $name($storage) @ 94620ba6a1dSAlexandre Courbot <$alias as $crate::io::register::Register>::OFFSET + 94720ba6a1dSAlexandre Courbot $idx * <$alias as $crate::io::register::RegisterArray>::STRIDE 94820ba6a1dSAlexandre Courbot ); 94920ba6a1dSAlexandre Courbot $crate::register!(@io_relative $vis $name($storage) @ $base); 95020ba6a1dSAlexandre Courbot }; 95120ba6a1dSAlexandre Courbot 95220ba6a1dSAlexandre Courbot // Generates the bitfield for the register. 95320ba6a1dSAlexandre Courbot // 95420ba6a1dSAlexandre Courbot // `#[allow(non_camel_case_types)]` is added since register names typically use 95520ba6a1dSAlexandre Courbot // `SCREAMING_CASE`. 95620ba6a1dSAlexandre Courbot ( 95720ba6a1dSAlexandre Courbot @bitfield $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* } 95820ba6a1dSAlexandre Courbot ) => { 95920ba6a1dSAlexandre Courbot $crate::register!(@bitfield_core 96020ba6a1dSAlexandre Courbot #[allow(non_camel_case_types)] 96120ba6a1dSAlexandre Courbot $(#[$attr])* $vis $name $storage 96220ba6a1dSAlexandre Courbot ); 96320ba6a1dSAlexandre Courbot $crate::register!(@bitfield_fields $vis $name $storage { $($fields)* }); 96420ba6a1dSAlexandre Courbot }; 96520ba6a1dSAlexandre Courbot 96620ba6a1dSAlexandre Courbot // Implementations shared by all registers types. 96720ba6a1dSAlexandre Courbot (@io_base $name:ident($storage:ty) @ $offset:expr) => { 96820ba6a1dSAlexandre Courbot impl $crate::io::register::Register for $name { 96920ba6a1dSAlexandre Courbot type Storage = $storage; 97020ba6a1dSAlexandre Courbot 97120ba6a1dSAlexandre Courbot const OFFSET: usize = $offset; 97220ba6a1dSAlexandre Courbot } 97320ba6a1dSAlexandre Courbot }; 97420ba6a1dSAlexandre Courbot 97520ba6a1dSAlexandre Courbot // Implementations of fixed registers. 97620ba6a1dSAlexandre Courbot (@io_fixed $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)) => { 97720ba6a1dSAlexandre Courbot impl $crate::io::register::FixedRegister for $name {} 97820ba6a1dSAlexandre Courbot 97920ba6a1dSAlexandre Courbot $(#[$attr])* 98020ba6a1dSAlexandre Courbot $vis const $name: $crate::io::register::FixedRegisterLoc<$name> = 98120ba6a1dSAlexandre Courbot $crate::io::register::FixedRegisterLoc::<$name>::new(); 98220ba6a1dSAlexandre Courbot }; 98320ba6a1dSAlexandre Courbot 98420ba6a1dSAlexandre Courbot // Implementations of relative registers. 98520ba6a1dSAlexandre Courbot (@io_relative $vis:vis $name:ident ($storage:ty) @ $base:ident) => { 98620ba6a1dSAlexandre Courbot impl $crate::io::register::WithBase for $name { 98720ba6a1dSAlexandre Courbot type BaseFamily = $base; 98820ba6a1dSAlexandre Courbot } 98920ba6a1dSAlexandre Courbot 99020ba6a1dSAlexandre Courbot impl $crate::io::register::RelativeRegister for $name {} 99120ba6a1dSAlexandre Courbot }; 99220ba6a1dSAlexandre Courbot 99320ba6a1dSAlexandre Courbot // Implementations of register arrays. 99420ba6a1dSAlexandre Courbot (@io_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ]) => { 99520ba6a1dSAlexandre Courbot impl $crate::io::register::Array for $name {} 99620ba6a1dSAlexandre Courbot 99720ba6a1dSAlexandre Courbot impl $crate::io::register::RegisterArray for $name { 99820ba6a1dSAlexandre Courbot const SIZE: usize = $size; 99920ba6a1dSAlexandre Courbot const STRIDE: usize = $stride; 100020ba6a1dSAlexandre Courbot } 100120ba6a1dSAlexandre Courbot }; 100220ba6a1dSAlexandre Courbot 100320ba6a1dSAlexandre Courbot // Implementations of relative array registers. 100420ba6a1dSAlexandre Courbot ( 100520ba6a1dSAlexandre Courbot @io_relative_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ] 100620ba6a1dSAlexandre Courbot @ $base:ident + $offset:literal 100720ba6a1dSAlexandre Courbot ) => { 100820ba6a1dSAlexandre Courbot impl $crate::io::register::WithBase for $name { 100920ba6a1dSAlexandre Courbot type BaseFamily = $base; 101020ba6a1dSAlexandre Courbot } 101120ba6a1dSAlexandre Courbot 101220ba6a1dSAlexandre Courbot impl $crate::io::register::RegisterArray for $name { 101320ba6a1dSAlexandre Courbot const SIZE: usize = $size; 101420ba6a1dSAlexandre Courbot const STRIDE: usize = $stride; 101520ba6a1dSAlexandre Courbot } 101620ba6a1dSAlexandre Courbot 101720ba6a1dSAlexandre Courbot impl $crate::io::register::RelativeRegisterArray for $name {} 101820ba6a1dSAlexandre Courbot }; 101920ba6a1dSAlexandre Courbot 102020ba6a1dSAlexandre Courbot // Defines the wrapper `$name` type and its conversions from/to the storage type. 102120ba6a1dSAlexandre Courbot (@bitfield_core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => { 102220ba6a1dSAlexandre Courbot $(#[$attr])* 102320ba6a1dSAlexandre Courbot #[repr(transparent)] 102420ba6a1dSAlexandre Courbot #[derive(Clone, Copy, PartialEq, Eq)] 102520ba6a1dSAlexandre Courbot $vis struct $name { 102620ba6a1dSAlexandre Courbot inner: $storage, 102720ba6a1dSAlexandre Courbot } 102820ba6a1dSAlexandre Courbot 102920ba6a1dSAlexandre Courbot #[allow(dead_code)] 103020ba6a1dSAlexandre Courbot impl $name { 103120ba6a1dSAlexandre Courbot /// Creates a bitfield from a raw value. 103220ba6a1dSAlexandre Courbot #[inline(always)] 103320ba6a1dSAlexandre Courbot $vis const fn from_raw(value: $storage) -> Self { 103420ba6a1dSAlexandre Courbot Self{ inner: value } 103520ba6a1dSAlexandre Courbot } 103620ba6a1dSAlexandre Courbot 103720ba6a1dSAlexandre Courbot /// Turns this bitfield into its raw value. 103820ba6a1dSAlexandre Courbot /// 103920ba6a1dSAlexandre Courbot /// This is similar to the [`From`] implementation, but is shorter to invoke in 104020ba6a1dSAlexandre Courbot /// most cases. 104120ba6a1dSAlexandre Courbot #[inline(always)] 104220ba6a1dSAlexandre Courbot $vis const fn into_raw(self) -> $storage { 104320ba6a1dSAlexandre Courbot self.inner 104420ba6a1dSAlexandre Courbot } 104520ba6a1dSAlexandre Courbot } 104620ba6a1dSAlexandre Courbot 104720ba6a1dSAlexandre Courbot // SAFETY: `$storage` is `Zeroable` and `$name` is transparent. 104820ba6a1dSAlexandre Courbot unsafe impl ::pin_init::Zeroable for $name {} 104920ba6a1dSAlexandre Courbot 105020ba6a1dSAlexandre Courbot impl ::core::convert::From<$name> for $storage { 105120ba6a1dSAlexandre Courbot #[inline(always)] 105220ba6a1dSAlexandre Courbot fn from(val: $name) -> $storage { 105320ba6a1dSAlexandre Courbot val.into_raw() 105420ba6a1dSAlexandre Courbot } 105520ba6a1dSAlexandre Courbot } 105620ba6a1dSAlexandre Courbot 105720ba6a1dSAlexandre Courbot impl ::core::convert::From<$storage> for $name { 105820ba6a1dSAlexandre Courbot #[inline(always)] 105920ba6a1dSAlexandre Courbot fn from(val: $storage) -> $name { 106020ba6a1dSAlexandre Courbot Self::from_raw(val) 106120ba6a1dSAlexandre Courbot } 106220ba6a1dSAlexandre Courbot } 106320ba6a1dSAlexandre Courbot }; 106420ba6a1dSAlexandre Courbot 106520ba6a1dSAlexandre Courbot // Definitions requiring knowledge of individual fields: private and public field accessors, 106620ba6a1dSAlexandre Courbot // and `Debug` implementation. 106720ba6a1dSAlexandre Courbot (@bitfield_fields $vis:vis $name:ident $storage:ty { 106820ba6a1dSAlexandre Courbot $($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident 106920ba6a1dSAlexandre Courbot $(?=> $try_into_type:ty)? 107020ba6a1dSAlexandre Courbot $(=> $into_type:ty)? 107120ba6a1dSAlexandre Courbot ; 107220ba6a1dSAlexandre Courbot )* 107320ba6a1dSAlexandre Courbot } 107420ba6a1dSAlexandre Courbot ) => { 107520ba6a1dSAlexandre Courbot #[allow(dead_code)] 107620ba6a1dSAlexandre Courbot impl $name { 107720ba6a1dSAlexandre Courbot $( 107820ba6a1dSAlexandre Courbot $crate::register!(@private_field_accessors $vis $name $storage : $hi:$lo $field); 107920ba6a1dSAlexandre Courbot $crate::register!( 108020ba6a1dSAlexandre Courbot @public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field 108120ba6a1dSAlexandre Courbot $(?=> $try_into_type)? 108220ba6a1dSAlexandre Courbot $(=> $into_type)? 108320ba6a1dSAlexandre Courbot ); 108420ba6a1dSAlexandre Courbot )* 108520ba6a1dSAlexandre Courbot } 108620ba6a1dSAlexandre Courbot 108720ba6a1dSAlexandre Courbot $crate::register!(@debug $name { $($field;)* }); 108820ba6a1dSAlexandre Courbot }; 108920ba6a1dSAlexandre Courbot 109020ba6a1dSAlexandre Courbot // Private field accessors working with the exact `Bounded` type for the field. 109120ba6a1dSAlexandre Courbot ( 109220ba6a1dSAlexandre Courbot @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident 109320ba6a1dSAlexandre Courbot ) => { 109420ba6a1dSAlexandre Courbot ::kernel::macros::paste!( 109520ba6a1dSAlexandre Courbot $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi; 109620ba6a1dSAlexandre Courbot $vis const [<$field:upper _MASK>]: $storage = 109720ba6a1dSAlexandre Courbot ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); 109820ba6a1dSAlexandre Courbot $vis const [<$field:upper _SHIFT>]: u32 = $lo; 109920ba6a1dSAlexandre Courbot ); 110020ba6a1dSAlexandre Courbot 110120ba6a1dSAlexandre Courbot ::kernel::macros::paste!( 110220ba6a1dSAlexandre Courbot fn [<__ $field>](self) -> 110320ba6a1dSAlexandre Courbot ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> { 110420ba6a1dSAlexandre Courbot // Left shift to align the field's MSB with the storage MSB. 110520ba6a1dSAlexandre Courbot const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1); 110620ba6a1dSAlexandre Courbot // Right shift to move the top-aligned field to bit 0 of the storage. 110720ba6a1dSAlexandre Courbot const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo; 110820ba6a1dSAlexandre Courbot 110920ba6a1dSAlexandre Courbot // Extract the field using two shifts. `Bounded::shr` produces the correctly-sized 111020ba6a1dSAlexandre Courbot // output type. 111120ba6a1dSAlexandre Courbot let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from( 111220ba6a1dSAlexandre Courbot self.inner << ALIGN_TOP 111320ba6a1dSAlexandre Courbot ); 111420ba6a1dSAlexandre Courbot val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >() 111520ba6a1dSAlexandre Courbot } 111620ba6a1dSAlexandre Courbot 111720ba6a1dSAlexandre Courbot const fn [<__with_ $field>]( 111820ba6a1dSAlexandre Courbot mut self, 111920ba6a1dSAlexandre Courbot value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>, 112020ba6a1dSAlexandre Courbot ) -> Self 112120ba6a1dSAlexandre Courbot { 112220ba6a1dSAlexandre Courbot const MASK: $storage = <$name>::[<$field:upper _MASK>]; 112320ba6a1dSAlexandre Courbot const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>]; 112420ba6a1dSAlexandre Courbot 112520ba6a1dSAlexandre Courbot let value = value.get() << SHIFT; 112620ba6a1dSAlexandre Courbot self.inner = (self.inner & !MASK) | value; 112720ba6a1dSAlexandre Courbot 112820ba6a1dSAlexandre Courbot self 112920ba6a1dSAlexandre Courbot } 113020ba6a1dSAlexandre Courbot ); 113120ba6a1dSAlexandre Courbot }; 113220ba6a1dSAlexandre Courbot 113320ba6a1dSAlexandre Courbot // Public accessors for fields infallibly (`=>`) converted to a type. 113420ba6a1dSAlexandre Courbot ( 113520ba6a1dSAlexandre Courbot @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : 113620ba6a1dSAlexandre Courbot $hi:literal:$lo:literal $field:ident => $into_type:ty 113720ba6a1dSAlexandre Courbot ) => { 113820ba6a1dSAlexandre Courbot ::kernel::macros::paste!( 113920ba6a1dSAlexandre Courbot 114020ba6a1dSAlexandre Courbot $(#[doc = $doc])* 114120ba6a1dSAlexandre Courbot #[doc = "Returns the value of this field."] 114220ba6a1dSAlexandre Courbot #[inline(always)] 114320ba6a1dSAlexandre Courbot $vis fn $field(self) -> $into_type 114420ba6a1dSAlexandre Courbot { 114520ba6a1dSAlexandre Courbot self.[<__ $field>]().into() 114620ba6a1dSAlexandre Courbot } 114720ba6a1dSAlexandre Courbot 114820ba6a1dSAlexandre Courbot $(#[doc = $doc])* 114920ba6a1dSAlexandre Courbot #[doc = "Sets this field to the given `value`."] 115020ba6a1dSAlexandre Courbot #[inline(always)] 115120ba6a1dSAlexandre Courbot $vis fn [<with_ $field>](self, value: $into_type) -> Self 115220ba6a1dSAlexandre Courbot { 115320ba6a1dSAlexandre Courbot self.[<__with_ $field>](value.into()) 115420ba6a1dSAlexandre Courbot } 115520ba6a1dSAlexandre Courbot 115620ba6a1dSAlexandre Courbot ); 115720ba6a1dSAlexandre Courbot }; 115820ba6a1dSAlexandre Courbot 115920ba6a1dSAlexandre Courbot // Public accessors for fields fallibly (`?=>`) converted to a type. 116020ba6a1dSAlexandre Courbot ( 116120ba6a1dSAlexandre Courbot @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : 116220ba6a1dSAlexandre Courbot $hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty 116320ba6a1dSAlexandre Courbot ) => { 116420ba6a1dSAlexandre Courbot ::kernel::macros::paste!( 116520ba6a1dSAlexandre Courbot 116620ba6a1dSAlexandre Courbot $(#[doc = $doc])* 116720ba6a1dSAlexandre Courbot #[doc = "Returns the value of this field."] 116820ba6a1dSAlexandre Courbot #[inline(always)] 116920ba6a1dSAlexandre Courbot $vis fn $field(self) -> 117020ba6a1dSAlexandre Courbot Result< 117120ba6a1dSAlexandre Courbot $try_into_type, 117220ba6a1dSAlexandre Courbot <$try_into_type as ::core::convert::TryFrom< 117320ba6a1dSAlexandre Courbot ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> 117420ba6a1dSAlexandre Courbot >>::Error 117520ba6a1dSAlexandre Courbot > 117620ba6a1dSAlexandre Courbot { 117720ba6a1dSAlexandre Courbot self.[<__ $field>]().try_into() 117820ba6a1dSAlexandre Courbot } 117920ba6a1dSAlexandre Courbot 118020ba6a1dSAlexandre Courbot $(#[doc = $doc])* 118120ba6a1dSAlexandre Courbot #[doc = "Sets this field to the given `value`."] 118220ba6a1dSAlexandre Courbot #[inline(always)] 118320ba6a1dSAlexandre Courbot $vis fn [<with_ $field>](self, value: $try_into_type) -> Self 118420ba6a1dSAlexandre Courbot { 118520ba6a1dSAlexandre Courbot self.[<__with_ $field>](value.into()) 118620ba6a1dSAlexandre Courbot } 118720ba6a1dSAlexandre Courbot 118820ba6a1dSAlexandre Courbot ); 118920ba6a1dSAlexandre Courbot }; 119020ba6a1dSAlexandre Courbot 119120ba6a1dSAlexandre Courbot // Public accessors for fields not converted to a type. 119220ba6a1dSAlexandre Courbot ( 119320ba6a1dSAlexandre Courbot @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : 119420ba6a1dSAlexandre Courbot $hi:tt:$lo:tt $field:ident 119520ba6a1dSAlexandre Courbot ) => { 119620ba6a1dSAlexandre Courbot ::kernel::macros::paste!( 119720ba6a1dSAlexandre Courbot 119820ba6a1dSAlexandre Courbot $(#[doc = $doc])* 119920ba6a1dSAlexandre Courbot #[doc = "Returns the value of this field."] 120020ba6a1dSAlexandre Courbot #[inline(always)] 120120ba6a1dSAlexandre Courbot $vis fn $field(self) -> 120220ba6a1dSAlexandre Courbot ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> 120320ba6a1dSAlexandre Courbot { 120420ba6a1dSAlexandre Courbot self.[<__ $field>]() 120520ba6a1dSAlexandre Courbot } 120620ba6a1dSAlexandre Courbot 120720ba6a1dSAlexandre Courbot $(#[doc = $doc])* 120820ba6a1dSAlexandre Courbot #[doc = "Sets this field to the compile-time constant `VALUE`."] 120920ba6a1dSAlexandre Courbot #[inline(always)] 121020ba6a1dSAlexandre Courbot $vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self { 121120ba6a1dSAlexandre Courbot self.[<__with_ $field>]( 121220ba6a1dSAlexandre Courbot ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>() 121320ba6a1dSAlexandre Courbot ) 121420ba6a1dSAlexandre Courbot } 121520ba6a1dSAlexandre Courbot 121620ba6a1dSAlexandre Courbot $(#[doc = $doc])* 121720ba6a1dSAlexandre Courbot #[doc = "Sets this field to the given `value`."] 121820ba6a1dSAlexandre Courbot #[inline(always)] 121920ba6a1dSAlexandre Courbot $vis fn [<with_ $field>]<T>( 122020ba6a1dSAlexandre Courbot self, 122120ba6a1dSAlexandre Courbot value: T, 122220ba6a1dSAlexandre Courbot ) -> Self 122320ba6a1dSAlexandre Courbot where T: Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>, 122420ba6a1dSAlexandre Courbot { 122520ba6a1dSAlexandre Courbot self.[<__with_ $field>](value.into()) 122620ba6a1dSAlexandre Courbot } 122720ba6a1dSAlexandre Courbot 122820ba6a1dSAlexandre Courbot $(#[doc = $doc])* 122920ba6a1dSAlexandre Courbot #[doc = "Tries to set this field to `value`, returning an error if it is out of range."] 123020ba6a1dSAlexandre Courbot #[inline(always)] 123120ba6a1dSAlexandre Courbot $vis fn [<try_with_ $field>]<T>( 123220ba6a1dSAlexandre Courbot self, 123320ba6a1dSAlexandre Courbot value: T, 123420ba6a1dSAlexandre Courbot ) -> ::kernel::error::Result<Self> 123520ba6a1dSAlexandre Courbot where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>, 123620ba6a1dSAlexandre Courbot { 123720ba6a1dSAlexandre Courbot Ok( 123820ba6a1dSAlexandre Courbot self.[<__with_ $field>]( 123920ba6a1dSAlexandre Courbot value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)? 124020ba6a1dSAlexandre Courbot ) 124120ba6a1dSAlexandre Courbot ) 124220ba6a1dSAlexandre Courbot } 124320ba6a1dSAlexandre Courbot 124420ba6a1dSAlexandre Courbot ); 124520ba6a1dSAlexandre Courbot }; 124620ba6a1dSAlexandre Courbot 124720ba6a1dSAlexandre Courbot // `Debug` implementation. 124820ba6a1dSAlexandre Courbot (@debug $name:ident { $($field:ident;)* }) => { 124920ba6a1dSAlexandre Courbot impl ::kernel::fmt::Debug for $name { 125020ba6a1dSAlexandre Courbot fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result { 125120ba6a1dSAlexandre Courbot f.debug_struct(stringify!($name)) 125220ba6a1dSAlexandre Courbot .field("<raw>", &::kernel::prelude::fmt!("{:#x}", self.inner)) 125320ba6a1dSAlexandre Courbot $( 125420ba6a1dSAlexandre Courbot .field(stringify!($field), &self.$field()) 125520ba6a1dSAlexandre Courbot )* 125620ba6a1dSAlexandre Courbot .finish() 125720ba6a1dSAlexandre Courbot } 125820ba6a1dSAlexandre Courbot } 125920ba6a1dSAlexandre Courbot }; 126020ba6a1dSAlexandre Courbot } 1261