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}