1mod field_ref;
2pub mod plugin_types;
3#[cfg(feature = "pyo3")]
4pub mod python;
5mod result;
6mod scope_ref;
7pub mod translator;
8pub mod variable_index;
9mod variable_ref;
10
11use derive_more::Display;
12use ecolor::Color32;
13#[cfg(feature = "wasm_plugins")]
14use extism_convert::{FromBytes, Json, ToBytes};
15use num::BigUint;
16use serde::{Deserialize, Serialize};
17use std::collections::HashMap;
18
19pub use crate::field_ref::FieldRef;
20pub use crate::result::{
21 HierFormatResult, SubFieldFlatTranslationResult, SubFieldTranslationResult, TranslatedValue,
22 TranslationResult, ValueRepr,
23};
24pub use crate::scope_ref::ScopeRef;
25pub use crate::translator::{
26 BasicTranslator, Translator, VariableNameInfo, WaveSource, translates_all_bit_types,
27};
28pub use crate::variable_index::VariableIndex;
29pub use crate::variable_ref::VariableRef;
30
31#[cfg_attr(feature = "wasm_plugins", derive(FromBytes, ToBytes))]
32#[cfg_attr(feature = "wasm_plugins", encoding(Json))]
33#[derive(Deserialize, Serialize)]
34pub struct PluginConfig(pub HashMap<String, String>);
35
36pub fn check_vector_variable(s: &str) -> Option<(String, ValueKind)> {
39 if s.contains('x') {
40 Some(("UNDEF".to_string(), ValueKind::Undef))
41 } else if s.contains('z') {
42 Some(("HIGHIMP".to_string(), ValueKind::HighImp))
43 } else if s.contains('-') {
44 Some(("DON'T CARE".to_string(), ValueKind::DontCare))
45 } else if s.contains('u') {
46 Some(("UNDEF".to_string(), ValueKind::Undef))
47 } else if s.contains('w') {
48 Some(("UNDEF WEAK".to_string(), ValueKind::Undef))
49 } else if s.contains('h') || s.contains('l') {
50 Some(("WEAK".to_string(), ValueKind::Weak))
51 } else if s.chars().all(|c| matches!(c, '0' | '1')) {
52 None
53 } else {
54 Some(("UNKNOWN VALUES".to_string(), ValueKind::Undef))
55 }
56}
57
58pub fn extend_string(val: &str, num_bits: u64) -> String {
60 if num_bits > val.len() as u64 {
61 let extra_count = num_bits - val.len() as u64;
62 let extra_value = match val.chars().next() {
63 Some('0') => "0",
64 Some('1') => "0",
65 Some('x') => "x",
66 Some('z') => "z",
67 _ => "",
71 };
72 extra_value.repeat(extra_count as usize)
73 } else {
74 String::new()
75 }
76}
77
78#[derive(Debug, PartialEq, Clone, Display, Serialize, Deserialize)]
79pub enum VariableValue {
80 #[display("{_0}")]
81 BigUint(BigUint),
82 #[display("{_0}")]
83 String(String),
84}
85
86impl VariableValue {
87 pub fn handle_bits<E>(
94 self,
95 handler: impl Fn(String) -> Result<TranslationResult, E>,
96 ) -> Result<TranslationResult, E> {
97 let value = match self {
98 VariableValue::BigUint(v) => format!("{v:b}"),
99 VariableValue::String(v) => {
100 if let Some((val, kind)) = check_vector_variable(&v) {
101 return Ok(TranslationResult {
102 val: ValueRepr::String(val),
103 subfields: vec![],
104 kind,
105 });
106 } else {
107 v
108 }
109 }
110 };
111
112 handler(value)
113 }
114}
115
116#[derive(Clone, PartialEq, Copy, Debug, Serialize, Deserialize)]
117pub enum ValueKind {
118 Normal,
119 Undef,
120 HighImp,
121 Custom(Color32),
122 Warn,
123 DontCare,
124 Weak,
125 Error,
126}
127
128#[cfg_attr(feature = "wasm_plugins", derive(FromBytes, ToBytes))]
129#[cfg_attr(feature = "wasm_plugins", encoding(Json))]
130#[derive(PartialEq, Deserialize, Serialize, Debug)]
131pub enum TranslationPreference {
132 Prefer,
135 Yes,
138 No,
139}
140
141#[cfg_attr(feature = "wasm_plugins", derive(FromBytes, ToBytes))]
143#[cfg_attr(feature = "wasm_plugins", encoding(Json))]
144#[derive(Clone, Debug, Default, Deserialize, Serialize)]
145pub enum VariableInfo {
146 Compound {
147 subfields: Vec<(String, VariableInfo)>,
148 },
149 Bits,
150 Bool,
151 Clock,
152 #[default]
154 String,
155 Real,
156}
157
158#[derive(Debug, Display, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
159pub enum VariableType {
160 #[display("event")]
162 VCDEvent,
163 #[display("reg")]
164 VCDReg,
165 #[display("wire")]
166 VCDWire,
167 #[display("real")]
168 VCDReal,
169 #[display("time")]
170 VCDTime,
171 #[display("string")]
172 VCDString,
173 #[display("parameter")]
174 VCDParameter,
175 #[display("integer")]
176 VCDInteger,
177 #[display("real time")]
178 VCDRealTime,
179 #[display("supply 0")]
180 VCDSupply0,
181 #[display("supply 1")]
182 VCDSupply1,
183 #[display("tri")]
184 VCDTri,
185 #[display("tri and")]
186 VCDTriAnd,
187 #[display("tri or")]
188 VCDTriOr,
189 #[display("tri reg")]
190 VCDTriReg,
191 #[display("tri 0")]
192 VCDTri0,
193 #[display("tri 1")]
194 VCDTri1,
195 #[display("wand")]
196 VCDWAnd,
197 #[display("wor")]
198 VCDWOr,
199 #[display("port")]
200 Port,
201 #[display("sparse array")]
202 SparseArray,
203 #[display("realtime")]
204 RealTime,
205
206 #[display("bit")]
208 Bit,
209 #[display("logic")]
210 Logic,
211 #[display("int")]
212 Int,
213 #[display("shortint")]
214 ShortInt,
215 #[display("longint")]
216 LongInt,
217 #[display("byte")]
218 Byte,
219 #[display("enum")]
220 Enum,
221 #[display("shortreal")]
222 ShortReal,
223
224 #[display("boolean")]
226 Boolean,
227 #[display("bit_vector")]
228 BitVector,
229 #[display("std_logic")]
230 StdLogic,
231 #[display("std_logic_vector")]
232 StdLogicVector,
233 #[display("std_ulogic")]
234 StdULogic,
235 #[display("std_ulogic_vector")]
236 StdULogicVector,
237}
238
239#[derive(Clone, Display, Copy, PartialOrd, Debug, Eq, PartialEq, Serialize, Deserialize)]
240pub enum VariableDirection {
241 #[display("input")]
243 Input,
244 #[display("output")]
245 Output,
246 #[display("inout")]
247 InOut,
248 #[display("buffer")]
249 Buffer,
250 #[display("linkage")]
251 Linkage,
252 #[display("implicit")]
253 Implicit,
254 #[display("unknown")]
255 Unknown,
256}
257
258#[cfg_attr(feature = "wasm_plugins", derive(FromBytes, ToBytes))]
259#[cfg_attr(feature = "wasm_plugins", encoding(Json))]
260#[derive(Clone, Debug, Serialize, Deserialize)]
261pub struct VariableMeta<VarId, ScopeId> {
262 pub var: VariableRef<VarId, ScopeId>,
263 pub num_bits: Option<u32>,
264 pub variable_type: Option<VariableType>,
266 pub variable_type_name: Option<String>,
268 pub index: Option<VariableIndex>,
269 pub direction: Option<VariableDirection>,
270 pub enum_map: HashMap<String, String>,
271 pub encoding: VariableEncoding,
274}
275
276#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
277pub enum VariableEncoding {
278 String,
279 Real,
280 BitVector,
281}
282
283impl<VarId1, ScopeId1> VariableMeta<VarId1, ScopeId1> {
284 pub fn map_ids<VarId2, ScopeId2>(
285 self,
286 var_fn: impl FnMut(VarId1) -> VarId2,
287 scope_fn: impl FnMut(ScopeId1) -> ScopeId2,
288 ) -> VariableMeta<VarId2, ScopeId2> {
289 VariableMeta {
290 var: self.var.map_ids(var_fn, scope_fn),
291 num_bits: self.num_bits,
292 variable_type: self.variable_type,
293 index: self.index,
294 direction: self.direction,
295 enum_map: self.enum_map,
296 encoding: self.encoding,
297 variable_type_name: self.variable_type_name,
298 }
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use super::{ValueKind, check_vector_variable, extend_string};
305
306 #[test]
307 fn binary_only_returns_none() {
308 for s in ["0", "1", "0101", "1111", "000000", "101010"].iter() {
309 assert_eq!(check_vector_variable(s), None, "{s}");
310 }
311 }
312
313 #[test]
314 fn x_marks_undef() {
315 let res = check_vector_variable("10x01").unwrap();
316 assert_eq!(res.0, "UNDEF");
317 assert_eq!(res.1, ValueKind::Undef);
318 }
319
320 #[test]
321 fn u_marks_undef() {
322 for s in ["u", "10u", "uuuu"].iter() {
323 let res = check_vector_variable(s).unwrap();
324 assert_eq!(res.0, "UNDEF");
325 assert_eq!(res.1, ValueKind::Undef);
326 }
327 }
328
329 #[test]
330 fn z_marks_highimp() {
331 let res = check_vector_variable("zz01").unwrap();
332 assert_eq!(res.0, "HIGHIMP");
333 assert_eq!(res.1, ValueKind::HighImp);
334 }
335
336 #[test]
337 fn dash_marks_dont_care() {
338 let res = check_vector_variable("-01--").unwrap();
339 assert_eq!(res.0, "DON'T CARE");
340 assert_eq!(res.1, ValueKind::DontCare);
341 }
342
343 #[test]
344 fn w_marks_undef_weak() {
345 let res = check_vector_variable("w101").unwrap();
346 assert_eq!(res.0, "UNDEF WEAK");
347 assert_eq!(res.1, ValueKind::Undef); }
349
350 #[test]
351 fn h_or_l_marks_weak() {
352 let res_h = check_vector_variable("h110").unwrap();
353 assert_eq!(res_h.0, "WEAK");
354 assert_eq!(res_h.1, ValueKind::Weak);
355
356 let res_l = check_vector_variable("l001").unwrap();
357 assert_eq!(res_l.0, "WEAK");
358 assert_eq!(res_l.1, ValueKind::Weak);
359 }
360
361 #[test]
362 fn unknown_values_fallback() {
363 for s in ["2", "a", "?", " "] {
364 let res = check_vector_variable(s).unwrap();
365 assert_eq!(res.0, "UNKNOWN VALUES");
366 assert_eq!(res.1, ValueKind::Undef);
367 }
368 }
369
370 #[test]
371 fn precedence_is_respected() {
372 let res = check_vector_variable("xz").unwrap();
374 assert_eq!(res.0, "UNDEF");
375 assert_eq!(res.1, ValueKind::Undef);
376
377 let res = check_vector_variable("wh").unwrap();
379 assert_eq!(res.0, "UNDEF WEAK");
380 assert_eq!(res.1, ValueKind::Undef);
381 }
382
383 #[test]
386 fn extend_string_zero_extend_from_0_and_1() {
387 assert_eq!(extend_string("001", 5), "00");
389 assert_eq!(extend_string("0", 3), "00");
390
391 assert_eq!(extend_string("101", 5), "00");
393 assert_eq!(extend_string("1", 4), "000");
394 }
395
396 #[test]
397 fn extend_string_x_and_z() {
398 assert_eq!(extend_string("x1", 4), "xx");
400 assert_eq!(extend_string("x", 3), "xx");
401
402 assert_eq!(extend_string("z0", 3), "z");
404 assert_eq!(extend_string("z", 5), "zzzz");
405 }
406
407 #[test]
408 fn extend_string_same_or_smaller_returns_empty() {
409 assert_eq!(extend_string("101", 3), "");
410 assert_eq!(extend_string("101", 2), "");
411 assert_eq!(extend_string("", 0), "");
412 }
413
414 #[test]
415 fn extend_string_weird_char_and_empty_input() {
416 assert_eq!(extend_string("h101", 6), "");
418 assert_eq!(extend_string("?", 10), "");
419
420 assert_eq!(extend_string("", 5), "");
422 }
423}