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