1use std::collections::HashMap;
10
11use crate::generic::MinDist;
12use crate::interval::Interval;
13use crate::manhattan_arc::ManhattanArc;
14use crate::point::Point;
15
16#[derive(Debug, Clone)]
18pub struct Sink {
19 pub name: String,
21 pub position: Point<i32, i32>,
23 pub capacitance: f64,
25}
26
27impl Sink {
28 pub fn new(name: &str, position: Point<i32, i32>, capacitance: f64) -> Self {
30 Sink {
31 name: name.to_string(),
32 position,
33 capacitance,
34 }
35 }
36}
37
38pub type NodeIdx = usize;
41
42#[derive(Debug, Clone)]
44pub struct TreeNode {
45 pub name: String,
47 pub position: Point<i32, i32>,
49 pub left: Option<NodeIdx>,
51 pub right: Option<NodeIdx>,
53 pub parent: Option<NodeIdx>,
55 pub wire_length: i32,
57 pub delay: f64,
59 pub capacitance: f64,
61 pub need_elongation: bool,
63}
64
65impl TreeNode {
66 pub fn new(name: &str, position: Point<i32, i32>) -> Self {
71 TreeNode {
72 name: name.to_string(),
73 position,
74 left: None,
75 right: None,
76 parent: None,
77 wire_length: 0,
78 delay: 0.0,
79 capacitance: 0.0,
80 need_elongation: false,
81 }
82 }
83
84 pub fn is_leaf(&self) -> bool {
86 self.left.is_none() && self.right.is_none()
87 }
88}
89
90#[derive(Debug, Clone, Default)]
96pub struct Tree {
97 nodes: Vec<TreeNode>,
98 pub root: Option<NodeIdx>,
100}
101
102impl Tree {
103 pub fn new() -> Self {
105 Self::default()
106 }
107
108 pub fn add(&mut self, node: TreeNode) -> NodeIdx {
110 let idx = self.nodes.len();
111 self.nodes.push(node);
112 idx
113 }
114
115 pub fn get(&self, idx: NodeIdx) -> &TreeNode {
117 &self.nodes[idx]
118 }
119
120 pub fn get_mut(&mut self, idx: NodeIdx) -> &mut TreeNode {
122 &mut self.nodes[idx]
123 }
124
125 pub fn len(&self) -> usize {
127 self.nodes.len()
128 }
129
130 pub fn is_empty(&self) -> bool {
132 self.nodes.is_empty()
133 }
134
135 pub fn iter(&self) -> impl Iterator<Item = &TreeNode> {
137 self.nodes.iter()
138 }
139
140 pub fn get_pair_mut(&mut self, a: NodeIdx, b: NodeIdx) -> (&mut TreeNode, &mut TreeNode) {
142 assert_ne!(a, b, "get_pair_mut called with identical indices");
143 if a < b {
144 let (left, right) = self.nodes.split_at_mut(b);
145 (&mut left[a], &mut right[0])
146 } else {
147 let (left, right) = self.nodes.split_at_mut(a);
148 (&mut right[0], &mut left[b])
149 }
150 }
151}
152
153#[derive(Debug, Clone, Copy, PartialEq)]
159pub struct TappingResult {
160 pub extend_left: i32,
162 pub raw_extend_left: i32,
164 pub delay_left: f64,
166}
167
168pub trait DelayCalculator {
170 fn calculate_wire_delay(&self, length: i32, load_capacitance: f64) -> f64;
174 fn calculate_wire_delay_per_unit(&self, load_capacitance: f64) -> f64;
176 fn calculate_wire_capacitance(&self, length: i32) -> f64;
178 fn calculate_tapping_point(
185 &self,
186 distance: i32,
187 left_delay: f64,
188 right_delay: f64,
189 left_capacitance: f64,
190 right_capacitance: f64,
191 ) -> TappingResult;
192}
193
194pub struct LinearDelayCalculator {
198 pub delay_per_unit: f64,
200 pub capacitance_per_unit: f64,
202}
203
204impl LinearDelayCalculator {
205 pub fn new(delay_per_unit: f64, capacitance_per_unit: f64) -> Self {
207 LinearDelayCalculator {
208 delay_per_unit,
209 capacitance_per_unit,
210 }
211 }
212}
213
214impl DelayCalculator for LinearDelayCalculator {
215 fn calculate_wire_delay(&self, length: i32, _load_capacitance: f64) -> f64 {
217 self.delay_per_unit * length as f64
218 }
219 fn calculate_wire_delay_per_unit(&self, _load_capacitance: f64) -> f64 {
220 self.delay_per_unit
221 }
222 fn calculate_wire_capacitance(&self, length: i32) -> f64 {
223 self.capacitance_per_unit * length as f64
224 }
225 fn calculate_tapping_point(
231 &self,
232 distance: i32,
233 left_delay: f64,
234 right_delay: f64,
235 _left_capacitance: f64,
236 _right_capacitance: f64,
237 ) -> TappingResult {
238 if distance == 0 {
239 return TappingResult {
240 extend_left: 0,
241 raw_extend_left: 0,
242 delay_left: left_delay.max(right_delay),
243 };
244 }
245 let skew = right_delay - left_delay;
246 let raw = ((skew / self.delay_per_unit + distance as f64) / 2.0).round() as i32;
247 let delay_left = left_delay + raw as f64 * self.delay_per_unit;
248 let (extend_left, delay_left) = if raw < 0 {
249 (0, left_delay)
250 } else if raw > distance {
251 (distance, right_delay)
252 } else {
253 (raw, delay_left)
254 };
255 TappingResult {
256 extend_left,
257 raw_extend_left: raw,
258 delay_left,
259 }
260 }
261}
262
263pub struct ElmoreDelayCalculator {
268 pub unit_resistance: f64,
270 pub unit_capacitance: f64,
272}
273
274impl ElmoreDelayCalculator {
275 pub fn new(unit_resistance: f64, unit_capacitance: f64) -> Self {
278 ElmoreDelayCalculator {
279 unit_resistance,
280 unit_capacitance,
281 }
282 }
283}
284
285impl DelayCalculator for ElmoreDelayCalculator {
286 fn calculate_wire_delay(&self, length: i32, load_capacitance: f64) -> f64 {
290 let r = self.unit_resistance * length as f64;
291 let c = self.unit_capacitance * length as f64;
292 r * (c / 2.0 + load_capacitance)
293 }
294 fn calculate_wire_delay_per_unit(&self, load_capacitance: f64) -> f64 {
295 self.unit_resistance * (self.unit_capacitance / 2.0 + load_capacitance)
296 }
297 fn calculate_wire_capacitance(&self, length: i32) -> f64 {
298 self.unit_capacitance * length as f64
299 }
300 fn calculate_tapping_point(
306 &self,
307 distance: i32,
308 left_delay: f64,
309 right_delay: f64,
310 left_capacitance: f64,
311 right_capacitance: f64,
312 ) -> TappingResult {
313 if distance == 0 {
314 return TappingResult {
315 extend_left: 0,
316 raw_extend_left: 0,
317 delay_left: left_delay.max(right_delay),
318 };
319 }
320 let skew = right_delay - left_delay;
321 let r = distance as f64 * self.unit_resistance;
322 let c_w = distance as f64 * self.unit_capacitance;
323 let z = (skew + r * (right_capacitance + c_w / 2.0))
324 / (r * (c_w + right_capacitance + left_capacitance));
325 let raw = (z * distance as f64).round() as i32;
326 let r_left = raw as f64 * self.unit_resistance;
327 let c_left = raw as f64 * self.unit_capacitance;
328 let delay_left = left_delay + r_left * (c_left / 2.0 + left_capacitance);
329 let (extend_left, delay_left) = if raw < 0 {
330 (0, left_delay)
331 } else if raw > distance {
332 (distance, right_delay)
333 } else {
334 (raw, delay_left)
335 };
336 TappingResult {
337 extend_left,
338 raw_extend_left: raw,
339 delay_left,
340 }
341 }
342}
343
344#[derive(Debug, Clone)]
346pub struct SkewAnalysis {
347 pub max_delay: f64,
349 pub min_delay: f64,
351 pub skew: f64,
353 pub sink_delays: Vec<f64>,
355 pub total_wirelength: i32,
357 pub delay_model: String,
359}
360
361#[derive(Debug, Clone)]
363pub struct TreeStatistics {
364 pub nodes: Vec<NodeInfo>,
366 pub wires: Vec<WireInfo>,
368 pub sinks: Vec<String>,
370 pub total_nodes: i32,
372 pub total_sinks: i32,
374 pub total_wires: i32,
376}
377
378#[derive(Debug, Clone)]
380pub struct NodeInfo {
381 pub name: String,
383 pub position: (i32, i32),
385 pub node_type: String,
387 pub delay: f64,
389 pub capacitance: f64,
391}
392
393#[derive(Debug, Clone)]
395pub struct WireInfo {
396 pub from_node: String,
398 pub to_node: String,
400 pub length: i32,
402 pub from_pos: (i32, i32),
404 pub to_pos: (i32, i32),
406}
407
408pub struct DMEAlgorithm {
422 sinks: Vec<Sink>,
423 delay_calculator: Box<dyn DelayCalculator>,
424 node_id: i32,
425 source: Option<Point<i32, i32>>,
426 tree: Tree,
427}
428
429impl DMEAlgorithm {
430 pub fn new(sinks: Vec<Sink>, calculator: Box<dyn DelayCalculator>) -> Self {
436 assert!(!sinks.is_empty(), "No sinks provided");
437 DMEAlgorithm {
438 sinks,
439 delay_calculator: calculator,
440 node_id: 0,
441 source: None,
442 tree: Tree::new(),
443 }
444 }
445
446 pub fn with_source(
452 sinks: Vec<Sink>,
453 calculator: Box<dyn DelayCalculator>,
454 source: Point<i32, i32>,
455 ) -> Self {
456 assert!(!sinks.is_empty(), "No sinks provided");
457 DMEAlgorithm {
458 sinks,
459 delay_calculator: calculator,
460 node_id: 0,
461 source: Some(source),
462 tree: Tree::new(),
463 }
464 }
465
466 pub fn get_tree(&self) -> &Tree {
468 &self.tree
469 }
470
471 pub fn get_tree_mut(&mut self) -> &mut Tree {
473 &mut self.tree
474 }
475
476 pub fn build_clock_tree(&mut self) -> NodeIdx {
478 self.node_id = 0;
479 self.tree = Tree::new();
480
481 for s in &self.sinks {
482 let mut node = TreeNode::new(&s.name, s.position);
483 node.capacitance = s.capacitance;
484 self.tree.add(node);
485 }
486
487 let leaf_indices: Vec<NodeIdx> = (0..self.tree.len()).collect();
488 let root = self.build_merging_tree(&leaf_indices, false);
489
490 let mut merging_segments: HashMap<NodeIdx, ManhattanArc<Interval<i32>>> = HashMap::new();
491 self.compute_merging_segment(root, &mut merging_segments);
492 self.embed_node(root, None, &merging_segments);
493 self.compute_delays(root, 0.0);
494
495 self.tree.root = Some(root);
496 root
497 }
498
499 fn build_merging_tree(&mut self, node_ids: &[NodeIdx], vertical: bool) -> NodeIdx {
501 if node_ids.len() == 1 {
502 return node_ids[0];
503 }
504
505 let mut sorted: Vec<NodeIdx> = node_ids.to_vec();
506 if vertical {
507 sorted.sort_by(|&a, &b| {
508 self.tree
509 .get(a)
510 .position
511 .xcoord
512 .cmp(&self.tree.get(b).position.xcoord)
513 });
514 } else {
515 sorted.sort_by(|&a, &b| {
516 self.tree
517 .get(a)
518 .position
519 .ycoord
520 .cmp(&self.tree.get(b).position.ycoord)
521 });
522 }
523
524 let mid = sorted.len() / 2;
525 let left_child = self.build_merging_tree(&sorted[..mid], !vertical);
526 let right_child = self.build_merging_tree(&sorted[mid..], !vertical);
527
528 let id = format!("n{}", self.node_id);
529 self.node_id += 1;
530 let pos = self.tree.get(left_child).position;
531 let parent_idx = self.tree.add(TreeNode::new(&id, pos));
532
533 self.tree.get_mut(parent_idx).left = Some(left_child);
534 self.tree.get_mut(parent_idx).right = Some(right_child);
535 self.tree.get_mut(left_child).parent = Some(parent_idx);
536 self.tree.get_mut(right_child).parent = Some(parent_idx);
537
538 parent_idx
539 }
540
541 fn compute_merging_segment(
542 &mut self,
543 node: NodeIdx,
544 segments: &mut HashMap<NodeIdx, ManhattanArc<Interval<i32>>>,
545 ) -> ManhattanArc<Interval<i32>> {
546 if self.tree.get(node).is_leaf() {
547 let pos = self.tree.get(node).position;
548 let ms1 = ManhattanArc::from_point(pos);
549 let ms = ManhattanArc::new(
550 Interval::new(ms1.xcoord(), ms1.xcoord()),
551 Interval::new(ms1.ycoord(), ms1.ycoord()),
552 );
553 segments.insert(node, ms);
554 return ms;
555 }
556
557 let left = self
558 .tree
559 .get(node)
560 .left
561 .expect("Internal node missing left child");
562 let right = self
563 .tree
564 .get(node)
565 .right
566 .expect("Internal node missing right child");
567
568 let left_ms = self.compute_merging_segment(left, segments);
569 let right_ms = self.compute_merging_segment(right, segments);
570
571 let distance = left_ms.min_dist_with(&right_ms) as i32;
572
573 let (left_delay, right_delay) = {
574 let ln = self.tree.get(left);
575 let rn = self.tree.get(right);
576 (ln.delay, rn.delay)
577 };
578 let (left_cap, right_cap) = {
579 let ln = self.tree.get(left);
580 let rn = self.tree.get(right);
581 (ln.capacitance, rn.capacitance)
582 };
583
584 let tp = self.delay_calculator.calculate_tapping_point(
585 distance,
586 left_delay,
587 right_delay,
588 left_cap,
589 right_cap,
590 );
591
592 {
597 let (l_node, r_node) = self.tree.get_pair_mut(left, right);
598 l_node.wire_length = tp.extend_left;
599 r_node.wire_length = distance - tp.raw_extend_left;
600
601 if tp.raw_extend_left < 0 {
602 l_node.wire_length = 0;
603 r_node.wire_length = distance - tp.raw_extend_left;
604 r_node.need_elongation = true;
605 #[cfg(feature = "std")]
606 log::warn!(
607 "Warning: Right node needs elongation: extend_left < 0 => extend_left \
608 set to 0"
609 );
610 } else if tp.raw_extend_left > distance {
611 r_node.wire_length = 0;
612 l_node.wire_length = tp.raw_extend_left;
613 l_node.need_elongation = true;
614 #[cfg(feature = "std")]
615 log::warn!(
616 "Warning: Left node needs elongation: extend_left > distance => \
617 extend_left set to distance"
618 );
619 }
620 }
621
622 self.tree.get_mut(node).delay = tp.delay_left;
623
624 let merged_segment = left_ms.merge_with(&right_ms, tp.extend_left);
625 segments.insert(node, merged_segment);
626
627 let wire_cap = self.delay_calculator.calculate_wire_capacitance(distance);
628 self.tree.get_mut(node).capacitance = {
629 let lc = self.tree.get(left).capacitance;
630 let rc = self.tree.get(right).capacitance;
631 lc + rc + wire_cap
632 };
633
634 merged_segment
635 }
636
637 fn embed_node(
638 &mut self,
639 node: NodeIdx,
640 parent_segment: Option<&ManhattanArc<Interval<i32>>>,
641 segments: &HashMap<NodeIdx, ManhattanArc<Interval<i32>>>,
642 ) {
643 let node_segment = segments
644 .get(&node)
645 .expect("Merging segment not found for node");
646
647 if parent_segment.is_none() {
648 if let Some(src) = self.source {
649 let nearest = node_segment.nearest_point_to(&src);
650 self.tree.get_mut(node).position = nearest;
651 } else {
652 let upper = node_segment.get_upper_corner();
653 self.tree.get_mut(node).position = upper;
654 }
655 } else {
656 let parent_pos = self
657 .tree
658 .get(node)
659 .parent
660 .map(|p| self.tree.get(p).position);
661 if let Some(pp) = parent_pos {
662 let nearest = node_segment.nearest_point_to(&pp);
663 self.tree.get_mut(node).position = nearest;
664 let dist = self.tree.get(node).position.min_dist_with(&pp) as i32;
665 self.tree.get_mut(node).wire_length = dist;
666 }
667 }
668
669 let left = self.tree.get(node).left;
670 let right = self.tree.get(node).right;
671
672 if let Some(l) = left {
673 self.embed_node(l, Some(node_segment), segments);
674 }
675 if let Some(r) = right {
676 self.embed_node(r, Some(node_segment), segments);
677 }
678 }
679
680 fn compute_delays(&mut self, node: NodeIdx, parent_delay: f64) {
681 let has_parent = self.tree.get(node).parent.is_some();
682 if has_parent {
683 let wl = self.tree.get(node).wire_length;
684 let cap = self.tree.get(node).capacitance;
685 let wire_delay = self.delay_calculator.calculate_wire_delay(wl, cap);
686 self.tree.get_mut(node).delay = parent_delay + wire_delay;
687 } else {
688 self.tree.get_mut(node).delay = 0.0;
689 }
690
691 let current_delay = self.tree.get(node).delay;
692 let left = self.tree.get(node).left;
693 let right = self.tree.get(node).right;
694
695 if let Some(l) = left {
696 self.compute_delays(l, current_delay);
697 }
698 if let Some(r) = right {
699 self.compute_delays(r, current_delay);
700 }
701 }
702
703 pub fn analyze_skew(&self, root: NodeIdx) -> SkewAnalysis {
705 let mut sink_delays = Vec::new();
706 collect_sink_delays(&self.tree, root, &mut sink_delays);
707
708 if sink_delays.is_empty() {
709 panic!("No sink delays collected");
710 }
711
712 let max_delay = sink_delays
713 .iter()
714 .cloned()
715 .fold(f64::NEG_INFINITY, f64::max);
716 let min_delay = sink_delays.iter().cloned().fold(f64::INFINITY, f64::min);
717 let skew = max_delay - min_delay;
718 let total_wl = total_wirelength(&self.tree, root);
719 #[allow(clippy::incompatible_msrv)]
720 let delay_model = std::any::type_name_of_val(&*self.delay_calculator).to_string();
721
722 SkewAnalysis {
723 max_delay,
724 min_delay,
725 skew,
726 sink_delays,
727 total_wirelength: total_wl,
728 delay_model,
729 }
730 }
731}
732
733fn collect_sink_delays(tree: &Tree, node: NodeIdx, sink_delays: &mut Vec<f64>) {
738 if tree.get(node).is_leaf() {
739 sink_delays.push(tree.get(node).delay);
740 }
741 if let Some(l) = tree.get(node).left {
742 collect_sink_delays(tree, l, sink_delays);
743 }
744 if let Some(r) = tree.get(node).right {
745 collect_sink_delays(tree, r, sink_delays);
746 }
747}
748
749fn total_wirelength(tree: &Tree, node: NodeIdx) -> i32 {
750 let mut total = tree.get(node).wire_length;
751 if let Some(l) = tree.get(node).left {
752 total += total_wirelength(tree, l);
753 }
754 if let Some(r) = tree.get(node).right {
755 total += total_wirelength(tree, r);
756 }
757 total
758}
759
760pub fn get_tree_statistics(tree: &Tree, root: NodeIdx) -> TreeStatistics {
762 let mut stats = TreeStatistics {
763 nodes: Vec::new(),
764 wires: Vec::new(),
765 sinks: Vec::new(),
766 total_nodes: 0,
767 total_sinks: 0,
768 total_wires: 0,
769 };
770 traverse_tree(tree, root, None, &mut stats);
771 stats.total_nodes = stats.nodes.len() as i32;
772 stats.total_sinks = stats.sinks.len() as i32;
773 stats.total_wires = stats.wires.len() as i32;
774 stats
775}
776
777fn traverse_tree(tree: &Tree, node: NodeIdx, parent: Option<NodeIdx>, stats: &mut TreeStatistics) {
778 let n = tree.get(node);
779 stats.nodes.push(NodeInfo {
780 name: n.name.clone(),
781 position: (n.position.xcoord, n.position.ycoord),
782 node_type: if n.is_leaf() {
783 "sink".to_string()
784 } else {
785 "internal".to_string()
786 },
787 delay: n.delay,
788 capacitance: n.capacitance,
789 });
790
791 if n.is_leaf() {
792 stats.sinks.push(n.name.clone());
793 }
794
795 if let Some(p) = parent {
796 let pb = tree.get(p);
797 stats.wires.push(WireInfo {
798 from_node: pb.name.clone(),
799 to_node: n.name.clone(),
800 length: n.wire_length,
801 from_pos: (pb.position.xcoord, pb.position.ycoord),
802 to_pos: (n.position.xcoord, n.position.ycoord),
803 });
804 }
805
806 let left = n.left;
807 let right = n.right;
808 let _ = n;
809
810 if let Some(l) = left {
811 traverse_tree(tree, l, Some(node), stats);
812 }
813 if let Some(r) = right {
814 traverse_tree(tree, r, Some(node), stats);
815 }
816}
817
818#[cfg(test)]
823mod tests {
824 use super::*;
825
826 fn make_sinks(count: i32) -> Vec<Sink> {
827 (0..count)
828 .map(|i| {
829 let x = (i * 37) % 100;
830 let y = (i * 53) % 100;
831 Sink::new(
832 &format!("s{}", i),
833 Point::new(x, y),
834 1.0 + (i % 5) as f64 * 0.2,
835 )
836 })
837 .collect()
838 }
839
840 fn run_tree(sinks: Vec<Sink>, calc: Box<dyn DelayCalculator>) -> (DMEAlgorithm, SkewAnalysis) {
841 let mut dme = DMEAlgorithm::new(sinks, calc);
842 let root = dme.build_clock_tree();
843 let analysis = dme.analyze_skew(root);
844 (dme, analysis)
845 }
846
847 #[test]
848 fn test_dme_skew_within_two_percent_linear() {
849 let sinks = make_sinks(8);
850 let calc = Box::new(LinearDelayCalculator::new(0.5, 0.1));
851 let (_, analysis) = run_tree(sinks, calc);
852 assert!(analysis.max_delay > 0.0);
853 let pct = analysis.skew / analysis.max_delay * 100.0;
854 assert!(
855 pct < 2.0,
856 "Skew {:.4} ({:.2}%) exceeds 2%",
857 analysis.skew,
858 pct
859 );
860 }
861
862 #[test]
863 fn test_dme_skew_within_two_percent_elmore() {
864 let sinks = make_sinks(8);
865 let calc = Box::new(ElmoreDelayCalculator::new(0.1, 0.1));
866 let (_, analysis) = run_tree(sinks, calc);
867 assert!(analysis.max_delay > 0.0);
868 let pct = analysis.skew / analysis.max_delay * 100.0;
869 assert!(
870 pct < 2.0,
871 "Skew {:.4} ({:.2}%) exceeds 2%",
872 analysis.skew,
873 pct
874 );
875 }
876
877 #[test]
878 fn test_dme_two_sinks_zero_skew() {
879 let sinks = vec![
880 Sink::new("s1", Point::new(0, 0), 1.0),
881 Sink::new("s2", Point::new(10, 0), 1.0),
882 ];
883 let (_, analysis) = run_tree(sinks, Box::new(LinearDelayCalculator::new(1.0, 0.1)));
884 assert_eq!(
885 analysis.skew, 0.0,
886 "Two symmetric sinks should have zero skew"
887 );
888 assert_eq!(analysis.total_wirelength, 10);
889 }
890
891 #[test]
892 fn test_dme_single_sink() {
893 let sinks = vec![Sink::new("s1", Point::new(5, 5), 1.0)];
894 let (dme, analysis) = run_tree(sinks, Box::new(LinearDelayCalculator::new(0.5, 0.1)));
895 assert!(dme.get_tree().get(dme.get_tree().root.unwrap()).is_leaf());
896 assert_eq!(analysis.skew, 0.0);
897 assert_eq!(analysis.sink_delays.len(), 1);
898 }
899
900 #[test]
901 fn test_dme_with_source() {
902 let sinks = vec![
903 Sink::new("s1", Point::new(-10, -10), 1.0),
904 Sink::new("s2", Point::new(10, -10), 1.0),
905 Sink::new("s3", Point::new(-10, 10), 1.0),
906 Sink::new("s4", Point::new(10, 10), 1.0),
907 ];
908 let calc = Box::new(LinearDelayCalculator::new(0.5, 0.1));
909 let mut dme = DMEAlgorithm::with_source(sinks, calc, Point::new(0, 0));
910 let root = dme.build_clock_tree();
911 let analysis = dme.analyze_skew(root);
912 assert!(analysis.max_delay > 0.0);
913 let pct = analysis.skew / analysis.max_delay * 100.0;
914 assert!(
915 pct < 2.0,
916 "Skew {:.4} ({:.2}%) exceeds 2%",
917 analysis.skew,
918 pct
919 );
920 }
921
922 #[test]
923 fn test_get_tree_statistics() {
924 let sinks = vec![
925 Sink::new("s1", Point::new(0, 0), 1.0),
926 Sink::new("s2", Point::new(10, 0), 1.0),
927 ];
928 let mut dme = DMEAlgorithm::new(sinks, Box::new(LinearDelayCalculator::new(1.0, 0.1)));
929 let root = dme.build_clock_tree();
930 let stats = get_tree_statistics(dme.get_tree(), root);
931 assert_eq!(stats.total_nodes, 3);
932 assert_eq!(stats.total_sinks, 2);
933 assert_eq!(stats.total_wires, 2);
934 }
935
936 fn apply_elongation(distance: i32, tp: &TappingResult) -> (i32, i32, bool, bool) {
942 let mut left_wl = tp.extend_left;
943 let mut right_wl = distance - tp.raw_extend_left;
944 let mut left_el = false;
945 let mut right_el = false;
946 if tp.raw_extend_left < 0 {
947 left_wl = 0;
948 right_wl = distance - tp.raw_extend_left;
949 right_el = true;
950 } else if tp.raw_extend_left > distance {
951 right_wl = 0;
952 left_wl = tp.raw_extend_left;
953 left_el = true;
954 }
955 (left_wl, right_wl, left_el, right_el)
956 }
957
958 #[test]
959 fn test_linear_tapping_point_balanced() {
960 let calc = LinearDelayCalculator::new(0.5, 0.2);
961 let tp = calc.calculate_tapping_point(10, 1.0, 1.0, 0.0, 0.0);
962 assert_eq!(tp.extend_left, 5);
963 assert_eq!(tp.raw_extend_left, 5);
964 approx_eq(tp.delay_left, 1.0 + 5.0 * 0.5);
965 }
966
967 #[test]
968 fn test_linear_tapping_point_right_slower() {
969 let calc = LinearDelayCalculator::new(0.5, 0.2);
970 let tp = calc.calculate_tapping_point(10, 1.0, 3.0, 0.0, 0.0);
971 assert_eq!(tp.extend_left, 7);
972 approx_eq(tp.delay_left, 1.0 + 7.0 * 0.5);
973 }
974
975 #[test]
976 fn test_linear_tapping_point_left_slower() {
977 let calc = LinearDelayCalculator::new(0.5, 0.2);
978 let tp = calc.calculate_tapping_point(10, 3.0, 1.0, 0.0, 0.0);
979 assert_eq!(tp.extend_left, 3);
980 approx_eq(tp.delay_left, 3.0 + 3.0 * 0.5);
981 }
982
983 #[test]
984 fn test_linear_elongation_right_branch() {
985 let calc = LinearDelayCalculator::new(0.5, 0.2);
988 let tp = calc.calculate_tapping_point(10, 10.0, 1.0, 0.0, 0.0);
989 assert_eq!(tp.extend_left, 0);
990 assert_eq!(tp.raw_extend_left, -4);
991 approx_eq(tp.delay_left, 10.0);
992
993 let (l_wl, r_wl, l_el, r_el) = apply_elongation(10, &tp);
994 assert_eq!(l_wl, 0);
995 assert_eq!(r_wl, 14); assert!(!l_el);
997 assert!(r_el);
998 }
999
1000 #[test]
1001 fn test_linear_elongation_left_branch() {
1002 let calc = LinearDelayCalculator::new(0.5, 0.2);
1005 let tp = calc.calculate_tapping_point(10, 1.0, 10.0, 0.0, 0.0);
1006 assert_eq!(tp.extend_left, 10);
1007 assert_eq!(tp.raw_extend_left, 14);
1008 approx_eq(tp.delay_left, 10.0);
1009
1010 let (l_wl, r_wl, l_el, r_el) = apply_elongation(10, &tp);
1011 assert_eq!(l_wl, 14); assert_eq!(r_wl, 0);
1013 assert!(l_el);
1014 assert!(!r_el);
1015 }
1016
1017 #[test]
1018 fn test_elmore_elongation_right_branch() {
1019 let calc = ElmoreDelayCalculator::new(0.1, 0.2);
1020 let tp = calc.calculate_tapping_point(10, 10.0, 1.0, 1.0, 1.0);
1021 assert_eq!(tp.extend_left, 0);
1022 assert_eq!(tp.raw_extend_left, -18);
1023 approx_eq(tp.delay_left, 10.0);
1024
1025 let (l_wl, r_wl, l_el, r_el) = apply_elongation(10, &tp);
1026 assert_eq!(l_wl, 0);
1027 assert_eq!(r_wl, 28); assert!(!l_el);
1029 assert!(r_el);
1030 }
1031
1032 #[test]
1033 fn test_elmore_elongation_left_branch() {
1034 let calc = ElmoreDelayCalculator::new(0.1, 0.2);
1035 let tp = calc.calculate_tapping_point(10, 1.0, 10.0, 1.0, 1.0);
1036 assert_eq!(tp.extend_left, 10);
1037 assert_eq!(tp.raw_extend_left, 28);
1038 approx_eq(tp.delay_left, 10.0);
1039
1040 let (l_wl, r_wl, l_el, r_el) = apply_elongation(10, &tp);
1041 assert_eq!(l_wl, 28); assert_eq!(r_wl, 0);
1043 assert!(l_el);
1044 assert!(!r_el);
1045 }
1046
1047 fn approx_eq(a: f64, b: f64) {
1049 assert!((a - b).abs() < 1e-9, "left={}, right={}", a, b);
1050 }
1051}