Skip to main content

celox_slt/
path.rs

1use std::{fmt, hash::Hash};
2
3use serde::{Deserialize, Serialize};
4
5use celox_design::VarAtomBase;
6
7use crate::{HashMap, HashSet, NodeId, SLTNodeArena, SLTNodeFactsError};
8
9#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
10pub struct LogicPathId(pub usize);
11
12#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(bound(
14    serialize = "A: Serialize + std::hash::Hash + Eq",
15    deserialize = "A: Deserialize<'de> + std::hash::Hash + Eq + Clone"
16))]
17pub enum LogicPathTarget<A: Hash + Eq + Clone> {
18    Var(VarAtomBase<A>),
19    CombCaptureEvent {
20        site_id: u32,
21        guard: Option<NodeId>,
22        emit_on_true: bool,
23        args: Vec<NodeId>,
24        loop_runner: Option<NodeId>,
25        fatal_error_code: Option<i64>,
26        consume_enabled: bool,
27    },
28}
29
30impl<A: Hash + Eq + Clone> LogicPathTarget<A> {
31    pub fn var(&self) -> Option<&VarAtomBase<A>> {
32        match self {
33            LogicPathTarget::Var(var) => Some(var),
34            LogicPathTarget::CombCaptureEvent { .. } => None,
35        }
36    }
37}
38
39impl<A: fmt::Display + Hash + Eq + Clone> fmt::Display for LogicPathTarget<A> {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        match self {
42            LogicPathTarget::Var(var) => write!(f, "{var}"),
43            LogicPathTarget::CombCaptureEvent { site_id, .. } => {
44                write!(f, "capture_event({site_id})")
45            }
46        }
47    }
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
51#[serde(bound(
52    serialize = "A: Serialize + std::hash::Hash + Eq",
53    deserialize = "A: Deserialize<'de> + std::hash::Hash + Eq + Clone"
54))]
55pub struct LogicPath<A: Hash + Eq + Clone> {
56    /// Semantic combinational process which produced this range definition.
57    ///
58    pub target: LogicPathTarget<A>,
59    pub sources: HashSet<VarAtomBase<A>>,
60    pub previous_sources: HashSet<VarAtomBase<A>>,
61    /// Sources used to compute a dynamic address.  These remain ordinary
62    /// dependencies even when they overlap a previous-value source.
63    #[serde(default)]
64    pub address_sources: HashSet<VarAtomBase<A>>,
65    pub local_inputs: Vec<(A, NodeId)>,
66    pub order_before: HashSet<LogicPathId>,
67    pub comb_capture_enable_sites: Vec<u32>,
68    /// Enable the listed capture sites whenever this path executes, even when
69    /// assignment conversion leaves the stored target unchanged.
70    #[serde(default)]
71    pub comb_capture_enable_always: bool,
72    pub pre_lower_nodes: Vec<NodeId>,
73    pub expr: NodeId,
74}
75
76impl<A: fmt::Display + Hash + Eq + Clone> fmt::Display for LogicPath<A> {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        write!(f, "{}", self.target)
79    }
80}
81
82impl<A: fmt::Debug + fmt::Display + Hash + Eq + Clone> LogicPath<A> {
83    pub fn map_addr<B: Hash + Eq + Clone, F>(
84        &self,
85        arena: &SLTNodeArena<A>,
86        target_arena: &mut SLTNodeArena<B>,
87        cache: &mut HashMap<NodeId, NodeId>,
88        f: &F,
89    ) -> Result<LogicPath<B>, SLTNodeFactsError>
90    where
91        F: Fn(&A) -> B,
92    {
93        let target = match &self.target {
94            LogicPathTarget::Var(var) => {
95                LogicPathTarget::Var(VarAtomBase::new(f(&var.id), var.access.lsb, var.access.msb))
96            }
97            LogicPathTarget::CombCaptureEvent {
98                site_id,
99                guard,
100                emit_on_true,
101                args,
102                loop_runner,
103                fatal_error_code,
104                consume_enabled,
105            } => LogicPathTarget::CombCaptureEvent {
106                site_id: *site_id,
107                guard: guard
108                    .map(|node| {
109                        arena
110                            .get(node)
111                            .map_addr(node, arena, target_arena, cache, f)
112                    })
113                    .transpose()?,
114                emit_on_true: *emit_on_true,
115                args: args
116                    .iter()
117                    .map(|node| {
118                        arena
119                            .get(*node)
120                            .map_addr(*node, arena, target_arena, cache, f)
121                    })
122                    .collect::<Result<Vec<_>, SLTNodeFactsError>>()?,
123                loop_runner: loop_runner
124                    .map(|node| {
125                        arena
126                            .get(node)
127                            .map_addr(node, arena, target_arena, cache, f)
128                    })
129                    .transpose()?,
130                fatal_error_code: *fatal_error_code,
131                consume_enabled: *consume_enabled,
132            },
133        };
134        let local_inputs = self
135            .local_inputs
136            .iter()
137            .map(|(id, node)| {
138                Ok((
139                    f(id),
140                    arena
141                        .get(*node)
142                        .map_addr(*node, arena, target_arena, cache, f)?,
143                ))
144            })
145            .collect::<Result<Vec<_>, SLTNodeFactsError>>()?;
146        let pre_lower_nodes = self
147            .pre_lower_nodes
148            .iter()
149            .map(|node| {
150                arena
151                    .get(*node)
152                    .map_addr(*node, arena, target_arena, cache, f)
153            })
154            .collect::<Result<Vec<_>, SLTNodeFactsError>>()?;
155        let expr = arena
156            .get(self.expr)
157            .map_addr(self.expr, arena, target_arena, cache, f)?;
158
159        Ok(LogicPath {
160            target,
161            sources: self
162                .sources
163                .iter()
164                .map(|v| VarAtomBase::new(f(&v.id), v.access.lsb, v.access.msb))
165                .collect(),
166            previous_sources: self
167                .previous_sources
168                .iter()
169                .map(|v| VarAtomBase::new(f(&v.id), v.access.lsb, v.access.msb))
170                .collect(),
171            address_sources: self
172                .address_sources
173                .iter()
174                .map(|v| VarAtomBase::new(f(&v.id), v.access.lsb, v.access.msb))
175                .collect(),
176            local_inputs,
177            order_before: self.order_before.clone(),
178            comb_capture_enable_sites: self.comb_capture_enable_sites.clone(),
179            comb_capture_enable_always: self.comb_capture_enable_always,
180            pre_lower_nodes,
181            expr,
182        })
183    }
184}