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 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 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 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 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 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 ($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 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 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 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
1007impl 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}