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