Skip to main content

gwr_models/registers/
state.rs

1// Copyright (c) 2023 Graphcore Ltd. All rights reserved.
2
3//! Underlying state of a register
4
5/// Specify priority for pending updates to define which one wins.
6#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
7pub enum UpdatePriority {
8    Low = 0,
9    High,
10}
11
12/// The [`RegisterState`] trait defines what functionality the underlying state
13/// provides.
14pub trait RegisterState<T> {
15    /// Write respecting permissions.
16    ///
17    /// **Note:** The actual state update will not take effect until
18    /// [`resolve`](gwr_engine::traits::Resolve) has been called.
19    fn write(&self, priority: UpdatePriority, perms: &T, value: u64) -> u64;
20
21    /// Set underlying value without checking permissions.
22    ///
23    /// **Note:** The actual state update will not take effect until
24    /// [`resolve`](gwr_engine::traits::Resolve) has been called.
25    fn set(&self, priority: UpdatePriority, perms: &T, value: u64);
26
27    /// Read and respect permissions.
28    fn read(&self, perms: &T) -> u64;
29
30    /// Return underlying value.
31    fn value(&self) -> u64;
32
33    /// Perform a synchronous reset.
34    ///
35    /// **Note:** The actual state update will not take effect until
36    /// [`resolve`](gwr_engine::traits::Resolve) has been called.
37    fn reset_sync(&self);
38
39    /// Perform an asynchronous reset.
40    fn reset_async(&self);
41}
42
43#[macro_export]
44macro_rules! build_register_state {
45    (
46        $(#[$($reg_attrs:tt)*])*
47        $reg:ident, $reg_num_bits:expr ;
48        $(
49            $(#[$($field_attrs:tt)*])*
50            $field:ident : $num_bits:expr, $reset:expr
51        ),+ $(,)*
52    ) => {
53    $crate::registers::paste! {
54    #[doc=concat!("Structure used to define the permissions of the  ", stringify!($reg), " register.")]
55    pub struct [< $reg StatePerms >] {
56        $(
57        #[doc=concat!("Permissions for the value for the ", stringify!($field), " field.")]
58        pub $field: $crate::registers::Permission,
59        )+
60    }
61
62    #[derive(Clone)]
63    #[doc=concat!("The underlying state for the ", stringify!($reg), " register.")]
64    pub struct [< $reg State >] {
65        $(
66        $(#[$($field_attrs)*])*
67        #[doc=concat!("(", stringify!($num_bits), " bits, ", stringify!($reset), " at reset).")]
68        pub $field: $crate::registers::field::Field,
69        )+
70
71        #[doc=concat!("The value of the ", stringify!($reg), " register.")]
72        register_value: std::cell::RefCell<u64>,
73
74        #[doc=concat!("A bitmask of the existing bits in the ", stringify!($reg), " register.")]
75        existing_bits_mask: u64,
76
77        pending: std::cell::RefCell<Vec<(UpdatePriority, u64)>>,
78    }
79
80    $(#[$($reg_attrs)*])*
81    impl [< $reg State >] {
82        #[must_use] pub fn new() -> Self {
83            let start_bit = 0;
84            $(
85            let $field = $crate::registers::field::Field::new($num_bits, start_bit, $reset);
86            let start_bit = $field.last_bit() + 1;
87            )+
88            let mask = if start_bit >= $reg_num_bits { !0 } else { (1 << start_bit) - 1 };
89            let state = Self {
90                register_value: std::cell::RefCell::new(0),
91                $( $field, )+
92                existing_bits_mask: mask,
93                pending: std::cell::RefCell::new(Vec::new()),
94            };
95            state.reset_async();
96            state
97        }
98    }
99
100    impl RegisterState< [< $reg StatePerms >] > for [< $reg State >] {
101        /// Returns the value that will be written to the register by the `resolve()` call
102        ///
103        /// Registers itself with the [`Resolver`]
104        fn write(&self, priority: $crate::registers::state::UpdatePriority, perms: &[< $reg StatePerms >], value: u64) -> u64 {
105            let mask = self.existing_bits_mask;
106            $(
107            let mask = self.$field.apply_write_permissions(mask, &perms.$field);
108            )+
109
110            let value = (*self.register_value.borrow() & !mask) | (value & mask);
111            self.pending.borrow_mut().push((priority, value));
112
113            value
114        }
115
116        fn set(&self, priority: $crate::registers::state::UpdatePriority, perms: &[< $reg StatePerms >], value: u64) {
117            let value = value & self.existing_bits_mask;
118            $(
119            let value = self.$field.apply_set_permissions(value, &perms.$field);
120            )+
121            self.pending.borrow_mut().push((priority, value));
122        }
123
124        fn read(&self, perms: &[< $reg StatePerms >]) -> u64 {
125            let value = *self.register_value.borrow();
126            $(
127            let value = self.$field.apply_read_permissions(value, &perms.$field);
128            )+
129            value
130        }
131
132        fn value(&self) -> u64 {
133            *self.register_value.borrow()
134        }
135
136        fn reset_sync(&self) {
137            let value = 0;
138            $(
139            let value = self.$field.apply_reset_value(value);
140            )+
141            self.pending.borrow_mut().push(($crate::registers::state::UpdatePriority::High, value));
142        }
143
144        fn reset_async(&self) {
145            let value = 0;
146            $(
147            let value = self.$field.apply_reset_value(value);
148            )+
149            *self.register_value.borrow_mut() = value;
150        }
151    }
152
153    impl Resolve for [< $reg State >] {
154        fn resolve(&self) {
155            // If there are multiple writers then resolve will be called more than once.
156            if !self.pending.borrow().is_empty() {
157                // No need to do anything if already resolved.
158                *self.register_value.borrow_mut() = self.pending.borrow().iter().reduce(|max, x| x.max(max)).unwrap().1;
159                self.pending.borrow_mut().clear();
160            }
161        }
162    }
163
164    impl Default for [< $reg State >] {
165        fn default() -> Self {
166            Self::new()
167        }
168    }
169
170    }}
171}
172
173/// Allow the creation of compile-time arrays of state up to 8 elements long
174/// without needing the `Copy` trait to be implemented.
175///
176/// Derived from: <https://danielkeep.github.io/tlborm/book/pat-push-down-accumulation.html>
177#[macro_export]
178macro_rules! array {
179    (@accum (0, $($_es:expr),*) -> ($($body:tt)*))
180        => {$crate::array!(@as_expr [$($body)*])};
181    (@accum (1, $($es:expr),*) -> ($($body:tt)*))
182        => {$crate::array!(@accum (0, $($es),*) -> ($($body)* $($es,)*))};
183    (@accum (2, $($es:expr),*) -> ($($body:tt)*))
184        => {$crate::array!(@accum (0, $($es),*) -> ($($body)* $($es,)* $($es,)*))};
185    (@accum (3, $($es:expr),*) -> ($($body:tt)*))
186        => {$crate::array!(@accum (2, $($es),*) -> ($($body)* $($es,)*))};
187    (@accum (4, $($es:expr),*) -> ($($body:tt)*))
188        => {$crate::array!(@accum (2, $($es,)* $($es),*) -> ($($body)*))};
189    (@accum (5, $($es:expr),*) -> ($($body:tt)*))
190        => {$crate::array!(@accum (4, $($es),*) -> ($($body)* $($es,)*))};
191    (@accum (6, $($es:expr),*) -> ($($body:tt)*))
192        => {$crate::array!(@accum (4, $($es),*) -> ($($body)* $($es,)* $($es,)*))};
193    (@accum (7, $($es:expr),*) -> ($($body:tt)*))
194        => {$crate::array!(@accum (4, $($es),*) -> ($($body)* $($es,)* $($es,)* $($es,)*))};
195    (@accum (8, $($es:expr),*) -> ($($body:tt)*))
196        => {$crate::array!(@accum (4, $($es,)* $($es),*) -> ($($body)*))};
197
198    (@as_expr $e:expr) => {$e};
199
200    [$e:expr; $n:tt] => { $crate::array!(@accum ($n, $e) -> ()) };
201}
202
203#[macro_export]
204macro_rules! build_register_states {
205    (
206        $(#[$($rf_attrs:tt)*])*
207        $state_name:ident ;
208        $(
209            $state:ident, $num:expr
210        ),+ $(,)*
211    ) => {
212    $crate::registers::paste! {
213        $(#[$($rf_attrs)*])*
214        pub struct $state_name {
215            $( pub [< $state:lower >] : [ std::rc::Rc< [< $state State >] > ; $num ], )+
216        }
217
218        impl $state_name {
219            #[must_use] pub fn new() -> Self {
220                $(
221                let [< $state:lower >] = $crate::array![ std::rc::Rc::new([< $state State >]::new()) ; $num ];
222                )+
223                Self {
224                    $( [< $state:lower >], )+
225                }
226            }
227        }
228
229        impl Default for $state_name {
230            fn default() -> Self {
231                Self::new()
232            }
233        }
234    }}
235}