1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
/***********************************************************************************************************************
* Copyright (c) 2019 by the authors
*
* Author: André Borrmann <pspwizard@gmx.de>
* License: Apache License 2.0 / MIT
**********************************************************************************************************************/
#![doc(html_root_url = "https://docs.rs/ruspiro-register/0.5.5")]
#![no_std]
//! # RusPiRo Register
//!
//! The crate provides the definitions to conviniently work with register field values that are typically presented by
//! a set of bit fields. This crate will likely be used in other crates that specifies the actual registers and their
//! structure using macros. Examples can be found at
//! [ruspiro-mmio-register](https://crates.io/crates/ruspiro-mmio-register) and
//! [ruspiro-arch-aarch64](https://crates.io/crates/ruspiro-arch-aarch64)
use core::cmp::PartialEq;
use core::fmt;
use core::ops::{BitAnd, BitOr, Not, Shl, Shr};
mod macros;
/// This trait is used to describe the register size/length as type specifier. The trait is only implemented for the
/// internal types **u8**, **u16**, **u32** and **u64** to ensure safe register access sizes with compile time checking
pub trait RegisterType:
Copy
+ Clone
+ PartialEq
+ BitOr<Output = Self>
+ BitAnd<Output = Self>
+ Not<Output = Self>
+ Shl<Self, Output = Self>
+ Shr<Self, Output = Self>
{
}
// Internal macro to ease the assignment of the custom trait to supported register sizes
#[doc(hidden)]
macro_rules! registertype_impl {
// invoke the macro for a given type t as often as types are provided when invoking the macro
($( $t:ty ),*) => ($(
impl RegisterType for $t { }
)*)
}
// implement the type trait for specific unsigned types to enable only those register types/sizes
registertype_impl![u8, u16, u32, u64];
/// Definition of a field contained inside of a register. Each field is defined by a mask and the bit shift value
/// when constructing the field definition the stored mask is already shifted by the shift value
#[derive(Copy, Clone)]
pub struct RegisterField<T: RegisterType> {
mask: T,
shift: T,
}
/// Definition of a specific fieldvalue of a regiser. This structure allows to combine field values with bit operators
/// like ``|`` and ``&`` to build the final value that should be written to a register
#[derive(Copy, Clone)]
pub struct RegisterFieldValue<T: RegisterType> {
/// register field definition
field: RegisterField<T>,
/// register field value
value: T,
}
// Internal helper macro to implement:
// - ``RegisterField``struct for all relevant basic types
// - ``FieldValue`` struct for all relevant basic types
// - the operators for ``FieldValue``struct for all relevant basic types
#[doc(hidden)]
macro_rules! registerfield_impl {
($($t:ty),*) => ($(
impl RegisterField<$t> {
/// Create a new register field definition with the mask and the shift offset for this
/// mask. The offset is the bit offset this field begins.
#[inline]
#[allow(dead_code)]
pub const fn new(mask: $t, shift: $t) -> RegisterField<$t> {
Self {
mask,
shift,
}
}
/// retrieve the current mask of the field shifted to its correct position
#[inline]
#[allow(dead_code)]
pub fn mask(&self) -> $t {
self.mask.checked_shl(self.shift as u32).unwrap_or(0)
}
/// retrieve the current shift of the field
#[allow(dead_code)]
#[inline]
pub fn shift(&self) -> $t {
self.shift
}
}
impl fmt::Debug for RegisterField<$t> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut high_bit = self.shift;
let mut mask = self.mask;
while mask > 0 {
high_bit += 1;
mask >>= 1;
};
high_bit -= 1;
write!(f, "RegisterField {{\n Bits: [{}:{}]\n Mask: {:#b}\n}}",
high_bit, self.shift, self.mask.checked_shl(self.shift as u32).unwrap_or(0))
}
}
impl RegisterFieldValue<$t> {
/// Create a new fieldvalue based on the field definition and the value given
#[inline]
#[allow(dead_code)]
pub const fn new(field: RegisterField<$t>, value: $t) -> Self {
RegisterFieldValue {
field,
value: value & field.mask
}
}
/// Create a new fieldvalue based on the field definition and the raw value given
#[inline]
#[allow(dead_code)]
pub const fn from_raw(field: RegisterField<$t>, raw_value: $t) -> Self {
RegisterFieldValue {
field,
value: (raw_value >> field.shift) & field.mask
}
}
/// Retrieve the register field value
#[inline]
#[allow(dead_code)]
pub fn value(&self) -> $t {
self.value //>> self.field.shift()
}
/// Retrieve the register field raw value, means the value is returned in it's position
/// as it appears in the register when read with the field mask applied but not
/// shifted
#[inline]
#[allow(dead_code)]
pub fn raw_value(&self) -> $t {
self.value.checked_shl(self.field.shift as u32).unwrap_or(0)
}
/// Retrieve the field mask used with this register field. The mask is shifted to it's
/// corresponding field position
#[inline]
#[allow(dead_code)]
pub fn mask(&self) -> $t {
self.field.mask()
}
}
impl fmt::Debug for RegisterFieldValue<$t> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RegisterFieldValue")
.field("field", &self.field)
.field("value", &self.value)
.field("raw_value", &self.raw_value())
.finish()
}
}
impl PartialEq for RegisterFieldValue<$t> {
fn eq(&self, other: &Self) -> bool {
self.value() == other.value()
}
}
impl BitOr for RegisterFieldValue<$t> {
type Output = RegisterFieldValue<$t>;
#[inline]
#[allow(dead_code)]
fn bitor(self, rhs: RegisterFieldValue<$t>) -> Self {
let field = RegisterField::<$t>::new( self.field.mask() | rhs.field.mask(), 0);
RegisterFieldValue {
field,
value: (self.raw_value() | rhs.raw_value()),
}
}
}
impl BitAnd for RegisterFieldValue<$t> {
type Output = RegisterFieldValue<$t>;
#[inline]
#[allow(dead_code)]
fn bitand(self, rhs: RegisterFieldValue<$t>) -> Self {
let field = RegisterField::<$t>::new( self.field.mask() & rhs.field.mask(), 0);
RegisterFieldValue {
field,
value: (self.raw_value() & rhs.raw_value()),
}
}
}
)*);
}
registerfield_impl![u8, u16, u32, u64];