ruspiro_register/
lib.rs

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