From b162d67a9d1b995e0cabb291bb084e7daa86948e Mon Sep 17 00:00:00 2001 From: TheZoq2 Date: Thu, 22 Dec 2022 18:11:19 +0100 Subject: [PATCH 1/6] impl traits required for maps for idxes --- src/vcd/types.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vcd/types.rs b/src/vcd/types.rs index 27b682b..3b2979a 100644 --- a/src/vcd/types.rs +++ b/src/vcd/types.rs @@ -29,10 +29,10 @@ pub struct Metadata { } // We do a lot of arena allocation in this codebase. -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct ScopeIdx(pub usize); -#[derive(Debug, Copy, Clone, PartialEq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct SignalIdx(pub usize); #[derive(Debug)] -- 2.47.1 From 3da35792138a25bf198b1dfa962dcd3993f5358d Mon Sep 17 00:00:00 2001 From: TheZoq2 Date: Fri, 23 Dec 2022 11:34:48 +0100 Subject: [PATCH 2/6] Add more timing information --- src/lib.rs | 2 +- src/vcd/parse.rs | 3 +- src/vcd/parse/events.rs | 7 +++- src/vcd/signal.rs | 83 ++++++++++++++++++++++++++++++++++------- src/vcd/types.rs | 6 +++ 5 files changed, 83 insertions(+), 18 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f73512a..1ab2b83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,6 @@ mod vcd; pub use vcd::parse::parse_vcd; pub use vcd::types::{ScopeIdx, SignalIdx, VCD}; pub use vcd::types::{Metadata, Timescale, Version}; -pub use vcd::signal::{Signal}; +pub use vcd::signal::{Signal, SignalValue}; pub use num::BigUint; diff --git a/src/vcd/parse.rs b/src/vcd/parse.rs index c89361c..4a5e3b0 100644 --- a/src/vcd/parse.rs +++ b/src/vcd/parse.rs @@ -27,10 +27,11 @@ pub fn parse_vcd(file: File) -> Result { all_signals: vec![], all_scopes: vec![], root_scopes: vec![], + largest_timestamp: None }; scopes::parse_scopes(&mut word_gen, &mut vcd, &mut signal_map)?; events::parse_events(&mut word_gen, &mut vcd, &mut signal_map)?; Ok(vcd) -} \ No newline at end of file +} diff --git a/src/vcd/parse/events.rs b/src/vcd/parse/events.rs index 05e24ed..49bff94 100644 --- a/src/vcd/parse/events.rs +++ b/src/vcd/parse/events.rs @@ -40,14 +40,14 @@ pub(super) fn parse_events<'a>( "#" => { let value = &word[1..]; let (f, l) = (file!(), line!()); - let value = BigUint::parse_bytes(value.as_bytes(), 10) + let value_biguint = BigUint::parse_bytes(value.as_bytes(), 10) .ok_or(()) .map_err(|_| { format!( "Error near {f}:{l}. Failed to parse {value} as BigInt at {cursor:?}" ) })?; - let mut value = value.to_bytes_le(); + let mut value = value_biguint.to_bytes_le(); // TODO : u32 helps with less memory, but should ideally likely be // configurable. curr_tmstmp_len_u8 = u8::try_from(value.len()).map_err(|_| { @@ -66,6 +66,7 @@ pub(super) fn parse_events<'a>( ) })?; vcd.tmstmps_encoded_as_u8s.append(&mut value); + vcd.largest_timestamp = Some(value_biguint); } // handle the case of an n bit signal whose value must be parsed @@ -134,6 +135,7 @@ pub(super) fn parse_events<'a>( lsb_indxs_of_num_tmstmp_vals_on_tmln, byte_len_of_num_tmstmp_vals_on_tmln, lsb_indxs_of_string_tmstmp_vals_on_tmln, + byte_len_of_string_tmstmp_vals_on_tmln, .. } => { // we've already identified in a prior loop iteration that the signal has @@ -176,6 +178,7 @@ pub(super) fn parse_events<'a>( if store_as_string { lsb_indxs_of_string_tmstmp_vals_on_tmln .push(LsbIdxOfTmstmpValOnTmln(curr_tmstmp_lsb_idx)); + byte_len_of_string_tmstmp_vals_on_tmln.push(curr_tmstmp_len_u8); string_vals.push(value_string); Ok(()) } else { diff --git a/src/vcd/signal.rs b/src/vcd/signal.rs index 1688f92..0e8dc9d 100644 --- a/src/vcd/signal.rs +++ b/src/vcd/signal.rs @@ -23,8 +23,8 @@ pub enum SigType { Time, } -#[derive(Debug)] -pub(super) enum TimelineQueryResults { +#[derive(Debug, PartialEq)] +pub enum SignalValue { BigUint(BigUint), String(String), } @@ -36,13 +36,19 @@ impl<'a> Signal<'a> { let Signal(signal_enum) = &self; signal_enum.name() } + + pub fn num_bits(&self) -> Option { + let Signal(signal_enum) = &self; + signal_enum.bits_required() + } + pub fn query_string_val_on_tmln( &self, desired_time: &BigUint, vcd: &types::VCD, ) -> Result { let Signal(signal_enum) = &self; - signal_enum.query_string_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals) + signal_enum.query_string_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals).map(|(val, _)| val) } pub fn query_num_val_on_tmln( &self, @@ -50,7 +56,44 @@ impl<'a> Signal<'a> { vcd: &types::VCD, ) -> Result { let Signal(signal_enum) = &self; - signal_enum.query_num_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals) + signal_enum.query_num_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals).map(|(val, _)| val) + } + + pub fn query_val_on_tmln( + &self, + desired_time: &BigUint, + vcd: &types::VCD, + ) -> Result { + let Signal(signal_enum) = &self; + let num_val = signal_enum + .query_num_val_on_tmln( + desired_time, + &vcd.tmstmps_encoded_as_u8s, + &vcd.all_signals + ); + let str_val = signal_enum + .query_string_val_on_tmln( + desired_time, + &vcd.tmstmps_encoded_as_u8s, + &vcd.all_signals + ); + + // Both num and str will return the newest value that is closest to + // the desired time. If both have valid values, select the most recent + // one + match (num_val, str_val) { + (Ok((num_val, num_time)), Ok((str_val, str_time))) => { + if num_time > str_time { + Ok(SignalValue::BigUint(num_val)) + } + else { + Ok(SignalValue::String(str_val)) + } + } + (Ok((num_val, _)), Err(_)) => Ok(SignalValue::BigUint(num_val)), + (Err(_), Ok((str_val, _))) => Ok(SignalValue::String(str_val)), + (Err(e), _e) => Err(e) + } } } @@ -187,6 +230,10 @@ impl SignalEnum { lsb_indxs_of_string_tmstmp_vals_on_tmln[event_idx]; let timestamp_idx = timestamp_idx as usize; + if byte_len_of_string_tmstmp_vals_on_tmln.is_empty() { + return Err(SignalErrors::EmptyTimeline); + } + // form timestamp let byte_len = byte_len_of_string_tmstmp_vals_on_tmln[event_idx] as usize; let timestamp = &tmstmps_encoded_as_u8s[timestamp_idx..(timestamp_idx + byte_len)]; @@ -253,6 +300,14 @@ impl SignalEnum { Ok((timestamp, signal_val)) } + + fn bits_required(&self) -> Option { + match self { + SignalEnum::Data {num_bits, ..} => num_bits.clone(), + // TODO: Follow aliases? + SignalEnum::Alias { name, signal_alias } => None, + } + } } // Val and string query functions. @@ -265,7 +320,7 @@ impl SignalEnum { desired_time: &BigUint, tmstmps_encoded_as_u8s: &Vec, all_signals: &Vec, - ) -> Result { + ) -> Result<(String, TimeStamp), SignalErrors> { let signal_idx = match self { Self::Data { self_idx, .. } => { let SignalIdx(idx) = self_idx; @@ -319,7 +374,7 @@ impl SignalEnum { if *desired_time < timeline_start_time { return Err(SignalErrors::PreTimeline { desired_time: desired_time.clone(), - timeline_start_time: timeline_start_time, + timeline_start_time, }); } @@ -331,7 +386,7 @@ impl SignalEnum { // check if we're requesting a value that occurs beyond the end of the timeline, // if so, return the last value in this timeline if *desired_time > timeline_end_time { - return Ok(timeline_end_val.to_string()); + return Ok((timeline_end_val.to_string(), timeline_end_time)); } // This while loop is the meat of the lookup. Performance is log2(n), @@ -350,7 +405,7 @@ impl SignalEnum { lower_idx = mid_idx + 1; } std::cmp::Ordering::Equal => { - return Ok(curr_val.to_string()); + return Ok((curr_val.to_string(), curr_time)); } std::cmp::Ordering::Greater => { upper_idx = mid_idx - 1; @@ -373,14 +428,14 @@ impl SignalEnum { }); } - return Ok(left_val.to_string()); + Ok((left_val.to_string(), left_time)) } pub fn query_num_val_on_tmln( &self, desired_time: &BigUint, tmstmps_encoded_as_u8s: &Vec, all_signals: &Vec, - ) -> Result { + ) -> Result<(BigUint, TimeStamp), SignalErrors> { let signal_idx = match self { Self::Data { self_idx, .. } => { let SignalIdx(idx) = self_idx; @@ -449,7 +504,7 @@ impl SignalEnum { if *desired_time < timeline_start_time { return Err(SignalErrors::PreTimeline { desired_time: desired_time.clone(), - timeline_start_time: timeline_start_time, + timeline_start_time, }); } @@ -461,7 +516,7 @@ impl SignalEnum { // check if we're requesting a value that occurs beyond the end of the timeline, // if so, return the last value in this timeline if *desired_time > timeline_end_time { - return Ok(timeline_end_val); + return Ok((timeline_end_val, timeline_end_time)); } // This while loop is the meat of the lookup. Performance is log2(n), @@ -480,7 +535,7 @@ impl SignalEnum { lower_idx = mid_idx + 1; } std::cmp::Ordering::Equal => { - return Ok(curr_val); + return Ok((curr_val, curr_time)); } std::cmp::Ordering::Greater => { upper_idx = mid_idx - 1; @@ -503,6 +558,6 @@ impl SignalEnum { }); } - return Ok(left_val); + Ok((left_val, left_time)) } } diff --git a/src/vcd/types.rs b/src/vcd/types.rs index 3b2979a..d589e73 100644 --- a/src/vcd/types.rs +++ b/src/vcd/types.rs @@ -5,6 +5,7 @@ // and the YEHOWSHUA license, both of which can be found at // the root of the folder containing the sources for this program. use chrono::prelude::{DateTime, Utc}; +use num::BigUint; use super::signal::{Signal, SignalEnum}; #[derive(Debug)] @@ -63,6 +64,7 @@ pub struct VCD { pub(super) all_signals: Vec, pub(super) all_scopes: Vec, pub(super) root_scopes: Vec, + pub(super) largest_timestamp: Option } impl VCD { @@ -121,4 +123,8 @@ impl VCD { )), } } + + pub fn max_timestamp(&self) -> &Option { + &self.largest_timestamp + } } -- 2.47.1 From bc73db5dba37f46790172b559e1c5a05d7ca8abe Mon Sep 17 00:00:00 2001 From: TheZoq2 Date: Tue, 3 Jan 2023 16:33:44 +0100 Subject: [PATCH 3/6] Do not include range in name --- src/vcd/parse/scopes.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vcd/parse/scopes.rs b/src/vcd/parse/scopes.rs index 94b8965..cb193cf 100644 --- a/src/vcd/parse/scopes.rs +++ b/src/vcd/parse/scopes.rs @@ -97,7 +97,11 @@ pub(super) fn parse_var<'a>( let (word, _) = next_word!(word_reader)?; match word { "$end" => break, - _ => full_signal_name.push(word.to_string()), + other => { + if !other.starts_with("[") { + full_signal_name.push(word.to_string()) + } + } } } let full_signal_name = full_signal_name.join(" "); -- 2.47.1 From 79300afd4344bd8f9cd4c31a7fb85f5fdc9c2cbf Mon Sep 17 00:00:00 2001 From: TheZoq2 Date: Mon, 9 Jan 2023 18:45:10 +0100 Subject: [PATCH 4/6] Make generic over readers --- src/vcd/parse.rs | 2 +- src/vcd/parse/combinator_atoms.rs | 5 ++++- src/vcd/parse/events.rs | 4 ++-- src/vcd/parse/metadata.rs | 8 ++++---- src/vcd/parse/scopes.rs | 16 ++++++++-------- src/vcd/reader.rs | 11 +++++------ 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/vcd/parse.rs b/src/vcd/parse.rs index 4a5e3b0..ef2ec61 100644 --- a/src/vcd/parse.rs +++ b/src/vcd/parse.rs @@ -11,7 +11,7 @@ mod scopes; mod events; -pub fn parse_vcd(file: File) -> Result { +pub fn parse_vcd(file: impl std::io::Read) -> Result { let mut word_gen = super::reader::WordReader::new(file); let header = metadata::parse_metadata(&mut word_gen)?; diff --git a/src/vcd/parse/combinator_atoms.rs b/src/vcd/parse/combinator_atoms.rs index 0473f63..c599f71 100644 --- a/src/vcd/parse/combinator_atoms.rs +++ b/src/vcd/parse/combinator_atoms.rs @@ -69,7 +69,10 @@ pub(super) fn tag<'a>(word: &'a str, pattern: &'a str) -> ParseResult<'a> { }; } -pub(super) fn ident(word_reader: &mut WordReader, keyword: &str) -> Result<(), String> { +pub(super) fn ident( + word_reader: &mut WordReader, + keyword: &str, +) -> Result<(), String> { // let keyword = "module"; let (word, cursor) = next_word!(word_reader)?; diff --git a/src/vcd/parse/events.rs b/src/vcd/parse/events.rs index 49bff94..2246d15 100644 --- a/src/vcd/parse/events.rs +++ b/src/vcd/parse/events.rs @@ -12,8 +12,8 @@ use super::super::reader::{WordReader, Cursor, Line, Word, next_word}; use super::super::types::{SignalIdx, VCD}; -pub(super) fn parse_events<'a>( - word_reader: &mut WordReader, +pub(super) fn parse_events<'a, R: std::io::Read>( + word_reader: &mut WordReader, vcd: &'a mut VCD, signal_map: &mut HashMap, ) -> Result<(), String> { diff --git a/src/vcd/parse/metadata.rs b/src/vcd/parse/metadata.rs index 6d0fffc..b908403 100644 --- a/src/vcd/parse/metadata.rs +++ b/src/vcd/parse/metadata.rs @@ -145,7 +145,7 @@ pub(super) fn parse_date( )) } -pub(super) fn parse_version(word_reader: &mut WordReader) -> Result { +pub(super) fn parse_version(word_reader: &mut WordReader) -> Result { let mut version = String::new(); loop { @@ -162,8 +162,8 @@ pub(super) fn parse_version(word_reader: &mut WordReader) -> Result( + word_reader: &mut WordReader, ) -> Result<(Option, Timescale), String> { // we might see `1ps $end` or `1 ps $end` // first get timescale @@ -220,7 +220,7 @@ pub(super) fn parse_timescale( return Ok(timescale); } -pub(super) fn parse_metadata(word_reader: &mut WordReader) -> Result { +pub(super) fn parse_metadata(word_reader: &mut WordReader) -> Result { let mut metadata = Metadata { date: None, version: None, diff --git a/src/vcd/parse/scopes.rs b/src/vcd/parse/scopes.rs index cb193cf..00a087e 100644 --- a/src/vcd/parse/scopes.rs +++ b/src/vcd/parse/scopes.rs @@ -15,8 +15,8 @@ use super::super::signal::{SigType, SignalEnum}; use super::combinator_atoms::{tag, ident}; use super::types::{ParseResult}; -pub(super) fn parse_var<'a>( - word_reader: &mut WordReader, +pub(super) fn parse_var<'a, R: std::io::Read>( + word_reader: &mut WordReader, parent_scope_idx: ScopeIdx, vcd: &'a mut VCD, signal_map: &mut HashMap, @@ -157,8 +157,8 @@ pub(super) fn parse_var<'a>( /// Sometimes, variables can be listed outside of scopes. /// We call these orphaned vars. -fn parse_orphaned_vars<'a>( - word_reader: &mut WordReader, +fn parse_orphaned_vars<'a, R: std::io::Read>( + word_reader: &mut WordReader, vcd: &'a mut VCD, signal_map: &mut HashMap, ) -> Result<(), String> { @@ -221,8 +221,8 @@ fn parse_orphaned_vars<'a>( Ok(()) } -fn parse_scopes_inner<'a>( - word_reader: &mut WordReader, +fn parse_scopes_inner<'a, R: std::io::Read>( + word_reader: &mut WordReader, parent_scope_idx: Option, vcd: &'a mut VCD, signal_map: &mut HashMap, @@ -328,8 +328,8 @@ fn parse_scopes_inner<'a>( Ok(()) } -pub(super) fn parse_scopes<'a>( - word_reader: &mut WordReader, +pub(super) fn parse_scopes<'a, R: std::io::Read>( + word_reader: &mut WordReader, vcd: &'a mut VCD, signal_map: &mut HashMap, ) -> Result<(), String> { diff --git a/src/vcd/reader.rs b/src/vcd/reader.rs index 9fc32ec..6ef242f 100644 --- a/src/vcd/reader.rs +++ b/src/vcd/reader.rs @@ -3,7 +3,6 @@ // and the YEHOWSHUA license, both of which can be found at // the root of the folder containing the sources for this program. use std::collections::VecDeque; -use std::fs::File; use std::io; use std::io::BufRead; use std::slice; @@ -16,8 +15,8 @@ pub(super) struct Word(pub(super) usize); #[derive(Debug, Clone)] pub(super) struct Cursor(pub(super) Line, pub(super) Word); -pub(super) struct WordReader { - reader: io::BufReader, +pub(super) struct WordReader { + reader: io::BufReader, eof: bool, buffers: Vec, curr_line: usize, @@ -25,11 +24,11 @@ pub(super) struct WordReader { curr_slice: Option<(*const u8, usize, Cursor)>, } -impl WordReader { - pub(super) fn new(file: File) -> WordReader { +impl WordReader { + pub(super) fn new(file: R) -> WordReader { let reader = io::BufReader::new(file); WordReader { - reader: reader, + reader, eof: false, buffers: vec![], curr_line: 0, -- 2.47.1 From 53bbacd261451231b593b8f39e570fcdb60c2bed Mon Sep 17 00:00:00 2001 From: TheZoq2 Date: Mon, 1 May 2023 17:37:24 +0200 Subject: [PATCH 5/6] Expose signal time stamp --- src/vcd/signal.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/vcd/signal.rs b/src/vcd/signal.rs index 0e8dc9d..503e0f2 100644 --- a/src/vcd/signal.rs +++ b/src/vcd/signal.rs @@ -63,7 +63,7 @@ impl<'a> Signal<'a> { &self, desired_time: &BigUint, vcd: &types::VCD, - ) -> Result { + ) -> Result<(TimeStamp, SignalValue), SignalErrors> { let Signal(signal_enum) = &self; let num_val = signal_enum .query_num_val_on_tmln( @@ -84,14 +84,14 @@ impl<'a> Signal<'a> { match (num_val, str_val) { (Ok((num_val, num_time)), Ok((str_val, str_time))) => { if num_time > str_time { - Ok(SignalValue::BigUint(num_val)) + Ok((num_time, SignalValue::BigUint(num_val))) } else { - Ok(SignalValue::String(str_val)) + Ok((str_time, SignalValue::String(str_val))) } } - (Ok((num_val, _)), Err(_)) => Ok(SignalValue::BigUint(num_val)), - (Err(_), Ok((str_val, _))) => Ok(SignalValue::String(str_val)), + (Ok((num_val, time)), Err(_)) => Ok((time, SignalValue::BigUint(num_val))), + (Err(_), Ok((str_val, time))) => Ok((time, SignalValue::String(str_val))), (Err(e), _e) => Err(e) } } -- 2.47.1 From a8edb3d60260756ea9d4805cb6a73b62a307d820 Mon Sep 17 00:00:00 2001 From: TheZoq2 Date: Fri, 16 Jun 2023 17:08:20 +0200 Subject: [PATCH 6/6] expse paths and fix warnings --- src/vcd/parse.rs | 1 - src/vcd/parse/scopes.rs | 32 +++++++++++++++++++------------- src/vcd/signal.rs | 18 ++++++++++++++---- src/vcd/types.rs | 1 - 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/vcd/parse.rs b/src/vcd/parse.rs index ef2ec61..7229045 100644 --- a/src/vcd/parse.rs +++ b/src/vcd/parse.rs @@ -2,7 +2,6 @@ // This program is distributed under both the GPLV3 license // and the YEHOWSHUA license, both of which can be found at // the root of the folder containing the sources for this program. -use std::fs::File; mod combinator_atoms; mod types; diff --git a/src/vcd/parse/scopes.rs b/src/vcd/parse/scopes.rs index 00a087e..c60deda 100644 --- a/src/vcd/parse/scopes.rs +++ b/src/vcd/parse/scopes.rs @@ -20,6 +20,7 @@ pub(super) fn parse_var<'a, R: std::io::Read>( parent_scope_idx: ScopeIdx, vcd: &'a mut VCD, signal_map: &mut HashMap, + path: &Vec, ) -> Result<(), String> { let (word, cursor) = next_word!(word_reader)?; let expected_types = [ @@ -120,7 +121,8 @@ pub(super) fn parse_var<'a, R: std::io::Read>( Some(ref_signal_idx) => { let signal_idx = SignalIdx(vcd.all_signals.len()); let signal = SignalEnum::Alias { - name: full_signal_name, + name: full_signal_name.clone(), + path: path.iter().cloned().chain([full_signal_name]).collect::>(), signal_alias: *ref_signal_idx, }; (signal, signal_idx) @@ -129,11 +131,12 @@ pub(super) fn parse_var<'a, R: std::io::Read>( let signal_idx = SignalIdx(vcd.all_signals.len()); signal_map.insert(signal_alias.to_string(), signal_idx); let signal = SignalEnum::Data { - name: full_signal_name, + name: full_signal_name.clone(), + path: path.iter().cloned().chain([full_signal_name]).collect::>(), sig_type: var_type, signal_error: None, - num_bits: num_bits, - num_bytes: num_bytes, + num_bits, + num_bytes, self_idx: signal_idx, nums_encoded_as_fixed_width_le_u8: vec![], string_vals: vec![], @@ -141,7 +144,6 @@ pub(super) fn parse_var<'a, R: std::io::Read>( byte_len_of_num_tmstmp_vals_on_tmln: vec![], byte_len_of_string_tmstmp_vals_on_tmln: vec![], lsb_indxs_of_string_tmstmp_vals_on_tmln: vec![], - scope_parent: parent_scope_idx, }; (signal, signal_idx) } @@ -185,7 +187,6 @@ fn parse_orphaned_vars<'a, R: std::io::Read>( if !scope_already_exists { vcd.all_scopes.push(Scope { name: scope_name.to_string(), - parent_idx: None, self_idx: scope_idx, child_signals: vec![], child_scopes: vec![], @@ -195,14 +196,14 @@ fn parse_orphaned_vars<'a, R: std::io::Read>( // we can go ahead and parse the current var as we've already encountered // "$var" before now. - parse_var(word_reader, scope_idx, vcd, signal_map)?; + parse_var(word_reader, scope_idx, vcd, signal_map, &vec![])?; loop { let (word, cursor) = next_word!(word_reader)?; match word { "$var" => { - parse_var(word_reader, scope_idx, vcd, signal_map)?; + parse_var(word_reader, scope_idx, vcd, signal_map, &vec![])?; } "$scope" => break, _ => { @@ -226,6 +227,7 @@ fn parse_scopes_inner<'a, R: std::io::Read>( parent_scope_idx: Option, vcd: &'a mut VCD, signal_map: &mut HashMap, + path: &Vec ) -> Result<(), String> { // $scope module reg_mag_i $end // ^^^^^^ - module keyword @@ -249,6 +251,9 @@ fn parse_scopes_inner<'a, R: std::io::Read>( // ^^^^^^^^^ - scope name let (scope_name, _) = next_word!(word_reader)?; + let mut path = path.clone(); + path.push(scope_name.to_string()); + let curr_scope_idx = ScopeIdx(vcd.all_scopes.len()); // register this scope as a child of the current parent scope @@ -265,7 +270,6 @@ fn parse_scopes_inner<'a, R: std::io::Read>( // add this scope to list of existing scopes vcd.all_scopes.push(Scope { name: scope_name.to_string(), - parent_idx: parent_scope_idx, self_idx: curr_scope_idx, child_signals: vec![], child_scopes: vec![], @@ -275,6 +279,8 @@ fn parse_scopes_inner<'a, R: std::io::Read>( // ^^^^ - end keyword ident(word_reader, "$end")?; + + loop { let (word, cursor) = next_word!(word_reader)?; let ParseResult { matched, residual } = tag(word, "$"); @@ -284,10 +290,10 @@ fn parse_scopes_inner<'a, R: std::io::Read>( match residual { "scope" => { // recursive - parse inside of current scope tree - parse_scopes_inner(word_reader, Some(curr_scope_idx), vcd, signal_map)?; + parse_scopes_inner(word_reader, Some(curr_scope_idx), vcd, signal_map, &path)?; } "var" => { - parse_var(word_reader, curr_scope_idx, vcd, signal_map)?; + parse_var(word_reader, curr_scope_idx, vcd, signal_map, &path)?; } "upscope" => { ident(word_reader, "$end")?; @@ -360,7 +366,7 @@ pub(super) fn parse_scopes<'a, R: std::io::Read>( } // now for the interesting part - parse_scopes_inner(word_reader, None, vcd, signal_map)?; + parse_scopes_inner(word_reader, None, vcd, signal_map, &vec![])?; // let err = format!("reached end of file without parser leaving {}", function_name!()); let expected_keywords = ["$scope", "$enddefinitions"]; @@ -374,7 +380,7 @@ pub(super) fn parse_scopes<'a, R: std::io::Read>( match word { "$scope" => { - parse_scopes_inner(word_reader, None, vcd, signal_map)?; + parse_scopes_inner(word_reader, None, vcd, signal_map, &vec![])?; } "$enddefinitions" => { ident(word_reader, "$end")?; diff --git a/src/vcd/signal.rs b/src/vcd/signal.rs index 503e0f2..0ac29ef 100644 --- a/src/vcd/signal.rs +++ b/src/vcd/signal.rs @@ -2,9 +2,9 @@ // This program is distributed under both the GPLV3 license // and the YEHOWSHUA license, both of which can be found at // the root of the folder containing the sources for this program. -use super::types::{ScopeIdx, SignalIdx}; +use super::types::SignalIdx; use super::types; -use num::{BigUint}; +use num::BigUint; // Index to the least significant byte of a timestamp // value on the timeline @@ -37,6 +37,13 @@ impl<'a> Signal<'a> { signal_enum.name() } + pub fn path(&self) -> &[String] { + match self.0 { + SignalEnum::Data {path, ..} => path, + SignalEnum::Alias { path, .. } => path, + } + } + pub fn num_bits(&self) -> Option { let Signal(signal_enum) = &self; signal_enum.bits_required() @@ -101,6 +108,7 @@ impl<'a> Signal<'a> { pub(super) enum SignalEnum { Data { name: String, + path: Vec, sig_type: SigType, /// I've seen a 0 bit signal parameter in a xilinx /// simulation before that gets assigned 1 bit values. @@ -136,10 +144,10 @@ pub(super) enum SignalEnum { byte_len_of_num_tmstmp_vals_on_tmln: Vec, byte_len_of_string_tmstmp_vals_on_tmln: Vec, lsb_indxs_of_string_tmstmp_vals_on_tmln: Vec, - scope_parent: ScopeIdx, }, Alias { name: String, + path: Vec, signal_alias: SignalIdx, }, } @@ -305,7 +313,7 @@ impl SignalEnum { match self { SignalEnum::Data {num_bits, ..} => num_bits.clone(), // TODO: Follow aliases? - SignalEnum::Alias { name, signal_alias } => None, + SignalEnum::Alias { .. } => None, } } } @@ -329,6 +337,7 @@ impl SignalEnum { Self::Alias { name: _, signal_alias, + path: _ } => { let SignalIdx(idx) = signal_alias; *idx @@ -443,6 +452,7 @@ impl SignalEnum { } Self::Alias { name: _, + path: _, signal_alias, } => { let SignalIdx(idx) = signal_alias; diff --git a/src/vcd/types.rs b/src/vcd/types.rs index d589e73..a53fb6c 100644 --- a/src/vcd/types.rs +++ b/src/vcd/types.rs @@ -40,7 +40,6 @@ pub struct SignalIdx(pub usize); pub(super) struct Scope { pub(super) name: String, - pub(super) parent_idx: Option, pub(super) self_idx: ScopeIdx, pub(super) child_signals: Vec, -- 2.47.1