cameleon_impl/
memory.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5#![allow(clippy::upper_case_acronyms)]
6
7pub use cameleon_impl_macros::{memory, register_map};
8
9use thiserror::Error;
10
11pub type MemoryResult<T> = std::result::Result<T, MemoryError>;
12
13#[derive(Debug, Error)]
14pub enum MemoryError {
15    #[error("attempt to read unreadable address")]
16    AddressNotReadable,
17
18    #[error("attempt to write to unwritable address")]
19    AddressNotWritable,
20
21    #[error("attempt to access non-existent memory location")]
22    InvalidAddress,
23
24    #[error("invalid register data: {0}")]
25    InvalidRegisterData(std::borrow::Cow<'static, str>),
26}
27
28pub mod prelude {
29    pub use super::{MemoryRead, MemoryWrite, Register};
30}
31
32pub trait MemoryRead {
33    fn read_raw(&self, range: std::ops::Range<usize>) -> MemoryResult<&[u8]>;
34
35    fn access_right<T: Register>(&self) -> AccessRight;
36
37    /// Read data from the register.
38    /// Since the host side know nothing about `Register`, this method can be called only from the machine side so access rights are temporarily set to `RW`.
39    fn read<T: Register>(&self) -> MemoryResult<T::Ty>;
40}
41
42pub trait MemoryWrite {
43    fn write_raw(&mut self, addr: usize, buf: &[u8]) -> MemoryResult<()>;
44
45    /// Write data to the register.
46    /// Since the host side know nothing about `Register`, this method can be called only from the machine side so access rights are temporarily set to `RW`.
47    fn write<T: Register>(&mut self, data: T::Ty) -> MemoryResult<()>;
48
49    fn set_access_right<T: Register>(&mut self, access_right: AccessRight);
50
51    fn register_observer<T, U>(&mut self, observer: U)
52    where
53        T: Register,
54        U: MemoryObserver + 'static;
55}
56
57pub trait MemoryObserver: Send {
58    fn update(&self);
59}
60
61/// Represent access right of each memory cell.
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum AccessRight {
64    /// Not Available.
65    NA,
66    /// Read Only.
67    RO,
68    /// Write Only.
69    WO,
70    /// Read Write.
71    RW,
72}
73
74impl AccessRight {
75    #[must_use]
76    pub const fn is_readable(self) -> bool {
77        self.as_num() & 0b1 == 1
78    }
79
80    #[must_use]
81    pub const fn is_writable(self) -> bool {
82        self.as_num() >> 1_i32 == 1
83    }
84
85    #[must_use]
86    pub const fn as_str(self) -> &'static str {
87        match self {
88            Self::NA => "NA",
89            Self::RO => "RO",
90            Self::WO => "WO",
91            Self::RW => "RW",
92        }
93    }
94
95    #[doc(hidden)]
96    #[must_use]
97    pub const fn as_num(self) -> u8 {
98        match self {
99            Self::NA => 0b00,
100            Self::RO => 0b01,
101            Self::WO => 0b10,
102            Self::RW => 0b11,
103        }
104    }
105
106    #[doc(hidden)]
107    #[must_use]
108    pub fn meet(self, rhs: Self) -> Self {
109        use AccessRight::{NA, RO, RW, WO};
110        match self {
111            RW => {
112                if rhs == RW {
113                    RW
114                } else {
115                    rhs
116                }
117            }
118            RO => {
119                if rhs.is_readable() {
120                    self
121                } else {
122                    NA
123                }
124            }
125            WO => {
126                if rhs.is_writable() {
127                    self
128                } else {
129                    NA
130                }
131            }
132            NA => NA,
133        }
134    }
135
136    #[doc(hidden)]
137    #[must_use]
138    pub fn from_num(num: u8) -> Self {
139        debug_assert!(num >> 2_i32 == 0);
140        match num {
141            0b00 => Self::NA,
142            0b01 => Self::RO,
143            0b10 => Self::WO,
144            0b11 => Self::RW,
145            _ => unreachable!(),
146        }
147    }
148}
149
150#[doc(hidden)]
151pub struct MemoryProtection {
152    inner: Vec<u8>,
153    memory_size: usize,
154}
155
156impl MemoryProtection {
157    #[must_use]
158    pub fn new(memory_size: usize) -> Self {
159        let len = if memory_size == 0 {
160            0
161        } else {
162            (memory_size - 1) / 4 + 1
163        };
164        let inner = vec![0; len];
165        Self { inner, memory_size }
166    }
167
168    pub fn set_access_right(&mut self, address: usize, access_right: AccessRight) {
169        let block = &mut self.inner[address / 4];
170        let offset = address % 4 * 2;
171        let mask = !(0b11 << offset);
172        *block = (*block & mask) | access_right.as_num() << offset;
173    }
174
175    #[must_use]
176    pub fn access_right(&self, address: usize) -> AccessRight {
177        let block = self.inner[address / 4];
178        let offset = address % 4 * 2;
179        AccessRight::from_num(block >> offset & 0b11)
180    }
181
182    pub fn access_right_with_range(&self, range: impl IntoIterator<Item = usize>) -> AccessRight {
183        range
184            .into_iter()
185            .fold(AccessRight::RW, |acc, i| acc.meet(self.access_right(i)))
186    }
187
188    pub fn set_access_right_with_range(
189        &mut self,
190        range: impl IntoIterator<Item = usize>,
191        access_right: AccessRight,
192    ) {
193        range
194            .into_iter()
195            .for_each(|i| self.set_access_right(i, access_right));
196    }
197
198    pub fn verify_address(&self, address: usize) -> MemoryResult<()> {
199        if self.memory_size <= address {
200            Err(MemoryError::InvalidAddress)
201        } else {
202            Ok(())
203        }
204    }
205
206    pub fn verify_address_with_range(
207        &self,
208        range: impl IntoIterator<Item = usize>,
209    ) -> MemoryResult<()> {
210        for i in range {
211            self.verify_address(i)?;
212        }
213        Ok(())
214    }
215}
216
217pub trait Register {
218    type Ty;
219
220    const ADDRESS: usize;
221    const LENGTH: usize;
222    const ACCESS_RIGHT: AccessRight;
223
224    fn parse(data: &[u8]) -> MemoryResult<Self::Ty>;
225    fn serialize(data: Self::Ty) -> MemoryResult<Vec<u8>>;
226
227    fn write(data: Self::Ty, memory: &mut [u8]) -> MemoryResult<()> {
228        let data = Self::serialize(data)?;
229        let range = Self::range();
230
231        memory[range].copy_from_slice(data.as_slice());
232        Ok(())
233    }
234
235    fn read(memory: &[u8]) -> MemoryResult<Self::Ty> {
236        let range = Self::range();
237        Self::parse(&memory[range])
238    }
239
240    #[must_use]
241    fn range() -> std::ops::Range<usize> {
242        Self::ADDRESS..Self::ADDRESS + Self::LENGTH
243    }
244}
245
246#[cfg(test)]
247mod tests {
248    use super::AccessRight::{NA, RO, RW, WO};
249    use super::*;
250
251    #[test]
252    fn test_protection() {
253        // [RO, RW, NA, WO, RO];
254        let mut protection = MemoryProtection::new(5);
255        protection.set_access_right(0, RO);
256        protection.set_access_right(1, RW);
257        protection.set_access_right(2, NA);
258        protection.set_access_right(3, WO);
259        protection.set_access_right(4, RO);
260
261        assert_eq!(protection.inner.len(), 2);
262        assert_eq!(protection.access_right(0), RO);
263        assert_eq!(protection.access_right(1), RW);
264        assert_eq!(protection.access_right(2), NA);
265        assert_eq!(protection.access_right(3), WO);
266        assert_eq!(protection.access_right(4), RO);
267
268        assert_eq!(protection.access_right_with_range(0..2), RO);
269        assert_eq!(protection.access_right_with_range(2..4), NA);
270        assert_eq!(protection.access_right_with_range(3..5), NA);
271    }
272
273    #[test]
274    fn test_verify_address() {
275        let protection = MemoryProtection::new(5);
276        assert!(protection.verify_address(0).is_ok());
277        assert!(protection.verify_address(4).is_ok());
278        assert!(protection.verify_address(5).is_err());
279        assert!(protection.verify_address_with_range(2..5).is_ok());
280        assert!(protection.verify_address_with_range(2..6).is_err());
281    }
282}