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