Skip to main content

celox_slt/
lib.rs

1//! Source-independent symbolic logic tree primitives.
2//!
3//! This crate owns semantic bit-range state independently of any HDL
4//! frontend. Frontends provide their own address identity and SLT node type.
5
6use std::collections::BTreeSet;
7
8use celox_design::{ModuleId, VarAtomBase};
9use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet};
10
11pub mod const_inline;
12mod lower;
13mod node;
14mod node_facts;
15mod node_rules;
16mod path;
17pub mod range_store;
18pub mod scheduler;
19mod symbolic_store;
20mod symbolic_verify;
21
22#[doc(hidden)]
23pub use lower::matches_slt_or_scan_group;
24pub use lower::{SLTToSIRLowerer, matches_slt_count_idiom};
25pub use node::{
26    NodeId, SLTForEffect, SLTForFoldGroupState, SLTForFoldResult, SLTForUpdate, SLTIndex,
27    SLTIndexKind, SLTLoopBound, SLTNode, SLTNodeArena, SLTNodeArenaEditError, SLTStepOp,
28};
29pub use node_facts::{SLTNodeFacts, SLTNodeFactsError};
30pub use path::{LogicPath, LogicPathId, LogicPathTarget};
31pub use range_store::{RangeStore, RangeStoreError};
32pub use scheduler::FfAccessSummary;
33pub use symbolic_store::SymbolicStore;
34pub use symbolic_verify::verify_symbolic_roots;
35
36/// Return the construction-time width cached when a node was interned.
37pub fn get_width<A: std::hash::Hash + Eq + Clone>(node: NodeId, arena: &SLTNodeArena<A>) -> usize {
38    arena
39        .width(node)
40        .unwrap_or_else(|| panic!("SLT node id n{} is outside the arena", node.0))
41}
42
43/// Symbolic state keyed by a frontend-independent semantic address.
44///
45/// `N` is the symbolic expression identity. It remains generic until the SLT
46/// arena itself moves into this crate.
47/// Bit boundaries discovered while constructing symbolic state.
48pub type BoundaryMap<A> = HashMap<A, BTreeSet<usize>>;
49
50/// Source-independent combinational observation recipe retained until SIR construction.
51#[derive(Clone, Debug)]
52pub struct CombObserver<A> {
53    pub site_id: u32,
54    pub activation_group: u32,
55    pub guard: Option<NodeId>,
56    pub args: Vec<NodeId>,
57    pub loop_runner: Option<NodeId>,
58    pub sensitivity: Vec<VarAtomBase<A>>,
59    pub local_inputs: Vec<(A, NodeId)>,
60    pub observed_inputs: Vec<VarAtomBase<A>>,
61    pub position_inputs: Vec<VarAtomBase<A>>,
62    pub preceding_writes: Vec<VarAtomBase<A>>,
63    pub written_before: Vec<VarAtomBase<A>>,
64    pub written_input_atoms: Vec<VarAtomBase<A>>,
65    pub written_inputs: Vec<A>,
66    pub captured_in_loop: bool,
67}
68
69#[derive(
70    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize,
71)]
72pub enum GlueAddrBase<V> {
73    Parent(V),
74    Child(V),
75}
76
77impl<V: Copy> GlueAddrBase<V> {
78    pub fn var_id(&self) -> V {
79        match self {
80            GlueAddrBase::Parent(value) | GlueAddrBase::Child(value) => *value,
81        }
82    }
83}
84
85impl<V: std::fmt::Display> std::fmt::Display for GlueAddrBase<V> {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        match self {
88            GlueAddrBase::Parent(value) => write!(f, "GlueAddr::Parent({value})"),
89            GlueAddrBase::Child(value) => write!(f, "GlueAddr::Child({value})"),
90        }
91    }
92}
93
94#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
95#[serde(bound(
96    serialize = "V: serde::Serialize",
97    deserialize = "V: serde::Deserialize<'de> + std::hash::Hash + Eq + Clone"
98))]
99pub struct GlueBlockBase<V: std::hash::Hash + Eq + Clone> {
100    pub module_id: ModuleId,
101    pub input_ports: Vec<(Vec<V>, LogicPath<GlueAddrBase<V>>)>,
102    pub output_ports: Vec<(Vec<V>, LogicPath<GlueAddrBase<V>>)>,
103    pub arena: SLTNodeArena<GlueAddrBase<V>>,
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109
110    #[test]
111    fn symbolic_store_key_is_a_semantic_address_not_a_frontend_id() {
112        #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
113        struct DesignAddress(u32);
114
115        let mut store = SymbolicStore::<DesignAddress, u32>::default();
116        store.insert(DesignAddress(7), RangeStore::new(None, 8));
117
118        assert!(store.contains_key(&DesignAddress(7)));
119    }
120}