// SPDX-License-Identifier: GPL-2.012//! `register!` macro to define register layout and accessors.3//!4//! A single register typically includes several fields, which are accessed through a combination5//! of bit-shift and mask operations that introduce a class of potential mistakes, notably because6//! not all possible field values are necessarily valid.7//!8//! The `register!` macro in this module provides an intuitive and readable syntax for defining a9//! dedicated type for each register. Each such type comes with its own field accessors that can10//! return an error if a field's value is invalid.1112/// Trait providing a base address to be added to the offset of a relative register to obtain13/// its actual offset.14///15/// The `T` generic argument is used to distinguish which base to use, in case a type provides16/// several bases. It is given to the `register!` macro to restrict the use of the register to17/// implementors of this particular variant.18pub(crate) trait RegisterBase<T> {19const BASE: usize;20}2122/// Defines a dedicated type for a register with an absolute offset, including getter and setter23/// methods for its fields and methods to read and write it from an `Io` region.24///25/// Example:26///27/// ```no_run28/// register!(BOOT_0 @ 0x00000100, "Basic revision information about the GPU" {29/// 3:0 minor_revision as u8, "Minor revision of the chip";30/// 7:4 major_revision as u8, "Major revision of the chip";31/// 28:20 chipset as u32 ?=> Chipset, "Chipset model";32/// });33/// ```34///35/// This defines a `BOOT_0` type which can be read or written from offset `0x100` of an `Io`36/// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 least37/// significant bits of the register. Each field can be accessed and modified using accessor38/// methods:39///40/// ```no_run41/// // Read from the register's defined offset (0x100).42/// let boot0 = BOOT_0::read(&bar);43/// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_revision());44///45/// // `Chipset::try_from` is called with the value of the `chipset` field and returns an46/// // error if it is invalid.47/// let chipset = boot0.chipset()?;48///49/// // Update some fields and write the value back.50/// boot0.set_major_revision(3).set_minor_revision(10).write(&bar);51///52/// // Or, just read and update the register in a single step:53/// BOOT_0::alter(&bar, |r| r.set_major_revision(3).set_minor_revision(10));54/// ```55///56/// Fields are defined as follows:57///58/// - `as <type>` simply returns the field value casted to <type>, typically `u32`, `u16`, `u8` or59/// `bool`. Note that `bool` fields must have a range of 1 bit.60/// - `as <type> => <into_type>` calls `<into_type>`'s `From::<<type>>` implementation and returns61/// the result.62/// - `as <type> ?=> <try_into_type>` calls `<try_into_type>`'s `TryFrom::<<type>>` implementation63/// and returns the result. This is useful with fields for which not all values are valid.64///65/// The documentation strings are optional. If present, they will be added to the type's66/// definition, or the field getter and setter methods they are attached to.67///68/// It is also possible to create a alias register by using the `=> ALIAS` syntax. This is useful69/// for cases where a register's interpretation depends on the context:70///71/// ```no_run72/// register!(SCRATCH @ 0x00000200, "Scratch register" {73/// 31:0 value as u32, "Raw value";74/// });75///76/// register!(SCRATCH_BOOT_STATUS => SCRATCH, "Boot status of the firmware" {77/// 0:0 completed as bool, "Whether the firmware has completed booting";78/// });79/// ```80///81/// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while also82/// providing its own `completed` field.83///84/// ## Relative registers85///86/// A register can be defined as being accessible from a fixed offset of a provided base. For87/// instance, imagine the following I/O space:88///89/// ```text90/// +-----------------------------+91/// | ... |92/// | |93/// 0x100--->+------------CPU0-------------+94/// | |95/// 0x110--->+-----------------------------+96/// | CPU_CTL |97/// +-----------------------------+98/// | ... |99/// | |100/// | |101/// 0x200--->+------------CPU1-------------+102/// | |103/// 0x210--->+-----------------------------+104/// | CPU_CTL |105/// +-----------------------------+106/// | ... |107/// +-----------------------------+108/// ```109///110/// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O111/// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define112/// them twice and would prefer a way to select which one to use from a single definition113///114/// This can be done using the `Base[Offset]` syntax when specifying the register's address.115///116/// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the117/// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for118/// this register needs to implement `RegisterBase<Base>`. Here is the above example translated119/// into code:120///121/// ```no_run122/// // Type used to identify the base.123/// pub(crate) struct CpuCtlBase;124///125/// // ZST describing `CPU0`.126/// struct Cpu0;127/// impl RegisterBase<CpuCtlBase> for Cpu0 {128/// const BASE: usize = 0x100;129/// }130/// // Singleton of `CPU0` used to identify it.131/// const CPU0: Cpu0 = Cpu0;132///133/// // ZST describing `CPU1`.134/// struct Cpu1;135/// impl RegisterBase<CpuCtlBase> for Cpu1 {136/// const BASE: usize = 0x200;137/// }138/// // Singleton of `CPU1` used to identify it.139/// const CPU1: Cpu1 = Cpu1;140///141/// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`.142/// register!(CPU_CTL @ CpuCtlBase[0x10], "CPU core control" {143/// 0:0 start as bool, "Start the CPU core";144/// });145///146/// // The `read`, `write` and `alter` methods of relative registers take an extra `base` argument147/// // that is used to resolve its final address by adding its `BASE` to the offset of the148/// // register.149///150/// // Start `CPU0`.151/// CPU_CTL::alter(bar, &CPU0, |r| r.set_start(true));152///153/// // Start `CPU1`.154/// CPU_CTL::alter(bar, &CPU1, |r| r.set_start(true));155///156/// // Aliases can also be defined for relative register.157/// register!(CPU_CTL_ALIAS => CpuCtlBase[CPU_CTL], "Alias to CPU core control" {158/// 1:1 alias_start as bool, "Start the aliased CPU core";159/// });160///161/// // Start the aliased `CPU0`.162/// CPU_CTL_ALIAS::alter(bar, &CPU0, |r| r.set_alias_start(true));163/// ```164///165/// ## Arrays of registers166///167/// Some I/O areas contain consecutive values that can be interpreted in the same way. These areas168/// can be defined as an array of identical registers, allowing them to be accessed by index with169/// compile-time or runtime bound checking. Simply define their address as `Address[Size]`, and add170/// an `idx` parameter to their `read`, `write` and `alter` methods:171///172/// ```no_run173/// # fn no_run() -> Result<(), Error> {174/// # fn get_scratch_idx() -> usize {175/// # 0x15176/// # }177/// // Array of 64 consecutive registers with the same layout starting at offset `0x80`.178/// register!(SCRATCH @ 0x00000080[64], "Scratch registers" {179/// 31:0 value as u32;180/// });181///182/// // Read scratch register 0, i.e. I/O address `0x80`.183/// let scratch_0 = SCRATCH::read(bar, 0).value();184/// // Read scratch register 15, i.e. I/O address `0x80 + (15 * 4)`.185/// let scratch_15 = SCRATCH::read(bar, 15).value();186///187/// // This is out of bounds and won't build.188/// // let scratch_128 = SCRATCH::read(bar, 128).value();189///190/// // Runtime-obtained array index.191/// let scratch_idx = get_scratch_idx();192/// // Access on a runtime index returns an error if it is out-of-bounds.193/// let some_scratch = SCRATCH::try_read(bar, scratch_idx)?.value();194///195/// // Alias to a particular register in an array.196/// // Here `SCRATCH[8]` is used to convey the firmware exit code.197/// register!(FIRMWARE_STATUS => SCRATCH[8], "Firmware exit status code" {198/// 7:0 status as u8;199/// });200///201/// let status = FIRMWARE_STATUS::read(bar).status();202///203/// // Non-contiguous register arrays can be defined by adding a stride parameter.204/// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the205/// // registers of the two declarations below are interleaved.206/// register!(SCRATCH_INTERLEAVED_0 @ 0x000000c0[16 ; 8], "Scratch registers bank 0" {207/// 31:0 value as u32;208/// });209/// register!(SCRATCH_INTERLEAVED_1 @ 0x000000c4[16 ; 8], "Scratch registers bank 1" {210/// 31:0 value as u32;211/// });212/// # Ok(())213/// # }214/// ```215///216/// ## Relative arrays of registers217///218/// Combining the two features described in the sections above, arrays of registers accessible from219/// a base can also be defined:220///221/// ```no_run222/// # fn no_run() -> Result<(), Error> {223/// # fn get_scratch_idx() -> usize {224/// # 0x15225/// # }226/// // Type used as parameter of `RegisterBase` to specify the base.227/// pub(crate) struct CpuCtlBase;228///229/// // ZST describing `CPU0`.230/// struct Cpu0;231/// impl RegisterBase<CpuCtlBase> for Cpu0 {232/// const BASE: usize = 0x100;233/// }234/// // Singleton of `CPU0` used to identify it.235/// const CPU0: Cpu0 = Cpu0;236///237/// // ZST describing `CPU1`.238/// struct Cpu1;239/// impl RegisterBase<CpuCtlBase> for Cpu1 {240/// const BASE: usize = 0x200;241/// }242/// // Singleton of `CPU1` used to identify it.243/// const CPU1: Cpu1 = Cpu1;244///245/// // 64 per-cpu scratch registers, arranged as an contiguous array.246/// register!(CPU_SCRATCH @ CpuCtlBase[0x00000080[64]], "Per-CPU scratch registers" {247/// 31:0 value as u32;248/// });249///250/// let cpu0_scratch_0 = CPU_SCRATCH::read(bar, &Cpu0, 0).value();251/// let cpu1_scratch_15 = CPU_SCRATCH::read(bar, &Cpu1, 15).value();252///253/// // This won't build.254/// // let cpu0_scratch_128 = CPU_SCRATCH::read(bar, &Cpu0, 128).value();255///256/// // Runtime-obtained array index.257/// let scratch_idx = get_scratch_idx();258/// // Access on a runtime value returns an error if it is out-of-bounds.259/// let cpu0_some_scratch = CPU_SCRATCH::try_read(bar, &Cpu0, scratch_idx)?.value();260///261/// // `SCRATCH[8]` is used to convey the firmware exit code.262/// register!(CPU_FIRMWARE_STATUS => CpuCtlBase[CPU_SCRATCH[8]],263/// "Per-CPU firmware exit status code" {264/// 7:0 status as u8;265/// });266///267/// let cpu0_status = CPU_FIRMWARE_STATUS::read(bar, &Cpu0).status();268///269/// // Non-contiguous register arrays can be defined by adding a stride parameter.270/// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the271/// // registers of the two declarations below are interleaved.272/// register!(CPU_SCRATCH_INTERLEAVED_0 @ CpuCtlBase[0x00000d00[16 ; 8]],273/// "Scratch registers bank 0" {274/// 31:0 value as u32;275/// });276/// register!(CPU_SCRATCH_INTERLEAVED_1 @ CpuCtlBase[0x00000d04[16 ; 8]],277/// "Scratch registers bank 1" {278/// 31:0 value as u32;279/// });280/// # Ok(())281/// # }282/// ```283macro_rules! register {284// Creates a register at a fixed offset of the MMIO space.285($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => {286register!(@core $name $(, $comment)? { $($fields)* } );287register!(@io_fixed $name @ $offset);288};289290// Creates an alias register of fixed offset register `alias` with its own fields.291($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => {292register!(@core $name $(, $comment)? { $($fields)* } );293register!(@io_fixed $name @ $alias::OFFSET);294};295296// Creates a register at a relative offset from a base address provider.297($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $($fields:tt)* } ) => {298register!(@core $name $(, $comment)? { $($fields)* } );299register!(@io_relative $name @ $base [ $offset ]);300};301302// Creates an alias register of relative offset register `alias` with its own fields.303($name:ident => $base:ty [ $alias:ident ] $(, $comment:literal)? { $($fields:tt)* }) => {304register!(@core $name $(, $comment)? { $($fields)* } );305register!(@io_relative $name @ $base [ $alias::OFFSET ]);306};307308// Creates an array of registers at a fixed offset of the MMIO space.309(310$name:ident @ $offset:literal [ $size:expr ; $stride:expr ] $(, $comment:literal)? {311$($fields:tt)*312}313) => {314static_assert!(::core::mem::size_of::<u32>() <= $stride);315register!(@core $name $(, $comment)? { $($fields)* } );316register!(@io_array $name @ $offset [ $size ; $stride ]);317};318319// Shortcut for contiguous array of registers (stride == size of element).320(321$name:ident @ $offset:literal [ $size:expr ] $(, $comment:literal)? {322$($fields:tt)*323}324) => {325register!($name @ $offset [ $size ; ::core::mem::size_of::<u32>() ] $(, $comment)? {326$($fields)*327} );328};329330// Creates an array of registers at a relative offset from a base address provider.331(332$name:ident @ $base:ty [ $offset:literal [ $size:expr ; $stride:expr ] ]333$(, $comment:literal)? { $($fields:tt)* }334) => {335static_assert!(::core::mem::size_of::<u32>() <= $stride);336register!(@core $name $(, $comment)? { $($fields)* } );337register!(@io_relative_array $name @ $base [ $offset [ $size ; $stride ] ]);338};339340// Shortcut for contiguous array of relative registers (stride == size of element).341(342$name:ident @ $base:ty [ $offset:literal [ $size:expr ] ] $(, $comment:literal)? {343$($fields:tt)*344}345) => {346register!($name @ $base [ $offset [ $size ; ::core::mem::size_of::<u32>() ] ]347$(, $comment)? { $($fields)* } );348};349350// Creates an alias of register `idx` of relative array of registers `alias` with its own351// fields.352(353$name:ident => $base:ty [ $alias:ident [ $idx:expr ] ] $(, $comment:literal)? {354$($fields:tt)*355}356) => {357static_assert!($idx < $alias::SIZE);358register!(@core $name $(, $comment)? { $($fields)* } );359register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $alias::STRIDE ] );360};361362// Creates an alias of register `idx` of array of registers `alias` with its own fields.363// This rule belongs to the (non-relative) register arrays set, but needs to be put last364// to avoid it being interpreted in place of the relative register array alias rule.365($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => {366static_assert!($idx < $alias::SIZE);367register!(@core $name $(, $comment)? { $($fields)* } );368register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE );369};370371// All rules below are helpers.372373// Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`,374// `Default`, `BitOr`, and conversion to the value type) and field accessor methods.375(@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) => {376$(377#[doc=$comment]378)?379#[repr(transparent)]380#[derive(Clone, Copy)]381pub(crate) struct $name(u32);382383impl ::core::ops::BitOr for $name {384type Output = Self;385386fn bitor(self, rhs: Self) -> Self::Output {387Self(self.0 | rhs.0)388}389}390391impl ::core::convert::From<$name> for u32 {392fn from(reg: $name) -> u32 {393reg.0394}395}396397register!(@fields_dispatcher $name { $($fields)* });398};399400// Captures the fields and passes them to all the implementers that require field information.401//402// Used to simplify the matching rules for implementers, so they don't need to match the entire403// complex fields rule even though they only make use of part of it.404(@fields_dispatcher $name:ident {405$($hi:tt:$lo:tt $field:ident as $type:tt406$(?=> $try_into_type:ty)?407$(=> $into_type:ty)?408$(, $comment:literal)?409;410)*411}412) => {413register!(@field_accessors $name {414$(415$hi:$lo $field as $type416$(?=> $try_into_type)?417$(=> $into_type)?418$(, $comment)?419;420)*421});422register!(@debug $name { $($field;)* });423register!(@default $name { $($field;)* });424};425426// Defines all the field getter/methods methods for `$name`.427(428@field_accessors $name:ident {429$($hi:tt:$lo:tt $field:ident as $type:tt430$(?=> $try_into_type:ty)?431$(=> $into_type:ty)?432$(, $comment:literal)?433;434)*435}436) => {437$(438register!(@check_field_bounds $hi:$lo $field as $type);439)*440441#[allow(dead_code)]442impl $name {443$(444register!(@field_accessor $name $hi:$lo $field as $type445$(?=> $try_into_type)?446$(=> $into_type)?447$(, $comment)?448;449);450)*451}452};453454// Boolean fields must have `$hi == $lo`.455(@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => {456#[allow(clippy::eq_op)]457const _: () = {458::kernel::build_assert!(459$hi == $lo,460concat!("boolean field `", stringify!($field), "` covers more than one bit")461);462};463};464465// Non-boolean fields must have `$hi >= $lo`.466(@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => {467#[allow(clippy::eq_op)]468const _: () = {469::kernel::build_assert!(470$hi >= $lo,471concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB")472);473};474};475476// Catches fields defined as `bool` and convert them into a boolean value.477(478@field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty479$(, $comment:literal)?;480) => {481register!(482@leaf_accessor $name $hi:$lo $field483{ |f| <$into_type>::from(if f != 0 { true } else { false }) }484$into_type => $into_type $(, $comment)?;485);486};487488// Shortcut for fields defined as `bool` without the `=>` syntax.489(490@field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?;491) => {492register!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;);493};494495// Catches the `?=>` syntax for non-boolean fields.496(497@field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty498$(, $comment:literal)?;499) => {500register!(@leaf_accessor $name $hi:$lo $field501{ |f| <$try_into_type>::try_from(f as $type) } $try_into_type =>502::core::result::Result<503$try_into_type,504<$try_into_type as ::core::convert::TryFrom<$type>>::Error505>506$(, $comment)?;);507};508509// Catches the `=>` syntax for non-boolean fields.510(511@field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty512$(, $comment:literal)?;513) => {514register!(@leaf_accessor $name $hi:$lo $field515{ |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;);516};517518// Shortcut for non-boolean fields defined without the `=>` or `?=>` syntax.519(520@field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt521$(, $comment:literal)?;522) => {523register!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;);524};525526// Generates the accessor methods for a single field.527(528@leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident529{ $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?;530) => {531::kernel::macros::paste!(532const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;533const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);534const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros();535);536537$(538#[doc="Returns the value of this field:"]539#[doc=$comment]540)?541#[inline(always)]542pub(crate) fn $field(self) -> $res_type {543::kernel::macros::paste!(544const MASK: u32 = $name::[<$field:upper _MASK>];545const SHIFT: u32 = $name::[<$field:upper _SHIFT>];546);547let field = ((self.0 & MASK) >> SHIFT);548549$process(field)550}551552::kernel::macros::paste!(553$(554#[doc="Sets the value of this field:"]555#[doc=$comment]556)?557#[inline(always)]558pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self {559const MASK: u32 = $name::[<$field:upper _MASK>];560const SHIFT: u32 = $name::[<$field:upper _SHIFT>];561let value = (u32::from(value) << SHIFT) & MASK;562self.0 = (self.0 & !MASK) | value;563564self565}566);567};568569// Generates the `Debug` implementation for `$name`.570(@debug $name:ident { $($field:ident;)* }) => {571impl ::kernel::fmt::Debug for $name {572fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {573f.debug_struct(stringify!($name))574.field("<raw>", &::kernel::prelude::fmt!("{:#x}", &self.0))575$(576.field(stringify!($field), &self.$field())577)*578.finish()579}580}581};582583// Generates the `Default` implementation for `$name`.584(@default $name:ident { $($field:ident;)* }) => {585/// Returns a value for the register where all fields are set to their default value.586impl ::core::default::Default for $name {587fn default() -> Self {588#[allow(unused_mut)]589let mut value = Self(Default::default());590591::kernel::macros::paste!(592$(593value.[<set_ $field>](Default::default());594)*595);596597value598}599}600};601602// Generates the IO accessors for a fixed offset register.603(@io_fixed $name:ident @ $offset:expr) => {604#[allow(dead_code)]605impl $name {606pub(crate) const OFFSET: usize = $offset;607608/// Read the register from its address in `io`.609#[inline(always)]610pub(crate) fn read<const SIZE: usize, T>(io: &T) -> Self where611T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,612{613Self(io.read32($offset))614}615616/// Write the value contained in `self` to the register address in `io`.617#[inline(always)]618pub(crate) fn write<const SIZE: usize, T>(self, io: &T) where619T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,620{621io.write32(self.0, $offset)622}623624/// Read the register from its address in `io` and run `f` on its value to obtain a new625/// value to write back.626#[inline(always)]627pub(crate) fn alter<const SIZE: usize, T, F>(628io: &T,629f: F,630) where631T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,632F: ::core::ops::FnOnce(Self) -> Self,633{634let reg = f(Self::read(io));635reg.write(io);636}637}638};639640// Generates the IO accessors for a relative offset register.641(@io_relative $name:ident @ $base:ty [ $offset:expr ]) => {642#[allow(dead_code)]643impl $name {644pub(crate) const OFFSET: usize = $offset;645646/// Read the register from `io`, using the base address provided by `base` and adding647/// the register's offset to it.648#[inline(always)]649pub(crate) fn read<const SIZE: usize, T, B>(650io: &T,651#[allow(unused_variables)]652base: &B,653) -> Self where654T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,655B: crate::regs::macros::RegisterBase<$base>,656{657const OFFSET: usize = $name::OFFSET;658659let value = io.read32(660<B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET661);662663Self(value)664}665666/// Write the value contained in `self` to `io`, using the base address provided by667/// `base` and adding the register's offset to it.668#[inline(always)]669pub(crate) fn write<const SIZE: usize, T, B>(670self,671io: &T,672#[allow(unused_variables)]673base: &B,674) where675T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,676B: crate::regs::macros::RegisterBase<$base>,677{678const OFFSET: usize = $name::OFFSET;679680io.write32(681self.0,682<B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET683);684}685686/// Read the register from `io`, using the base address provided by `base` and adding687/// the register's offset to it, then run `f` on its value to obtain a new value to688/// write back.689#[inline(always)]690pub(crate) fn alter<const SIZE: usize, T, B, F>(691io: &T,692base: &B,693f: F,694) where695T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,696B: crate::regs::macros::RegisterBase<$base>,697F: ::core::ops::FnOnce(Self) -> Self,698{699let reg = f(Self::read(io, base));700reg.write(io, base);701}702}703};704705// Generates the IO accessors for an array of registers.706(@io_array $name:ident @ $offset:literal [ $size:expr ; $stride:expr ]) => {707#[allow(dead_code)]708impl $name {709pub(crate) const OFFSET: usize = $offset;710pub(crate) const SIZE: usize = $size;711pub(crate) const STRIDE: usize = $stride;712713/// Read the array register at index `idx` from its address in `io`.714#[inline(always)]715pub(crate) fn read<const SIZE: usize, T>(716io: &T,717idx: usize,718) -> Self where719T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,720{721build_assert!(idx < Self::SIZE);722723let offset = Self::OFFSET + (idx * Self::STRIDE);724let value = io.read32(offset);725726Self(value)727}728729/// Write the value contained in `self` to the array register with index `idx` in `io`.730#[inline(always)]731pub(crate) fn write<const SIZE: usize, T>(732self,733io: &T,734idx: usize735) where736T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,737{738build_assert!(idx < Self::SIZE);739740let offset = Self::OFFSET + (idx * Self::STRIDE);741742io.write32(self.0, offset);743}744745/// Read the array register at index `idx` in `io` and run `f` on its value to obtain a746/// new value to write back.747#[inline(always)]748pub(crate) fn alter<const SIZE: usize, T, F>(749io: &T,750idx: usize,751f: F,752) where753T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,754F: ::core::ops::FnOnce(Self) -> Self,755{756let reg = f(Self::read(io, idx));757reg.write(io, idx);758}759760/// Read the array register at index `idx` from its address in `io`.761///762/// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the763/// access was out-of-bounds.764#[inline(always)]765pub(crate) fn try_read<const SIZE: usize, T>(766io: &T,767idx: usize,768) -> ::kernel::error::Result<Self> where769T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,770{771if idx < Self::SIZE {772Ok(Self::read(io, idx))773} else {774Err(EINVAL)775}776}777778/// Write the value contained in `self` to the array register with index `idx` in `io`.779///780/// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the781/// access was out-of-bounds.782#[inline(always)]783pub(crate) fn try_write<const SIZE: usize, T>(784self,785io: &T,786idx: usize,787) -> ::kernel::error::Result where788T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,789{790if idx < Self::SIZE {791Ok(self.write(io, idx))792} else {793Err(EINVAL)794}795}796797/// Read the array register at index `idx` in `io` and run `f` on its value to obtain a798/// new value to write back.799///800/// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the801/// access was out-of-bounds.802#[inline(always)]803pub(crate) fn try_alter<const SIZE: usize, T, F>(804io: &T,805idx: usize,806f: F,807) -> ::kernel::error::Result where808T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,809F: ::core::ops::FnOnce(Self) -> Self,810{811if idx < Self::SIZE {812Ok(Self::alter(io, idx, f))813} else {814Err(EINVAL)815}816}817}818};819820// Generates the IO accessors for an array of relative registers.821(822@io_relative_array $name:ident @ $base:ty823[ $offset:literal [ $size:expr ; $stride:expr ] ]824) => {825#[allow(dead_code)]826impl $name {827pub(crate) const OFFSET: usize = $offset;828pub(crate) const SIZE: usize = $size;829pub(crate) const STRIDE: usize = $stride;830831/// Read the array register at index `idx` from `io`, using the base address provided832/// by `base` and adding the register's offset to it.833#[inline(always)]834pub(crate) fn read<const SIZE: usize, T, B>(835io: &T,836#[allow(unused_variables)]837base: &B,838idx: usize,839) -> Self where840T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,841B: crate::regs::macros::RegisterBase<$base>,842{843build_assert!(idx < Self::SIZE);844845let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE +846Self::OFFSET + (idx * Self::STRIDE);847let value = io.read32(offset);848849Self(value)850}851852/// Write the value contained in `self` to `io`, using the base address provided by853/// `base` and adding the offset of array register `idx` to it.854#[inline(always)]855pub(crate) fn write<const SIZE: usize, T, B>(856self,857io: &T,858#[allow(unused_variables)]859base: &B,860idx: usize861) where862T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,863B: crate::regs::macros::RegisterBase<$base>,864{865build_assert!(idx < Self::SIZE);866867let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE +868Self::OFFSET + (idx * Self::STRIDE);869870io.write32(self.0, offset);871}872873/// Read the array register at index `idx` from `io`, using the base address provided874/// by `base` and adding the register's offset to it, then run `f` on its value to875/// obtain a new value to write back.876#[inline(always)]877pub(crate) fn alter<const SIZE: usize, T, B, F>(878io: &T,879base: &B,880idx: usize,881f: F,882) where883T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,884B: crate::regs::macros::RegisterBase<$base>,885F: ::core::ops::FnOnce(Self) -> Self,886{887let reg = f(Self::read(io, base, idx));888reg.write(io, base, idx);889}890891/// Read the array register at index `idx` from `io`, using the base address provided892/// by `base` and adding the register's offset to it.893///894/// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the895/// access was out-of-bounds.896#[inline(always)]897pub(crate) fn try_read<const SIZE: usize, T, B>(898io: &T,899base: &B,900idx: usize,901) -> ::kernel::error::Result<Self> where902T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,903B: crate::regs::macros::RegisterBase<$base>,904{905if idx < Self::SIZE {906Ok(Self::read(io, base, idx))907} else {908Err(EINVAL)909}910}911912/// Write the value contained in `self` to `io`, using the base address provided by913/// `base` and adding the offset of array register `idx` to it.914///915/// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the916/// access was out-of-bounds.917#[inline(always)]918pub(crate) fn try_write<const SIZE: usize, T, B>(919self,920io: &T,921base: &B,922idx: usize,923) -> ::kernel::error::Result where924T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,925B: crate::regs::macros::RegisterBase<$base>,926{927if idx < Self::SIZE {928Ok(self.write(io, base, idx))929} else {930Err(EINVAL)931}932}933934/// Read the array register at index `idx` from `io`, using the base address provided935/// by `base` and adding the register's offset to it, then run `f` on its value to936/// obtain a new value to write back.937///938/// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the939/// access was out-of-bounds.940#[inline(always)]941pub(crate) fn try_alter<const SIZE: usize, T, B, F>(942io: &T,943base: &B,944idx: usize,945f: F,946) -> ::kernel::error::Result where947T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,948B: crate::regs::macros::RegisterBase<$base>,949F: ::core::ops::FnOnce(Self) -> Self,950{951if idx < Self::SIZE {952Ok(Self::alter(io, base, idx, f))953} else {954Err(EINVAL)955}956}957}958};959}960961962