xref: /linux/drivers/gpu/nova-core/regs/macros.rs (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
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 ///
217 /// ## Relative arrays of registers
218 ///
219 /// Combining the two features described in the sections above, arrays of registers accessible from
220 /// a base can also be defined:
221 ///
222 /// ```no_run
223 /// # fn no_run() -> Result<(), Error> {
224 /// # fn get_scratch_idx() -> usize {
225 /// #   0x15
226 /// # }
227 /// // Type used as parameter of `RegisterBase` to specify the base.
228 /// pub(crate) struct CpuCtlBase;
229 ///
230 /// // ZST describing `CPU0`.
231 /// struct Cpu0;
232 /// impl RegisterBase<CpuCtlBase> for Cpu0 {
233 ///     const BASE: usize = 0x100;
234 /// }
235 /// // Singleton of `CPU0` used to identify it.
236 /// const CPU0: Cpu0 = Cpu0;
237 ///
238 /// // ZST describing `CPU1`.
239 /// struct Cpu1;
240 /// impl RegisterBase<CpuCtlBase> for Cpu1 {
241 ///     const BASE: usize = 0x200;
242 /// }
243 /// // Singleton of `CPU1` used to identify it.
244 /// const CPU1: Cpu1 = Cpu1;
245 ///
246 /// // 64 per-cpu scratch registers, arranged as an contiguous array.
247 /// register!(CPU_SCRATCH @ CpuCtlBase[0x00000080[64]], "Per-CPU scratch registers" {
248 ///     31:0    value as u32;
249 /// });
250 ///
251 /// let cpu0_scratch_0 = CPU_SCRATCH::read(bar, &Cpu0, 0).value();
252 /// let cpu1_scratch_15 = CPU_SCRATCH::read(bar, &Cpu1, 15).value();
253 ///
254 /// // This won't build.
255 /// // let cpu0_scratch_128 = CPU_SCRATCH::read(bar, &Cpu0, 128).value();
256 ///
257 /// // Runtime-obtained array index.
258 /// let scratch_idx = get_scratch_idx();
259 /// // Access on a runtime value returns an error if it is out-of-bounds.
260 /// let cpu0_some_scratch = CPU_SCRATCH::try_read(bar, &Cpu0, scratch_idx)?.value();
261 ///
262 /// // `SCRATCH[8]` is used to convey the firmware exit code.
263 /// register!(CPU_FIRMWARE_STATUS => CpuCtlBase[CPU_SCRATCH[8]],
264 ///     "Per-CPU firmware exit status code" {
265 ///     7:0     status as u8;
266 /// });
267 ///
268 /// let cpu0_status = CPU_FIRMWARE_STATUS::read(bar, &Cpu0).status();
269 ///
270 /// // Non-contiguous register arrays can be defined by adding a stride parameter.
271 /// // Here, each of the 16 registers of the array are separated by 8 bytes, meaning that the
272 /// // registers of the two declarations below are interleaved.
273 /// register!(CPU_SCRATCH_INTERLEAVED_0 @ CpuCtlBase[0x00000d00[16 ; 8]],
274 ///           "Scratch registers bank 0" {
275 ///     31:0    value as u32;
276 /// });
277 /// register!(CPU_SCRATCH_INTERLEAVED_1 @ CpuCtlBase[0x00000d04[16 ; 8]],
278 ///           "Scratch registers bank 1" {
279 ///     31:0    value as u32;
280 /// });
281 /// # Ok(())
282 /// # }
283 /// ```
284 macro_rules! register {
285     // Creates a register at a fixed offset of the MMIO space.
286     ($name:ident @ $offset:literal $(, $comment:literal)? { $($fields:tt)* } ) => {
287         register!(@core $name $(, $comment)? { $($fields)* } );
288         register!(@io_fixed $name @ $offset);
289     };
290 
291     // Creates an alias register of fixed offset register `alias` with its own fields.
292     ($name:ident => $alias:ident $(, $comment:literal)? { $($fields:tt)* } ) => {
293         register!(@core $name $(, $comment)? { $($fields)* } );
294         register!(@io_fixed $name @ $alias::OFFSET);
295     };
296 
297     // Creates a register at a relative offset from a base address provider.
298     ($name:ident @ $base:ty [ $offset:literal ] $(, $comment:literal)? { $($fields:tt)* } ) => {
299         register!(@core $name $(, $comment)? { $($fields)* } );
300         register!(@io_relative $name @ $base [ $offset ]);
301     };
302 
303     // Creates an alias register of relative offset register `alias` with its own fields.
304     ($name:ident => $base:ty [ $alias:ident ] $(, $comment:literal)? { $($fields:tt)* }) => {
305         register!(@core $name $(, $comment)? { $($fields)* } );
306         register!(@io_relative $name @ $base [ $alias::OFFSET ]);
307     };
308 
309     // Creates an array of registers at a fixed offset of the MMIO space.
310     (
311         $name:ident @ $offset:literal [ $size:expr ; $stride:expr ] $(, $comment:literal)? {
312             $($fields:tt)*
313         }
314     ) => {
315         static_assert!(::core::mem::size_of::<u32>() <= $stride);
316         register!(@core $name $(, $comment)? { $($fields)* } );
317         register!(@io_array $name @ $offset [ $size ; $stride ]);
318     };
319 
320     // Shortcut for contiguous array of registers (stride == size of element).
321     (
322         $name:ident @ $offset:literal [ $size:expr ] $(, $comment:literal)? {
323             $($fields:tt)*
324         }
325     ) => {
326         register!($name @ $offset [ $size ; ::core::mem::size_of::<u32>() ] $(, $comment)? {
327             $($fields)*
328         } );
329     };
330 
331     // Creates an array of registers at a relative offset from a base address provider.
332     (
333         $name:ident @ $base:ty [ $offset:literal [ $size:expr ; $stride:expr ] ]
334             $(, $comment:literal)? { $($fields:tt)* }
335     ) => {
336         static_assert!(::core::mem::size_of::<u32>() <= $stride);
337         register!(@core $name $(, $comment)? { $($fields)* } );
338         register!(@io_relative_array $name @ $base [ $offset [ $size ; $stride ] ]);
339     };
340 
341     // Shortcut for contiguous array of relative registers (stride == size of element).
342     (
343         $name:ident @ $base:ty [ $offset:literal [ $size:expr ] ] $(, $comment:literal)? {
344             $($fields:tt)*
345         }
346     ) => {
347         register!($name @ $base [ $offset [ $size ; ::core::mem::size_of::<u32>() ] ]
348             $(, $comment)? { $($fields)* } );
349     };
350 
351     // Creates an alias of register `idx` of relative array of registers `alias` with its own
352     // fields.
353     (
354         $name:ident => $base:ty [ $alias:ident [ $idx:expr ] ] $(, $comment:literal)? {
355             $($fields:tt)*
356         }
357     ) => {
358         static_assert!($idx < $alias::SIZE);
359         register!(@core $name $(, $comment)? { $($fields)* } );
360         register!(@io_relative $name @ $base [ $alias::OFFSET + $idx * $alias::STRIDE ] );
361     };
362 
363     // Creates an alias of register `idx` of array of registers `alias` with its own fields.
364     // This rule belongs to the (non-relative) register arrays set, but needs to be put last
365     // to avoid it being interpreted in place of the relative register array alias rule.
366     ($name:ident => $alias:ident [ $idx:expr ] $(, $comment:literal)? { $($fields:tt)* }) => {
367         static_assert!($idx < $alias::SIZE);
368         register!(@core $name $(, $comment)? { $($fields)* } );
369         register!(@io_fixed $name @ $alias::OFFSET + $idx * $alias::STRIDE );
370     };
371 
372     // All rules below are helpers.
373 
374     // Defines the wrapper `$name` type, as well as its relevant implementations (`Debug`,
375     // `Default`, `BitOr`, and conversion to the value type) and field accessor methods.
376     (@core $name:ident $(, $comment:literal)? { $($fields:tt)* }) => {
377         $(
378         #[doc=$comment]
379         )?
380         #[repr(transparent)]
381         #[derive(Clone, Copy)]
382         pub(crate) struct $name(u32);
383 
384         impl ::core::ops::BitOr for $name {
385             type Output = Self;
386 
387             fn bitor(self, rhs: Self) -> Self::Output {
388                 Self(self.0 | rhs.0)
389             }
390         }
391 
392         impl ::core::convert::From<$name> for u32 {
393             fn from(reg: $name) -> u32 {
394                 reg.0
395             }
396         }
397 
398         register!(@fields_dispatcher $name { $($fields)* });
399     };
400 
401     // Captures the fields and passes them to all the implementers that require field information.
402     //
403     // Used to simplify the matching rules for implementers, so they don't need to match the entire
404     // complex fields rule even though they only make use of part of it.
405     (@fields_dispatcher $name:ident {
406         $($hi:tt:$lo:tt $field:ident as $type:tt
407             $(?=> $try_into_type:ty)?
408             $(=> $into_type:ty)?
409             $(, $comment:literal)?
410         ;
411         )*
412     }
413     ) => {
414         register!(@field_accessors $name {
415             $(
416                 $hi:$lo $field as $type
417                 $(?=> $try_into_type)?
418                 $(=> $into_type)?
419                 $(, $comment)?
420             ;
421             )*
422         });
423         register!(@debug $name { $($field;)* });
424         register!(@default $name { $($field;)* });
425     };
426 
427     // Defines all the field getter/methods methods for `$name`.
428     (
429         @field_accessors $name:ident {
430         $($hi:tt:$lo:tt $field:ident as $type:tt
431             $(?=> $try_into_type:ty)?
432             $(=> $into_type:ty)?
433             $(, $comment:literal)?
434         ;
435         )*
436         }
437     ) => {
438         $(
439             register!(@check_field_bounds $hi:$lo $field as $type);
440         )*
441 
442         #[allow(dead_code)]
443         impl $name {
444             $(
445             register!(@field_accessor $name $hi:$lo $field as $type
446                 $(?=> $try_into_type)?
447                 $(=> $into_type)?
448                 $(, $comment)?
449                 ;
450             );
451             )*
452         }
453     };
454 
455     // Boolean fields must have `$hi == $lo`.
456     (@check_field_bounds $hi:tt:$lo:tt $field:ident as bool) => {
457         #[allow(clippy::eq_op)]
458         const _: () = {
459             ::kernel::build_assert!(
460                 $hi == $lo,
461                 concat!("boolean field `", stringify!($field), "` covers more than one bit")
462             );
463         };
464     };
465 
466     // Non-boolean fields must have `$hi >= $lo`.
467     (@check_field_bounds $hi:tt:$lo:tt $field:ident as $type:tt) => {
468         #[allow(clippy::eq_op)]
469         const _: () = {
470             ::kernel::build_assert!(
471                 $hi >= $lo,
472                 concat!("field `", stringify!($field), "`'s MSB is smaller than its LSB")
473             );
474         };
475     };
476 
477     // Catches fields defined as `bool` and convert them into a boolean value.
478     (
479         @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool => $into_type:ty
480             $(, $comment:literal)?;
481     ) => {
482         register!(
483             @leaf_accessor $name $hi:$lo $field
484             { |f| <$into_type>::from(if f != 0 { true } else { false }) }
485             $into_type => $into_type $(, $comment)?;
486         );
487     };
488 
489     // Shortcut for fields defined as `bool` without the `=>` syntax.
490     (
491         @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as bool $(, $comment:literal)?;
492     ) => {
493         register!(@field_accessor $name $hi:$lo $field as bool => bool $(, $comment)?;);
494     };
495 
496     // Catches the `?=>` syntax for non-boolean fields.
497     (
498         @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt ?=> $try_into_type:ty
499             $(, $comment:literal)?;
500     ) => {
501         register!(@leaf_accessor $name $hi:$lo $field
502             { |f| <$try_into_type>::try_from(f as $type) } $try_into_type =>
503             ::core::result::Result<
504                 $try_into_type,
505                 <$try_into_type as ::core::convert::TryFrom<$type>>::Error
506             >
507             $(, $comment)?;);
508     };
509 
510     // Catches the `=>` syntax for non-boolean fields.
511     (
512         @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt => $into_type:ty
513             $(, $comment:literal)?;
514     ) => {
515         register!(@leaf_accessor $name $hi:$lo $field
516             { |f| <$into_type>::from(f as $type) } $into_type => $into_type $(, $comment)?;);
517     };
518 
519     // Shortcut for non-boolean fields defined without the `=>` or `?=>` syntax.
520     (
521         @field_accessor $name:ident $hi:tt:$lo:tt $field:ident as $type:tt
522             $(, $comment:literal)?;
523     ) => {
524         register!(@field_accessor $name $hi:$lo $field as $type => $type $(, $comment)?;);
525     };
526 
527     // Generates the accessor methods for a single field.
528     (
529         @leaf_accessor $name:ident $hi:tt:$lo:tt $field:ident
530             { $process:expr } $to_type:ty => $res_type:ty $(, $comment:literal)?;
531     ) => {
532         ::kernel::macros::paste!(
533         const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi;
534         const [<$field:upper _MASK>]: u32 = ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1);
535         const [<$field:upper _SHIFT>]: u32 = Self::[<$field:upper _MASK>].trailing_zeros();
536         );
537 
538         $(
539         #[doc="Returns the value of this field:"]
540         #[doc=$comment]
541         )?
542         #[inline(always)]
543         pub(crate) fn $field(self) -> $res_type {
544             ::kernel::macros::paste!(
545             const MASK: u32 = $name::[<$field:upper _MASK>];
546             const SHIFT: u32 = $name::[<$field:upper _SHIFT>];
547             );
548             let field = ((self.0 & MASK) >> SHIFT);
549 
550             $process(field)
551         }
552 
553         ::kernel::macros::paste!(
554         $(
555         #[doc="Sets the value of this field:"]
556         #[doc=$comment]
557         )?
558         #[inline(always)]
559         pub(crate) fn [<set_ $field>](mut self, value: $to_type) -> Self {
560             const MASK: u32 = $name::[<$field:upper _MASK>];
561             const SHIFT: u32 = $name::[<$field:upper _SHIFT>];
562             let value = (u32::from(value) << SHIFT) & MASK;
563             self.0 = (self.0 & !MASK) | value;
564 
565             self
566         }
567         );
568     };
569 
570     // Generates the `Debug` implementation for `$name`.
571     (@debug $name:ident { $($field:ident;)* }) => {
572         impl ::kernel::fmt::Debug for $name {
573             fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result {
574                 f.debug_struct(stringify!($name))
575                     .field("<raw>", &::kernel::prelude::fmt!("{:#x}", &self.0))
576                 $(
577                     .field(stringify!($field), &self.$field())
578                 )*
579                     .finish()
580             }
581         }
582     };
583 
584     // Generates the `Default` implementation for `$name`.
585     (@default $name:ident { $($field:ident;)* }) => {
586         /// Returns a value for the register where all fields are set to their default value.
587         impl ::core::default::Default for $name {
588             fn default() -> Self {
589                 #[allow(unused_mut)]
590                 let mut value = Self(Default::default());
591 
592                 ::kernel::macros::paste!(
593                 $(
594                 value.[<set_ $field>](Default::default());
595                 )*
596                 );
597 
598                 value
599             }
600         }
601     };
602 
603     // Generates the IO accessors for a fixed offset register.
604     (@io_fixed $name:ident @ $offset:expr) => {
605         #[allow(dead_code)]
606         impl $name {
607             pub(crate) const OFFSET: usize = $offset;
608 
609             /// Read the register from its address in `io`.
610             #[inline(always)]
611             pub(crate) fn read<const SIZE: usize, T>(io: &T) -> Self where
612                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
613             {
614                 Self(io.read32($offset))
615             }
616 
617             /// Write the value contained in `self` to the register address in `io`.
618             #[inline(always)]
619             pub(crate) fn write<const SIZE: usize, T>(self, io: &T) where
620                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
621             {
622                 io.write32(self.0, $offset)
623             }
624 
625             /// Read the register from its address in `io` and run `f` on its value to obtain a new
626             /// value to write back.
627             #[inline(always)]
628             pub(crate) fn alter<const SIZE: usize, T, F>(
629                 io: &T,
630                 f: F,
631             ) where
632                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
633                 F: ::core::ops::FnOnce(Self) -> Self,
634             {
635                 let reg = f(Self::read(io));
636                 reg.write(io);
637             }
638         }
639     };
640 
641     // Generates the IO accessors for a relative offset register.
642     (@io_relative $name:ident @ $base:ty [ $offset:expr ]) => {
643         #[allow(dead_code)]
644         impl $name {
645             pub(crate) const OFFSET: usize = $offset;
646 
647             /// Read the register from `io`, using the base address provided by `base` and adding
648             /// the register's offset to it.
649             #[inline(always)]
650             pub(crate) fn read<const SIZE: usize, T, B>(
651                 io: &T,
652                 #[allow(unused_variables)]
653                 base: &B,
654             ) -> Self where
655                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
656                 B: crate::regs::macros::RegisterBase<$base>,
657             {
658                 const OFFSET: usize = $name::OFFSET;
659 
660                 let value = io.read32(
661                     <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET
662                 );
663 
664                 Self(value)
665             }
666 
667             /// Write the value contained in `self` to `io`, using the base address provided by
668             /// `base` and adding the register's offset to it.
669             #[inline(always)]
670             pub(crate) fn write<const SIZE: usize, T, B>(
671                 self,
672                 io: &T,
673                 #[allow(unused_variables)]
674                 base: &B,
675             ) where
676                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
677                 B: crate::regs::macros::RegisterBase<$base>,
678             {
679                 const OFFSET: usize = $name::OFFSET;
680 
681                 io.write32(
682                     self.0,
683                     <B as crate::regs::macros::RegisterBase<$base>>::BASE + OFFSET
684                 );
685             }
686 
687             /// Read the register from `io`, using the base address provided by `base` and adding
688             /// the register's offset to it, then run `f` on its value to obtain a new value to
689             /// write back.
690             #[inline(always)]
691             pub(crate) fn alter<const SIZE: usize, T, B, F>(
692                 io: &T,
693                 base: &B,
694                 f: F,
695             ) where
696                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
697                 B: crate::regs::macros::RegisterBase<$base>,
698                 F: ::core::ops::FnOnce(Self) -> Self,
699             {
700                 let reg = f(Self::read(io, base));
701                 reg.write(io, base);
702             }
703         }
704     };
705 
706     // Generates the IO accessors for an array of registers.
707     (@io_array $name:ident @ $offset:literal [ $size:expr ; $stride:expr ]) => {
708         #[allow(dead_code)]
709         impl $name {
710             pub(crate) const OFFSET: usize = $offset;
711             pub(crate) const SIZE: usize = $size;
712             pub(crate) const STRIDE: usize = $stride;
713 
714             /// Read the array register at index `idx` from its address in `io`.
715             #[inline(always)]
716             pub(crate) fn read<const SIZE: usize, T>(
717                 io: &T,
718                 idx: usize,
719             ) -> Self where
720                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
721             {
722                 build_assert!(idx < Self::SIZE);
723 
724                 let offset = Self::OFFSET + (idx * Self::STRIDE);
725                 let value = io.read32(offset);
726 
727                 Self(value)
728             }
729 
730             /// Write the value contained in `self` to the array register with index `idx` in `io`.
731             #[inline(always)]
732             pub(crate) fn write<const SIZE: usize, T>(
733                 self,
734                 io: &T,
735                 idx: usize
736             ) where
737                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
738             {
739                 build_assert!(idx < Self::SIZE);
740 
741                 let offset = Self::OFFSET + (idx * Self::STRIDE);
742 
743                 io.write32(self.0, offset);
744             }
745 
746             /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a
747             /// new value to write back.
748             #[inline(always)]
749             pub(crate) fn alter<const SIZE: usize, T, F>(
750                 io: &T,
751                 idx: usize,
752                 f: F,
753             ) where
754                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
755                 F: ::core::ops::FnOnce(Self) -> Self,
756             {
757                 let reg = f(Self::read(io, idx));
758                 reg.write(io, idx);
759             }
760 
761             /// Read the array register at index `idx` from its address in `io`.
762             ///
763             /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
764             /// access was out-of-bounds.
765             #[inline(always)]
766             pub(crate) fn try_read<const SIZE: usize, T>(
767                 io: &T,
768                 idx: usize,
769             ) -> ::kernel::error::Result<Self> where
770                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
771             {
772                 if idx < Self::SIZE {
773                     Ok(Self::read(io, idx))
774                 } else {
775                     Err(EINVAL)
776                 }
777             }
778 
779             /// Write the value contained in `self` to the array register with index `idx` in `io`.
780             ///
781             /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
782             /// access was out-of-bounds.
783             #[inline(always)]
784             pub(crate) fn try_write<const SIZE: usize, T>(
785                 self,
786                 io: &T,
787                 idx: usize,
788             ) -> ::kernel::error::Result where
789                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
790             {
791                 if idx < Self::SIZE {
792                     Ok(self.write(io, idx))
793                 } else {
794                     Err(EINVAL)
795                 }
796             }
797 
798             /// Read the array register at index `idx` in `io` and run `f` on its value to obtain a
799             /// new value to write back.
800             ///
801             /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
802             /// access was out-of-bounds.
803             #[inline(always)]
804             pub(crate) fn try_alter<const SIZE: usize, T, F>(
805                 io: &T,
806                 idx: usize,
807                 f: F,
808             ) -> ::kernel::error::Result where
809                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
810                 F: ::core::ops::FnOnce(Self) -> Self,
811             {
812                 if idx < Self::SIZE {
813                     Ok(Self::alter(io, idx, f))
814                 } else {
815                     Err(EINVAL)
816                 }
817             }
818         }
819     };
820 
821     // Generates the IO accessors for an array of relative registers.
822     (
823         @io_relative_array $name:ident @ $base:ty
824             [ $offset:literal [ $size:expr ; $stride:expr ] ]
825     ) => {
826         #[allow(dead_code)]
827         impl $name {
828             pub(crate) const OFFSET: usize = $offset;
829             pub(crate) const SIZE: usize = $size;
830             pub(crate) const STRIDE: usize = $stride;
831 
832             /// Read the array register at index `idx` from `io`, using the base address provided
833             /// by `base` and adding the register's offset to it.
834             #[inline(always)]
835             pub(crate) fn read<const SIZE: usize, T, B>(
836                 io: &T,
837                 #[allow(unused_variables)]
838                 base: &B,
839                 idx: usize,
840             ) -> Self where
841                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
842                 B: crate::regs::macros::RegisterBase<$base>,
843             {
844                 build_assert!(idx < Self::SIZE);
845 
846                 let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE +
847                     Self::OFFSET + (idx * Self::STRIDE);
848                 let value = io.read32(offset);
849 
850                 Self(value)
851             }
852 
853             /// Write the value contained in `self` to `io`, using the base address provided by
854             /// `base` and adding the offset of array register `idx` to it.
855             #[inline(always)]
856             pub(crate) fn write<const SIZE: usize, T, B>(
857                 self,
858                 io: &T,
859                 #[allow(unused_variables)]
860                 base: &B,
861                 idx: usize
862             ) where
863                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
864                 B: crate::regs::macros::RegisterBase<$base>,
865             {
866                 build_assert!(idx < Self::SIZE);
867 
868                 let offset = <B as crate::regs::macros::RegisterBase<$base>>::BASE +
869                     Self::OFFSET + (idx * Self::STRIDE);
870 
871                 io.write32(self.0, offset);
872             }
873 
874             /// Read the array register at index `idx` from `io`, using the base address provided
875             /// by `base` and adding the register's offset to it, then run `f` on its value to
876             /// obtain a new value to write back.
877             #[inline(always)]
878             pub(crate) fn alter<const SIZE: usize, T, B, F>(
879                 io: &T,
880                 base: &B,
881                 idx: usize,
882                 f: F,
883             ) where
884                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
885                 B: crate::regs::macros::RegisterBase<$base>,
886                 F: ::core::ops::FnOnce(Self) -> Self,
887             {
888                 let reg = f(Self::read(io, base, idx));
889                 reg.write(io, base, idx);
890             }
891 
892             /// Read the array register at index `idx` from `io`, using the base address provided
893             /// by `base` and adding the register's offset to it.
894             ///
895             /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
896             /// access was out-of-bounds.
897             #[inline(always)]
898             pub(crate) fn try_read<const SIZE: usize, T, B>(
899                 io: &T,
900                 base: &B,
901                 idx: usize,
902             ) -> ::kernel::error::Result<Self> where
903                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
904                 B: crate::regs::macros::RegisterBase<$base>,
905             {
906                 if idx < Self::SIZE {
907                     Ok(Self::read(io, base, idx))
908                 } else {
909                     Err(EINVAL)
910                 }
911             }
912 
913             /// Write the value contained in `self` to `io`, using the base address provided by
914             /// `base` and adding the offset of array register `idx` to it.
915             ///
916             /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
917             /// access was out-of-bounds.
918             #[inline(always)]
919             pub(crate) fn try_write<const SIZE: usize, T, B>(
920                 self,
921                 io: &T,
922                 base: &B,
923                 idx: usize,
924             ) -> ::kernel::error::Result where
925                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
926                 B: crate::regs::macros::RegisterBase<$base>,
927             {
928                 if idx < Self::SIZE {
929                     Ok(self.write(io, base, idx))
930                 } else {
931                     Err(EINVAL)
932                 }
933             }
934 
935             /// Read the array register at index `idx` from `io`, using the base address provided
936             /// by `base` and adding the register's offset to it, then run `f` on its value to
937             /// obtain a new value to write back.
938             ///
939             /// The validity of `idx` is checked at run-time, and `EINVAL` is returned is the
940             /// access was out-of-bounds.
941             #[inline(always)]
942             pub(crate) fn try_alter<const SIZE: usize, T, B, F>(
943                 io: &T,
944                 base: &B,
945                 idx: usize,
946                 f: F,
947             ) -> ::kernel::error::Result where
948                 T: ::core::ops::Deref<Target = ::kernel::io::Io<SIZE>>,
949                 B: crate::regs::macros::RegisterBase<$base>,
950                 F: ::core::ops::FnOnce(Self) -> Self,
951             {
952                 if idx < Self::SIZE {
953                     Ok(Self::alter(io, base, idx, f))
954                 } else {
955                     Err(EINVAL)
956                 }
957             }
958         }
959     };
960 }
961