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
363#[derive(Clone, Display, Copy, PartialOrd, Debug, Eq, PartialEq, Serialize, Deserialize)]
364pub enum VariableDirection {
365 #[display("input")]
367 Input,
368 #[display("output")]
369 Output,
370 #[display("inout")]
371 InOut,
372 #[display("buffer")]
373 Buffer,
374 #[display("linkage")]
375 Linkage,
376 #[display("implicit")]
377 Implicit,
378 #[display("unknown")]
379 Unknown,
380}
381
382#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
383pub enum VariableEncoding {
385 String,
386 Real,
387 BitVector,
388 Event,
389}
390
391#[cfg(test)]
392mod tests {
393 use super::{ValueKind, check_vector_variable, extend_string, parse_numeric_string};
394
395 #[test]
396 fn binary_only_returns_none() {
397 for s in ["0", "1", "0101", "1111", "000000", "101010"].iter() {
398 assert_eq!(check_vector_variable(s), None, "{s}");
399 }
400 }
401
402 #[test]
403 fn x_marks_undef() {
404 let res = check_vector_variable("10x01").unwrap();
405 assert_eq!(res.0, "UNDEF");
406 assert_eq!(res.1, ValueKind::Undef);
407 }
408
409 #[test]
410 fn u_marks_undef() {
411 for s in ["u", "10u", "uuuu"].iter() {
412 let res = check_vector_variable(s).unwrap();
413 assert_eq!(res.0, "UNDEF");
414 assert_eq!(res.1, ValueKind::Undef);
415 }
416 }
417
418 #[test]
419 fn z_marks_highimp() {
420 let res = check_vector_variable("zz01").unwrap();
421 assert_eq!(res.0, "HIGHIMP");
422 assert_eq!(res.1, ValueKind::HighImp);
423 }
424
425 #[test]
426 fn dash_marks_dont_care() {
427 let res = check_vector_variable("-01--").unwrap();
428 assert_eq!(res.0, "DON'T CARE");
429 assert_eq!(res.1, ValueKind::DontCare);
430 }
431
432 #[test]
433 fn w_marks_undef_weak() {
434 let res = check_vector_variable("w101").unwrap();
435 assert_eq!(res.0, "UNDEF WEAK");
436 assert_eq!(res.1, ValueKind::Undef); }
438
439 #[test]
440 fn h_or_l_marks_weak() {
441 let res_h = check_vector_variable("h110").unwrap();
442 assert_eq!(res_h.0, "WEAK");
443 assert_eq!(res_h.1, ValueKind::Weak);
444
445 let res_l = check_vector_variable("l001").unwrap();
446 assert_eq!(res_l.0, "WEAK");
447 assert_eq!(res_l.1, ValueKind::Weak);
448 }
449
450 #[test]
451 fn unknown_values_fallback() {
452 for s in ["2", "a", "?", " "] {
453 let res = check_vector_variable(s).unwrap();
454 assert_eq!(res.0, "UNKNOWN VALUES");
455 assert_eq!(res.1, ValueKind::Undef);
456 }
457 }
458
459 #[test]
460 fn precedence_is_respected() {
461 let res = check_vector_variable("xz").unwrap();
463 assert_eq!(res.0, "UNDEF");
464 assert_eq!(res.1, ValueKind::Undef);
465
466 let res = check_vector_variable("wh").unwrap();
468 assert_eq!(res.0, "UNDEF WEAK");
469 assert_eq!(res.1, ValueKind::Undef);
470 }
471
472 #[test]
475 fn extend_string_zero_extend_from_0_and_1() {
476 assert_eq!(extend_string("001", 5), "00");
478 assert_eq!(extend_string("0", 3), "00");
479
480 assert_eq!(extend_string("101", 5), "00");
482 assert_eq!(extend_string("1", 4), "000");
483 }
484
485 #[test]
486 fn extend_string_x_and_z() {
487 assert_eq!(extend_string("x1", 4), "xx");
489 assert_eq!(extend_string("x", 3), "xx");
490
491 assert_eq!(extend_string("z0", 3), "z");
493 assert_eq!(extend_string("z", 5), "zzzz");
494 }
495
496 #[test]
497 fn extend_string_same_or_smaller_returns_empty() {
498 assert_eq!(extend_string("101", 3), "");
499 assert_eq!(extend_string("101", 2), "");
500 assert_eq!(extend_string("", 0), "");
501 }
502
503 #[test]
504 fn extend_string_weird_char_and_empty_input() {
505 assert_eq!(extend_string("h101", 6), "");
507 assert_eq!(extend_string("?", 10), "");
508
509 assert_eq!(extend_string("", 5), "");
511 }
512
513 #[test]
516 fn parse_numeric_string_hex() {
517 assert_eq!(parse_numeric_string("f9", "Hex"), Some(249.0));
518 assert_eq!(parse_numeric_string("ca", "Hexadecimal"), Some(202.0));
519 assert_eq!(parse_numeric_string("80", "Hex"), Some(128.0));
520 assert_eq!(parse_numeric_string("10", "Hex"), Some(16.0));
521 assert_eq!(parse_numeric_string("0x10", "Hex"), Some(16.0));
522 assert_eq!(parse_numeric_string("0xFF", "Hexadecimal"), Some(255.0));
523 }
524
525 #[test]
526 fn parse_numeric_string_decimal() {
527 assert_eq!(parse_numeric_string("123", "Unsigned"), Some(123.0));
528 assert_eq!(parse_numeric_string("123.45", "Float"), Some(123.45));
529 assert_eq!(parse_numeric_string("80", "Unsigned"), Some(80.0));
530 assert_eq!(parse_numeric_string("10", "Signed"), Some(10.0));
531 assert_eq!(parse_numeric_string("1.5e3", "Float"), Some(1500.0));
532 assert_eq!(parse_numeric_string("-3.14e-2", "Float"), Some(-0.0314));
533 }
534
535 #[test]
536 fn parse_numeric_string_binary() {
537 assert_eq!(parse_numeric_string("1010", "Binary"), Some(10.0));
538 assert_eq!(parse_numeric_string("0b1010", "Binary"), Some(10.0));
539 assert_eq!(parse_numeric_string("11111111", "Bin"), Some(255.0));
540 }
541
542 #[test]
543 fn parse_numeric_string_fallback_to_hex() {
544 assert_eq!(parse_numeric_string("f9", "Unsigned"), Some(249.0));
546 assert_eq!(parse_numeric_string("ca", "Signed"), Some(202.0));
547 }
548
549 #[test]
550 fn parse_numeric_string_invalid() {
551 assert_eq!(parse_numeric_string("xyz", "Hex"), None);
552 assert_eq!(parse_numeric_string("invalid", "Unsigned"), None);
553 assert_eq!(parse_numeric_string("12", "Binary"), None);
554 }
555
556 #[test]
557 fn parse_numeric_string_large_values() {
558 let hex_128bit = "ffffffffffffffffffffffffffffffff";
560 assert_eq!(
561 parse_numeric_string(hex_128bit, "Hexadecimal"),
562 Some(3.402823669209385e38)
563 );
564
565 let hex_256bit = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
567 assert_eq!(
568 parse_numeric_string(hex_256bit, "Hex"),
569 Some(1.157920892373162e77)
570 );
571
572 let bin_128bit = "1111111111111111111111111111111111111111111111111111111111111111\
574 1111111111111111111111111111111111111111111111111111111111111111";
575 assert_eq!(
576 parse_numeric_string(bin_128bit, "Binary"),
577 Some(3.402823669209385e38)
578 );
579
580 let hex_64bit = "ffffffffffffffff";
582 assert_eq!(
583 parse_numeric_string(hex_64bit, "Hexadecimal"),
584 Some(1.8446744073709552e19)
585 );
586
587 let decimal_128bit = "340282366920938463463374607431768211455";
590 assert_eq!(
591 parse_numeric_string(decimal_128bit, "Unsigned"),
592 Some(3.402823669209385e38)
593 );
594 }
595}