// SPDX-License-Identifier: GPL-2.012//! Macro to define register layout and accessors.3//!4//! The [`register!`](kernel::io::register!) macro provides an intuitive and readable syntax for5//! defining a dedicated type for each register and accessing it using [`Io`](super::Io). Each such6//! type comes with its own field accessors that can return an error if a field's value is invalid.7//!8//! Note: most of the items in this module are public so they can be referenced by the macro, but9//! most are not to be used directly by users. Outside of the `register!` macro itself, the only10//! items you might want to import from this module are [`WithBase`] and [`Array`].11//!12//! # Simple example13//!14//! ```no_run15//! use kernel::io::register;16//!17//! register! {18//! /// Basic information about the chip.19//! pub BOOT_0(u32) @ 0x00000100 {20//! /// Vendor ID.21//! 15:8 vendor_id;22//! /// Major revision of the chip.23//! 7:4 major_revision;24//! /// Minor revision of the chip.25//! 3:0 minor_revision;26//! }27//! }28//! ```29//!30//! This defines a 32-bit `BOOT_0` type which can be read from or written to offset `0x100` of an31//! `Io` region, with the described bitfields. For instance, `minor_revision` consists of the 432//! least significant bits of the type.33//!34//! Fields are instances of [`Bounded`](kernel::num::Bounded) and can be read by calling their35//! getter method, which is named after them. They also have setter methods prefixed with `with_`36//! for runtime values and `with_const_` for constant values. All setters return the updated37//! register value.38//!39//! Fields can also be transparently converted from/to an arbitrary type by using the `=>` and40//! `?=>` syntaxes.41//!42//! If present, doc comments above register or fields definitions are added to the relevant item43//! they document (the register type itself, or the field's setter and getter methods).44//!45//! Note that multiple registers can be defined in a single `register!` invocation. This can be46//! useful to group related registers together.47//!48//! Here is how the register defined above can be used in code:49//!50//!51//! ```no_run52//! use kernel::{53//! io::{54//! register,55//! Io,56//! IoLoc,57//! },58//! num::Bounded,59//! };60//! # use kernel::io::Mmio;61//! # register! {62//! # pub BOOT_0(u32) @ 0x00000100 {63//! # 15:8 vendor_id;64//! # 7:4 major_revision;65//! # 3:0 minor_revision;66//! # }67//! # }68//! # fn test(io: &Mmio<0x1000>) {69//! # fn obtain_vendor_id() -> u8 { 0xff }70//!71//! // Read from the register's defined offset (0x100).72//! let boot0 = io.read(BOOT_0);73//! pr_info!("chip revision: {}.{}", boot0.major_revision().get(), boot0.minor_revision().get());74//!75//! // Update some fields and write the new value back.76//! let new_boot0 = boot077//! // Constant values.78//! .with_const_major_revision::<3>()79//! .with_const_minor_revision::<10>()80//! // Runtime value.81//! .with_vendor_id(obtain_vendor_id());82//! io.write_reg(new_boot0);83//!84//! // Or, build a new value from zero and write it:85//! io.write_reg(BOOT_0::zeroed()86//! .with_const_major_revision::<3>()87//! .with_const_minor_revision::<10>()88//! .with_vendor_id(obtain_vendor_id())89//! );90//!91//! // Or, read and update the register in a single step.92//! io.update(BOOT_0, |r| r93//! .with_const_major_revision::<3>()94//! .with_const_minor_revision::<10>()95//! .with_vendor_id(obtain_vendor_id())96//! );97//!98//! // Constant values can also be built using the const setters.99//! const V: BOOT_0 = pin_init::zeroed::<BOOT_0>()100//! .with_const_major_revision::<3>()101//! .with_const_minor_revision::<10>();102//! # }103//! ```104//!105//! For more extensive documentation about how to define registers, see the106//! [`register!`](kernel::io::register!) macro.107108use core::marker::PhantomData;109110use crate::io::IoLoc;111112use kernel::build_assert;113114/// Trait implemented by all registers.115pub trait Register: Sized {116/// Backing primitive type of the register.117type Storage: Into<Self> + From<Self>;118119/// Start offset of the register.120///121/// The interpretation of this offset depends on the type of the register.122const OFFSET: usize;123}124125/// Trait implemented by registers with a fixed offset.126pub trait FixedRegister: Register {}127128/// Allows `()` to be used as the `location` parameter of [`Io::write`](super::Io::write) when129/// passing a [`FixedRegister`] value.130impl<T> IoLoc<T> for ()131where132T: FixedRegister,133{134type IoType = T::Storage;135136#[inline(always)]137fn offset(self) -> usize {138T::OFFSET139}140}141142/// A [`FixedRegister`] carries its location in its type. Thus `FixedRegister` values can be used143/// as an [`IoLoc`].144impl<T> IoLoc<T> for T145where146T: FixedRegister,147{148type IoType = T::Storage;149150#[inline(always)]151fn offset(self) -> usize {152T::OFFSET153}154}155156/// Location of a fixed register.157pub struct FixedRegisterLoc<T: FixedRegister>(PhantomData<T>);158159impl<T: FixedRegister> FixedRegisterLoc<T> {160/// Returns the location of `T`.161#[inline(always)]162// We do not implement `Default` so we can be const.163#[expect(clippy::new_without_default)]164pub const fn new() -> Self {165Self(PhantomData)166}167}168169impl<T> IoLoc<T> for FixedRegisterLoc<T>170where171T: FixedRegister,172{173type IoType = T::Storage;174175#[inline(always)]176fn offset(self) -> usize {177T::OFFSET178}179}180181/// Trait providing a base address to be added to the offset of a relative register to obtain182/// its actual offset.183///184/// The `T` generic argument is used to distinguish which base to use, in case a type provides185/// several bases. It is given to the `register!` macro to restrict the use of the register to186/// implementors of this particular variant.187pub trait RegisterBase<T> {188/// Base address to which register offsets are added.189const BASE: usize;190}191192/// Trait implemented by all registers that are relative to a base.193pub trait WithBase {194/// Family of bases applicable to this register.195type BaseFamily;196197/// Returns the absolute location of this type when using `B` as its base.198#[inline(always)]199fn of<B: RegisterBase<Self::BaseFamily>>() -> RelativeRegisterLoc<Self, B>200where201Self: Register,202{203RelativeRegisterLoc::new()204}205}206207/// Trait implemented by relative registers.208pub trait RelativeRegister: Register + WithBase {}209210/// Location of a relative register.211///212/// This can either be an immediately accessible regular [`RelativeRegister`], or a213/// [`RelativeRegisterArray`] that needs one additional resolution through214/// [`RelativeRegisterLoc::at`].215pub struct RelativeRegisterLoc<T: WithBase, B: ?Sized>(PhantomData<T>, PhantomData<B>);216217impl<T, B> RelativeRegisterLoc<T, B>218where219T: Register + WithBase,220B: RegisterBase<T::BaseFamily> + ?Sized,221{222/// Returns the location of a relative register or register array.223#[inline(always)]224// We do not implement `Default` so we can be const.225#[expect(clippy::new_without_default)]226pub const fn new() -> Self {227Self(PhantomData, PhantomData)228}229230// Returns the absolute offset of the relative register using base `B`.231//232// This is implemented as a private const method so it can be reused by the [`IoLoc`]233// implementations of both [`RelativeRegisterLoc`] and [`RelativeRegisterArrayLoc`].234#[inline]235const fn offset(self) -> usize {236B::BASE + T::OFFSET237}238}239240impl<T, B> IoLoc<T> for RelativeRegisterLoc<T, B>241where242T: RelativeRegister,243B: RegisterBase<T::BaseFamily> + ?Sized,244{245type IoType = T::Storage;246247#[inline(always)]248fn offset(self) -> usize {249RelativeRegisterLoc::offset(self)250}251}252253/// Trait implemented by arrays of registers.254pub trait RegisterArray: Register {255/// Number of elements in the registers array.256const SIZE: usize;257/// Number of bytes between the start of elements in the registers array.258const STRIDE: usize;259}260261/// Location of an array register.262pub struct RegisterArrayLoc<T: RegisterArray>(usize, PhantomData<T>);263264impl<T: RegisterArray> RegisterArrayLoc<T> {265/// Returns the location of register `T` at position `idx`, with build-time validation.266#[inline(always)]267pub fn new(idx: usize) -> Self {268build_assert!(idx < T::SIZE);269270Self(idx, PhantomData)271}272273/// Attempts to return the location of register `T` at position `idx`, with runtime validation.274#[inline(always)]275pub fn try_new(idx: usize) -> Option<Self> {276if idx < T::SIZE {277Some(Self(idx, PhantomData))278} else {279None280}281}282}283284impl<T> IoLoc<T> for RegisterArrayLoc<T>285where286T: RegisterArray,287{288type IoType = T::Storage;289290#[inline(always)]291fn offset(self) -> usize {292T::OFFSET + self.0 * T::STRIDE293}294}295296/// Trait providing location builders for [`RegisterArray`]s.297pub trait Array {298/// Returns the location of the register at position `idx`, with build-time validation.299#[inline(always)]300fn at(idx: usize) -> RegisterArrayLoc<Self>301where302Self: RegisterArray,303{304RegisterArrayLoc::new(idx)305}306307/// Returns the location of the register at position `idx`, with runtime validation.308#[inline(always)]309fn try_at(idx: usize) -> Option<RegisterArrayLoc<Self>>310where311Self: RegisterArray,312{313RegisterArrayLoc::try_new(idx)314}315}316317/// Trait implemented by arrays of relative registers.318pub trait RelativeRegisterArray: RegisterArray + WithBase {}319320/// Location of a relative array register.321pub struct RelativeRegisterArrayLoc<322T: RelativeRegisterArray,323B: RegisterBase<T::BaseFamily> + ?Sized,324>(RelativeRegisterLoc<T, B>, usize);325326impl<T, B> RelativeRegisterArrayLoc<T, B>327where328T: RelativeRegisterArray,329B: RegisterBase<T::BaseFamily> + ?Sized,330{331/// Returns the location of register `T` from the base `B` at index `idx`, with build-time332/// validation.333#[inline(always)]334pub fn new(idx: usize) -> Self {335build_assert!(idx < T::SIZE);336337Self(RelativeRegisterLoc::new(), idx)338}339340/// Attempts to return the location of register `T` from the base `B` at index `idx`, with341/// runtime validation.342#[inline(always)]343pub fn try_new(idx: usize) -> Option<Self> {344if idx < T::SIZE {345Some(Self(RelativeRegisterLoc::new(), idx))346} else {347None348}349}350}351352/// Methods exclusive to [`RelativeRegisterLoc`]s created with a [`RelativeRegisterArray`].353impl<T, B> RelativeRegisterLoc<T, B>354where355T: RelativeRegisterArray,356B: RegisterBase<T::BaseFamily> + ?Sized,357{358/// Returns the location of the register at position `idx`, with build-time validation.359#[inline(always)]360pub fn at(self, idx: usize) -> RelativeRegisterArrayLoc<T, B> {361RelativeRegisterArrayLoc::new(idx)362}363364/// Returns the location of the register at position `idx`, with runtime validation.365#[inline(always)]366pub fn try_at(self, idx: usize) -> Option<RelativeRegisterArrayLoc<T, B>> {367RelativeRegisterArrayLoc::try_new(idx)368}369}370371impl<T, B> IoLoc<T> for RelativeRegisterArrayLoc<T, B>372where373T: RelativeRegisterArray,374B: RegisterBase<T::BaseFamily> + ?Sized,375{376type IoType = T::Storage;377378#[inline(always)]379fn offset(self) -> usize {380self.0.offset() + self.1 * T::STRIDE381}382}383384/// Trait implemented by items that contain both a register value and the absolute I/O location at385/// which to write it.386///387/// Implementors can be used with [`Io::write_reg`](super::Io::write_reg).388pub trait LocatedRegister {389/// Register value to write.390type Value: Register;391/// Full location information at which to write the value.392type Location: IoLoc<Self::Value>;393394/// Consumes `self` and returns a `(location, value)` tuple describing a valid I/O write395/// operation.396fn into_io_op(self) -> (Self::Location, Self::Value);397}398399impl<T> LocatedRegister for T400where401T: FixedRegister,402{403type Location = FixedRegisterLoc<Self::Value>;404type Value = T;405406#[inline(always)]407fn into_io_op(self) -> (FixedRegisterLoc<T>, T) {408(FixedRegisterLoc::new(), self)409}410}411412/// Defines a dedicated type for a register, including getter and setter methods for its fields and413/// methods to read and write it from an [`Io`](kernel::io::Io) region.414///415/// This documentation focuses on how to declare registers. See the [module-level416/// documentation](mod@kernel::io::register) for examples of how to access them.417///418/// There are 4 possible kinds of registers: fixed offset registers, relative registers, arrays of419/// registers, and relative arrays of registers.420///421/// ## Fixed offset registers422///423/// These are the simplest kind of registers. Their location is simply an offset inside the I/O424/// region. For instance:425///426/// ```ignore427/// register! {428/// pub FIXED_REG(u16) @ 0x80 {429/// ...430/// }431/// }432/// ```433///434/// This creates a 16-bit register named `FIXED_REG` located at offset `0x80` of an I/O region.435///436/// These registers' location can be built simply by referencing their name:437///438/// ```no_run439/// use kernel::{440/// io::{441/// register,442/// Io,443/// },444/// };445/// # use kernel::io::Mmio;446///447/// register! {448/// FIXED_REG(u32) @ 0x100 {449/// 16:8 high_byte;450/// 7:0 low_byte;451/// }452/// }453///454/// # fn test(io: &Mmio<0x1000>) {455/// let val = io.read(FIXED_REG);456///457/// // Write from an already-existing value.458/// io.write(FIXED_REG, val.with_low_byte(0xff));459///460/// // Create a register value from scratch.461/// let val2 = FIXED_REG::zeroed().with_high_byte(0x80);462///463/// // The location of fixed offset registers is already contained in their type. Thus, the464/// // `location` argument of `Io::write` is technically redundant and can be replaced by `()`.465/// io.write((), val2);466///467/// // Or, the single-argument `Io::write_reg` can be used.468/// io.write_reg(val2);469/// # }470///471/// ```472///473/// It is possible to create an alias of an existing register with new field definitions by using474/// the `=> ALIAS` syntax. This is useful for cases where a register's interpretation depends on475/// the context:476///477/// ```no_run478/// use kernel::io::register;479///480/// register! {481/// /// Scratch register.482/// pub SCRATCH(u32) @ 0x00000200 {483/// 31:0 value;484/// }485///486/// /// Boot status of the firmware.487/// pub SCRATCH_BOOT_STATUS(u32) => SCRATCH {488/// 0:0 completed;489/// }490/// }491/// ```492///493/// In this example, `SCRATCH_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while providing494/// its own `completed` field.495///496/// ## Relative registers497///498/// Relative registers can be instantiated several times at a relative offset of a group of bases.499/// For instance, imagine the following I/O space:500///501/// ```text502/// +-----------------------------+503/// | ... |504/// | |505/// 0x100--->+------------CPU0-------------+506/// | |507/// 0x110--->+-----------------------------+508/// | CPU_CTL |509/// +-----------------------------+510/// | ... |511/// | |512/// | |513/// 0x200--->+------------CPU1-------------+514/// | |515/// 0x210--->+-----------------------------+516/// | CPU_CTL |517/// +-----------------------------+518/// | ... |519/// +-----------------------------+520/// ```521///522/// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O523/// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define524/// them twice and would prefer a way to select which one to use from a single definition.525///526/// This can be done using the `Base + Offset` syntax when specifying the register's address:527///528/// ```ignore529/// register! {530/// pub RELATIVE_REG(u32) @ Base + 0x80 {531/// ...532/// }533/// }534/// ```535///536/// This creates a register with an offset of `0x80` from a given base.537///538/// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the539/// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for540/// this register needs to implement `RegisterBase<Base>`.541///542/// The location of relative registers can be built using the [`WithBase::of`] method to specify543/// its base. All relative registers implement [`WithBase`].544///545/// Here is the above layout translated into code:546///547/// ```no_run548/// use kernel::{549/// io::{550/// register,551/// register::{552/// RegisterBase,553/// WithBase,554/// },555/// Io,556/// },557/// };558/// # use kernel::io::Mmio;559///560/// // Type used to identify the base.561/// pub struct CpuCtlBase;562///563/// // ZST describing `CPU0`.564/// struct Cpu0;565/// impl RegisterBase<CpuCtlBase> for Cpu0 {566/// const BASE: usize = 0x100;567/// }568///569/// // ZST describing `CPU1`.570/// struct Cpu1;571/// impl RegisterBase<CpuCtlBase> for Cpu1 {572/// const BASE: usize = 0x200;573/// }574///575/// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`.576/// register! {577/// /// CPU core control.578/// pub CPU_CTL(u32) @ CpuCtlBase + 0x10 {579/// 0:0 start;580/// }581/// }582///583/// # fn test(io: Mmio<0x1000>) {584/// // Read the status of `Cpu0`.585/// let cpu0_started = io.read(CPU_CTL::of::<Cpu0>());586///587/// // Stop `Cpu0`.588/// io.write(WithBase::of::<Cpu0>(), CPU_CTL::zeroed());589/// # }590///591/// // Aliases can also be defined for relative register.592/// register! {593/// /// Alias to CPU core control.594/// pub CPU_CTL_ALIAS(u32) => CpuCtlBase + CPU_CTL {595/// /// Start the aliased CPU core.596/// 1:1 alias_start;597/// }598/// }599///600/// # fn test2(io: Mmio<0x1000>) {601/// // Start the aliased `CPU0`, leaving its other fields untouched.602/// io.update(CPU_CTL_ALIAS::of::<Cpu0>(), |r| r.with_alias_start(true));603/// # }604/// ```605///606/// ## Arrays of registers607///608/// Some I/O areas contain consecutive registers that share the same field layout. These areas can609/// be defined as an array of identical registers, allowing them to be accessed by index with610/// compile-time or runtime bound checking:611///612/// ```ignore613/// register! {614/// pub REGISTER_ARRAY(u8)[10, stride = 4] @ 0x100 {615/// ...616/// }617/// }618/// ```619///620/// This defines `REGISTER_ARRAY`, an array of 10 byte registers starting at offset `0x100`. Each621/// register is separated from its neighbor by 4 bytes.622///623/// The `stride` parameter is optional; if unspecified, the registers are placed consecutively from624/// each other.625///626/// A location for a register in a register array is built using the [`Array::at`] trait method.627/// All arrays of registers implement [`Array`].628///629/// ```no_run630/// use kernel::{631/// io::{632/// register,633/// register::Array,634/// Io,635/// },636/// };637/// # use kernel::io::Mmio;638/// # fn get_scratch_idx() -> usize {639/// # 0x15640/// # }641///642/// // Array of 64 consecutive registers with the same layout starting at offset `0x80`.643/// register! {644/// /// Scratch registers.645/// pub SCRATCH(u32)[64] @ 0x00000080 {646/// 31:0 value;647/// }648/// }649///650/// # fn test(io: &Mmio<0x1000>)651/// # -> Result<(), Error>{652/// // Read scratch register 0, i.e. I/O address `0x80`.653/// let scratch_0 = io.read(SCRATCH::at(0)).value();654///655/// // Write scratch register 15, i.e. I/O address `0x80 + (15 * 4)`.656/// io.write(Array::at(15), SCRATCH::from(0xffeeaabb));657///658/// // This is out of bounds and won't build.659/// // let scratch_128 = io.read(SCRATCH::at(128)).value();660///661/// // Runtime-obtained array index.662/// let idx = get_scratch_idx();663/// // Access on a runtime index returns an error if it is out-of-bounds.664/// let some_scratch = io.read(SCRATCH::try_at(idx).ok_or(EINVAL)?).value();665///666/// // Alias to a specific register in an array.667/// // Here `SCRATCH[8]` is used to convey the firmware exit code.668/// register! {669/// /// Firmware exit status code.670/// pub FIRMWARE_STATUS(u32) => SCRATCH[8] {671/// 7:0 status;672/// }673/// }674///675/// let status = io.read(FIRMWARE_STATUS).status();676///677/// // Non-contiguous register arrays can be defined by adding a stride parameter.678/// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the679/// // registers of the two declarations below are interleaved.680/// register! {681/// /// Scratch registers bank 0.682/// pub SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ 0x000000c0 {683/// 31:0 value;684/// }685///686/// /// Scratch registers bank 1.687/// pub SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ 0x000000c4 {688/// 31:0 value;689/// }690/// }691/// # Ok(())692/// # }693/// ```694///695/// ## Relative arrays of registers696///697/// Combining the two features described in the sections above, arrays of registers accessible from698/// a base can also be defined:699///700/// ```ignore701/// register! {702/// pub RELATIVE_REGISTER_ARRAY(u8)[10, stride = 4] @ Base + 0x100 {703/// ...704/// }705/// }706/// ```707///708/// Like relative registers, they implement the [`WithBase`] trait. However the return value of709/// [`WithBase::of`] cannot be used directly as a location and must be further specified using the710/// [`at`](RelativeRegisterLoc::at) method.711///712/// ```no_run713/// use kernel::{714/// io::{715/// register,716/// register::{717/// RegisterBase,718/// WithBase,719/// },720/// Io,721/// },722/// };723/// # use kernel::io::Mmio;724/// # fn get_scratch_idx() -> usize {725/// # 0x15726/// # }727///728/// // Type used as parameter of `RegisterBase` to specify the base.729/// pub struct CpuCtlBase;730///731/// // ZST describing `CPU0`.732/// struct Cpu0;733/// impl RegisterBase<CpuCtlBase> for Cpu0 {734/// const BASE: usize = 0x100;735/// }736///737/// // ZST describing `CPU1`.738/// struct Cpu1;739/// impl RegisterBase<CpuCtlBase> for Cpu1 {740/// const BASE: usize = 0x200;741/// }742///743/// // 64 per-cpu scratch registers, arranged as a contiguous array.744/// register! {745/// /// Per-CPU scratch registers.746/// pub CPU_SCRATCH(u32)[64] @ CpuCtlBase + 0x00000080 {747/// 31:0 value;748/// }749/// }750///751/// # fn test(io: &Mmio<0x1000>) -> Result<(), Error> {752/// // Read scratch register 0 of CPU0.753/// let scratch = io.read(CPU_SCRATCH::of::<Cpu0>().at(0));754///755/// // Write the retrieved value into scratch register 15 of CPU1.756/// io.write(WithBase::of::<Cpu1>().at(15), scratch);757///758/// // This won't build.759/// // let cpu0_scratch_128 = io.read(CPU_SCRATCH::of::<Cpu0>().at(128)).value();760///761/// // Runtime-obtained array index.762/// let scratch_idx = get_scratch_idx();763/// // Access on a runtime index returns an error if it is out-of-bounds.764/// let cpu0_scratch = io.read(765/// CPU_SCRATCH::of::<Cpu0>().try_at(scratch_idx).ok_or(EINVAL)?766/// ).value();767/// # Ok(())768/// # }769///770/// // Alias to `SCRATCH[8]` used to convey the firmware exit code.771/// register! {772/// /// Per-CPU firmware exit status code.773/// pub CPU_FIRMWARE_STATUS(u32) => CpuCtlBase + CPU_SCRATCH[8] {774/// 7:0 status;775/// }776/// }777///778/// // Non-contiguous relative register arrays can be defined by adding a stride parameter.779/// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the780/// // registers of the two declarations below are interleaved.781/// register! {782/// /// Scratch registers bank 0.783/// pub CPU_SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d00 {784/// 31:0 value;785/// }786///787/// /// Scratch registers bank 1.788/// pub CPU_SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d04 {789/// 31:0 value;790/// }791/// }792///793/// # fn test2(io: &Mmio<0x1000>) -> Result<(), Error> {794/// let cpu0_status = io.read(CPU_FIRMWARE_STATUS::of::<Cpu0>()).status();795/// # Ok(())796/// # }797/// ```798#[macro_export]799macro_rules! register {800// Entry point for the macro, allowing multiple registers to be defined in one call.801// It matches all possible register declaration patterns to dispatch them to corresponding802// `@reg` rule that defines a single register.803(804$(805$(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)806$([ $size:expr $(, stride = $stride:expr)? ])?807$(@ $($base:ident +)? $offset:literal)?808$(=> $alias:ident $(+ $alias_offset:ident)? $([$alias_idx:expr])? )?809{ $($fields:tt)* }810)*811) => {812$(813$crate::register!(814@reg $(#[$attr])* $vis $name ($storage) $([$size $(, stride = $stride)?])?815$(@ $($base +)? $offset)?816$(=> $alias $(+ $alias_offset)? $([$alias_idx])? )?817{ $($fields)* }818);819)*820};821822// All the rules below are private helpers.823824// Creates a register at a fixed offset of the MMIO space.825(826@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $offset:literal827{ $($fields:tt)* }828) => {829$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });830$crate::register!(@io_base $name($storage) @ $offset);831$crate::register!(@io_fixed $(#[$attr])* $vis $name($storage));832};833834// Creates an alias register of fixed offset register `alias` with its own fields.835(836@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident837{ $($fields:tt)* }838) => {839$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });840$crate::register!(841@io_base $name($storage) @842<$alias as $crate::io::register::Register>::OFFSET843);844$crate::register!(@io_fixed $(#[$attr])* $vis $name($storage));845};846847// Creates a register at a relative offset from a base address provider.848(849@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $base:ident + $offset:literal850{ $($fields:tt)* }851) => {852$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });853$crate::register!(@io_base $name($storage) @ $offset);854$crate::register!(@io_relative $vis $name($storage) @ $base);855};856857// Creates an alias register of relative offset register `alias` with its own fields.858(859@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $base:ident + $alias:ident860{ $($fields:tt)* }861) => {862$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });863$crate::register!(864@io_base $name($storage) @ <$alias as $crate::io::register::Register>::OFFSET865);866$crate::register!(@io_relative $vis $name($storage) @ $base);867};868869// Creates an array of registers at a fixed offset of the MMIO space.870(871@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)872[ $size:expr, stride = $stride:expr ] @ $offset:literal { $($fields:tt)* }873) => {874::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride);875876$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });877$crate::register!(@io_base $name($storage) @ $offset);878$crate::register!(@io_array $vis $name($storage) [ $size, stride = $stride ]);879};880881// Shortcut for contiguous array of registers (stride == size of element).882(883@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ] @ $offset:literal884{ $($fields:tt)* }885) => {886$crate::register!(887$(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ]888@ $offset { $($fields)* }889);890};891892// Creates an alias of register `idx` of array of registers `alias` with its own fields.893(894@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident [ $idx:expr ]895{ $($fields:tt)* }896) => {897::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE);898899$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });900$crate::register!(901@io_base $name($storage) @902<$alias as $crate::io::register::Register>::OFFSET903+ $idx * <$alias as $crate::io::register::RegisterArray>::STRIDE904);905$crate::register!(@io_fixed $(#[$attr])* $vis $name($storage));906};907908// Creates an array of registers at a relative offset from a base address provider.909(910@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)911[ $size:expr, stride = $stride:expr ]912@ $base:ident + $offset:literal { $($fields:tt)* }913) => {914::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride);915916$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });917$crate::register!(@io_base $name($storage) @ $offset);918$crate::register!(919@io_relative_array $vis $name($storage) [ $size, stride = $stride ] @ $base + $offset920);921};922923// Shortcut for contiguous array of relative registers (stride == size of element).924(925@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ]926@ $base:ident + $offset:literal { $($fields:tt)* }927) => {928$crate::register!(929$(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ]930@ $base + $offset { $($fields)* }931);932};933934// Creates an alias of register `idx` of relative array of registers `alias` with its own935// fields.936(937@reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)938=> $base:ident + $alias:ident [ $idx:expr ] { $($fields:tt)* }939) => {940::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE);941942$crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* });943$crate::register!(944@io_base $name($storage) @945<$alias as $crate::io::register::Register>::OFFSET +946$idx * <$alias as $crate::io::register::RegisterArray>::STRIDE947);948$crate::register!(@io_relative $vis $name($storage) @ $base);949};950951// Generates the bitfield for the register.952//953// `#[allow(non_camel_case_types)]` is added since register names typically use954// `SCREAMING_CASE`.955(956@bitfield $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* }957) => {958$crate::register!(@bitfield_core959#[allow(non_camel_case_types)]960$(#[$attr])* $vis $name $storage961);962$crate::register!(@bitfield_fields $vis $name $storage { $($fields)* });963};964965// Implementations shared by all registers types.966(@io_base $name:ident($storage:ty) @ $offset:expr) => {967impl $crate::io::register::Register for $name {968type Storage = $storage;969970const OFFSET: usize = $offset;971}972};973974// Implementations of fixed registers.975(@io_fixed $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)) => {976impl $crate::io::register::FixedRegister for $name {}977978$(#[$attr])*979$vis const $name: $crate::io::register::FixedRegisterLoc<$name> =980$crate::io::register::FixedRegisterLoc::<$name>::new();981};982983// Implementations of relative registers.984(@io_relative $vis:vis $name:ident ($storage:ty) @ $base:ident) => {985impl $crate::io::register::WithBase for $name {986type BaseFamily = $base;987}988989impl $crate::io::register::RelativeRegister for $name {}990};991992// Implementations of register arrays.993(@io_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ]) => {994impl $crate::io::register::Array for $name {}995996impl $crate::io::register::RegisterArray for $name {997const SIZE: usize = $size;998const STRIDE: usize = $stride;999}1000};10011002// Implementations of relative array registers.1003(1004@io_relative_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ]1005@ $base:ident + $offset:literal1006) => {1007impl $crate::io::register::WithBase for $name {1008type BaseFamily = $base;1009}10101011impl $crate::io::register::RegisterArray for $name {1012const SIZE: usize = $size;1013const STRIDE: usize = $stride;1014}10151016impl $crate::io::register::RelativeRegisterArray for $name {}1017};10181019// Defines the wrapper `$name` type and its conversions from/to the storage type.1020(@bitfield_core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => {1021$(#[$attr])*1022#[repr(transparent)]1023#[derive(Clone, Copy, PartialEq, Eq)]1024$vis struct $name {1025inner: $storage,1026}10271028#[allow(dead_code)]1029impl $name {1030/// Creates a bitfield from a raw value.1031#[inline(always)]1032$vis const fn from_raw(value: $storage) -> Self {1033Self{ inner: value }1034}10351036/// Turns this bitfield into its raw value.1037///1038/// This is similar to the [`From`] implementation, but is shorter to invoke in1039/// most cases.1040#[inline(always)]1041$vis const fn into_raw(self) -> $storage {1042self.inner1043}1044}10451046// SAFETY: `$storage` is `Zeroable` and `$name` is transparent.1047unsafe impl ::pin_init::Zeroable for $name {}10481049impl ::core::convert::From<$name> for $storage {1050#[inline(always)]1051fn from(val: $name) -> $storage {1052val.into_raw()1053}1054}10551056impl ::core::convert::From<$storage> for $name {1057#[inline(always)]1058fn from(val: $storage) -> $name {1059Self::from_raw(val)1060}1061}1062};10631064// Definitions requiring knowledge of individual fields: private and public field accessors,1065// and `Debug` implementation.1066(@bitfield_fields $vis:vis $name:ident $storage:ty {1067$($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident1068$(?=> $try_into_type:ty)?1069$(=> $into_type:ty)?1070;1071)*1072}1073) => {1074#[allow(dead_code)]1075impl $name {1076$(1077$crate::register!(@private_field_accessors $vis $name $storage : $hi:$lo $field);1078$crate::register!(1079@public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field1080$(?=> $try_into_type)?1081$(=> $into_type)?1082);1083)*1084}10851086$crate::register!(@debug $name { $($field;)* });1087};10881089// Private field accessors working with the exact `Bounded` type for the field.1090(1091@private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident1092) => {1093::kernel::macros::paste!(1094$vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;1095$vis const [<$field:upper _MASK>]: $storage =1096((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);1097$vis const [<$field:upper _SHIFT>]: u32 = $lo;1098);10991100::kernel::macros::paste!(1101fn [<__ $field>](self) ->1102::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> {1103// Left shift to align the field's MSB with the storage MSB.1104const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1);1105// Right shift to move the top-aligned field to bit 0 of the storage.1106const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo;11071108// Extract the field using two shifts. `Bounded::shr` produces the correctly-sized1109// output type.1110let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from(1111self.inner << ALIGN_TOP1112);1113val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >()1114}11151116const fn [<__with_ $field>](1117mut self,1118value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>,1119) -> Self1120{1121const MASK: $storage = <$name>::[<$field:upper _MASK>];1122const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>];11231124let value = value.get() << SHIFT;1125self.inner = (self.inner & !MASK) | value;11261127self1128}1129);1130};11311132// Public accessors for fields infallibly (`=>`) converted to a type.1133(1134@public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :1135$hi:literal:$lo:literal $field:ident => $into_type:ty1136) => {1137::kernel::macros::paste!(11381139$(#[doc = $doc])*1140#[doc = "Returns the value of this field."]1141#[inline(always)]1142$vis fn $field(self) -> $into_type1143{1144self.[<__ $field>]().into()1145}11461147$(#[doc = $doc])*1148#[doc = "Sets this field to the given `value`."]1149#[inline(always)]1150$vis fn [<with_ $field>](self, value: $into_type) -> Self1151{1152self.[<__with_ $field>](value.into())1153}11541155);1156};11571158// Public accessors for fields fallibly (`?=>`) converted to a type.1159(1160@public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :1161$hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty1162) => {1163::kernel::macros::paste!(11641165$(#[doc = $doc])*1166#[doc = "Returns the value of this field."]1167#[inline(always)]1168$vis fn $field(self) ->1169Result<1170$try_into_type,1171<$try_into_type as ::core::convert::TryFrom<1172::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>1173>>::Error1174>1175{1176self.[<__ $field>]().try_into()1177}11781179$(#[doc = $doc])*1180#[doc = "Sets this field to the given `value`."]1181#[inline(always)]1182$vis fn [<with_ $field>](self, value: $try_into_type) -> Self1183{1184self.[<__with_ $field>](value.into())1185}11861187);1188};11891190// Public accessors for fields not converted to a type.1191(1192@public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty :1193$hi:tt:$lo:tt $field:ident1194) => {1195::kernel::macros::paste!(11961197$(#[doc = $doc])*1198#[doc = "Returns the value of this field."]1199#[inline(always)]1200$vis fn $field(self) ->1201::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>1202{1203self.[<__ $field>]()1204}12051206$(#[doc = $doc])*1207#[doc = "Sets this field to the compile-time constant `VALUE`."]1208#[inline(always)]1209$vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self {1210self.[<__with_ $field>](1211::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>()1212)1213}12141215$(#[doc = $doc])*1216#[doc = "Sets this field to the given `value`."]1217#[inline(always)]1218$vis fn [<with_ $field>]<T>(1219self,1220value: T,1221) -> Self1222where T: Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>,1223{1224self.[<__with_ $field>](value.into())1225}12261227$(#[doc = $doc])*1228#[doc = "Tries to set this field to `value`, returning an error if it is out of range."]1229#[inline(always)]1230$vis fn [<try_with_ $field>]<T>(1231self,1232value: T,1233) -> ::kernel::error::Result<Self>1234where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>,1235{1236Ok(1237self.[<__with_ $field>](1238value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)?1239)1240)1241}12421243);1244};12451246// `Debug` implementation.1247(@debug $name:ident { $($field:ident;)* }) => {1248impl ::kernel::fmt::Debug for $name {1249fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {1250f.debug_struct(stringify!($name))1251.field("<raw>", &::kernel::prelude::fmt!("{:#x}", self.inner))1252$(1253.field(stringify!($field), &self.$field())1254)*1255.finish()1256}1257}1258};1259}126012611262