diff --git a/examples/load_signals.rs b/examples/load_signals.rs index f51f4bf..bbc65a6 100644 --- a/examples/load_signals.rs +++ b/examples/load_signals.rs @@ -14,6 +14,11 @@ use wellen::*; struct Args { #[arg(value_name = "FSTFILE", index = 1)] filename: String, + #[arg( + long, + help = "only parse the file, but do not actually load the signals" + )] + skip_load: bool, } fn print_size_of_full_vs_reduced_names(hierarchy: &Hierarchy) { @@ -80,6 +85,10 @@ fn main() { ); print_size_of_full_vs_reduced_names(wave.hierarchy()); + if args.skip_load { + return; + } + // load every signal individually let mut signal_load_times = Vec::new(); let mut signal_sizes = Vec::new(); diff --git a/src/ghw/common.rs b/src/ghw/common.rs index 371a2ed..e51ea96 100644 --- a/src/ghw/common.rs +++ b/src/ghw/common.rs @@ -233,28 +233,22 @@ impl GhwSignalInfo { } } +pub type GhwDecodeInfo = (GhwSignals, Vec); + /// Contains information needed in order to decode value changes. #[derive(Debug, Default)] -pub struct GhwDecodeInfo { +pub struct GhwSignals { /// Type and signal reference info. Indexed by `GhwSignalId` signals: Vec, - /// Vector info. Indexed by `GhwVecId`. - vectors: Vec, } -impl GhwDecodeInfo { - pub fn new(signals: Vec, vectors: Vec) -> Self { - Self { signals, vectors } - } - pub fn is_empty(&self) -> bool { - self.signals.is_empty() +impl GhwSignals { + pub fn new(signals: Vec) -> Self { + Self { signals } } pub fn get_info(&self, signal_id: GhwSignalId) -> &GhwSignalInfo { &self.signals[signal_id.index()] } - pub fn vectors(&self) -> &[GhwVecInfo] { - &self.vectors - } pub fn signal_len(&self) -> usize { self.signals.len() } @@ -435,6 +429,6 @@ mod tests { // This is in comparison to ghwdump which stores at least two 8-bit pointers per signal. assert_eq!(std::mem::size_of::(), 8); - assert_eq!(std::mem::size_of::(), 16); + assert_eq!(std::mem::size_of::(), 20); } } diff --git a/src/ghw/hierarchy.rs b/src/ghw/hierarchy.rs index bdac196..11d8510 100644 --- a/src/ghw/hierarchy.rs +++ b/src/ghw/hierarchy.rs @@ -116,7 +116,7 @@ pub(crate) fn read_hierarchy( ) -> Result<(GhwDecodeInfo, Hierarchy)> { let mut tables = GhwTables::default(); let mut strings = Vec::new(); - let mut decode = GhwDecodeInfo::default(); + let mut decode: Option = None; let mut hb = HierarchyBuilder::new(FileFormat::Ghw); // GHW seems to always uses fs @@ -182,12 +182,12 @@ pub(crate) fn read_hierarchy( GHW_HIERARCHY_SECTION => { let dec = read_hierarchy_section(header, &mut tables, input, &mut hb)?; debug_assert!( - decode.is_empty(), + decode.is_none(), "unexpected second hierarchy section:\n{:?}\n{:?}", decode, dec ); - decode = dec; + decode = Some(dec); } GHW_END_OF_HEADER_SECTION => { break; // done @@ -200,7 +200,7 @@ pub(crate) fn read_hierarchy( } } let hierarchy = hb.finish(); - Ok((decode, hierarchy)) + Ok((decode.unwrap(), hierarchy)) } /// adds all enums to the hierarchy and @@ -716,12 +716,12 @@ fn read_hierarchy_section( // declared signals, may be composite let expected_num_declared_vars = header.read_u32(&mut &hdr[8..12])?; let max_signal_id = header.read_u32(&mut &hdr[12..16])?; - println!("Max signal id: {max_signal_id}"); - println!("expected_num_declared_vars {expected_num_declared_vars}"); + // println!("Max signal id: {max_signal_id}"); + // println!("expected_num_declared_vars {expected_num_declared_vars}"); let mut num_declared_vars = 0; let mut index_string_cache = IndexCache::new(); - let mut signal_info = GhwSignals::new(max_signal_id); + let mut signal_info = GhwSignalTracker::new(max_signal_id); loop { let kind = GhwHierarchyKind::try_from_primitive(read_u8(input)?)?; @@ -771,10 +771,10 @@ fn read_hierarchy_section( } } - println!("Wellen Signal Refs: {}", signal_info.signal_ref_count); + // println!("Wellen Signal Refs: {}", signal_info.signal_ref_count); let decode_info = signal_info.into_decode_info(); - println!("GHW Signals: {}", decode_info.signal_len()); - println!("Vectors: {}", decode_info.vectors().len()); + // println!("GHW Signals: {}", decode_info.0.signal_len()); + // println!("Vectors: {}", decode_info.1.len()); Ok(decode_info) } @@ -865,7 +865,7 @@ fn read_hierarchy_var( tables: &mut GhwTables, input: &mut impl BufRead, kind: GhwHierarchyKind, - signals: &mut GhwSignals, + signals: &mut GhwSignalTracker, index_string_cache: &mut IndexCache, h: &mut HierarchyBuilder, ) -> Result<()> { @@ -906,7 +906,7 @@ fn get_index_string( /// information that is needed in order to map the bit-wise signal encoding /// in a GHW to the bit-vector signal encoding used in our `wellen` wavemem. #[derive(Debug)] -struct GhwSignals { +struct GhwSignalTracker { signals: Vec>, signal_ref_count: usize, vectors: Vec, @@ -922,7 +922,7 @@ struct AliasInfo { next: Option, } -impl GhwSignals { +impl GhwSignalTracker { fn new(max_signal_id: u32) -> Self { let signals = vec![None; max_signal_id as usize]; Self { @@ -936,7 +936,7 @@ impl GhwSignals { fn into_decode_info(self) -> GhwDecodeInfo { let mut signals: Vec<_> = self.signals.into_iter().flatten().collect(); signals.shrink_to_fit(); - GhwDecodeInfo::new(signals, self.vectors) + (GhwSignals::new(signals), self.vectors) } fn max_signal_id(&self) -> usize { @@ -1096,7 +1096,7 @@ fn add_var( tables: &GhwTables, input: &mut impl BufRead, kind: GhwHierarchyKind, - signals: &mut GhwSignals, + signals: &mut GhwSignalTracker, index_string_cache: &mut IndexCache, h: &mut HierarchyBuilder, name: HierarchyStringId, diff --git a/src/ghw/mod.rs b/src/ghw/mod.rs index 19ba1f9..2cd922f 100644 --- a/src/ghw/mod.rs +++ b/src/ghw/mod.rs @@ -38,6 +38,6 @@ fn read_internal(input: &mut (impl BufRead + Seek)) -> std::result::Result Result> { + let (info, vectors) = decode_info; // TODO: multi-threading let mut encoder = Encoder::new(hierarchy); - let mut vecs = VecBuffer::from_vec_info(info.vectors()); + let mut vecs = VecBuffer::from_vec_info(vectors); // loop over signal sections loop { @@ -26,9 +27,9 @@ pub(crate) fn read_signals( // read_sm_hdr match &mark { GHW_SNAPSHOT_SECTION => { - read_snapshot_section(header, info, &mut vecs, &mut encoder, input)? + read_snapshot_section(header, &info, &mut vecs, &mut encoder, input)? } - GHW_CYCLE_SECTION => read_cycle_section(header, info, &mut vecs, &mut encoder, input)?, + GHW_CYCLE_SECTION => read_cycle_section(header, &info, &mut vecs, &mut encoder, input)?, GHW_DIRECTORY_SECTION => { // skip the directory by reading it let _ = read_directory(header, input)?; @@ -49,7 +50,7 @@ pub(crate) fn read_signals( fn read_snapshot_section( header: &HeaderData, - info: &GhwDecodeInfo, + info: &GhwSignals, vecs: &mut VecBuffer, enc: &mut Encoder, input: &mut impl BufRead, @@ -74,7 +75,7 @@ fn read_snapshot_section( fn read_cycle_section( header: &HeaderData, - info: &GhwDecodeInfo, + info: &GhwSignals, vecs: &mut VecBuffer, enc: &mut Encoder, input: &mut impl BufRead, @@ -106,7 +107,7 @@ fn read_cycle_section( } fn read_cycle_signals( - info: &GhwDecodeInfo, + info: &GhwSignals, vecs: &mut VecBuffer, enc: &mut Encoder, input: &mut impl BufRead, @@ -138,7 +139,7 @@ fn finish_time_step(vecs: &mut VecBuffer, enc: &mut Encoder) { } fn read_signal_value( - info: &GhwDecodeInfo, + info: &GhwSignals, signal_id: GhwSignalId, vecs: &mut VecBuffer, enc: &mut Encoder, @@ -167,18 +168,16 @@ fn read_signal_value( }; let vec_id = signal_info.vec_id().unwrap(); - let vec_info = &info.vectors()[vec_id.index()]; - let bit = (signal_id.index() - vec_info.min().index()) as u32; // check to see if we already had a change to this same bit in the current time step - if vecs.is_second_change(vec_id, bit, value) { + if vecs.is_second_change(vec_id, signal_id, value) { // immediately dispatch the change to properly reflect the delta cycle let data = vecs.get_full_value_and_clear_changes(vec_id); enc.raw_value_change(signal_ref, data, states); } // update value - vecs.update_value(vec_id, bit, value); + vecs.update_value(vec_id, signal_id, value); // check to see if we need to report a change if vecs.full_signal_has_changed(vec_id) { @@ -224,6 +223,7 @@ struct VecBufferInfo { bits: u32, states: States, signal_ref: SignalRef, + min_index: u32, } impl VecBufferInfo { @@ -242,28 +242,33 @@ impl VecBufferInfo { } impl VecBuffer { - fn from_vec_info(vectors: &[GhwVecInfo]) -> Self { - let mut info = Vec::with_capacity(vectors.len()); + fn from_vec_info(vectors: Vec) -> Self { let mut data_start = 0; let mut bit_change_start = 0; - for vector in vectors.iter() { - let bits = vector.bits(); - let states = if vector.is_two_state() { - States::Two - } else { - States::Nine - }; - info.push(VecBufferInfo { - data_start: data_start as u32, - bit_change_start: bit_change_start as u32, - bits, - states, - signal_ref: vector.signal_ref(), - }); - data_start += (bits as usize).div_ceil(states.bits_in_a_byte()); - bit_change_start += (bits as usize).div_ceil(8); - } + let mut info = vectors + .into_iter() + .map(|vector| { + let bits = vector.bits(); + let states = if vector.is_two_state() { + States::Two + } else { + States::Nine + }; + let info = VecBufferInfo { + data_start: data_start as u32, + bit_change_start: bit_change_start as u32, + bits, + states, + signal_ref: vector.signal_ref(), + min_index: vector.min().index() as u32, + }; + data_start += (bits as usize).div_ceil(states.bits_in_a_byte()); + bit_change_start += (bits as usize).div_ceil(8); + info + }) + .collect::>(); + info.shrink_to_fit(); let data = vec![0; data_start]; let bit_change = vec![0; bit_change_start]; @@ -292,14 +297,16 @@ impl VecBuffer { } #[inline] - fn is_second_change(&self, vector_id: GhwVecId, bit: u32, value: u8) -> bool { + fn is_second_change(&self, vector_id: GhwVecId, signal_id: GhwSignalId, value: u8) -> bool { let info = &self.info[vector_id.index()]; + let bit = signal_id.index() as u32 - info.min_index; self.has_bit_changed(info, bit) && self.get_value(info, bit) != value } #[inline] - fn update_value(&mut self, vector_id: GhwVecId, bit: u32, value: u8) { + fn update_value(&mut self, vector_id: GhwVecId, signal_id: GhwSignalId, value: u8) { let info = &self.info[vector_id.index()]; + let bit = signal_id.index() as u32 - info.min_index; let is_a_real_change = self.get_value(info, bit) != value; if is_a_real_change { Self::mark_bit_changed(&mut self.bit_change, info, bit); diff --git a/src/wavemem.rs b/src/wavemem.rs index 5d21f9d..6f8004c 100644 --- a/src/wavemem.rs +++ b/src/wavemem.rs @@ -944,7 +944,30 @@ fn check_min_state(value: &[u8], states: States) -> States { States::from_value(union) } +/// picks a specialized compress implementation fn compress(value: &[u8], in_states: States, out_states: States, bits: usize, out: &mut Vec) { + match (in_states, out_states) { + (States::Nine, States::Two) => { + compress_template(value, States::Nine, States::Two, bits, out) + } + (States::Four, States::Two) => { + compress_template(value, States::Four, States::Two, bits, out) + } + (States::Nine, States::Four) => { + compress_template(value, States::Nine, States::Four, bits, out) + } + _ => unreachable!("Cannot compress {in_states:?} => {out_states:?}"), + } +} + +#[inline] +fn compress_template( + value: &[u8], + in_states: States, + out_states: States, + bits: usize, + out: &mut Vec, +) { debug_assert!(in_states.bits_in_a_byte() < out_states.bits_in_a_byte()); let mut working_byte = 0u8; for bit in (0..bits).rev() {