diff --git a/README.md b/README.md index 7d44f3e..c96e9a9 100644 --- a/README.md +++ b/README.md @@ -92,11 +92,8 @@ Here's a command to test on a malformed VCD: - [ ] once the access patterns of the GUI frontend are well understood, create specific functions and restrict as many types to private as possible - - [ ] be explicit with imports, remove exports as possible - once FastWave is known to be fairly stable. - [ ] Print out git commit or release number. - [ ] do a read through all the code - look for uneeded code - - [ ] Take a look at GTKWave parser to compare efficiency. - [ ] Move part of the performance section to another markdown file. ## Repairs @@ -108,7 +105,6 @@ Here's a command to test on a malformed VCD: able to successfully parse all sample VCDs. ## Code Consistency - - [ ] split impls in signal.rs into groups - [ ] Change error messages to line and filenames. Go through all calls to unwrap. - [ ] search for any unwraps or any direct vectors indexing - [ ] Handle TODOs diff --git a/examples/vcd.rs b/examples/vcd.rs index 2577410..d89d76a 100644 --- a/examples/vcd.rs +++ b/examples/vcd.rs @@ -4,7 +4,7 @@ // the root of the folder containing the sources for this program. use std::fs::File; -use fastwave_backend::{ScopeIdx, VCD, parse_vcd}; +use fastwave_backend::{ScopeIdx, VCD, parse_vcd, SignalIdx}; fn indented_print(indent : u8, name : &String) { for _ in 0..indent {print!(" |");} @@ -12,29 +12,26 @@ fn indented_print(indent : u8, name : &String) { println!("{name}"); } -fn print_root_scope_tree(root_idx: ScopeIdx, vcd: &VCD, indent : u8) { - if vcd.child_scopes_by_idx(root_idx).is_empty() { - } else { - for child_scope_idx in vcd.child_scopes_by_idx(root_idx) { - indented_print(indent, vcd.scope_name_by_idx(child_scope_idx)); - // for signal_idx in vcd.get_children_signal_idxs(child_scope_idx) { - // let signal = vcd.try_signal_idx_to_signal(signal_idx).unwrap(); - // match signal { - // Signal::Data {..} => {} - // Signal::Alias {..} => {} - // } - // // let to_print = format!("{},{}", signal.name(), ) - // } - // vcd.try_signal_idx_to_signal(idx) - print_root_scope_tree(child_scope_idx, vcd.clone(), indent + 1); +// TODO: refactor into more general visitor pattern that takes a +// function as an argument. +fn visit_all_scopes(vcd: &VCD) { + fn visit_all_scope_children(root_idx: ScopeIdx, vcd: &VCD, indent : u8) { + if vcd.child_scopes_by_idx(root_idx).is_empty() { + } else { + for child_scope_idx in vcd.child_scopes_by_idx(root_idx) { + indented_print(indent, vcd.scope_name_by_idx(child_scope_idx)); + for signal_idx in vcd.get_children_signal_idxs(child_scope_idx) { + let signal = vcd.signal_from_signal_idx(signal_idx); + let SignalIdx(idx) = signal_idx; + indented_print(indent + 1, &format!("{},{}", signal.name(), idx)); + } + visit_all_scope_children(child_scope_idx, vcd.clone(), indent + 1); + } } } -} - -fn ui_all_scopes(vcd: &VCD) { for root_scope_idx in vcd.root_scopes_by_idx() { indented_print(0, vcd.scope_name_by_idx(root_scope_idx)); - print_root_scope_tree(root_scope_idx, vcd, 1u8); + visit_all_scope_children(root_scope_idx, vcd, 1u8); } } @@ -42,6 +39,8 @@ fn main() -> std::io::Result<()> { use std::time::Instant; + // we start by printing out the entire signal tree of + // a parsed VCD let now = Instant::now(); let file_path = "tests/vcd-files/icarus/CPU.vcd"; let file = File::open(file_path)?; @@ -50,25 +49,36 @@ fn main() -> std::io::Result<()> { println!("Parsed VCD file {} : {:.2?}", file_path, elapsed); println!("Printing Scopes"); - ui_all_scopes(&vcd); + visit_all_scopes(&vcd); + println!("Done Printing Scopes"); + println!(); + // we then parse another VCD, print its signal tree and + // query some values on its timeline + let now = Instant::now(); let file_path = "tests/vcd-files/amaranth/up_counter.vcd"; let file = File::open(file_path)?; let vcd = parse_vcd(file).unwrap(); - // let state_signal = vcd.all_si - // for signal_idx in vcd.si - // let name = state_signal.name(); - // let time = BigUint::from(57760000u32); - // let val = state_signal - // .query_string_val_on_tmln( - // &time, - // &vcd.tmstmps_encoded_as_u8s, - // &vcd.all_signals, - // ) - // .unwrap(); - // println!("Signal `{name}` has value `{val}` at time `{time}`"); + let elapsed = now.elapsed(); + println!("Parsed VCD file {} : {:.2?}", file_path, elapsed); + println!("Printing Scopes"); + visit_all_scopes(&vcd); + println!("Done Printing Scopes"); + + let state_signal = vcd.signal_from_signal_idx(SignalIdx(4)); + let name = state_signal.name(); + + let timestamps = vec![31499_000u32, 31500_000u32, 57760_000u32]; + for timestamp in timestamps { + let time = num::BigUint::from(timestamp); + let val = state_signal + .query_string_val_on_tmln(&time, &vcd) + .unwrap(); + println!("Signal `{name}` has value `{val}` at time `{time}`"); + + } Ok(()) } diff --git a/src/vcd/signal.rs b/src/vcd/signal.rs index fb15c5a..1688f92 100644 --- a/src/vcd/signal.rs +++ b/src/vcd/signal.rs @@ -39,20 +39,18 @@ impl<'a> Signal<'a> { pub fn query_string_val_on_tmln( &self, desired_time: &BigUint, - tmstmps_encoded_as_u8s: &Vec, vcd: &types::VCD, ) -> Result { let Signal(signal_enum) = &self; - signal_enum.query_string_val_on_tmln(desired_time, tmstmps_encoded_as_u8s, &vcd.all_signals) + signal_enum.query_string_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals) } pub fn query_num_val_on_tmln( &self, desired_time: &BigUint, - tmstmps_encoded_as_u8s: &Vec, vcd: &types::VCD, ) -> Result { let Signal(signal_enum) = &self; - signal_enum.query_num_val_on_tmln(desired_time, tmstmps_encoded_as_u8s, &vcd.all_signals) + signal_enum.query_num_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals) } } diff --git a/src/vcd/types.rs b/src/vcd/types.rs index 60be9bc..27b682b 100644 --- a/src/vcd/types.rs +++ b/src/vcd/types.rs @@ -33,7 +33,7 @@ pub struct Metadata { pub struct ScopeIdx(pub usize); #[derive(Debug, Copy, Clone, PartialEq)] -pub struct SignalIdx(pub(super) usize); +pub struct SignalIdx(pub usize); #[derive(Debug)] pub(super) struct Scope { @@ -84,6 +84,11 @@ impl VCD { let scope = &self.all_scopes[idx]; &scope.name } + pub fn signal_from_signal_idx<'a>(&'a self, idx: SignalIdx) -> Signal<'a> { + let SignalIdx(idx) = idx; + let signal_enum = &self.all_signals[idx]; + return Signal(signal_enum); + } /// We take in a Signal and attempt to de-alias that signal if it is of /// variant ``Signal::Alias``. If it is of variant ``Signal::Alias`` and points to /// another alias, that's an error. Otherwise, we return the ``Signal::Data`` @@ -116,42 +121,4 @@ impl VCD { )), } } - pub fn get_signal<'a>(&'a self, idx: SignalIdx) -> Signal<'a> { - let SignalIdx(idx) = idx; - let signal_enum = &self.all_signals[idx]; - return Signal(signal_enum); - } - // Takes a signal_idx as input and returns the corresponding signal if the - // corresponding signal is of the Signal::Data variant, else the function the - // SignalIdx in the signal_alias field of Signal::Alias variant to index - // into the signal arena in the all_signals field of the vcd, and returns - // the resulting signal if that signal is a Signal::Data variant, else, - // this function returns an Err. - // pub fn try_signal_idx_to_signal<'a>( - // &'a self, - // idx: SignalIdx, - // ) -> Result<&'a Signal, String> { - // // get the signal pointed to be SignalIdx from the arena - // let SignalIdx(idx) = idx; - // let signal = &self.all_signals[idx]; - - // // dereference signal if Signal::Alias, or keep idx if Signal::Data - // let signal_idx = match signal { - // Signal::Data { self_idx, .. } => *self_idx, - // Signal::Alias { name, signal_alias } => *signal_alias, - // }; - - // // Should now point to Signal::Data variant, or else there's an error - // let SignalIdx(idx) = signal_idx; - // let signal = self.all_signals.get(idx).unwrap(); - // match signal { - // Signal::Data { .. } => Ok(signal), - // Signal::Alias { .. } => Err(format!( - // "Error near {}:{}. A signal alias shouldn't \ - // point to a signal alias.", - // file!(), - // line!() - // )), - // } - // } }