1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Macro to define register layout and accessors. 4 //! 5 //! The [`register!`](kernel::io::register!) macro provides an intuitive and readable syntax for 6 //! defining a dedicated type for each register and accessing it using [`Io`](super::Io). Each such 7 //! type comes with its own field accessors that can return an error if a field's value is invalid. 8 //! 9 //! Note: most of the items in this module are public so they can be referenced by the macro, but 10 //! most are not to be used directly by users. Outside of the `register!` macro itself, the only 11 //! items you might want to import from this module are [`WithBase`] and [`Array`]. 12 //! 13 //! # Simple example 14 //! 15 //! ```no_run 16 //! use kernel::io::register; 17 //! 18 //! register! { 19 //! /// Basic information about the chip. 20 //! pub BOOT_0(u32) @ 0x00000100 { 21 //! /// Vendor ID. 22 //! 15:8 vendor_id; 23 //! /// Major revision of the chip. 24 //! 7:4 major_revision; 25 //! /// Minor revision of the chip. 26 //! 3:0 minor_revision; 27 //! } 28 //! } 29 //! ``` 30 //! 31 //! This defines a 32-bit `BOOT_0` type which can be read from or written to offset `0x100` of an 32 //! `Io` region, with the described bitfields. For instance, `minor_revision` consists of the 4 33 //! least significant bits of the type. 34 //! 35 //! Fields are instances of [`Bounded`](kernel::num::Bounded) and can be read by calling their 36 //! getter method, which is named after them. They also have setter methods prefixed with `with_` 37 //! for runtime values and `with_const_` for constant values. All setters return the updated 38 //! register value. 39 //! 40 //! Fields can also be transparently converted from/to an arbitrary type by using the `=>` and 41 //! `?=>` syntaxes. 42 //! 43 //! If present, doc comments above register or fields definitions are added to the relevant item 44 //! they document (the register type itself, or the field's setter and getter methods). 45 //! 46 //! Note that multiple registers can be defined in a single `register!` invocation. This can be 47 //! useful to group related registers together. 48 //! 49 //! Here is how the register defined above can be used in code: 50 //! 51 //! 52 //! ```no_run 53 //! use kernel::{ 54 //! io::{ 55 //! register, 56 //! Io, 57 //! IoLoc, 58 //! }, 59 //! num::Bounded, 60 //! }; 61 //! # use kernel::io::Mmio; 62 //! # register! { 63 //! # pub BOOT_0(u32) @ 0x00000100 { 64 //! # 15:8 vendor_id; 65 //! # 7:4 major_revision; 66 //! # 3:0 minor_revision; 67 //! # } 68 //! # } 69 //! # fn test(io: &Mmio<0x1000>) { 70 //! # fn obtain_vendor_id() -> u8 { 0xff } 71 //! 72 //! // Read from the register's defined offset (0x100). 73 //! let boot0 = io.read(BOOT_0); 74 //! pr_info!("chip revision: {}.{}", boot0.major_revision().get(), boot0.minor_revision().get()); 75 //! 76 //! // Update some fields and write the new value back. 77 //! let new_boot0 = boot0 78 //! // Constant values. 79 //! .with_const_major_revision::<3>() 80 //! .with_const_minor_revision::<10>() 81 //! // Runtime value. 82 //! .with_vendor_id(obtain_vendor_id()); 83 //! io.write((), new_boot0); 84 //! 85 //! // Or, build a new value from zero and write it: 86 //! io.write((), BOOT_0::zeroed() 87 //! .with_const_major_revision::<3>() 88 //! .with_const_minor_revision::<10>() 89 //! .with_vendor_id(obtain_vendor_id()) 90 //! ); 91 //! 92 //! // Or, read and update the register in a single step. 93 //! io.update(BOOT_0, |r| r 94 //! .with_const_major_revision::<3>() 95 //! .with_const_minor_revision::<10>() 96 //! .with_vendor_id(obtain_vendor_id()) 97 //! ); 98 //! 99 //! // Constant values can also be built using the const setters. 100 //! const V: BOOT_0 = pin_init::zeroed::<BOOT_0>() 101 //! .with_const_major_revision::<3>() 102 //! .with_const_minor_revision::<10>(); 103 //! # } 104 //! ``` 105 //! 106 //! For more extensive documentation about how to define registers, see the 107 //! [`register!`](kernel::io::register!) macro. 108 109 use core::marker::PhantomData; 110 111 use crate::io::IoLoc; 112 113 use kernel::build_assert; 114 115 /// Trait implemented by all registers. 116 pub trait Register: Sized { 117 /// Backing primitive type of the register. 118 type Storage: Into<Self> + From<Self>; 119 120 /// Start offset of the register. 121 /// 122 /// The interpretation of this offset depends on the type of the register. 123 const OFFSET: usize; 124 } 125 126 /// Trait implemented by registers with a fixed offset. 127 pub trait FixedRegister: Register {} 128 129 /// Allows `()` to be used as the `location` parameter of [`Io::write`](super::Io::write) when 130 /// passing a [`FixedRegister`] value. 131 impl<T> IoLoc<T> for () 132 where 133 T: FixedRegister, 134 { 135 type IoType = T::Storage; 136 137 #[inline(always)] 138 fn offset(self) -> usize { 139 T::OFFSET 140 } 141 } 142 143 /// A [`FixedRegister`] carries its location in its type. Thus `FixedRegister` values can be used 144 /// as an [`IoLoc`]. 145 impl<T> IoLoc<T> for T 146 where 147 T: FixedRegister, 148 { 149 type IoType = T::Storage; 150 151 #[inline(always)] 152 fn offset(self) -> usize { 153 T::OFFSET 154 } 155 } 156 157 /// Location of a fixed register. 158 pub struct FixedRegisterLoc<T: FixedRegister>(PhantomData<T>); 159 160 impl<T: FixedRegister> FixedRegisterLoc<T> { 161 /// Returns the location of `T`. 162 #[inline(always)] 163 // We do not implement `Default` so we can be const. 164 #[expect(clippy::new_without_default)] 165 pub const fn new() -> Self { 166 Self(PhantomData) 167 } 168 } 169 170 impl<T> IoLoc<T> for FixedRegisterLoc<T> 171 where 172 T: FixedRegister, 173 { 174 type IoType = T::Storage; 175 176 #[inline(always)] 177 fn offset(self) -> usize { 178 T::OFFSET 179 } 180 } 181 182 /// Trait providing a base address to be added to the offset of a relative register to obtain 183 /// its actual offset. 184 /// 185 /// The `T` generic argument is used to distinguish which base to use, in case a type provides 186 /// several bases. It is given to the `register!` macro to restrict the use of the register to 187 /// implementors of this particular variant. 188 pub trait RegisterBase<T> { 189 /// Base address to which register offsets are added. 190 const BASE: usize; 191 } 192 193 /// Trait implemented by all registers that are relative to a base. 194 pub trait WithBase { 195 /// Family of bases applicable to this register. 196 type BaseFamily; 197 198 /// Returns the absolute location of this type when using `B` as its base. 199 #[inline(always)] 200 fn of<B: RegisterBase<Self::BaseFamily>>() -> RelativeRegisterLoc<Self, B> 201 where 202 Self: Register, 203 { 204 RelativeRegisterLoc::new() 205 } 206 } 207 208 /// Trait implemented by relative registers. 209 pub trait RelativeRegister: Register + WithBase {} 210 211 /// Location of a relative register. 212 /// 213 /// This can either be an immediately accessible regular [`RelativeRegister`], or a 214 /// [`RelativeRegisterArray`] that needs one additional resolution through 215 /// [`RelativeRegisterLoc::at`]. 216 pub struct RelativeRegisterLoc<T: WithBase, B: ?Sized>(PhantomData<T>, PhantomData<B>); 217 218 impl<T, B> RelativeRegisterLoc<T, B> 219 where 220 T: Register + WithBase, 221 B: RegisterBase<T::BaseFamily> + ?Sized, 222 { 223 /// Returns the location of a relative register or register array. 224 #[inline(always)] 225 // We do not implement `Default` so we can be const. 226 #[expect(clippy::new_without_default)] 227 pub const fn new() -> Self { 228 Self(PhantomData, PhantomData) 229 } 230 231 // Returns the absolute offset of the relative register using base `B`. 232 // 233 // This is implemented as a private const method so it can be reused by the [`IoLoc`] 234 // implementations of both [`RelativeRegisterLoc`] and [`RelativeRegisterArrayLoc`]. 235 #[inline] 236 const fn offset(self) -> usize { 237 B::BASE + T::OFFSET 238 } 239 } 240 241 impl<T, B> IoLoc<T> for RelativeRegisterLoc<T, B> 242 where 243 T: RelativeRegister, 244 B: RegisterBase<T::BaseFamily> + ?Sized, 245 { 246 type IoType = T::Storage; 247 248 #[inline(always)] 249 fn offset(self) -> usize { 250 RelativeRegisterLoc::offset(self) 251 } 252 } 253 254 /// Trait implemented by arrays of registers. 255 pub trait RegisterArray: Register { 256 /// Number of elements in the registers array. 257 const SIZE: usize; 258 /// Number of bytes between the start of elements in the registers array. 259 const STRIDE: usize; 260 } 261 262 /// Location of an array register. 263 pub struct RegisterArrayLoc<T: RegisterArray>(usize, PhantomData<T>); 264 265 impl<T: RegisterArray> RegisterArrayLoc<T> { 266 /// Returns the location of register `T` at position `idx`, with build-time validation. 267 #[inline(always)] 268 pub fn new(idx: usize) -> Self { 269 build_assert!(idx < T::SIZE); 270 271 Self(idx, PhantomData) 272 } 273 274 /// Attempts to return the location of register `T` at position `idx`, with runtime validation. 275 #[inline(always)] 276 pub fn try_new(idx: usize) -> Option<Self> { 277 if idx < T::SIZE { 278 Some(Self(idx, PhantomData)) 279 } else { 280 None 281 } 282 } 283 } 284 285 impl<T> IoLoc<T> for RegisterArrayLoc<T> 286 where 287 T: RegisterArray, 288 { 289 type IoType = T::Storage; 290 291 #[inline(always)] 292 fn offset(self) -> usize { 293 T::OFFSET + self.0 * T::STRIDE 294 } 295 } 296 297 /// Trait providing location builders for [`RegisterArray`]s. 298 pub trait Array { 299 /// Returns the location of the register at position `idx`, with build-time validation. 300 #[inline(always)] 301 fn at(idx: usize) -> RegisterArrayLoc<Self> 302 where 303 Self: RegisterArray, 304 { 305 RegisterArrayLoc::new(idx) 306 } 307 308 /// Returns the location of the register at position `idx`, with runtime validation. 309 #[inline(always)] 310 fn try_at(idx: usize) -> Option<RegisterArrayLoc<Self>> 311 where 312 Self: RegisterArray, 313 { 314 RegisterArrayLoc::try_new(idx) 315 } 316 } 317 318 /// Trait implemented by arrays of relative registers. 319 pub trait RelativeRegisterArray: RegisterArray + WithBase {} 320 321 /// Location of a relative array register. 322 pub struct RelativeRegisterArrayLoc< 323 T: RelativeRegisterArray, 324 B: RegisterBase<T::BaseFamily> + ?Sized, 325 >(RelativeRegisterLoc<T, B>, usize); 326 327 impl<T, B> RelativeRegisterArrayLoc<T, B> 328 where 329 T: RelativeRegisterArray, 330 B: RegisterBase<T::BaseFamily> + ?Sized, 331 { 332 /// Returns the location of register `T` from the base `B` at index `idx`, with build-time 333 /// validation. 334 #[inline(always)] 335 pub fn new(idx: usize) -> Self { 336 build_assert!(idx < T::SIZE); 337 338 Self(RelativeRegisterLoc::new(), idx) 339 } 340 341 /// Attempts to return the location of register `T` from the base `B` at index `idx`, with 342 /// runtime validation. 343 #[inline(always)] 344 pub fn try_new(idx: usize) -> Option<Self> { 345 if idx < T::SIZE { 346 Some(Self(RelativeRegisterLoc::new(), idx)) 347 } else { 348 None 349 } 350 } 351 } 352 353 /// Methods exclusive to [`RelativeRegisterLoc`]s created with a [`RelativeRegisterArray`]. 354 impl<T, B> RelativeRegisterLoc<T, B> 355 where 356 T: RelativeRegisterArray, 357 B: RegisterBase<T::BaseFamily> + ?Sized, 358 { 359 /// Returns the location of the register at position `idx`, with build-time validation. 360 #[inline(always)] 361 pub fn at(self, idx: usize) -> RelativeRegisterArrayLoc<T, B> { 362 RelativeRegisterArrayLoc::new(idx) 363 } 364 365 /// Returns the location of the register at position `idx`, with runtime validation. 366 #[inline(always)] 367 pub fn try_at(self, idx: usize) -> Option<RelativeRegisterArrayLoc<T, B>> { 368 RelativeRegisterArrayLoc::try_new(idx) 369 } 370 } 371 372 impl<T, B> IoLoc<T> for RelativeRegisterArrayLoc<T, B> 373 where 374 T: RelativeRegisterArray, 375 B: RegisterBase<T::BaseFamily> + ?Sized, 376 { 377 type IoType = T::Storage; 378 379 #[inline(always)] 380 fn offset(self) -> usize { 381 self.0.offset() + self.1 * T::STRIDE 382 } 383 } 384 385 /// Defines a dedicated type for a register, including getter and setter methods for its fields and 386 /// methods to read and write it from an [`Io`](kernel::io::Io) region. 387 /// 388 /// This documentation focuses on how to declare registers. See the [module-level 389 /// documentation](mod@kernel::io::register) for examples of how to access them. 390 /// 391 /// There are 4 possible kinds of registers: fixed offset registers, relative registers, arrays of 392 /// registers, and relative arrays of registers. 393 /// 394 /// ## Fixed offset registers 395 /// 396 /// These are the simplest kind of registers. Their location is simply an offset inside the I/O 397 /// region. For instance: 398 /// 399 /// ```ignore 400 /// register! { 401 /// pub FIXED_REG(u16) @ 0x80 { 402 /// ... 403 /// } 404 /// } 405 /// ``` 406 /// 407 /// This creates a 16-bit register named `FIXED_REG` located at offset `0x80` of an I/O region. 408 /// 409 /// These registers' location can be built simply by referencing their name: 410 /// 411 /// ```no_run 412 /// use kernel::{ 413 /// io::{ 414 /// register, 415 /// Io, 416 /// }, 417 /// }; 418 /// # use kernel::io::Mmio; 419 /// 420 /// register! { 421 /// FIXED_REG(u32) @ 0x100 { 422 /// 16:8 high_byte; 423 /// 7:0 low_byte; 424 /// } 425 /// } 426 /// 427 /// # fn test(io: &Mmio<0x1000>) { 428 /// let val = io.read(FIXED_REG); 429 /// 430 /// // Write from an already-existing value. 431 /// io.write(FIXED_REG, val.with_low_byte(0xff)); 432 /// 433 /// // Create a register value from scratch. 434 /// let val2 = FIXED_REG::zeroed().with_high_byte(0x80); 435 /// 436 /// // The location of fixed offset registers is already contained in their type. Thus, the 437 /// // `location` argument of `Io::write` is technically redundant and can be replaced by `()`. 438 /// io.write((), val2); 439 /// # } 440 /// 441 /// ``` 442 /// 443 /// It is possible to create an alias of an existing register with new field definitions by using 444 /// the `=> ALIAS` syntax. This is useful for cases where a register's interpretation depends on 445 /// the context: 446 /// 447 /// ```no_run 448 /// use kernel::io::register; 449 /// 450 /// register! { 451 /// /// Scratch register. 452 /// pub SCRATCH(u32) @ 0x00000200 { 453 /// 31:0 value; 454 /// } 455 /// 456 /// /// Boot status of the firmware. 457 /// pub SCRATCH_BOOT_STATUS(u32) => SCRATCH { 458 /// 0:0 completed; 459 /// } 460 /// } 461 /// ``` 462 /// 463 /// In this example, `SCRATCH_BOOT_STATUS` uses the same I/O address as `SCRATCH`, while providing 464 /// its own `completed` field. 465 /// 466 /// ## Relative registers 467 /// 468 /// Relative registers can be instantiated several times at a relative offset of a group of bases. 469 /// For instance, imagine the following I/O space: 470 /// 471 /// ```text 472 /// +-----------------------------+ 473 /// | ... | 474 /// | | 475 /// 0x100--->+------------CPU0-------------+ 476 /// | | 477 /// 0x110--->+-----------------------------+ 478 /// | CPU_CTL | 479 /// +-----------------------------+ 480 /// | ... | 481 /// | | 482 /// | | 483 /// 0x200--->+------------CPU1-------------+ 484 /// | | 485 /// 0x210--->+-----------------------------+ 486 /// | CPU_CTL | 487 /// +-----------------------------+ 488 /// | ... | 489 /// +-----------------------------+ 490 /// ``` 491 /// 492 /// `CPU0` and `CPU1` both have a `CPU_CTL` register that starts at offset `0x10` of their I/O 493 /// space segment. Since both instances of `CPU_CTL` share the same layout, we don't want to define 494 /// them twice and would prefer a way to select which one to use from a single definition. 495 /// 496 /// This can be done using the `Base + Offset` syntax when specifying the register's address: 497 /// 498 /// ```ignore 499 /// register! { 500 /// pub RELATIVE_REG(u32) @ Base + 0x80 { 501 /// ... 502 /// } 503 /// } 504 /// ``` 505 /// 506 /// This creates a register with an offset of `0x80` from a given base. 507 /// 508 /// `Base` is an arbitrary type (typically a ZST) to be used as a generic parameter of the 509 /// [`RegisterBase`] trait to provide the base as a constant, i.e. each type providing a base for 510 /// this register needs to implement `RegisterBase<Base>`. 511 /// 512 /// The location of relative registers can be built using the [`WithBase::of`] method to specify 513 /// its base. All relative registers implement [`WithBase`]. 514 /// 515 /// Here is the above layout translated into code: 516 /// 517 /// ```no_run 518 /// use kernel::{ 519 /// io::{ 520 /// register, 521 /// register::{ 522 /// RegisterBase, 523 /// WithBase, 524 /// }, 525 /// Io, 526 /// }, 527 /// }; 528 /// # use kernel::io::Mmio; 529 /// 530 /// // Type used to identify the base. 531 /// pub struct CpuCtlBase; 532 /// 533 /// // ZST describing `CPU0`. 534 /// struct Cpu0; 535 /// impl RegisterBase<CpuCtlBase> for Cpu0 { 536 /// const BASE: usize = 0x100; 537 /// } 538 /// 539 /// // ZST describing `CPU1`. 540 /// struct Cpu1; 541 /// impl RegisterBase<CpuCtlBase> for Cpu1 { 542 /// const BASE: usize = 0x200; 543 /// } 544 /// 545 /// // This makes `CPU_CTL` accessible from all implementors of `RegisterBase<CpuCtlBase>`. 546 /// register! { 547 /// /// CPU core control. 548 /// pub CPU_CTL(u32) @ CpuCtlBase + 0x10 { 549 /// 0:0 start; 550 /// } 551 /// } 552 /// 553 /// # fn test(io: Mmio<0x1000>) { 554 /// // Read the status of `Cpu0`. 555 /// let cpu0_started = io.read(CPU_CTL::of::<Cpu0>()); 556 /// 557 /// // Stop `Cpu0`. 558 /// io.write(WithBase::of::<Cpu0>(), CPU_CTL::zeroed()); 559 /// # } 560 /// 561 /// // Aliases can also be defined for relative register. 562 /// register! { 563 /// /// Alias to CPU core control. 564 /// pub CPU_CTL_ALIAS(u32) => CpuCtlBase + CPU_CTL { 565 /// /// Start the aliased CPU core. 566 /// 1:1 alias_start; 567 /// } 568 /// } 569 /// 570 /// # fn test2(io: Mmio<0x1000>) { 571 /// // Start the aliased `CPU0`, leaving its other fields untouched. 572 /// io.update(CPU_CTL_ALIAS::of::<Cpu0>(), |r| r.with_alias_start(true)); 573 /// # } 574 /// ``` 575 /// 576 /// ## Arrays of registers 577 /// 578 /// Some I/O areas contain consecutive registers that share the same field layout. These areas can 579 /// be defined as an array of identical registers, allowing them to be accessed by index with 580 /// compile-time or runtime bound checking: 581 /// 582 /// ```ignore 583 /// register! { 584 /// pub REGISTER_ARRAY(u8)[10, stride = 4] @ 0x100 { 585 /// ... 586 /// } 587 /// } 588 /// ``` 589 /// 590 /// This defines `REGISTER_ARRAY`, an array of 10 byte registers starting at offset `0x100`. Each 591 /// register is separated from its neighbor by 4 bytes. 592 /// 593 /// The `stride` parameter is optional; if unspecified, the registers are placed consecutively from 594 /// each other. 595 /// 596 /// A location for a register in a register array is built using the [`Array::at`] trait method. 597 /// All arrays of registers implement [`Array`]. 598 /// 599 /// ```no_run 600 /// use kernel::{ 601 /// io::{ 602 /// register, 603 /// register::Array, 604 /// Io, 605 /// }, 606 /// }; 607 /// # use kernel::io::Mmio; 608 /// # fn get_scratch_idx() -> usize { 609 /// # 0x15 610 /// # } 611 /// 612 /// // Array of 64 consecutive registers with the same layout starting at offset `0x80`. 613 /// register! { 614 /// /// Scratch registers. 615 /// pub SCRATCH(u32)[64] @ 0x00000080 { 616 /// 31:0 value; 617 /// } 618 /// } 619 /// 620 /// # fn test(io: &Mmio<0x1000>) 621 /// # -> Result<(), Error>{ 622 /// // Read scratch register 0, i.e. I/O address `0x80`. 623 /// let scratch_0 = io.read(SCRATCH::at(0)).value(); 624 /// 625 /// // Write scratch register 15, i.e. I/O address `0x80 + (15 * 4)`. 626 /// io.write(Array::at(15), SCRATCH::from(0xffeeaabb)); 627 /// 628 /// // This is out of bounds and won't build. 629 /// // let scratch_128 = io.read(SCRATCH::at(128)).value(); 630 /// 631 /// // Runtime-obtained array index. 632 /// let idx = get_scratch_idx(); 633 /// // Access on a runtime index returns an error if it is out-of-bounds. 634 /// let some_scratch = io.read(SCRATCH::try_at(idx).ok_or(EINVAL)?).value(); 635 /// 636 /// // Alias to a specific register in an array. 637 /// // Here `SCRATCH[8]` is used to convey the firmware exit code. 638 /// register! { 639 /// /// Firmware exit status code. 640 /// pub FIRMWARE_STATUS(u32) => SCRATCH[8] { 641 /// 7:0 status; 642 /// } 643 /// } 644 /// 645 /// let status = io.read(FIRMWARE_STATUS).status(); 646 /// 647 /// // Non-contiguous register arrays can be defined by adding a stride parameter. 648 /// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the 649 /// // registers of the two declarations below are interleaved. 650 /// register! { 651 /// /// Scratch registers bank 0. 652 /// pub SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ 0x000000c0 { 653 /// 31:0 value; 654 /// } 655 /// 656 /// /// Scratch registers bank 1. 657 /// pub SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ 0x000000c4 { 658 /// 31:0 value; 659 /// } 660 /// } 661 /// # Ok(()) 662 /// # } 663 /// ``` 664 /// 665 /// ## Relative arrays of registers 666 /// 667 /// Combining the two features described in the sections above, arrays of registers accessible from 668 /// a base can also be defined: 669 /// 670 /// ```ignore 671 /// register! { 672 /// pub RELATIVE_REGISTER_ARRAY(u8)[10, stride = 4] @ Base + 0x100 { 673 /// ... 674 /// } 675 /// } 676 /// ``` 677 /// 678 /// Like relative registers, they implement the [`WithBase`] trait. However the return value of 679 /// [`WithBase::of`] cannot be used directly as a location and must be further specified using the 680 /// [`at`](RelativeRegisterLoc::at) method. 681 /// 682 /// ```no_run 683 /// use kernel::{ 684 /// io::{ 685 /// register, 686 /// register::{ 687 /// RegisterBase, 688 /// WithBase, 689 /// }, 690 /// Io, 691 /// }, 692 /// }; 693 /// # use kernel::io::Mmio; 694 /// # fn get_scratch_idx() -> usize { 695 /// # 0x15 696 /// # } 697 /// 698 /// // Type used as parameter of `RegisterBase` to specify the base. 699 /// pub struct CpuCtlBase; 700 /// 701 /// // ZST describing `CPU0`. 702 /// struct Cpu0; 703 /// impl RegisterBase<CpuCtlBase> for Cpu0 { 704 /// const BASE: usize = 0x100; 705 /// } 706 /// 707 /// // ZST describing `CPU1`. 708 /// struct Cpu1; 709 /// impl RegisterBase<CpuCtlBase> for Cpu1 { 710 /// const BASE: usize = 0x200; 711 /// } 712 /// 713 /// // 64 per-cpu scratch registers, arranged as a contiguous array. 714 /// register! { 715 /// /// Per-CPU scratch registers. 716 /// pub CPU_SCRATCH(u32)[64] @ CpuCtlBase + 0x00000080 { 717 /// 31:0 value; 718 /// } 719 /// } 720 /// 721 /// # fn test(io: &Mmio<0x1000>) -> Result<(), Error> { 722 /// // Read scratch register 0 of CPU0. 723 /// let scratch = io.read(CPU_SCRATCH::of::<Cpu0>().at(0)); 724 /// 725 /// // Write the retrieved value into scratch register 15 of CPU1. 726 /// io.write(WithBase::of::<Cpu1>().at(15), scratch); 727 /// 728 /// // This won't build. 729 /// // let cpu0_scratch_128 = io.read(CPU_SCRATCH::of::<Cpu0>().at(128)).value(); 730 /// 731 /// // Runtime-obtained array index. 732 /// let scratch_idx = get_scratch_idx(); 733 /// // Access on a runtime index returns an error if it is out-of-bounds. 734 /// let cpu0_scratch = io.read( 735 /// CPU_SCRATCH::of::<Cpu0>().try_at(scratch_idx).ok_or(EINVAL)? 736 /// ).value(); 737 /// # Ok(()) 738 /// # } 739 /// 740 /// // Alias to `SCRATCH[8]` used to convey the firmware exit code. 741 /// register! { 742 /// /// Per-CPU firmware exit status code. 743 /// pub CPU_FIRMWARE_STATUS(u32) => CpuCtlBase + CPU_SCRATCH[8] { 744 /// 7:0 status; 745 /// } 746 /// } 747 /// 748 /// // Non-contiguous relative register arrays can be defined by adding a stride parameter. 749 /// // Here, each of the 16 registers of the array is separated by 8 bytes, meaning that the 750 /// // registers of the two declarations below are interleaved. 751 /// register! { 752 /// /// Scratch registers bank 0. 753 /// pub CPU_SCRATCH_INTERLEAVED_0(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d00 { 754 /// 31:0 value; 755 /// } 756 /// 757 /// /// Scratch registers bank 1. 758 /// pub CPU_SCRATCH_INTERLEAVED_1(u32)[16, stride = 8] @ CpuCtlBase + 0x00000d04 { 759 /// 31:0 value; 760 /// } 761 /// } 762 /// 763 /// # fn test2(io: &Mmio<0x1000>) -> Result<(), Error> { 764 /// let cpu0_status = io.read(CPU_FIRMWARE_STATUS::of::<Cpu0>()).status(); 765 /// # Ok(()) 766 /// # } 767 /// ``` 768 #[macro_export] 769 macro_rules! register { 770 // Entry point for the macro, allowing multiple registers to be defined in one call. 771 // It matches all possible register declaration patterns to dispatch them to corresponding 772 // `@reg` rule that defines a single register. 773 ( 774 $( 775 $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 776 $([ $size:expr $(, stride = $stride:expr)? ])? 777 $(@ $($base:ident +)? $offset:literal)? 778 $(=> $alias:ident $(+ $alias_offset:ident)? $([$alias_idx:expr])? )? 779 { $($fields:tt)* } 780 )* 781 ) => { 782 $( 783 $crate::register!( 784 @reg $(#[$attr])* $vis $name ($storage) $([$size $(, stride = $stride)?])? 785 $(@ $($base +)? $offset)? 786 $(=> $alias $(+ $alias_offset)? $([$alias_idx])? )? 787 { $($fields)* } 788 ); 789 )* 790 }; 791 792 // All the rules below are private helpers. 793 794 // Creates a register at a fixed offset of the MMIO space. 795 ( 796 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $offset:literal 797 { $($fields:tt)* } 798 ) => { 799 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 800 $crate::register!(@io_base $name($storage) @ $offset); 801 $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); 802 }; 803 804 // Creates an alias register of fixed offset register `alias` with its own fields. 805 ( 806 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident 807 { $($fields:tt)* } 808 ) => { 809 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 810 $crate::register!( 811 @io_base $name($storage) @ 812 <$alias as $crate::io::register::Register>::OFFSET 813 ); 814 $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); 815 }; 816 817 // Creates a register at a relative offset from a base address provider. 818 ( 819 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) @ $base:ident + $offset:literal 820 { $($fields:tt)* } 821 ) => { 822 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 823 $crate::register!(@io_base $name($storage) @ $offset); 824 $crate::register!(@io_relative $vis $name($storage) @ $base); 825 }; 826 827 // Creates an alias register of relative offset register `alias` with its own fields. 828 ( 829 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $base:ident + $alias:ident 830 { $($fields:tt)* } 831 ) => { 832 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 833 $crate::register!( 834 @io_base $name($storage) @ <$alias as $crate::io::register::Register>::OFFSET 835 ); 836 $crate::register!(@io_relative $vis $name($storage) @ $base); 837 }; 838 839 // Creates an array of registers at a fixed offset of the MMIO space. 840 ( 841 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 842 [ $size:expr, stride = $stride:expr ] @ $offset:literal { $($fields:tt)* } 843 ) => { 844 ::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride); 845 846 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 847 $crate::register!(@io_base $name($storage) @ $offset); 848 $crate::register!(@io_array $vis $name($storage) [ $size, stride = $stride ]); 849 }; 850 851 // Shortcut for contiguous array of registers (stride == size of element). 852 ( 853 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ] @ $offset:literal 854 { $($fields:tt)* } 855 ) => { 856 $crate::register!( 857 $(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ] 858 @ $offset { $($fields)* } 859 ); 860 }; 861 862 // Creates an alias of register `idx` of array of registers `alias` with its own fields. 863 ( 864 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) => $alias:ident [ $idx:expr ] 865 { $($fields:tt)* } 866 ) => { 867 ::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE); 868 869 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 870 $crate::register!( 871 @io_base $name($storage) @ 872 <$alias as $crate::io::register::Register>::OFFSET 873 + $idx * <$alias as $crate::io::register::RegisterArray>::STRIDE 874 ); 875 $crate::register!(@io_fixed $(#[$attr])* $vis $name($storage)); 876 }; 877 878 // Creates an array of registers at a relative offset from a base address provider. 879 ( 880 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 881 [ $size:expr, stride = $stride:expr ] 882 @ $base:ident + $offset:literal { $($fields:tt)* } 883 ) => { 884 ::kernel::static_assert!(::core::mem::size_of::<$storage>() <= $stride); 885 886 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 887 $crate::register!(@io_base $name($storage) @ $offset); 888 $crate::register!( 889 @io_relative_array $vis $name($storage) [ $size, stride = $stride ] @ $base + $offset 890 ); 891 }; 892 893 // Shortcut for contiguous array of relative registers (stride == size of element). 894 ( 895 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) [ $size:expr ] 896 @ $base:ident + $offset:literal { $($fields:tt)* } 897 ) => { 898 $crate::register!( 899 $(#[$attr])* $vis $name($storage) [ $size, stride = ::core::mem::size_of::<$storage>() ] 900 @ $base + $offset { $($fields)* } 901 ); 902 }; 903 904 // Creates an alias of register `idx` of relative array of registers `alias` with its own 905 // fields. 906 ( 907 @reg $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty) 908 => $base:ident + $alias:ident [ $idx:expr ] { $($fields:tt)* } 909 ) => { 910 ::kernel::static_assert!($idx < <$alias as $crate::io::register::RegisterArray>::SIZE); 911 912 $crate::register!(@bitfield $(#[$attr])* $vis struct $name($storage) { $($fields)* }); 913 $crate::register!( 914 @io_base $name($storage) @ 915 <$alias as $crate::io::register::Register>::OFFSET + 916 $idx * <$alias as $crate::io::register::RegisterArray>::STRIDE 917 ); 918 $crate::register!(@io_relative $vis $name($storage) @ $base); 919 }; 920 921 // Generates the bitfield for the register. 922 // 923 // `#[allow(non_camel_case_types)]` is added since register names typically use 924 // `SCREAMING_CASE`. 925 ( 926 @bitfield $(#[$attr:meta])* $vis:vis struct $name:ident($storage:ty) { $($fields:tt)* } 927 ) => { 928 $crate::register!(@bitfield_core 929 #[allow(non_camel_case_types)] 930 $(#[$attr])* $vis $name $storage 931 ); 932 $crate::register!(@bitfield_fields $vis $name $storage { $($fields)* }); 933 }; 934 935 // Implementations shared by all registers types. 936 (@io_base $name:ident($storage:ty) @ $offset:expr) => { 937 impl $crate::io::register::Register for $name { 938 type Storage = $storage; 939 940 const OFFSET: usize = $offset; 941 } 942 }; 943 944 // Implementations of fixed registers. 945 (@io_fixed $(#[$attr:meta])* $vis:vis $name:ident ($storage:ty)) => { 946 impl $crate::io::register::FixedRegister for $name {} 947 948 $(#[$attr])* 949 $vis const $name: $crate::io::register::FixedRegisterLoc<$name> = 950 $crate::io::register::FixedRegisterLoc::<$name>::new(); 951 }; 952 953 // Implementations of relative registers. 954 (@io_relative $vis:vis $name:ident ($storage:ty) @ $base:ident) => { 955 impl $crate::io::register::WithBase for $name { 956 type BaseFamily = $base; 957 } 958 959 impl $crate::io::register::RelativeRegister for $name {} 960 }; 961 962 // Implementations of register arrays. 963 (@io_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ]) => { 964 impl $crate::io::register::Array for $name {} 965 966 impl $crate::io::register::RegisterArray for $name { 967 const SIZE: usize = $size; 968 const STRIDE: usize = $stride; 969 } 970 }; 971 972 // Implementations of relative array registers. 973 ( 974 @io_relative_array $vis:vis $name:ident ($storage:ty) [ $size:expr, stride = $stride:expr ] 975 @ $base:ident + $offset:literal 976 ) => { 977 impl $crate::io::register::WithBase for $name { 978 type BaseFamily = $base; 979 } 980 981 impl $crate::io::register::RegisterArray for $name { 982 const SIZE: usize = $size; 983 const STRIDE: usize = $stride; 984 } 985 986 impl $crate::io::register::RelativeRegisterArray for $name {} 987 }; 988 989 // Defines the wrapper `$name` type and its conversions from/to the storage type. 990 (@bitfield_core $(#[$attr:meta])* $vis:vis $name:ident $storage:ty) => { 991 $(#[$attr])* 992 #[repr(transparent)] 993 #[derive(Clone, Copy, PartialEq, Eq)] 994 $vis struct $name { 995 inner: $storage, 996 } 997 998 #[allow(dead_code)] 999 impl $name { 1000 /// Creates a bitfield from a raw value. 1001 #[inline(always)] 1002 $vis const fn from_raw(value: $storage) -> Self { 1003 Self{ inner: value } 1004 } 1005 1006 /// Turns this bitfield into its raw value. 1007 /// 1008 /// This is similar to the [`From`] implementation, but is shorter to invoke in 1009 /// most cases. 1010 #[inline(always)] 1011 $vis const fn into_raw(self) -> $storage { 1012 self.inner 1013 } 1014 } 1015 1016 // SAFETY: `$storage` is `Zeroable` and `$name` is transparent. 1017 unsafe impl ::pin_init::Zeroable for $name {} 1018 1019 impl ::core::convert::From<$name> for $storage { 1020 #[inline(always)] 1021 fn from(val: $name) -> $storage { 1022 val.into_raw() 1023 } 1024 } 1025 1026 impl ::core::convert::From<$storage> for $name { 1027 #[inline(always)] 1028 fn from(val: $storage) -> $name { 1029 Self::from_raw(val) 1030 } 1031 } 1032 }; 1033 1034 // Definitions requiring knowledge of individual fields: private and public field accessors, 1035 // and `Debug` implementation. 1036 (@bitfield_fields $vis:vis $name:ident $storage:ty { 1037 $($(#[doc = $doc:expr])* $hi:literal:$lo:literal $field:ident 1038 $(?=> $try_into_type:ty)? 1039 $(=> $into_type:ty)? 1040 ; 1041 )* 1042 } 1043 ) => { 1044 #[allow(dead_code)] 1045 impl $name { 1046 $( 1047 $crate::register!(@private_field_accessors $vis $name $storage : $hi:$lo $field); 1048 $crate::register!( 1049 @public_field_accessors $(#[doc = $doc])* $vis $name $storage : $hi:$lo $field 1050 $(?=> $try_into_type)? 1051 $(=> $into_type)? 1052 ); 1053 )* 1054 } 1055 1056 $crate::register!(@debug $name { $($field;)* }); 1057 }; 1058 1059 // Private field accessors working with the exact `Bounded` type for the field. 1060 ( 1061 @private_field_accessors $vis:vis $name:ident $storage:ty : $hi:tt:$lo:tt $field:ident 1062 ) => { 1063 ::kernel::macros::paste!( 1064 $vis const [<$field:upper _RANGE>]: ::core::ops::RangeInclusive<u8> = $lo..=$hi; 1065 $vis const [<$field:upper _MASK>]: $storage = 1066 ((((1 << $hi) - 1) << 1) + 1) - ((1 << $lo) - 1); 1067 $vis const [<$field:upper _SHIFT>]: u32 = $lo; 1068 ); 1069 1070 ::kernel::macros::paste!( 1071 fn [<__ $field>](self) -> 1072 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> { 1073 // Left shift to align the field's MSB with the storage MSB. 1074 const ALIGN_TOP: u32 = $storage::BITS - ($hi + 1); 1075 // Right shift to move the top-aligned field to bit 0 of the storage. 1076 const ALIGN_BOTTOM: u32 = ALIGN_TOP + $lo; 1077 1078 // Extract the field using two shifts. `Bounded::shr` produces the correctly-sized 1079 // output type. 1080 let val = ::kernel::num::Bounded::<$storage, { $storage::BITS }>::from( 1081 self.inner << ALIGN_TOP 1082 ); 1083 val.shr::<ALIGN_BOTTOM, { $hi + 1 - $lo } >() 1084 } 1085 1086 const fn [<__with_ $field>]( 1087 mut self, 1088 value: ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>, 1089 ) -> Self 1090 { 1091 const MASK: $storage = <$name>::[<$field:upper _MASK>]; 1092 const SHIFT: u32 = <$name>::[<$field:upper _SHIFT>]; 1093 1094 let value = value.get() << SHIFT; 1095 self.inner = (self.inner & !MASK) | value; 1096 1097 self 1098 } 1099 ); 1100 }; 1101 1102 // Public accessors for fields infallibly (`=>`) converted to a type. 1103 ( 1104 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : 1105 $hi:literal:$lo:literal $field:ident => $into_type:ty 1106 ) => { 1107 ::kernel::macros::paste!( 1108 1109 $(#[doc = $doc])* 1110 #[doc = "Returns the value of this field."] 1111 #[inline(always)] 1112 $vis fn $field(self) -> $into_type 1113 { 1114 self.[<__ $field>]().into() 1115 } 1116 1117 $(#[doc = $doc])* 1118 #[doc = "Sets this field to the given `value`."] 1119 #[inline(always)] 1120 $vis fn [<with_ $field>](self, value: $into_type) -> Self 1121 { 1122 self.[<__with_ $field>](value.into()) 1123 } 1124 1125 ); 1126 }; 1127 1128 // Public accessors for fields fallibly (`?=>`) converted to a type. 1129 ( 1130 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : 1131 $hi:tt:$lo:tt $field:ident ?=> $try_into_type:ty 1132 ) => { 1133 ::kernel::macros::paste!( 1134 1135 $(#[doc = $doc])* 1136 #[doc = "Returns the value of this field."] 1137 #[inline(always)] 1138 $vis fn $field(self) -> 1139 Result< 1140 $try_into_type, 1141 <$try_into_type as ::core::convert::TryFrom< 1142 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> 1143 >>::Error 1144 > 1145 { 1146 self.[<__ $field>]().try_into() 1147 } 1148 1149 $(#[doc = $doc])* 1150 #[doc = "Sets this field to the given `value`."] 1151 #[inline(always)] 1152 $vis fn [<with_ $field>](self, value: $try_into_type) -> Self 1153 { 1154 self.[<__with_ $field>](value.into()) 1155 } 1156 1157 ); 1158 }; 1159 1160 // Public accessors for fields not converted to a type. 1161 ( 1162 @public_field_accessors $(#[doc = $doc:expr])* $vis:vis $name:ident $storage:ty : 1163 $hi:tt:$lo:tt $field:ident 1164 ) => { 1165 ::kernel::macros::paste!( 1166 1167 $(#[doc = $doc])* 1168 #[doc = "Returns the value of this field."] 1169 #[inline(always)] 1170 $vis fn $field(self) -> 1171 ::kernel::num::Bounded<$storage, { $hi + 1 - $lo }> 1172 { 1173 self.[<__ $field>]() 1174 } 1175 1176 $(#[doc = $doc])* 1177 #[doc = "Sets this field to the compile-time constant `VALUE`."] 1178 #[inline(always)] 1179 $vis const fn [<with_const_ $field>]<const VALUE: $storage>(self) -> Self { 1180 self.[<__with_ $field>]( 1181 ::kernel::num::Bounded::<$storage, { $hi + 1 - $lo }>::new::<VALUE>() 1182 ) 1183 } 1184 1185 $(#[doc = $doc])* 1186 #[doc = "Sets this field to the given `value`."] 1187 #[inline(always)] 1188 $vis fn [<with_ $field>]<T>( 1189 self, 1190 value: T, 1191 ) -> Self 1192 where T: Into<::kernel::num::Bounded<$storage, { $hi + 1 - $lo }>>, 1193 { 1194 self.[<__with_ $field>](value.into()) 1195 } 1196 1197 $(#[doc = $doc])* 1198 #[doc = "Tries to set this field to `value`, returning an error if it is out of range."] 1199 #[inline(always)] 1200 $vis fn [<try_with_ $field>]<T>( 1201 self, 1202 value: T, 1203 ) -> ::kernel::error::Result<Self> 1204 where T: ::kernel::num::TryIntoBounded<$storage, { $hi + 1 - $lo }>, 1205 { 1206 Ok( 1207 self.[<__with_ $field>]( 1208 value.try_into_bounded().ok_or(::kernel::error::code::EOVERFLOW)? 1209 ) 1210 ) 1211 } 1212 1213 ); 1214 }; 1215 1216 // `Debug` implementation. 1217 (@debug $name:ident { $($field:ident;)* }) => { 1218 impl ::kernel::fmt::Debug for $name { 1219 fn fmt(&self, f: &mut ::kernel::fmt::Formatter<'_>) -> ::kernel::fmt::Result { 1220 f.debug_struct(stringify!($name)) 1221 .field("<raw>", &::kernel::prelude::fmt!("{:#x}", self.inner)) 1222 $( 1223 .field(stringify!($field), &self.$field()) 1224 )* 1225 .finish() 1226 } 1227 } 1228 }; 1229 } 1230