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 pub target: LogicPathTarget<A>,
59 pub sources: HashSet<VarAtomBase<A>>,
60 pub previous_sources: HashSet<VarAtomBase<A>>,
61 #[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 #[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}