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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
use super::*; /// Represents a simple MMIO address that can be safely read or 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 addresses using this type are "plain" addresses. /// * Reads will just get the current value (without any other side effect). /// * Writes will set a new value without changing any other memory of the /// system (though usually there's a hardware side effect). /// * If you perform a write, and then you immediately perform a read, you'll /// read back exactly whatever you just wrote (the same as with normal /// memory). /// /// For addresses where there's anything weird going on (read-only, write-only, /// read and write represent different effects, etc) then other volatile address /// types are used. #[repr(transparent)] #[derive(Debug, Clone, Copy)] pub struct SimpleVolAddr<T> { addr: NonZeroUsize, _marker: PhantomData<T>, } impl<T> SimpleVolAddr<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`](SimpleVolAddr::read) and [`write`](SimpleVolAddr::write) 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) } } /// Writes a new value to the address. #[inline(always)] pub fn write(&self, t: T) where T: Copy, { unsafe { write_volatile(self.addr.get() as *mut T, t) } } }