riscv_peripheral/
common.rs

1//! Common definitions for all the peripheral registers.
2
3/// Read-only type state for `A` in [`Reg`].
4#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5pub struct RO;
6
7/// Write-only type state for `A` in [`Reg`].
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub struct WO;
10
11/// Read-write type state for `A` in [`Reg`].
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub struct RW;
14
15/// Generic trait for all the peripheral registers.
16/// This trait is sealed and cannot be implemented by any external crate.
17pub trait Access: sealed::Access + Copy {}
18impl Access for RO {}
19impl Access for WO {}
20impl Access for RW {}
21
22/// Trait for readable registers.
23pub trait Read: Access {}
24impl Read for RO {}
25impl Read for RW {}
26
27/// Trait for writable registers.
28pub trait Write: Access {}
29impl Write for WO {}
30impl Write for RW {}
31
32/// Generic register structure. `T` refers to the data type of the register.
33/// Alternatively, `A` corresponds to the access level (e.g., read-only, read-write...).
34///
35/// # Note
36///
37/// This structure assumes that it points to a valid peripheral register.
38/// If so, it is safe to read from or write to the register.
39/// However, keep in mind that read-modify-write operations may lead to **wrong** behavior.
40#[derive(Clone, Copy, Debug, Eq, PartialEq)]
41#[repr(transparent)]
42pub struct Reg<T: Copy, A: Access> {
43    ptr: *mut T,
44    phantom: core::marker::PhantomData<A>,
45}
46
47unsafe impl<T: Copy + Send, A: Access> Send for Reg<T, A> {}
48unsafe impl<T: Copy + Sync, A: Access> Sync for Reg<T, A> {}
49
50impl<T: Copy, A: Access> Reg<T, A> {
51    /// Creates a new register from a pointer.
52    ///
53    /// # Safety
54    ///
55    /// The pointer must be valid and must be correctly aligned.
56    #[inline]
57    pub const unsafe fn new(ptr: *mut T) -> Self {
58        Self {
59            ptr,
60            phantom: core::marker::PhantomData,
61        }
62    }
63
64    /// Returns a pointer to the register.
65    #[inline]
66    pub const fn get_ptr(self) -> *mut T {
67        self.ptr
68    }
69}
70
71impl<T: Copy, A: Read> Reg<T, A> {
72    /// Performs a volatile read of the peripheral register with no side effects.
73    ///
74    /// # Note
75    ///
76    /// If you want to perform a read-modify-write operation, use [`Reg::modify`] instead.
77    #[inline]
78    pub fn read(self) -> T {
79        // SAFETY: valid address and register is readable
80        unsafe { self.ptr.read_volatile() }
81    }
82}
83
84impl<T: Copy, A: Write> Reg<T, A> {
85    /// Performs a volatile write of the peripheral register.
86    ///
87    /// # Note
88    ///
89    /// If you want to perform a read-modify-write operation, use [`Reg::modify`] instead.
90    #[inline]
91    pub fn write(self, val: T) {
92        // SAFETY: valid address and register is writable
93        unsafe { self.ptr.write_volatile(val) }
94    }
95}
96
97impl<T: Copy, A: Read + Write> Reg<T, A> {
98    /// It modifies the value of the register according to a given function `f`.
99    /// After writing the new value to the register, it returns the value returned by `f`.
100    ///
101    /// # Note
102    ///
103    /// It performs a non-atomic read-modify-write operation, which may lead to **wrong** behavior.
104    #[inline]
105    pub fn modify<R>(self, f: impl FnOnce(&mut T) -> R) -> R {
106        let mut val = self.read();
107        let res = f(&mut val);
108        self.write(val);
109        res
110    }
111}
112
113/// Macro to provide bit-wise operations to integer number registers.
114macro_rules! bitwise_reg {
115    ($TYPE: ty) => {
116        impl<A: Read> Reg<$TYPE, A> {
117            /// Reads the `n`th bit of the register.
118            #[inline]
119            pub fn read_bit(self, n: usize) -> bool {
120                let mask = 1 << n;
121                let val = self.read();
122                val & mask == mask
123            }
124
125            /// Reads a range of bits of the register specified by the `start` and `end` indexes, both included.
126            #[inline]
127            pub fn read_bits(self, start: usize, end: usize) -> $TYPE {
128                let n_bits = end - start + 1;
129                let mask = ((1 << n_bits) - 1) << start;
130                let val = self.read();
131                (val & mask) >> start
132            }
133        }
134
135        impl<A: Read + Write> Reg<$TYPE, A> {
136            /// Clears the `n`th bit of the register.
137            ///
138            /// # Note
139            ///
140            /// It performs a non-atomic read-modify-write operation, which may lead to **wrong** behavior.
141            #[inline]
142            pub fn clear_bit(self, n: usize) {
143                self.modify(|val| *val &= !(1 << n));
144            }
145
146            /// Sets the nth bit of the register.
147            ///
148            /// # Note
149            ///
150            /// It performs a non-atomic read-modify-write operation, which may lead to **wrong** behavior.
151            #[inline]
152            pub fn set_bit(self, n: usize) {
153                self.modify(|val| *val |= 1 << n);
154            }
155
156            /// Writes a range of bits of the register specified by the `start` and `end` indexes, both included.
157            #[inline]
158            pub fn write_bits(self, start: usize, end: usize, val: $TYPE) {
159                let n_bits = end - start + 1;
160                let mask = ((1 << n_bits) - 1) << start;
161                self.modify(|v| *v = (*v & !mask) | ((val << start) & mask));
162            }
163        }
164    };
165}
166bitwise_reg!(u8);
167bitwise_reg!(u16);
168bitwise_reg!(u32);
169bitwise_reg!(u64);
170bitwise_reg!(u128);
171bitwise_reg!(usize);
172bitwise_reg!(i8);
173bitwise_reg!(i16);
174bitwise_reg!(i32);
175bitwise_reg!(i64);
176bitwise_reg!(i128);
177bitwise_reg!(isize);
178
179/// Macro to provide atomic bit-wise operations to integer number registers.
180#[cfg(any(
181    target_has_atomic = "8",
182    target_has_atomic = "16",
183    target_has_atomic = "32",
184    target_has_atomic = "64",
185    target_has_atomic = "ptr"
186))]
187macro_rules! bitwise_atomic_reg {
188    ($TYPE: ty, $ATOMIC: ty) => {
189        impl<A: Read + Write> Reg<$TYPE, A> {
190            /// Creates a new atomic reference to the register.
191            ///
192            /// # Safety
193            ///
194            /// * Register must be properly aligned **for atomic operations**.
195            /// * The register must not be accessed through non-atomic operations for the whole lifetime `'a`.
196            pub unsafe fn as_atomic<'a>(&self) -> &'a $ATOMIC {
197                // SAFETY: guaranteed by the caller
198                unsafe { &*self.ptr.cast() }
199            }
200
201            /// Clears the `n`th bit of the register atomically.
202            ///
203            /// # Safety
204            ///
205            /// * Register must be properly aligned **for atomic operations**.
206            /// * The register must not be accessed through non-atomic operations until this function returns.
207            #[inline]
208            pub unsafe fn atomic_clear_bit(&self, n: usize, order: core::sync::atomic::Ordering) {
209                // SAFETY: guaranteed by the caller
210                unsafe { self.as_atomic() }.fetch_and(!(1 << n), order);
211            }
212
213            /// Sets the `n`th bit of the register atomically.
214            ///
215            /// # Safety
216            ///
217            /// * Register must be properly aligned **for atomic operations**.
218            /// * The register must not be accessed through non-atomic operations until this function returns.
219            #[inline]
220            pub unsafe fn atomic_set_bit(&self, n: usize, order: core::sync::atomic::Ordering) {
221                // SAFETY: guaranteed by the caller
222                unsafe { self.as_atomic() }.fetch_or(1 << n, order);
223            }
224        }
225    };
226}
227
228#[cfg(target_has_atomic = "8")]
229bitwise_atomic_reg!(u8, core::sync::atomic::AtomicU8);
230#[cfg(target_has_atomic = "16")]
231bitwise_atomic_reg!(u16, core::sync::atomic::AtomicU16);
232#[cfg(target_has_atomic = "32")]
233bitwise_atomic_reg!(u32, core::sync::atomic::AtomicU32);
234#[cfg(target_has_atomic = "64")]
235bitwise_atomic_reg!(u64, core::sync::atomic::AtomicU64);
236#[cfg(target_has_atomic = "ptr")]
237bitwise_atomic_reg!(usize, core::sync::atomic::AtomicUsize);
238#[cfg(target_has_atomic = "8")]
239bitwise_atomic_reg!(i8, core::sync::atomic::AtomicI8);
240#[cfg(target_has_atomic = "16")]
241bitwise_atomic_reg!(i16, core::sync::atomic::AtomicI16);
242#[cfg(target_has_atomic = "32")]
243bitwise_atomic_reg!(i32, core::sync::atomic::AtomicI32);
244#[cfg(target_has_atomic = "64")]
245bitwise_atomic_reg!(i64, core::sync::atomic::AtomicI64);
246#[cfg(target_has_atomic = "ptr")]
247bitwise_atomic_reg!(isize, core::sync::atomic::AtomicIsize);
248
249/// Macro to define the archetypal behavior of registers.
250macro_rules! peripheral {
251    ($REGISTER: ident, $TYPE: ty, $ACCESS: ident) => {
252        /// Peripheral register.
253        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
254        #[repr(transparent)]
255        pub struct $REGISTER {
256            register: $crate::common::Reg<$TYPE, $crate::common::$ACCESS>,
257        }
258
259        impl $REGISTER {
260            /// Creates a new register from an address.
261            ///
262            /// # Safety
263            ///
264            /// The address assigned must be valid and must be correctly aligned.
265            #[inline]
266            pub const unsafe fn new(address: usize) -> Self {
267                Self {
268                    register: $crate::common::Reg::new(address as _),
269                }
270            }
271        }
272    };
273    ($REGISTER: ident, $TYPE: ty, $ACCESS: ident, $GENERIC: ident) => {
274        /// Peripheral register.
275        #[derive(Clone, Copy, Debug, Eq, PartialEq)]
276        #[repr(transparent)]
277        pub struct $REGISTER<$GENERIC> {
278            register: $crate::common::Reg<$TYPE, $crate::common::$ACCESS>,
279            _marker: core::marker::PhantomData<$GENERIC>,
280        }
281
282        impl<$GENERIC> $REGISTER<$GENERIC> {
283            /// Creates a new register from an address.
284            ///
285            /// # Safety
286            ///
287            /// The address assigned must be valid and must be correctly aligned.
288            #[inline]
289            pub const unsafe fn new(address: usize) -> Self {
290                Self {
291                    register: $crate::common::Reg::new(address as _),
292                    _marker: core::marker::PhantomData,
293                }
294            }
295        }
296    };
297}
298
299/// Macro to define the archetypal behavior of *safe* registers.
300/// You must specify the register name, its data type, and its access level.
301///
302/// # Note
303///
304/// Safe peripheral registers implement [`core::ops::Deref`] to [`Reg`].
305/// You can safely use the dereferenced [`Reg::read`], [`Reg::write`], and/or [`Reg::modify`] methods.
306macro_rules! safe_peripheral {
307    ($REGISTER: ident, $TYPE: ty, $ACCESS: ident) => {
308        $crate::common::peripheral!($REGISTER, $TYPE, $ACCESS);
309
310        impl $REGISTER {
311            /// Returns the underlying raw register.
312            #[inline]
313            pub const fn get_register(self) -> $crate::common::Reg<$TYPE, $crate::common::$ACCESS> {
314                self.register
315            }
316        }
317
318        impl core::ops::Deref for $REGISTER {
319            type Target = $crate::common::Reg<$TYPE, $crate::common::$ACCESS>;
320
321            fn deref(&self) -> &Self::Target {
322                &self.register
323            }
324        }
325    };
326    ($REGISTER: ident, $TYPE: ty, $ACCESS: ident, $GENERIC: ident) => {
327        $crate::common::peripheral!($REGISTER, $TYPE, $ACCESS, $GENERIC);
328
329        impl $REGISTER {
330            /// Returns the underlying raw register.
331            #[inline]
332            pub const fn get_register(self) -> $crate::common::Reg<$TYPE, $crate::common::$ACCESS> {
333                self.register
334            }
335        }
336
337        impl<$GENERIC> core::ops::Deref for $REGISTER<$GENERIC> {
338            type Target = $crate::common::Reg<$TYPE, $crate::common::$ACCESS>;
339
340            fn deref(&self) -> &Self::Target {
341                &self.register
342            }
343        }
344    };
345}
346
347/// Macro to define the archetypal behavior of *unsafe* registers.
348/// You must specify the register name, its data type, and its access level.
349///
350/// # Note
351///
352/// Unsafe peripheral registers need special care when reading and/or writing.
353/// They usually provide additional methods to perform safe (or unsafe) operations.
354/// Nevertheless, you can still access the underlying register using the `unsafe get_register(self)` method.
355macro_rules! unsafe_peripheral {
356    ($REGISTER: ident, $TYPE: ty, $ACCESS: ident) => {
357        $crate::common::peripheral!($REGISTER, $TYPE, $ACCESS);
358
359        impl $REGISTER {
360            /// Returns a raw pointer to the register.
361            #[inline]
362            pub const fn get_ptr(self) -> *mut $TYPE {
363                self.register.get_ptr()
364            }
365
366            /// Returns the underlying raw register.
367            ///
368            /// # Safety
369            ///
370            /// This register is not supposed to be used directly.
371            /// Use the other provided methods instead. Otherwise, use this method at your own risk.
372            #[inline]
373            pub const unsafe fn get_register(
374                self,
375            ) -> $crate::common::Reg<$TYPE, $crate::common::$ACCESS> {
376                self.register
377            }
378        }
379    };
380    ($REGISTER: ident, $TYPE: ty, $ACCESS: ident, $GENERIC: ident) => {
381        $crate::common::peripheral!($REGISTER, $TYPE, $ACCESS, $GENERIC);
382
383        impl<$GENERIC> $REGISTER<$GENERIC> {
384            /// Returns a raw pointer to the register.
385            #[inline]
386            pub const fn get_ptr(self) -> *mut $TYPE {
387                self.register.get_ptr()
388            }
389
390            /// Returns the underlying register.
391            ///
392            /// # Safety
393            ///
394            /// This register is not supposed to be used directly.
395            /// Use the other provided methods instead. Otherwise, use this method at your own risk.
396            #[inline]
397            pub const unsafe fn get_register(
398                self,
399            ) -> $crate::common::Reg<$TYPE, $crate::common::$ACCESS> {
400                self.register
401            }
402        }
403    };
404}
405
406pub(crate) use {peripheral, safe_peripheral, unsafe_peripheral};
407
408mod sealed {
409    use super::*;
410    pub trait Access {}
411    impl Access for RO {}
412    impl Access for WO {}
413    impl Access for RW {}
414}