Skip to main content

prjunnamed_netlist/
design.rs

1use std::fmt::Display;
2use std::ops::{Deref, Range};
3use std::cell::{Ref, RefCell};
4use std::borrow::Cow;
5use std::hash::Hash;
6use std::collections::{btree_map, BTreeMap, BTreeSet, HashMap};
7use std::rc::Rc;
8use std::sync::Arc;
9
10use crate::{MetaItem, MetaStringRef, MetaItemRef};
11use crate::{
12    cell::CellRepr, AssignCell, Cell, ControlNet, FlipFlop, Instance, IoBuffer, IoNet, IoValue, MatchCell, Memory, Net,
13    Target, TargetCell, TargetCellPurity, TargetPrototype, Trit, Value,
14};
15use crate::metadata::{MetadataStore, MetaStringIndex, MetaItemIndex};
16use crate::smt::{SmtEngine, SmtBuilder};
17
18/// Sea of [`Cell`]s.
19#[derive(Debug, Clone)]
20pub struct Design {
21    ios: BTreeMap<String, Range<u32>>,
22    cells: Vec<AnnotatedCell>,
23    changes: RefCell<ChangeQueue>,
24    metadata: RefCell<MetadataStore>,
25    target: Option<Arc<dyn Target>>,
26}
27
28#[derive(Debug, Clone, Default)]
29struct ChangeQueue {
30    next_io: u32,
31    added_ios: BTreeMap<String, Range<u32>>,
32    added_cells: Vec<AnnotatedCell>,
33    cell_cache: HashMap<AnnotatedCell, Value>,
34    cell_metadata: MetaItemIndex,
35    appended_metadata: BTreeMap<usize, Vec<MetaItemIndex>>,
36    replaced_cells: BTreeMap<usize, AnnotatedCell>,
37    unalived_cells: BTreeSet<usize>,
38    replaced_nets: BTreeMap<Net, Net>,
39}
40
41impl Design {
42    pub fn new() -> Design {
43        Self::with_target(None)
44    }
45
46    pub fn with_target(target: Option<Arc<dyn Target>>) -> Design {
47        Design {
48            ios: BTreeMap::new(),
49            cells: vec![
50                CellRepr::Const(Trit::Zero).into(),
51                CellRepr::Const(Trit::One).into(),
52                CellRepr::Const(Trit::Undef).into(),
53            ],
54            changes: RefCell::new(ChangeQueue::default()),
55            metadata: RefCell::new(MetadataStore::new()),
56            target,
57        }
58    }
59
60    pub fn add_io(&self, name: impl Into<String>, width: usize) -> IoValue {
61        let mut changes = self.changes.borrow_mut();
62        let name = name.into();
63        let width = width as u32;
64        let range = changes.next_io..(changes.next_io + width);
65        changes.next_io += width;
66        if self.ios.contains_key(&name) {
67            panic!("duplicate IO port {name}");
68        }
69        match changes.added_ios.entry(name) {
70            btree_map::Entry::Occupied(entry) => {
71                panic!("duplicate IO port {}", entry.key());
72            }
73            btree_map::Entry::Vacant(entry) => {
74                entry.insert(range.clone());
75            }
76        }
77        IoValue::from_range(range)
78    }
79
80    pub fn get_io(&self, name: impl AsRef<str>) -> Option<IoValue> {
81        self.ios.get(name.as_ref()).map(|range| IoValue::from_range(range.clone()))
82    }
83
84    pub fn find_io(&self, io_net: IoNet) -> Option<(&str, usize)> {
85        for (name, range) in self.ios.iter() {
86            if range.contains(&io_net.index) {
87                return Some((name.as_str(), (io_net.index - range.start) as usize));
88            }
89        }
90        None
91    }
92
93    pub fn iter_ios(&self) -> impl Iterator<Item = (&str, IoValue)> {
94        self.ios.iter().map(|(name, range)| (name.as_str(), IoValue::from_range(range.clone())))
95    }
96
97    pub(crate) fn add_cell_with_metadata_index(&self, cell: Cell, metadata: MetaItemIndex) -> Value {
98        cell.validate(self);
99        if let Cell::Const(v) = cell {
100            return v.into();
101        }
102        let cell_with_meta = AnnotatedCell { repr: cell.clone().into(), meta: metadata };
103        let mut changes = self.changes.borrow_mut();
104        if let Some(value) = changes.cell_cache.get(&cell_with_meta) {
105            value.clone()
106        } else {
107            let index = self.cells.len() + changes.added_cells.len();
108            let output_len = cell.output_len();
109            let output = Value::from_cell_range(index, output_len);
110            if !cell.has_effects(self) {
111                changes.cell_cache.insert(cell_with_meta.clone(), output.clone());
112            }
113            changes.added_cells.push(cell_with_meta);
114            for _ in 0..output_len.saturating_sub(1) {
115                changes.added_cells.push(CellRepr::Skip(index.try_into().expect("cell index too large")).into())
116            }
117            output
118        }
119    }
120
121    pub fn add_cell_with_metadata_ref(&self, cell: Cell, metadata: MetaItemRef) -> Value {
122        self.add_cell_with_metadata_index(cell, metadata.index())
123    }
124
125    pub fn add_cell_with_metadata(&self, cell: Cell, metadata: &MetaItem) -> Value {
126        metadata.validate();
127        let metadata = self.metadata.borrow_mut().add_item(metadata);
128        self.add_cell_with_metadata_index(cell, metadata)
129    }
130
131    pub fn use_metadata(&self, item: MetaItemRef) -> WithMetadataGuard<'_> {
132        let mut changes = self.changes.borrow_mut();
133        let guard = WithMetadataGuard { design: self, restore: changes.cell_metadata };
134        changes.cell_metadata = item.index();
135        guard
136    }
137
138    pub fn use_metadata_from(&self, cell_refs: &[CellRef]) -> WithMetadataGuard<'_> {
139        let item = MetaItemRef::from_merge(self, cell_refs.iter().map(CellRef::metadata));
140        self.use_metadata(item)
141    }
142
143    pub fn get_use_metadata(&self) -> MetaItemRef<'_> {
144        let changes = self.changes.borrow();
145        self.ref_metadata_item(changes.cell_metadata)
146    }
147
148    pub fn add_cell(&self, cell: Cell) -> Value {
149        let metadata = self.changes.borrow().cell_metadata;
150        self.add_cell_with_metadata_index(cell, metadata)
151    }
152
153    pub fn add_void(&self, width: usize) -> Value {
154        let mut changes = self.changes.borrow_mut();
155        let index = self.cells.len() + changes.added_cells.len();
156        for _ in 0..width {
157            changes.added_cells.push(CellRepr::Void.into());
158        }
159        Value::from_cell_range(index, width)
160    }
161
162    #[inline]
163    pub fn find_cell(&self, net: Net) -> (CellRef<'_>, usize) {
164        let index = net.as_cell_index();
165        match self.cells[index].repr {
166            CellRepr::Void => panic!("located a void cell %{index} in design"),
167            CellRepr::Skip(start) => (CellRef { design: self, index: start as usize }, index - start as usize),
168            _ => (CellRef { design: self, index }, 0),
169        }
170    }
171
172    pub fn map_net_new(&self, net: impl Into<Net>) -> Net {
173        let changes = self.changes.borrow();
174        let mut net = net.into();
175        while let Some(new_net) = changes.replaced_nets.get(&net) {
176            net = *new_net;
177        }
178        net
179    }
180
181    pub fn find_new_cell(&self, net: Net) -> (Cow<'_, Cell>, MetaItemRef<'_>, usize) {
182        let net = self.map_net_new(net);
183        let index = net.as_cell_index();
184        let changes = self.changes.borrow();
185        let (mut cell, mut meta, index, bit) = if index < self.cells.len() {
186            let (index, bit) = match self.cells[index].repr {
187                CellRepr::Void => panic!("located a void cell %{index} in design"),
188                CellRepr::Skip(start) => (start as usize, index - start as usize),
189                _ => (index, 0),
190            };
191            (self.cells[index].get(), self.cells[index].meta, index, bit)
192        } else {
193            let (index, bit) = match changes.added_cells[index - self.cells.len()].repr {
194                CellRepr::Void => panic!("located a void cell %{index} in change queue"),
195                CellRepr::Skip(start) => (start as usize, index - start as usize),
196                _ => (index, 0),
197            };
198            let acell = &changes.added_cells[index - self.cells.len()];
199            (Cow::Owned(acell.get().into_owned()), acell.meta, index, bit)
200        };
201        if changes.unalived_cells.contains(&index) {
202            panic!("cell %{index} has been unalived");
203        }
204        if let Some(new_cell) = changes.replaced_cells.get(&index) {
205            cell = Cow::Owned(new_cell.get().into_owned());
206            meta = new_cell.meta;
207        }
208        let mut meta = self.ref_metadata_item(meta);
209        if let Some(extra_meta) = changes.appended_metadata.get(&index) {
210            meta = MetaItemRef::from_iter(
211                self,
212                meta.iter().chain(extra_meta.iter().flat_map(|&index| self.ref_metadata_item(index).iter())),
213            );
214        }
215        (cell, meta, bit)
216    }
217
218    pub fn append_metadata_by_net(&self, net: Net, metadata: MetaItemRef<'_>) {
219        let net = self.map_net_new(net);
220        if net.is_const() {
221            return;
222        }
223        let index = net.as_cell_index();
224        let mut changes = self.changes.borrow_mut();
225        let index = if index < self.cells.len() {
226            match self.cells[index].repr {
227                CellRepr::Void => panic!("located a void cell %{index} in design"),
228                CellRepr::Skip(start) => start as usize,
229                _ => index,
230            }
231        } else {
232            match changes.added_cells[index - self.cells.len()].repr {
233                CellRepr::Void => panic!("located a void cell %{index} in change queue"),
234                CellRepr::Skip(start) => start as usize,
235                _ => index,
236            }
237        };
238        changes.appended_metadata.entry(index).or_default().push(metadata.index())
239    }
240
241    pub fn iter_cells(&self) -> CellIter<'_> {
242        CellIter { design: self, index: 0 }
243    }
244
245    pub(crate) fn is_valid_cell_index(&self, index: usize) -> bool {
246        index < self.cells.len()
247    }
248
249    pub(crate) fn metadata(&self) -> Ref<'_, MetadataStore> {
250        self.metadata.borrow()
251    }
252
253    pub fn add_metadata_string(&self, string: &str) -> MetaStringRef<'_> {
254        let index = self.metadata.borrow_mut().add_string(string);
255        self.metadata.borrow().ref_string(self, index)
256    }
257
258    pub(crate) fn ref_metadata_string(&self, index: MetaStringIndex) -> MetaStringRef<'_> {
259        self.metadata.borrow().ref_string(self, index)
260    }
261
262    pub fn add_metadata_item(&self, item: &MetaItem) -> MetaItemRef<'_> {
263        item.validate();
264        let index = self.metadata.borrow_mut().add_item(item);
265        self.metadata.borrow().ref_item(self, index)
266    }
267
268    pub(crate) fn ref_metadata_item(&self, index: MetaItemIndex) -> MetaItemRef<'_> {
269        self.metadata.borrow().ref_item(self, index)
270    }
271
272    pub fn replace_net(&self, from_net: impl Into<Net>, to_net: impl Into<Net>) {
273        let (from_net, to_net) = (from_net.into(), to_net.into());
274        assert!(!from_net.is_const());
275        if from_net != to_net {
276            let mut changes = self.changes.borrow_mut();
277            assert_eq!(changes.replaced_nets.insert(from_net, to_net), None);
278        }
279    }
280
281    pub fn replace_value<'a, 'b>(&self, from_value: impl Into<Cow<'a, Value>>, to_value: impl Into<Cow<'b, Value>>) {
282        let (from_value, to_value) = (from_value.into(), to_value.into());
283        assert_eq!(from_value.len(), to_value.len());
284        for (from_net, to_net) in from_value.iter().zip(to_value.iter()) {
285            self.replace_net(from_net, to_net);
286        }
287    }
288
289    pub fn map_net(&self, net: impl Into<Net>) -> Net {
290        let changes = self.changes.borrow();
291        let net = net.into();
292        let mut mapped_net = net;
293        while let Some(new_net) = changes.replaced_nets.get(&mapped_net) {
294            mapped_net = *new_net;
295        }
296        // Assume the caller might want to locate the cell behind the net.
297        if mapped_net.as_cell_index() >= self.cells.len() { net } else { mapped_net }
298    }
299
300    pub fn map_value(&self, value: impl Into<Value>) -> Value {
301        let mut value = value.into();
302        value.visit_mut(|net| *net = self.map_net(*net));
303        value
304    }
305
306    pub fn is_empty(&self) -> bool {
307        self.ios.is_empty() && self.cells.len() == 3 && !self.is_changed() && self.target.is_none()
308    }
309
310    pub fn is_changed(&self) -> bool {
311        let changes = self.changes.borrow();
312        !changes.added_ios.is_empty()
313            || !changes.added_cells.is_empty()
314            || !changes.replaced_cells.is_empty()
315            || !changes.unalived_cells.is_empty()
316            || !changes.replaced_nets.is_empty()
317    }
318
319    pub fn verify<SMT: SmtEngine>(&self, engine: SMT) -> Result<(), SMT::Error> {
320        let changes = self.changes.borrow();
321        let locate_cell = |net: Net| {
322            let index = net.as_cell_index();
323            if index < self.cells.len() {
324                &self.cells[index].repr
325            } else {
326                &changes.added_cells[index - self.cells.len()].repr
327            }
328        };
329        let get_cell = |net: Net| match locate_cell(net) {
330            CellRepr::Skip(index) => locate_cell(Net::from_cell_index(*index as usize)),
331            result => result,
332        };
333
334        let mut smt = SmtBuilder::new(self, engine);
335        for (index, cell) in self.cells.iter().chain(changes.added_cells.iter()).enumerate() {
336            if matches!(cell.repr, CellRepr::Skip(_) | CellRepr::Void) || cell.output_len() == 0 {
337            } else if let Some(new_cell) = changes.replaced_cells.get(&index) {
338                smt.replace_cell(&Value::from_cell_range(index, cell.output_len()), &cell.get(), &new_cell.get())?;
339            } else {
340                smt.add_cell(&Value::from_cell_range(index, cell.output_len()), &cell.get())?;
341            }
342        }
343        for (&net, &new_net) in changes.replaced_nets.iter() {
344            let cell = get_cell(net);
345            if matches!(cell, CellRepr::Void) {
346                smt.replace_void_net(net, new_net)?;
347                continue;
348            } else if matches!(&*cell.get(), Cell::Dff(_))
349                && let new_cell = get_cell(new_net)
350                && matches!(&*new_cell.get(), Cell::Dff(_))
351            {
352                smt.replace_dff_net(net, new_net)?;
353            }
354            smt.replace_net(net, new_net)?;
355        }
356        if let Some(example) = smt.check()? {
357            let mut message = "verification failed!\n".to_string();
358            message.push_str(&format!("\ndesign:\n{self:#}"));
359            message.push_str("\ncounterexample:\n");
360            for (index, cell) in self.cells.iter().chain(changes.added_cells.iter()).enumerate() {
361                if matches!(cell.repr, CellRepr::Skip(_) | CellRepr::Void) || cell.output_len() == 0 {
362                } else {
363                    let output = Value::from_cell_range(index, cell.output_len());
364                    let (was, now) = (example.get_past_value(&output), example.get_value(&output));
365                    message.push_str(&match (was, now) {
366                        (Some(was), Some(now)) => format!("{} = {} -> {}\n", self.display_value(&output), was, now),
367                        (None, Some(now)) => format!("{} = {}\n", self.display_value(&output), now),
368                        (Some(was), None) => format!("{} = {} -> ?\n", self.display_value(&output), was),
369                        (None, None) => unreachable!(),
370                    });
371                }
372            }
373            for (&net, &new_net) in changes.replaced_nets.iter() {
374                if example.get_value(net) != example.get_value(new_net) {
375                    message.push_str(&format!(
376                        "\npossible cause: replacing net {} with net {} is not valid",
377                        self.display_net(net),
378                        self.display_net(new_net)
379                    ));
380                }
381            }
382            panic!("{message}");
383        }
384        Ok(())
385    }
386
387    pub fn apply(&mut self) -> bool {
388        #[cfg(feature = "verify")]
389        self.verify(crate::EasySmtEngine::z3().unwrap()).unwrap();
390
391        let mut changes = std::mem::take(self.changes.get_mut());
392        self.changes.get_mut().next_io = changes.next_io;
393
394        let mut did_change = !changes.added_ios.is_empty() || !changes.added_cells.is_empty();
395        self.ios.extend(changes.added_ios);
396        self.cells.extend(changes.added_cells);
397        for cell_index in changes.unalived_cells {
398            let output_len = self.cells[cell_index].output_len().max(1);
399            for index in cell_index..cell_index + output_len {
400                self.cells[index] = CellRepr::Void.into();
401            }
402            did_change = true;
403        }
404        for (index, new_cell) in changes.replaced_cells {
405            assert_eq!(self.cells[index].output_len(), new_cell.output_len());
406            self.cells[index] = new_cell;
407            // CellRef::replace() ensures the new cell is different.
408            did_change = true;
409        }
410        for (cell_index, new_items) in changes.appended_metadata {
411            let cell_meta_iter = self.ref_metadata_item(self.cells[cell_index].meta).iter();
412            let new_items_iter = new_items.into_iter().flat_map(|new_item| self.ref_metadata_item(new_item).iter());
413            self.cells[cell_index].meta = MetaItemRef::from_iter(self, cell_meta_iter.chain(new_items_iter)).index();
414        }
415        changes.cell_cache.clear();
416        if !changes.replaced_nets.is_empty() {
417            for cell in self.cells.iter_mut().filter(|cell| !matches!(cell.repr, CellRepr::Skip(_) | CellRepr::Void)) {
418                cell.repr.visit_mut(|net| {
419                    while let Some(new_net) = changes.replaced_nets.get(net) {
420                        if *net != *new_net {
421                            *net = *new_net;
422                            did_change = true;
423                        }
424                    }
425                });
426            }
427            changes.replaced_nets.clear();
428        }
429        did_change
430    }
431
432    pub fn target(&self) -> Option<Arc<dyn Target>> {
433        self.target.as_ref().map(|target| target.clone())
434    }
435
436    pub fn target_prototype(&self, target_cell: &TargetCell) -> &TargetPrototype {
437        self.target
438            .as_ref()
439            .expect("design has no target")
440            .prototype(&target_cell.kind)
441            .expect("target prototype not defined")
442    }
443}
444
445impl Default for Design {
446    fn default() -> Self {
447        Self::new()
448    }
449}
450
451#[derive(Debug, Clone, PartialEq, Eq, Hash)]
452struct AnnotatedCell {
453    repr: CellRepr,
454    meta: MetaItemIndex,
455}
456
457impl Deref for AnnotatedCell {
458    type Target = CellRepr;
459
460    fn deref(&self) -> &Self::Target {
461        &self.repr
462    }
463}
464
465impl From<CellRepr> for AnnotatedCell {
466    fn from(val: CellRepr) -> Self {
467        AnnotatedCell { repr: val, meta: MetaItemIndex::NONE }
468    }
469}
470
471pub struct WithMetadataGuard<'a> {
472    design: &'a Design,
473    restore: MetaItemIndex,
474}
475
476impl Drop for WithMetadataGuard<'_> {
477    fn drop(&mut self) {
478        self.design.changes.borrow_mut().cell_metadata = self.restore;
479    }
480}
481
482#[derive(Clone, Copy)]
483pub struct CellRef<'a> {
484    design: &'a Design,
485    index: usize,
486}
487
488impl PartialEq<CellRef<'_>> for CellRef<'_> {
489    fn eq(&self, other: &CellRef<'_>) -> bool {
490        std::ptr::eq(self.design, other.design) && self.index == other.index
491    }
492}
493
494impl Eq for CellRef<'_> {}
495
496impl PartialOrd<CellRef<'_>> for CellRef<'_> {
497    fn partial_cmp(&self, other: &CellRef<'_>) -> Option<std::cmp::Ordering> {
498        Some(self.cmp(other))
499    }
500}
501
502impl Ord for CellRef<'_> {
503    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
504        match (self.design as *const Design).cmp(&(other.design as *const Design)) {
505            core::cmp::Ordering::Equal => self.index.cmp(&other.index),
506            ord => ord,
507        }
508    }
509}
510
511impl Hash for CellRef<'_> {
512    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
513        self.index.hash(state);
514    }
515}
516
517impl<'a> CellRef<'a> {
518    pub fn get(self) -> Cow<'a, Cell> {
519        self.design.cells[self.index].get()
520    }
521
522    pub fn metadata(&self) -> MetaItemRef<'a> {
523        self.design.metadata.borrow().ref_item(self.design, self.design.cells[self.index].meta)
524    }
525
526    pub fn output_len(&self) -> usize {
527        self.design.cells[self.index].output_len()
528    }
529
530    pub fn output(&self) -> Value {
531        Value::from_cell_range(self.index, self.output_len())
532    }
533
534    pub fn visit(&self, f: impl FnMut(Net)) {
535        self.design.cells[self.index].visit(f)
536    }
537
538    pub fn replace(&self, to_cell: Cell) {
539        if let Cell::Const(val) = to_cell {
540            self.design.replace_value(self.output(), val);
541            self.unalive();
542        } else if *self.design.cells[self.index].get() != to_cell {
543            to_cell.validate(self.design);
544            let to_cell = AnnotatedCell { repr: to_cell.into(), meta: self.design.cells[self.index].meta };
545            let mut changes = self.design.changes.borrow_mut();
546            assert!(changes.replaced_cells.insert(self.index, to_cell).is_none());
547        }
548    }
549
550    pub fn append_metadata(&self, metadata: MetaItemRef<'a>) {
551        let mut changes = self.design.changes.borrow_mut();
552        changes.appended_metadata.entry(self.index).or_default().push(metadata.index())
553    }
554
555    pub fn unalive(&self) {
556        let mut changes = self.design.changes.borrow_mut();
557        changes.unalived_cells.insert(self.index);
558    }
559
560    /// Returns the same index as the one used by `Display` implementation. There is intentionally no way to retrieve
561    /// a cell by its index.
562    pub fn debug_index(&self) -> usize {
563        self.index
564    }
565
566    pub(crate) fn metadata_index(&self) -> MetaItemIndex {
567        self.design.cells[self.index].meta
568    }
569
570    /// Returns a reference to the underlying [`Design`].
571    pub fn design(self) -> &'a Design {
572        self.design
573    }
574}
575
576pub struct CellIter<'a> {
577    design: &'a Design,
578    index: usize,
579}
580
581impl<'a> Iterator for CellIter<'a> {
582    type Item = CellRef<'a>;
583
584    fn next(&mut self) -> Option<Self::Item> {
585        while matches!(
586            self.design.cells.get(self.index),
587            Some(AnnotatedCell { repr: CellRepr::Void | CellRepr::Const(_), .. })
588        ) {
589            self.index += 1;
590        }
591        if self.index < self.design.cells.len() {
592            let cell_ref = CellRef { design: self.design, index: self.index };
593            self.index += self.design.cells[self.index].output_len().max(1);
594            Some(cell_ref)
595        } else {
596            None
597        }
598    }
599}
600
601macro_rules! builder_fn {
602    () => {};
603
604    ($func:ident( $($arg:ident : $argty:ty),+ ) -> $retty:ty : $cstr:ident $body:tt; $($rest:tt)*) => {
605        pub fn $func(&self, $( $arg: $argty ),+) -> $retty {
606            self.add_cell(Cell::$cstr $body).try_into().unwrap()
607        }
608
609        builder_fn!{ $($rest)* }
610    };
611
612    // For cells with no output value.
613    ($func:ident( $($arg:ident : $argty:ty),+ ) : $cstr:ident $body:tt; $($rest:tt)*) => {
614        pub fn $func(&self, $( $arg: $argty ),+) {
615            self.add_cell(Cell::$cstr $body);
616        }
617
618        builder_fn!{ $($rest)* }
619    };
620}
621
622impl Design {
623    builder_fn! {
624        add_buf(arg: impl Into<Value>) -> Value :
625            Buf(arg.into());
626        add_buf1(arg: impl Into<Net>) -> Net :
627            Buf(arg.into().into());
628        add_not(arg: impl Into<Value>) -> Value :
629            Not(arg.into());
630        add_not1(arg: impl Into<Net>) -> Net :
631            Not(arg.into().into());
632        add_and(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Value :
633            And(arg1.into(), arg2.into());
634        add_and1(arg1: impl Into<Net>, arg2: impl Into<Net>) -> Net :
635            And(arg1.into().into(), arg2.into().into());
636        add_or(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Value :
637            Or(arg1.into(), arg2.into());
638        add_or1(arg1: impl Into<Net>, arg2: impl Into<Net>) -> Net :
639            Or(arg1.into().into(), arg2.into().into());
640        add_xor(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Value :
641            Xor(arg1.into(), arg2.into());
642        add_xor1(arg1: impl Into<Net>, arg2: impl Into<Net>) -> Net :
643            Xor(arg1.into().into(), arg2.into().into());
644        add_adc(arg1: impl Into<Value>, arg2: impl Into<Value>, arg3: impl Into<Net>) -> Value :
645            Adc(arg1.into(), arg2.into(), arg3.into());
646        add_aig(arg1: impl Into<ControlNet>, arg2: impl Into<ControlNet>) -> Net :
647            Aig(arg1.into(), arg2.into());
648
649        add_eq(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Net :
650            Eq(arg1.into(), arg2.into());
651        add_ult(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Net :
652            ULt(arg1.into(), arg2.into());
653        add_slt(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Net :
654            SLt(arg1.into(), arg2.into());
655
656        add_shl(arg1: impl Into<Value>, arg2: impl Into<Value>, stride: u32) -> Value :
657            Shl(arg1.into(), arg2.into(), stride);
658        add_ushr(arg1: impl Into<Value>, arg2: impl Into<Value>, stride: u32) -> Value :
659            UShr(arg1.into(), arg2.into(), stride);
660        add_sshr(arg1: impl Into<Value>, arg2: impl Into<Value>, stride: u32) -> Value :
661            SShr(arg1.into(), arg2.into(), stride);
662        add_xshr(arg1: impl Into<Value>, arg2: impl Into<Value>, stride: u32) -> Value :
663            XShr(arg1.into(), arg2.into(), stride);
664
665        add_mul(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Value :
666            Mul(arg1.into(), arg2.into());
667        add_udiv(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Value :
668            UDiv(arg1.into(), arg2.into());
669        add_umod(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Value :
670            UMod(arg1.into(), arg2.into());
671        add_sdiv_trunc(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Value :
672            SDivTrunc(arg1.into(), arg2.into());
673        add_sdiv_floor(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Value :
674            SDivFloor(arg1.into(), arg2.into());
675        add_smod_trunc(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Value :
676            SModTrunc(arg1.into(), arg2.into());
677        add_smod_floor(arg1: impl Into<Value>, arg2: impl Into<Value>) -> Value :
678            SModFloor(arg1.into(), arg2.into());
679
680        add_match(arg: impl Into<MatchCell>) -> Value :
681            Match(arg.into());
682        add_assign(arg: impl Into<AssignCell>) -> Value :
683            Assign(arg.into());
684        add_dff(arg: impl Into<FlipFlop>) -> Value :
685            Dff(arg.into());
686        add_memory(arg: impl Into<Memory>) -> Value :
687            Memory(arg.into());
688        add_iobuf(arg: impl Into<IoBuffer>) -> Value :
689            IoBuf(arg.into());
690        add_other(arg: impl Into<Instance>) -> Value :
691            Other(arg.into());
692        add_target(arg: impl Into<TargetCell>) -> Value :
693            Target(arg.into());
694
695        add_input(name: impl Into<String>, width: usize) -> Value :
696            Input(name.into(), width);
697        add_input1(name: impl Into<String>) -> Net :
698            Input(name.into(), 1);
699        add_output(name: impl Into<String>, value: impl Into<Value>) :
700            Output(name.into(), value.into());
701        add_name(name: impl Into<String>, value: impl Into<Value>) :
702            Name(name.into(), value.into());
703        add_debug(name: impl Into<String>, value: impl Into<Value>) :
704            Debug(name.into(), value.into());
705    }
706
707    pub fn add_mux(&self, arg1: impl Into<ControlNet>, arg2: impl Into<Value>, arg3: impl Into<Value>) -> Value {
708        match arg1.into() {
709            ControlNet::Pos(net) => self.add_cell(Cell::Mux(net, arg2.into(), arg3.into())),
710            ControlNet::Neg(net) => self.add_cell(Cell::Mux(net, arg3.into(), arg2.into())),
711        }
712    }
713
714    pub fn add_mux1(&self, arg1: impl Into<ControlNet>, arg2: impl Into<Net>, arg3: impl Into<Net>) -> Net {
715        match arg1.into() {
716            ControlNet::Pos(net) => self.add_cell(Cell::Mux(net, arg2.into().into(), arg3.into().into())).unwrap_net(),
717            ControlNet::Neg(net) => self.add_cell(Cell::Mux(net, arg3.into().into(), arg2.into().into())).unwrap_net(),
718        }
719    }
720
721    pub fn add_ne(&self, arg1: impl Into<Value>, arg2: impl Into<Value>) -> Net {
722        let eq = self.add_eq(arg1, arg2);
723        self.add_not1(eq)
724    }
725}
726
727#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
728pub enum TopoSortItem<'a> {
729    Cell(CellRef<'a>),
730    CellBit(CellRef<'a>, usize),
731}
732
733impl Design {
734    pub fn topo_sort(&self) -> Vec<TopoSortItem<'_>> {
735        fn is_splittable(cell: CellRef) -> bool {
736            matches!(
737                &*cell.get(),
738                Cell::Buf(..) | Cell::Not(..) | Cell::And(..) | Cell::Or(..) | Cell::Xor(..) | Cell::Mux(..)
739            )
740        }
741
742        fn is_comb_edge(design: &Design, net: Net) -> bool {
743            let (cell, _) = design.find_cell(net);
744            match &*cell.get() {
745                Cell::Input(..) | Cell::IoBuf(..) | Cell::Dff(..) | Cell::Other(..) => false,
746                Cell::Target(target_cell) => design.target_prototype(target_cell).purity == TargetCellPurity::Pure,
747                _ => true,
748            }
749        }
750
751        fn get_deps(item: TopoSortItem) -> Vec<Net> {
752            let mut result = vec![];
753            match item {
754                TopoSortItem::Cell(cell) => {
755                    cell.visit(|net| {
756                        result.push(net);
757                    });
758                }
759                TopoSortItem::CellBit(cell, bit) => match &*cell.get() {
760                    Cell::Buf(val) | Cell::Not(val) => {
761                        result.push(val[bit]);
762                    }
763                    Cell::And(val1, val2) | Cell::Or(val1, val2) | Cell::Xor(val1, val2) => {
764                        result.push(val1[bit]);
765                        result.push(val2[bit]);
766                    }
767                    Cell::Mux(net, val1, val2) => {
768                        result.push(*net);
769                        result.push(val1[bit]);
770                        result.push(val2[bit]);
771                    }
772                    _ => unreachable!(),
773                },
774            }
775            let cell = match item {
776                TopoSortItem::Cell(cell) => cell,
777                TopoSortItem::CellBit(cell, _) => cell,
778            };
779            result.retain(|net| is_comb_edge(cell.design(), *net));
780            result
781        }
782
783        fn get_item_from_net(design: &Design, net: Net) -> Option<TopoSortItem<'_>> {
784            let (cell, bit) = design.find_cell(net);
785            if is_splittable(cell) { Some(TopoSortItem::CellBit(cell, bit)) } else { Some(TopoSortItem::Cell(cell)) }
786        }
787
788        struct StackEntry<'a> {
789            item: TopoSortItem<'a>,
790            deps: Vec<Net>,
791        }
792
793        let mut result = vec![];
794        let mut visited = BTreeSet::new();
795        for cell in self.iter_cells() {
796            let roots = if is_splittable(cell) {
797                Vec::from_iter((0..cell.output_len()).map(|bit| TopoSortItem::CellBit(cell, bit)))
798            } else {
799                vec![TopoSortItem::Cell(cell)]
800            };
801            for root in roots {
802                let mut stack = vec![StackEntry { item: root, deps: get_deps(root) }];
803                if visited.contains(&root) {
804                    continue;
805                }
806                visited.insert(root);
807                while let Some(top) = stack.last_mut() {
808                    if let Some(net) = top.deps.pop() {
809                        let Some(item) = get_item_from_net(self, net) else { continue };
810                        if visited.contains(&item) {
811                            continue;
812                        }
813                        visited.insert(item);
814                        stack.push(StackEntry { item, deps: get_deps(item) });
815                    } else {
816                        result.push(top.item);
817                        stack.pop();
818                    };
819                }
820            }
821        }
822        result
823    }
824
825    pub fn iter_cells_topo(&self) -> impl DoubleEndedIterator<Item = CellRef<'_>> {
826        fn get_deps(design: &Design, cell: CellRef) -> BTreeSet<usize> {
827            let mut result = BTreeSet::new();
828            cell.visit(|net| {
829                if !net.is_const() {
830                    let (cell, _offset) = design.find_cell(net);
831                    result.insert(cell.index);
832                }
833            });
834            result
835        }
836
837        let mut result = vec![];
838        let mut visited = BTreeSet::new();
839        // emit inputs, iobs and stateful cells first, in netlist order
840        for cell in self.iter_cells() {
841            match &*cell.get() {
842                Cell::Input(..) | Cell::IoBuf(..) | Cell::Dff(..) | Cell::Other(..) => {
843                    visited.insert(cell.index);
844                    result.push(cell);
845                }
846                Cell::Target(target_cell) => {
847                    if self.target_prototype(target_cell).purity != TargetCellPurity::Pure {
848                        visited.insert(cell.index);
849                        result.push(cell);
850                    }
851                }
852                _ => (),
853            }
854        }
855        // now emit combinational cells, in topologically-sorted order whenever possible.
856        // we try to emit them in netlist order; however, if we try to emit a cell
857        // that has an input that has not yet been emitted, we push it on a stack,
858        // and go emit the inputs instead.  the cell is put on the "visitted" list
859        // as soon as we start processing it, so cycles will be automatically broken
860        // by considering inputs already on the processing stack as "already emitted".
861        for cell in self.iter_cells() {
862            if matches!(&*cell.get(), Cell::Output(..) | Cell::Name(..) | Cell::Debug(..)) {
863                continue;
864            }
865            if visited.contains(&cell.index) {
866                continue;
867            }
868            visited.insert(cell.index);
869            if matches!(&*cell.get(), Cell::Const(_)) {
870                continue;
871            }
872            let mut stack = vec![(cell, get_deps(self, cell))];
873            'outer: while let Some((cell, deps)) = stack.last_mut() {
874                while let Some(dep_index) = deps.pop_first() {
875                    if !visited.contains(&dep_index) {
876                        let cell = CellRef { design: self, index: dep_index };
877                        visited.insert(dep_index);
878                        stack.push((cell, get_deps(self, cell)));
879                        continue 'outer;
880                    }
881                }
882                result.push(*cell);
883                stack.pop();
884            }
885        }
886        // finally, emit outputs, names, and debugs
887        for cell in self.iter_cells() {
888            if visited.contains(&cell.index) {
889                continue;
890            }
891            if matches!(&*cell.get(), Cell::Const(_)) {
892                continue;
893            }
894            result.push(cell);
895        }
896        result.into_iter()
897    }
898
899    pub fn compact(&mut self) -> bool {
900        let did_change = self.apply();
901
902        let mut queue = BTreeSet::new();
903        let mut debug = BTreeMap::new();
904        for (index, cell) in self.cells.iter().enumerate() {
905            if matches!(cell.repr, CellRepr::Skip(_) | CellRepr::Void) {
906                continue;
907            }
908            match &*cell.get() {
909                cell if cell.has_effects(self) => {
910                    queue.insert(index);
911                }
912                Cell::Const(_) => {
913                    queue.insert(index);
914                }
915                Cell::Debug(name, value) => {
916                    debug.insert(name.clone(), (value.clone(), cell.meta));
917                }
918                _ => (),
919            }
920        }
921
922        let mut keep = BTreeSet::new();
923        while let Some(index) = queue.pop_first() {
924            keep.insert(index);
925            self.cells[index].visit(|net| {
926                let (cell_ref, _offset) = self.find_cell(net);
927                if !keep.contains(&cell_ref.index) {
928                    queue.insert(cell_ref.index);
929                }
930            });
931        }
932
933        let mut net_map = BTreeMap::new();
934        for (old_index, cell) in std::mem::take(&mut self.cells).into_iter().enumerate() {
935            if keep.contains(&old_index) {
936                let new_index = self.cells.len();
937                for offset in 0..cell.output_len() {
938                    net_map.insert(Net::from_cell_index(old_index + offset), Net::from_cell_index(new_index + offset));
939                }
940                let skip_count = cell.output_len().saturating_sub(1);
941                self.cells.push(cell);
942                for _ in 0..skip_count {
943                    self.cells.push(CellRepr::Skip(new_index as u32).into());
944                }
945            }
946        }
947
948        for cell in self.cells.iter_mut().filter(|cell| !matches!(cell.repr, CellRepr::Skip(_))) {
949            cell.repr.visit_mut(|net| {
950                if !net.is_const() {
951                    *net = net_map[net];
952                }
953            });
954        }
955
956        for (name, (mut value, meta)) in debug {
957            value.visit_mut(|net| {
958                if !net.is_const() {
959                    if let Some(&new_net) = net_map.get(net) {
960                        *net = new_net;
961                    } else {
962                        *net = Net::UNDEF;
963                    }
964                }
965            });
966            self.cells.push(AnnotatedCell { repr: CellRepr::Boxed(Box::new(Cell::Debug(name, value))), meta });
967        }
968
969        did_change
970    }
971
972    pub fn statistics(&self) -> BTreeMap<String, usize> {
973        let result = RefCell::new(BTreeMap::<String, usize>::new());
974        for cell_ref in self.iter_cells() {
975            let simple = |name: &str| {
976                *result.borrow_mut().entry(name.to_string()).or_default() += 1;
977            };
978            let bitwise = |name: &str, amount: usize| {
979                *result.borrow_mut().entry(name.to_string()).or_default() += amount;
980            };
981            let wide = |name: &str, size: usize| {
982                *result.borrow_mut().entry(format!("{name}:{size}")).or_default() += 1;
983            };
984            let custom = |args: std::fmt::Arguments| {
985                *result.borrow_mut().entry(format!("{args}")).or_default() += 1;
986            };
987            match &*cell_ref.get() {
988                Cell::Const(_) => (),
989                Cell::Buf(arg) => bitwise("buf", arg.len()),
990                Cell::Not(arg) => bitwise("not", arg.len()),
991                Cell::And(arg, _) => bitwise("and", arg.len()),
992                Cell::Or(arg, _) => bitwise("or", arg.len()),
993                Cell::Xor(arg, _) => bitwise("xor", arg.len()),
994                Cell::Mux(_, arg, _) => bitwise("mux", arg.len()),
995                Cell::Adc(arg, _, _) => wide("adc", arg.len()),
996                Cell::Aig(_, _) => simple("aig"),
997                Cell::Eq(arg, _) => wide("eq", arg.len()),
998                Cell::ULt(arg, _) => wide("ult", arg.len()),
999                Cell::SLt(arg, _) => wide("slt", arg.len()),
1000                Cell::Shl(arg, _, _) => wide("shl", arg.len()),
1001                Cell::UShr(arg, _, _) => wide("ushr", arg.len()),
1002                Cell::SShr(arg, _, _) => wide("sshr", arg.len()),
1003                Cell::XShr(arg, _, _) => wide("xshr", arg.len()),
1004                Cell::Mul(arg, _) => wide("mul", arg.len()),
1005                Cell::UDiv(arg, _) => wide("udiv", arg.len()),
1006                Cell::UMod(arg, _) => wide("umod", arg.len()),
1007                Cell::SDivTrunc(arg, _) => wide("sdiv_trunc", arg.len()),
1008                Cell::SDivFloor(arg, _) => wide("sdiv_floor", arg.len()),
1009                Cell::SModTrunc(arg, _) => wide("smod_trunc", arg.len()),
1010                Cell::SModFloor(arg, _) => wide("smod_floor", arg.len()),
1011                Cell::Match(_) => custom(format_args!("match")),
1012                Cell::Assign(AssignCell { value, .. }) => bitwise("assign", value.len()),
1013                Cell::Dff(FlipFlop { data, .. }) => bitwise("dff", data.len()),
1014                Cell::Memory(Memory { depth, width, .. }) => custom(format_args!("memory:{depth}:{width}")),
1015                Cell::IoBuf(IoBuffer { io, .. }) => bitwise("iobuf", io.len()),
1016                Cell::Target(TargetCell { kind, .. }) => custom(format_args!("{kind}")),
1017                Cell::Other(Instance { kind, .. }) => custom(format_args!("{kind}")),
1018                Cell::Input(_, width) => bitwise("input", *width),
1019                Cell::Output(_, value) => bitwise("output", value.len()),
1020                Cell::Name(..) | Cell::Debug(..) => (),
1021            }
1022        }
1023        result.into_inner()
1024    }
1025}
1026
1027// This can't be in `crate::print` because of the privacy violations.
1028impl Display for Design {
1029    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1030        let changes = self.changes.borrow();
1031
1032        let diff = self.is_changed();
1033        let added = "+";
1034        let removed = "-";
1035        let unchanged = " ";
1036        let comment = if !diff { "; " } else { " ; " };
1037
1038        let mut net_names = BTreeMap::new();
1039        for cell_ref in self.iter_cells() {
1040            match &*cell_ref.get() {
1041                Cell::Output(name, value) | Cell::Name(name, value) | Cell::Debug(name, value) => {
1042                    let name = Rc::new(name.clone());
1043                    for (offset, net) in value.iter().enumerate() {
1044                        if !net.is_const() {
1045                            net_names.insert(net, (name.clone(), offset));
1046                        }
1047                    }
1048                }
1049                _ => (),
1050            }
1051        }
1052
1053        if let Some(target) = self.target() {
1054            write!(f, "{}target ", if !diff { "" } else { unchanged })?;
1055            Design::write_string(f, target.name())?;
1056            for (name, value) in target.options() {
1057                write!(f, " ")?;
1058                Design::write_string(f, &name)?;
1059                write!(f, "=")?;
1060                Design::write_string(f, &value)?;
1061            }
1062            writeln!(f)?;
1063        }
1064
1065        for metadata_ref in self.metadata.borrow().iter_items(self) {
1066            if metadata_ref.index() == MetaItemIndex::NONE {
1067                continue;
1068            }
1069            write!(f, "{}", if !diff { "" } else { unchanged })?;
1070            write!(f, "{} = ", metadata_ref.index())?;
1071            let item = metadata_ref.get();
1072            match item {
1073                MetaItem::None => unreachable!(),
1074                MetaItem::Set(items) => {
1075                    write!(f, "{{")?;
1076                    for item in items {
1077                        write!(f, " {}", item.index())?;
1078                    }
1079                    write!(f, " }}")?;
1080                }
1081                MetaItem::Source { file, start, end } => {
1082                    write!(f, "source ")?;
1083                    Design::write_string(f, &file.get())?;
1084                    write!(f, " (#{} #{}) (#{} #{})", start.line, start.column, end.line, end.column)?;
1085                }
1086                MetaItem::NamedScope { name: _, source, parent }
1087                | MetaItem::IndexedScope { index: _, source, parent } => {
1088                    write!(f, "scope ")?;
1089                    match item {
1090                        MetaItem::NamedScope { name, .. } => Design::write_string(f, &name.get())?,
1091                        MetaItem::IndexedScope { index, .. } => write!(f, "#{index}")?,
1092                        _ => unreachable!(),
1093                    }
1094                    if !parent.is_none() {
1095                        write!(f, " in={}", parent.index())?;
1096                    }
1097                    if !source.is_none() {
1098                        write!(f, " src={}", source.index())?;
1099                    }
1100                }
1101                MetaItem::Ident { name, scope } => {
1102                    write!(f, "ident ")?;
1103                    Design::write_string(f, &name.get())?;
1104                    write!(f, " in={}", scope.index())?;
1105                }
1106                MetaItem::Attr { name, value } => {
1107                    write!(f, "attr ")?;
1108                    Design::write_string(f, &name.get())?;
1109                    write!(f, " {value}")?;
1110                }
1111            }
1112            writeln!(f)?;
1113        }
1114
1115        for (name, io_value) in self.iter_ios() {
1116            write!(f, "{}&", if !diff { "" } else { unchanged })?;
1117            Design::write_string(f, name)?;
1118            writeln!(f, ":{} = io", io_value.len())?;
1119        }
1120        for (name, io_value) in &changes.added_ios {
1121            write!(f, "{added}&")?;
1122            Design::write_string(f, name)?;
1123            writeln!(f, ":{} = io", io_value.len())?;
1124        }
1125
1126        let write_cell = |f: &mut std::fmt::Formatter, index: usize, cell: &Cell, metadata: MetaItemIndex| {
1127            for item in self.ref_metadata_item(metadata).iter() {
1128                match item.get() {
1129                    MetaItem::Source { file, start, end: _ } => {
1130                        writeln!(f, "{comment}source file://{}#{}", file.get(), start.line + 1)?;
1131                    }
1132                    MetaItem::NamedScope { .. } => {
1133                        let mut names = Vec::new();
1134                        let mut scope = item;
1135                        while !scope.is_none() {
1136                            let MetaItem::NamedScope { name, parent, .. } = scope.get() else { break };
1137                            names.push(name);
1138                            scope = parent;
1139                        }
1140                        if !names.is_empty() {
1141                            write!(f, "{comment}scope ")?;
1142                            for (index, name) in names.iter().rev().enumerate() {
1143                                if index > 0 {
1144                                    write!(f, ".")?;
1145                                }
1146                                write!(f, "{}", name.get())?;
1147                            }
1148                            writeln!(f)?;
1149                        }
1150                    }
1151                    _ => (),
1152                }
1153            }
1154            if matches!(cell, Cell::Target(..)) {
1155                for index in (index..index + cell.output_len()).rev() {
1156                    if let Some((name, offset)) = net_names.get(&Net::from_cell_index(index)) {
1157                        write!(f, "{comment}drives ")?;
1158                        Design::write_string(f, name)?;
1159                        writeln!(f, "+{offset}")?;
1160                    }
1161                }
1162            }
1163            if !diff {
1164                self.write_cell(f, "", index, cell, metadata)?;
1165            } else if changes.unalived_cells.contains(&index) {
1166                self.write_cell(f, removed, index, cell, metadata)?;
1167            } else {
1168                let mut mapped_cell;
1169                if let Some(replaced_cell) = changes.replaced_cells.get(&index) {
1170                    mapped_cell = (*replaced_cell.get()).clone();
1171                } else {
1172                    mapped_cell = cell.clone();
1173                }
1174                mapped_cell.visit_mut(|net| {
1175                    while let Some(&new_net) = changes.replaced_nets.get(net) {
1176                        *net = new_net;
1177                    }
1178                });
1179                if index >= self.cells.len() {
1180                    self.write_cell(f, added, index, &mapped_cell, metadata)?;
1181                } else if mapped_cell != *cell {
1182                    self.write_cell(f, removed, index, cell, metadata)?;
1183                    writeln!(f)?;
1184                    self.write_cell(f, added, index, &mapped_cell, metadata)?;
1185                } else {
1186                    self.write_cell(f, unchanged, index, cell, metadata)?;
1187                }
1188            }
1189            writeln!(f)
1190        };
1191
1192        if f.alternate() {
1193            for cell_ref in self.iter_cells() {
1194                write_cell(f, cell_ref.index, &cell_ref.get(), cell_ref.metadata_index())?;
1195            }
1196        } else {
1197            for cell_ref in self.iter_cells_topo() {
1198                write_cell(f, cell_ref.index, &cell_ref.get(), cell_ref.metadata_index())?;
1199            }
1200        }
1201        for (offset, cell) in changes.added_cells.iter().enumerate() {
1202            if !matches!(cell.repr, CellRepr::Skip(_) | CellRepr::Void) {
1203                write_cell(f, self.cells.len() + offset, &cell.get(), cell.meta)?;
1204            }
1205        }
1206
1207        Ok(())
1208    }
1209}