#[derive(Debug, thiserror::Error)]
#[error(
"Overflow while attempting to determine the MMIO address for register {register} at offset {offset:#x} from base address {base_address:#x}"
)]
pub struct RegisterAddressOutOfBounds {
register: &'static str,
base_address: u64,
offset: u64,
}
pub trait MemoryMappedRegister<T>: Clone + From<T> + Into<T> + Sized + std::fmt::Debug {
const ADDRESS_OFFSET: u64;
const NAME: &'static str;
fn get_mmio_address_from_base(base_address: u64) -> Result<u64, RegisterAddressOutOfBounds> {
if let Some(mmio_address) = base_address.checked_add(Self::ADDRESS_OFFSET) {
Ok(mmio_address)
} else {
Err(RegisterAddressOutOfBounds {
register: Self::NAME,
base_address,
offset: Self::ADDRESS_OFFSET,
})
}
}
fn get_mmio_address() -> u64 {
Self::ADDRESS_OFFSET
}
}
#[macro_export]
macro_rules! memory_mapped_bitfield_register {
($(#[$outer:meta])* $visibility:vis struct $struct_name:ident($reg_type:ty); $addr:expr, $reg_name:expr, impl From; $($rest:tt)*) => {
$crate::memory_mapped_bitfield_register!{
$(#[$outer])* $visibility struct $struct_name($reg_type); $addr, $reg_name, $($rest)*
}
impl From<$struct_name> for $reg_type {
fn from(register: $struct_name) -> Self {
register.0
}
}
impl From<$reg_type> for $struct_name {
fn from(value: $reg_type) -> Self {
Self(value)
}
}
};
($(#[$outer:meta])* $vis_modifier:vis struct $struct_name:ident($reg_type:ty); $addr:expr, $reg_name:expr, $($rest:tt)*) => {
bitfield::bitfield!{
$(#[$outer])*
#[doc= concat!("A [`bitfield::bitfield!`] register mapping for the register `", $reg_name, "` located at address `", stringify!($addr), "`.")]
#[derive(Copy, Clone)]
#[allow(clippy::upper_case_acronyms)]
#[allow(non_camel_case_types)]
$vis_modifier struct $struct_name($reg_type);
impl Debug;
$($rest)*
}
impl $crate::MemoryMappedRegister<$reg_type> for $struct_name {
const ADDRESS_OFFSET: u64 = $addr;
const NAME: &'static str = $reg_name;
}
};
}