|
@@ -0,0 +1,407 @@
|
|
|
|
+//! Common definitions for all the peripheral registers.
|
|
|
|
+
|
|
|
|
+/// Read-only type state for `A` in [`Reg`].
|
|
|
|
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
|
|
+pub struct RO;
|
|
|
|
+
|
|
|
|
+/// Write-only type state for `A` in [`Reg`].
|
|
|
|
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
|
|
+pub struct WO;
|
|
|
|
+
|
|
|
|
+/// Read-write type state for `A` in [`Reg`].
|
|
|
|
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
|
|
+pub struct RW;
|
|
|
|
+
|
|
|
|
+/// Generic trait for all the peripheral registers.
|
|
|
|
+/// This trait is sealed and cannot be implemented by any external crate.
|
|
|
|
+pub trait Access: sealed::Access + Copy {}
|
|
|
|
+impl Access for RO {}
|
|
|
|
+impl Access for WO {}
|
|
|
|
+impl Access for RW {}
|
|
|
|
+
|
|
|
|
+/// Trait for readable registers.
|
|
|
|
+pub trait Read: Access {}
|
|
|
|
+impl Read for RO {}
|
|
|
|
+impl Read for RW {}
|
|
|
|
+
|
|
|
|
+/// Trait for writable registers.
|
|
|
|
+pub trait Write: Access {}
|
|
|
|
+impl Write for WO {}
|
|
|
|
+impl Write for RW {}
|
|
|
|
+
|
|
|
|
+/// Generic register structure. `T` refers to the data type of the register.
|
|
|
|
+/// Alternatively, `A` corresponds to the access level (e.g., read-only, read-write...).
|
|
|
|
+///
|
|
|
|
+/// # Note
|
|
|
|
+///
|
|
|
|
+/// This structure assumes that it points to a valid peripheral register.
|
|
|
|
+/// If so, it is safe to read from or write to the register.
|
|
|
|
+/// However, keep in mind that read-modify-write operations may lead to **wrong** behavior.
|
|
|
|
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
|
|
+#[repr(transparent)]
|
|
|
|
+pub struct Reg<T: Copy, A: Access> {
|
|
|
|
+ ptr: *mut T,
|
|
|
|
+ phantom: core::marker::PhantomData<A>,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+unsafe impl<T: Copy + Send, A: Access> Send for Reg<T, A> {}
|
|
|
|
+unsafe impl<T: Copy + Sync, A: Access> Sync for Reg<T, A> {}
|
|
|
|
+
|
|
|
|
+impl<T: Copy, A: Access> Reg<T, A> {
|
|
|
|
+ /// Creates a new register from a pointer.
|
|
|
|
+ ///
|
|
|
|
+ /// # Safety
|
|
|
|
+ ///
|
|
|
|
+ /// The pointer must be valid and must be correctly aligned.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub const unsafe fn new(ptr: *mut T) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ ptr,
|
|
|
|
+ phantom: core::marker::PhantomData,
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Returns a pointer to the register.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub const fn get_ptr(self) -> *mut T {
|
|
|
|
+ self.ptr
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Copy, A: Read> Reg<T, A> {
|
|
|
|
+ /// Performs a volatile read of the peripheral register with no side effects.
|
|
|
|
+ ///
|
|
|
|
+ /// # Note
|
|
|
|
+ ///
|
|
|
|
+ /// If you want to perform a read-modify-write operation, use [`Reg::modify`] instead.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn read(self) -> T {
|
|
|
|
+ // SAFETY: valid address and register is readable
|
|
|
|
+ unsafe { self.ptr.read_volatile() }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Copy, A: Write> Reg<T, A> {
|
|
|
|
+ /// Performs a volatile write of the peripheral register.
|
|
|
|
+ ///
|
|
|
|
+ /// # Note
|
|
|
|
+ ///
|
|
|
|
+ /// If you want to perform a read-modify-write operation, use [`Reg::modify`] instead.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn write(self, val: T) {
|
|
|
|
+ // SAFETY: valid address and register is writable
|
|
|
|
+ unsafe { self.ptr.write_volatile(val) }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl<T: Copy, A: Read + Write> Reg<T, A> {
|
|
|
|
+ /// It modifies the value of the register according to a given function `f`.
|
|
|
|
+ /// After writing the new value to the register, it returns the value returned by `f`.
|
|
|
|
+ ///
|
|
|
|
+ /// # Note
|
|
|
|
+ ///
|
|
|
|
+ /// It performs a non-atomic read-modify-write operation, which may lead to **wrong** behavior.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn modify<R>(self, f: impl FnOnce(&mut T) -> R) -> R {
|
|
|
|
+ let mut val = self.read();
|
|
|
|
+ let res = f(&mut val);
|
|
|
|
+ self.write(val);
|
|
|
|
+ res
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/// Macro to provide bit-wise operations to integer number registers.
|
|
|
|
+macro_rules! bitwise_reg {
|
|
|
|
+ ($TYPE: ty) => {
|
|
|
|
+ impl<A: Read> Reg<$TYPE, A> {
|
|
|
|
+ /// Reads the `n`th bit of the register.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn read_bit(self, n: usize) -> bool {
|
|
|
|
+ let mask = 1 << n;
|
|
|
|
+ let val = self.read();
|
|
|
|
+ val & mask == mask
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Reads a range of bits of the register specified by the `start` and `end` indexes, both included.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn read_bits(self, start: usize, end: usize) -> $TYPE {
|
|
|
|
+ let n_bits = end - start + 1;
|
|
|
|
+ let mask = ((1 << n_bits) - 1) << start;
|
|
|
|
+ let val = self.read();
|
|
|
|
+ (val & mask) >> start
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ impl<A: Read + Write> Reg<$TYPE, A> {
|
|
|
|
+ /// Clears the `n`th bit of the register.
|
|
|
|
+ ///
|
|
|
|
+ /// # Note
|
|
|
|
+ ///
|
|
|
|
+ /// It performs a non-atomic read-modify-write operation, which may lead to **wrong** behavior.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn clear_bit(self, n: usize) {
|
|
|
|
+ self.modify(|val| *val &= !(1 << n));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Sets the nth bit of the register.
|
|
|
|
+ ///
|
|
|
|
+ /// # Note
|
|
|
|
+ ///
|
|
|
|
+ /// It performs a non-atomic read-modify-write operation, which may lead to **wrong** behavior.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn set_bit(self, n: usize) {
|
|
|
|
+ self.modify(|val| *val |= 1 << n);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Writes a range of bits of the register specified by the `start` and `end` indexes, both included.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub fn write_bits(self, start: usize, end: usize, val: $TYPE) {
|
|
|
|
+ let n_bits = end - start + 1;
|
|
|
|
+ let mask = ((1 << n_bits) - 1) << start;
|
|
|
|
+ self.modify(|v| *v = (*v & !mask) | ((val << start) & mask));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+bitwise_reg!(u8);
|
|
|
|
+bitwise_reg!(u16);
|
|
|
|
+bitwise_reg!(u32);
|
|
|
|
+bitwise_reg!(u64);
|
|
|
|
+bitwise_reg!(u128);
|
|
|
|
+bitwise_reg!(usize);
|
|
|
|
+bitwise_reg!(i8);
|
|
|
|
+bitwise_reg!(i16);
|
|
|
|
+bitwise_reg!(i32);
|
|
|
|
+bitwise_reg!(i64);
|
|
|
|
+bitwise_reg!(i128);
|
|
|
|
+bitwise_reg!(isize);
|
|
|
|
+
|
|
|
|
+/// Macro to provide atomic bit-wise operations to integer number registers.
|
|
|
|
+macro_rules! bitwise_atomic_reg {
|
|
|
|
+ ($TYPE: ty, $ATOMIC: ty) => {
|
|
|
|
+ impl<A: Read + Write> Reg<$TYPE, A> {
|
|
|
|
+ /// Creates a new atomic reference to the register.
|
|
|
|
+ ///
|
|
|
|
+ /// # Safety
|
|
|
|
+ ///
|
|
|
|
+ /// * Register must be properly aligned **for atomic operations**.
|
|
|
|
+ /// * The register must not be accessed through non-atomic operations for the whole lifetime `'a`.
|
|
|
|
+ pub unsafe fn as_atomic<'a>(&self) -> &'a $ATOMIC {
|
|
|
|
+ // SAFETY: guaranteed by the caller
|
|
|
|
+ unsafe { &*self.ptr.cast() }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Clears the `n`th bit of the register atomically.
|
|
|
|
+ ///
|
|
|
|
+ /// # Safety
|
|
|
|
+ ///
|
|
|
|
+ /// * Register must be properly aligned **for atomic operations**.
|
|
|
|
+ /// * The register must not be accessed through non-atomic operations until this function returns.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub unsafe fn atomic_clear_bit(&self, n: usize, order: core::sync::atomic::Ordering) {
|
|
|
|
+ // SAFETY: guaranteed by the caller
|
|
|
|
+ unsafe { self.as_atomic() }.fetch_and(!(1 << n), order);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Sets the `n`th bit of the register atomically.
|
|
|
|
+ ///
|
|
|
|
+ /// # Safety
|
|
|
|
+ ///
|
|
|
|
+ /// * Register must be properly aligned **for atomic operations**.
|
|
|
|
+ /// * The register must not be accessed through non-atomic operations until this function returns.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub unsafe fn atomic_set_bit(&self, n: usize, order: core::sync::atomic::Ordering) {
|
|
|
|
+ // SAFETY: guaranteed by the caller
|
|
|
|
+ unsafe { self.as_atomic() }.fetch_or(1 << n, order);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#[cfg(target_has_atomic = "8")]
|
|
|
|
+bitwise_atomic_reg!(u8, core::sync::atomic::AtomicU8);
|
|
|
|
+#[cfg(target_has_atomic = "16")]
|
|
|
|
+bitwise_atomic_reg!(u16, core::sync::atomic::AtomicU16);
|
|
|
|
+#[cfg(target_has_atomic = "32")]
|
|
|
|
+bitwise_atomic_reg!(u32, core::sync::atomic::AtomicU32);
|
|
|
|
+#[cfg(target_has_atomic = "64")]
|
|
|
|
+bitwise_atomic_reg!(u64, core::sync::atomic::AtomicU64);
|
|
|
|
+#[cfg(target_has_atomic = "ptr")]
|
|
|
|
+bitwise_atomic_reg!(usize, core::sync::atomic::AtomicUsize);
|
|
|
|
+#[cfg(target_has_atomic = "8")]
|
|
|
|
+bitwise_atomic_reg!(i8, core::sync::atomic::AtomicI8);
|
|
|
|
+#[cfg(target_has_atomic = "16")]
|
|
|
|
+bitwise_atomic_reg!(i16, core::sync::atomic::AtomicI16);
|
|
|
|
+#[cfg(target_has_atomic = "32")]
|
|
|
|
+bitwise_atomic_reg!(i32, core::sync::atomic::AtomicI32);
|
|
|
|
+#[cfg(target_has_atomic = "64")]
|
|
|
|
+bitwise_atomic_reg!(i64, core::sync::atomic::AtomicI64);
|
|
|
|
+#[cfg(target_has_atomic = "ptr")]
|
|
|
|
+bitwise_atomic_reg!(isize, core::sync::atomic::AtomicIsize);
|
|
|
|
+
|
|
|
|
+/// Macro to define the archetypal behavior of registers.
|
|
|
|
+macro_rules! peripheral {
|
|
|
|
+ ($REGISTER: ident, $TYPE: ty, $ACCESS: ident) => {
|
|
|
|
+ /// Peripheral register.
|
|
|
|
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
|
|
+ #[repr(transparent)]
|
|
|
|
+ pub struct $REGISTER {
|
|
|
|
+ register: $crate::common::Reg<$TYPE, $crate::common::$ACCESS>,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ impl $REGISTER {
|
|
|
|
+ /// Creates a new register from an address.
|
|
|
|
+ ///
|
|
|
|
+ /// # Safety
|
|
|
|
+ ///
|
|
|
|
+ /// The address assigned must be valid and must be correctly aligned.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub const unsafe fn new(address: usize) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ register: $crate::common::Reg::new(address as _),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ ($REGISTER: ident, $TYPE: ty, $ACCESS: ident, $GENERIC: ident) => {
|
|
|
|
+ /// Peripheral register.
|
|
|
|
+ #[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
|
|
|
+ #[repr(transparent)]
|
|
|
|
+ pub struct $REGISTER<$GENERIC> {
|
|
|
|
+ register: $crate::common::Reg<$TYPE, $crate::common::$ACCESS>,
|
|
|
|
+ _marker: core::marker::PhantomData<$GENERIC>,
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ impl<$GENERIC> $REGISTER<$GENERIC> {
|
|
|
|
+ /// Creates a new register from an address.
|
|
|
|
+ ///
|
|
|
|
+ /// # Safety
|
|
|
|
+ ///
|
|
|
|
+ /// The address assigned must be valid and must be correctly aligned.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub const unsafe fn new(address: usize) -> Self {
|
|
|
|
+ Self {
|
|
|
|
+ register: $crate::common::Reg::new(address as _),
|
|
|
|
+ _marker: core::marker::PhantomData,
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/// Macro to define the archetypal behavior of *safe* registers.
|
|
|
|
+/// You must specify the register name, its data type, and its access level.
|
|
|
|
+///
|
|
|
|
+/// # Note
|
|
|
|
+///
|
|
|
|
+/// Safe peripheral registers implement [`core::ops::Deref`] to [`Reg`].
|
|
|
|
+/// You can safely use the dereferenced [`Reg::read`], [`Reg::write`], and/or [`Reg::modify`] methods.
|
|
|
|
+macro_rules! safe_peripheral {
|
|
|
|
+ ($REGISTER: ident, $TYPE: ty, $ACCESS: ident) => {
|
|
|
|
+ $crate::common::peripheral!($REGISTER, $TYPE, $ACCESS);
|
|
|
|
+
|
|
|
|
+ impl $REGISTER {
|
|
|
|
+ /// Returns the underlying raw register.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub const fn get_register(self) -> $crate::common::Reg<$TYPE, $crate::common::$ACCESS> {
|
|
|
|
+ self.register
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ impl core::ops::Deref for $REGISTER {
|
|
|
|
+ type Target = $crate::common::Reg<$TYPE, $crate::common::$ACCESS>;
|
|
|
|
+
|
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
|
+ &self.register
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ ($REGISTER: ident, $TYPE: ty, $ACCESS: ident, $GENERIC: ident) => {
|
|
|
|
+ $crate::common::peripheral!($REGISTER, $TYPE, $ACCESS, $GENERIC);
|
|
|
|
+
|
|
|
|
+ impl $REGISTER {
|
|
|
|
+ /// Returns the underlying raw register.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub const fn get_register(self) -> $crate::common::Reg<$TYPE, $crate::common::$ACCESS> {
|
|
|
|
+ self.register
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ impl<$GENERIC> core::ops::Deref for $REGISTER<$GENERIC> {
|
|
|
|
+ type Target = $crate::common::Reg<$TYPE, $crate::common::$ACCESS>;
|
|
|
|
+
|
|
|
|
+ fn deref(&self) -> &Self::Target {
|
|
|
|
+ &self.register
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/// Macro to define the archetypal behavior of *unsafe* registers.
|
|
|
|
+/// You must specify the register name, its data type, and its access level.
|
|
|
|
+///
|
|
|
|
+/// # Note
|
|
|
|
+///
|
|
|
|
+/// Unsafe peripheral registers need special care when reading and/or writing.
|
|
|
|
+/// They usually provide additional methods to perform safe (or unsafe) operations.
|
|
|
|
+/// Nevertheless, you can still access the underlying register using the `unsafe get_register(self)` method.
|
|
|
|
+macro_rules! unsafe_peripheral {
|
|
|
|
+ ($REGISTER: ident, $TYPE: ty, $ACCESS: ident) => {
|
|
|
|
+ $crate::common::peripheral!($REGISTER, $TYPE, $ACCESS);
|
|
|
|
+
|
|
|
|
+ impl $REGISTER {
|
|
|
|
+ /// Returns a raw pointer to the register.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub const fn get_ptr(self) -> *mut $TYPE {
|
|
|
|
+ self.register.get_ptr()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Returns the underlying raw register.
|
|
|
|
+ ///
|
|
|
|
+ /// # Safety
|
|
|
|
+ ///
|
|
|
|
+ /// This register is not supposed to be used directly.
|
|
|
|
+ /// Use the other provided methods instead. Otherwise, use this method at your own risk.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub const unsafe fn get_register(
|
|
|
|
+ self,
|
|
|
|
+ ) -> $crate::common::Reg<$TYPE, $crate::common::$ACCESS> {
|
|
|
|
+ self.register
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ ($REGISTER: ident, $TYPE: ty, $ACCESS: ident, $GENERIC: ident) => {
|
|
|
|
+ $crate::common::peripheral!($REGISTER, $TYPE, $ACCESS, $GENERIC);
|
|
|
|
+
|
|
|
|
+ impl<$GENERIC> $REGISTER<$GENERIC> {
|
|
|
|
+ /// Returns a raw pointer to the register.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub const fn get_ptr(self) -> *mut $TYPE {
|
|
|
|
+ self.register.get_ptr()
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// Returns the underlying register.
|
|
|
|
+ ///
|
|
|
|
+ /// # Safety
|
|
|
|
+ ///
|
|
|
|
+ /// This register is not supposed to be used directly.
|
|
|
|
+ /// Use the other provided methods instead. Otherwise, use this method at your own risk.
|
|
|
|
+ #[inline]
|
|
|
|
+ pub const unsafe fn get_register(
|
|
|
|
+ self,
|
|
|
|
+ ) -> $crate::common::Reg<$TYPE, $crate::common::$ACCESS> {
|
|
|
|
+ self.register
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+pub(crate) use {peripheral, safe_peripheral, unsafe_peripheral};
|
|
|
|
+
|
|
|
|
+mod sealed {
|
|
|
|
+ use super::*;
|
|
|
|
+ pub trait Access {}
|
|
|
|
+ impl Access for RO {}
|
|
|
|
+ impl Access for WO {}
|
|
|
|
+ impl Access for RW {}
|
|
|
|
+}
|