peakrdl_rust/
mem.rs

1//! Memory abstraction used to read, write, and iterate over memory entries
2
3use crate::{
4    access::{Access, Read, Write},
5    endian::Endian,
6    reg::RegInt,
7};
8use core::{
9    fmt::Debug,
10    iter::{ExactSizeIterator, FusedIterator},
11    ops::{Bound, RangeBounds},
12};
13
14/// Behaviors common to all SystemRDL memories
15pub trait Memory: Sized {
16    /// Primitive integer type used to represented a memory entry
17    type Memwidth: RegInt;
18    type Access: Access;
19    type Endian: Endian;
20
21    #[must_use]
22    fn first_entry_ptr(&self) -> *mut Self::Memwidth;
23
24    /// Number of memory entries
25    #[must_use]
26    fn num_entries(&self) -> usize;
27
28    /// Bit width of each memory entry
29    #[must_use]
30    fn width(&self) -> usize;
31
32    /// Access the memory entry at a specific index. Panics if out of bounds.
33    #[must_use]
34    fn index(&self, idx: usize) -> MemEntry<Self> {
35        if idx < self.num_entries() {
36            unsafe { MemEntry::from_ptr(self.first_entry_ptr().wrapping_add(idx)) }
37        } else {
38            panic!(
39                "Tried to index {} in a memory with only {} entries",
40                idx,
41                self.num_entries()
42            );
43        }
44    }
45
46    /// Iterate over a range of memory entries
47    #[must_use]
48    fn slice(&self, range: impl RangeBounds<usize>) -> MemEntryIter<Self> {
49        let low_idx = match range.start_bound() {
50            Bound::Included(idx) => *idx,
51            Bound::Excluded(idx) => *idx + 1,
52            Bound::Unbounded => 0,
53        };
54        let high_idx = match range.end_bound() {
55            Bound::Included(idx) => *idx,
56            Bound::Excluded(idx) => *idx - 1,
57            Bound::Unbounded => self.num_entries() - 1,
58        };
59        let num_entries = high_idx - low_idx + 1;
60        MemEntryIter {
61            next: self.index(low_idx),
62            remaining: num_entries,
63        }
64    }
65
66    /// Iterate over all memory entries
67    #[must_use]
68    fn iter(&self) -> MemEntryIter<Self> {
69        self.slice(..)
70    }
71}
72
73/// Representation of a single memory entry
74#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
75pub struct MemEntry<M: Memory> {
76    ptr: *mut M::Memwidth,
77}
78
79impl<M: Memory> MemEntry<M> {
80    /// # Safety
81    ///
82    /// The caller must guarantee that the provided address points to a
83    /// hardware memory entry of size `T` with access `A` and endianness `E`.
84    #[must_use]
85    pub const unsafe fn from_ptr(ptr: *mut M::Memwidth) -> Self {
86        Self { ptr }
87    }
88
89    #[must_use]
90    pub const fn as_ptr(&self) -> *mut M::Memwidth {
91        self.ptr
92    }
93}
94
95impl<M: Memory> MemEntry<M>
96where
97    M::Access: Read,
98{
99    /// Read the value of the hardware memory entry.
100    #[must_use]
101    pub fn read(&self) -> M::Memwidth {
102        // SAFETY: MemEntry can only be constructed through from_ptr(),
103        // which means the user has guaranteed the address points to
104        // a suitable hardware memory.
105        M::Endian::from_register_endian(unsafe { self.ptr.read_volatile() })
106    }
107}
108
109impl<M: Memory> MemEntry<M>
110where
111    M::Access: Write,
112{
113    /// Write the provided value to the hardware memory entry.
114    pub fn write(&mut self, value: M::Memwidth) {
115        // SAFETY: MemEntry can only be constructed through from_ptr(),
116        // which means the user has guaranteed the address points to
117        // a suitable hardware memory.
118        unsafe {
119            self.ptr
120                .write_volatile(M::Endian::to_register_endian(value));
121        }
122    }
123}
124
125/// Iterator over memory entries
126#[derive(Debug)]
127pub struct MemEntryIter<M: Memory> {
128    next: MemEntry<M>,
129    remaining: usize,
130}
131
132impl<M: Memory> Iterator for MemEntryIter<M> {
133    type Item = MemEntry<M>;
134
135    fn next(&mut self) -> Option<Self::Item> {
136        if self.remaining == 0 {
137            None
138        } else {
139            self.remaining -= 1;
140            let new_next = unsafe { MemEntry::from_ptr(self.next.as_ptr().wrapping_add(1)) };
141            Some(core::mem::replace(&mut self.next, new_next))
142        }
143    }
144
145    fn size_hint(&self) -> (usize, Option<usize>) {
146        (self.remaining, Some(self.remaining))
147    }
148}
149
150impl<M: Memory> DoubleEndedIterator for MemEntryIter<M> {
151    fn next_back(&mut self) -> Option<Self::Item> {
152        if self.remaining == 0 {
153            None
154        } else {
155            self.remaining -= 1;
156            unsafe {
157                Some(MemEntry::from_ptr(
158                    self.next.as_ptr().wrapping_add(self.remaining),
159                ))
160            }
161        }
162    }
163}
164
165impl<M: Memory> ExactSizeIterator for MemEntryIter<M> {}
166impl<M: Memory> FusedIterator for MemEntryIter<M> {}