1use std::collections::{HashMap, HashSet};
2use std::fmt::Write;
3use std::sync::Arc;
4
5use derive_more::Debug;
6use eyre::{Result, anyhow, bail};
7use num::{BigUint, ToPrimitive};
8use surfer_translation_types::{
9 VariableDirection, VariableEncoding, VariableIndex, VariableType, VariableValue,
10};
11use tracing::warn;
12use wellen::{
13 FileFormat, Hierarchy, ScopeType, Signal, SignalEncoding, SignalRef, SignalSource, Time,
14 TimeTable, TimeTableIdx, Timescale, TimescaleUnit, Var, VarRef, VarType,
15};
16
17use crate::time::{TimeScale, TimeUnit};
18use crate::variable_direction::VariableDirectionExt;
19use crate::variable_index::VariableIndexExt;
20use crate::wave_container::{
21 MetaData, QueryResult, ScopeId, ScopeRef, ScopeRefExt, VarId, VariableMeta, VariableRef,
22 VariableRefExt,
23};
24
25static UNIQUE_ID_COUNT: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
26
27#[derive(Debug)]
28pub struct WellenContainer {
29 #[debug(skip)]
30 hierarchy: std::sync::Arc<Hierarchy>,
31 server: Option<String>,
33 scopes: Vec<String>,
34 vars: Vec<String>,
35 varrefs: Vec<VariableRef>,
36 signals: HashMap<SignalRef, Arc<Signal>>,
37 signals_to_be_loaded: HashSet<SignalRef>,
39 time_table: Arc<TimeTable>,
40 #[debug(skip)]
41 source: Option<SignalSource>,
42 unique_id: u64,
43 body_loaded: bool,
44}
45
46pub struct LoadSignalsCmd {
49 signals: Vec<SignalRef>,
50 from_unique_id: u64,
51 payload: LoadSignalPayload,
52}
53
54pub enum HeaderResult {
55 LocalFile(Box<wellen::viewers::HeaderResult<std::io::BufReader<std::fs::File>>>),
57 LocalBytes(Box<wellen::viewers::HeaderResult<std::io::Cursor<Vec<u8>>>>),
59 Remote(std::sync::Arc<Hierarchy>, FileFormat, String, usize),
61}
62
63pub enum BodyResult {
64 Local(wellen::viewers::BodyResult),
66 Remote(Vec<wellen::Time>, String),
68}
69
70pub enum LoadSignalPayload {
71 Local(SignalSource, std::sync::Arc<Hierarchy>),
72 Remote(String),
73}
74
75impl LoadSignalsCmd {
76 #[must_use]
77 pub fn destruct(self) -> (Vec<SignalRef>, u64, LoadSignalPayload) {
78 (self.signals, self.from_unique_id, self.payload)
79 }
80}
81
82pub struct LoadSignalsResult {
83 source: Option<SignalSource>,
84 server: Option<String>,
85 signals: Vec<(SignalRef, Signal)>,
86 from_unique_id: u64,
87}
88
89impl LoadSignalsResult {
90 #[must_use]
91 pub fn local(
92 source: SignalSource,
93 signals: Vec<(SignalRef, Signal)>,
94 from_unique_id: u64,
95 ) -> Self {
96 Self {
97 source: Some(source),
98 server: None,
99 signals,
100 from_unique_id,
101 }
102 }
103
104 #[must_use]
105 pub fn remote(server: String, signals: Vec<(SignalRef, Signal)>, from_unique_id: u64) -> Self {
106 Self {
107 source: None,
108 server: Some(server),
109 signals,
110 from_unique_id,
111 }
112 }
113
114 #[must_use]
115 pub fn len(&self) -> usize {
116 self.signals.len()
117 }
118
119 #[must_use]
120 pub fn is_empty(&self) -> bool {
121 self.signals.is_empty()
122 }
123}
124
125#[must_use]
126pub fn convert_format(format: FileFormat) -> crate::WaveFormat {
127 match format {
128 FileFormat::Vcd => crate::WaveFormat::Vcd,
129 FileFormat::Fst => crate::WaveFormat::Fst,
130 FileFormat::Ghw => crate::WaveFormat::Ghw,
131 FileFormat::Unknown => unreachable!("should never get here"),
132 }
133}
134
135impl WellenContainer {
136 pub fn new(hierarchy: std::sync::Arc<Hierarchy>, server: Option<String>) -> Self {
137 let h = &hierarchy;
139 let scopes = h.iter_scopes().map(|r| r.full_name(h)).collect::<Vec<_>>();
140 let vars: Vec<String> = h
141 .iter_vars()
142 .map(|r| {
143 if let Some(i) = r.index()
144 && i.length() == 1
145 {
146 format!("{}[{}]", r.full_name(h), i.lsb())
147 } else {
148 r.full_name(h)
149 }
150 })
151 .collect::<Vec<_>>();
152 let varrefs = vars
153 .iter()
154 .enumerate()
155 .filter_map(|(n, name)| {
156 let r = VarRef::from_index(n).unwrap();
157 if h[r].var_type().is_parameter() {
158 None
159 } else {
160 Some(VariableRef::from_hierarchy_string_with_id(
161 name,
162 VarId::Wellen(r),
163 ))
164 }
165 })
166 .collect::<Vec<_>>();
167
168 let unique_id = UNIQUE_ID_COUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
169
170 Self {
171 hierarchy,
172 server,
173 scopes,
174 vars,
175 varrefs,
176 signals: HashMap::new(),
177 signals_to_be_loaded: HashSet::new(),
178 time_table: Arc::new(vec![]),
179 source: None,
180 unique_id,
181 body_loaded: false,
182 }
183 }
184
185 #[must_use]
186 pub fn body_loaded(&self) -> bool {
187 self.body_loaded
188 }
189
190 pub fn add_body(&mut self, body: BodyResult) -> Result<Option<LoadSignalsCmd>> {
191 if self.body_loaded {
192 bail!("Did we just parse the body twice? That should not happen!");
193 }
194 match body {
195 BodyResult::Local(body) => {
196 if self.server.is_some() {
197 bail!(
198 "We are connected to a server, but also received the result of parsing a file locally. Something is going wrong here!"
199 );
200 }
201 self.time_table = Arc::new(body.time_table);
202 self.source = Some(body.source);
203 }
204 BodyResult::Remote(time_table, server) => {
205 if let Some(old) = &self.server {
206 if old != &server {
207 bail!("Inconsistent server URLs: {old} vs. {server}")
208 }
209 } else {
210 bail!("Missing server URL!");
211 }
212 self.time_table = Arc::new(time_table);
213 }
214 }
215 self.body_loaded = true;
216
217 Ok(self.load_signals(&[]))
220 }
221
222 #[must_use]
223 pub fn metadata(&self) -> MetaData {
224 let timescale = self
225 .hierarchy
226 .timescale()
227 .unwrap_or(Timescale::new(1, TimescaleUnit::Unknown));
228 let date = None;
229 MetaData {
230 date,
231 version: Some(self.hierarchy.version().to_string()),
232 timescale: TimeScale {
233 unit: TimeUnit::from(timescale.unit),
234 multiplier: Some(timescale.factor),
235 },
236 }
237 }
238
239 #[must_use]
240 pub fn max_timestamp(&self) -> Option<BigUint> {
241 self.time_table.last().map(|t| BigUint::from(*t))
242 }
243
244 #[must_use]
245 pub fn is_fully_loaded(&self) -> bool {
246 (self.source.is_some() || self.server.is_some()) && self.signals_to_be_loaded.is_empty()
247 }
248
249 #[must_use]
250 pub fn variable_names(&self) -> Vec<String> {
251 self.vars.clone()
252 }
253
254 fn lookup_scope(&self, scope: &ScopeRef) -> Option<wellen::ScopeRef> {
255 match scope.id {
256 ScopeId::Wellen(id) => Some(id),
257 ScopeId::None => self.hierarchy.lookup_scope(scope.strs()),
258 }
259 }
260
261 fn has_scope(&self, scope: &ScopeRef) -> bool {
262 match scope.id {
263 ScopeId::Wellen(_) => true,
264 ScopeId::None => self.hierarchy.lookup_scope(scope.strs()).is_some(),
265 }
266 }
267
268 #[must_use]
269 pub fn get_scope_type(&self, scope: &ScopeRef) -> Option<ScopeType> {
270 self.lookup_scope(scope)
271 .map(|scope_ref| self.hierarchy[scope_ref].scope_type())
272 }
273
274 #[must_use]
275 pub fn variables(&self) -> Vec<VariableRef> {
276 self.varrefs.clone()
277 }
278
279 pub fn variables_in_scope(&self, scope_ref: &ScopeRef) -> Vec<VariableRef> {
280 let h = &self.hierarchy;
281 if scope_ref.has_empty_strs() {
283 h.vars()
284 .filter(|id| !h[*id].var_type().is_parameter())
285 .map(|id| {
286 let v = &h[id];
287 let index = v
288 .index()
289 .and_then(|i| if i.length() == 1 { Some(i.lsb()) } else { None });
290 VariableRef::new_with_id_and_index(
291 scope_ref.clone(),
292 v.name(h).to_string(),
293 VarId::Wellen(id),
294 index,
295 )
296 })
297 .collect::<Vec<_>>()
298 } else {
299 let scope = if let Some(id) = self.lookup_scope(scope_ref) {
300 &h[id]
301 } else {
302 warn!("Found no scope '{scope_ref}'. Defaulting to no variables");
303 return vec![];
304 };
305 scope
306 .vars(h)
307 .filter(|id| !h[*id].var_type().is_parameter())
308 .map(|id| {
309 let v = &h[id];
310 let index = v
311 .index()
312 .and_then(|i| if i.length() == 1 { Some(i.lsb()) } else { None });
313 VariableRef::new_with_id_and_index(
314 scope_ref.clone(),
315 v.name(h).to_string(),
316 VarId::Wellen(id),
317 index,
318 )
319 })
320 .collect::<Vec<_>>()
321 }
322 }
323
324 pub fn parameters_in_scope(&self, scope_ref: &ScopeRef) -> Vec<VariableRef> {
325 let h = &self.hierarchy;
326 if scope_ref.strs().is_empty() {
328 h.vars()
329 .filter(|id| h[*id].var_type().is_parameter())
330 .map(|id| {
331 let v = &h[id];
332 let index = v
333 .index()
334 .and_then(|i| if i.length() == 1 { Some(i.lsb()) } else { None });
335 VariableRef::new_with_id_and_index(
336 scope_ref.clone(),
337 v.name(h).to_string(),
338 VarId::Wellen(id),
339 index,
340 )
341 })
342 .collect::<Vec<_>>()
343 } else {
344 let scope = if let Some(id) = self.lookup_scope(scope_ref) {
345 &h[id]
346 } else {
347 warn!("Found no scope '{scope_ref}'. Defaulting to no variables");
348 return vec![];
349 };
350 scope
351 .vars(h)
352 .filter(|id| h[*id].var_type().is_parameter())
353 .map(|id| {
354 let v = &h[id];
355 let index = v
356 .index()
357 .and_then(|i| if i.length() == 1 { Some(i.lsb()) } else { None });
358 VariableRef::new_with_id_and_index(
359 scope_ref.clone(),
360 v.name(h).to_string(),
361 VarId::Wellen(id),
362 index,
363 )
364 })
365 .collect::<Vec<_>>()
366 }
367 }
368
369 pub fn no_variables_in_scope(&self, scope_ref: &ScopeRef) -> bool {
370 let h = &self.hierarchy;
371 if scope_ref.has_empty_strs() {
373 h.vars().next().is_none()
374 } else {
375 let scope = if let Some(id) = self.lookup_scope(scope_ref) {
376 &h[id]
377 } else {
378 warn!("Found no scope '{scope_ref}'. Defaulting to no variables");
379 return true;
380 };
381 scope.vars(h).next().is_none()
382 }
383 }
384
385 #[must_use]
386 pub fn update_variable_ref(&self, variable: &VariableRef) -> Option<VariableRef> {
387 let h = &self.hierarchy;
389 let index = variable
390 .index
391 .as_ref()
392 .map(|i| wellen::VarIndex::new(*i, *i));
393 let (var, new_scope_ref) = if variable.path.has_empty_strs() {
394 if let Some(var) = h.lookup_var_with_index(&[], &variable.name, &index) {
396 (var, variable.path.clone())
397 } else {
398 let var = h.lookup_var(&[], &variable.name)?;
400 (var, variable.path.clone())
401 }
402 } else {
403 let scope = h.lookup_scope(variable.path.strs())?;
405 let new_scope_ref = variable.path.with_id(ScopeId::Wellen(scope));
406
407 let var = h[scope].vars(h).find(|r| {
409 h[*r].name(h) == variable.name && {
410 let var_index = h[*r].index();
411 var_index == index
413 || (index.is_none() && var_index.is_some_and(|i| i.length() >= 2))
414 }
415 })?;
416 (var, new_scope_ref)
417 };
418
419 let new_variable_ref = VariableRef::new_with_id_and_index(
420 new_scope_ref,
421 variable.name.clone(),
422 VarId::Wellen(var),
423 variable.index,
424 );
425 Some(new_variable_ref)
426 }
427
428 pub fn get_var(&self, r: &VariableRef) -> Result<&Var> {
429 let h = &self.hierarchy;
430 self.get_var_ref(r).map(|r| &h[r])
431 }
432
433 #[must_use]
434 pub fn get_enum_map(&self, v: &Var) -> HashMap<String, String> {
435 match v.enum_type(&self.hierarchy) {
436 None => HashMap::new(),
437 Some((_, mapping)) => HashMap::from_iter(
438 mapping
439 .into_iter()
440 .map(|(k, v)| (k.to_string(), v.to_string())),
441 ),
442 }
443 }
444
445 fn get_var_ref(&self, r: &VariableRef) -> Result<VarRef> {
446 match r.id {
447 VarId::Wellen(id) => Ok(id),
448 VarId::None => {
449 let h = &self.hierarchy;
450 let index = r.index.as_ref().map(|i| wellen::VarIndex::new(*i, *i));
451
452 let Some(var) = h.lookup_var_with_index(r.path.strs(), r.name.clone(), &index)
453 else {
454 bail!("Failed to find variable: {r:?}")
455 };
456 Ok(var)
457 }
458 }
459 }
460
461 pub fn load_variables<S: AsRef<VariableRef>, T: Iterator<Item = S>>(
462 &mut self,
463 variables: T,
464 ) -> Result<Option<LoadSignalsCmd>> {
465 let h = &self.hierarchy;
466 let signal_refs = variables
467 .flat_map(|s| {
468 let r = s.as_ref();
469 self.get_var_ref(r).map(|v| h[v].signal_ref())
470 })
471 .collect::<Vec<_>>();
472 Ok(self.load_signals(&signal_refs))
473 }
474
475 pub fn load_all_params(&mut self) -> Result<Option<LoadSignalsCmd>> {
476 let h = &self.hierarchy;
477 let params = h
478 .iter_vars()
479 .filter(|r| r.var_type().is_parameter())
480 .map(wellen::Var::signal_ref)
481 .collect::<Vec<_>>();
482 Ok(self.load_signals(¶ms))
483 }
484
485 pub fn on_signals_loaded(&mut self, res: LoadSignalsResult) -> Result<Option<LoadSignalsCmd>> {
486 if res.from_unique_id == self.unique_id {
488 debug_assert!(self.source.is_none());
490 debug_assert!(self.server.is_none());
491 self.source = res.source;
492 self.server = res.server;
493 debug_assert!(self.server.is_some() || self.source.is_some());
494 for (id, signal) in res.signals {
496 self.signals.insert(id, Arc::new(signal));
497 }
498 }
499
500 Ok(self.load_signals(&[]))
502 }
503
504 fn load_signals(&mut self, ids: &[SignalRef]) -> Option<LoadSignalsCmd> {
505 let filtered_ids = ids
507 .iter()
508 .filter(|id| !self.signals.contains_key(id) && !self.signals_to_be_loaded.contains(id))
509 .copied()
510 .collect::<Vec<_>>();
511
512 self.signals_to_be_loaded.extend(filtered_ids.iter());
514
515 if self.signals_to_be_loaded.is_empty() {
516 return None; }
518
519 if !self.body_loaded {
520 return None; }
522
523 if let Some(server) = std::mem::take(&mut self.server) {
525 let mut signals = self.signals_to_be_loaded.drain().collect::<Vec<_>>();
527 signals.sort(); let cmd = LoadSignalsCmd {
529 signals,
530 payload: LoadSignalPayload::Remote(server),
531 from_unique_id: self.unique_id,
532 };
533 Some(cmd)
534 } else if let Some(source) = std::mem::take(&mut self.source) {
535 let mut signals = self.signals_to_be_loaded.drain().collect::<Vec<_>>();
537 signals.sort(); let cmd = LoadSignalsCmd {
539 signals,
540 payload: LoadSignalPayload::Local(source, self.hierarchy.clone()),
541 from_unique_id: self.unique_id,
542 };
543 Some(cmd)
544 } else {
545 None
546 }
547 }
548
549 fn time_to_time_table_idx(&self, time: &BigUint) -> Option<TimeTableIdx> {
550 let time: Time = time.to_u64().expect("unsupported time!");
551 let table = &self.time_table;
552 if table.is_empty() || table[0] > time {
553 None
554 } else {
555 let idx = binary_search(table, time);
557 assert!(table[idx] <= time);
558 Some(idx as TimeTableIdx)
559 }
560 }
561
562 pub fn query_variable(
563 &self,
564 variable: &VariableRef,
565 time: &BigUint,
566 ) -> Result<Option<QueryResult>> {
567 let h = &self.hierarchy;
568 let var_ref = self.get_var_ref(variable)?;
570 let signal_ref = h[var_ref].signal_ref();
572 let Some(sig) = self.signals.get(&signal_ref) else {
573 return Ok(None);
575 };
576 let time_table = &self.time_table;
577
578 if let Some(idx) = self.time_to_time_table_idx(time) {
580 if let Some(offset) = sig.get_offset(idx) {
582 let offset_time_idx = sig.get_time_idx_at(&offset);
584 let offset_time = time_table[offset_time_idx as usize];
585 let current_value = sig.get_value_at(&offset, offset.elements - 1);
587 let next_time = offset
589 .next_index
590 .and_then(|i| time_table.get(i.get() as usize));
591
592 let converted_value = convert_variable_value(current_value);
593 let result = QueryResult {
594 current: Some((BigUint::from(offset_time), converted_value)),
595 next: next_time.map(|t| BigUint::from(*t)),
596 };
597 return Ok(Some(result));
598 }
599 }
600
601 let first_index = sig.get_first_time_idx();
603 let next_time = first_index.and_then(|i| time_table.get(i as usize));
604 let result = QueryResult {
605 current: None,
606 next: next_time.map(|t| BigUint::from(*t)),
607 };
608 Ok(Some(result))
609 }
610
611 #[must_use]
612 pub fn scope_names(&self) -> Vec<String> {
613 self.scopes.clone()
614 }
615
616 #[must_use]
617 pub fn array_scope_names(&self) -> Vec<String> {
618 let h = &self.hierarchy;
619
620 fn collect_array_scopes(h: &Hierarchy, scope_id: wellen::ScopeRef, out: &mut Vec<String>) {
621 let scope = &h[scope_id];
622 if matches!(
623 scope.scope_type(),
624 ScopeType::VhdlArray | ScopeType::SvArray
625 ) {
626 out.push(scope.full_name(h));
627 }
628
629 for child in scope.scopes(h) {
630 collect_array_scopes(h, child, out);
631 }
632 }
633
634 let mut out = Vec::new();
635 for root in h.scopes() {
636 collect_array_scopes(h, root, &mut out);
637 }
638 out
639 }
640
641 #[must_use]
642 pub fn root_scopes(&self) -> Vec<ScopeRef> {
643 let h = &self.hierarchy;
644 h.scopes()
645 .map(|id| ScopeRef::from_strs_with_id(&[h[id].name(h)], ScopeId::Wellen(id)))
646 .collect::<Vec<_>>()
647 }
648
649 pub fn child_scopes(&self, scope_ref: &ScopeRef) -> Result<Vec<ScopeRef>> {
650 let h = &self.hierarchy;
651 let scope = match self.lookup_scope(scope_ref) {
652 Some(id) => &h[id],
653 None => return Err(anyhow!("Failed to find scope {scope_ref:?}")),
654 };
655 Ok(scope
656 .scopes(h)
657 .map(|id| scope_ref.with_subscope(h[id].name(h).to_string(), ScopeId::Wellen(id)))
658 .collect::<Vec<_>>())
659 }
660
661 #[must_use]
662 pub fn scope_exists(&self, scope: &ScopeRef) -> bool {
663 scope.has_empty_strs() || self.has_scope(scope)
664 }
665
666 #[must_use]
667 pub fn scope_is_variable(&self, scope: &ScopeRef) -> bool {
669 if let Some(scope_ref) = self.lookup_scope(scope) {
670 let h = &self.hierarchy;
671 let scope = &h[scope_ref];
672 matches!(
673 scope.scope_type(),
674 ScopeType::Struct
675 | ScopeType::Union
676 | ScopeType::Class
677 | ScopeType::Interface
678 | ScopeType::VhdlRecord
679 | ScopeType::VhdlArray
680 | ScopeType::SvArray
681 )
682 } else {
683 false
684 }
685 }
686
687 #[must_use]
688 pub fn scope_is_array(&self, scope: &ScopeRef) -> bool {
690 if let Some(scope_ref) = self.lookup_scope(scope) {
691 let h = &self.hierarchy;
692 let scope = &h[scope_ref];
693 matches!(
694 scope.scope_type(),
695 ScopeType::VhdlArray | ScopeType::SvArray
696 )
697 } else {
698 false
699 }
700 }
701
702 #[must_use]
703 pub fn get_scope_tooltip_data(&self, scope: &ScopeRef) -> String {
704 let mut out = String::new();
705 if let Some(scope_ref) = self.lookup_scope(scope) {
706 let h = &self.hierarchy;
707 let scope = &h[scope_ref];
708 writeln!(&mut out, "{}", scope_type_to_string(scope.scope_type())).unwrap();
709 if let Some((path, line)) = scope.instantiation_source_loc(h) {
710 writeln!(&mut out, "{path}:{line}").unwrap();
711 }
712 match (scope.component(h), scope.source_loc(h)) {
713 (Some(name), Some((path, line))) => {
714 write!(&mut out, "{name} : {path}:{line}").unwrap();
715 }
716 (None, Some((path, line))) => {
717 let same = scope
719 .instantiation_source_loc(h)
720 .is_some_and(|(i_path, i_line)| path == i_path && line == i_line);
721 if !same {
722 write!(&mut out, "{path}:{line}").unwrap();
723 }
724 }
725 (Some(name), None) => write!(&mut out, "{name}").unwrap(),
726 (None, None) => {}
728 }
729 }
730 if out.ends_with('\n') {
731 out.pop().unwrap();
732 }
733 out
734 }
735
736 pub fn variable_to_meta(&self, variable: &VariableRef) -> Result<VariableMeta> {
737 let var = self.get_var(variable)?;
738 let encoding = match var.signal_encoding() {
739 SignalEncoding::String => VariableEncoding::String,
740 SignalEncoding::Real => VariableEncoding::Real,
741 SignalEncoding::BitVector(_) => VariableEncoding::BitVector,
742 SignalEncoding::Event => VariableEncoding::Event,
743 };
744 Ok(VariableMeta {
745 var: variable.clone(),
746 num_bits: var.length(),
747 variable_type: Some(VariableType::from_wellen_type(var.var_type())),
748 variable_type_name: var.vhdl_type_name(&self.hierarchy).map(ToString::to_string),
749 index: var.index().map(VariableIndex::from_wellen_type),
750 direction: Some(VariableDirection::from_wellen_direction(var.direction())),
751 enum_map: self.get_enum_map(var),
752 encoding,
753 })
754 }
755
756 pub fn signal_accessor(&self, signal_ref: SignalRef) -> Result<WellenSignalAccessor> {
757 let signal = self
758 .signals
759 .get(&signal_ref)
760 .cloned()
761 .ok_or_else(|| anyhow!("Signal not loaded"))?;
762 Ok(WellenSignalAccessor::new(
763 signal,
764 Arc::clone(&self.time_table),
765 ))
766 }
767
768 pub fn signal_ref(&self, variable: &VariableRef) -> Result<SignalRef> {
770 let var_ref = self.get_var_ref(variable)?;
771 Ok(self.hierarchy[var_ref].signal_ref())
772 }
773
774 #[must_use]
776 pub fn is_signal_loaded(&self, signal_ref: SignalRef) -> bool {
777 self.signals.contains_key(&signal_ref)
778 }
779}
780
781pub struct WellenSignalAccessor {
783 signal: Arc<Signal>,
784 time_table: Arc<TimeTable>,
785}
786
787impl WellenSignalAccessor {
788 #[must_use]
790 pub fn new(signal: Arc<Signal>, time_table: Arc<TimeTable>) -> Self {
791 Self { signal, time_table }
792 }
793
794 #[must_use]
796 pub fn iter_changes(
797 &self,
798 ) -> Box<dyn Iterator<Item = (u64, surfer_translation_types::VariableValue)> + '_> {
799 Box::new(
800 self.signal
801 .iter_changes()
802 .filter_map(|(time_idx, signal_value)| {
803 let time_u64 = *self.time_table.get(time_idx as usize)?;
804 let var_value = convert_variable_value(signal_value);
805 Some((time_u64, var_value))
806 }),
807 )
808 }
809}
810
811fn scope_type_to_string(tpe: ScopeType) -> &'static str {
812 match tpe {
813 ScopeType::Module => "module",
814 ScopeType::Task => "task",
815 ScopeType::Function => "function",
816 ScopeType::Begin => "begin",
817 ScopeType::Fork => "fork",
818 ScopeType::Generate => "generate",
819 ScopeType::Struct => "struct",
820 ScopeType::Union => "union",
821 ScopeType::Class => "class",
822 ScopeType::Interface => "interface",
823 ScopeType::Package => "package",
824 ScopeType::Program => "program",
825 ScopeType::VhdlArchitecture => "architecture",
826 ScopeType::VhdlProcedure => "procedure",
827 ScopeType::VhdlFunction => "function",
828 ScopeType::VhdlRecord => "record",
829 ScopeType::VhdlProcess => "process",
830 ScopeType::VhdlBlock => "block",
831 ScopeType::VhdlForGenerate => "for-generate",
832 ScopeType::VhdlIfGenerate => "if-generate",
833 ScopeType::VhdlGenerate => "generate",
834 ScopeType::VhdlPackage => "package",
835 ScopeType::GhwGeneric => "generic",
836 ScopeType::VhdlArray => "array",
837 ScopeType::SvArray => "array",
838 ScopeType::Unknown => "unknown",
839 _ => todo!(),
840 }
841}
842
843fn convert_variable_value(value: wellen::SignalValue) -> VariableValue {
844 match value {
845 wellen::SignalValue::Binary(data, _bits) => {
846 VariableValue::BigUint(BigUint::from_bytes_be(data))
847 }
848 wellen::SignalValue::FourValue(_, _) | wellen::SignalValue::NineValue(_, _) => {
849 VariableValue::String(
850 value
851 .to_bit_string()
852 .expect("failed to convert value {value:?} to a string"),
853 )
854 }
855 wellen::SignalValue::String(value) => VariableValue::String(value.to_string()),
856 wellen::SignalValue::Real(value) => VariableValue::BigUint(BigUint::from(value.to_bits())),
857 wellen::SignalValue::Event => VariableValue::String("Event".to_string()),
858 }
859}
860
861#[local_impl::local_impl]
862impl FromVarType for VariableType {
863 fn from_wellen_type(signaltype: VarType) -> Self {
864 match signaltype {
865 VarType::Reg => VariableType::VCDReg,
866 VarType::Wire => VariableType::VCDWire,
867 VarType::Integer => VariableType::VCDInteger,
868 VarType::Real => VariableType::VCDReal,
869 VarType::Parameter => VariableType::VCDParameter,
870 VarType::String => VariableType::VCDString,
871 VarType::Time => VariableType::VCDTime,
872 VarType::Event => VariableType::VCDEvent,
873 VarType::Supply0 => VariableType::VCDSupply0,
874 VarType::Supply1 => VariableType::VCDSupply1,
875 VarType::Tri => VariableType::VCDTri,
876 VarType::TriAnd => VariableType::VCDTriAnd,
877 VarType::TriOr => VariableType::VCDTriOr,
878 VarType::TriReg => VariableType::VCDTriReg,
879 VarType::Tri0 => VariableType::VCDTri0,
880 VarType::Tri1 => VariableType::VCDTri1,
881 VarType::WAnd => VariableType::VCDWAnd,
882 VarType::WOr => VariableType::VCDWOr,
883 VarType::Port => VariableType::Port,
884 VarType::Bit => VariableType::Bit,
885 VarType::Logic => VariableType::Logic,
886 VarType::Int => VariableType::Int,
887 VarType::Enum => VariableType::Enum,
888 VarType::SparseArray => VariableType::SparseArray,
889 VarType::RealTime => VariableType::RealTime,
890 VarType::ShortInt => VariableType::ShortInt,
891 VarType::LongInt => VariableType::LongInt,
892 VarType::Byte => VariableType::Byte,
893 VarType::ShortReal => VariableType::ShortReal,
894 VarType::Boolean => VariableType::Boolean,
895 VarType::BitVector => VariableType::BitVector,
896 VarType::StdLogic => VariableType::StdLogic,
897 VarType::StdLogicVector => VariableType::StdLogicVector,
898 VarType::StdULogic => VariableType::StdULogic,
899 VarType::StdULogicVector => VariableType::StdULogicVector,
900 VarType::RealParameter => VariableType::RealParameter,
901 }
902 }
903}
904
905#[local_impl::local_impl]
906impl ToVarType for VariableType {
907 fn to_wellen_type(&self) -> VarType {
908 match self {
909 VariableType::VCDReg => VarType::Reg,
910 VariableType::VCDWire => VarType::Wire,
911 VariableType::VCDInteger => VarType::Integer,
912 VariableType::VCDReal => VarType::Real,
913 VariableType::VCDParameter => VarType::Parameter,
914 VariableType::VCDString => VarType::String,
915 VariableType::VCDTime => VarType::Time,
916 VariableType::VCDEvent => VarType::Event,
917 VariableType::VCDSupply0 => VarType::Supply0,
918 VariableType::VCDSupply1 => VarType::Supply1,
919 VariableType::VCDTri => VarType::Tri,
920 VariableType::VCDTriAnd => VarType::TriAnd,
921 VariableType::VCDTriOr => VarType::TriOr,
922 VariableType::VCDTriReg => VarType::TriReg,
923 VariableType::VCDTri0 => VarType::Tri0,
924 VariableType::VCDTri1 => VarType::Tri1,
925 VariableType::VCDWAnd => VarType::WAnd,
926 VariableType::VCDWOr => VarType::WOr,
927 VariableType::Port => VarType::Port,
928 VariableType::Bit => VarType::Bit,
929 VariableType::Logic => VarType::Logic,
930 VariableType::Int => VarType::Int,
931 VariableType::Enum => VarType::Enum,
932 VariableType::SparseArray => VarType::SparseArray,
933 VariableType::ShortInt => VarType::ShortInt,
934 VariableType::LongInt => VarType::LongInt,
935 VariableType::Byte => VarType::Byte,
936 VariableType::ShortReal => VarType::ShortReal,
937 VariableType::Boolean => VarType::Boolean,
938 VariableType::BitVector => VarType::BitVector,
939 VariableType::StdLogic => VarType::StdLogic,
940 VariableType::StdLogicVector => VarType::StdLogicVector,
941 VariableType::StdULogic => VarType::StdULogic,
942 VariableType::StdULogicVector => VarType::StdULogicVector,
943 VariableType::RealParameter => VarType::RealParameter,
944 VariableType::RealTime => VarType::RealTime,
945 }
946 }
947}
948
949#[local_impl::local_impl]
950impl VarTypeExt for VarType {
951 fn is_parameter(&self) -> bool {
952 matches!(self, VarType::Parameter | VarType::RealParameter)
953 }
954}
955
956#[inline]
957fn binary_search(times: &[Time], needle: Time) -> usize {
958 let mut lower_idx = 0usize;
959 let mut upper_idx = times.len() - 1;
960 while lower_idx <= upper_idx {
961 let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
962
963 match times[mid_idx].cmp(&needle) {
964 std::cmp::Ordering::Less => {
965 lower_idx = mid_idx + 1;
966 }
967 std::cmp::Ordering::Equal => {
968 return mid_idx;
969 }
970 std::cmp::Ordering::Greater => {
971 upper_idx = mid_idx - 1;
972 }
973 }
974 }
975 lower_idx - 1
976}
977
978#[cfg(test)]
979mod tests {
980 use super::*;
981
982 #[test]
983 fn test_signal_conversion() {
984 let inp0: &[u8] = &[128, 0, 0, 3];
985 let out0 = convert_variable_value(wellen::SignalValue::Binary(inp0, 32));
986 assert_eq!(out0, VariableValue::BigUint(BigUint::from(0x80000003u64)));
987 }
988}