xref: /linux/rust/kernel/io/register.rs (revision 4793dae01f47754e288cdbb3a22581cac2317f2b)
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