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 pub package_instances: HashSet<InstanceId>,
118}
119
120impl fmt::Debug for FrontendLookup {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 f.debug_struct("FrontendLookup")
123 .field("instances", &self.instance_module.len())
124 .field("modules", &self.module_variables.len())
125 .field("projected_state_objects", &self.source_to_state.len())
126 .finish_non_exhaustive()
127 }
128}
129
130impl FrontendLookup {
131 pub fn instance_path_segments(&self, path: &InstancePath) -> Vec<String> {
132 let mut prefix = Vec::with_capacity(path.0.len());
133 path.0
134 .iter()
135 .map(|(name, index)| {
136 prefix.push((name.clone(), *index));
137 let instance = self.instance_ids.get(&InstancePath(prefix.clone()));
138 if instance.is_some_and(|id| self.indexed_instances.contains(id)) {
139 format!("{name}[{index}]")
140 } else {
141 name.clone()
142 }
143 })
144 .collect()
145 }
146
147 pub fn root_instance_and_module(&self) -> Option<(InstanceId, ModuleId)> {
148 let instance_id = *self.instance_ids.get(&InstancePath(Vec::new()))?;
149 let module_id = *self.instance_module.get(&instance_id)?;
150 Some((instance_id, module_id))
151 }
152
153 pub fn root_variable(&self, var_id: SourceVarId) -> Option<(StateAddr, &VariableInfo)> {
154 let (instance_id, _) = self.root_instance_and_module()?;
155 self.instance_variable(instance_id, var_id)
156 }
157
158 pub fn instance_variable(
159 &self,
160 instance_id: InstanceId,
161 var_id: SourceVarId,
162 ) -> Option<(StateAddr, &VariableInfo)> {
163 let module_id = *self.instance_module.get(&instance_id)?;
164 let info = self.module_variables.get(&module_id)?.get(&var_id)?;
165 let address = self.state_address(&SourceAddr {
166 instance_id,
167 var_id,
168 })?;
169 Some((address, info))
170 }
171
172 pub fn root_named_variable(&self, name: &str) -> Option<(StateAddr, &VariableInfo)> {
173 let (_, module_id) = self.root_instance_and_module()?;
174 let var_id = self
175 .module_var_path_index
176 .get(&module_id)?
177 .get(&vec![name.to_string()])
178 .copied()
179 .flatten()?;
180 self.root_variable(var_id)
181 }
182
183 pub fn get_path(&self, address: &SourceAddr) -> String {
184 let instance_path = self
185 .instance_ids
186 .iter()
187 .find(|(_, id)| **id == address.instance_id)
188 .map(|(path, _)| path);
189 let module_id = self.instance_module.get(&address.instance_id).unwrap();
190 let module_vars = self.module_variables.get(module_id).unwrap();
191 let variable_path = module_vars
192 .values()
193 .find(|info| info.id == address.var_id)
194 .map(|info| &info.path);
195
196 let mut instance = Vec::new();
197 if let Some(instance_path) = instance_path {
198 instance.extend(self.instance_path_segments(instance_path));
199 }
200 let variable = variable_path.map(|path| path.join(".")).unwrap_or_default();
201 if self.package_instances.contains(&address.instance_id) {
203 return format!("{}{variable}", instance.join("."));
204 }
205 instance.extend((!variable.is_empty()).then_some(variable));
206 instance.join(".")
207 }
208
209 pub fn get_state_path(&self, address: &StateAddr) -> String {
210 self.state_to_source
211 .get(address)
212 .map(|source| self.get_path(source))
213 .unwrap_or_else(|| address.to_string())
214 }
215
216 pub fn source_address(&self, address: &StateAddr) -> Option<SourceAddr> {
217 self.state_to_source.get(address).copied()
218 }
219
220 pub fn state_address(&self, address: &SourceAddr) -> Option<StateAddr> {
221 self.source_to_state.get(address).copied()
222 }
223}