Skip to main content

gwr_models/registers/
mod.rs

1// Copyright (c) 2023 Graphcore Ltd. All rights reserved.
2
3//! Control and Status Registers builders.
4
5pub mod field;
6pub mod regfile;
7pub mod register;
8pub mod state;
9
10pub mod test_helpers;
11
12#[doc(hidden)]
13pub use paste::paste;
14
15/// Register access permissions
16pub enum Permission {
17    /// Writes ignored. Reads return constant value.
18    ReadOnly,
19
20    /// Writes ignored. Reads return current value of dynamic state.
21    ReadVolatileOnly,
22
23    /// Writes value committed to state. Reads return last value written, or
24    /// reset value if not written yet.
25    ReadWrite,
26
27    /// Writes value committed to state. Reads return current value of dynamic
28    /// state.
29    ReadVolatileWrite,
30
31    /// Writes value committed to state. Reads return 0.
32    WriteCommits,
33
34    /// Writes of `0b1` initiate background operation. Reads return 0.
35    WriteOneCommits,
36
37    /// Writes value commited to state. Reads not possible. There is no
38    /// mechanism available to directly read this state. It may be possible
39    /// to read the state indirectly.
40    WriteOnly,
41
42    /// All writes ignored. Reads return 0.
43    WriteIgnore,
44
45    /// Writes ignored. Reads return 0.
46    Reserved,
47}
48
49#[cfg(test)]
50pub mod tests {
51    use std::cell::RefCell;
52    use std::rc::Rc;
53
54    use gwr_engine::traits::Resolve;
55
56    use super::register::{Read, Register, Written};
57    use super::state::{RegisterState, UpdatePriority};
58    use crate::registers::test_helpers::TestResolver;
59    use crate::{
60        build_register_file, build_register_state, build_register_states, build_register_view,
61    };
62
63    pub struct TestCallbackHandler {
64        pub written_count: RefCell<usize>,
65        pub read_count: RefCell<usize>,
66        pub last_write: RefCell<Option<(u64, u64, u64)>>,
67    }
68
69    impl TestCallbackHandler {
70        #[must_use]
71        pub fn new() -> Self {
72            Self {
73                written_count: RefCell::new(0),
74                read_count: RefCell::new(0),
75                last_write: RefCell::new(None),
76            }
77        }
78    }
79
80    impl Default for TestCallbackHandler {
81        fn default() -> Self {
82            Self::new()
83        }
84    }
85
86    impl Written for TestCallbackHandler {
87        fn written(&self, old_value: u64, value_written: u64, new_value: u64) {
88            *self.written_count.borrow_mut() += 1;
89            *self.last_write.borrow_mut() = Some((old_value, value_written, new_value));
90        }
91    }
92
93    impl Read for TestCallbackHandler {
94        fn read(&self, _value_read: u64) {
95            *self.read_count.borrow_mut() += 1;
96        }
97    }
98
99    // Reset values of different field types.
100    pub const CSR_RESET_VALUE: u64 = 0x0000_cc01;
101    // ReadVolatileOnly fields can't be changed by a write.
102    pub const CSR_WRITE_VALUE: u64 = 0x0000_ccff;
103    // ReadVolatileOnly can be changed by a set.
104    pub const CSR_SET_VALUE: u64 = 0x00ff_ccff;
105
106    // An underlying register state.
107    build_register_state!(
108        /// The Control Status Register Example (multiple views)
109        Csr, 32 ;
110        /// A per-thread `enable` bit
111        enabled: 8, 0x1,
112        /// Reserved
113        reserved: 8, 0xcc,
114        /// A per-thread `excepted` bit
115        excepted: 8, 0,
116        /// A single trigger bit
117        trigger: 1, 0,
118    );
119
120    // A set of test states.
121    build_register_states!(
122        /// All register state
123        TestCsrStates ; Csr, 1,
124    );
125
126    // A ReadWrite register view.
127    build_register_view!(
128        /// Read-only view of the Control Status Register.
129        CsrRw, CsrState, CsrStatePerms, High ;
130        /// The `enable` field is Read-only in this view
131        enabled: ReadWrite,
132        /// Reserved
133        reserved: Reserved,
134        /// The `excepted` field is Read-only in this view.
135        excepted: ReadVolatileOnly,
136        /// Trigger
137        trigger: WriteOneCommits,
138    );
139
140    // A ReadOnly register view.
141    build_register_view!(
142        /// Read-only view of the Control Status Register.
143        CsrRo, CsrState, CsrStatePerms, High ;
144        /// The `enable` field is Read-only in this view
145        enabled: ReadOnly,
146        /// Reserved
147        reserved: Reserved,
148        /// The `excepted` field is Read-only in this view.
149        excepted: ReadVolatileOnly,
150        /// Trigger
151        trigger: ReadOnly,
152    );
153
154    // A test register file with ReadWrite view.
155    build_register_file!(
156        /// Test Register File
157        TestCsrsRw, TestCsrStates ;
158        Csr : 0x00, CsrRw, Csr,
159    );
160
161    // A test register file with ReadOnly view.
162    build_register_file!(
163        /// Test Register File
164        TestCsrsRo, TestCsrStates ;
165        Csr : 0x10, CsrRo, Csr,
166    );
167
168    #[test]
169    fn basics() {
170        let resolver = TestResolver::new();
171        let csr_state = Rc::new(CsrState::new());
172
173        let csr_ro = CsrRoReg::new(csr_state.clone());
174        let csr_rw = CsrRwReg::new(csr_state);
175
176        assert_eq!(csr_ro.read(), CSR_RESET_VALUE);
177        assert_eq!(csr_rw.read(), CSR_RESET_VALUE);
178
179        csr_ro.write(&resolver, 0xffff_ffff);
180        resolver.resolve();
181        assert_eq!(csr_ro.read(), CSR_RESET_VALUE);
182        assert_eq!(csr_rw.read(), CSR_RESET_VALUE);
183
184        csr_rw.write(&resolver, 0xffff_ffff);
185        resolver.resolve();
186        assert_eq!(csr_ro.read(), CSR_WRITE_VALUE);
187        assert_eq!(csr_rw.read(), CSR_WRITE_VALUE);
188    }
189
190    #[test]
191    fn reset() {
192        let resolver = TestResolver::new();
193        let csr_state = Rc::new(CsrState::new());
194        let csr_rw = CsrRwReg::new(csr_state);
195
196        csr_rw.write(&resolver, 0xffff);
197        assert_eq!(csr_rw.value(), CSR_RESET_VALUE);
198        resolver.resolve();
199        assert_eq!(csr_rw.value(), CSR_WRITE_VALUE);
200
201        // Test the sync reset
202        csr_rw.reset_sync(&resolver);
203        assert_eq!(csr_rw.value(), CSR_WRITE_VALUE);
204
205        resolver.resolve();
206        assert_eq!(csr_rw.value(), CSR_RESET_VALUE);
207
208        // Test the async reset
209        csr_rw.write(&resolver, 0xffff);
210        resolver.resolve();
211        assert_eq!(csr_rw.value(), CSR_WRITE_VALUE);
212
213        csr_rw.reset_async();
214        assert_eq!(csr_rw.value(), CSR_RESET_VALUE);
215    }
216
217    #[test]
218    fn reg_file() {
219        let resolver = TestResolver::new();
220        let csr_states = TestCsrStates::new();
221        let csrs = TestCsrsRwRegs::new(&csr_states, 0);
222        assert_eq!(csrs.csr.value(), CSR_RESET_VALUE);
223
224        csrs.csr.write(&resolver, 0xffff);
225        assert_eq!(csrs.csr.value(), CSR_RESET_VALUE);
226
227        resolver.resolve();
228        assert_eq!(csrs.csr.value(), CSR_WRITE_VALUE);
229
230        csrs.reset_sync(&resolver);
231        assert_eq!(csrs.csr.value(), CSR_WRITE_VALUE);
232
233        resolver.resolve();
234        assert_eq!(csrs.csr.value(), CSR_RESET_VALUE);
235    }
236
237    #[test]
238    fn reg_file_by_index() {
239        const CSR_RW_INDEX: u64 = testcsrsrw_indices::CSR;
240        const CSR_RO_INDEX: u64 = testcsrsro_indices::CSR;
241
242        let resolver = TestResolver::new();
243        let csr_states = TestCsrStates::new();
244        let csrs_rw = TestCsrsRwRegs::new(&csr_states, 0);
245        let csrs_ro = TestCsrsRoRegs::new(&csr_states, 0);
246        assert_eq!(csrs_rw.csr.value(), CSR_RESET_VALUE);
247
248        csrs_rw.write(&resolver, testcsrsrw_indices::CSR, 0xffff);
249        assert_eq!(csrs_rw.csr.value(), CSR_RESET_VALUE);
250
251        resolver.resolve();
252        assert_eq!(csrs_rw.csr.value(), CSR_WRITE_VALUE);
253        assert_eq!(csrs_rw.read(CSR_RW_INDEX), CSR_WRITE_VALUE);
254        assert_eq!(csrs_ro.read(CSR_RO_INDEX), CSR_WRITE_VALUE);
255    }
256
257    #[test]
258    fn reserved_stays_on_set() {
259        let resolver = TestResolver::new();
260        let state = Rc::new(CsrState::new());
261        let reg = CsrRwReg::new(state);
262
263        assert_eq!(reg.value(), CSR_RESET_VALUE);
264
265        reg.set(&resolver, 0xffff_ffff);
266        assert_eq!(reg.value(), CSR_RESET_VALUE);
267
268        resolver.resolve();
269        assert_eq!(reg.value(), CSR_SET_VALUE);
270    }
271
272    #[test]
273    fn alias() {
274        let resolver = TestResolver::new();
275        let state = Rc::new(TestCsrStates::new());
276        let regs_ro = TestCsrsRoRegs::new(&state, 0);
277        let regs_rw = TestCsrsRwRegs::new(&state, 0);
278
279        assert_eq!(regs_ro.csr.value(), CSR_RESET_VALUE);
280        assert_eq!(regs_rw.csr.value(), CSR_RESET_VALUE);
281
282        regs_ro.csr.write(&resolver, 0xffff_ffff);
283        resolver.resolve();
284        assert_eq!(regs_ro.csr.value(), CSR_RESET_VALUE);
285        assert_eq!(regs_rw.csr.value(), CSR_RESET_VALUE);
286
287        regs_rw.csr.write(&resolver, 0xffff_ffff);
288        assert_eq!(regs_ro.csr.value(), CSR_RESET_VALUE);
289        assert_eq!(regs_rw.csr.value(), CSR_RESET_VALUE);
290
291        resolver.resolve();
292        assert_eq!(regs_ro.csr.value(), CSR_WRITE_VALUE);
293        assert_eq!(regs_rw.csr.value(), CSR_WRITE_VALUE);
294
295        regs_ro.reset_sync(&resolver);
296        assert_eq!(regs_ro.csr.value(), CSR_WRITE_VALUE);
297        assert_eq!(regs_rw.csr.value(), CSR_WRITE_VALUE);
298
299        resolver.resolve();
300        assert_eq!(regs_ro.csr.value(), CSR_RESET_VALUE);
301        assert_eq!(regs_rw.csr.value(), CSR_RESET_VALUE);
302    }
303
304    #[test]
305    fn write_callback() {
306        let resolver = TestResolver::new();
307        let state = Rc::new(CsrState::new());
308        let mut reg: CsrRwReg = CsrRwReg::new(state);
309
310        let cb_handler = Rc::new(TestCallbackHandler::new());
311        reg.install_read_cb(cb_handler.clone());
312        reg.install_write_cb(cb_handler.clone());
313
314        reg.write(&resolver, 0xffff_ffff);
315        resolver.resolve();
316
317        assert_eq!(*cb_handler.read_count.borrow(), 0);
318        assert_eq!(*cb_handler.written_count.borrow(), 1);
319    }
320
321    #[test]
322    fn read_callback() {
323        let state = Rc::new(CsrState::new());
324        let mut reg = CsrRwReg::new(state);
325
326        let cb_handler = Rc::new(TestCallbackHandler::new());
327        reg.install_read_cb(cb_handler.clone());
328        reg.install_write_cb(cb_handler.clone());
329
330        let _ = reg.read();
331        assert_eq!(*cb_handler.read_count.borrow(), 1);
332        assert_eq!(*cb_handler.written_count.borrow(), 0);
333    }
334
335    #[test]
336    fn write_one_commit() {
337        // Ensure that the `WriteOneCommit` field doesn't get changed, but that a
338        // callback handler would see the value written to act on it.
339        let resolver = TestResolver::new();
340        let state = Rc::new(CsrState::new());
341        let mut reg: CsrRwReg = CsrRwReg::new(state);
342
343        let cb_handler = Rc::new(TestCallbackHandler::new());
344        reg.install_read_cb(cb_handler.clone());
345        reg.install_write_cb(cb_handler.clone());
346
347        reg.write(&resolver, 0xffff_ffff);
348        resolver.resolve();
349
350        assert_eq!(*cb_handler.read_count.borrow(), 0);
351        assert_eq!(*cb_handler.written_count.borrow(), 1);
352
353        assert_eq!(reg.read(), CSR_WRITE_VALUE);
354
355        let (old_value, written_value, new_value) = cb_handler.last_write.borrow().unwrap();
356
357        assert_eq!(old_value, CSR_RESET_VALUE);
358        assert_eq!(written_value, 0xffff_ffff);
359        assert_eq!(new_value, CSR_WRITE_VALUE);
360    }
361}