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#[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 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 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 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 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 ($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 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 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 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
1027impl 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}