1use crate::Nothing;
4use crate::guard::StaticTiming;
5
6use super::{
7 Attributes, Direction, GetAttributes, Guard, Id, PortDef, RRC, WRC,
8};
9use calyx_frontend::{Attribute, BoolAttr};
10use calyx_utils::{CalyxResult, Error, GetName};
11use itertools::Itertools;
12use smallvec::{SmallVec, smallvec};
13use std::collections::HashMap;
14use std::hash::Hash;
15use std::rc::Rc;
16
17#[derive(Debug, Clone)]
19pub enum PortParent {
20 Cell(WRC<Cell>),
21 Group(WRC<Group>),
22 StaticGroup(WRC<StaticGroup>),
23 FSM(WRC<FSM>),
24}
25
26#[derive(Debug, Clone)]
28#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
29pub struct Port {
30 pub name: Id,
32 pub width: u64,
34 pub direction: Direction,
36 pub parent: PortParent,
38 pub attributes: Attributes,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub struct Canonical {
45 pub cell: Id,
46 pub port: Id,
47}
48
49impl Canonical {
50 pub const fn new(cell: Id, port: Id) -> Self {
51 Self { cell, port }
52 }
53}
54
55impl std::fmt::Display for Canonical {
56 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57 write!(f, "{}.{}", self.cell, self.port)
58 }
59}
60
61impl Port {
62 pub fn is_hole(&self) -> bool {
64 matches!(&self.parent, PortParent::Group(_))
65 || matches!(&self.parent, PortParent::StaticGroup(_))
66 }
67
68 pub fn cell_parent(&self) -> RRC<Cell> {
71 if let PortParent::Cell(cell_wref) = &self.parent {
72 return cell_wref.upgrade();
73 }
74 unreachable!("This port should have a cell parent")
75 }
76
77 pub fn is_constant(&self, val: u64, width: u64) -> bool {
79 if let PortParent::Cell(cell) = &self.parent {
80 match cell.upgrade().borrow().prototype {
81 CellType::Constant { val: v, width: w } => {
82 v == val && width == w
83 }
84 _ => false,
85 }
86 } else {
87 false
88 }
89 }
90
91 pub fn get_parent_name(&self) -> Id {
93 match &self.parent {
94 PortParent::Cell(cell) => cell.upgrade().borrow().name,
95 PortParent::Group(group) => group.upgrade().borrow().name,
96 PortParent::FSM(fsm) => fsm.upgrade().borrow().name,
97 PortParent::StaticGroup(group) => group.upgrade().borrow().name,
98 }
99 }
100
101 pub fn parent_is_comb(&self) -> bool {
103 match &self.parent {
104 PortParent::Cell(cell) => cell.upgrade().borrow().is_comb_cell(),
105 _ => false,
106 }
107 }
108
109 pub fn parent_is_protected(&self) -> bool {
111 match &self.parent {
112 PortParent::Cell(cell) => {
113 cell.upgrade().borrow().attributes.has(BoolAttr::Protected)
114 }
115 _ => false,
116 }
117 }
118
119 pub fn parent_is_fsm(&self) -> bool {
121 matches!(&self.parent, PortParent::FSM(..))
122 }
123
124 pub fn canonical(&self) -> Canonical {
126 Canonical {
127 cell: self.get_parent_name(),
128 port: self.name,
129 }
130 }
131
132 pub fn get_attribute<A>(&self, attr: A) -> Option<u64>
134 where
135 A: Into<Attribute>,
136 {
137 self.get_attributes().get(attr)
138 }
139
140 pub fn has_attribute<A>(&self, attr: A) -> bool
142 where
143 A: Into<Attribute>,
144 {
145 self.get_attributes().has(attr)
146 }
147
148 pub fn type_equivalent(&self, other: &Port) -> bool {
151 self.width == other.width
152 && self.direction == other.direction
153 && self.name == other.name
154 && self.attributes == other.attributes
155 }
156}
157
158impl GetAttributes for Port {
159 fn get_attributes(&self) -> &Attributes {
160 &self.attributes
161 }
162
163 fn get_mut_attributes(&mut self) -> &mut Attributes {
164 &mut self.attributes
165 }
166}
167
168impl PartialEq for Port {
169 fn eq(&self, other: &Self) -> bool {
170 self.get_parent_name() == other.get_parent_name()
171 && self.name == other.name
172 }
173}
174
175impl Eq for Port {}
176
177pub struct PortIterator<'a> {
180 port_iter: Box<dyn Iterator<Item = RRC<Port>> + 'a>,
181}
182
183impl<'a> PortIterator<'a> {
184 pub fn new<T>(iter: T) -> Self
186 where
187 T: Iterator<Item = RRC<Port>> + 'a,
188 {
189 PortIterator {
190 port_iter: Box::new(iter),
191 }
192 }
193
194 pub fn empty() -> Self {
196 PortIterator {
197 port_iter: Box::new(std::iter::empty()),
198 }
199 }
200}
201
202impl Iterator for PortIterator<'_> {
203 type Item = RRC<Port>;
204
205 fn next(&mut self) -> Option<Self::Item> {
206 self.port_iter.next()
207 }
208}
209
210pub type Binding = SmallVec<[(Id, u64); 5]>;
212
213#[derive(Debug, PartialEq, Eq, Hash, Clone)]
215#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
216pub enum CellType {
217 Primitive {
219 name: Id,
221 param_binding: Box<Binding>,
223 is_comb: bool,
225 latency: Option<std::num::NonZeroU64>,
227 },
228 Component {
230 name: Id,
232 },
233 ThisComponent,
235 Constant {
237 val: u64,
239 width: u64,
241 },
242}
243
244impl CellType {
245 pub fn get_name(&self) -> Option<Id> {
247 match self {
248 CellType::Primitive { name, .. } | CellType::Component { name } => {
249 Some(*name)
250 }
251 CellType::ThisComponent | CellType::Constant { .. } => None,
252 }
253 }
254
255 pub fn surface_name(&self) -> Option<String> {
257 match self {
258 CellType::Primitive {
259 name,
260 param_binding,
261 ..
262 } => Some(format!(
263 "{}({})",
264 name,
265 param_binding.iter().map(|(_, v)| v.to_string()).join(", ")
266 )),
267 CellType::Component { name } => Some(name.to_string()),
268 CellType::ThisComponent | CellType::Constant { .. } => None,
269 }
270 }
271}
272
273#[derive(Debug, Clone)]
275#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
276pub struct Cell {
277 name: Id,
279 pub ports: SmallVec<[RRC<Port>; 10]>,
281 pub prototype: CellType,
283 pub attributes: Attributes,
285 reference: bool,
287}
288
289impl GetAttributes for Cell {
290 fn get_attributes(&self) -> &Attributes {
291 &self.attributes
292 }
293
294 fn get_mut_attributes(&mut self) -> &mut Attributes {
295 &mut self.attributes
296 }
297}
298
299impl Cell {
300 pub fn new(name: Id, prototype: CellType) -> Self {
302 Self {
303 name,
304 ports: smallvec![],
305 prototype,
306 attributes: Attributes::default(),
307 reference: false,
308 }
309 }
310
311 pub fn is_reference(&self) -> bool {
313 self.reference
314 }
315
316 pub fn set_reference(&mut self, reference: bool) -> bool {
318 self.reference = reference;
319 self.reference
320 }
321
322 pub fn find<S>(&self, name: S) -> Option<RRC<Port>>
324 where
325 S: std::fmt::Display + Clone,
326 Id: PartialEq<S>,
327 {
328 self.ports
329 .iter()
330 .find(|&g| g.borrow().name == name)
331 .map(Rc::clone)
332 }
333
334 pub fn find_all_with_attr<A>(
336 &self,
337 attr: A,
338 ) -> impl Iterator<Item = RRC<Port>> + '_
339 where
340 A: Into<Attribute>,
341 {
342 let attr = attr.into();
343 self.ports
344 .iter()
345 .filter(move |&p| p.borrow().attributes.has(attr))
346 .map(Rc::clone)
347 }
348
349 pub fn find_unique_with_attr<A>(
353 &self,
354 attr: A,
355 ) -> CalyxResult<Option<RRC<Port>>>
356 where
357 A: Into<Attribute>,
358 {
359 let attr = attr.into();
360 let mut ports = self.find_all_with_attr(attr);
361 if let Some(port) = ports.next() {
362 if ports.next().is_some() {
363 Err(Error::malformed_structure(format!(
364 "Multiple ports with attribute `{}` found on cell `{}`",
365 attr, self.name
366 )))
367 } else {
368 Ok(Some(port))
369 }
370 } else {
371 Ok(None)
372 }
373 }
374
375 pub fn get<S>(&self, name: S) -> RRC<Port>
378 where
379 S: std::fmt::Display + Clone,
380 Id: PartialEq<S>,
381 {
382 self.find(name.clone()).unwrap_or_else(|| {
383 panic!(
384 "Port `{name}' not found on cell `{}'. Known ports are: {}",
385 self.name,
386 self.ports
387 .iter()
388 .map(|p| p.borrow().name.to_string())
389 .join(",")
390 )
391 })
392 }
393
394 pub fn is_component(&self) -> bool {
396 matches!(&self.prototype, CellType::Component { .. })
397 }
398
399 pub fn is_this(&self) -> bool {
401 matches!(&self.prototype, CellType::ThisComponent)
402 }
403
404 pub fn is_primitive<S>(&self, prim: Option<S>) -> bool
407 where
408 Id: PartialEq<S>,
409 {
410 match &self.prototype {
411 CellType::Primitive { name, .. } => {
412 prim.as_ref().map(|p| name == p).unwrap_or(true)
413 }
414 _ => false,
415 }
416 }
417
418 pub fn get_unique_with_attr<A>(&self, attr: A) -> CalyxResult<RRC<Port>>
421 where
422 A: Into<Attribute> + std::fmt::Display + Copy,
423 {
424 Ok(self.find_unique_with_attr(attr)?.unwrap_or_else(|| {
425 panic!(
426 "Port with attribute `{attr}' not found on cell `{}'",
427 self.name,
428 )
429 }))
430 }
431
432 pub fn type_name(&self) -> Option<Id> {
434 self.prototype.get_name()
435 }
436
437 pub fn get_parameter<S>(&self, param: S) -> Option<u64>
439 where
440 Id: PartialEq<S>,
441 {
442 match &self.prototype {
443 CellType::Primitive { param_binding, .. } => param_binding
444 .iter()
445 .find(|(key, _)| *key == param)
446 .map(|(_, val)| *val),
447 CellType::Component { .. } => None,
448 CellType::ThisComponent => None,
449 CellType::Constant { .. } => None,
450 }
451 }
452
453 pub fn constant_name(val: u64, width: u64) -> Id {
456 format!("_{val}_{width}").into()
457 }
458
459 pub fn get_attribute<A: Into<Attribute>>(&self, attr: A) -> Option<u64> {
461 self.attributes.get(attr.into())
462 }
463
464 pub fn add_attribute<A: Into<Attribute>>(&mut self, attr: A, value: u64) {
466 self.attributes.insert(attr.into(), value);
467 }
468
469 pub fn name(&self) -> Id {
471 self.name
472 }
473
474 pub fn ports(&self) -> &SmallVec<[RRC<Port>; 10]> {
476 &self.ports
477 }
478
479 pub fn get_signature(&self) -> Vec<PortDef<u64>> {
481 self.ports
482 .iter()
483 .map(|port_ref| {
484 let port = port_ref.borrow();
485 PortDef::new(
486 port.name,
487 port.width,
488 port.direction.clone(),
489 port.attributes.clone(),
490 )
491 })
492 .collect()
493 }
494
495 pub fn is_comb_cell(&self) -> bool {
500 match self.prototype {
501 CellType::Primitive { is_comb, .. } => is_comb,
502 _ => false,
503 }
504 }
505}
506
507#[derive(Clone, Debug)]
509#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
510pub struct Assignment<T> {
511 pub dst: RRC<Port>,
513
514 pub src: RRC<Port>,
516
517 pub guard: Box<Guard<T>>,
519
520 pub attributes: Attributes,
522}
523
524impl<T> Assignment<T> {
525 pub fn new(dst: RRC<Port>, src: RRC<Port>) -> Self {
527 assert!(
528 dst.borrow().direction == Direction::Input,
529 "{} is not in input port",
530 dst.borrow().canonical()
531 );
532 assert!(
533 src.borrow().direction == Direction::Output,
534 "{} is not in output port",
535 src.borrow().canonical()
536 );
537 Self {
538 dst,
539 src,
540 guard: Box::new(Guard::True),
541 attributes: Attributes::default(),
542 }
543 }
544
545 pub fn for_each_port<F>(&mut self, mut f: F)
548 where
549 F: FnMut(&RRC<Port>) -> Option<RRC<Port>>,
550 {
551 if let Some(new_src) = f(&self.src) {
552 self.src = new_src;
553 }
554 if let Some(new_dst) = f(&self.dst) {
555 self.dst = new_dst;
556 }
557 self.guard.for_each(&mut |port| f(&port).map(Guard::port))
558 }
559
560 pub fn iter_ports(&self) -> impl Iterator<Item = RRC<Port>> {
562 self.guard
563 .all_ports()
564 .into_iter()
565 .chain(std::iter::once(Rc::clone(&self.dst)))
566 .chain(std::iter::once(Rc::clone(&self.src)))
567 }
568
569 pub fn and_guard(&mut self, addition: Guard<T>)
571 where
572 T: Eq,
573 {
574 if !(addition.is_true()) {
575 self.guard.update(|g| g.and(addition));
576 }
577 }
578}
579
580impl From<Assignment<Nothing>> for Assignment<StaticTiming> {
581 fn from(assgn: Assignment<Nothing>) -> Assignment<StaticTiming> {
583 Assignment {
584 dst: Rc::clone(&assgn.dst),
585 src: Rc::clone(&assgn.src),
586 guard: Box::new(Guard::from(*assgn.guard)),
587 attributes: assgn.attributes,
588 }
589 }
590}
591
592impl From<Assignment<StaticTiming>> for Assignment<Nothing> {
593 fn from(mut assgn: Assignment<StaticTiming>) -> Assignment<Nothing> {
596 assgn.guard.as_mut().remove_static_timing_info();
597 Assignment {
598 dst: Rc::clone(&assgn.dst),
599 src: Rc::clone(&assgn.src),
600 guard: Box::new(Guard::from(*assgn.guard)),
601 attributes: assgn.attributes,
602 }
603 }
604}
605
606impl<StaticTiming> Assignment<StaticTiming> {
607 pub fn for_each_interval<F>(&mut self, mut f: F)
610 where
611 F: FnMut(&mut StaticTiming) -> Option<Guard<StaticTiming>>,
612 {
613 self.guard.for_each_info(&mut |interval| f(interval))
614 }
615}
616
617#[derive(Debug, Clone)]
618#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
619pub enum Transition {
620 Unconditional(u64),
621 Conditional(Vec<(Guard<Nothing>, u64)>),
622}
623
624impl Transition {
625 pub fn new_uncond(s: u64) -> Self {
626 Self::Unconditional(s)
627 }
628}
629
630#[derive(Debug)]
632#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
633pub struct Group {
634 name: Id,
636
637 pub assignments: Vec<Assignment<Nothing>>,
639
640 pub holes: SmallVec<[RRC<Port>; 3]>,
642
643 pub attributes: Attributes,
645}
646impl Group {
647 pub fn new(name: Id) -> Self {
648 Self {
649 name,
650 assignments: vec![],
651 holes: smallvec![],
652 attributes: Attributes::default(),
653 }
654 }
655
656 pub fn find<S>(&self, name: S) -> Option<RRC<Port>>
658 where
659 S: std::fmt::Display,
660 Id: PartialEq<S>,
661 {
662 self.holes
663 .iter()
664 .find(|&g| g.borrow().name == name)
665 .map(Rc::clone)
666 }
667
668 pub fn get<S>(&self, name: S) -> RRC<Port>
670 where
671 S: std::fmt::Display + Clone,
672 Id: PartialEq<S>,
673 {
674 self.find(name.clone()).unwrap_or_else(|| {
675 panic!("Hole `{name}' not found on group `{}'", self.name)
676 })
677 }
678
679 fn find_done_cond(&self) -> usize {
681 self.assignments
682 .iter()
683 .position(|assign| {
684 let dst = assign.dst.borrow();
685 dst.is_hole() && dst.name == "done"
686 })
687 .unwrap_or_else(|| {
688 panic!("Group `{}' has no done condition", self.name)
689 })
690 }
691
692 pub fn done_cond(&self) -> &Assignment<Nothing> {
694 let idx = self.find_done_cond();
695 &self.assignments[idx]
696 }
697
698 pub fn done_cond_mut(&mut self) -> &mut Assignment<Nothing> {
701 let idx = self.find_done_cond();
702 &mut self.assignments[idx]
703 }
704
705 #[inline]
707 pub fn name(&self) -> Id {
708 self.name
709 }
710
711 #[inline]
713 pub fn get_attributes(&self) -> Option<&Attributes> {
714 Some(&self.attributes)
715 }
716
717 pub fn remove_attribute(&mut self, attr: Attribute) {
718 self.attributes.remove(attr);
719 }
720}
721
722#[derive(Debug)]
724#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
725pub struct StaticGroup {
726 name: Id,
728
729 pub assignments: Vec<Assignment<StaticTiming>>,
731
732 pub holes: SmallVec<[RRC<Port>; 3]>,
734
735 pub attributes: Attributes,
737
738 pub latency: u64,
740}
741
742impl StaticGroup {
744 pub fn new(name: Id, latency: u64) -> Self {
745 Self {
746 name,
747 assignments: vec![],
748 holes: smallvec![],
749 attributes: Attributes::default(),
750 latency,
751 }
752 }
753
754 pub fn get_latency(&self) -> u64 {
755 self.latency
756 }
757
758 pub fn find<S>(&self, name: S) -> Option<RRC<Port>>
760 where
761 S: std::fmt::Display,
762 Id: PartialEq<S>,
763 {
764 self.holes
765 .iter()
766 .find(|&g| g.borrow().name == name)
767 .map(Rc::clone)
768 }
769
770 pub fn get<S>(&self, name: S) -> RRC<Port>
772 where
773 S: std::fmt::Display + Clone,
774 Id: PartialEq<S>,
775 {
776 self.find(name.clone()).unwrap_or_else(|| {
777 panic!("Hole `{name}' not found on group `{}'", self.name)
778 })
779 }
780
781 #[inline]
783 pub fn name(&self) -> Id {
784 self.name
785 }
786
787 #[inline]
789 pub fn get_attributes(&self) -> Option<&Attributes> {
790 Some(&self.attributes)
791 }
792
793 pub fn remove_attribute(&mut self, attr: Attribute) {
794 self.attributes.remove(attr);
795 }
796}
797
798#[derive(Debug)]
802#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
803pub struct CombGroup {
804 pub(super) name: Id,
806
807 pub assignments: Vec<Assignment<Nothing>>,
809
810 pub attributes: Attributes,
812}
813impl CombGroup {
814 #[inline]
816 pub fn name(&self) -> Id {
817 self.name
818 }
819
820 #[inline]
822 pub fn get_attributes(&self) -> Option<&Attributes> {
823 Some(&self.attributes)
824 }
825}
826
827#[derive(Debug)]
828#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
829pub struct FSM {
830 pub(super) name: Id,
832 pub attributes: Attributes,
834 pub assignments: Vec<Vec<Assignment<Nothing>>>,
836 pub transitions: Vec<Transition>,
838 pub wires: SmallVec<[RRC<Port>; 2]>,
840}
841
842impl FSM {
843 pub fn name(&self) -> Id {
845 self.name
846 }
847
848 pub fn new(name: Id) -> Self {
850 Self {
851 name,
852 assignments: vec![],
853 transitions: vec![],
854 wires: SmallVec::new(),
855 attributes: Attributes::default(),
856 }
857 }
858
859 pub fn num_states(&self) -> u64 {
861 self.assignments.len().try_into().unwrap()
862 }
863
864 pub fn find<S>(&self, name: S) -> Option<RRC<Port>>
866 where
867 S: std::fmt::Display,
868 Id: PartialEq<S>,
869 {
870 self.wires
871 .iter()
872 .find(|&g| g.borrow().name == name)
873 .map(Rc::clone)
874 }
875
876 pub fn get<S>(&self, name: S) -> RRC<Port>
877 where
878 S: std::fmt::Display + Clone,
879 Id: PartialEq<S>,
880 {
881 self.find(name.clone()).unwrap_or_else(|| {
882 panic!("Wire `{name}' not found on group `{}'", self.name)
883 })
884 }
885
886 pub fn extend_fsm<A, T>(&mut self, assigns: A, transitions: T)
889 where
890 A: IntoIterator<Item = Vec<Assignment<Nothing>>>,
891 T: IntoIterator<Item = Transition>,
892 {
893 self.assignments.extend(assigns);
894 self.transitions.extend(transitions);
895 }
896
897 pub fn extend_state_assignments<I>(&mut self, state: u64, assigns: I)
899 where
900 I: IntoIterator<Item = Assignment<Nothing>>,
901 {
902 let msg = format!("State {state} does not exist in FSM");
903 self.assignments
904 .get_mut(state as usize)
905 .expect(&msg)
906 .extend(assigns);
907 }
908
909 pub fn get_called_port_parents<F>(&self, push_parent_name: F) -> Vec<Id>
913 where
914 F: Fn(&mut Vec<Id>, &RRC<Port>),
915 {
916 self.transitions
917 .iter()
918 .zip(self.assignments.iter())
919 .flat_map(|(state_transitions, state_assignments)| {
920 let mut parent_names = vec![];
921
922 if let Transition::Conditional(conds) = state_transitions {
924 for (guard, _) in conds.iter() {
925 guard.all_ports().iter().for_each(|port| {
926 push_parent_name(&mut parent_names, port)
927 });
928 }
929 }
930 for assign in state_assignments.iter() {
932 assign.iter_ports().for_each(|port| {
933 push_parent_name(&mut parent_names, &port);
934 });
935 }
936 parent_names
937 })
938 .collect()
939 }
940
941 pub fn merge_assignments(&self) -> Vec<Vec<(usize, Assignment<Nothing>)>> {
945 let mut assigns_by_port: HashMap<
946 Canonical,
947 Vec<(usize, Assignment<Nothing>)>,
948 > = HashMap::new();
949 for (case, assigns_at_state) in self.assignments.iter().enumerate() {
950 for assign in assigns_at_state.iter() {
951 let dest_port = assign.dst.borrow().canonical();
952 assigns_by_port
953 .entry(dest_port)
954 .and_modify(|assigns_at_port| {
955 assigns_at_port.push((case, assign.clone()));
956 })
957 .or_insert(vec![(case, assign.clone())]);
958 }
959 }
960 assigns_by_port
961 .into_values()
962 .sorted_by(|a, b| a.first().unwrap().0.cmp(&b.first().unwrap().0))
964 .collect()
965 }
966}
967
968impl GetName for Cell {
969 fn name(&self) -> Id {
970 self.name()
971 }
972}
973
974impl GetName for Group {
975 fn name(&self) -> Id {
976 self.name()
977 }
978}
979
980impl GetName for CombGroup {
981 fn name(&self) -> Id {
982 self.name()
983 }
984}
985
986impl GetName for FSM {
987 fn name(&self) -> Id {
988 self.name()
989 }
990}
991
992impl GetName for StaticGroup {
993 fn name(&self) -> Id {
994 self.name()
995 }
996}