1use std::sync::atomic::AtomicU32;
8use std::sync::atomic::Ordering;
9
10use fnv::FnvHashMap;
11use libreda_db::reference_access::*;
12use libreda_db::traits::*;
13use pargraph::id_rwlock::IdLockWriteGuard;
14use petgraph::visit::EdgeRef;
15use smallvec::SmallVec;
16
17use crate::traits::CellConstraintModel;
18use crate::traits::ConstraintBase;
19use crate::traits::{CellDelayModel, TimingBase};
20use crate::RiseFall;
21use crate::StaError;
22use crate::PATH_SEPARATOR;
23use fnv::FnvHashSet;
24use libreda_db::prelude as db;
25use pargraph::id_rwlock::IdLockReadGuard;
26use pargraph::BorrowDataCell;
27use pargraph::DataCell;
28use petgraph::prelude::NodeIndex;
29use petgraph::stable_graph::StableDiGraph;
30
31#[derive(Debug)]
35pub(crate) struct NodeData<N, D>
36where
37 N: NetlistIds,
38 D: TimingBase + ConstraintBase,
39{
40 pub node_type: GraphNodeType<N>,
42 sync_data: DataCell<SyncNodeData<D>>,
44 pub forward_level: AtomicU32,
46 pub forward_dependencies: DependencyCounter,
48 pub backward_dependencies: DependencyCounter,
52 pub generation_forward: AtomicU32,
55 pub generation_backward: AtomicU32,
58}
59
60impl<N, D> NodeData<N, D>
61where
62 N: NetlistBase,
63 D: TimingBase + ConstraintBase,
64{
65 pub fn new(node_type: GraphNodeType<N>) -> Self {
66 Self {
67 node_type,
68 sync_data: Default::default(),
69 forward_level: Default::default(),
70 generation_forward: Default::default(),
71 generation_backward: Default::default(),
72 forward_dependencies: Default::default(),
73 backward_dependencies: Default::default(),
74 }
75 }
76}
77
78impl<N, D> BorrowDataCell for NodeData<N, D>
79where
80 N: NetlistBase,
81 D: TimingBase + ConstraintBase,
82{
83 type UserData = SyncNodeData<D>;
84
85 fn borrow_data_cell(&self) -> &DataCell<Self::UserData> {
86 &self.sync_data
87 }
88}
89
90#[derive(Debug, Default)]
92pub(crate) struct DependencyCounter {
93 num_unresolved: AtomicU32,
95}
96
97impl DependencyCounter {
98 pub fn num_unresolved(&self) -> u32 {
101 self.num_unresolved.load(Ordering::Relaxed)
102 }
103
104 pub fn set_num_unresolved(&self, num_unresolved: u32) {
107 self.num_unresolved.store(num_unresolved, Ordering::Relaxed);
108 }
109
110 pub fn increment_unresolved(&self) -> u32 {
113 self.num_unresolved.fetch_add(1, Ordering::Relaxed) + 1
114 }
115
116 pub fn decrement_unresolved(&self) -> u32 {
121 let r = self.num_unresolved.fetch_sub(1, Ordering::Relaxed);
122 assert!(r > 0, "integer underflow in number of dependencies");
123 r - 1
124 }
125}
126
127#[derive(Debug, Clone)]
130pub(crate) struct SyncNodeData<D>
131where
132 D: TimingBase + ConstraintBase,
133{
134 pub is_primary_input: bool,
138 pub signal: Option<D::Signal>,
141 pub required_signal: Option<D::RequiredSignal>,
144}
145
146impl<D> Default for SyncNodeData<D>
147where
148 D: TimingBase + ConstraintBase,
149{
150 fn default() -> Self {
151 Self {
152 signal: Default::default(),
153 required_signal: Default::default(),
154 is_primary_input: false,
155 }
156 }
157}
158
159#[derive(Clone)]
163pub(crate) enum GraphNodeType<N: NetlistIds> {
164 ForwardPropagationSource,
167 BackwardPropagationSource,
169 TerminalRise(db::TerminalId<N>),
172 TerminalFall(db::TerminalId<N>),
175}
176
177impl<N> std::fmt::Debug for GraphNodeType<N>
178where
179 N: NetlistIds,
180 N::PinId: std::fmt::Debug,
181 N::PinInstId: std::fmt::Debug,
182{
183 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184 match self {
185 GraphNodeType::ForwardPropagationSource => write!(f, "source"),
186 GraphNodeType::BackwardPropagationSource => write!(f, "sink"),
187 GraphNodeType::TerminalRise(t) => write!(f, "TerminalRise({:?})", t),
188 GraphNodeType::TerminalFall(t) => write!(f, "TerminalFall({:?})", t),
189 }
190 }
191}
192
193#[derive(Debug)]
194pub(crate) struct EdgeData<T: ConstraintBase> {
195 pub edge_type: GraphEdgeType,
196 pub sync_data: DataCell<SyncEdgeData<T>>,
197}
198
199impl<T> EdgeData<T>
200where
201 T: ConstraintBase,
202{
203 pub fn new(edge_type: GraphEdgeType) -> Self {
204 Self {
205 edge_type,
206 sync_data: Default::default(),
207 }
208 }
209}
210impl<D> BorrowDataCell for EdgeData<D>
211where
212 D: TimingBase + ConstraintBase,
213{
214 type UserData = SyncEdgeData<D>;
215
216 fn borrow_data_cell(&self) -> &DataCell<Self::UserData> {
217 &self.sync_data
218 }
219}
220
221#[derive(Debug, Clone)]
224pub(crate) struct SyncEdgeData<D>
225where
226 D: TimingBase + ConstraintBase,
227{
228 pub delay: Option<D::Delay>,
229 pub constraint: Option<D::Constraint>, }
231
232impl<D> Default for SyncEdgeData<D>
233where
234 D: TimingBase + ConstraintBase,
235{
236 fn default() -> Self {
237 Self {
238 delay: Default::default(),
239 constraint: Default::default(),
240 }
241 }
242}
243
244#[derive(Copy, Clone, PartialEq, Eq, Debug)]
245pub(crate) enum GraphEdgeType {
246 Delay,
247 Constraint,
248 Virtual,
249}
250
251impl GraphEdgeType {
252 pub fn is_delay_arc(&self) -> bool {
253 matches!(self, Self::Delay)
254 }
255
256 pub fn is_constraint_arc(&self) -> bool {
257 matches!(self, Self::Constraint)
258 }
259}
260
261#[derive(Debug)]
262pub(crate) struct TimingGraph<N: NetlistIds, T: ConstraintBase> {
263 pub(crate) arc_graph: StableDiGraph<NodeData<N, T>, EdgeData<T>>,
265 pub(crate) aat_source_node: NodeIndex,
268 pub(crate) rat_source_node: NodeIndex,
271 pub(crate) node2term: FnvHashMap<NodeIndex, db::TerminalId<N>>,
274 pub(crate) term2node: FnvHashMap<db::TerminalId<N>, [NodeIndex; 2]>,
277 frontier: FnvHashSet<NodeIndex>,
281}
282
283impl<N: NetlistBase, T: ConstraintBase> TimingGraph<N, T> {
284 pub fn new() -> Self {
286 let mut delay_arc_graph: StableDiGraph<_, _> = Default::default();
287 let source_node =
288 delay_arc_graph.add_node(NodeData::new(GraphNodeType::ForwardPropagationSource));
289 let sink_node =
290 delay_arc_graph.add_node(NodeData::new(GraphNodeType::BackwardPropagationSource));
291 Self {
292 arc_graph: delay_arc_graph,
293 node2term: Default::default(),
294 term2node: Default::default(),
295 aat_source_node: source_node,
296 rat_source_node: sink_node,
297 frontier: Default::default(),
298 }
299 }
300
301 pub fn get_terminal_data(
305 &self,
306 pin: &db::TerminalId<N>,
307 edge_polarity: RiseFall,
308 ) -> Option<IdLockReadGuard<SyncNodeData<T>>> {
309 let graph_node = self.term2node.get(pin)?[edge_polarity as usize];
310 self.get_node_data(graph_node)
311 }
312 pub fn get_node_data(&self, graph_node: NodeIndex) -> Option<IdLockReadGuard<SyncNodeData<T>>> {
316 self.arc_graph
317 .node_weight(graph_node)
318 .expect("node has no weight")
319 .borrow_data_cell()
320 .try_read()
321 .expect("failed to acquire read-lock")
322 .into()
323 }
324
325 pub fn get_terminal_data_mut(
329 &self,
330 pin: &db::TerminalId<N>,
331 edge_polarity: RiseFall,
332 ) -> Option<IdLockWriteGuard<SyncNodeData<T>>> {
333 let idx = match edge_polarity {
334 RiseFall::Rise => 0,
335 RiseFall::Fall => 1,
336 };
337 let graph_node = self.term2node.get(pin)?[idx];
338
339 self.get_node_data_mut(graph_node)
340 }
341
342 pub fn get_node_data_mut(
346 &self,
347 graph_node: NodeIndex,
348 ) -> Option<IdLockWriteGuard<SyncNodeData<T>>> {
349 self.arc_graph
350 .node_weight(graph_node)
351 .expect("node has no weight")
352 .borrow_data_cell()
353 .try_write(0)
354 .expect("failed to acquire write-lock")
355 .into()
356 }
357
358 pub fn take_frontier(&mut self) -> FnvHashSet<NodeIndex> {
360 std::mem::take(&mut self.frontier)
361 }
362
363 pub fn add_terminal_to_frontier(
366 &mut self,
367 terminal: &db::TerminalId<N>,
368 edge_polarity: Option<RiseFall>,
369 ) {
370 let nodes = self
371 .term2node
372 .get(terminal)
373 .expect("terminal does not exist in timing graph");
374
375 match edge_polarity {
376 Some(RiseFall::Rise) => {
377 self.add_node_to_frontier(nodes[0]);
378 }
379 Some(RiseFall::Fall) => {
380 self.add_node_to_frontier(nodes[1]);
381 }
382 None => {
383 for node in nodes {
384 self.frontier.insert(*node);
385 }
386 }
387 };
388 }
389
390 pub fn add_node_to_frontier(&mut self, node: NodeIndex) {
392 self.frontier.insert(node);
393 }
394
395 pub fn build_from_netlist<C, D>(
400 top_ref: &CellRef<N>,
401 delay_model: &D,
402 constraint_model: &C,
403 ) -> Result<Self, StaError>
404 where
405 D: CellDelayModel<N, Delay = T::Delay>,
406 C: CellConstraintModel<N, Constraint = T::Constraint>,
407 {
408 let mut timing_graph = Self::new();
410
411 for p in top_ref.each_pin() {
412 timing_graph.create_pin(p);
413 }
414
415 for inst in top_ref.each_cell_instance() {
417 timing_graph.create_cell_instance(&inst, delay_model, constraint_model);
418 }
419
420 timing_graph.create_delay_edges_inter_cell(top_ref)?;
421 timing_graph.create_primary_input_delay_arcs(top_ref);
422
423 timing_graph.frontier.insert(timing_graph.aat_source_node);
426
427 Ok(timing_graph)
428 }
429
430 pub fn create_cell_instance<C, D>(
432 &mut self,
433 inst: &CellInstRef<N>,
434 delay_model: D,
435 constraint_model: C,
436 ) where
437 D: CellDelayModel<N, Delay = T::Delay>,
438 C: CellConstraintModel<N, Constraint = T::Constraint>,
439 {
440 for p in inst.each_pin_instance() {
441 let terminal = p.into_terminal();
442 self.create_terminal(terminal.id());
443 }
444
445 self.create_delay_edges_intra_cell(inst, delay_model);
446 self.create_constraint_edges(inst, constraint_model);
447 }
448
449 pub fn remove_cell_instance(&mut self, inst: &CellInstRef<N>) {
450 for p in inst.each_pin_instance() {
451 let terminal = p.into_terminal();
452 self.remove_terminal(terminal.id());
453 }
454 }
455
456 pub fn remove_net(&mut self, net: &NetRef<N>) -> Result<(), StaError> {
458 let terminals = net.each_terminal();
459 let (sources, sinks): (Vec<_>, Vec<_>) = terminals.into_iter().partition(|t| {
461 match t {
464 db::TerminalRef::Pin(p) => p.direction().is_input(),
465 db::TerminalRef::PinInst(p) => p.pin().direction().is_output(),
466 }
467 });
468
469 if !sources.is_empty() {
470 if sources.len() != 1 {
471 log::warn!(
472 "Net must have 1 driver (has {}): {}",
473 sources.len(),
474 net.qname(PATH_SEPARATOR)
475 );
476 return Err(StaError::Other(format!(
477 "Net must have 1 driver (has {}): {}",
478 sources.len(),
479 net.qname(PATH_SEPARATOR)
480 )));
481 }
482
483 let source = sources[0].id();
484 let source_ids = self.term2node[&source];
485
486 for sink in sinks {
487 let sink_ids = self.term2node[&sink.id()];
488 for source_id in source_ids {
489 for sink_id in sink_ids {
490 let edge = self.arc_graph.find_edge(source_id, sink_id);
491 if let Some(edge) = edge {
492 self.arc_graph.remove_edge(edge);
493 }
494 }
495 }
496 }
497 }
498
499 Ok(())
500 }
501
502 pub fn connect_terminal(&mut self, t: db::TerminalRef<N>, net: Option<N::NetId>) {
504 let is_source = match &t {
505 db::TerminalRef::Pin(p) => p.direction().is_input(),
506 db::TerminalRef::PinInst(p) => p.pin().direction().is_output(),
507 };
508
509 let nodes = *self
511 .term2node
512 .get(&t.id())
513 .expect("terminal is not in timing graph");
514
515 let dir = if is_source {
516 petgraph::Direction::Outgoing
517 } else {
518 petgraph::Direction::Incoming
519 };
520
521 let edges: SmallVec<[_; 8]> = nodes
525 .iter()
526 .flat_map(|node| self.arc_graph.edges_directed(*node, dir))
527 .inspect(|e| {
529 assert_eq!(
530 e.weight().edge_type,
531 GraphEdgeType::Delay,
532 "should remove only interconnect delay arcs"
533 )
534 })
535 .map(|e| (e.source(), e.target(), e.id()))
536 .collect();
537
538 for (src, dest, edge_id) in edges {
539 debug_assert!(
540 if is_source {
542 nodes.contains(&src)
543 } else {
544 nodes.contains(&dest)
545 },
546 "this is not an interconnect edge"
547 );
548 self.arc_graph.remove_edge(edge_id);
549 self.frontier.insert(src);
550 self.frontier.insert(dest);
551 }
552
553 self.connect_nodes_to_net(t, net, is_source, nodes);
555 }
556
557 fn connect_nodes_to_net(
558 &mut self,
559 t: TerminalRef<'_, N>,
560 net: Option<N::NetId>,
561 is_source: bool,
562 nodes: [NodeIndex; 2],
563 ) {
564 let netlist = t.base();
565 if let Some(net) = net {
566 let net = netlist.net_ref(&net);
567 if is_source {
569 for sink in net.each_sink() {
570 let sink_nodes = self.term2node[&sink.id()];
571 for (node, sink_node) in nodes.into_iter().zip(sink_nodes) {
573 self.arc_graph.update_edge(
574 node,
575 sink_node,
576 EdgeData::new(GraphEdgeType::Delay),
577 );
578 self.frontier.insert(node);
579 self.frontier.remove(&sink_node); }
581 }
582 } else {
583 for source in net.each_driver() {
584 let source_nodes = self.term2node[&source.id()];
585 for (node, source_node) in nodes.into_iter().zip(source_nodes) {
587 self.arc_graph.update_edge(
590 source_node,
591 node,
592 EdgeData::new(GraphEdgeType::Delay),
593 );
594 self.frontier.insert(source_node);
595 self.frontier.remove(&node); }
597 }
598 };
599 }
600 }
601
602 pub fn create_terminal(&mut self, terminal_id: db::TerminalId<N>) {
605 debug_assert!(
606 !self.term2node.contains_key(&terminal_id),
607 "terminal is already present"
608 );
609
610 let node_types = [
611 GraphNodeType::TerminalRise(terminal_id.clone()),
612 GraphNodeType::TerminalFall(terminal_id.clone()),
613 ];
614 let node_ids = node_types.map(|t| self.arc_graph.add_node(NodeData::new(t)));
615 for node_id in &node_ids {
616 self.node2term.insert(*node_id, terminal_id.clone());
617 }
618 self.term2node.insert(terminal_id, node_ids);
619 }
620
621 fn create_pin(&mut self, pin: PinRef<N>) {
623 let terminal = pin.into_terminal();
624 self.create_terminal(terminal.id());
625 }
626
627 fn remove_terminal(&mut self, terminal: db::TerminalId<N>) {
630 let nodes = self
631 .term2node
632 .remove(&terminal)
633 .expect("pin does not exist in timing graph");
634
635 for node in nodes {
636 self.remove_node(node);
637 }
638 }
639
640 fn remove_node(&mut self, node: NodeIndex) {
642 self.arc_graph.remove_node(node);
643 self.node2term.remove(&node).expect("node does not exist");
644 }
645
646 pub fn remove_pin(&mut self, pin: N::PinId) {
649 let terminal = db::TerminalId::PinId(pin);
650 self.remove_terminal(terminal)
651 }
652
653 pub fn remove_pin_instance(&mut self, pin: N::PinInstId) {
656 let terminal = db::TerminalId::PinInstId(pin);
657 self.remove_terminal(terminal)
658 }
659
660 fn create_delay_edges_inter_cell(&mut self, top_ref: &CellRef<N>) -> Result<(), StaError> {
661 let netlist = top_ref.base();
662 let top = top_ref.id();
663
664 for net in netlist.each_internal_net(&top) {
666 let terminals = netlist.each_terminal_of_net_vec(&net);
667 let (sources, sinks): (Vec<_>, Vec<_>) = terminals.into_iter().partition(|t| {
669 match t {
671 db::TerminalId::PinId(p) => netlist.pin_direction(p).is_input(),
672 db::TerminalId::PinInstId(p) => {
673 let pin = netlist.template_pin(p);
674 netlist.pin_direction(&pin).is_output()
675 }
676 }
677 });
678
679 if !sources.is_empty() {
680 if sources.len() != 1 {
681 log::warn!(
682 "Net must have 1 driver (has {}): {}",
683 sources.len(),
684 netlist.net_ref(&net).qname(PATH_SEPARATOR)
685 );
686 return Err(StaError::Other(format!(
687 "Net must have 1 driver (has {}): {}",
688 sources.len(),
689 netlist.net_ref(&net).qname(PATH_SEPARATOR)
690 )));
691 }
692
693 let source_terminal = &sources[0];
694 let source_ids = self.term2node[source_terminal];
695
696 for sink_terminal in sinks {
697 let sink_ids = self.term2node[&sink_terminal];
698 for (source_id, sink_id) in source_ids.into_iter().zip(sink_ids) {
701 self.arc_graph.update_edge(
702 source_id,
703 sink_id,
704 EdgeData::new(GraphEdgeType::Delay),
705 );
706 }
707 }
708 }
709 }
710
711 Ok(())
712 }
713
714 fn pin_instance_to_graph_nodes(&self, pin_inst: &PinInstRef<N>) -> [NodeIndex; 2] {
715 let terminal = pin_inst.terminal_id();
716 *self
717 .term2node
718 .get(&terminal)
719 .expect("Pin node does not exist.")
720 }
721
722 fn create_delay_edges_intra_cell<D>(&mut self, inst: &CellInstRef<N>, delay_model: D)
723 where
724 D: CellDelayModel<N, Delay = T::Delay>,
725 {
726 let netlist = inst.base();
727
728 for delay_arc in delay_model.delay_arcs(netlist, &inst.template_id()) {
732 let [input_node, output_node] =
734 [delay_arc.input_pin, delay_arc.output_pin].map(|(p, edge)| {
735 let nodes = self.pin_instance_to_graph_nodes(&inst.pin_instance(&p));
736 nodes[edge as usize]
738 });
739
740 self.arc_graph.update_edge(
741 input_node,
742 output_node,
743 EdgeData::new(GraphEdgeType::Delay),
744 );
745 }
746 }
747
748 fn create_constraint_edges<C>(&mut self, inst: &CellInstRef<N>, constraint_model: C)
750 where
751 C: CellConstraintModel<N, Constraint = T::Constraint>,
752 {
753 let netlist = inst.base();
754
755 for constraint_arc in constraint_model.constraint_arcs(netlist, &inst.template_id()) {
756 let [related_node, constrained_node] =
758 [constraint_arc.related_pin, constraint_arc.constrained_pin].map(|(p, edge)| {
759 let nodes = self.pin_instance_to_graph_nodes(&inst.pin_instance(&p));
760 nodes[edge as usize]
762 });
763
764 self.arc_graph.update_edge(
765 related_node,
766 constrained_node,
767 EdgeData::new(GraphEdgeType::Constraint),
768 );
769
770 self.arc_graph.update_edge(
772 self.rat_source_node,
773 constrained_node,
774 EdgeData::new(GraphEdgeType::Virtual),
775 );
776 }
777 }
778
779 fn create_primary_input(&mut self, primary_input: db::TerminalId<N>) {
781 let t_ids = self.term2node[&primary_input];
782 for t_id in t_ids {
784 self.arc_graph.update_edge(
785 self.aat_source_node,
786 t_id,
787 EdgeData::new(GraphEdgeType::Delay),
788 );
789 }
790 }
791
792 fn create_primary_input_delay_arcs(&mut self, top_cell: &CellRef<N>) {
794 for prim_input in get_primary_inputs(top_cell) {
796 self.create_primary_input(prim_input.into_terminal().into());
797 }
798 }
799
800 pub fn check_cycles(&self) -> Result<(), StaError> {
802 let delay_graph = petgraph::visit::EdgeFiltered::from_fn(&self.arc_graph, |edge_ref| {
804 edge_ref.weight().edge_type.is_delay_arc()
805 });
806
807 let constraint_graph =
809 petgraph::visit::EdgeFiltered::from_fn(&self.arc_graph, |edge_ref| {
810 edge_ref.weight().edge_type.is_constraint_arc()
811 });
812
813 let delay_is_cyclic = petgraph::algo::is_cyclic_directed(&delay_graph);
814 let constraint_is_cyclic = petgraph::algo::is_cyclic_directed(&constraint_graph);
815
816 if delay_is_cyclic {
817 log::error!("Cycle found in delay graph.")
818 }
819 if constraint_is_cyclic {
820 log::error!("Cycle found in constraint graph.")
821 }
822
823 if delay_is_cyclic {
824 Err(StaError::CombinationalCycle)
825 } else {
826 Ok(())
827 }
828 }
829}
830
831fn get_primary_inputs<'a, N: NetlistBase>(top_ref: &CellRef<'a, N>) -> Vec<PinRef<'a, N>> {
833 top_ref
834 .each_pin()
835 .filter(|p| p.direction().is_input())
836 .collect()
837}