[![crates.io](https://img.shields.io/crates/d/register.svg)](https://crates.io/crates/register) [![crates.io](https://img.shields.io/crates/v/register.svg)](https://crates.io/crates/register) # register-rs Unified interface for type-safe MMIO and CPU register access in Rust. ## Outline - [Usage](#usage) - [Defining MMIO registers](#defining-mmio-registers) - [The Deref pattern for drivers](#the-deref-pattern-for-drivers) - [Defining CPU registers](#defining-cpu-registers) - [License](#license) - [Contribution](#contribution) ## Usage This crate uses the tock-register-interface, please refer to their [Readme](https://github.com/tock/tock/tree/master/libraries/tock-register-interface) for the whole API. Make sure to check the `register_structs!` explanation, especially the fact that you must [explicitly annotate gaps]. [explicitly annotate gaps]: https://github.com/tock/tock/tree/master/libraries/tock-register-interface#defining-registers ### Defining MMIO registers ```rust use register::{mmio::*, register_bitfields, register_structs}; register_bitfields! { u32, GPFSEL1 [ FSEL14 OFFSET(12) NUMBITS(3) [ Input = 0b000, Output = 0b001, TXD0 = 0b100 ], FSEL15 OFFSET(15) NUMBITS(3) [ Input = 0b000, Output = 0b001, RXD0 = 0b100 ] ] } register_structs! { #[allow(non_snake_case)] pub RegisterBlock { (0x000 => GPFSEL1: ReadWrite), (0x004 => SYSTMR_HI: ReadOnly), (0x008 => @END), } } fn main() { let regs = 0x1337_0000 as *const RegisterBlock; unsafe { (*regs).SYSTMR_HI.get() }; } ``` #### The Deref pattern for drivers The `MMIO` part of this crate can and will often be used for implementing device drivers. In this case, you might find the `Deref pattern` useful for referencing your registers. It alleviates you from manually dereferencing each time a register access is due, and also encapsulates the `unsafe` keyword. Here is an example (extending the code snippet from above): ```rust register_bitfields! { u32, // omitted } register_structs! { #[allow(non_snake_case)] pub RegisterBlock { // omitted } } pub struct DeviceDriver { base_addr: usize, } impl ops::Deref for DeviceDriver { type Target = RegisterBlock; fn deref(&self) -> &Self::Target { unsafe { &*self.ptr() } } } impl DeviceDriver { pub fn new(base_addr: usize) -> Self { DeviceDriver { base_addr } } /// Returns a pointer to the register block fn ptr(&self) -> *const RegisterBlock { self.base_addr as *const _ } fn do_something(&self) -> u32 { self.GPFSEL1.set(0x1337); self.SYSTMR_HI.get() } } ``` ### Defining CPU registers For CPU registers, you only need to implement the respective read/write trait. All other methods are provided by default. ```rust #![feature(llvm_asm)] use register::{cpu::RegisterReadWrite, register_bitfields}; register_bitfields! {u32, pub CNTP_CTL_EL0 [ /// Enables the timer. ENABLE OFFSET(0) NUMBITS(1) [], /// Timer interrupt mask bit. IMASK OFFSET(1) NUMBITS(1) [], /// The status of the timer. ISTATUS OFFSET(2) NUMBITS(1) [] ] } struct Reg; impl RegisterReadWrite for Reg { /// Reads the raw bits of the CPU register. #[inline(always)] fn get(&self) -> u32 { let reg; unsafe { llvm_asm!("mrs $0, CNTP_CTL_EL0" : "=r"(reg) ::: "volatile"); } reg } /// Writes raw bits to the CPU register. #[inline(always)] fn set(&self, value: u32) { unsafe { llvm_asm!("msr CNTP_CTL_EL0, $0" :: "r"(value) :: "volatile"); } } } static CNTP_CTL_EL0: Reg = Reg {}; fn main() { CNTP_CTL_EL0.modify(CNTP_CTL_EL0::ENABLE::SET + CNTP_CTL_EL0::IMASK::SET); } ``` ## Testing In order to use this crate in `custom_test_frameworks` environments, please set the `no_std_unit_tests` feature flag in your dependency section. Otherwise, you might encounter errors like the following: ```console error[E0463]: can't find crate for `test` --> src/bsp/driver/bcm/bcm2xxx_gpio.rs:52:1 | 52 | / register_structs! { 53 | | #[allow(non_snake_case)] 54 | | RegisterBlock { 55 | | (0x00 => GPFSEL0: ReadWrite), ... | 66 | | } 67 | | } | |_^ can't find crate | = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info) error: aborting due to previous error ``` ## License Licensed under either of - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - MIT License ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.