1use crate::guard::StaticTiming;
4use crate::Nothing;
5
6use super::{
7 Attributes, Direction, GetAttributes, Guard, Id, PortDef, RRC, WRC,
8};
9use calyx_frontend::Attribute;
10use calyx_utils::{CalyxResult, Error, GetName};
11use itertools::Itertools;
12use smallvec::{smallvec, SmallVec};
13use std::hash::Hash;
14use std::rc::Rc;
15
16#[derive(Debug, Clone)]
18pub enum PortParent {
19 Cell(WRC<Cell>),
20 Group(WRC<Group>),
21 StaticGroup(WRC<StaticGroup>),
22}
23
24#[derive(Debug, Clone)]
26#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
27pub struct Port {
28 pub name: Id,
30 pub width: u64,
32 pub direction: Direction,
34 pub parent: PortParent,
36 pub attributes: Attributes,
38}
39
40#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
42pub struct Canonical {
43 pub cell: Id,
44 pub port: Id,
45}
46
47impl Canonical {
48 pub const fn new(cell: Id, port: Id) -> Self {
49 Self { cell, port }
50 }
51}
52
53impl std::fmt::Display for Canonical {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 write!(f, "{}.{}", self.cell, self.port)
56 }
57}
58
59impl Port {
60 pub fn is_hole(&self) -> bool {
62 matches!(&self.parent, PortParent::Group(_))
63 || matches!(&self.parent, PortParent::StaticGroup(_))
64 }
65
66 pub fn cell_parent(&self) -> RRC<Cell> {
69 if let PortParent::Cell(cell_wref) = &self.parent {
70 return cell_wref.upgrade();
71 }
72 unreachable!("This port should have a cell parent")
73 }
74
75 pub fn is_constant(&self, val: u64, width: u64) -> bool {
77 if let PortParent::Cell(cell) = &self.parent {
78 match cell.upgrade().borrow().prototype {
79 CellType::Constant { val: v, width: w } => {
80 v == val && width == w
81 }
82 _ => false,
83 }
84 } else {
85 false
86 }
87 }
88
89 pub fn get_parent_name(&self) -> Id {
91 match &self.parent {
92 PortParent::Cell(cell) => cell.upgrade().borrow().name,
93 PortParent::Group(group) => group.upgrade().borrow().name,
94 PortParent::StaticGroup(group) => group.upgrade().borrow().name,
95 }
96 }
97
98 pub fn parent_is_comb(&self) -> bool {
100 match &self.parent {
101 PortParent::Cell(cell) => cell.upgrade().borrow().is_comb_cell(),
102 _ => false,
103 }
104 }
105
106 pub fn canonical(&self) -> Canonical {
108 Canonical {
109 cell: self.get_parent_name(),
110 port: self.name,
111 }
112 }
113
114 pub fn get_attribute<A>(&self, attr: A) -> Option<u64>
116 where
117 A: Into<Attribute>,
118 {
119 self.get_attributes().get(attr)
120 }
121
122 pub fn has_attribute<A>(&self, attr: A) -> bool
124 where
125 A: Into<Attribute>,
126 {
127 self.get_attributes().has(attr)
128 }
129}
130
131impl GetAttributes for Port {
132 fn get_attributes(&self) -> &Attributes {
133 &self.attributes
134 }
135
136 fn get_mut_attributes(&mut self) -> &mut Attributes {
137 &mut self.attributes
138 }
139}
140
141impl PartialEq for Port {
142 fn eq(&self, other: &Self) -> bool {
143 self.get_parent_name() == other.get_parent_name()
144 && self.name == other.name
145 }
146}
147
148impl Eq for Port {}
149
150pub struct PortIterator<'a> {
153 port_iter: Box<dyn Iterator<Item = RRC<Port>> + 'a>,
154}
155
156impl<'a> PortIterator<'a> {
157 pub fn new<T>(iter: T) -> Self
159 where
160 T: Iterator<Item = RRC<Port>> + 'a,
161 {
162 PortIterator {
163 port_iter: Box::new(iter),
164 }
165 }
166
167 pub fn empty() -> Self {
169 PortIterator {
170 port_iter: Box::new(std::iter::empty()),
171 }
172 }
173}
174
175impl Iterator for PortIterator<'_> {
176 type Item = RRC<Port>;
177
178 fn next(&mut self) -> Option<Self::Item> {
179 self.port_iter.next()
180 }
181}
182
183pub type Binding = SmallVec<[(Id, u64); 5]>;
185
186#[derive(Debug, PartialEq, Eq, Hash, Clone)]
188#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
189pub enum CellType {
190 Primitive {
192 name: Id,
194 param_binding: Box<Binding>,
196 is_comb: bool,
198 latency: Option<std::num::NonZeroU64>,
200 },
201 Component {
203 name: Id,
205 },
206 ThisComponent,
208 Constant {
210 val: u64,
212 width: u64,
214 },
215}
216
217impl CellType {
218 pub fn get_name(&self) -> Option<Id> {
220 match self {
221 CellType::Primitive { name, .. } | CellType::Component { name } => {
222 Some(*name)
223 }
224 CellType::ThisComponent | CellType::Constant { .. } => None,
225 }
226 }
227
228 pub fn surface_name(&self) -> Option<String> {
230 match self {
231 CellType::Primitive {
232 name,
233 param_binding,
234 ..
235 } => Some(format!(
236 "{}({})",
237 name,
238 param_binding.iter().map(|(_, v)| v.to_string()).join(", ")
239 )),
240 CellType::Component { name } => Some(name.to_string()),
241 CellType::ThisComponent | CellType::Constant { .. } => None,
242 }
243 }
244}
245
246#[derive(Debug)]
248#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
249pub struct Cell {
250 name: Id,
252 pub ports: SmallVec<[RRC<Port>; 10]>,
254 pub prototype: CellType,
256 pub attributes: Attributes,
258 reference: bool,
260}
261
262impl GetAttributes for Cell {
263 fn get_attributes(&self) -> &Attributes {
264 &self.attributes
265 }
266
267 fn get_mut_attributes(&mut self) -> &mut Attributes {
268 &mut self.attributes
269 }
270}
271
272impl Cell {
273 pub fn new(name: Id, prototype: CellType) -> Self {
275 Self {
276 name,
277 ports: smallvec![],
278 prototype,
279 attributes: Attributes::default(),
280 reference: false,
281 }
282 }
283
284 pub fn is_reference(&self) -> bool {
286 self.reference
287 }
288
289 pub(super) fn set_reference(&mut self, reference: bool) -> bool {
291 self.reference = reference;
292 self.reference
293 }
294
295 pub fn find<S>(&self, name: S) -> Option<RRC<Port>>
297 where
298 S: std::fmt::Display + Clone,
299 Id: PartialEq<S>,
300 {
301 self.ports
302 .iter()
303 .find(|&g| g.borrow().name == name)
304 .map(Rc::clone)
305 }
306
307 pub fn find_all_with_attr<A>(
309 &self,
310 attr: A,
311 ) -> impl Iterator<Item = RRC<Port>> + '_
312 where
313 A: Into<Attribute>,
314 {
315 let attr = attr.into();
316 self.ports
317 .iter()
318 .filter(move |&p| p.borrow().attributes.has(attr))
319 .map(Rc::clone)
320 }
321
322 pub fn find_unique_with_attr<A>(
326 &self,
327 attr: A,
328 ) -> CalyxResult<Option<RRC<Port>>>
329 where
330 A: Into<Attribute>,
331 {
332 let attr = attr.into();
333 let mut ports = self.find_all_with_attr(attr);
334 if let Some(port) = ports.next() {
335 if ports.next().is_some() {
336 Err(Error::malformed_structure(format!(
337 "Multiple ports with attribute `{}` found on cell `{}`",
338 attr, self.name
339 )))
340 } else {
341 Ok(Some(port))
342 }
343 } else {
344 Ok(None)
345 }
346 }
347
348 pub fn get<S>(&self, name: S) -> RRC<Port>
351 where
352 S: std::fmt::Display + Clone,
353 Id: PartialEq<S>,
354 {
355 self.find(name.clone()).unwrap_or_else(|| {
356 panic!(
357 "Port `{name}' not found on cell `{}'. Known ports are: {}",
358 self.name,
359 self.ports
360 .iter()
361 .map(|p| p.borrow().name.to_string())
362 .join(",")
363 )
364 })
365 }
366
367 pub fn is_component(&self) -> bool {
369 matches!(&self.prototype, CellType::Component { .. })
370 }
371
372 pub fn is_this(&self) -> bool {
374 matches!(&self.prototype, CellType::ThisComponent)
375 }
376
377 pub fn is_primitive<S>(&self, prim: Option<S>) -> bool
380 where
381 Id: PartialEq<S>,
382 {
383 match &self.prototype {
384 CellType::Primitive { name, .. } => {
385 prim.as_ref().map(|p| name == p).unwrap_or(true)
386 }
387 _ => false,
388 }
389 }
390
391 pub fn get_unique_with_attr<A>(&self, attr: A) -> CalyxResult<RRC<Port>>
394 where
395 A: Into<Attribute> + std::fmt::Display + Copy,
396 {
397 Ok(self.find_unique_with_attr(attr)?.unwrap_or_else(|| {
398 panic!(
399 "Port with attribute `{attr}' not found on cell `{}'",
400 self.name,
401 )
402 }))
403 }
404
405 pub fn type_name(&self) -> Option<Id> {
407 self.prototype.get_name()
408 }
409
410 pub fn get_parameter<S>(&self, param: S) -> Option<u64>
412 where
413 Id: PartialEq<S>,
414 {
415 match &self.prototype {
416 CellType::Primitive { param_binding, .. } => param_binding
417 .iter()
418 .find(|(key, _)| *key == param)
419 .map(|(_, val)| *val),
420 CellType::Component { .. } => None,
421 CellType::ThisComponent => None,
422 CellType::Constant { .. } => None,
423 }
424 }
425
426 pub fn constant_name(val: u64, width: u64) -> Id {
429 format!("_{}_{}", val, width).into()
430 }
431
432 pub fn get_attribute<A: Into<Attribute>>(&self, attr: A) -> Option<u64> {
434 self.attributes.get(attr.into())
435 }
436
437 pub fn add_attribute<A: Into<Attribute>>(&mut self, attr: A, value: u64) {
439 self.attributes.insert(attr.into(), value);
440 }
441
442 pub fn name(&self) -> Id {
444 self.name
445 }
446
447 pub fn ports(&self) -> &SmallVec<[RRC<Port>; 10]> {
449 &self.ports
450 }
451
452 pub fn get_signature(&self) -> Vec<PortDef<u64>> {
454 self.ports
455 .iter()
456 .map(|port_ref| {
457 let port = port_ref.borrow();
458 PortDef::new(
459 port.name,
460 port.width,
461 port.direction.clone(),
462 port.attributes.clone(),
463 )
464 })
465 .collect()
466 }
467
468 pub fn is_comb_cell(&self) -> bool {
473 match self.prototype {
474 CellType::Primitive { is_comb, .. } => is_comb,
475 _ => false,
476 }
477 }
478}
479
480#[derive(Clone, Debug)]
482#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
483pub struct Assignment<T> {
484 pub dst: RRC<Port>,
486
487 pub src: RRC<Port>,
489
490 pub guard: Box<Guard<T>>,
492
493 pub attributes: Attributes,
495}
496
497impl<T> Assignment<T> {
498 pub fn new(dst: RRC<Port>, src: RRC<Port>) -> Self {
500 assert!(
501 dst.borrow().direction == Direction::Input,
502 "{} is not in input port",
503 dst.borrow().canonical()
504 );
505 assert!(
506 src.borrow().direction == Direction::Output,
507 "{} is not in output port",
508 src.borrow().canonical()
509 );
510 Self {
511 dst,
512 src,
513 guard: Box::new(Guard::True),
514 attributes: Attributes::default(),
515 }
516 }
517
518 pub fn for_each_port<F>(&mut self, mut f: F)
521 where
522 F: FnMut(&RRC<Port>) -> Option<RRC<Port>>,
523 {
524 if let Some(new_src) = f(&self.src) {
525 self.src = new_src;
526 }
527 if let Some(new_dst) = f(&self.dst) {
528 self.dst = new_dst;
529 }
530 self.guard.for_each(&mut |port| f(&port).map(Guard::port))
531 }
532}
533
534impl From<Assignment<Nothing>> for Assignment<StaticTiming> {
535 fn from(assgn: Assignment<Nothing>) -> Assignment<StaticTiming> {
537 Assignment {
538 dst: Rc::clone(&assgn.dst),
539 src: Rc::clone(&assgn.src),
540 guard: Box::new(Guard::from(*assgn.guard)),
541 attributes: assgn.attributes,
542 }
543 }
544}
545
546impl<StaticTiming> Assignment<StaticTiming> {
547 pub fn for_each_interval<F>(&mut self, mut f: F)
550 where
551 F: FnMut(&mut StaticTiming) -> Option<Guard<StaticTiming>>,
552 {
553 self.guard.for_each_info(&mut |interval| f(interval))
554 }
555}
556
557#[derive(Debug)]
559#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
560pub struct Group {
561 name: Id,
563
564 pub assignments: Vec<Assignment<Nothing>>,
566
567 pub holes: SmallVec<[RRC<Port>; 3]>,
569
570 pub attributes: Attributes,
572}
573impl Group {
574 pub fn new(name: Id) -> Self {
575 Self {
576 name,
577 assignments: vec![],
578 holes: smallvec![],
579 attributes: Attributes::default(),
580 }
581 }
582
583 pub fn find<S>(&self, name: S) -> Option<RRC<Port>>
585 where
586 S: std::fmt::Display,
587 Id: PartialEq<S>,
588 {
589 self.holes
590 .iter()
591 .find(|&g| g.borrow().name == name)
592 .map(Rc::clone)
593 }
594
595 pub fn get<S>(&self, name: S) -> RRC<Port>
597 where
598 S: std::fmt::Display + Clone,
599 Id: PartialEq<S>,
600 {
601 self.find(name.clone()).unwrap_or_else(|| {
602 panic!("Hole `{name}' not found on group `{}'", self.name)
603 })
604 }
605
606 fn find_done_cond(&self) -> usize {
608 self.assignments
609 .iter()
610 .position(|assign| {
611 let dst = assign.dst.borrow();
612 dst.is_hole() && dst.name == "done"
613 })
614 .unwrap_or_else(|| {
615 panic!("Group `{}' has no done condition", self.name)
616 })
617 }
618
619 pub fn done_cond(&self) -> &Assignment<Nothing> {
621 let idx = self.find_done_cond();
622 &self.assignments[idx]
623 }
624
625 pub fn done_cond_mut(&mut self) -> &mut Assignment<Nothing> {
628 let idx = self.find_done_cond();
629 &mut self.assignments[idx]
630 }
631
632 #[inline]
634 pub fn name(&self) -> Id {
635 self.name
636 }
637
638 #[inline]
640 pub fn get_attributes(&self) -> Option<&Attributes> {
641 Some(&self.attributes)
642 }
643
644 pub fn remove_attribute(&mut self, attr: Attribute) {
645 self.attributes.remove(attr);
646 }
647}
648
649#[derive(Debug)]
651#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
652pub struct StaticGroup {
653 name: Id,
655
656 pub assignments: Vec<Assignment<StaticTiming>>,
658
659 pub holes: SmallVec<[RRC<Port>; 3]>,
661
662 pub attributes: Attributes,
664
665 pub latency: u64,
667}
668
669impl StaticGroup {
671 pub fn new(name: Id, latency: u64) -> Self {
672 Self {
673 name,
674 assignments: vec![],
675 holes: smallvec![],
676 attributes: Attributes::default(),
677 latency,
678 }
679 }
680
681 pub fn get_latency(&self) -> u64 {
682 self.latency
683 }
684
685 pub fn find<S>(&self, name: S) -> Option<RRC<Port>>
687 where
688 S: std::fmt::Display,
689 Id: PartialEq<S>,
690 {
691 self.holes
692 .iter()
693 .find(|&g| g.borrow().name == name)
694 .map(Rc::clone)
695 }
696
697 pub fn get<S>(&self, name: S) -> RRC<Port>
699 where
700 S: std::fmt::Display + Clone,
701 Id: PartialEq<S>,
702 {
703 self.find(name.clone()).unwrap_or_else(|| {
704 panic!("Hole `{name}' not found on group `{}'", self.name)
705 })
706 }
707
708 #[inline]
710 pub fn name(&self) -> Id {
711 self.name
712 }
713
714 #[inline]
716 pub fn get_attributes(&self) -> Option<&Attributes> {
717 Some(&self.attributes)
718 }
719
720 pub fn remove_attribute(&mut self, attr: Attribute) {
721 self.attributes.remove(attr);
722 }
723}
724
725#[derive(Debug)]
729#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
730pub struct CombGroup {
731 pub(super) name: Id,
733
734 pub assignments: Vec<Assignment<Nothing>>,
736
737 pub attributes: Attributes,
739}
740impl CombGroup {
741 #[inline]
743 pub fn name(&self) -> Id {
744 self.name
745 }
746
747 #[inline]
749 pub fn get_attributes(&self) -> Option<&Attributes> {
750 Some(&self.attributes)
751 }
752}
753
754impl GetName for Cell {
755 fn name(&self) -> Id {
756 self.name()
757 }
758}
759
760impl GetName for Group {
761 fn name(&self) -> Id {
762 self.name()
763 }
764}
765
766impl GetName for CombGroup {
767 fn name(&self) -> Id {
768 self.name()
769 }
770}
771
772impl GetName for StaticGroup {
773 fn name(&self) -> Id {
774 self.name()
775 }
776}