1use crate::{Const, ControlNet, Design, Net, Value};
2
3#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct Memory {
20 pub depth: usize,
26 pub width: usize,
28 pub init_value: Const,
31 pub write_ports: Vec<MemoryWritePort>,
32 pub read_ports: Vec<MemoryReadPort>,
33}
34
35#[derive(Debug, Clone, PartialEq, Eq, Hash)]
39pub struct MemoryWritePort {
40 pub addr: Value,
51 pub data: Value,
53 pub mask: Value,
56 pub clock: ControlNet,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, Hash)]
61pub struct MemoryReadPort {
62 pub addr: Value,
67 pub data_len: usize,
69 pub flip_flop: Option<MemoryReadFlipFlop>,
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, Hash)]
88pub struct MemoryReadFlipFlop {
89 pub clock: ControlNet,
90 pub clear: ControlNet, pub reset: ControlNet, pub enable: ControlNet,
93 pub reset_over_enable: bool,
94
95 pub clear_value: Const,
96 pub reset_value: Const,
97 pub init_value: Const,
98
99 pub relations: Vec<MemoryPortRelation>,
111}
112
113#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
114pub enum MemoryPortRelation {
115 #[default]
116 Undefined,
119 ReadBeforeWrite,
122 Transparent,
125}
126
127impl Memory {
128 pub fn output_len(&self) -> usize {
129 self.read_ports.iter().map(|port| port.data_len).sum()
130 }
131
132 pub fn visit(&self, mut f: impl FnMut(Net)) {
133 for write_port in &self.write_ports {
134 write_port.visit(&mut f);
135 }
136 for read_port in &self.read_ports {
137 read_port.visit(&mut f);
138 }
139 }
140
141 pub fn visit_mut(&mut self, mut f: impl FnMut(&mut Net)) {
142 for write_port in &mut self.write_ports {
143 write_port.visit_mut(&mut f);
144 }
145 for read_port in &mut self.read_ports {
146 read_port.visit_mut(&mut f);
147 }
148 }
149
150 pub fn read_port_output_slice(&self, port_index: usize) -> std::ops::Range<usize> {
151 let mut start = 0;
152 for port in &self.read_ports[..port_index] {
153 start += port.data_len;
154 }
155 let port = &self.read_ports[port_index];
156 start..start + port.data_len
157 }
158}
159
160impl MemoryWritePort {
161 pub fn wide_log2(&self, memory: &Memory) -> usize {
162 if memory.width == 0 {
163 return 0;
164 }
165 (self.data.len() / memory.width).ilog2() as usize
166 }
167
168 pub fn visit(&self, mut f: impl FnMut(Net)) {
169 self.addr.visit(&mut f);
170 self.data.visit(&mut f);
171 self.mask.visit(&mut f);
172 self.clock.visit(&mut f);
173 }
174
175 pub fn visit_mut(&mut self, mut f: impl FnMut(&mut Net)) {
176 self.addr.visit_mut(&mut f);
177 self.data.visit_mut(&mut f);
178 self.mask.visit_mut(&mut f);
179 self.clock.visit_mut(&mut f);
180 }
181}
182
183impl MemoryReadPort {
184 pub fn new_asynchronous(addr: impl Into<Value>, data_len: usize) -> Self {
185 Self { addr: addr.into(), data_len, flip_flop: None }
186 }
187
188 pub fn new_clocked(addr: impl Into<Value>, data_len: usize, clock: impl Into<ControlNet>) -> Self {
189 Self {
190 addr: addr.into(),
191 data_len,
192 flip_flop: Some(MemoryReadFlipFlop {
193 clock: clock.into(),
194 clear: ControlNet::ZERO,
195 reset: ControlNet::ZERO,
196 enable: ControlNet::ONE,
197 reset_over_enable: false,
198 clear_value: Const::undef(data_len),
199 reset_value: Const::undef(data_len),
200 init_value: Const::undef(data_len),
201 relations: vec![],
202 }),
203 }
204 }
205
206 pub fn wide_log2(&self, memory: &Memory) -> usize {
207 if memory.width == 0 {
208 return 0;
209 }
210 (self.data_len / memory.width).ilog2() as usize
211 }
212
213 pub fn visit(&self, mut f: impl FnMut(Net)) {
214 self.addr.visit(&mut f);
215 if let Some(ref flip_flop) = self.flip_flop {
216 flip_flop.clock.visit(&mut f);
217 flip_flop.clear.visit(&mut f);
218 flip_flop.reset.visit(&mut f);
219 flip_flop.enable.visit(&mut f);
220 }
221 }
222
223 pub fn visit_mut(&mut self, mut f: impl FnMut(&mut Net)) {
224 self.addr.visit_mut(&mut f);
225 if let Some(ref mut flip_flop) = self.flip_flop {
226 flip_flop.clock.visit_mut(&mut f);
227 flip_flop.clear.visit_mut(&mut f);
228 flip_flop.reset.visit_mut(&mut f);
229 flip_flop.enable.visit_mut(&mut f);
230 }
231 }
232}
233
234impl MemoryReadFlipFlop {
235 pub fn with_clock(self, clock: impl Into<ControlNet>) -> Self {
236 Self { clock: clock.into(), ..self }
237 }
238
239 pub fn with_clear(self, clear: impl Into<ControlNet>) -> Self {
240 Self { clear: clear.into(), ..self }
241 }
242
243 pub fn with_clear_value(self, clear: impl Into<ControlNet>, clear_value: impl Into<Const>) -> Self {
244 Self { clear: clear.into(), clear_value: clear_value.into(), ..self }
245 }
246
247 pub fn with_reset(self, reset: impl Into<ControlNet>) -> Self {
248 Self { reset: reset.into(), reset_over_enable: false, ..self }
249 }
250
251 pub fn with_reset_value(self, reset: impl Into<ControlNet>, reset_value: impl Into<Const>) -> Self {
252 Self { reset: reset.into(), reset_over_enable: false, reset_value: reset_value.into(), ..self }
253 }
254
255 pub fn with_enable(self, enable: impl Into<ControlNet>) -> Self {
256 Self { enable: enable.into(), reset_over_enable: true, ..self }
257 }
258
259 pub fn with_init(self, value: impl Into<Const>) -> Self {
260 let value = value.into();
261 Self { clear_value: value.clone(), reset_value: value.clone(), init_value: value, ..self }
262 }
263
264 pub fn has_clock(&self) -> bool {
265 !self.clock.is_const()
266 }
267
268 pub fn has_enable(&self) -> bool {
269 !self.enable.is_always(true)
270 }
271
272 pub fn has_reset(&self) -> bool {
273 !self.reset.is_always(false)
274 }
275
276 pub fn has_reset_value(&self) -> bool {
277 !self.reset_value.is_undef()
278 }
279
280 pub fn has_clear(&self) -> bool {
281 !self.clear.is_always(false)
282 }
283
284 pub fn has_clear_value(&self) -> bool {
285 !self.clear_value.is_undef()
286 }
287
288 pub fn has_init_value(&self) -> bool {
289 !self.init_value.is_undef()
290 }
291
292 pub fn remap_reset_over_enable(&mut self, design: &Design) {
293 if self.reset_over_enable {
294 return;
295 }
296 self.reset_over_enable = true;
297 if self.reset.is_always(false) || self.enable.is_always(true) {
298 return;
299 }
300 let reset = self.reset.into_pos(design);
301 let enable = self.enable.into_pos(design);
302 self.reset = ControlNet::Pos(design.add_and(reset, enable).unwrap_net());
303 }
304
305 pub fn remap_enable_over_reset(&mut self, design: &Design) {
306 if !self.reset_over_enable {
307 return;
308 }
309 self.reset_over_enable = false;
310 if self.reset.is_always(false) || self.enable.is_always(true) {
311 return;
312 }
313 let reset = self.reset.into_pos(design);
314 let enable = self.enable.into_pos(design);
315 self.enable = ControlNet::Pos(design.add_or(reset, enable).unwrap_net());
316 }
317}