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}