Skip to main content

physdes/
dme_algorithm.rs

1//! Deferred Merge Embedding (DME) algorithm for clock tree synthesis.
2//!
3//! Implements the DME algorithm for constructing zero-skew clock trees
4//! with Manhattan geometry. Supports both linear and Elmore delay models.
5
6use std::cell::RefCell;
7use std::collections::HashMap;
8use std::rc::Rc;
9
10use crate::generic::MinDist;
11use crate::interval::Interval;
12use crate::manhattan_arc::ManhattanArc;
13use crate::point::Point;
14
15/// A clock sink with name, position, and capacitance.
16#[derive(Debug, Clone)]
17pub struct Sink {
18    pub name: String,
19    pub position: Point<i32, i32>,
20    pub capacitance: f64,
21}
22
23impl Sink {
24    pub fn new(name: &str, position: Point<i32, i32>, capacitance: f64) -> Self {
25        Sink {
26            name: name.to_string(),
27            position,
28            capacitance,
29        }
30    }
31}
32
33/// A node in the clock tree.
34#[derive(Debug, Clone)]
35pub struct TreeNode {
36    pub name: String,
37    pub position: Point<i32, i32>,
38    pub left: Option<Rc<RefCell<TreeNode>>>,
39    pub right: Option<Rc<RefCell<TreeNode>>>,
40    pub parent: Option<Rc<RefCell<TreeNode>>>,
41    pub wire_length: i32,
42    pub delay: f64,
43    pub capacitance: f64,
44    pub need_elongation: bool,
45}
46
47impl TreeNode {
48    pub fn new(name: &str, position: Point<i32, i32>) -> Self {
49        TreeNode {
50            name: name.to_string(),
51            position,
52            left: None,
53            right: None,
54            parent: None,
55            wire_length: 0,
56            delay: 0.0,
57            capacitance: 0.0,
58            need_elongation: false,
59        }
60    }
61
62    pub fn is_leaf(&self) -> bool {
63        self.left.is_none() && self.right.is_none()
64    }
65}
66
67/// Abstract delay model for wire delay calculation.
68pub trait DelayCalculator {
69    fn calculate_wire_delay(&self, length: i32, load_capacitance: f64) -> f64;
70    fn calculate_wire_delay_per_unit(&self, load_capacitance: f64) -> f64;
71    fn calculate_wire_capacitance(&self, length: i32) -> f64;
72    fn calculate_tapping_point(
73        &self,
74        node_left: &mut TreeNode,
75        node_right: &mut TreeNode,
76        distance: i32,
77    ) -> (i32, f64);
78}
79
80/// Linear delay model: delay proportional to wire length.
81pub struct LinearDelayCalculator {
82    pub delay_per_unit: f64,
83    pub capacitance_per_unit: f64,
84}
85
86impl LinearDelayCalculator {
87    pub fn new(delay_per_unit: f64, capacitance_per_unit: f64) -> Self {
88        LinearDelayCalculator {
89            delay_per_unit,
90            capacitance_per_unit,
91        }
92    }
93}
94
95impl DelayCalculator for LinearDelayCalculator {
96    fn calculate_wire_delay(&self, length: i32, _load_capacitance: f64) -> f64 {
97        self.delay_per_unit * length as f64
98    }
99
100    fn calculate_wire_delay_per_unit(&self, _load_capacitance: f64) -> f64 {
101        self.delay_per_unit
102    }
103
104    fn calculate_wire_capacitance(&self, length: i32) -> f64 {
105        self.capacitance_per_unit * length as f64
106    }
107
108    fn calculate_tapping_point(
109        &self,
110        node_left: &mut TreeNode,
111        node_right: &mut TreeNode,
112        distance: i32,
113    ) -> (i32, f64) {
114        let skew = node_right.delay - node_left.delay;
115        let extend_left = ((skew / self.delay_per_unit + distance as f64) / 2.0).round() as i32;
116        let delay_left = node_left.delay + extend_left as f64 * self.delay_per_unit;
117
118        node_left.wire_length = extend_left;
119        node_right.wire_length = distance - extend_left;
120
121        let (extend_left, delay_left) = if extend_left < 0 {
122            node_left.wire_length = 0;
123            node_right.wire_length = distance - extend_left;
124            node_right.need_elongation = true;
125            (0, node_left.delay)
126        } else if extend_left > distance {
127            node_right.wire_length = 0;
128            node_left.wire_length = extend_left;
129            node_left.need_elongation = true;
130            (distance, node_right.delay)
131        } else {
132            (extend_left, delay_left)
133        };
134
135        (extend_left, delay_left)
136    }
137}
138
139/// Elmore delay model: considers wire resistance and capacitance.
140pub struct ElmoreDelayCalculator {
141    pub unit_resistance: f64,
142    pub unit_capacitance: f64,
143}
144
145impl ElmoreDelayCalculator {
146    pub fn new(unit_resistance: f64, unit_capacitance: f64) -> Self {
147        ElmoreDelayCalculator {
148            unit_resistance,
149            unit_capacitance,
150        }
151    }
152}
153
154impl DelayCalculator for ElmoreDelayCalculator {
155    fn calculate_wire_delay(&self, length: i32, load_capacitance: f64) -> f64 {
156        let wire_resistance = self.unit_resistance * length as f64;
157        let wire_capacitance = self.unit_capacitance * length as f64;
158        wire_resistance * (wire_capacitance / 2.0 + load_capacitance)
159    }
160
161    fn calculate_wire_delay_per_unit(&self, load_capacitance: f64) -> f64 {
162        self.unit_resistance * (self.unit_capacitance / 2.0 + load_capacitance)
163    }
164
165    fn calculate_wire_capacitance(&self, length: i32) -> f64 {
166        self.unit_capacitance * length as f64
167    }
168
169    fn calculate_tapping_point(
170        &self,
171        node_left: &mut TreeNode,
172        node_right: &mut TreeNode,
173        distance: i32,
174    ) -> (i32, f64) {
175        let skew = node_right.delay - node_left.delay;
176        let r = distance as f64 * self.unit_resistance;
177        let c = distance as f64 * self.unit_capacitance;
178
179        let z = (skew + r * (node_right.capacitance + c / 2.0))
180            / (r * (c + node_right.capacitance + node_left.capacitance));
181
182        let extend_left = (z * distance as f64).round() as i32;
183        let r_left = extend_left as f64 * self.unit_resistance;
184        let c_left = extend_left as f64 * self.unit_capacitance;
185        let delay_left = node_left.delay + r_left * (c_left / 2.0 + node_left.capacitance);
186
187        node_left.wire_length = extend_left;
188        node_right.wire_length = distance - extend_left;
189
190        let (extend_left, delay_left) = if extend_left < 0 {
191            node_left.wire_length = 0;
192            node_right.wire_length = distance - extend_left;
193            node_right.need_elongation = true;
194            (0, node_left.delay)
195        } else if extend_left > distance {
196            node_right.wire_length = 0;
197            node_left.wire_length = extend_left;
198            node_left.need_elongation = true;
199            (distance, node_right.delay)
200        } else {
201            (extend_left, delay_left)
202        };
203
204        (extend_left, delay_left)
205    }
206}
207
208/// Results of clock skew analysis.
209#[derive(Debug, Clone)]
210pub struct SkewAnalysis {
211    pub max_delay: f64,
212    pub min_delay: f64,
213    pub skew: f64,
214    pub sink_delays: Vec<f64>,
215    pub total_wirelength: i32,
216    pub delay_model: String,
217}
218
219/// Detailed tree statistics.
220#[derive(Debug, Clone)]
221pub struct TreeStatistics {
222    pub nodes: Vec<NodeInfo>,
223    pub wires: Vec<WireInfo>,
224    pub sinks: Vec<String>,
225    pub total_nodes: i32,
226    pub total_sinks: i32,
227    pub total_wires: i32,
228}
229
230#[derive(Debug, Clone)]
231pub struct NodeInfo {
232    pub name: String,
233    pub position: (i32, i32),
234    pub node_type: String,
235    pub delay: f64,
236    pub capacitance: f64,
237}
238
239#[derive(Debug, Clone)]
240pub struct WireInfo {
241    pub from_node: String,
242    pub to_node: String,
243    pub length: i32,
244    pub from_pos: (i32, i32),
245    pub to_pos: (i32, i32),
246}
247
248/// The DME algorithm for clock tree synthesis.
249pub struct DMEAlgorithm {
250    sinks: Vec<Sink>,
251    delay_calculator: Box<dyn DelayCalculator>,
252    node_id: i32,
253}
254
255impl DMEAlgorithm {
256    pub fn new(sinks: Vec<Sink>, calculator: Box<dyn DelayCalculator>) -> Self {
257        assert!(!sinks.is_empty(), "No sinks provided");
258        DMEAlgorithm {
259            sinks,
260            delay_calculator: calculator,
261            node_id: 0,
262        }
263    }
264
265    /// Builds the zero-skew clock tree.
266    pub fn build_clock_tree(&mut self) -> Rc<RefCell<TreeNode>> {
267        let nodes: Vec<Rc<RefCell<TreeNode>>> = self
268            .sinks
269            .iter()
270            .map(|s| {
271                let mut node = TreeNode::new(&s.name, s.position);
272                node.capacitance = s.capacitance;
273                Rc::new(RefCell::new(node))
274            })
275            .collect();
276
277        let merging_tree = self.build_merging_tree(&nodes, false);
278        let mut merging_segments = HashMap::new();
279        self.compute_merging_segment(Rc::clone(&merging_tree), &mut merging_segments);
280        self.embed_node(Rc::clone(&merging_tree), None, &merging_segments);
281        self.compute_delays(Rc::clone(&merging_tree), 0.0);
282        merging_tree
283    }
284
285    fn build_merging_tree(
286        &mut self,
287        nodes: &[Rc<RefCell<TreeNode>>],
288        vertical: bool,
289    ) -> Rc<RefCell<TreeNode>> {
290        if nodes.len() == 1 {
291            return Rc::clone(&nodes[0]);
292        }
293
294        let mut sorted = nodes.to_vec();
295        if vertical {
296            sorted.sort_by(|a, b| a.borrow().position.xcoord.cmp(&b.borrow().position.xcoord));
297        } else {
298            sorted.sort_by(|a, b| a.borrow().position.ycoord.cmp(&b.borrow().position.ycoord));
299        }
300
301        let mid = sorted.len() / 2;
302        let left_group: Vec<_> = sorted[..mid].to_vec();
303        let right_group: Vec<_> = sorted[mid..].to_vec();
304
305        let left_child = self.build_merging_tree(&left_group, !vertical);
306        let right_child = self.build_merging_tree(&right_group, !vertical);
307
308        let id = format!("n{}", self.node_id);
309        self.node_id += 1;
310        let pos = left_child.borrow().position;
311        let parent = Rc::new(RefCell::new(TreeNode::new(&id, pos)));
312        {
313            let mut p = parent.borrow_mut();
314            p.left = Some(Rc::clone(&left_child));
315            p.right = Some(Rc::clone(&right_child));
316        }
317        left_child.borrow_mut().parent = Some(Rc::clone(&parent));
318        right_child.borrow_mut().parent = Some(Rc::clone(&parent));
319
320        parent
321    }
322
323    fn compute_merging_segment(
324        &self,
325        node: Rc<RefCell<TreeNode>>,
326        segments: &mut HashMap<*const TreeNode, ManhattanArc<Interval<i32>>>,
327    ) -> ManhattanArc<Interval<i32>> {
328        let is_leaf = node.borrow().is_leaf();
329        let node_ptr: *const TreeNode = &*node.borrow();
330
331        if is_leaf {
332            let pos = node.borrow().position;
333            let ms1 = ManhattanArc::from_point(pos);
334            let ms = ManhattanArc::new(
335                Interval::new(ms1.xcoord(), ms1.xcoord()),
336                Interval::new(ms1.ycoord(), ms1.ycoord()),
337            );
338            segments.insert(node_ptr, ms);
339            return ms;
340        }
341
342        let left = node.borrow().left.as_ref().map(Rc::clone);
343        let right = node.borrow().right.as_ref().map(Rc::clone);
344        let left = left.expect("Internal node missing left child");
345        let right = right.expect("Internal node missing right child");
346
347        let left_ms = self.compute_merging_segment(Rc::clone(&left), segments);
348        let right_ms = self.compute_merging_segment(Rc::clone(&right), segments);
349
350        let distance = left_ms.min_dist_with(&right_ms) as i32;
351
352        let (extend_left, delay_left) = self.delay_calculator.calculate_tapping_point(
353            &mut left.borrow_mut(),
354            &mut right.borrow_mut(),
355            distance,
356        );
357        node.borrow_mut().delay = delay_left;
358
359        let merged_segment = left_ms.merge_with(&right_ms, extend_left);
360        segments.insert(node_ptr, merged_segment);
361
362        let wire_cap = self.delay_calculator.calculate_wire_capacitance(distance);
363        node.borrow_mut().capacitance =
364            left.borrow().capacitance + right.borrow().capacitance + wire_cap;
365
366        merged_segment
367    }
368
369    fn embed_node(
370        &self,
371        node: Rc<RefCell<TreeNode>>,
372        parent_segment: Option<&ManhattanArc<Interval<i32>>>,
373        segments: &HashMap<*const TreeNode, ManhattanArc<Interval<i32>>>,
374    ) {
375        let node_ptr: *const TreeNode = &*node.borrow();
376        let node_segment = segments
377            .get(&node_ptr)
378            .expect("Merging segment not found for node");
379
380        if parent_segment.is_none() {
381            // Root node: use upper corner of merging segment
382            let upper = Point::new(node_segment.impl_p.xcoord.ub, node_segment.impl_p.ycoord.ub);
383            node.borrow_mut().position = upper;
384        } else {
385            let parent_pos = node.borrow().parent.as_ref().map(|p| p.borrow().position);
386            if let Some(pp) = parent_pos {
387                let nearest = node_segment.nearest_point_to(&pp);
388                node.borrow_mut().position = nearest;
389                let dist = node.borrow().position.min_dist_with(&pp);
390                node.borrow_mut().wire_length = dist as i32;
391            }
392        }
393
394        let left = node.borrow().left.as_ref().map(Rc::clone);
395        let right = node.borrow().right.as_ref().map(Rc::clone);
396
397        if let Some(l) = left {
398            self.embed_node(l, Some(node_segment), segments);
399        }
400        if let Some(r) = right {
401            self.embed_node(r, Some(node_segment), segments);
402        }
403    }
404
405    fn compute_delays(&self, node: Rc<RefCell<TreeNode>>, parent_delay: f64) {
406        let has_parent = node.borrow().parent.is_some();
407        if has_parent {
408            let wire_delay = self
409                .delay_calculator
410                .calculate_wire_delay(node.borrow().wire_length, node.borrow().capacitance);
411            node.borrow_mut().delay = parent_delay + wire_delay;
412        } else {
413            node.borrow_mut().delay = 0.0;
414        }
415
416        let current_delay = node.borrow().delay;
417        let left = node.borrow().left.as_ref().map(Rc::clone);
418        let right = node.borrow().right.as_ref().map(Rc::clone);
419
420        if let Some(l) = left {
421            self.compute_delays(l, current_delay);
422        }
423        if let Some(r) = right {
424            self.compute_delays(r, current_delay);
425        }
426    }
427
428    /// Analyzes clock skew of the constructed tree.
429    pub fn analyze_skew(&self, root: Rc<RefCell<TreeNode>>) -> SkewAnalysis {
430        let mut sink_delays = Vec::new();
431        collect_sink_delays(&root, &mut sink_delays);
432
433        if sink_delays.is_empty() {
434            panic!("No sink delays collected");
435        }
436
437        let max_delay = sink_delays
438            .iter()
439            .cloned()
440            .fold(f64::NEG_INFINITY, f64::max);
441        let min_delay = sink_delays.iter().cloned().fold(f64::INFINITY, f64::min);
442        let skew = max_delay - min_delay;
443        let total_wl = total_wirelength(&root);
444        #[allow(clippy::incompatible_msrv)]
445        let delay_model = std::any::type_name_of_val(&*self.delay_calculator).to_string();
446
447        SkewAnalysis {
448            max_delay,
449            min_delay,
450            skew,
451            sink_delays,
452            total_wirelength: total_wl,
453            delay_model,
454        }
455    }
456}
457
458fn collect_sink_delays(node: &Rc<RefCell<TreeNode>>, sink_delays: &mut Vec<f64>) {
459    if node.borrow().is_leaf() {
460        sink_delays.push(node.borrow().delay);
461    }
462    let left = node.borrow().left.as_ref().map(Rc::clone);
463    let right = node.borrow().right.as_ref().map(Rc::clone);
464    if let Some(l) = left {
465        collect_sink_delays(&l, sink_delays);
466    }
467    if let Some(r) = right {
468        collect_sink_delays(&r, sink_delays);
469    }
470}
471
472fn total_wirelength(node: &Rc<RefCell<TreeNode>>) -> i32 {
473    let mut total = node.borrow().wire_length;
474    let left = node.borrow().left.as_ref().map(Rc::clone);
475    let right = node.borrow().right.as_ref().map(Rc::clone);
476    if let Some(l) = left {
477        total += total_wirelength(&l);
478    }
479    if let Some(r) = right {
480        total += total_wirelength(&r);
481    }
482    total
483}
484
485/// Extracts detailed statistics from a clock tree.
486pub fn get_tree_statistics(root: Rc<RefCell<TreeNode>>) -> TreeStatistics {
487    let mut stats = TreeStatistics {
488        nodes: Vec::new(),
489        wires: Vec::new(),
490        sinks: Vec::new(),
491        total_nodes: 0,
492        total_sinks: 0,
493        total_wires: 0,
494    };
495    traverse_tree(&root, None, &mut stats);
496    stats.total_nodes = stats.nodes.len() as i32;
497    stats.total_sinks = stats.sinks.len() as i32;
498    stats.total_wires = stats.wires.len() as i32;
499    stats
500}
501
502fn traverse_tree(
503    node: &Rc<RefCell<TreeNode>>,
504    parent: Option<&Rc<RefCell<TreeNode>>>,
505    stats: &mut TreeStatistics,
506) {
507    let n = node.borrow();
508    stats.nodes.push(NodeInfo {
509        name: n.name.clone(),
510        position: (n.position.xcoord, n.position.ycoord),
511        node_type: if n.is_leaf() {
512            "sink".to_string()
513        } else {
514            "internal".to_string()
515        },
516        delay: n.delay,
517        capacitance: n.capacitance,
518    });
519
520    if n.is_leaf() {
521        stats.sinks.push(n.name.clone());
522    }
523
524    if let Some(p) = parent {
525        let pb = p.borrow();
526        stats.wires.push(WireInfo {
527            from_node: pb.name.clone(),
528            to_node: n.name.clone(),
529            length: n.wire_length,
530            from_pos: (pb.position.xcoord, pb.position.ycoord),
531            to_pos: (n.position.xcoord, n.position.ycoord),
532        });
533    }
534
535    let left = n.left.as_ref().map(Rc::clone);
536    let right = n.right.as_ref().map(Rc::clone);
537    drop(n);
538
539    if let Some(l) = left {
540        traverse_tree(&l, Some(node), stats);
541    }
542    if let Some(r) = right {
543        traverse_tree(&r, Some(node), stats);
544    }
545}