1 // SPDX-License-Identifier: GPL-2.0 2 3 //! `register!` macro to define register layout and accessors. 4 //! 5 //! A single register typically includes several fields, which are accessed through a combination 6 //! of bit-shift and mask operations that introduce a class of potential mistakes, notably because 7 //! not all possible field values are necessarily valid. 8 //! 9 //! The `register!` macro in this module provides an intuitive and readable syntax for defining a 10 //! dedicated type for each register. Each such type comes with its own field accessors that can 11 //! return an error if a field's value is invalid. 12 13 /// Trait providing a base address to be added to the offset of a relative register to obtain 14 /// its actual offset. 15 /// 16 /// The `T` generic argument is used to distinguish which base to use, in case a type provides 17 /// several bases. It is given to the `register!` macro to restrict the use of the register to 18 /// implementors of this particular variant. 19 pub(crate) trait RegisterBase<T> { 20 const BASE: usize; 21 } 22 23 /// Defines a dedicated type for a register with an absolute offset, including getter and setter 24 /// methods for its fields and methods to read and write it from an `Io` region. 25 /// 26 /// Example: 27 /// 28 /// ```no_run 29 /// register!(BOOT_0 @ 0x00000100, "Basic revision information about the GPU" { 30 /// 3:0 minor_revision as u8, "Minor revision of the chip"; 31 /// 7:4 major_revision as u8, "Major revision of the chip"; 32 /// 28:20 chipset as u32 ?=> Chipset, "Chipset model"; 33 /// }); 34 /// ``` 35 /// 36 /// This defines a `BOOT_0` type which can be read or written from offset `0x100` of an `Io` 37 /// region. It is composed of 3 fields, for instance `minor_revision` is made of the 4 least 38 /// significant bits of the register. Each field can be accessed and modified using accessor 39 /// methods: 40 /// 41 /// ```no_run 42 /// // Read from the register's defined offset (0x100). 43 /// let boot0 = BOOT_0::read(&bar); 44 /// pr_info!("chip revision: {}.{}", boot0.major_revision(), boot0.minor_revision()); 45 /// 46 /// // `Chipset::try_from` is called with the value of the `chipset` field and returns an 47 /// // error if it is invalid. 48 /// let chipset = boot0.chipset()?; 49 /// 50 /// // Update some fields and write the value back. 51 /// boot0.set_major_revision(3).set_minor_revision(10).write(&bar); 52 /// 53 /// // Or, just read and update the register in a single step: 54 /// BOOT_0::alter(&bar, |r| r.set_major_revision(3).set_minor_revision(10)); 55 /// ``` 56 /// 57 /// Fields are defined as follows: 58 /// 59 /// - `as <type>` simply returns the field value casted to <type>, typically `u32`, `u16`, `u8` or 60 /// `bool`. Note that `bool` fields must have a range of 1 bit. 61 /// - `as <type> => <into_type>` calls `<into_type>`'s `From::<<type>>` implementation and returns 62 /// the result. 63 /// - `as <type> ?=> <try_into_type>` calls `<try_into_type>`'s `TryFrom::<<type>>` implementation 64 /// and returns the result. This is useful with fields for which not all values are valid. 65 /// 66 /// The documentation strings are optional. If present, they will be added to the type's 67 /// definition, or the field getter and setter methods they are attached to. 68 /// 69 /// It is also possible to create a alias register by using the `=> ALIAS` syntax. This is useful 70 /// for cases where a register's interpretation depends on the context: 71 /// 72 /// ```no_run 73 /// register!(SCRATCH @ 0x00000200, "Scratch register" { 74 /// 31:0 value as u32, "Raw value"; 75 /// }); 76 /// 77 /// register!(SCRATCH_BOOT_STATUS => SCRATCH, "Boot status of the firmware" { 78 /// 0:0 completed as bool, "Whether the firmware has completed booting"; 79 /// }); 80 /// ``` 81 /// 82 /// In this example, `SCRATCH_0_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while also 83 /// providing its own `completed` field. 84 /// 85 /// ## Relative registers 86 /// 87 /// A register can be defined as being accessible from a fixed offset of a provided base. For 88 /// instance, imagine the following I/O space: 89 /// 90 /// ```text 91 /// +-----------------------------+ 92 /// | ... | 93 /// | | 94 /// 0x100--->+------------CPU0-------------+ 95 /// | | 96 /// 0x110--->+-----------------------------+ 97 /// | CPU_CTL | 98 /// +-----------------------------+ 99 /// | ... | 100 /// | | 101 /// | | 102 /// 0x200--->+------------CPU1-------------+ 103 /// | | 104 /// 0x210--->+-----------------------------+ 105 /// | CPU_CTL | 106 /// +-----------------------------+ 107 /// | ... | 108 /// +-----------------------------+ 109 /// ``` 110 /// 111 /// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O 112 /// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define 113 /// them twice and would prefer a way to select which one to use from a single definition 114 /// 115 /// This can be done using the `Base[Offset]` syntax when specifying the register's address. 116 /// 117 /// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the 118 /// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for 119 /// this register needs to implement `RegisterBase<Base>`. Here is the above example translated 120 /// into code: 121 /// 122 /// ```no_run 123 /// // Type used to identify the base. 124 /// pub(crate) struct CpuCtlBase; 125 /// 126 /// // ZST describing `CPU0`. 127 /// struct Cpu0; 128 /// impl RegisterBase<CpuCtlBase> for Cpu0 { 129 /// const BASE: usize = 0x100; 130 /// } 131 /// // Singleton of `CPU0` used to identify it. 132 /// const CPU0: Cpu0 = Cpu0; 133 /// 134 /// // ZST describing `CPU1`. 135 /// struct Cpu1; 136 /// impl RegisterBase<CpuCtlBase> for Cpu1 { 137 /// const BASE: usize = 0x200; 138 /// } 139 /// // Singleton of `CPU1` used to identify it. 140 /// const CPU1: Cpu1 = Cpu1; 141 /// 142 /// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`. 143 /// register!(CPU_CTL @ CpuCtlBase[0x10], "CPU core control" { 144 /// 0:0 start as bool, "Start the CPU core"; 145 /// }); 146 /// 147 /// // The `read`, `write` and `alter` methods of relative registers take an extra `base` argument 148 /// // that is used to resolve its final address by adding its `BASE` to the offset of the 149 /// // register. 150 /// 151 /// // Start `CPU0`. 152 /// CPU_CTL::alter(bar, &CPU0, |r| r.set_start(true)); 153 /// 154 /// // Start `CPU1`. 155 /// CPU_CTL::alter(bar, &CPU1, |r| r.set_start(true)); 156 /// 157 /// // Aliases can also be defined for relative register. 158 /// register!(CPU_CTL_ALIAS => CpuCtlBase[CPU_CTL], "Alias to CPU core control" { 159 /// 1:1 alias_start as bool, "Start the aliased CPU core"; 160 /// }); 161 /// 162 /// // Start the aliased `CPU0`. 163 /// CPU_CTL_ALIAS::alter(bar, &CPU0, |r| r.set_alias_start(true)); 164 /// ``` 165 /// 166 /// ## Arrays of registers 167 /// 168 /// Some I/O areas contain consecutive values that can be interpreted in the same way. These areas 169 /// can be defined as an array of identical registers, allowing them to be accessed by index with 170 /// compile-time or runtime bound checking. Simply define their address as `Address[Size]`, and add 171 /// an `idx` parameter to their `read`, `write` and `alter` methods: 172 /// 173 /// ```no_run 174 /// # fn no_run() -> Result<(), Error> { 175 /// # fn get_scratch_idx() -> usize { 176 /// # 0x15 177 /// # } 178 /// // Array of 64 consecutive registers with the same layout starting at offset `0x80`. 179 /// register!(SCRATCH @ 0x00000080[64], "Scratch registers" { 180 /// 31:0 value as u32; 181 /// }); 182 /// 183 /// // Read scratch register 0, i.e. I/O address `0x80`. 184 /// let scratch_0 = SCRATCH::read(bar, 0).value(); 185 /// // Read scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. 186 /// let scratch_15 = SCRATCH::read(bar, 15).value(); 187 /// 188 /// // This is out of bounds and won't build. 189 /// // let scratch_128 = SCRATCH::read(bar, 128).value(); 190 /// 191 /// // Runtime-obtained array index. 192 /// let scratch_idx = get_scratch_idx(); 193 /// // Access on a runtime index returns an error if it is out-of-bounds. 194 /// let some_scratch = SCRATCH::try_read(bar, scratch_idx)?.value(); 195 /// 196 /// // Alias to a particular register in an array. 197 /// // Here `SCRATCH[8]` is used to convey the firmware exit code. 198 /// register!(FIRMWARE_STATUS => SCRATCH[8], "Firmware exit status code" { 199 /// 7:0 status as u8; 200 /// }); 201 /// 202 /// let status = FIRMWARE_STATUS::read(bar).status(); 203 /// 204 /// // Non-contiguous register arrays can be defined by adding a stride parameter. 205 /// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the 206 /// // registers of the two declarations below are interleaved. 207 /// register!(SCRATCH_INTERLEAVED_0 @ 0x000000c0[16 ; 8], "Scratch registers bank 0" { 208 /// 31:0 value as u32; 209 /// }); 210 /// register!(SCRATCH_INTERLEAVED_1 @ 0x000000c4[16 ; 8], "Scratch registers bank 1" { 211 /// 31:0 value as u32; 212 /// }); 213 /// # Ok(()) 214 /// # } 215 /// ``` 216 macro_rules! register { 217 // Creates a register at a fixed offset of the MMIO space. 218 ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => { 219 register!(@core $name $(, $comment)? { $($fields)* } ); 220 register!(@io_fixed $name @ $offset); 221 }; 222 223 // Creates an alias register of fixed offset register `alias` with its own fields. 224 ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => { 225 register!(@core $name $(, $comment)? { $($fields)* } ); 226 register!(@io_fixed $name @ $alias::OFFSET); 227 }; 228 229 // Creates a register at a relative offset from a base address provider. 230 ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $($fields:tt)* } ) => { 231 register!(@core $name $(, $comment)? { $($fields)* } ); 232 register!(@io_relative $name @ $base [ $offset ]); 233 }; 234 235 // Creates an alias register of relative offset register `alias` with its own fields. 236 ($name:ident => $base:ty [ $alias:ident ] $(, $comment:literal)? { $($fields:tt)* }) => { 237 register!(@core $name $(, $comment)? { $($fields)* } ); 238 register!(@io_relative $name @ $base [ $alias::OFFSET ]); 239 }; 240 241 // Creates an array of registers at a fixed offset of the MMIO space. 242 ( 243 $name:ident @ $offset:literal [ $size:expr ; $stride:expr ] $(, $comment:literal)? { 244 $($fields:tt)* 245 } 246 ) => { 247 static_assert!(::core::mem::size_of::<u32>() <= $stride); 248 register!(@core $name $(, $comment)? { $($fields)* } ); 249 register!(@io_array $name @ $offset [ $size ; $stride ]); 250 }; 251 252 // Shortcut for contiguous array of registers (stride == size of element). 253 ( 254 $name:ident @ $offset:literal [ $size:expr ] $(, $comment:literal)? { 255 $($fields:tt)* 256 } 257 ) => { 258 register!($name @ $offset [ $size ; ::core::mem::size_of::<u32>() ] $(, $comment)? { 259 $($fields)* 260 } ); 261 }; 262 263 // Creates an alias of register `idx` of array of registers `alias` with its own fields. 264 ($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => { 265 static_assert!($idx < $alias::SIZE); 266 register!(@core $name $(, $comment)? { $($fields)* } ); 267 register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE ); 268 }; 269 270 // All rules below are helpers. 271 272 // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`, 273 // `Default`, `BitOr`, and conversion to the value type) and field accessor methods. 274 (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) => { 275 $( 276 #[doc=$comment] 277 )? 278 #[repr(transparent)] 279 #[derive(Clone, Copy)] 280 pub(crate) struct $name(u32); 281 282 impl ::core::ops::BitOr for $name { 283 type Output = Self; 284 285 fn bitor(self, rhs: Self) -> Self::Output { 286 Self(self.0 | rhs.0) 287 } 288 } 289 290 impl ::core::convert::From<$name> for u32 { 291 fn from(reg: $name) -> u32 { 292 reg.0 293 } 294 } 295 296 register!(@fields_dispatcher $name { $($fields)* }); 297 }; 298 299 // Captures the fields and passes them to all the implementers that require field information. 300 // 301 // Used to simplify the matching rules for implementers, so they don't need to match the entire 302 // complex fields rule even though they only make use of part of it. 303 (@fields_dispatcher $name:ident { 304 $($hi:tt:$lo:tt $field:ident as $type:tt 305 $(?=> $try_into_type:ty)? 306 $(=> $into_type:ty)? 307 $(, $comment:literal)? 308 ; 309 )* 310 } 311 ) => { 312 register!(@field_accessors $name { 313 $( 314 $hi:$lo $field as $type 315 $(?=> $try_into_type)? 316 $(=> $into_type)? 317 $(, $comment)? 318 ; 319 )* 320 }); 321 register!(@debug $name { $($field;)* }); 322 register!(@default $name { $($field;)* }); 323 }; 324 325 // Defines all the field getter/methods methods for `$name`. 326 ( 327 @field_accessors $name:ident { 328 $($hi:tt:$lo:tt $field:ident as $type:tt 329 $(?=> $try_into_type:ty)? 330 $(=> $into_type:ty)? 331 $(, $comment:literal)? 332 ; 333 )* 334 } 335 ) => { 336 $( 337 register!(@check_field_bounds $hi:$lo $field as $type); 338 )* 339 340 #[allow(dead_code)] 341 impl $name { 342 $( 343 register!(@field_accessor $name $hi:$lo $field as $type 344 $(?=> $try_into_type)? 345 $(=> $into_type)? 346 $(, $comment)? 347 ; 348 ); 349 )* 350 } 351 }; 352 353 // Boolean fields must have `$hi == $lo`. 354 (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => { 355 #[allow(clippy::eq_op)] 356 const _: () = { 357 ::kernel::build_assert!( 358 $hi == $lo, 359 concat!("boolean field `", stringify!($field), "` covers more than one bit") 360 ); 361 }; 362 }; 363 364 // Non-boolean fields must have `$hi >= $lo`. 365 (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => { 366 #[allow(clippy::eq_op)] 367 const _: () = { 368 ::kernel::build_assert!( 369 $hi >= $lo, 370 concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB") 371 ); 372 }; 373 }; 374 375 // Catches fields defined as `bool` and convert them into a boolean value. 376 ( 377 @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty 378 $(, $comment:literal)?; 379 ) => { 380 register!( 381 @leaf_accessor $name $hi:$lo $field 382 { |f| <$into_type>::from(if f != 0 { true } else { false }) } 383 $into_type => $into_type $(, $comment)?; 384 ); 385 }; 386 387 // Shortcut for fields defined as `bool` without the `=>` syntax. 388 ( 389 @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?; 390 ) => { 391 register!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;); 392 }; 393 394 // Catches the `?=>` syntax for non-boolean fields. 395 ( 396 @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty 397 $(, $comment:literal)?; 398 ) => { 399 register!(@leaf_accessor $name $hi:$lo $field 400 { |f| <$try_into_type>::try_from(f as $type) } $try_into_type => 401 ::core::result::Result< 402 $try_into_type, 403 <$try_into_type as ::core::convert::TryFrom<$type>>::Error 404 > 405 $(, $comment)?;); 406 }; 407 408 // Catches the `=>` syntax for non-boolean fields. 409 ( 410 @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty 411 $(, $comment:literal)?; 412 ) => { 413 register!(@leaf_accessor $name $hi:$lo $field 414 { |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;); 415 }; 416 417 // Shortcut for non-boolean fields defined without the `=>` or `?=>` syntax. 418 ( 419 @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt 420 $(, $comment:literal)?; 421 ) => { 422 register!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;); 423 }; 424 425 // Generates the accessor methods for a single field. 426 ( 427 @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident 428 { $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?; 429 ) => { 430 ::kernel::macros::paste!( 431 const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi; 432 const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); 433 const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros(); 434 ); 435 436 $( 437 #[doc="Returns the value of this field:"] 438 #[doc=$comment] 439 )? 440 #[inline(always)] 441 pub(crate) fn $field(self) -> $res_type { 442 ::kernel::macros::paste!( 443 const MASK: u32 = $name::[<$field:upper _MASK>]; 444 const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; 445 ); 446 let field = ((self.0 & MASK) >> SHIFT); 447 448 $process(field) 449 } 450 451 ::kernel::macros::paste!( 452 $( 453 #[doc="Sets the value of this field:"] 454 #[doc=$comment] 455 )? 456 #[inline(always)] 457 pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self { 458 const MASK: u32 = $name::[<$field:upper _MASK>]; 459 const SHIFT: u32 = $name::[<$field:upper _SHIFT>]; 460 let value = (u32::from(value) << SHIFT) & MASK; 461 self.0 = (self.0 & !MASK) | value; 462 463 self 464 } 465 ); 466 }; 467 468 // Generates the `Debug` implementation for `$name`. 469 (@debug $name:ident { $($field:ident;)* }) => { 470 impl ::core::fmt::Debug for $name { 471 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { 472 f.debug_struct(stringify!($name)) 473 .field("<raw>", &format_args!("{:#x}", &self.0)) 474 $( 475 .field(stringify!($field), &self.$field()) 476 )* 477 .finish() 478 } 479 } 480 }; 481 482 // Generates the `Default` implementation for `$name`. 483 (@default $name:ident { $($field:ident;)* }) => { 484 /// Returns a value for the register where all fields are set to their default value. 485 impl ::core::default::Default for $name { 486 fn default() -> Self { 487 #[allow(unused_mut)] 488 let mut value = Self(Default::default()); 489 490 ::kernel::macros::paste!( 491 $( 492 value.[<set_ $field>](Default::default()); 493 )* 494 ); 495 496 value 497 } 498 } 499 }; 500 501 // Generates the IO accessors for a fixed offset register. 502 (@io_fixed $name:ident @ $offset:expr) => { 503 #[allow(dead_code)] 504 impl $name { 505 pub(crate) const OFFSET: usize = $offset; 506 507 /// Read the register from its address in `io`. 508 #[inline(always)] 509 pub(crate) fn read<const SIZE: usize, T>(io: &T) -> Self where 510 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 511 { 512 Self(io.read32($offset)) 513 } 514 515 /// Write the value contained in `self` to the register address in `io`. 516 #[inline(always)] 517 pub(crate) fn write<const SIZE: usize, T>(self, io: &T) where 518 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 519 { 520 io.write32(self.0, $offset) 521 } 522 523 /// Read the register from its address in `io` and run `f` on its value to obtain a new 524 /// value to write back. 525 #[inline(always)] 526 pub(crate) fn alter<const SIZE: usize, T, F>( 527 io: &T, 528 f: F, 529 ) where 530 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 531 F: ::core::ops::FnOnce(Self) -> Self, 532 { 533 let reg = f(Self::read(io)); 534 reg.write(io); 535 } 536 } 537 }; 538 539 // Generates the IO accessors for a relative offset register. 540 (@io_relative $name:ident @ $base:ty [ $offset:expr ]) => { 541 #[allow(dead_code)] 542 impl $name { 543 pub(crate) const OFFSET: usize = $offset; 544 545 /// Read the register from `io`, using the base address provided by `base` and adding 546 /// the register's offset to it. 547 #[inline(always)] 548 pub(crate) fn read<const SIZE: usize, T, B>( 549 io: &T, 550 #[allow(unused_variables)] 551 base: &B, 552 ) -> Self where 553 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 554 B: crate::regs::macros::RegisterBase<$base>, 555 { 556 const OFFSET: usize = $name::OFFSET; 557 558 let value = io.read32( 559 <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET 560 ); 561 562 Self(value) 563 } 564 565 /// Write the value contained in `self` to `io`, using the base address provided by 566 /// `base` and adding the register's offset to it. 567 #[inline(always)] 568 pub(crate) fn write<const SIZE: usize, T, B>( 569 self, 570 io: &T, 571 #[allow(unused_variables)] 572 base: &B, 573 ) where 574 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 575 B: crate::regs::macros::RegisterBase<$base>, 576 { 577 const OFFSET: usize = $name::OFFSET; 578 579 io.write32( 580 self.0, 581 <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET 582 ); 583 } 584 585 /// Read the register from `io`, using the base address provided by `base` and adding 586 /// the register's offset to it, then run `f` on its value to obtain a new value to 587 /// write back. 588 #[inline(always)] 589 pub(crate) fn alter<const SIZE: usize, T, B, F>( 590 io: &T, 591 base: &B, 592 f: F, 593 ) where 594 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 595 B: crate::regs::macros::RegisterBase<$base>, 596 F: ::core::ops::FnOnce(Self) -> Self, 597 { 598 let reg = f(Self::read(io, base)); 599 reg.write(io, base); 600 } 601 } 602 }; 603 604 // Generates the IO accessors for an array of registers. 605 (@io_array $name:ident @ $offset:literal [ $size:expr ; $stride:expr ]) => { 606 #[allow(dead_code)] 607 impl $name { 608 pub(crate) const OFFSET: usize = $offset; 609 pub(crate) const SIZE: usize = $size; 610 pub(crate) const STRIDE: usize = $stride; 611 612 /// Read the array register at index `idx` from its address in `io`. 613 #[inline(always)] 614 pub(crate) fn read<const SIZE: usize, T>( 615 io: &T, 616 idx: usize, 617 ) -> Self where 618 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 619 { 620 build_assert!(idx < Self::SIZE); 621 622 let offset = Self::OFFSET + (idx * Self::STRIDE); 623 let value = io.read32(offset); 624 625 Self(value) 626 } 627 628 /// Write the value contained in `self` to the array register with index `idx` in `io`. 629 #[inline(always)] 630 pub(crate) fn write<const SIZE: usize, T>( 631 self, 632 io: &T, 633 idx: usize 634 ) where 635 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 636 { 637 build_assert!(idx < Self::SIZE); 638 639 let offset = Self::OFFSET + (idx * Self::STRIDE); 640 641 io.write32(self.0, offset); 642 } 643 644 /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a 645 /// new value to write back. 646 #[inline(always)] 647 pub(crate) fn alter<const SIZE: usize, T, F>( 648 io: &T, 649 idx: usize, 650 f: F, 651 ) where 652 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 653 F: ::core::ops::FnOnce(Self) -> Self, 654 { 655 let reg = f(Self::read(io, idx)); 656 reg.write(io, idx); 657 } 658 659 /// Read the array register at index `idx` from its address in `io`. 660 /// 661 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 662 /// access was out-of-bounds. 663 #[inline(always)] 664 pub(crate) fn try_read<const SIZE: usize, T>( 665 io: &T, 666 idx: usize, 667 ) -> ::kernel::error::Result<Self> where 668 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 669 { 670 if idx < Self::SIZE { 671 Ok(Self::read(io, idx)) 672 } else { 673 Err(EINVAL) 674 } 675 } 676 677 /// Write the value contained in `self` to the array register with index `idx` in `io`. 678 /// 679 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 680 /// access was out-of-bounds. 681 #[inline(always)] 682 pub(crate) fn try_write<const SIZE: usize, T>( 683 self, 684 io: &T, 685 idx: usize, 686 ) -> ::kernel::error::Result where 687 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 688 { 689 if idx < Self::SIZE { 690 Ok(self.write(io, idx)) 691 } else { 692 Err(EINVAL) 693 } 694 } 695 696 /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a 697 /// new value to write back. 698 /// 699 /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the 700 /// access was out-of-bounds. 701 #[inline(always)] 702 pub(crate) fn try_alter<const SIZE: usize, T, F>( 703 io: &T, 704 idx: usize, 705 f: F, 706 ) -> ::kernel::error::Result where 707 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>, 708 F: ::core::ops::FnOnce(Self) -> Self, 709 { 710 if idx < Self::SIZE { 711 Ok(Self::alter(io, idx, f)) 712 } else { 713 Err(EINVAL) 714 } 715 } 716 } 717 }; 718 } 719