prjunnamed_netlist/cell/
memory.rs

1use crate::{Const, ControlNet, Design, Net, Value};
2
3/// An all-in-one random-access memory cell.
4///
5/// A memory is made of `depth` rows, each of them `width` bits wide.  While a memory row
6/// is considered to be the basic access unit, we support the notion of "wide ports",
7/// which access a (naturally aligned) power-of-two number of memory rows at once.
8///
9/// While any number and combination of read and write ports is considered valid in
10/// the netlist, the rules for what memories can actually be realized in hardware depend
11/// on the target, and can be quite byzantine.
12///
13/// There are no priority rules among write ports.  If more than one port writes to the same
14/// memory bit at the same time, the value written is undefined.
15///
16/// The output of the memory cell consists of the read data from all the read ports,
17/// concatenated in order.
18#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct Memory {
20    /// The number of rows in the memory.
21    ///
22    /// For every port on the memory, `depth` must be evenly divisible
23    /// by `port.data_len / memory.width`.  This ensures that, for wide ports, every access
24    /// is either completely in-bounds, or completely out-of-bounds.
25    pub depth: usize,
26    /// The width of single memory row.
27    pub width: usize,
28    /// Initial value for the memory, with all the rows concatenated in order.
29    /// Must have a length equal to `depth * width`.
30    pub init_value: Const,
31    pub write_ports: Vec<MemoryWritePort>,
32    pub read_ports: Vec<MemoryReadPort>,
33}
34
35/// A synchronous memory write port.
36///
37/// Asynchronous memory write ports are not currently supported.
38#[derive(Debug, Clone, PartialEq, Eq, Hash)]
39pub struct MemoryWritePort {
40    /// The write address, selecting which row(s) to write.  The address is always counted
41    /// in units of the port's data width.  Thus, if the port width is equal to the memory
42    /// width, the address is equal to the row index.  However, for wide ports,
43    /// the address is implicitly shifted left by `log2(port.data.len() / memory.width)` bits
44    /// to obtain the first row index.
45    ///
46    /// The address can have any width.  If the address is too short to address all
47    /// memory rows, so be it — higher rows will be unreachable by this port.
48    ///
49    /// Writes to out-of-bounds addresses do not modify the memory.
50    pub addr: Value,
51    /// The write data.  The width must be a power-of-two multiple of the memory width.
52    pub data: Value,
53    /// The write mask.  Must have the same width as `data`.  On every active clock edge,
54    /// a `1` enables writing to the memory for the given data bit, `0` prevents writing.
55    pub mask: Value,
56    pub clock: ControlNet,
57}
58
59/// A memory read port, either synchronous or asynchronous.
60#[derive(Debug, Clone, PartialEq, Eq, Hash)]
61pub struct MemoryReadPort {
62    /// The read address, selecting which row(s) to read.  Follows the same rules as
63    /// [`MemoryWritePort`] address.
64    ///
65    /// Reading an out-of-bounds address results in an undefined value.
66    pub addr: Value,
67    /// The width of the read data.  Must be a power-of-two multiple of the memory width.
68    pub data_len: usize,
69    /// A flip-flop-like structure describing the synchronous read port, or `None` for asynchronous
70    /// read ports.  If this is `None`, the read port continuously reads the memory row(s) selected
71    /// by the `addr` value and outputs that as the read data.
72    pub flip_flop: Option<MemoryReadFlipFlop>,
73}
74
75/// A structure describing a synchronous read port's control signals and behavior.
76///
77/// The behavior of a synchronous read port is mostly the same as an asynchronous read port
78/// feeding a flip-flop with the controls described in this structure.  However, synchronous
79/// read ports have special behavior when a read coincides with a write to the same memory
80/// row.  This behavior is selected by the `relations` field.
81///
82/// The fields other than `relations` have the same meaning as the corresponding fields in
83/// the [`FlipFlop`] structure.  The width of the reset, clear, and init values must be equal to
84/// the `data_len` of the port.
85///
86/// [`FlipFlop`]: crate::FlipFlop
87#[derive(Debug, Clone, PartialEq, Eq, Hash)]
88pub struct MemoryReadFlipFlop {
89    pub clock: ControlNet,
90    pub clear: ControlNet, // async reset
91    pub reset: ControlNet, // sync reset
92    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    /// The behavior of this read port during a simultaneous write by a given write port.
100    ///
101    /// Each entry in this vector describes the behavior of this read port in relation to a write
102    /// port with the same index in the `write_ports` vector of the containing memory.
103    ///
104    /// Only ports sharing the same `clock` net can have defined relations — this vector must contain
105    /// `MemoryPortRelation::Undefined` for every write port where `write_port.clock != read_port.clock`.
106    ///
107    /// If a given memory bit is simultanously written by more than one write port while being
108    /// read, the read data is undefined (as is the value written to memory), regardless of
109    /// the relations between the ports.
110    pub relations: Vec<MemoryPortRelation>,
111}
112
113#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
114pub enum MemoryPortRelation {
115    #[default]
116    /// When the same memory bit is written by the given write port while being read,
117    /// the read value is undefined.
118    Undefined,
119    /// When the same memory bit is written by the given write port while being read,
120    /// the read value is the value of the memory bit before the write.
121    ReadBeforeWrite,
122    /// When the same memory bit is written by the given write port while being read,
123    /// the read value is the newly written value.
124    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}