Crate ral[][src]

Library providing basis for low level registers access This crate re-exports macros refined in ral-macro, so this is the only library needed to be defined in dependencies

Code generator

Refer to ral-gen crate documentation for code generation guidelines

DSL and produced result

Internally generates register description backed by ral

use ral::register;

register! {
    use crate_name::types::CustomType; // Use expressions for custom types used in field declarations

    #[access = "read-write"] // Optional register wide access specifier
    #[doc = "Register description"] // Optional register description
    reg0 { // Register name
        offset: 0x8, // Register offset in enclosing peripheral
        value_size: 32, // Register size, expected values are 8, 16, 32 or 64
        reset_mask: 0xFFFFFFFF, // Reset mask
        reset_value: 0x0, // Reset value
        fields: { // Optional fields
            #[doc = "Bits 16:31 - Read-only u16 field"] // Each field can have a description
            #[access = "read-only"] // Access specifier
            field5[16:16] as u16, // Field specification `<name>[<offset>:<width>] as <type>`

            #[doc = "Bits 14:15 - Write-only field"]
            #[access = "write-only"] // Only setters will be generated
            field4[14:2] as u8, // Default supported types are `u8`, `u16`, `u32` and `u64`

            #[doc = "Bits 11:13 - Read-only field"]
            #[access = "read-only"] // Only getters will be generated
            field3[11:3] as u8,

            #[doc = "Bit 10 - Boolean field"]
            #[access = "read-write"] // `read-write` is a default access specifier
            field2[10:1] as bool, // `bool` fields are also supported by default

            #[doc = "Bits 8:9 - Enum field"]
            #[access = "read-write"] // Both getters and setters will be generated
            field1[8:2] as CustomType, // Custom types are supported with limitations

            #[doc = "Bits 0:7 - Read-write by default long field"]
            field0[0:8] as u8
        }
    }
}

Above register definition will be transformed into following code

// Required uses section
use core::sync::atomic::AtomicPtr;
use core::convert::TryFrom;
use ral::{borrow_register, init_register, return_register, value_read, value_write, R, ReadableRegister, Register, VolatileCell, WritableRegister};
use crate_name::types::CustomType;
const REGISTER: AtomicPtr<VolatileCell<<Reg0 as Register>::ValueType>> = AtomicPtr::new(
    (super::BASE_ADDRESS /* Enclosing peripheral/cluster base address */ + 0x00 /* offset */) as *mut VolatileCell<<Reg0 as Register>::ValueType>,
);
///Register description
pub fn reg0() -> Option<Reg0> {
    borrow_register(&REGISTER).map(Reg0)
}
pub struct Reg0(R<u32, Reg0>);
impl Drop for Reg0 {
    fn drop(&mut self) {
        let Reg0(register) = self;
        return_register(&REGISTER, register);
    }
}
impl Register for Reg0 {
    type RegisterType = Self;
    type ValueType = u32;
    const RESET_MASK: Self::ValueType = 0xFFFF_FFFF;
    const RESET_VALUE: Self::ValueType = 0x1234_0000;
}
impl ReadableRegister for Reg0 { // Will be added if register wide access allows read
    fn get_bits(&self) -> Self::ValueType {
        self.0.get_bits()
    }

    fn read(&mut self) -> &mut Self::RegisterType {
        self.0.read();
        self
    }
}
impl WritableRegister for Reg0 { // Will be added if register wide access allows write
    fn set_bits(&mut self, bits: Self::ValueType) -> &mut Self::RegisterType {
        self.0.set_bits(bits);
        self
    }
    fn reset(&mut self) -> &mut Self::RegisterType {
        self.set_bits(Self::RESET_VALUE)
    }
    fn write(&mut self) -> &mut Self::RegisterType {
        self.0.write();
        self
    }
}
impl Reg0 { // Will be added if any fields specified
    ///Bits 16:31 - Read-only u16 field
    #[inline]
    pub fn get_field5(&self) -> u16 {
        value_read!(self, 0x0000FFFFu32, 16) as u16
        // Will further expand into
        // ((self.0.get_bits() >> 16) & 0x0000FFFFu32) as u16
    }
    ///Bits 14:15 - Write-only field
    #[inline]
    pub fn set_field4(&mut self, value: u8) -> &mut Self {
        value_write!(self, 0x00000003u32, 14, value as <Self as Register>::ValueType);
        // Will further expand into
        // self.0.set_bits(
        //     (self.0.get_bits() & !(0x00000003u32 << 14))
        //         | ((value as <Self as Register>::ValueType & 0x00000003u32) << 14),
        // );
        self
    }
    ///Bits 11:13 - Read-only field
    #[inline]
    pub fn get_field3(&self) -> u8 {
        value_read!(self, 0x00000007u32, 11) as u8
        // Will further expand into
        // ((self.0.get_bits() >> 11) & 0x00000007u32) as u8
    }
    ///Bit 10 - Boolean field
    #[inline]
    pub fn is_field2_set(&self) -> bool {
        value_read!(self, 0x00000001u32, 10) == 1
        // Will further expand into
        // ((self.0.get_bits() >> 10) & 0x00000001u32) == 1
    }
    ///Bit 10 - Boolean field
    #[inline]
    pub fn set_field2_value(&mut self, value: bool) -> &mut Self {
        value_write!(self, 0x00000001u32, 10, value as <Self as Register>::ValueType);
        // Will further expand into
        // self.0.set_bits(
        //     (self.0.get_bits() & !(0x00000001u32 << 10))
        //         | ((value as <Self as Register>::ValueType & 0x00000001u32) << 10),
        // );
        self
    }
    ///Bit 10 - Boolean field
    #[inline]
    pub fn set_field2(&mut self) -> &mut Self {
        self.set_field2_value(true)
    }
    ///Bit 10 - Boolean field
    #[inline]
    pub fn unset_field2(&mut self) -> &mut Self {
        self.set_field2_value(false)
    }
    ///Bits 8:9 - Enum field
    #[inline]
    pub fn get_field1(
        &self,
    ) -> Result<CustomType, <CustomType as TryFrom<<Self as Register>::ValueType>>::Error> {
        <CustomType as TryFrom<<Self as Register>::ValueType>>::try_from(value_read!(self, 0x00000003u32, 8))
        // Will further expand into
        // <CustomType as TryFrom<<Self as Register>::ValueType>>::try_from(
        //     (self.0.get_bits() >> 8) & 0x00000003u32,
        // )
    }
    ///Bits 8:9 - Enum field
    #[inline]
    pub fn set_field1(
        &mut self,
        value: CustomType,
    ) -> Result<&mut Self, <<Self as Register>::ValueType as TryFrom<CustomType>>::Error>
    {
        value_write!(self, 0x00000003u32, 8, <<Self as Register>::ValueType as TryFrom<#ty>>::try_from(value)?);
        // Will further expand into
        // self.0.set_bits(
        //     (self.0.get_bits() & !(0x00000003u32 << 8))
        //         | ((<<Self as Register>::ValueType as TryFrom<CustomType>>::try_from(value)?
        //             & 0x00000003u32) << 8),
        // );
        Ok(self)
    }
    ///Bits 0:7 - Read-write by default long field
    #[inline]
    pub fn get_field0(&self) -> u8 {
        value_read!(self, 0x000000FFu32, 0) as u8
        // Will further expand into
        // ((self.0.get_bits() >> 0) & 0x000000FFu32) as u8
    }
    ///Bits 0:7 - Read-write by default long field
    #[inline]
    pub fn set_field0(&mut self, value: u8) -> &mut Self {
        value_write!(self, 0x000000FFu32, 0, value as <Self as Register>::ValueType);
        // Will further expand into
        // self.0.set_bits(
        //     (self.0.get_bits() & !(0x000000FFu32 << 0))
        //         | ((value as <Self as Register>::ValueType & 0x000000FFu32) << 0),
        // );
        self
    }
}

Proposed modules structure

Enclosing peripheral module can look like this

#![doc = "Peripheral description"]

mod reg0;
pub use reg0::*;

const BASE_ADDRESS: usize = 0x0000_0000; // Should be actual peripheral base address

Peripherals module should look like this

pub mod peripheral;

And finally lib.rs should look like this

#![doc = "Device description"]

pub mod peripherals;

So the recommended module hierarchy is

src/
├── lib.rs
└── peripherals/
    ├── mod.rs
    └── peripheral/
        ├── mod.rs
        ├── reg0.rs
        ├── reg1.rs
        └── cluster/
            ├── mod.rs
            ├── reg2.rs
            ├── reg3.rs
            └── reg4.rs

The layout also includes optional cluster module, which can look like this

#![doc = "Cluster description"]

mod reg2;
pub use reg2::*;
mod reg3;
pub use reg3::*;
mod reg4;
pub use reg4::*;

const BASE_ADDRESS: usize = super::BASE_ADDRESS + 0x40; // Enclosing peripheral/cluster base address plus offset

Requirenments to custom types

For read access you must implement TryFrom<u32> for CustomType or From<u32> for CustomType if your register is 32-bit For write access you have to implement TryFrom<CustomType> for u32 or From<CustomType> for u32 respectively

How to use resulting library

use device_crate::peripherals::peripheral;

let mut reg0 = peripheral::reg0()
        .unwrap() // Borrow the register
        .read(); // Load current data stored in register
let field3 = reg0.get_field3(); // Read `u8` field

let field2 = reg0.is_field2_set(); // Read `bool` field
let field1: CustomType = reg0.get_field1().unwrap(); // Read field represented by `CustomType`
reg0
    .set_field0(if field2 {
        reg0.get_field5() as u8
    } else {
        0
    }) // Set `u8` field
    .unset_field2() // Unset `bool` field
    .set_field4(field3 + 10) // Set 'u8' field
    .set_field1(if field1 == Two { One } else { Three }).unwrap() // Set `CustomType` field
    .write(); // Finally write result to hardware register

Macros

init_register

Init register

register

Macro expanding into register definition and required uses

register_definition

Macro expanding into register definition, might be useful when multiple registers to be defined in the same module

register_uses

Macro expanding into required uses, might be useful when multiple registers to be defined in the same module

value_read

Extract specific bits from register value

value_write

Set specific bits to register value

Structs

R

Register data holder, abstracts interaction with actual hardware

VolatileCell

Just like Cell but with volatile read / write operations

Traits

ReadableRegister

Trait representing readable part of register, actual registers are to implement this

Register

Trait representing register, actual registers are to implement this

WritableRegister

Trait representing writable part of register, actual registers are to implement this

Functions

borrow_register

Exclusively borrows register

return_register

Releases register, so it can be borrowed again