peakrdl_rust/
reg.rs

1//! Register abstraction used to read, write, and modify register values
2#![allow(clippy::inline_always)]
3
4use core::convert::Infallible;
5
6use crate::{
7    access::{Access, Read, Write},
8    endian::Endian,
9    io::{PtrIO, RegisterIO},
10};
11use num_traits::{
12    AsPrimitive, FromBytes, PrimInt, ToBytes, WrappingAdd, WrappingSub, identities::ConstZero,
13};
14
15/// Trait for primitive integer types accessed as registers.
16pub trait RegInt:
17    PrimInt
18    + ConstZero
19    + WrappingSub
20    + WrappingAdd
21    + FromBytes<Bytes: for<'a> TryFrom<&'a [u8], Error: core::fmt::Debug>>
22    + ToBytes<Bytes: AsRef<[u8]>>
23    + core::fmt::Debug
24    + 'static
25{
26}
27impl RegInt for u8 {}
28impl RegInt for u16 {}
29impl RegInt for u32 {}
30impl RegInt for u64 {}
31impl RegInt for u128 {}
32impl RegInt for i8 {}
33impl RegInt for i16 {}
34impl RegInt for i32 {}
35impl RegInt for i64 {}
36impl RegInt for i128 {}
37
38/// Trait implemented by all register types.
39pub trait Register: Copy {
40    // NOTE: SystemRDL guarantees accesswidth <= regwidth, and both are 2^N bits where N >= 3
41    /// Primitive integer type representing the size of the full register value.
42    type Regwidth: RegInt + AsPrimitive<Self::Accesswidth>;
43    /// Primitive integer type representing the size of memory accesses used when
44    /// reading/writing this register.
45    type Accesswidth: RegInt + AsPrimitive<Self::Regwidth>;
46    /// Access controls for this register.
47    type Access: Access;
48    /// Ordering of bytes within each accesswidth subword.
49    type ByteEndian: Endian;
50    /// Ordering of accesswidth subwords within the register.
51    type WordEndian: Endian;
52
53    /// Convert a raw bit value into a Register instance.
54    ///
55    /// # Safety
56    ///
57    /// The caller must ensure the raw bit value is valid for the given register.
58    /// For example, by reading it directly from hardware.
59    unsafe fn from_raw(val: Self::Regwidth) -> Self;
60
61    /// Convert a Register instance into its raw bit value.
62    fn to_raw(self) -> Self::Regwidth;
63}
64
65/// Register abstraction used to read, write, and modify register values.
66///
67/// This is generic over both the [`Register`] to access and the [`RegisterIO`] type
68/// used to access the register.
69///
70/// The [`Register`] trait has associated types defining the register width,
71/// access controls, and endianness which are used to customize the read/write
72/// implementation for each register.
73///
74/// [`RegisterIO`] defaults to regular volatile pointer
75/// I/O and is only needed for advanced use cases like tunneled registers.
76#[derive(Debug, PartialEq, Eq)]
77pub struct Reg<'io, R: Register, IO: RegisterIO = PtrIO> {
78    ptr: *mut R::Regwidth,
79    io: &'io IO,
80}
81
82// manually implemented to ease generic bounds (IO does not need to be Copy)
83impl<R: Register, IO: RegisterIO> Copy for Reg<'_, R, IO> where R::Regwidth: Copy {}
84
85// manually implemented to ease generic bounds (IO does not need to be Clone)
86impl<R: Register, IO: RegisterIO> Clone for Reg<'_, R, IO>
87where
88    R::Regwidth: Clone,
89{
90    fn clone(&self) -> Self {
91        *self
92    }
93}
94
95unsafe impl<R: Register, IO: RegisterIO + Sync> Send for Reg<'_, R, IO> {}
96unsafe impl<R: Register, IO: RegisterIO + Sync> Sync for Reg<'_, R, IO> {}
97
98// pointer conversion functions
99impl<R: Register> Reg<'static, R, PtrIO> {
100    /// # Safety
101    ///
102    /// The caller must guarantee that the provided address points to a
103    /// hardware register of type `R`.
104    #[inline(always)]
105    pub const unsafe fn from_ptr(ptr: *mut R::Regwidth) -> Self {
106        Self { ptr, io: &PtrIO }
107    }
108}
109
110impl<'io, R: Register, IO: RegisterIO> Reg<'io, R, IO> {
111    /// # Safety
112    ///
113    /// The caller must guarantee that the provided address points to a
114    /// hardware register of type `R`.
115    #[inline(always)]
116    pub const unsafe fn from_ptr_with(ptr: *mut R::Regwidth, io: &'io IO) -> Self {
117        Self { ptr, io }
118    }
119
120    #[inline(always)]
121    #[must_use]
122    pub const fn as_ptr(&self) -> *mut R {
123        self.ptr.cast()
124    }
125}
126
127// read access
128impl<R: Register, IO: RegisterIO> Reg<'_, R, IO>
129where
130    R::Access: Read,
131{
132    /// Try to read a register value.
133    ///
134    /// If the register is to be modified (i.e., a read-modify-write), use the
135    /// [`Reg::modify`] method instead.
136    ///
137    /// # Example
138    ///
139    /// ```ignore
140    /// let reg1_val = registers.regfile().register1().try_read().unwrap();
141    /// let field1_val = reg1_val.field1();
142    /// let field2_val = reg1_val.field2();
143    /// ```
144    #[inline(always)]
145    #[allow(clippy::missing_errors_doc)]
146    pub fn try_read(&self) -> Result<R, IO::Error> {
147        unsafe { self.io.try_read_register(self.ptr) }
148    }
149}
150
151impl<R: Register, IO: RegisterIO<Error = Infallible>> Reg<'_, R, IO>
152where
153    R::Access: Read,
154{
155    /// Read a register value.
156    ///
157    /// If the register is to be modified (i.e., a read-modify-write), use the
158    /// [`Reg::modify`] method instead.
159    ///
160    /// # Example
161    ///
162    /// ```ignore
163    /// let reg1_val = registers.regfile().register1().read();
164    /// let field1_val = reg1_val.field1();
165    /// let field2_val = reg1_val.field2();
166    /// ```
167    #[inline(always)]
168    #[allow(clippy::must_use_candidate)]
169    pub fn read(&self) -> R {
170        self.try_read().unwrap_infallible()
171    }
172}
173
174// write access
175impl<R: Register, IO: RegisterIO> Reg<'_, R, IO>
176where
177    R::Access: Write,
178{
179    /// Try to write a register value.
180    ///
181    /// Typically one would use [`Reg::try_write`] or [`Reg::try_modify`] to update a
182    /// register's contents, but this method has a few different use cases such
183    /// as updating a register with a stored value, or updating one register with
184    /// the contents of another.
185    ///
186    /// # Example
187    ///
188    /// ```ignore
189    /// # write array index 0 value to index 1
190    /// let reg0 = registers.regfile().reg_array()[0].try_read().unwrap();
191    /// registers.regfile().reg_array()[1].try_write_value(reg0).unwrap();
192    /// ```
193    #[inline(always)]
194    #[allow(clippy::missing_errors_doc)]
195    pub fn try_write_value(&self, val: R) -> Result<(), IO::Error> {
196        unsafe { self.io.try_write_register(self.ptr, val) }
197    }
198}
199
200impl<R: Register, IO: RegisterIO<Error = Infallible>> Reg<'_, R, IO>
201where
202    R::Access: Write,
203{
204    /// Write a register value.
205    ///
206    /// Typically one would use [`Reg::write`] or [`Reg::modify`] to update a
207    /// register's contents, but this method has a few different use cases such
208    /// as updating a register with a stored value, or updating one register with
209    /// the contents of another.
210    ///
211    /// # Example
212    ///
213    /// ```ignore
214    /// # write array index 0 value to index 1
215    /// let reg0 = registers.regfile().reg_array()[0].read();
216    /// registers.regfile().reg_array()[1].write_value(reg0);
217    /// ```
218    #[inline(always)]
219    pub fn write_value(&self, val: R) {
220        self.try_write_value(val).unwrap_infallible();
221    }
222}
223
224impl<R: Default + Register, IO: RegisterIO> Reg<'_, R, IO>
225where
226    R::Access: Write,
227{
228    /// Try to write a register.
229    ///
230    /// This method takes a closure. The input to the closure is a mutable reference
231    /// to the default value of the register. It can be updated in the closure. The
232    /// updated value is then written to the hardware register.
233    ///
234    /// # Example
235    ///
236    /// ```ignore
237    /// registers.regfile().register1().try_write(|r| {
238    ///     // r contains the default (reset) value of the register
239    ///     r.set_field1(0x1);
240    ///     r.set_field2(0x0);
241    /// }).unwrap();
242    /// ```
243    #[inline(always)]
244    #[allow(clippy::missing_errors_doc)]
245    pub fn try_write<T>(&self, f: impl FnOnce(&mut R) -> T) -> Result<T, IO::Error> {
246        let mut val = Default::default();
247        let res = f(&mut val);
248        self.try_write_value(val)?;
249        Ok(res)
250    }
251}
252
253impl<R: Default + Register, IO: RegisterIO<Error = Infallible>> Reg<'_, R, IO>
254where
255    R::Access: Write,
256{
257    /// Write a register.
258    ///
259    /// This method takes a closure. The input to the closure is a mutable reference
260    /// to the default value of the register. It can be updated in the closure. The
261    /// updated value is then written to the hardware register.
262    ///
263    /// # Example
264    ///
265    /// ```ignore
266    /// registers.regfile().register1().write(|r| {
267    ///     // r contains the default (reset) value of the register
268    ///     r.set_field1(0x1);
269    ///     r.set_field2(0x0);
270    /// });
271    /// ```
272    #[inline(always)]
273    pub fn write<T>(&self, f: impl FnOnce(&mut R) -> T) -> T {
274        self.try_write(f).unwrap_infallible()
275    }
276}
277
278// read/write access
279impl<R: Register, IO: RegisterIO> Reg<'_, R, IO>
280where
281    R::Access: Read + Write,
282{
283    /// Try to modify a register.
284    ///
285    /// This method takes a closure. The input to the closure is a mutable reference
286    /// to the current value of the register. It can be updated in the closure. The
287    /// updated value is then written back to the hardware register.
288    ///
289    /// # Example
290    ///
291    /// ```ignore
292    /// let orig_r = registers.regfile().register1().try_modify(|r| {
293    ///     // r contains the current value of the register
294    ///     orig_r = r.clone()
295    ///     r.set_field1(r.field1());
296    ///     r.set_field2(0x0);
297    ///     // whatever value the closure returns is returned by the .try_modify() method
298    ///     orig_r
299    /// }).unwrap();
300    /// ```
301    #[inline(always)]
302    #[allow(clippy::missing_errors_doc)]
303    pub fn try_modify<T>(&self, f: impl FnOnce(&mut R) -> T) -> Result<T, IO::Error> {
304        let mut val = self.try_read()?;
305        let res = f(&mut val);
306        self.try_write_value(val)?;
307        Ok(res)
308    }
309}
310
311impl<R: Register, IO: RegisterIO<Error = Infallible>> Reg<'_, R, IO>
312where
313    R::Access: Read + Write,
314{
315    /// Modify a register.
316    ///
317    /// This method takes a closure. The input to the closure is a mutable reference
318    /// to the current value of the register. It can be updated in the closure. The
319    /// updated value is then written back to the hardware register.
320    ///
321    /// # Example
322    ///
323    /// ```ignore
324    /// let orig_r = registers.regfile().register1().modify(|r| {
325    ///     // r contains the current value of the register
326    ///     orig_r = r.clone()
327    ///     r.set_field1(r.field1());
328    ///     r.set_field2(0x0);
329    ///     // whatever value the closure returns is returned by the .modify() method
330    ///     orig_r
331    /// });
332    /// ```
333    #[inline(always)]
334    pub fn modify<T>(&self, f: impl FnOnce(&mut R) -> T) -> T {
335        self.try_modify(f).unwrap_infallible()
336    }
337}
338
339trait UnwrapInfallible {
340    type T;
341
342    fn unwrap_infallible(self) -> Self::T;
343}
344
345impl<T> UnwrapInfallible for Result<T, Infallible> {
346    type T = T;
347
348    fn unwrap_infallible(self) -> T {
349        match self {
350            Ok(v) => v,
351            Err(e) => match e {}, // exhaustive match on uninhabited type
352        }
353    }
354}