From a30b1b4ec2c91ae6fa8bfb6b466a0067bba26000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kevin=20L=C3=A4ufer?= Date: Tue, 5 Mar 2024 10:38:15 -0500 Subject: [PATCH] wip --- src/ghw/common.rs | 41 ++++--- src/ghw/hierarchy.rs | 275 ++++++++++++++++++++++++++++++------------- src/ghw/signals.rs | 95 ++++++--------- 3 files changed, 249 insertions(+), 162 deletions(-) diff --git a/src/ghw/common.rs b/src/ghw/common.rs index 67ce4bb..756c4fe 100644 --- a/src/ghw/common.rs +++ b/src/ghw/common.rs @@ -191,37 +191,44 @@ impl HeaderData { /// Contains information needed in order to decode value changes. #[derive(Debug, Default)] pub struct GhwDecodeInfo { - pub signals: Vec, + +} + +impl GhwDecodeInfo { + pub fn get_tpe_and_signal_ref(pos_id: usize) -> (SignalType, SignalRef) { + todo!() + } + + pub fn get_vec_id_and_start(pos_id: usize) -> (usize, u32) { + todo!() + } } -/// Holds information from the header needed in order to read the corresponding data in the signal section. -#[derive(Debug, Clone)] -pub struct GhwSignal { - /// Signal ID in the wavemem Encoder. - pub signal_ref: SignalRef, - pub tpe: SignalType, - // currently used for debugging - pub alias_entry: Option, + + +#[derive(Debug, Clone, Copy)] +pub struct GhwVecInfo { + max: NonZeroU32, + min: NonZeroU32, } /// Specifies the signal type info that is needed in order to read it. -#[derive(Debug, PartialEq, Copy, Clone)] +#[repr(u8)] +#[derive(Debug, PartialEq, Copy, Clone, TryFromPrimitive)] pub enum SignalType { /// Nine value signal encoded as a single byte. NineState, - /// A single bit in a 9 value bit vector. bit N / M bits. - NineStateBit(u32, u32), + /// A single bit in a 9 value bit vector. + NineStateVec, /// Two value signal encoded as a single byte. TwoState, /// A single bit in a 2 value bit vector. bit N / M bits. - TwoStateBit(u32, u32), + TwoStateVec, /// Binary signal encoded as a single byte with N valid bits. - U8(u32), + U8, /// Binary signal encoded as a variable number of bytes with N valid bits. - #[allow(dead_code)] - Leb128Signed(u32), + Leb128Signed, /// F64 (real) - #[allow(dead_code)] F64, } diff --git a/src/ghw/hierarchy.rs b/src/ghw/hierarchy.rs index 3bbcee8..d13bb6d 100644 --- a/src/ghw/hierarchy.rs +++ b/src/ghw/hierarchy.rs @@ -717,14 +717,14 @@ fn read_hierarchy_section( let _expected_num_scopes = header.read_u32(&mut &hdr[4..8])?; // 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])? as usize; + 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}"); let mut num_declared_vars = 0; - let mut signals: Vec> = Vec::with_capacity(max_signal_id + 1); - signals.resize(max_signal_id + 1, None); let mut signal_ref_count = 0; let mut index_string_cache = IndexCache::new(); - let mut aliases = AliasTable::default(); + let mut signal_info = GhwSignals::new(max_signal_id); loop { let kind = GhwHierarchyKind::try_from_primitive(read_u8(input)?)?; @@ -757,11 +757,10 @@ fn read_hierarchy_section( tables, input, kind, - &mut signals, + &mut signal_info, &mut signal_ref_count, &mut index_string_cache, h, - &mut aliases, )?; num_declared_vars += 1; if num_declared_vars > expected_num_declared_vars { @@ -777,7 +776,7 @@ fn read_hierarchy_section( } let decode = GhwDecodeInfo { - signals: signals.into_iter().flatten().collect::>(), + signals: vec![] }; Ok((decode, signal_ref_count)) @@ -869,11 +868,10 @@ fn read_hierarchy_var( tables: &mut GhwTables, input: &mut impl BufRead, kind: GhwHierarchyKind, - signals: &mut [Option], + signals: &mut GhwSignals, signal_ref_count: &mut usize, index_string_cache: &mut IndexCache, h: &mut HierarchyBuilder, - aliases: &mut AliasTable, ) -> Result<()> { let name_id = read_string_id(input)?; let name = tables.get_str(name_id); @@ -886,7 +884,6 @@ fn read_hierarchy_var( signal_ref_count, index_string_cache, h, - aliases, name, tpe, ) @@ -925,53 +922,180 @@ fn get_index_string( } } + +/// Collects information for every signal id in the GHW file. +/// We store the type information needed to decode the signal as well as +/// 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)] +pub(crate) struct GhwSignals { + signals: Vec>, + signal_ref_count: usize, + vectors: Vec, + aliases: Vec, +} + +/// Information needed to read a signal value. +#[derive(Debug, Clone, Copy)] +struct SignalInfo { + tpe_and_vec: NonZeroU32, + signal_ref: SignalRef, +} + +impl SignalInfo { + fn new(tpe: SignalType, signal_ref: SignalRef, vector: Option) -> Self { + let raw_tpe = ((tpe as u8) as u32) + 1; + debug_assert_eq!(raw_tpe & 0x7, raw_tpe); + let tpe_and_vec = if let Some(vector) = vector { + let raw_vector_id = (vector as u32) + 1; + debug_assert_eq!((raw_vector_id << 3) >> 3, raw_vector_id); + NonZeroU32::new((raw_vector_id << 3) | raw_tpe).unwrap() + } else { NonZeroU32::new(raw_tpe).unwrap() }; + Self { tpe_and_vec, signal_ref } + } + + fn signal_ref(&self) -> SignalRef { self.signal_ref } + + fn vec_id(&self) -> Option { + let vec_id = self.tpe_and_vec.get() >> 3; + if vec_id == 0 { + None + } else { + Some(vec_id as usize - 1) + } + } + + fn tpe(&self) -> SignalType { + let value = self.tpe_and_vec.get(); + let tpe = SignalType::try_from_primitive((value & 0x7) as u8).unwrap(); + tpe + } +} + + + + +/// Used to define aliased signals in the `wellen` wavemem. #[derive(Debug, Clone, Copy)] struct AliasInfo { - min: u32, max: u32, - name: HierarchyStringId, + min: u32, } +impl GhwSignals { -// tracking aliasing of BitVec and Bits -#[derive(Debug, Default)] -struct AliasTable { - info: Vec, -} + 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} + } -impl AliasTable { - fn check(&mut self, h: &HierarchyBuilder, prev: Option<&GhwSignal>, min: SignalId, max: SignalId, name: HierarchyStringId) -> NonZeroU32 { - let (min, max) = (min.0.get, max.0.get()) - if let Some(prev_signal) = prev { - let id = prev_signal.alias_entry.unwrap(); - debug_assert!(prev_signal.alias_entry.is_some(), "Expected an alias entry!"); - let entry = self.info[(id.get() - 1) as usize].clone(); + fn max_signal_id(&self) -> usize { self.signals.len() } - if entry.min == min && entry.max == max { - id + /// used for f64, i32, i64 and u8 + fn register_scalar(&mut self, index: SignalId, tpe: SignalType) -> SignalRef { + if let Some(prev) = &self.signals[index.0.get() as usize] { + debug_assert_eq!(prev.tpe(), tpe); + prev.signal_ref() + } else { + // create new id + let id = self.new_signal_ref(); + // we do not need to store any extra aliasing info + self.signals[index.0.get() as usize] = Some(SignalInfo::new(tpe, id, None)); + id + } + } + + fn new_signal_ref(&mut self) -> SignalRef { + let id = SignalRef::from_index(self.signal_ref_count).unwrap(); + self.signal_ref_count += 1; + id + } + + fn register_bit_vec(&mut self, min_id: SignalId, max_id: SignalId, is_binary: bool) -> SignalRef { + let (min, max) = (min_id.0.get() as usize, max_id.0.get() as usize); + 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]); + if let Some(vector) = maybe_vector { + let (prev_min, prev_max) = (vector.min as usize, vector.max as usize); + if max == prev_max && min == prev_min { // 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 { + todo!("super signal alias!") } else { - panic!("Incompatible aliasing between {} ({:?}..{:?}) and {} ({:?}..{:?})",h.get_str(entry.name), entry.min, entry.max, h.get_str(name), min, max) + todo!("overlapped aliased vectors") } } else { - // allocate new entry - let id = NonZeroU32::new(self.info.len() as u32 + 1).unwrap(); - self.info.push(AliasInfo { - min, max, name - }); - id + // no existing vector to alias with + if min == max { + // single bit with no aliased vector behaves essentially like a scalar + if is_binary { + self.register_scalar(min_id, SignalType::TwoState) + } else { + self.register_scalar(min_id, SignalType::NineState) + } + } else { + // for a vector we want to make sure that there are no bits that alias this vector + for ii in min..=max { + // this situation is very unlikely since assigning bit ids first would make it harder for GHDL + // to assign contiguous vec ids + assert!(self.signals[ii].is_none(), "TODO: deal with bit that aliases with vector"); + } + + // create a new vec entry + let vec_id = self.vectors.len(); + self.vectors.push(GhwVecInfo { + max: max as u32, + min: min as u32, + }); + let tpe = if is_binary { SignalType::TwoStateVec } else { SignalType::NineStateVec }; + let id = self.new_signal_ref(); + + // update all bits + for ii in min..=max { + self.signals[ii] = Some(SignalInfo::new(tpe, id, Some(vec_id))); + } + id + } + } + } + + + /// Searches for vector info in the specified range. + #[inline] + fn find_vec(&self, min: usize, max: usize) -> Option { + let mut res = None; + for ii in min..=max { + if let Some(info) = &self.signals[ii] { + let vec_id = info.vec_id(); + debug_assert!(res.is_none() || vec_id.is_none() || res == vec_id, "Signal spans several sub-vectors"); + res = vec_id; + // early returns in release mode + if !cfg!(debug_assertions) && res.is_some() { + return res; + } + } } + res } } + fn add_var( tables: &GhwTables, input: &mut impl BufRead, kind: GhwHierarchyKind, - signals: &mut [Option], + signals: &mut GhwSignals, signal_ref_count: &mut usize, index_string_cache: &mut IndexCache, h: &mut HierarchyBuilder, - aliases: &mut AliasTable, name: HierarchyStringId, type_id: TypeId, ) -> Result<()> { @@ -980,9 +1104,9 @@ fn add_var( match vhdl_tpe { VhdlType::Enum(_, literals, enum_id) => { let enum_type = tables.enums[*enum_id as usize]; - let index = read_signal_id(input, signals)?; - let signal_ref = get_signal_ref(signals, signal_ref_count, index); + let index = read_signal_id(input, signals.max_signal_id())?; let bits = get_enum_bits(&literals); + let signal_ref = signals.register_scalar(index, SignalType::U8); h.add_var( name, VarType::Enum, @@ -993,13 +1117,11 @@ fn add_var( Some(enum_type), Some(tpe_name), ); - // meta date for writing the signal later - let tpe = SignalType::U8(8); // TODO: try to find the actual number of bits used - signals[index.0.get() as usize] = Some(GhwSignal { signal_ref, tpe, alias_entry: None }) } VhdlType::NineValueBit(_) | VhdlType::Bit(_) => { - let index = read_signal_id(input, signals)?; - let signal_ref = get_signal_ref(signals, signal_ref_count, index); + let index = read_signal_id(input, signals.max_signal_id())?; + let is_binary = matches!(vhdl_tpe, VhdlType::Bit(_)); + let signal_ref = signals.register_bit_vec(index, index, is_binary); let var_type = match h.get_str(tpe_name).to_ascii_lowercase().as_str() { "std_ulogic" => VarType::StdULogic, "std_logic" => VarType::StdLogic, @@ -1016,20 +1138,13 @@ fn add_var( None, Some(tpe_name), ); - // meta date for writing the signal later - let tpe = match vhdl_tpe { - VhdlType::Bit(_) => SignalType::TwoState, - _ => SignalType::NineState, - }; - let alias_entry = Some(aliases.check(h, signals[index.0.get() as usize].as_ref(), index, index, name)); - signals[index.0.get() as usize] = Some(GhwSignal { signal_ref, tpe, alias_entry}) } VhdlType::I32(_, maybe_range) => { // TODO: we could use the range to deduce indices and tighter widths let _range = IntRange::from_i32_option(*maybe_range); let bits = 32; - let index = read_signal_id(input, signals)?; - let signal_ref = get_signal_ref(signals, signal_ref_count, index); + let index = read_signal_id(input, signals.max_signal_id())?; + let signal_ref = signals.register_scalar(index, SignalType::Leb128Signed); let var_type = VarType::Integer; h.add_var( name, @@ -1041,16 +1156,13 @@ fn add_var( None, Some(tpe_name), ); - // meta date for writing the signal later - let tpe = SignalType::Leb128Signed(bits); - signals[index.0.get() as usize] = Some(GhwSignal { signal_ref, tpe, alias_entry: None }) } VhdlType::F64(_, maybe_range) => { // TODO: we could use the range to deduce indices and tighter widths let _range = FloatRange::from_f64_option(*maybe_range); let bits = 64; - let index = read_signal_id(input, signals)?; - let signal_ref = get_signal_ref(signals, signal_ref_count, index); + let index = read_signal_id(input, signals.max_signal_id())?; + let signal_ref = signals.register_scalar(index, SignalType::F64); let var_type = VarType::Real; h.add_var( name, @@ -1062,12 +1174,7 @@ fn add_var( None, Some(tpe_name), ); - // meta date for writing the signal later - signals[index.0.get() as usize] = Some(GhwSignal { - signal_ref, - tpe: SignalType::F64, - alias_entry: None, - }) + } VhdlType::NineValueVec(_, range) | VhdlType::BitVec(_, range) => { let num_bits = range.len().abs() as u32; @@ -1075,14 +1182,29 @@ fn add_var( // TODO: how should we correctly deal with an empty vector? return Ok(()); } + let mut signal_ids = Vec::with_capacity(num_bits as usize); for _ in 0..num_bits { - signal_ids.push(read_signal_id(input, signals)?); + signal_ids.push(read_signal_id(input, signals.max_signal_id())?); } - for (prev, cur) in signal_ids.iter().take(signal_ids.len() -1).zip(signal_ids.iter().skip(1)) { - debug_assert_eq!(prev.0 .get()+ 1, cur.0.get(), "We expected signal ids increasing by exactly 1, not {prev:?} -> {cur:?}"); + + // check assumption that all IDs are continuous + for (prev, cur) in signal_ids + .iter() + .take(signal_ids.len() - 1) + .zip(signal_ids.iter().skip(1)) + { + debug_assert_eq!( + prev.0.get() + 1, + cur.0.get(), + "We expected signal ids increasing by exactly 1, not {prev:?} -> {cur:?}" + ); } - let signal_ref = get_signal_ref(signals, signal_ref_count, signal_ids[0]); + + let is_binary = matches!(vhdl_tpe, VhdlType::BitVec(_, _)); + let min = signal_ids.first().unwrap().clone(); + let max = signal_ids.last().unwrap().clone(); + let signal_ref = signals.register_bit_vec(min, max, is_binary); let var_type = match h.get_str(tpe_name).to_ascii_lowercase().as_str() { "std_ulogic_vector" => VarType::StdULogicVector, "std_logic_vector" => VarType::StdLogicVector, @@ -1099,19 +1221,6 @@ fn add_var( None, Some(tpe_name), ); - // meta date for writing the signal later - let is_bitvec = matches!(vhdl_tpe, VhdlType::BitVec(_, _)); - let min = signal_ids.first().unwrap().clone(); - let max = signal_ids.last().unwrap().clone(); - for (bit, index) in signal_ids.iter().rev().enumerate() { - let tpe = if is_bitvec { - SignalType::TwoStateBit(bit as u32, num_bits) - } else { - SignalType::NineStateBit(bit as u32, num_bits) - }; - let alias_entry = Some(aliases.check(h, signals[index.0.get() as usize].as_ref(), min, max, name)); - signals[index.0.get() as usize] = Some(GhwSignal { signal_ref, tpe, alias_entry }) - } } VhdlType::Record(_, fields) => { h.add_scope(name, None, ScopeType::VhdlRecord, None, None, false); @@ -1124,7 +1233,6 @@ fn add_var( signal_ref_count, index_string_cache, h, - aliases, tables.get_str(*field_name), *field_type, )?; @@ -1145,7 +1253,6 @@ fn add_var( signal_ref_count, index_string_cache, h, - aliases, name, *element_tpe, )?; @@ -1157,12 +1264,12 @@ fn add_var( Ok(()) } -fn read_signal_id(input: &mut impl BufRead, signals: &mut [Option]) -> Result { +fn read_signal_id(input: &mut impl BufRead, max_signal_id: usize) -> Result { let index = leb128::read::unsigned(input)? as usize; - if index >= signals.len() { + if index > max_signal_id { Err(GhwParseError::FailedToParseSection( "hierarchy", - format!("SignalId too large {index} > {}", signals.len()), + format!("SignalId too large {index} > {}", max_signal_id), )) } else { let id = SignalId(NonZeroU32::new(index as u32).unwrap()); diff --git a/src/ghw/signals.rs b/src/ghw/signals.rs index b63126a..b0eb091 100644 --- a/src/ghw/signals.rs +++ b/src/ghw/signals.rs @@ -6,6 +6,7 @@ use crate::ghw::common::*; use crate::wavemem::{Encoder, States}; use crate::{Hierarchy, SignalRef}; use std::io::BufRead; +use std::num::NonZeroU32; /// Reads the GHW signal values. `input` should be advanced until right after the end of hierarchy pub(crate) fn read_signals( @@ -139,94 +140,63 @@ fn finish_time_step(vecs: &mut VecBuffer, enc: &mut Encoder) { } fn read_signal_value( - signal: &GhwSignal, + info: &GhwDecodeInfo, + pos_id: usize, vecs: &mut VecBuffer, enc: &mut Encoder, input: &mut impl BufRead, ) -> Result<()> { - match signal.tpe { + let (tpe, signal_ref) = info.get_tpe_and_signal_ref(pos_id); + match tpe { SignalType::NineState => { let ghdl_value = read_u8(input)?; let value = [STD_LOGIC_LUT[ghdl_value as usize]]; - enc.raw_value_change(signal.signal_ref, &value, States::Nine); + enc.raw_value_change(signal_ref, &value, States::Nine); } SignalType::TwoState => { let value = [read_u8(input)?]; debug_assert!(value[0] <= 1); - enc.raw_value_change(signal.signal_ref, &value, States::Two); + enc.raw_value_change(signal_ref, &value, States::Two); } - SignalType::NineStateBit(bit, _) => { + SignalType::NineStateVec | SignalType::TwoStateVec => { let ghdl_value = read_u8(input)?; - let value = STD_LOGIC_LUT[ghdl_value as usize]; - - // check to see if we already had a change to this same bit in the current time step - if vecs.is_second_change(signal.signal_ref, bit, value) { - // immediately dispatch the change to properly reflect the delta cycle - let data = vecs.get_full_value_and_clear_changes(signal.signal_ref); - enc.raw_value_change(signal.signal_ref, data, States::Nine); - } - - // update value - vecs.update_value(signal.signal_ref, bit, value); - - // check to see if we need to report a change - if vecs.full_signal_has_changed(signal.signal_ref) { - let data = vecs.get_full_value_and_clear_changes(signal.signal_ref); - enc.raw_value_change(signal.signal_ref, data, States::Nine); - } - } - SignalType::TwoStateBit(bit, _) => { - let value = read_u8(input)?; - debug_assert!(value <= 1); + let (value, states) = if tpe == SignalType::NineStateVec { + (STD_LOGIC_LUT[ghdl_value as usize], States::Nine) + } else { + debug_assert!(ghdl_value <= 1); + (ghdl_value, States::Two) + }; // check to see if we already had a change to this same bit in the current time step - if vecs.is_second_change(signal.signal_ref, bit, value) { + if vecs.is_second_change(signal_ref, bit, value) { // immediately dispatch the change to properly reflect the delta cycle let data = vecs.get_full_value_and_clear_changes(signal.signal_ref); - enc.raw_value_change(signal.signal_ref, data, States::Two); + enc.raw_value_change(signal_ref, data, States::Nine); } // update value - vecs.update_value(signal.signal_ref, bit, value); + vecs.update_value(signal_ref, bit, value); // check to see if we need to report a change - if vecs.full_signal_has_changed(signal.signal_ref) { - let data = vecs.get_full_value_and_clear_changes(signal.signal_ref); - enc.raw_value_change(signal.signal_ref, data, States::Two); + if vecs.full_signal_has_changed(signal_ref) { + let data = vecs.get_full_value_and_clear_changes(signal_ref); + enc.raw_value_change(signal_ref, data, States::Nine); } } - SignalType::U8(bits) => { + SignalType::U8 => { let value = [read_u8(input)?]; - if bits < 8 { - debug_assert!(value[0] < (1u8 << bits)); - } - enc.raw_value_change(signal.signal_ref, &value, States::Two); + enc.raw_value_change(signal_ref, &value, States::Two); } - SignalType::Leb128Signed(bits) => { + SignalType::Leb128Signed => { let signed_value = leb128::read::signed(input)?; let value = signed_value as u64; - if bits < u64::BITS { - if signed_value >= 0 { - debug_assert!( - value < (1u64 << bits), - "{value} does not fit into 32 {bits}" - ); - } else { - let non_sign_mask = (1u64 << (bits - 1)) - 1; - let sign_bits = value & !non_sign_mask; - debug_assert_eq!(sign_bits, !non_sign_mask); - } - } - let num_bytes = bits.div_ceil(8) as usize; - let bytes = &value.to_be_bytes()[(8 - num_bytes)..]; - debug_assert_eq!(bytes.len(), num_bytes); - enc.raw_value_change(signal.signal_ref, bytes, States::Two); + let bytes = &value.to_be_bytes(); + enc.raw_value_change(signal_ref, bytes, States::Two); } - SignalType::F64 => { // we need to figure out the endianes here let value = read_f64_le(input)?; - enc.real_change(signal.signal_ref, value); + enc.real_change(signal_ref, value); } } Ok(()) @@ -235,7 +205,7 @@ fn read_signal_value( /// Keeps track of individual bits and combines them into a full bit vector. #[derive(Debug)] struct VecBuffer { - info: Vec>, + info: Vec, data: Vec, bit_change: Vec, change_list: Vec, @@ -244,6 +214,7 @@ struct VecBuffer { #[derive(Debug, Clone)] struct VecBufferInfo { + min_signal_id: NonZeroU32, /// start as byte index data_start: u32, /// start as byte index @@ -268,13 +239,15 @@ impl VecBufferInfo { } impl VecBuffer { - fn from_decode_info(decode_info: &GhwDecodeInfo, signal_ref_count: usize) -> Self { - let mut info = Vec::with_capacity(signal_ref_count); - info.resize(signal_ref_count, None); + fn from_vec_info(vectors: Vec) -> Self { + let mut info = Vec::with_capacity(vectors.len()); let mut data_start = 0; let mut bit_change_start = 0; - for signal in decode_info.signals.iter() { + for vector in vectors.into_iter() { + let bits = + + if info[signal.signal_ref.index()].is_none() { match signal.tpe { SignalType::NineStateBit(0, bits) | SignalType::TwoStateBit(0, bits) => {