celox_frontend_core/shared/
lookup.rs1use std::fmt;
2
3use celox_design::{AbsoluteAddrBase, InstanceId, ModuleId, StateAddr, VariableMetadata};
4use serde::{Deserialize, Serialize};
5
6use crate::{HashMap, HashSet};
7
8pub type SourceAddr = AbsoluteAddrBase<SourceVarId>;
9
10#[derive(
16 Debug, Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize,
17)]
18pub struct SourceVarId(pub u32);
19
20impl fmt::Display for SourceVarId {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 write!(f, "var{}", self.0)
23 }
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
28pub enum VariableKind {
29 Parameter,
30 Constant,
31 Input,
32 Output,
33 Inout,
34 Variable,
35 Let,
36}
37
38impl VariableKind {
39 pub const fn is_port(self) -> bool {
40 matches!(self, Self::Input | Self::Output | Self::Inout)
41 }
42
43 pub const fn description(self) -> &'static str {
44 match self {
45 Self::Parameter => "parameter",
46 Self::Constant => "constant",
47 Self::Input => "input",
48 Self::Output => "output",
49 Self::Inout => "inout",
50 Self::Variable => "variable",
51 Self::Let => "let-bounded variable",
52 }
53 }
54}
55
56#[derive(Clone, Serialize, Deserialize)]
57pub struct VariableInfo {
58 pub id: SourceVarId,
59 pub path: Vec<String>,
60 pub var_kind: VariableKind,
61 pub signed: bool,
62 pub metadata: VariableMetadata,
63 pub packed_dims: Vec<usize>,
69}
70
71impl std::ops::Deref for VariableInfo {
72 type Target = VariableMetadata;
73
74 fn deref(&self) -> &Self::Target {
75 &self.metadata
76 }
77}
78
79impl fmt::Debug for VariableInfo {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 f.debug_struct("VariableInfo")
82 .field("width", &self.width)
83 .field("id", &self.id)
84 .field("is_4state", &self.is_4state)
85 .field("signed", &self.signed)
86 .field("kind", &self.kind)
87 .field("type_kind", &self.type_kind)
88 .finish()
89 }
90}
91
92#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
93pub struct InstancePath(pub Vec<(String, usize)>);
94
95#[derive(Clone, Default, Serialize, Deserialize)]
99pub struct FrontendLookup {
100 pub instance_ids: HashMap<InstancePath, InstanceId>,
101 pub instance_module: HashMap<InstanceId, ModuleId>,
102 pub indexed_instances: HashSet<InstanceId>,
104 pub module_variables: HashMap<ModuleId, HashMap<SourceVarId, VariableInfo>>,
105 pub module_var_path_index: HashMap<ModuleId, HashMap<Vec<String>, Option<SourceVarId>>>,
108 pub module_names: HashMap<ModuleId, String>,
109 pub source_to_state: HashMap<SourceAddr, StateAddr>,
112 pub state_to_source: HashMap<StateAddr, SourceAddr>,
113 pub event_aliases: HashMap<StateAddr, StateAddr>,
115}
116
117impl fmt::Debug for FrontendLookup {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.debug_struct("FrontendLookup")
120 .field("instances", &self.instance_module.len())
121 .field("modules", &self.module_variables.len())
122 .field("projected_state_objects", &self.source_to_state.len())
123 .finish_non_exhaustive()
124 }
125}
126
127impl FrontendLookup {
128 pub fn instance_path_segments(&self, path: &InstancePath) -> Vec<String> {
129 let mut prefix = Vec::with_capacity(path.0.len());
130 path.0
131 .iter()
132 .map(|(name, index)| {
133 prefix.push((name.clone(), *index));
134 let instance = self.instance_ids.get(&InstancePath(prefix.clone()));
135 if instance.is_some_and(|id| self.indexed_instances.contains(id)) {
136 format!("{name}[{index}]")
137 } else {
138 name.clone()
139 }
140 })
141 .collect()
142 }
143
144 pub fn root_instance_and_module(&self) -> Option<(InstanceId, ModuleId)> {
145 let instance_id = *self.instance_ids.get(&InstancePath(Vec::new()))?;
146 let module_id = *self.instance_module.get(&instance_id)?;
147 Some((instance_id, module_id))
148 }
149
150 pub fn root_variable(&self, var_id: SourceVarId) -> Option<(StateAddr, &VariableInfo)> {
151 let (instance_id, _) = self.root_instance_and_module()?;
152 self.instance_variable(instance_id, var_id)
153 }
154
155 pub fn instance_variable(
156 &self,
157 instance_id: InstanceId,
158 var_id: SourceVarId,
159 ) -> Option<(StateAddr, &VariableInfo)> {
160 let module_id = *self.instance_module.get(&instance_id)?;
161 let info = self.module_variables.get(&module_id)?.get(&var_id)?;
162 let address = self.state_address(&SourceAddr {
163 instance_id,
164 var_id,
165 })?;
166 Some((address, info))
167 }
168
169 pub fn root_named_variable(&self, name: &str) -> Option<(StateAddr, &VariableInfo)> {
170 let (_, module_id) = self.root_instance_and_module()?;
171 let var_id = self
172 .module_var_path_index
173 .get(&module_id)?
174 .get(&vec![name.to_string()])
175 .copied()
176 .flatten()?;
177 self.root_variable(var_id)
178 }
179
180 pub fn get_path(&self, address: &SourceAddr) -> String {
181 let instance_path = self
182 .instance_ids
183 .iter()
184 .find(|(_, id)| **id == address.instance_id)
185 .map(|(path, _)| path);
186 let module_id = self.instance_module.get(&address.instance_id).unwrap();
187 let module_vars = self.module_variables.get(module_id).unwrap();
188 let variable_path = module_vars
189 .values()
190 .find(|info| info.id == address.var_id)
191 .map(|info| &info.path);
192
193 let mut result = Vec::new();
194 if let Some(instance_path) = instance_path {
195 result.extend(self.instance_path_segments(instance_path));
196 }
197 if let Some(variable_path) = variable_path {
198 result.extend(variable_path.iter().cloned());
199 }
200 result.join(".")
201 }
202
203 pub fn get_state_path(&self, address: &StateAddr) -> String {
204 self.state_to_source
205 .get(address)
206 .map(|source| self.get_path(source))
207 .unwrap_or_else(|| address.to_string())
208 }
209
210 pub fn source_address(&self, address: &StateAddr) -> Option<SourceAddr> {
211 self.state_to_source.get(address).copied()
212 }
213
214 pub fn state_address(&self, address: &SourceAddr) -> Option<StateAddr> {
215 self.source_to_state.get(address).copied()
216 }
217}