1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
use super::*;

/// Represents an MMIO address that can be safely read, but not written.
///
/// Unlike with raw pointers, this type favors unsafe construction and then
/// assumes that all usage is safe once the value has been constructed.
///
/// The convention is that reading the address will have no side effects.
/// However, the register can be changed by non-CPU parts of the hardware, and
/// so each time you perform a read the value might have changed.
///
/// For addresses where reads have a side effect, other types are used.
#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
pub struct ReadOnlyVolAddr<T> {
  addr: NonZeroUsize,
  _marker: PhantomData<T>,
}

impl<T> ReadOnlyVolAddr<T> {
  /// Constructs a new address.
  ///
  /// ## Safety
  /// The input must
  /// * Not be 0 (or _instant_ UB).
  /// * Be an actual MMIO location for the data type specified (or
  ///   [`read`](RwVolAddr::read) will UB).
  #[must_use]
  #[inline(always)]
  pub(crate) const unsafe fn new(addr: usize) -> Self {
    Self { addr: NonZeroUsize::new_unchecked(addr), _marker: PhantomData }
  }

  /// Reads the current value at the address.
  #[must_use]
  #[inline(always)]
  pub fn read(&self) -> T
  where
    T: Copy,
  {
    unsafe { read_volatile(self.addr.get() as *const T) }
  }
}