libreda_sta/models/
clock_tag.rs

1// SPDX-FileCopyrightText: 2023 Thomas Kramer <code@tkramer.ch>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5//! Wrap delay/constraint models and add the capability to tag signals with an associated clock.
6
7use libreda_db::prelude as db;
8use num_traits::Zero;
9use smallvec::{smallvec, SmallVec};
10use std::{collections::HashMap, num::NonZeroU32, ops::Deref, sync::RwLock};
11
12use uom::si::f64::Time;
13
14use crate::{
15    traits::{
16        cell_constraint_model::{CellConstraintArc, CellConstraintModel},
17        cell_logic_model::{LogicModel, OutputFunction},
18        timing_base::SignalTransitionType,
19        CellDelayArc, CellDelayModel, CellModel, ConstraintBase, DelayBase, InterconnectDelayModel,
20        LoadBase, Signal, TimingBase,
21    },
22    RequiredSignal, RiseFall,
23};
24
25/// Compact ID for marking signals with a clock.
26///
27/// Identifier for clocks, generated clocks, propagated clocks, inverted clocks, etc.
28/// This struct is a wrapper around a 32-bit integer. It is used
29/// as an efficient marker to associate nets with a clock source.
30#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
31pub struct ClockId {
32    /// Allow to efficiently encode `None` by using a non-zero integer.
33    /// The lowest-significant bits indicate:
34    /// * bit 0: this signal is marked as a clock signal
35    /// * bit 1: inversion of the clock levels.
36    /// * bit 2: signal can change on rising edge of clock
37    /// * bit 3: signal can change on falling edge of clock
38    ///
39    /// For example, bit 1 and 2 are always set for a signal in the clock tree.
40    /// When passing through a single-edge-triggered flip-flop one of the bits will be cleared.
41    ///
42    /// Id = 1 must not be used because the clock id = 0 is used for encoding `None`.
43    ///
44    id: NonZeroU32,
45}
46
47#[test]
48fn test_clock_id_compact_encoding_of_option() {
49    use core::mem::size_of;
50    assert_eq!(size_of::<Option<ClockId>>(), size_of::<ClockId>());
51}
52
53impl std::fmt::Debug for ClockId {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        write!(f, "ClockId(index={}, flags=[", self.storage_index())?;
56
57        // Display the enabled flags using letters.
58        let flags = [
59            ("C", ClockId::BIT_INDEX_IS_CLOCK),
60            ("I", ClockId::BIT_INDEX_INVERTED),
61            ("R", ClockId::BIT_INDEX_RISING_EDGE),
62            ("F", ClockId::BIT_INDEX_FALLING_EDGE),
63        ];
64        for (symbol, bit_index) in flags {
65            if self.get_bit(bit_index) {
66                write!(f, "{}", symbol)?;
67            }
68        }
69
70        write!(f, "])")
71    }
72}
73
74impl ClockId {
75    /// Number of least-significant bits which are used as flag bits.
76    const NUM_FLAGS: usize = 4;
77    const BIT_INDEX_IS_CLOCK: usize = 0;
78    const BIT_INDEX_INVERTED: usize = 1;
79    const BIT_INDEX_RISING_EDGE: usize = 2;
80    const BIT_INDEX_FALLING_EDGE: usize = 3;
81
82    /// Create a new clock ID from the index of the clock.
83    /// The index is a 'pointer' to the specification of the clock.
84    /// The ID is used to annotate signals in order to link them to a clock source.
85    /// The ID does not only store this index but also keeps track of other properties such as
86    /// on which clock events the signal can change.
87    pub fn new(storage_index: u32) -> Self {
88        // Make sure `id` is not zero (`0` this is used for encoding `None`).
89        let id = storage_index + 1;
90
91        // Add flags.
92        let id = id << Self::NUM_FLAGS;
93
94        let mut id = Self {
95            id: NonZeroU32::new(id).unwrap(),
96        };
97
98        // By default, the signal can change on both clock edges.
99        id.set_edge_sensitivity(RiseFall::Rise, true);
100        id.set_edge_sensitivity(RiseFall::Fall, true);
101
102        id
103    }
104
105    /// Create a new ID by taking the index from `self` and the bit flags from `other`.
106    fn with_flags_from(&self, other: Self) -> Self {
107        let mask = (1 << Self::NUM_FLAGS) - 1;
108
109        let raw = self.id.get();
110        // Clear flags.
111        let cleared = raw & !mask;
112        // Copy flags.
113        let with_flags = cleared | (other.id.get() & mask);
114
115        Self {
116            id: NonZeroU32::new(with_flags).unwrap(),
117        }
118    }
119
120    /// Get the index into the array of clocks.
121    /// Points to the detailed description of the corresponding clock.
122    pub fn storage_index(&self) -> usize {
123        ((self.id.get() >> Self::NUM_FLAGS) - 1) as usize
124    }
125
126    /// Check if this ID refers to an inverted version of the clock.
127    pub fn is_inverted(&self) -> bool {
128        self.get_bit(Self::BIT_INDEX_INVERTED)
129    }
130
131    /// Test if this signal is marked as a clock signal.
132    /// This flag gets cleared when a clock signal passes through a clock input
133    /// of a sequential cell to a data output.
134    pub fn is_clock(&self) -> bool {
135        self.get_bit(Self::BIT_INDEX_IS_CLOCK)
136    }
137
138    /// Define if this signal is a clock or just a clocked signal otherwise.
139    pub fn set_clock(&mut self, is_clock: bool) {
140        self.set_bit(Self::BIT_INDEX_IS_CLOCK, is_clock)
141    }
142
143    /// Get the ID of the inverted clock.
144    pub fn inverted(&self) -> Self {
145        let mut inverted = *self;
146        inverted.flip_bit(Self::BIT_INDEX_INVERTED);
147        inverted
148    }
149
150    /// For actual signals: Test if the signal can change on the given edge type of the associated clock.
151    /// For required signals: Test if the constraint applies to the given edge type of the associated clock.
152    pub fn is_sensitive_on_edge(&self, edge_type: RiseFall) -> bool {
153        let bit_idx = match edge_type {
154            RiseFall::Rise => Self::BIT_INDEX_RISING_EDGE,
155            RiseFall::Fall => Self::BIT_INDEX_FALLING_EDGE,
156        };
157
158        self.get_bit(bit_idx)
159    }
160
161    /// For actual signals: Define if the signal annotated with this ID can change on the given clock edge.
162    pub fn set_edge_sensitivity(&mut self, edge_type: RiseFall, can_change: bool) {
163        let bit_idx = match edge_type {
164            RiseFall::Rise => Self::BIT_INDEX_RISING_EDGE,
165            RiseFall::Fall => Self::BIT_INDEX_FALLING_EDGE,
166        };
167
168        self.set_bit(bit_idx, can_change);
169    }
170
171    /// Set the value of the bit at the given index.
172    fn set_bit(&mut self, bit_idx: usize, value: bool) {
173        debug_assert!(bit_idx < Self::NUM_FLAGS, "cannot modify the clock index");
174        let id = self.id.get();
175
176        // Clear flag.
177        let id = id & (!(1 << bit_idx));
178        // Conditionally set flag.
179        let id = id | ((value as u32) << bit_idx);
180
181        // Store the modified id.
182        self.id = NonZeroU32::new(id).unwrap();
183    }
184
185    /// Flip the bit at the given index.
186    /// # Panics
187    /// Panics if the bitflip leads to an all-zero value.
188    fn flip_bit(&mut self, bit_idx: usize) {
189        debug_assert!(
190            bit_idx < Self::NUM_FLAGS,
191            "bit index out of range: cannot modify the clock index"
192        );
193        let id = self.id.get() ^ (1 << bit_idx);
194        self.id = NonZeroU32::new(id).unwrap()
195    }
196
197    /// Get the value of the bit a the given index.
198    fn get_bit(&self, bit_idx: usize) -> bool {
199        debug_assert!(
200            bit_idx < Self::NUM_FLAGS,
201            "bit index out of range: cannot modify the clock index"
202        );
203        self.id.get() & (1 << bit_idx) != 0
204    }
205}
206
207#[test]
208fn test_create_clock_id() {
209    let id = ClockId::new(7);
210    assert_eq!(id.storage_index(), 7);
211    // Check defaults:
212    assert!(!id.is_clock());
213    assert!(!id.is_inverted());
214    assert!(id.is_sensitive_on_edge(RiseFall::Rise));
215    assert!(id.is_sensitive_on_edge(RiseFall::Fall));
216}
217
218#[test]
219fn test_clock_id_set_flags() {
220    let mut id = ClockId::new(7);
221    id.set_clock(true);
222    assert!(id.is_clock());
223    assert!(id.inverted().is_inverted());
224    assert!(!id.inverted().inverted().is_inverted());
225}
226
227/// Signal representation wich can keep track of the clock(s) which launch the signal transition.
228#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
229pub struct SignalWithClock<S> {
230    /// Underlying signal representation.
231    inner: S,
232    /// Clock which drives this signal.
233    clock_id: Option<ClockId>,
234}
235
236impl<S> Deref for SignalWithClock<S> {
237    type Target = S;
238
239    fn deref(&self) -> &Self::Target {
240        &self.inner
241    }
242}
243
244impl<S> SignalWithClock<S> {
245    /// Wrap a signal without clock ID.
246    pub fn new(signal: S) -> Self {
247        Self {
248            inner: signal,
249            clock_id: Default::default(),
250        }
251    }
252
253    /// Set the ID of the clock which triggers this signal.
254    pub fn with_clock_id(mut self, clock_id: Option<ClockId>) -> Self {
255        self.set_clock_id(clock_id);
256        self
257    }
258
259    /// Set or clear the associated clock ID.
260    pub fn set_clock_id(&mut self, clock_id: Option<ClockId>) {
261        self.clock_id = clock_id;
262    }
263
264    /// Get the ID of the clock which launches this signal.
265    pub fn clock_id(&self) -> Option<ClockId> {
266        self.clock_id
267    }
268
269    /// Access the underlying signal data.
270    pub fn inner(&self) -> &S {
271        &self.inner
272    }
273
274    /// Get the underlying signal data.
275    pub fn into_inner(self) -> S {
276        self.inner
277    }
278}
279
280impl<S> RequiredSignal for SignalWithClock<S> where S: RequiredSignal {}
281
282impl<S> Signal for SignalWithClock<S>
283where
284    S: Signal,
285{
286    type LogicValue = S::LogicValue;
287
288    fn logic_value(&self) -> Self::LogicValue {
289        self.inner.logic_value()
290    }
291
292    fn transition_type(&self) -> SignalTransitionType {
293        self.inner.transition_type()
294    }
295
296    fn with_transition_type(self, trans: SignalTransitionType) -> Self {
297        let clock_id = self.clock_id;
298        Self {
299            inner: self.inner.with_transition_type(trans),
300            clock_id,
301        }
302    }
303}
304
305/// Wrap a delay and/or constraint model and add the capability of tracking
306/// clock sources.
307#[derive(Debug)]
308pub struct ClockAwareModel<M> {
309    /// Underlying delay/constraint model.
310    pub(crate) inner: M,
311    /// Clock definitions.
312    ///
313    /// During signal propagation this does not need to be accessed most of the time.
314    /// Only when merging signals from different clock domains it is necessary
315    /// to acquire a read or even write lock.
316    clocks: RwLock<Clocks>,
317}
318
319impl<M> Deref for ClockAwareModel<M> {
320    type Target = M;
321
322    fn deref(&self) -> &Self::Target {
323        &self.inner
324    }
325}
326
327impl<M> ClockAwareModel<M> {
328    /// Wrap a cell delay model.
329    pub fn new(inner_model: M) -> Self {
330        Self {
331            inner: inner_model,
332            clocks: Default::default(),
333        }
334    }
335
336    /// Register a clock. Returns an ID which can be used for labelling signals with this clock.
337    pub fn create_primary_clock(&mut self, period: Time, jitter: Time) -> ClockId {
338        let clock_definition = PrimaryClockDefinition { period, jitter };
339
340        self.clocks
341            .write()
342            .expect("failed to acquire read lock")
343            .create_defined_clock(clock_definition)
344    }
345
346    /// Merge the clock IDs of two delay arcs.
347    ///
348    /// Typically, the clock IDs of two merging delay arcs are identical. In this case the clock ID remains the same.
349    /// When joining delay arcs from different clock domains, it will be necessary to create a new clock ID
350    /// which refers to the both clock domains being joined.
351    fn join_clocks(&self, clock1: Option<ClockId>, clock2: Option<ClockId>) -> Option<ClockId> {
352        // Merging two clocks.
353        // Requires to create a new clock definition or find an existing one which matches.
354
355        match (clock1, clock2) {
356            // Both clock IDs are equal:
357            (c1, c2) if c1 == c2 => c1,
358            // Clock IDs are different:
359            (Some(c1), Some(c2)) => {
360                debug_assert_ne!(c1, c2);
361                // Need to merge the two clock IDs.
362
363                // Find existing merged clock ID, if any.
364                let existing_id = {
365                    let ids = smallvec::smallvec![c1, c2];
366                    let clocks = self.clocks.read().expect("failed to acquire read-lock");
367                    clocks.find_joined_clock_id(ids)
368                };
369
370                let joined_id = existing_id.unwrap_or_else(|| {
371                    // Joined clock does not exist yet. Need to create it.
372                    let ids = smallvec::smallvec![c1, c2];
373                    let mut clocks = self.clocks.write().expect("failed to acquire write-lock");
374                    clocks.create_joined_clock(ids)
375                });
376
377                Some(joined_id)
378            }
379            // Only one signal has a clock ID:
380            (None, Some(c)) | (Some(c), None) => Some(c),
381            // No clock ID present:
382            (None, None) => None,
383        }
384    }
385
386    fn join_clocks_of_required_signals(
387        &self,
388        clock1: Option<ClockId>,
389        clock2: Option<ClockId>,
390    ) -> Option<ClockId> {
391        self.join_clocks(clock1, clock2)
392    }
393
394    /// Get clock period.
395    fn clock_period(&self, clock_id: ClockId) -> Time {
396        let clocks_guard = self.clocks.read().unwrap();
397        let clock = clocks_guard.get_by_id(&clock_id);
398        match clock {
399            Clock::Primary(p) => p.period,
400            Clock::Joined(_) => {
401                // TODO
402                // Make all timing fail by setting clock period to zero.
403                Time::zero()
404            }
405        }
406    }
407}
408
409/// Collection of defined/generated/derived clocks.
410#[derive(Debug, Clone, Default)]
411struct Clocks {
412    /// Clock definitions.
413    /// `ClockId`s refer to this definitions.
414    clocks: Vec<Clock>,
415    /// Lookup-table to find the clock ID which results from joining multiple clocks together.
416    /// The clock IDs in the key of the map must be sorted lexicographically.
417    joined_clocks: HashMap<SmallVec<[ClockId; 2]>, ClockId>,
418}
419
420impl Clocks {
421    /// Create a new defined clock.
422    /// Also creates the inverted clock.
423    fn create_defined_clock(&mut self, clock_definition: PrimaryClockDefinition) -> ClockId {
424        assert!(self.clocks.len() < u32::MAX as usize - 2);
425
426        let mut new_id = self.next_id();
427        new_id.set_clock(true);
428
429        self.clocks.push(Clock::Primary(clock_definition));
430        new_id
431    }
432
433    /// Get the next free clock ID.
434    fn next_id(&self) -> ClockId {
435        ClockId::new(self.clocks.len() as u32)
436    }
437
438    /// Get a clock by its ID.
439    fn get_by_id(&self, id: &ClockId) -> &Clock {
440        &self.clocks[id.storage_index()]
441    }
442
443    /// Find existing merged clock ID, if any.
444    fn find_joined_clock_id(
445        &self,
446        mut source_clock_ids: SmallVec<[ClockId; 2]>,
447    ) -> Option<ClockId> {
448        // Normalize the list of IDs such that it can be used for table-lookup:
449        source_clock_ids.sort();
450        source_clock_ids.dedup();
451
452        self.joined_clocks
453            .get(&source_clock_ids)
454            .copied()
455            .or_else(|| {
456                // Replace IDs of joined clocks with their primary sources.
457                // This is the canonical form and guarantees finding the existing joined clock, if it exists.
458                // But it has some overhead.
459                let resolved_ids = self.resolve_joined_clocks(source_clock_ids.iter().copied());
460                self.joined_clocks.get(&resolved_ids).copied()
461            })
462    }
463
464    /// Replace IDs of joined clocks with the primary clock sources of the joined clocks.
465    fn resolve_joined_clocks(&self, ids: impl Iterator<Item = ClockId>) -> SmallVec<[ClockId; 2]> {
466        let mut primary_clock_ids: SmallVec<[_; 2]> = smallvec![];
467        // Flatten the clock IDs such that the list contains only primary clock sources.
468        for src_id in ids {
469            match self.get_by_id(&src_id) {
470                // Use primary clock IDs as is.
471                Clock::Primary(_) => primary_clock_ids.push(src_id),
472                // Resolve joined clocks.
473                Clock::Joined(clock_def) => {
474                    // Flatten.
475                    for inner_id in &clock_def.source_clocks {
476                        // Sanity check:
477                        debug_assert!(
478                            matches!(self.get_by_id(inner_id), Clock::Primary(_)),
479                            "definition of joined clock should contain only primary clocks"
480                        );
481                        // Use flags from provided clock ID.
482                        let primary_id = inner_id.with_flags_from(src_id);
483                        primary_clock_ids.push(primary_id);
484                    }
485                }
486            }
487        }
488
489        // Normalize
490        primary_clock_ids.sort();
491        primary_clock_ids.dedup();
492
493        primary_clock_ids
494    }
495
496    /// Create new clock by joining delay arcs from multiple clock domains.
497    fn create_joined_clock(&mut self, mut source_clock_ids: SmallVec<[ClockId; 2]>) -> ClockId {
498        source_clock_ids.sort();
499        source_clock_ids.dedup();
500
501        let primary_clock_ids = self.resolve_joined_clocks(source_clock_ids.iter().copied());
502
503        // Sanity check:
504        debug_assert!(
505            !self.joined_clocks.contains_key(&source_clock_ids),
506            "joined clock already exists"
507        );
508
509        let clock_definition = JoinedClockDefinition {
510            source_clocks: primary_clock_ids.clone(),
511        };
512
513        let new_id = self.next_id();
514        // Store clock definition.
515        self.clocks.push(Clock::Joined(clock_definition));
516
517        // Register in lookup table.
518        self.joined_clocks.insert(source_clock_ids, new_id);
519        self.joined_clocks.insert(primary_clock_ids, new_id);
520
521        new_id
522    }
523}
524
525/// Definiton of a clock source.
526/// This represents user-defined clocks.
527#[derive(Debug, Clone)]
528struct PrimaryClockDefinition {
529    period: Time,
530    jitter: Time,
531}
532
533/// Clock which emerged from joining delay arcs from multiple clock domains.
534#[derive(Debug, Clone)]
535struct JoinedClockDefinition {
536    /// IDs of the clock which have been joined.
537    source_clocks: SmallVec<[ClockId; 2]>,
538}
539
540#[derive(Debug, Clone)]
541enum Clock {
542    /// A clock defined by constraints.
543    Primary(PrimaryClockDefinition),
544    /// A clock which emerged by joining delay arcs from multiple clock domains.
545    Joined(JoinedClockDefinition),
546}
547
548impl<M> LoadBase for ClockAwareModel<M>
549where
550    M: LoadBase,
551{
552    type Load = M::Load;
553
554    fn sum_loads(&self, load1: &Self::Load, load2: &Self::Load) -> Self::Load {
555        self.inner.sum_loads(load1, load2)
556    }
557}
558
559impl<M> TimingBase for ClockAwareModel<M>
560where
561    M: TimingBase,
562{
563    type Signal = SignalWithClock<M::Signal>;
564
565    type LogicValue = M::LogicValue;
566}
567
568impl<M> DelayBase for ClockAwareModel<M>
569where
570    M: DelayBase,
571{
572    type Delay = M::Delay;
573
574    fn summarize_delays(&self, signal1: &Self::Signal, signal2: &Self::Signal) -> Self::Signal {
575        let s = self.inner.summarize_delays(&signal1.inner, &signal2.inner);
576
577        let clock_id = self.join_clocks(signal1.clock_id, signal2.clock_id);
578        SignalWithClock { inner: s, clock_id }
579    }
580
581    fn get_delay(&self, from: &Self::Signal, to: &Self::Signal) -> Self::Delay {
582        self.inner.get_delay(&from.inner, &to.inner)
583    }
584}
585
586impl<M> ConstraintBase for ClockAwareModel<M>
587where
588    M: ConstraintBase,
589{
590    type Constraint = M::Constraint;
591
592    type RequiredSignal = SignalWithClock<M::RequiredSignal>;
593
594    type Slack = M::Slack;
595
596    fn summarize_constraints(
597        &self,
598        constraint1: &Self::RequiredSignal,
599        constraint2: &Self::RequiredSignal,
600    ) -> Self::RequiredSignal {
601        let constraint_without_clock = self
602            .inner
603            .summarize_constraints(constraint1.inner(), constraint2.inner());
604
605        // Merge clock IDs.
606        let clock_id =
607            self.join_clocks_of_required_signals(constraint1.clock_id(), constraint2.clock_id());
608
609        SignalWithClock {
610            inner: constraint_without_clock,
611            clock_id,
612        }
613    }
614
615    fn solve_delay_constraint(
616        &self,
617        actual_delay: &Self::Delay,
618        required_output: &Self::RequiredSignal,
619        actual_signal: &Self::Signal,
620    ) -> Self::RequiredSignal {
621        let without_clock = self.inner.solve_delay_constraint(
622            actual_delay,
623            required_output.inner(),
624            actual_signal.inner(),
625        );
626
627        SignalWithClock {
628            inner: without_clock,
629            clock_id: required_output.clock_id(),
630        }
631    }
632
633    fn get_slack(
634        &self,
635        actual_signal: &Self::Signal,
636        required_signal: &Self::RequiredSignal,
637    ) -> Self::Slack {
638        self.inner
639            .get_slack(actual_signal.inner(), required_signal.inner())
640    }
641
642    fn add_clock_period(
643        &self,
644        required: Self::RequiredSignal,
645        clock_period: Time,
646    ) -> Self::RequiredSignal {
647        SignalWithClock {
648            inner: self.inner.add_clock_period(required.inner, clock_period),
649            ..required
650        }
651    }
652}
653
654impl<M, N> CellModel<N> for ClockAwareModel<M>
655where
656    N: db::NetlistBase,
657    M: CellModel<N>,
658{
659    fn ordered_pins(
660        &self,
661        cell: &<N>::CellId,
662    ) -> Vec<<N as libreda_db::traits::NetlistIds>::PinId> {
663        self.inner.ordered_pins(cell)
664    }
665}
666
667impl<M, N> CellDelayModel<N> for ClockAwareModel<M>
668where
669    N: db::NetlistBase,
670    M: CellDelayModel<N> + LogicModel<N>,
671    M::LogicValue: libreda_logic::traits::LogicOps + TryInto<bool>,
672{
673    fn cell_output(
674        &self,
675        netlist: &N,
676        arc: &CellDelayArc<N::PinId>,
677        input_signal: &Self::Signal,
678        output_load: &Self::Load,
679        other_inputs: &impl Fn(&N::PinId) -> Option<Self::LogicValue>,
680    ) -> Option<Self::Signal> {
681        // Query the timing model.
682        let output_signals_without_clock =
683            self.inner
684                .cell_output(netlist, arc, &input_signal.inner, output_load, other_inputs);
685
686        // Get logic function of this output pin.
687        let output_function = self.inner.pin_function(&arc.output_pin.0);
688
689        // Distinguish between combinational and sequential outputs.
690        let is_combinational_arc = match output_function {
691            OutputFunction::Unknown => true, // Assume it is combinational.
692            OutputFunction::Comb(_) => true,
693            OutputFunction::Sequential(_) => false,
694        };
695
696        let clock_id = input_signal.clock_id.and_then(|input_clock_id| {
697            if input_clock_id.is_clock() {
698                // This is a clock signal.
699                // The logic function of the cell may have an impact on the clock ID.
700
701                // Construct the clock ID of the output signal.
702                let mut output_clock_id = input_clock_id;
703
704                // Remember on which clock edge this signal can change it's value.
705                output_clock_id.set_edge_sensitivity(arc.input_pin.1, true);
706
707                // Clear clock-flag when passing through a sequential delay arc.
708                // When passing through a combinational circuit (buffer, inverter, mux, ...)
709                // a clock signal is still considered a clock signal.
710                output_clock_id.set_clock(is_combinational_arc);
711
712                // For combinational arcs: investigate if the clock gets inverted or set to a constant.
713                if is_combinational_arc {
714                    let unateness = self.inner.timing_sense(
715                        &arc.output_pin.0,
716                        &arc.input_pin.0,
717                        // Provide logic values of other inputs (if available):
718                        &|pin| {
719                            // Convert logic values to boolean values (if possible)
720                            other_inputs(pin).and_then(|l| l.try_into().ok())
721                        },
722                    );
723
724                    // Set flags according to the logic function of the arc.
725                    use crate::cell_logic_model::Unateness;
726                    match unateness {
727                        Unateness::None => {
728                            todo!("ClockId needs to know concept of 'unknown polarity'");
729                        }
730                        Unateness::Negative => Some(output_clock_id.inverted()),
731                        Unateness::Positive => {
732                            // Changes nothing about the semantics of the clock signal.
733                            Some(output_clock_id)
734                        }
735                    }
736                } else {
737                    // Sequential arc.
738                    // TODO
739                    debug_assert!(
740                        !output_clock_id.is_clock(),
741                        "clock-flag should be cleared already"
742                    );
743                    Some(output_clock_id)
744                }
745            } else {
746                // Not a clock signal.
747                // The logic function of the cell has no impact on the clock ID.
748                Some(input_clock_id)
749            }
750        });
751
752        // Annotate the output signal with the derived clock ID.
753        output_signals_without_clock.map(|s| SignalWithClock { inner: s, clock_id })
754    }
755
756    fn delay_arcs(
757        &self,
758        netlist: &N,
759        cell_id: &N::CellId,
760    ) -> impl Iterator<Item = CellDelayArc<N::PinId>> + '_ {
761        self.inner.delay_arcs(netlist, cell_id)
762    }
763}
764
765impl<M, N> CellConstraintModel<N> for ClockAwareModel<M>
766where
767    N: db::NetlistBase,
768    M: CellConstraintModel<N>,
769{
770    fn get_required_input(
771        &self,
772        netlist: &N,
773        arc: &CellConstraintArc<N::PinId>,
774        constrained_pin_signal: &Self::Signal,
775        related_pin_signal: &Self::Signal,
776        other_inputs: &impl Fn(&<N>::PinId) -> Option<Self::Signal>,
777        output_loads: &impl Fn(&<N>::PinId) -> Option<Self::Load>,
778    ) -> Option<Self::RequiredSignal> {
779        // Find clock ID associated with the required signal.
780        let clock_id = related_pin_signal.clock_id().map(|mut clock_id| {
781            // TODO: Set flags of clock ID.
782            // Requires knowledge of the constraint type.
783            // Most likely clear the "clock" flag.
784            clock_id.set_clock(false);
785            // Set default values:
786            clock_id.set_edge_sensitivity(RiseFall::Rise, false);
787            clock_id.set_edge_sensitivity(RiseFall::Fall, false);
788
789            use SignalTransitionType::*;
790            match related_pin_signal.transition_type() {
791                Rise => clock_id.set_edge_sensitivity(RiseFall::Rise, true),
792                Fall => clock_id.set_edge_sensitivity(RiseFall::Fall, true),
793                Any => {
794                    panic!("propagated signals should have a defined edge polarity");
795                }
796                Constant(_) => {
797                    // Not sensitive to any clock edge because the related signal is constant.
798                }
799            };
800            clock_id
801        });
802
803        let clock_period: Option<_> = clock_id.map(|c| self.clock_period(c));
804
805        // Get the required signal from the underlying model.
806        let required_signal_without_clock = self.inner.get_required_input(
807            netlist,
808            arc,
809            &constrained_pin_signal.inner,
810            &related_pin_signal.inner,
811            &|pin_id| other_inputs(pin_id).map(|signal| signal.inner),
812            output_loads,
813        );
814
815        // Add clock period to arrival time for setup constraints.
816        let required_signal_without_clock = if let Some(t_clock) = clock_period {
817            required_signal_without_clock.map(|r| self.inner.add_clock_period(r, t_clock))
818        } else {
819            required_signal_without_clock
820        };
821
822        // Annotate the signal with a clock ID.
823        required_signal_without_clock.map(|signal| SignalWithClock {
824            inner: signal,
825            clock_id,
826        })
827    }
828
829    fn constraint_arcs(
830        &self,
831        netlist: &N,
832        cell_id: &<N>::CellId,
833    ) -> impl Iterator<Item = CellConstraintArc<N::PinId>> + '_ {
834        self.inner.constraint_arcs(netlist, cell_id)
835    }
836}
837
838/// Wrapper around interconnect delay models.
839///
840/// Used to keep the link between signals and their clock domains.
841/// The data-structure is zero-cost for the interconnect model.
842/// The data-structure for the signals gets larger because of the additional clock ID.
843#[derive(Debug, Clone)]
844pub struct ClockAwareInterconnectModel<M> {
845    /// Underlying interconnect model.
846    inner: M,
847}
848
849impl<M> ClockAwareInterconnectModel<M> {
850    /// Wrap an interconnect model.
851    /// This is zero-cost. Best use a reference type as the inner model.
852    pub fn new(inner_model: M) -> Self {
853        Self { inner: inner_model }
854    }
855}
856
857/// Delegate trait implementation to the inner model.
858impl<M> LoadBase for ClockAwareInterconnectModel<M>
859where
860    M: LoadBase,
861{
862    type Load = M::Load;
863
864    fn sum_loads(&self, load1: &Self::Load, load2: &Self::Load) -> Self::Load {
865        self.inner.sum_loads(load1, load2)
866    }
867}
868
869/// Delegate trait implementation to the inner model.
870impl<M> TimingBase for ClockAwareInterconnectModel<M>
871where
872    M: TimingBase,
873{
874    type Signal = SignalWithClock<M::Signal>;
875
876    type LogicValue = M::LogicValue;
877}
878
879/// Delegate trait implementation to the inner model.
880impl<M> DelayBase for ClockAwareInterconnectModel<M>
881where
882    M: DelayBase,
883{
884    type Delay = M::Delay;
885    fn summarize_delays(&self, signal1: &Self::Signal, signal2: &Self::Signal) -> Self::Signal {
886        assert_eq!(
887            signal1.clock_id, signal2.clock_id,
888            "signals must have same clock ID" // TODO: Do they?
889        );
890        let signal_without_clock = self.inner.summarize_delays(&signal1.inner, &signal2.inner);
891
892        Self::Signal {
893            inner: signal_without_clock,
894            clock_id: signal1.clock_id,
895        }
896    }
897
898    fn get_delay(&self, from: &Self::Signal, to: &Self::Signal) -> Self::Delay {
899        self.inner.get_delay(&from.inner, &to.inner)
900    }
901}
902
903impl<M, N> InterconnectDelayModel<N> for ClockAwareInterconnectModel<M>
904where
905    N: db::NetlistBase,
906    M: InterconnectDelayModel<N>,
907{
908    fn interconnect_output(
909        &self,
910        netlist: &N,
911        source_terminal: &db::TerminalId<N>,
912        input_signal: &Self::Signal,
913        target_terminal: &db::TerminalId<N>,
914        output_load: &Self::Load,
915    ) -> Option<Self::Signal> {
916        // Query the underlying interconnect model.
917        let output_without_clock = self.inner.interconnect_output(
918            netlist,
919            source_terminal,
920            &input_signal.inner,
921            target_terminal,
922            output_load,
923        );
924
925        // Propagate the clock ID.
926        output_without_clock.map(|s| SignalWithClock {
927            inner: s,
928            clock_id: input_signal.clock_id,
929        })
930    }
931}