diff --git a/src/ghw/common.rs b/src/ghw/common.rs index b66818d..6746f68 100644 --- a/src/ghw/common.rs +++ b/src/ghw/common.rs @@ -292,6 +292,8 @@ pub struct GhwVecInfo { max: GhwSignalId, min: GhwSignalId, two_state: bool, + /// pointer to an alias list + alias: Option, } impl GhwVecInfo { @@ -300,6 +302,7 @@ impl GhwVecInfo { min, max, two_state, + alias: None, } } pub fn bits(&self) -> u32 { @@ -314,6 +317,13 @@ impl GhwVecInfo { pub fn max(&self) -> GhwSignalId { self.max } + pub fn alias(&self) -> Option { + self.alias + } + + pub fn set_alias(&mut self, alias: NonZeroU32) { + self.alias = Some(alias); + } } /// Specifies the signal type info that is needed in order to read it. @@ -409,3 +419,17 @@ pub const STD_LOGIC_LUT: [u8; 9] = [5, 2, 0, 1, 3, 6, 7, 4, 8]; /// The order in which the two values appear in the BIT enum. pub const VHDL_BIT_VALUES: [u8; 2] = [b'0', b'1']; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_sizes() { + // We store 8-bytes per GHW signal to have the SignalRef mapping, type and vector info available. + // 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); + } +} diff --git a/src/ghw/hierarchy.rs b/src/ghw/hierarchy.rs index 936bbbe..c90eb91 100644 --- a/src/ghw/hierarchy.rs +++ b/src/ghw/hierarchy.rs @@ -916,21 +916,20 @@ struct GhwSignals { /// Used to define aliased signals in the `wellen` wavemem. #[derive(Debug, Clone, Copy)] struct AliasInfo { - max: u32, - min: u32, + msb: u32, + lsb: u32, + signal_ref: SignalRef, + next: Option, } impl GhwSignals { fn new(max_signal_id: u32) -> Self { let signals = vec![None; max_signal_id as usize]; - let signal_ref_count = 0; - let vectors = vec![]; - let aliases = vec![]; Self { signals, - signal_ref_count, - vectors, - aliases, + signal_ref_count: 0, + vectors: vec![], + aliases: vec![], } } @@ -964,6 +963,47 @@ impl GhwSignals { id } + fn find_or_add_alias(&mut self, vec_id: GhwVecId, msb: u32, lsb: u32) -> SignalRef { + // first we try to see if we can find an existing alias + if let Some(mut alias_id) = self.vectors[vec_id.index()].alias() { + loop { + let alias = self.aliases[alias_id.get() as usize - 1].clone(); + if alias.msb == msb && alias.lsb == lsb { + return alias.signal_ref; + } + match alias.next { + Some(next) => alias_id = next, + None => { + // create new entry + let signal_ref = self.new_signal_ref(); + let new_alias_id = self.aliases.len() + 1; + self.aliases.push(AliasInfo { + msb, + lsb, + signal_ref, + next: None, + }); + self.aliases[alias_id.get() as usize - 1].next = + Some(NonZeroU32::new(new_alias_id as u32).unwrap()); + return signal_ref; + } + } + } + } else { + // create entry + let signal_ref = self.new_signal_ref(); + let alias_id = self.aliases.len() + 1; + self.aliases.push(AliasInfo { + msb, + lsb, + signal_ref, + next: None, + }); + self.vectors[vec_id.index()].set_alias(NonZeroU32::new(alias_id as u32).unwrap()); + signal_ref + } + } + fn register_bit_vec( &mut self, min_id: GhwSignalId, @@ -974,16 +1014,18 @@ impl GhwSignals { debug_assert!(max >= min); // check to see if there is already a vector that this signal aliases with - let maybe_vector = self.find_vec(min, max).map(|i| &self.vectors[i.index()]); - if let Some(vector) = maybe_vector { + let maybe_vector_id = self.find_vec(min, max); + if let Some(vector_id) = maybe_vector_id { + let vector = &self.vectors[vector_id.index()]; let (prev_min, prev_max) = (vector.min().index(), vector.max().index()); if max == prev_max && min == prev_min { - // perfect alias - // just return the signal ref + // perfect alias -> just return the signal ref self.signals[min].unwrap().signal_ref() - } else if prev_min as usize <= min && prev_max as usize >= max { - todo!("sub signal alias!") - } else if prev_min as usize >= min && prev_max as usize <= max { + } else if prev_min <= min && prev_max >= max { + // this means that a larger vector already exists and our signal is a slice of this vector + let (msb, lsb) = (max - prev_min, min - prev_min); + self.find_or_add_alias(vector_id, msb as u32, lsb as u32) + } else if prev_min >= min && prev_max <= max { todo!("super signal alias!") } else { todo!("overlapped aliased vectors") diff --git a/src/ghw/signals.rs b/src/ghw/signals.rs index 18df023..7f7442a 100644 --- a/src/ghw/signals.rs +++ b/src/ghw/signals.rs @@ -133,7 +133,7 @@ fn read_cycle_signals( /// This dispatches any remaining vector changes. fn finish_time_step(vecs: &mut VecBuffer, enc: &mut Encoder) { vecs.process_changed_signals(|signal_ref, data, states| { - todo!("finish timestep with vec_id!"); + todo!("finish timestep with vec_id! {signal_ref:?}"); // enc.raw_value_change(signal_ref, data, states); }) } diff --git a/src/wavemem.rs b/src/wavemem.rs index 04ae639..5d21f9d 100644 --- a/src/wavemem.rs +++ b/src/wavemem.rs @@ -696,14 +696,16 @@ impl SignalEncoder { match self.tpe { SignalType::BitVector(len, _) => { let bits = len.get(); - debug_assert_eq!( - value.len(), - (bits as usize).div_ceil(states.bits_in_a_byte()) - ); if bits == 1 { + debug_assert_eq!(value.len(), 1); let write_value = ((time_idx_delta as u64) << 4) + value[0] as u64; leb128::write::unsigned(&mut self.data, write_value).unwrap(); } else { + // sometimes we might include some leading zeros that are not necessary + let required_bytes = (bits as usize).div_ceil(states.bits_in_a_byte()); + debug_assert!(value.len() >= required_bytes); + let value = &value[(value.len() - required_bytes)..]; + // we automatically compress the signal to its minimum states encoding let min_states = check_min_state(value, states); // write time and meta data