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