Skip to main content

celox_frontend_core/shared/
artifact.rs

1use std::fmt;
2
3use celox_design::{ElaboratedDesign, RegionedStateAddr, RuntimeSchema, StateAddr, VarAtomBase};
4use celox_sir::{SIRInstruction, SirProgram};
5
6use crate::{FrontendLookup, HashMap};
7
8/// Source-independent SIR and design data produced after all SLT nodes have
9/// been scheduled and lowered.
10///
11/// No `NodeId`, SLT arena, or source-language-owned testbench syntax may cross
12/// this boundary. `frontend_lookup` contains only neutral source IDs and owned
13/// strings.
14#[derive(Clone)]
15pub struct ScheduledRtl {
16    pub sir: SirProgram<StateAddr, RegionedStateAddr>,
17    pub design: ElaboratedDesign<StateAddr>,
18    pub frontend_lookup: FrontendLookup,
19    pub runtime_schema: RuntimeSchema<StateAddr>,
20}
21
22impl fmt::Debug for ScheduledRtl {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        f.debug_struct("ScheduledRtl")
25            .field("sir", &self.sir)
26            .field("design", &self.design)
27            .field("frontend_lookup", &self.frontend_lookup)
28            .field("runtime_schema", &self.runtime_schema)
29            .finish()
30    }
31}
32
33impl ScheduledRtl {
34    /// Attach runtime event IDs after fused SIR pre-optimization has removed
35    /// disposable state publications.
36    pub fn inject_triggers(&mut self) {
37        let mut trigger_map = HashMap::default();
38        for (id, address) in self.design.events.ordered_events.iter().enumerate() {
39            if let Some(metadata) = self.design.state_objects.get(address) {
40                trigger_map.entry(*address).or_insert_with(Vec::new).push(
41                    celox_design::TriggerIdWithKind {
42                        kind: metadata.kind,
43                        id,
44                    },
45                );
46            }
47        }
48
49        let events = &self.design.events;
50        for unit in self
51            .sir
52            .eval_apply_ffs
53            .values_mut()
54            .flatten()
55            .chain(self.sir.eval_comb_apply_ffs.values_mut().flatten())
56            .chain(self.sir.eval_only_ffs.values_mut().flatten())
57            .chain(self.sir.apply_ffs.values_mut().flatten())
58            .chain(self.sir.eval_comb.iter_mut())
59        {
60            for block in unit.blocks.values_mut() {
61                for instruction in &mut block.instructions {
62                    let (address, triggers) = match instruction {
63                        SIRInstruction::Store(address, _, _, _, triggers, _) => {
64                            (address.absolute_addr(), triggers)
65                        }
66                        SIRInstruction::Commit(_, address, .., triggers) => {
67                            (address.absolute_addr(), triggers)
68                        }
69                        _ => continue,
70                    };
71                    let canonical = events.canonical(address);
72                    if let Some(event_triggers) = trigger_map.get(&canonical) {
73                        *triggers = event_triggers.clone();
74                    }
75                }
76            }
77        }
78    }
79}
80
81/// Optimizer inputs derived while fused comb/FF scheduling still has exact
82/// action provenance. These hints are kept beside, not inside, `SirProgram`.
83#[derive(Clone, Debug, Default)]
84pub struct FusedSirOptimizationHints {
85    pub direct_ff_writes: HashMap<StateAddr, Vec<VarAtomBase<RegionedStateAddr>>>,
86}
87
88#[derive(Clone, Debug)]
89pub struct ScheduledRtlOutput {
90    pub scheduled: ScheduledRtl,
91    pub fused_optimization_hints: FusedSirOptimizationHints,
92}