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_meta;
10mod variable_ref;
11
12use derive_more::Display;
13use ecolor::Color32;
14#[cfg(feature = "wasm_plugins")]
15use extism_convert::{FromBytes, Json, ToBytes};
16use num::{BigUint, ToPrimitive};
17use serde::{Deserialize, Serialize};
18use std::collections::HashMap;
19
20pub use crate::field_ref::FieldRef;
21pub use crate::result::{
22 HierFormatResult, SubFieldFlatTranslationResult, SubFieldTranslationResult, TranslatedValue,
23 TranslationResult, ValueRepr,
24};
25pub use crate::scope_ref::ScopeRef;
26pub use crate::translator::{
27 BasicTranslator, NumericRange, Translator, VariableNameInfo, WaveSource,
28 translates_all_bit_types,
29};
30pub use crate::variable_index::VariableIndex;
31pub use crate::variable_meta::VariableMeta;
32pub use crate::variable_ref::VariableRef;
33
34#[cfg_attr(feature = "wasm_plugins", derive(FromBytes, ToBytes))]
35#[cfg_attr(feature = "wasm_plugins", encoding(Json))]
36#[derive(Deserialize, Serialize)]
37pub struct PluginConfig(pub HashMap<String, String>);
38
39pub const NAN_UNDEF: f64 = f64::from_bits(0x7FF8_0000_0000_0000_u64);
41
42pub const NAN_HIGHIMP: f64 = f64::from_bits(0x7FF8_0000_0000_0001_u64);
44
45#[must_use]
47pub fn is_nan_highimp(value: f64) -> bool {
48 value.to_bits() == NAN_HIGHIMP.to_bits()
49}
50
51#[must_use]
56pub fn biguint_to_f64(v: &BigUint) -> f64 {
57 v.to_u64()
58 .map(|x| x as f64)
59 .or_else(|| v.to_f64())
60 .unwrap_or(f64::INFINITY)
61}
62
63#[must_use]
72pub fn parse_numeric_string(s: &str, translator_name: &str) -> Option<f64> {
73 let s = s.trim();
74 let translator_lower = translator_name.to_lowercase();
75
76 if translator_lower.contains("hex") {
77 let hex_str = s
78 .strip_prefix("0x")
79 .or_else(|| s.strip_prefix("0X"))
80 .unwrap_or(s);
81 BigUint::parse_bytes(hex_str.as_bytes(), 16).map(|v| biguint_to_f64(&v))
82 } else if translator_lower.contains("bin") {
83 let bin_str = s
84 .strip_prefix("0b")
85 .or_else(|| s.strip_prefix("0B"))
86 .unwrap_or(s);
87 BigUint::parse_bytes(bin_str.as_bytes(), 2).map(|v| biguint_to_f64(&v))
88 } else {
89 if let Ok(v) = s.parse::<f64>() {
90 return Some(v);
91 }
92 BigUint::parse_bytes(s.as_bytes(), 16).map(|v| biguint_to_f64(&v))
94 }
95}
96
97#[must_use]
102pub fn parse_value_to_numeric(value: &VariableValue, to_f64: impl FnOnce(&BigUint) -> f64) -> f64 {
103 match value.parse_biguint() {
104 Ok(v) => to_f64(&v),
105 Err((_, ValueKind::HighImp)) => NAN_HIGHIMP,
106 Err((_, _)) => NAN_UNDEF,
107 }
108}
109
110#[must_use]
114pub fn check_vector_variable(s: &str) -> Option<(String, ValueKind)> {
115 if s.contains('x') {
116 Some(("UNDEF".to_string(), ValueKind::Undef))
117 } else if s.contains('z') {
118 Some(("HIGHIMP".to_string(), ValueKind::HighImp))
119 } else if s.contains('-') {
120 Some(("DON'T CARE".to_string(), ValueKind::DontCare))
121 } else if s.contains('u') {
122 Some(("UNDEF".to_string(), ValueKind::Undef))
123 } else if s.contains('w') {
124 Some(("UNDEF WEAK".to_string(), ValueKind::Undef))
125 } else if s.contains('h') || s.contains('l') {
126 Some(("WEAK".to_string(), ValueKind::Weak))
127 } else if s.chars().all(|c| matches!(c, '0' | '1')) {
128 None
129 } else {
130 Some(("UNKNOWN VALUES".to_string(), ValueKind::Undef))
131 }
132}
133
134#[must_use]
138pub fn kind_for_binary_representation(s: &str) -> ValueKind {
139 if s.contains('x') {
140 ValueKind::Undef
141 } else if s.contains('z') {
142 ValueKind::HighImp
143 } else if s.contains('-') {
144 ValueKind::DontCare
145 } else if s.contains('u') || s.contains('w') {
146 ValueKind::Undef
147 } else if s.contains('h') || s.contains('l') {
148 ValueKind::Weak
149 } else {
150 ValueKind::Normal
151 }
152}
153
154#[must_use]
162pub fn extend_string(val: &str, num_bits: u32) -> String {
163 if num_bits as usize > val.len() {
164 let extra_count = num_bits as usize - val.len();
165 let extra_value = match val.chars().next() {
166 Some('0' | '1') => "0",
167 Some('x') => "x",
168 Some('z') => "z",
169 Some('u') => "u",
171 Some('w') => "w",
172 Some('l') => "l",
173 Some('h') => "h",
174 Some('-') => "-",
175 _ => "",
179 };
180 extra_value.repeat(extra_count)
181 } else {
182 String::new()
183 }
184}
185
186#[derive(Debug, PartialEq, Eq, Clone, Display, Hash, Serialize, Deserialize)]
187pub enum VariableValue {
191 #[display("{_0}")]
192 BigUint(BigUint),
193 #[display("{_0}")]
194 String(String),
195}
196
197impl VariableValue {
198 pub fn handle_bits<E>(
205 self,
206 handler: impl Fn(String) -> Result<TranslationResult, E>,
207 ) -> Result<TranslationResult, E> {
208 let value = match self {
209 VariableValue::BigUint(v) => format!("{v:b}"),
210 VariableValue::String(v) => {
211 if let Some((val, kind)) = check_vector_variable(&v) {
212 return Ok(TranslationResult {
213 val: ValueRepr::String(val),
214 subfields: vec![],
215 kind,
216 });
217 }
218 v
220 }
221 };
222
223 handler(value)
224 }
225}
226
227#[derive(Clone, PartialEq, Copy, Debug, Serialize, Deserialize)]
228pub enum ValueKind {
230 Normal,
231 Undef,
232 HighImp,
233 Custom(Color32),
234 Warn,
235 DontCare,
236 Weak,
237 Error,
238 Event,
239}
240
241#[cfg_attr(feature = "wasm_plugins", derive(FromBytes, ToBytes))]
242#[cfg_attr(feature = "wasm_plugins", encoding(Json))]
243#[derive(PartialEq, Deserialize, Serialize, Debug)]
244pub enum TranslationPreference {
245 Prefer,
248 Yes,
251 No,
255}
256
257#[cfg_attr(feature = "wasm_plugins", derive(FromBytes, ToBytes))]
259#[cfg_attr(feature = "wasm_plugins", encoding(Json))]
260#[derive(Clone, Debug, Default, Deserialize, Serialize)]
261pub enum VariableInfo {
262 Compound {
264 subfields: Vec<(String, VariableInfo)>,
265 },
266 Bits,
268 Bool,
270 Clock,
272 #[default]
274 String,
276 Real,
278 Event,
279}
280
281#[derive(Debug, Display, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
282pub enum VariableType {
284 #[display("event")]
286 VCDEvent,
287 #[display("reg")]
288 VCDReg,
289 #[display("wire")]
290 VCDWire,
291 #[display("real")]
292 VCDReal,
293 #[display("time")]
294 VCDTime,
295 #[display("string")]
296 VCDString,
297 #[display("parameter")]
298 VCDParameter,
299 #[display("integer")]
300 VCDInteger,
301 #[display("real time")]
302 RealTime,
303 #[display("supply 0")]
304 VCDSupply0,
305 #[display("supply 1")]
306 VCDSupply1,
307 #[display("tri")]
308 VCDTri,
309 #[display("tri and")]
310 VCDTriAnd,
311 #[display("tri or")]
312 VCDTriOr,
313 #[display("tri reg")]
314 VCDTriReg,
315 #[display("tri 0")]
316 VCDTri0,
317 #[display("tri 1")]
318 VCDTri1,
319 #[display("wand")]
320 VCDWAnd,
321 #[display("wor")]
322 VCDWOr,
323 #[display("port")]
324 Port,
325 #[display("sparse array")]
326 SparseArray,
327
328 #[display("bit")]
330 Bit,
331 #[display("logic")]
332 Logic,
333 #[display("int")]
334 Int,
335 #[display("shortint")]
336 ShortInt,
337 #[display("longint")]
338 LongInt,
339 #[display("byte")]
340 Byte,
341 #[display("enum")]
342 Enum,
343 #[display("shortreal")]
344 ShortReal,
345 #[display("real parameter")]
346 RealParameter,
347
348 #[display("boolean")]
350 Boolean,
351 #[display("bit_vector")]
352 BitVector,
353 #[display("std_logic")]
354 StdLogic,
355 #[display("std_logic_vector")]
356 StdLogicVector,
357 #[display("std_ulogic")]
358 StdULogic,
359 #[display("std_ulogic_vector")]
360 StdULogicVector,
361
362 #[display("event")]
363 EventParameter,
364}
365
366#[derive(Clone, Display, Copy, PartialOrd, Debug, Eq, PartialEq, Serialize, Deserialize)]
367pub enum VariableDirection {
368 #[display("input")]
370 Input,
371 #[display("output")]
372 Output,
373 #[display("inout")]
374 InOut,
375 #[display("buffer")]
376 Buffer,
377 #[display("linkage")]
378 Linkage,
379 #[display("implicit")]
380 Implicit,
381 #[display("unknown")]
382 Unknown,
383}
384
385#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
386pub enum VariableEncoding {
388 String,
389 Real,
390 BitVector,
391}
392
393#[cfg(test)]
394mod tests {
395 use super::{ValueKind, check_vector_variable, extend_string, parse_numeric_string};
396
397 #[test]
398 fn binary_only_returns_none() {
399 for s in ["0", "1", "0101", "1111", "000000", "101010"].iter() {
400 assert_eq!(check_vector_variable(s), None, "{s}");
401 }
402 }
403
404 #[test]
405 fn x_marks_undef() {
406 let res = check_vector_variable("10x01").unwrap();
407 assert_eq!(res.0, "UNDEF");
408 assert_eq!(res.1, ValueKind::Undef);
409 }
410
411 #[test]
412 fn u_marks_undef() {
413 for s in ["u", "10u", "uuuu"].iter() {
414 let res = check_vector_variable(s).unwrap();
415 assert_eq!(res.0, "UNDEF");
416 assert_eq!(res.1, ValueKind::Undef);
417 }
418 }
419
420 #[test]
421 fn z_marks_highimp() {
422 let res = check_vector_variable("zz01").unwrap();
423 assert_eq!(res.0, "HIGHIMP");
424 assert_eq!(res.1, ValueKind::HighImp);
425 }
426
427 #[test]
428 fn dash_marks_dont_care() {
429 let res = check_vector_variable("-01--").unwrap();
430 assert_eq!(res.0, "DON'T CARE");
431 assert_eq!(res.1, ValueKind::DontCare);
432 }
433
434 #[test]
435 fn w_marks_undef_weak() {
436 let res = check_vector_variable("w101").unwrap();
437 assert_eq!(res.0, "UNDEF WEAK");
438 assert_eq!(res.1, ValueKind::Undef); }
440
441 #[test]
442 fn h_or_l_marks_weak() {
443 let res_h = check_vector_variable("h110").unwrap();
444 assert_eq!(res_h.0, "WEAK");
445 assert_eq!(res_h.1, ValueKind::Weak);
446
447 let res_l = check_vector_variable("l001").unwrap();
448 assert_eq!(res_l.0, "WEAK");
449 assert_eq!(res_l.1, ValueKind::Weak);
450 }
451
452 #[test]
453 fn unknown_values_fallback() {
454 for s in ["2", "a", "?", " "] {
455 let res = check_vector_variable(s).unwrap();
456 assert_eq!(res.0, "UNKNOWN VALUES");
457 assert_eq!(res.1, ValueKind::Undef);
458 }
459 }
460
461 #[test]
462 fn precedence_is_respected() {
463 let res = check_vector_variable("xz").unwrap();
465 assert_eq!(res.0, "UNDEF");
466 assert_eq!(res.1, ValueKind::Undef);
467
468 let res = check_vector_variable("wh").unwrap();
470 assert_eq!(res.0, "UNDEF WEAK");
471 assert_eq!(res.1, ValueKind::Undef);
472 }
473
474 #[test]
477 fn extend_string_zero_extend_from_0_and_1() {
478 assert_eq!(extend_string("001", 5), "00");
480 assert_eq!(extend_string("0", 3), "00");
481
482 assert_eq!(extend_string("101", 5), "00");
484 assert_eq!(extend_string("1", 4), "000");
485 }
486
487 #[test]
488 fn extend_string_x_and_z() {
489 assert_eq!(extend_string("x1", 4), "xx");
491 assert_eq!(extend_string("x", 3), "xx");
492
493 assert_eq!(extend_string("z0", 3), "z");
495 assert_eq!(extend_string("z", 5), "zzzz");
496 }
497
498 #[test]
499 fn extend_string_same_or_smaller_returns_empty() {
500 assert_eq!(extend_string("101", 3), "");
501 assert_eq!(extend_string("101", 2), "");
502 assert_eq!(extend_string("", 0), "");
503 }
504
505 #[test]
506 fn extend_string_weird_char_and_empty_input() {
507 assert_eq!(extend_string("h101", 6), "");
509 assert_eq!(extend_string("?", 10), "");
510
511 assert_eq!(extend_string("", 5), "");
513 }
514
515 #[test]
518 fn parse_numeric_string_hex() {
519 assert_eq!(parse_numeric_string("f9", "Hex"), Some(249.0));
520 assert_eq!(parse_numeric_string("ca", "Hexadecimal"), Some(202.0));
521 assert_eq!(parse_numeric_string("80", "Hex"), Some(128.0));
522 assert_eq!(parse_numeric_string("10", "Hex"), Some(16.0));
523 assert_eq!(parse_numeric_string("0x10", "Hex"), Some(16.0));
524 assert_eq!(parse_numeric_string("0xFF", "Hexadecimal"), Some(255.0));
525 }
526
527 #[test]
528 fn parse_numeric_string_decimal() {
529 assert_eq!(parse_numeric_string("123", "Unsigned"), Some(123.0));
530 assert_eq!(parse_numeric_string("123.45", "Float"), Some(123.45));
531 assert_eq!(parse_numeric_string("80", "Unsigned"), Some(80.0));
532 assert_eq!(parse_numeric_string("10", "Signed"), Some(10.0));
533 assert_eq!(parse_numeric_string("1.5e3", "Float"), Some(1500.0));
534 assert_eq!(parse_numeric_string("-3.14e-2", "Float"), Some(-0.0314));
535 }
536
537 #[test]
538 fn parse_numeric_string_binary() {
539 assert_eq!(parse_numeric_string("1010", "Binary"), Some(10.0));
540 assert_eq!(parse_numeric_string("0b1010", "Binary"), Some(10.0));
541 assert_eq!(parse_numeric_string("11111111", "Bin"), Some(255.0));
542 }
543
544 #[test]
545 fn parse_numeric_string_fallback_to_hex() {
546 assert_eq!(parse_numeric_string("f9", "Unsigned"), Some(249.0));
548 assert_eq!(parse_numeric_string("ca", "Signed"), Some(202.0));
549 }
550
551 #[test]
552 fn parse_numeric_string_invalid() {
553 assert_eq!(parse_numeric_string("xyz", "Hex"), None);
554 assert_eq!(parse_numeric_string("invalid", "Unsigned"), None);
555 assert_eq!(parse_numeric_string("12", "Binary"), None);
556 }
557
558 #[test]
559 fn parse_numeric_string_large_values() {
560 let hex_128bit = "ffffffffffffffffffffffffffffffff";
562 assert_eq!(
563 parse_numeric_string(hex_128bit, "Hexadecimal"),
564 Some(3.402823669209385e38)
565 );
566
567 let hex_256bit = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
569 assert_eq!(
570 parse_numeric_string(hex_256bit, "Hex"),
571 Some(1.157920892373162e77)
572 );
573
574 let bin_128bit = "1111111111111111111111111111111111111111111111111111111111111111\
576 1111111111111111111111111111111111111111111111111111111111111111";
577 assert_eq!(
578 parse_numeric_string(bin_128bit, "Binary"),
579 Some(3.402823669209385e38)
580 );
581
582 let hex_64bit = "ffffffffffffffff";
584 assert_eq!(
585 parse_numeric_string(hex_64bit, "Hexadecimal"),
586 Some(1.8446744073709552e19)
587 );
588
589 let decimal_128bit = "340282366920938463463374607431768211455";
592 assert_eq!(
593 parse_numeric_string(decimal_128bit, "Unsigned"),
594 Some(3.402823669209385e38)
595 );
596 }
597}