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