1c3f22262SAlexandre Courbot // SPDX-License-Identifier: GPL-2.0 2c3f22262SAlexandre Courbot 3c3f22262SAlexandre Courbot //! Macro to define register layout and accessors. 4c3f22262SAlexandre Courbot //! 5c3f22262SAlexandre Courbot //! A single register typically includes several fields, which are accessed through a combination 6c3f22262SAlexandre Courbot //! of bit-shift and mask operations that introduce a class of potential mistakes, notably because 7c3f22262SAlexandre Courbot //! not all possible field values are necessarily valid. 8c3f22262SAlexandre Courbot //! 9c3f22262SAlexandre Courbot //! The macro in this module allow to define, using an intruitive and readable syntax, a dedicated 10c3f22262SAlexandre Courbot //! type for each register with its own field accessors that can return an error is a field's value 11c3f22262SAlexandre Courbot //! is invalid. 12c3f22262SAlexandre Courbot 13c3f22262SAlexandre Courbot /// Defines a dedicated type for a register with an absolute offset, alongside with getter and 14c3f22262SAlexandre Courbot /// setter methods for its fields and methods to read and write it from an `Io` region. 15c3f22262SAlexandre Courbot /// 16c3f22262SAlexandre Courbot /// Example: 17c3f22262SAlexandre Courbot /// 18c3f22262SAlexandre Courbot /// ```no_run 19c3f22262SAlexandre Courbot /// register!(BOOT_0 @ 0x00000100, "Basic revision information about the GPU" { 20c3f22262SAlexandre Courbot /// 3:0 minor_revision as u8, "Minor revision of the chip"; 21c3f22262SAlexandre Courbot /// 7:4 major_revision as u8, "Major revision of the chip"; 22c3f22262SAlexandre Courbot /// 28:20 chipset as u32 ?=> Chipset, "Chipset model"; 23c3f22262SAlexandre Courbot /// }); 24c3f22262SAlexandre Courbot /// ``` 25c3f22262SAlexandre Courbot /// 26c3f22262SAlexandre Courbot /// This defines a `BOOT_0` type which can be read or written from offset `0x100` of an `Io` 27c3f22262SAlexandre Courbot /// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 less 28c3f22262SAlexandre Courbot /// significant bits of the register. Each field can be accessed and modified using accessor 29c3f22262SAlexandre Courbot /// methods: 30c3f22262SAlexandre Courbot /// 31c3f22262SAlexandre Courbot /// ```no_run 32c3f22262SAlexandre Courbot /// // Read from the register's defined offset (0x100). 33c3f22262SAlexandre Courbot /// let boot0 = BOOT_0::read(&bar); 34c3f22262SAlexandre Courbot /// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_revision()); 35c3f22262SAlexandre Courbot /// 36c3f22262SAlexandre Courbot /// // `Chipset::try_from` will be called with the value of the field and returns an error if the 37c3f22262SAlexandre Courbot /// // value is invalid. 38c3f22262SAlexandre Courbot /// let chipset = boot0.chipset()?; 39c3f22262SAlexandre Courbot /// 40c3f22262SAlexandre Courbot /// // Update some fields and write the value back. 41c3f22262SAlexandre Courbot /// boot0.set_major_revision(3).set_minor_revision(10).write(&bar); 42c3f22262SAlexandre Courbot /// 43c3f22262SAlexandre Courbot /// // Or just read and update the register in a single step: 44c3f22262SAlexandre Courbot /// BOOT_0::alter(&bar, |r| r.set_major_revision(3).set_minor_revision(10)); 45c3f22262SAlexandre Courbot /// ``` 46c3f22262SAlexandre Courbot /// 47c3f22262SAlexandre Courbot /// Fields can be defined as follows: 48c3f22262SAlexandre Courbot /// 49c3f22262SAlexandre Courbot /// - `as <type>` simply returns the field value casted as the requested integer type, typically 50c3f22262SAlexandre Courbot /// `u32`, `u16`, `u8` or `bool`. Note that `bool` fields must have a range of 1 bit. 51c3f22262SAlexandre Courbot /// - `as <type> => <into_type>` calls `<into_type>`'s `From::<<type>>` implementation and returns 52c3f22262SAlexandre Courbot /// the result. 53c3f22262SAlexandre Courbot /// - `as <type> ?=> <try_into_type>` calls `<try_into_type>`'s `TryFrom::<<type>>` implementation 54c3f22262SAlexandre Courbot /// and returns the result. This is useful on fields for which not all values are value. 55c3f22262SAlexandre Courbot /// 56c3f22262SAlexandre Courbot /// The documentation strings are optional. If present, they will be added to the type's 57c3f22262SAlexandre Courbot /// definition, or the field getter and setter methods they are attached to. 58c3f22262SAlexandre Courbot /// 59c3f22262SAlexandre Courbot /// Putting a `+` before the address of the register makes it relative to a base: the `read` and 60c3f22262SAlexandre Courbot /// `write` methods take a `base` argument that is added to the specified address before access, 61c3f22262SAlexandre Courbot /// and `try_read` and `try_write` methods are also created, allowing access with offsets unknown 62c3f22262SAlexandre Courbot /// at compile-time: 63c3f22262SAlexandre Courbot /// 64c3f22262SAlexandre Courbot /// ```no_run 65c3f22262SAlexandre Courbot /// register!(CPU_CTL @ +0x0000010, "CPU core control" { 66c3f22262SAlexandre Courbot /// 0:0 start as bool, "Start the CPU core"; 67c3f22262SAlexandre Courbot /// }); 68c3f22262SAlexandre Courbot /// 69c3f22262SAlexandre Courbot /// // Flip the `start` switch for the CPU core which base address is at `CPU_BASE`. 70c3f22262SAlexandre Courbot /// let cpuctl = CPU_CTL::read(&bar, CPU_BASE); 71c3f22262SAlexandre Courbot /// pr_info!("CPU CTL: {:#x}", cpuctl); 72c3f22262SAlexandre Courbot /// cpuctl.set_start(true).write(&bar, CPU_BASE); 73c3f22262SAlexandre Courbot /// ``` 74e66aaaffSAlexandre Courbot /// 75e66aaaffSAlexandre Courbot /// It is also possible to create a alias register by using the `=> ALIAS` syntax. This is useful 76e66aaaffSAlexandre Courbot /// for cases where a register's interpretation depends on the context: 77e66aaaffSAlexandre Courbot /// 78e66aaaffSAlexandre Courbot /// ```no_run 79e66aaaffSAlexandre Courbot /// register!(SCRATCH_0 @ 0x0000100, "Scratch register 0" { 80e66aaaffSAlexandre Courbot /// 31:0 value as u32, "Raw value"; 81e66aaaffSAlexandre Courbot /// 82e66aaaffSAlexandre Courbot /// register!(SCRATCH_0_BOOT_STATUS => SCRATCH_0, "Boot status of the firmware" { 83e66aaaffSAlexandre Courbot /// 0:0 completed as bool, "Whether the firmware has completed booting"; 84e66aaaffSAlexandre Courbot /// ``` 85e66aaaffSAlexandre Courbot /// 86e66aaaffSAlexandre Courbot /// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH_0`, while also 87e66aaaffSAlexandre Courbot /// providing its own `completed` method. 88c3f22262SAlexandre Courbot macro_rules! register { 89c3f22262SAlexandre Courbot // Creates a register at a fixed offset of the MMIO space. 90c3f22262SAlexandre Courbot ( 91c3f22262SAlexandre Courbot $name:ident @ $offset:literal $(, $comment:literal)? { 92c3f22262SAlexandre Courbot $($fields:tt)* 93c3f22262SAlexandre Courbot } 94c3f22262SAlexandre Courbot ) => { 95cdfe233eSAlexandre Courbot register!(@common $name @ $offset $(, $comment)?); 96c3f22262SAlexandre Courbot register!(@field_accessors $name { $($fields)* }); 97c3f22262SAlexandre Courbot register!(@io $name @ $offset); 98c3f22262SAlexandre Courbot }; 99c3f22262SAlexandre Courbot 100e66aaaffSAlexandre Courbot // Creates a alias register of fixed offset register `alias` with its own fields. 101e66aaaffSAlexandre Courbot ( 102e66aaaffSAlexandre Courbot $name:ident => $alias:ident $(, $comment:literal)? { 103e66aaaffSAlexandre Courbot $($fields:tt)* 104e66aaaffSAlexandre Courbot } 105e66aaaffSAlexandre Courbot ) => { 106e66aaaffSAlexandre Courbot register!(@common $name @ $alias::OFFSET $(, $comment)?); 107e66aaaffSAlexandre Courbot register!(@field_accessors $name { $($fields)* }); 108e66aaaffSAlexandre Courbot register!(@io $name @ $alias::OFFSET); 109e66aaaffSAlexandre Courbot }; 110e66aaaffSAlexandre Courbot 111c3f22262SAlexandre Courbot // Creates a register at a relative offset from a base address. 112c3f22262SAlexandre Courbot ( 113c3f22262SAlexandre Courbot $name:ident @ + $offset:literal $(, $comment:literal)? { 114c3f22262SAlexandre Courbot $($fields:tt)* 115c3f22262SAlexandre Courbot } 116c3f22262SAlexandre Courbot ) => { 117cdfe233eSAlexandre Courbot register!(@common $name @ $offset $(, $comment)?); 118c3f22262SAlexandre Courbot register!(@field_accessors $name { $($fields)* }); 119c3f22262SAlexandre Courbot register!(@io$name @ + $offset); 120c3f22262SAlexandre Courbot }; 121c3f22262SAlexandre Courbot 122e66aaaffSAlexandre Courbot // Creates a alias register of relative offset register `alias` with its own fields. 123e66aaaffSAlexandre Courbot ( 124e66aaaffSAlexandre Courbot $name:ident => + $alias:ident $(, $comment:literal)? { 125e66aaaffSAlexandre Courbot $($fields:tt)* 126e66aaaffSAlexandre Courbot } 127e66aaaffSAlexandre Courbot ) => { 128e66aaaffSAlexandre Courbot register!(@common $name @ $alias::OFFSET $(, $comment)?); 129e66aaaffSAlexandre Courbot register!(@field_accessors $name { $($fields)* }); 130e66aaaffSAlexandre Courbot register!(@io $name @ + $alias::OFFSET); 131e66aaaffSAlexandre Courbot }; 132e66aaaffSAlexandre Courbot 1338dd1433dSAlexandre Courbot // All rules below are helpers. 1348dd1433dSAlexandre Courbot 135c3f22262SAlexandre Courbot // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, `BitOr`, 136c3f22262SAlexandre Courbot // and conversion to regular `u32`). 137e66aaaffSAlexandre Courbot (@common $name:ident @ $offset:expr $(, $comment:literal)?) => { 138c3f22262SAlexandre Courbot $( 139c3f22262SAlexandre Courbot #[doc=$comment] 140c3f22262SAlexandre Courbot )? 141c3f22262SAlexandre Courbot #[repr(transparent)] 142c3f22262SAlexandre Courbot #[derive(Clone, Copy, Default)] 143c3f22262SAlexandre Courbot pub(crate) struct $name(u32); 144c3f22262SAlexandre Courbot 145cdfe233eSAlexandre Courbot #[allow(dead_code)] 146cdfe233eSAlexandre Courbot impl $name { 147cdfe233eSAlexandre Courbot pub(crate) const OFFSET: usize = $offset; 148cdfe233eSAlexandre Courbot } 149cdfe233eSAlexandre Courbot 1503606620bSAlexandre Courbot // TODO[REGA]: display the raw hex value, then the value of all the fields. This requires 151c3f22262SAlexandre Courbot // matching the fields, which will complexify the syntax considerably... 152c3f22262SAlexandre Courbot impl ::core::fmt::Debug for $name { 153c3f22262SAlexandre Courbot fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 154c3f22262SAlexandre Courbot f.debug_tuple(stringify!($name)) 155c3f22262SAlexandre Courbot .field(&format_args!("0x{0:x}", &self.0)) 156c3f22262SAlexandre Courbot .finish() 157c3f22262SAlexandre Courbot } 158c3f22262SAlexandre Courbot } 159c3f22262SAlexandre Courbot 1608d5fbb8dSAlexandre Courbot impl ::core::ops::BitOr for $name { 161c3f22262SAlexandre Courbot type Output = Self; 162c3f22262SAlexandre Courbot 163c3f22262SAlexandre Courbot fn bitor(self, rhs: Self) -> Self::Output { 164c3f22262SAlexandre Courbot Self(self.0 | rhs.0) 165c3f22262SAlexandre Courbot } 166c3f22262SAlexandre Courbot } 167c3f22262SAlexandre Courbot 168c3f22262SAlexandre Courbot impl ::core::convert::From<$name> for u32 { 169c3f22262SAlexandre Courbot fn from(reg: $name) -> u32 { 170c3f22262SAlexandre Courbot reg.0 171c3f22262SAlexandre Courbot } 172c3f22262SAlexandre Courbot } 173c3f22262SAlexandre Courbot }; 174c3f22262SAlexandre Courbot 175c3f22262SAlexandre Courbot // Defines all the field getter/methods methods for `$name`. 176c3f22262SAlexandre Courbot ( 177c3f22262SAlexandre Courbot @field_accessors $name:ident { 178c3f22262SAlexandre Courbot $($hi:tt:$lo:tt $field:ident as $type:tt 179c3f22262SAlexandre Courbot $(?=> $try_into_type:ty)? 180c3f22262SAlexandre Courbot $(=> $into_type:ty)? 181c3f22262SAlexandre Courbot $(, $comment:literal)? 182c3f22262SAlexandre Courbot ; 183c3f22262SAlexandre Courbot )* 184c3f22262SAlexandre Courbot } 185c3f22262SAlexandre Courbot ) => { 186c3f22262SAlexandre Courbot $( 187c3f22262SAlexandre Courbot register!(@check_field_bounds $hi:$lo $field as $type); 188c3f22262SAlexandre Courbot )* 189c3f22262SAlexandre Courbot 190c3f22262SAlexandre Courbot #[allow(dead_code)] 191c3f22262SAlexandre Courbot impl $name { 192c3f22262SAlexandre Courbot $( 193c3f22262SAlexandre Courbot register!(@field_accessor $name $hi:$lo $field as $type 194c3f22262SAlexandre Courbot $(?=> $try_into_type)? 195c3f22262SAlexandre Courbot $(=> $into_type)? 196c3f22262SAlexandre Courbot $(, $comment)? 197c3f22262SAlexandre Courbot ; 198c3f22262SAlexandre Courbot ); 199c3f22262SAlexandre Courbot )* 200c3f22262SAlexandre Courbot } 201c3f22262SAlexandre Courbot }; 202c3f22262SAlexandre Courbot 203c3f22262SAlexandre Courbot // Boolean fields must have `$hi == $lo`. 204c3f22262SAlexandre Courbot (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => { 205c3f22262SAlexandre Courbot #[allow(clippy::eq_op)] 206c3f22262SAlexandre Courbot const _: () = { 2078d5fbb8dSAlexandre Courbot ::kernel::build_assert!( 208c3f22262SAlexandre Courbot $hi == $lo, 209c3f22262SAlexandre Courbot concat!("boolean field `", stringify!($field), "` covers more than one bit") 210c3f22262SAlexandre Courbot ); 211c3f22262SAlexandre Courbot }; 212c3f22262SAlexandre Courbot }; 213c3f22262SAlexandre Courbot 214c3f22262SAlexandre Courbot // Non-boolean fields must have `$hi >= $lo`. 215c3f22262SAlexandre Courbot (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => { 216c3f22262SAlexandre Courbot #[allow(clippy::eq_op)] 217c3f22262SAlexandre Courbot const _: () = { 2188d5fbb8dSAlexandre Courbot ::kernel::build_assert!( 219c3f22262SAlexandre Courbot $hi >= $lo, 220c3f22262SAlexandre Courbot concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB") 221c3f22262SAlexandre Courbot ); 222c3f22262SAlexandre Courbot }; 223c3f22262SAlexandre Courbot }; 224c3f22262SAlexandre Courbot 225c3f22262SAlexandre Courbot // Catches fields defined as `bool` and convert them into a boolean value. 226c3f22262SAlexandre Courbot ( 227c3f22262SAlexandre Courbot @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty 228c3f22262SAlexandre Courbot $(, $comment:literal)?; 229c3f22262SAlexandre Courbot ) => { 230c3f22262SAlexandre Courbot register!( 231c3f22262SAlexandre Courbot @leaf_accessor $name $hi:$lo $field as bool 232c3f22262SAlexandre Courbot { |f| <$into_type>::from(if f != 0 { true } else { false }) } 233c3f22262SAlexandre Courbot $into_type => $into_type $(, $comment)?; 234c3f22262SAlexandre Courbot ); 235c3f22262SAlexandre Courbot }; 236c3f22262SAlexandre Courbot 237c3f22262SAlexandre Courbot // Shortcut for fields defined as `bool` without the `=>` syntax. 238c3f22262SAlexandre Courbot ( 239c3f22262SAlexandre Courbot @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?; 240c3f22262SAlexandre Courbot ) => { 241c3f22262SAlexandre Courbot register!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;); 242c3f22262SAlexandre Courbot }; 243c3f22262SAlexandre Courbot 244c3f22262SAlexandre Courbot // Catches the `?=>` syntax for non-boolean fields. 245c3f22262SAlexandre Courbot ( 246c3f22262SAlexandre Courbot @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty 247c3f22262SAlexandre Courbot $(, $comment:literal)?; 248c3f22262SAlexandre Courbot ) => { 249c3f22262SAlexandre Courbot register!(@leaf_accessor $name $hi:$lo $field as $type 250c3f22262SAlexandre Courbot { |f| <$try_into_type>::try_from(f as $type) } $try_into_type => 251c3f22262SAlexandre Courbot ::core::result::Result< 252c3f22262SAlexandre Courbot $try_into_type, 253c3f22262SAlexandre Courbot <$try_into_type as ::core::convert::TryFrom<$type>>::Error 254c3f22262SAlexandre Courbot > 255c3f22262SAlexandre Courbot $(, $comment)?;); 256c3f22262SAlexandre Courbot }; 257c3f22262SAlexandre Courbot 258c3f22262SAlexandre Courbot // Catches the `=>` syntax for non-boolean fields. 259c3f22262SAlexandre Courbot ( 260c3f22262SAlexandre Courbot @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty 261c3f22262SAlexandre Courbot $(, $comment:literal)?; 262c3f22262SAlexandre Courbot ) => { 263c3f22262SAlexandre Courbot register!(@leaf_accessor $name $hi:$lo $field as $type 264c3f22262SAlexandre Courbot { |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;); 265c3f22262SAlexandre Courbot }; 266c3f22262SAlexandre Courbot 267c3f22262SAlexandre Courbot // Shortcut for fields defined as non-`bool` without the `=>` or `?=>` syntax. 268c3f22262SAlexandre Courbot ( 269c3f22262SAlexandre Courbot @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt 270c3f22262SAlexandre Courbot $(, $comment:literal)?; 271c3f22262SAlexandre Courbot ) => { 272c3f22262SAlexandre Courbot register!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;); 273c3f22262SAlexandre Courbot }; 274c3f22262SAlexandre Courbot 275c3f22262SAlexandre Courbot // Generates the accessor methods for a single field. 276c3f22262SAlexandre Courbot ( 277c3f22262SAlexandre Courbot @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:ty 278c3f22262SAlexandre Courbot { $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?; 279c3f22262SAlexandre Courbot ) => { 2808d5fbb8dSAlexandre Courbot ::kernel::macros::paste!( 281c3f22262SAlexandre Courbot const [<$field:upper>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi; 282c3f22262SAlexandre Courbot const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); 283c3f22262SAlexandre Courbot const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros(); 284c3f22262SAlexandre Courbot ); 285c3f22262SAlexandre Courbot 286c3f22262SAlexandre Courbot $( 287c3f22262SAlexandre Courbot #[doc="Returns the value of this field:"] 288c3f22262SAlexandre Courbot #[doc=$comment] 289c3f22262SAlexandre Courbot )? 290c3f22262SAlexandre Courbot #[inline] 291c3f22262SAlexandre Courbot pub(crate) fn $field(self) -> $res_type { 2928d5fbb8dSAlexandre Courbot ::kernel::macros::paste!( 293c3f22262SAlexandre Courbot const MASK: u32 = $name::[<$field:upper _MASK>]; 294c3f22262SAlexandre Courbot const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; 295c3f22262SAlexandre Courbot ); 296c3f22262SAlexandre Courbot let field = ((self.0 & MASK) >> SHIFT); 297c3f22262SAlexandre Courbot 298c3f22262SAlexandre Courbot $process(field) 299c3f22262SAlexandre Courbot } 300c3f22262SAlexandre Courbot 3018d5fbb8dSAlexandre Courbot ::kernel::macros::paste!( 302c3f22262SAlexandre Courbot $( 303c3f22262SAlexandre Courbot #[doc="Sets the value of this field:"] 304c3f22262SAlexandre Courbot #[doc=$comment] 305c3f22262SAlexandre Courbot )? 306c3f22262SAlexandre Courbot #[inline] 307c3f22262SAlexandre Courbot pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self { 308c3f22262SAlexandre Courbot const MASK: u32 = $name::[<$field:upper _MASK>]; 309c3f22262SAlexandre Courbot const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; 310*b7c8d7a8STamir Duberstein let value = (u32::from(value) << SHIFT) & MASK; 311c3f22262SAlexandre Courbot self.0 = (self.0 & !MASK) | value; 312c3f22262SAlexandre Courbot 313c3f22262SAlexandre Courbot self 314c3f22262SAlexandre Courbot } 315c3f22262SAlexandre Courbot ); 316c3f22262SAlexandre Courbot }; 317c3f22262SAlexandre Courbot 318c3f22262SAlexandre Courbot // Creates the IO accessors for a fixed offset register. 319e66aaaffSAlexandre Courbot (@io $name:ident @ $offset:expr) => { 320c3f22262SAlexandre Courbot #[allow(dead_code)] 321c3f22262SAlexandre Courbot impl $name { 322c3f22262SAlexandre Courbot #[inline] 323c3f22262SAlexandre Courbot pub(crate) fn read<const SIZE: usize, T>(io: &T) -> Self where 324c3f22262SAlexandre Courbot T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 325c3f22262SAlexandre Courbot { 326c3f22262SAlexandre Courbot Self(io.read32($offset)) 327c3f22262SAlexandre Courbot } 328c3f22262SAlexandre Courbot 329c3f22262SAlexandre Courbot #[inline] 330c3f22262SAlexandre Courbot pub(crate) fn write<const SIZE: usize, T>(self, io: &T) where 331c3f22262SAlexandre Courbot T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 332c3f22262SAlexandre Courbot { 333c3f22262SAlexandre Courbot io.write32(self.0, $offset) 334c3f22262SAlexandre Courbot } 335c3f22262SAlexandre Courbot 336c3f22262SAlexandre Courbot #[inline] 337c3f22262SAlexandre Courbot pub(crate) fn alter<const SIZE: usize, T, F>( 338c3f22262SAlexandre Courbot io: &T, 339c3f22262SAlexandre Courbot f: F, 340c3f22262SAlexandre Courbot ) where 341c3f22262SAlexandre Courbot T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 342c3f22262SAlexandre Courbot F: ::core::ops::FnOnce(Self) -> Self, 343c3f22262SAlexandre Courbot { 344c3f22262SAlexandre Courbot let reg = f(Self::read(io)); 345c3f22262SAlexandre Courbot reg.write(io); 346c3f22262SAlexandre Courbot } 347c3f22262SAlexandre Courbot } 348c3f22262SAlexandre Courbot }; 349c3f22262SAlexandre Courbot 350c3f22262SAlexandre Courbot // Create the IO accessors for a relative offset register. 351c3f22262SAlexandre Courbot (@io $name:ident @ + $offset:literal) => { 352c3f22262SAlexandre Courbot #[allow(dead_code)] 353c3f22262SAlexandre Courbot impl $name { 354c3f22262SAlexandre Courbot #[inline] 355c3f22262SAlexandre Courbot pub(crate) fn read<const SIZE: usize, T>( 356c3f22262SAlexandre Courbot io: &T, 357c3f22262SAlexandre Courbot base: usize, 358c3f22262SAlexandre Courbot ) -> Self where 359c3f22262SAlexandre Courbot T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 360c3f22262SAlexandre Courbot { 361c3f22262SAlexandre Courbot Self(io.read32(base + $offset)) 362c3f22262SAlexandre Courbot } 363c3f22262SAlexandre Courbot 364c3f22262SAlexandre Courbot #[inline] 365c3f22262SAlexandre Courbot pub(crate) fn write<const SIZE: usize, T>( 366c3f22262SAlexandre Courbot self, 367c3f22262SAlexandre Courbot io: &T, 368c3f22262SAlexandre Courbot base: usize, 369c3f22262SAlexandre Courbot ) where 370c3f22262SAlexandre Courbot T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 371c3f22262SAlexandre Courbot { 372c3f22262SAlexandre Courbot io.write32(self.0, base + $offset) 373c3f22262SAlexandre Courbot } 374c3f22262SAlexandre Courbot 375c3f22262SAlexandre Courbot #[inline] 376c3f22262SAlexandre Courbot pub(crate) fn alter<const SIZE: usize, T, F>( 377c3f22262SAlexandre Courbot io: &T, 378c3f22262SAlexandre Courbot base: usize, 379c3f22262SAlexandre Courbot f: F, 380c3f22262SAlexandre Courbot ) where 381c3f22262SAlexandre Courbot T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 382c3f22262SAlexandre Courbot F: ::core::ops::FnOnce(Self) -> Self, 383c3f22262SAlexandre Courbot { 384c3f22262SAlexandre Courbot let reg = f(Self::read(io, base)); 385c3f22262SAlexandre Courbot reg.write(io, base); 386c3f22262SAlexandre Courbot } 387c3f22262SAlexandre Courbot 388c3f22262SAlexandre Courbot #[inline] 389c3f22262SAlexandre Courbot pub(crate) fn try_read<const SIZE: usize, T>( 390c3f22262SAlexandre Courbot io: &T, 391c3f22262SAlexandre Courbot base: usize, 392c3f22262SAlexandre Courbot ) -> ::kernel::error::Result<Self> where 393c3f22262SAlexandre Courbot T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 394c3f22262SAlexandre Courbot { 395c3f22262SAlexandre Courbot io.try_read32(base + $offset).map(Self) 396c3f22262SAlexandre Courbot } 397c3f22262SAlexandre Courbot 398c3f22262SAlexandre Courbot #[inline] 399c3f22262SAlexandre Courbot pub(crate) fn try_write<const SIZE: usize, T>( 400c3f22262SAlexandre Courbot self, 401c3f22262SAlexandre Courbot io: &T, 402c3f22262SAlexandre Courbot base: usize, 403c3f22262SAlexandre Courbot ) -> ::kernel::error::Result<()> where 404c3f22262SAlexandre Courbot T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 405c3f22262SAlexandre Courbot { 406c3f22262SAlexandre Courbot io.try_write32(self.0, base + $offset) 407c3f22262SAlexandre Courbot } 408c3f22262SAlexandre Courbot 409c3f22262SAlexandre Courbot #[inline] 410c3f22262SAlexandre Courbot pub(crate) fn try_alter<const SIZE: usize, T, F>( 411c3f22262SAlexandre Courbot io: &T, 412c3f22262SAlexandre Courbot base: usize, 413c3f22262SAlexandre Courbot f: F, 414c3f22262SAlexandre Courbot ) -> ::kernel::error::Result<()> where 415c3f22262SAlexandre Courbot T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 416c3f22262SAlexandre Courbot F: ::core::ops::FnOnce(Self) -> Self, 417c3f22262SAlexandre Courbot { 418c3f22262SAlexandre Courbot let reg = f(Self::try_read(io, base)?); 419c3f22262SAlexandre Courbot reg.try_write(io, base) 420c3f22262SAlexandre Courbot } 421c3f22262SAlexandre Courbot } 422c3f22262SAlexandre Courbot }; 423c3f22262SAlexandre Courbot } 424