diff --git a/Cargo.toml b/Cargo.toml index d176fd8..1a59b3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ [package] name = "wellen" -version = "0.8.1" +version = "0.8.2" edition = "2021" authors = ["Kevin Laeufer "] description = "Fast VCD and FST library for waveform viewers written in Rust." diff --git a/src/ghw/common.rs b/src/ghw/common.rs index b83bb2b..3003946 100644 --- a/src/ghw/common.rs +++ b/src/ghw/common.rs @@ -184,13 +184,6 @@ impl HeaderData { #[derive(Debug, Default)] pub struct GhwDecodeInfo { pub signals: Vec, - pub luts: Vec, -} - -impl GhwDecodeInfo { - pub fn decode(&self, value: u8, lut_id: NineValueLutId) -> u8 { - self.luts[lut_id.0 as usize][value as usize] - } } /// Holds information from the header needed in order to read the corresponding data in the signal section. @@ -201,18 +194,13 @@ pub struct GhwSignal { pub tpe: SignalType, } -#[derive(Debug, PartialEq, Copy, Clone)] -pub struct NineValueLutId(pub u8); - -pub type NineValueLut = [u8; 9]; - /// Specifies the signal type info that is needed in order to read it. #[derive(Debug, PartialEq, Copy, Clone)] pub enum SignalType { /// Nine value signal encoded as a single byte. - NineState(NineValueLutId), + NineState, /// A single bit in a nine value bit vector. bit N / M bits. - NineStateBit(NineValueLutId, u32, u32), + NineStateBit(u32, u32), /// Binary signal encoded as a single byte with N valid bits. U8(u32), /// Binary signal encoded as a variable number of bytes with N valid bits. @@ -288,3 +276,8 @@ pub enum GhwHierarchyKind { Buffer = 20, Linkage = 21, } + +/// The order in which the nine values appear in the STD_LOGIC enum. +pub const STD_LOGIC_VALUES: [u8; 9] = [b'u', b'x', b'0', b'1', b'z', b'w', b'l', b'h', b'-']; +/// Mapping from STD_LOGIC value to the `wellen` nine state encoding: ['0', '1', 'x', 'z', 'h', 'u', 'w', 'l', '-'] +pub const STD_LOGIC_LUT: [u8; 9] = [5, 2, 0, 1, 3, 6, 7, 4, 8]; diff --git a/src/ghw/hierarchy.rs b/src/ghw/hierarchy.rs index 7f03033..74a6f92 100644 --- a/src/ghw/hierarchy.rs +++ b/src/ghw/hierarchy.rs @@ -8,7 +8,6 @@ use crate::ghw::common::*; use crate::hierarchy::HierarchyBuilder; -use crate::wavemem::bit_char_to_num; use crate::{ FileFormat, Hierarchy, ScopeType, SignalRef, Timescale, TimescaleUnit, VarDirection, VarIndex, VarType, @@ -155,7 +154,7 @@ pub(crate) fn read_hierarchy( GhwWellKnownType::Bit => todo!("add bit"), GhwWellKnownType::StdULogic => { debug_assert!( - matches!(tpe, VhdlType::NineValueBit(_, _)), + matches!(tpe, VhdlType::NineValueBit(_)), "{tpe:?} not recognized a std_ulogic!" ); } @@ -355,9 +354,9 @@ fn read_type_section( #[derive(Debug)] enum VhdlType { /// std_logic or std_ulogic with lut to convert to the `wellen` 9-value representation. - NineValueBit(StringId, NineValueLutId), + NineValueBit(StringId), /// std_logic_vector or std_ulogic_vector with lut to convert to the `wellen` 9-value representation. - NineValueVec(StringId, NineValueLutId, IntRange), + NineValueVec(StringId, IntRange), /// Type alias that does not restrict the underlying type in any way. TypeAlias(StringId, TypeId), /// Integer type with possible upper and lower bounds. @@ -415,10 +414,10 @@ impl VhdlType { let element_tpe_id = lookup_concrete_type_id(types, element_tpe); let index_type = lookup_concrete_type(types, index); let index_range = index_type.int_range(); - if let (VhdlType::NineValueBit(_, lut), Some(range)) = + if let (VhdlType::NineValueBit(_), Some(range)) = (&types[element_tpe_id.index()], index_range) { - VhdlType::NineValueVec(name, lut.clone(), range) + VhdlType::NineValueVec(name, range) } else { VhdlType::Array(name, element_tpe_id, index_range) } @@ -437,12 +436,12 @@ impl VhdlType { lookup_concrete_type(types, *element_tpe) ) } - (VhdlType::NineValueVec(base_name, lut, base_range), Range::Int(int_range)) => { + (VhdlType::NineValueVec(base_name, base_range), Range::Int(int_range)) => { debug_assert!( int_range.is_subset_of(&base_range), "{int_range:?} {base_range:?}" ); - VhdlType::NineValueVec(pick_best_name(name, *base_name), lut.clone(), int_range) + VhdlType::NineValueVec(pick_best_name(name, *base_name), int_range) } other => todo!("Currently unsupported combination: {other:?}"), } @@ -462,7 +461,7 @@ impl VhdlType { todo!("actual sub enum!") } } - (VhdlType::NineValueBit(_, _), Range::Int(int_range)) => { + (VhdlType::NineValueBit(_), Range::Int(int_range)) => { let range = int_range.range(); if range.start == 0 && range.end == 9 { VhdlType::TypeAlias(name, base) @@ -484,8 +483,8 @@ impl VhdlType { fn name(&self) -> StringId { match self { - VhdlType::NineValueBit(name, _) => *name, - VhdlType::NineValueVec(name, _, _) => *name, + VhdlType::NineValueBit(name) => *name, + VhdlType::NineValueVec(name, _) => *name, VhdlType::TypeAlias(name, _) => *name, VhdlType::I32(name, _) => *name, VhdlType::I64(name, _) => *name, @@ -498,7 +497,7 @@ impl VhdlType { fn int_range(&self) -> Option { match self { - VhdlType::NineValueBit(_, _) => Some(IntRange(RangeDir::To, 0, 8)), + VhdlType::NineValueBit(_) => Some(IntRange(RangeDir::To, 0, 8)), VhdlType::I32(_, range) => *range, VhdlType::I64(_, range) => *range, VhdlType::Enum(_, lits) => Some(IntRange(RangeDir::To, 0, lits.len() as i64)), @@ -517,30 +516,20 @@ fn try_parse_nine_value_bit( return None; } - // try to build a translation table - let mut lut = [0u8; 9]; - let mut out_covered = [false; 9]; - - // map to the wellen 9-state lookup: ['0', '1', 'x', 'z', 'h', 'u', 'w', 'l', '-']; - for (ii, lit_id) in literals.iter().enumerate() { + // check to see if it matches the standard std_logic enum + for (lit_id, expected) in literals.iter().zip(STD_LOGIC_VALUES.iter()) { let lit = tables.get_str(*lit_id).as_bytes(); let cc = match lit.len() { 1 => lit[0], 3 => lit[1], // this is to account for GHDL encoding things as '0' (including the tick!) _ => return None, }; - if let Some(out) = bit_char_to_num(cc) { - if out_covered[out as usize] { - return None; // duplicate detected - } - out_covered[out as usize] = true; - lut[ii] = out; - } else { - return None; // invalid character + if !cc.eq_ignore_ascii_case(expected) { + return None; // encoding does not match } } - let lut_id = tables.get_lut_id(lut); - Some(VhdlType::NineValueBit(name, lut_id)) + + Some(VhdlType::NineValueBit(name)) } fn read_well_known_types_section( @@ -566,7 +555,6 @@ fn read_well_known_types_section( struct GhwTables { types: Vec, strings: Vec, - pub luts: Vec, } /// Returns a if it is a non-anonymous string, otherwise b. @@ -589,12 +577,6 @@ impl GhwTables { fn get_str(&self, string_id: StringId) -> &str { &self.strings[string_id.0] } - - fn get_lut_id(&mut self, lut: NineValueLut) -> NineValueLutId { - let id = NineValueLutId(self.luts.len() as u8); - self.luts.push(lut); - id - } } fn read_hierarchy_section( @@ -661,7 +643,6 @@ fn read_hierarchy_section( let decode = GhwDecodeInfo { signals: signals.into_iter().flatten().collect::>(), - luts: tables.luts.clone(), }; Ok((decode, signal_ref_count)) @@ -777,7 +758,7 @@ fn add_var( 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 }) } - VhdlType::NineValueBit(_, lut) => { + VhdlType::NineValueBit(_) => { let index = read_signal_id(input, signals)?; let signal_ref = get_signal_ref(signals, signal_ref_count, index); let var_type = match type_name.to_ascii_lowercase().as_str() { @@ -796,10 +777,10 @@ fn add_var( Some(tpe_name), ); // meta date for writing the signal later - let tpe = SignalType::NineState(*lut); + let tpe = SignalType::NineState; signals[index.0.get() as usize] = Some(GhwSignal { signal_ref, tpe }) } - VhdlType::NineValueVec(_, lut, range) => { + VhdlType::NineValueVec(_, range) => { let num_bits = range.len() as u32; let mut signal_ids = Vec::with_capacity(num_bits as usize); for _ in 0..num_bits { @@ -823,7 +804,7 @@ fn add_var( ); // meta date for writing the signal later for (bit, index) in signal_ids.iter().rev().enumerate() { - let tpe = SignalType::NineStateBit(*lut, bit as u32, num_bits); + let tpe = SignalType::NineStateBit(bit as u32, num_bits); signals[index.0.get() as usize] = Some(GhwSignal { signal_ref, tpe }) } } diff --git a/src/ghw/signals.rs b/src/ghw/signals.rs index ae768cf..13f789e 100644 --- a/src/ghw/signals.rs +++ b/src/ghw/signals.rs @@ -64,7 +64,7 @@ fn read_snapshot_section( enc.time_change(start_time); for sig in info.signals.iter() { - read_signal_value(info, sig, vecs, enc, input)?; + read_signal_value(sig, vecs, enc, input)?; } finish_time_step(vecs, enc); @@ -126,7 +126,7 @@ fn read_cycle_signals( )); } let sig = &info.signals[pos_signal_index - 1]; - read_signal_value(info, sig, vecs, enc, input)?; + read_signal_value(sig, vecs, enc, input)?; } Ok(()) } @@ -139,19 +139,20 @@ fn finish_time_step(vecs: &mut VecBuffer, enc: &mut Encoder) { } fn read_signal_value( - info: &GhwDecodeInfo, signal: &GhwSignal, vecs: &mut VecBuffer, enc: &mut Encoder, input: &mut impl BufRead, ) -> Result<()> { match signal.tpe { - SignalType::NineState(lut) => { - let value = [info.decode(read_u8(input)?, lut)]; + 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); } - SignalType::NineStateBit(lut, bit, _) => { - let value = info.decode(read_u8(input)?, lut); + SignalType::NineStateBit(bit, _) => { + 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) { @@ -237,7 +238,7 @@ impl VecBuffer { let mut offset = 0; for signal in decode_info.signals.iter() { - if let SignalType::NineStateBit(_, 0, bits) = signal.tpe { + if let SignalType::NineStateBit(0, bits) = signal.tpe { if info[signal.signal_ref.index()].is_none() { info[signal.signal_ref.index()] = Some(VecBufferInfo { offset, bits }); // pad offset to ensure that each value starts with its own byte