Skip to content

Commit

Permalink
ghw: add alias info to hierarchy and start taking it into account in …
Browse files Browse the repository at this point in the history
…the wavemem
  • Loading branch information
ekiwi committed Mar 6, 2024
1 parent 6dbc73f commit c52bc24
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 25 deletions.
6 changes: 5 additions & 1 deletion src/fst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,14 @@ impl<R: BufRead + Seek> FstWaveDatabase<R> {
impl<R: BufRead + Seek> SignalSource for FstWaveDatabase<R> {
fn load_signals(
&mut self,
ids: &[(SignalRef, SignalType)],
ids: &[SignalRef],
types: &[SignalType],
_multi_threaded: bool,
) -> Vec<Signal> {
// create a FST filter
let fst_ids = ids
.iter()
.zip(types.iter())
.map(|(ii, _)| FstSignalHandle::from_index(ii.index()))
.collect::<Vec<_>>();
let filter = FstFilter::filter_signals(fst_ids);
Expand All @@ -60,10 +62,12 @@ impl<R: BufRead + Seek> SignalSource for FstWaveDatabase<R> {
// store signals
let mut signals = ids
.iter()
.zip(types.iter())
.map(|(id, tpe)| SignalWriter::new(*id, *tpe))
.collect::<Vec<_>>();
let idx_to_pos: HashMap<usize, usize> = HashMap::from_iter(
ids.iter()
.zip(types.iter())
.map(|(r, _)| r.index())
.enumerate()
.map(|(pos, idx)| (idx, pos)),
Expand Down
13 changes: 10 additions & 3 deletions src/ghw/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,10 @@ fn read_hierarchy_section(
}

// println!("Wellen Signal Refs: {}", signal_info.signal_ref_count);
let decode_info = signal_info.into_decode_info();
let (decode_info, aliases) = signal_info.into_decode_info();
for alias in aliases.into_iter() {
h.add_slice(alias.signal_ref, alias.msb, alias.lsb, alias.sliced_signal);
}
// println!("GHW Signals: {}", decode_info.0.signal_len());
// println!("Vectors: {}", decode_info.1.len());

Expand Down Expand Up @@ -919,6 +922,7 @@ struct AliasInfo {
msb: u32,
lsb: u32,
signal_ref: SignalRef,
sliced_signal: SignalRef,
next: Option<NonZeroU32>,
}

Expand All @@ -933,10 +937,10 @@ impl GhwSignalTracker {
}
}

fn into_decode_info(self) -> GhwDecodeInfo {
fn into_decode_info(self) -> (GhwDecodeInfo, Vec<AliasInfo>) {
let mut signals: Vec<_> = self.signals.into_iter().flatten().collect();
signals.shrink_to_fit();
(GhwSignals::new(signals), self.vectors)
((GhwSignals::new(signals), self.vectors), self.aliases)
}

fn max_signal_id(&self) -> usize {
Expand Down Expand Up @@ -965,6 +969,7 @@ impl GhwSignalTracker {

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
let sliced_signal = self.vectors[vec_id.index()].signal_ref();
if let Some(mut alias_id) = self.vectors[vec_id.index()].alias() {
loop {
let alias = self.aliases[alias_id.get() as usize - 1].clone();
Expand All @@ -981,6 +986,7 @@ impl GhwSignalTracker {
msb,
lsb,
signal_ref,
sliced_signal,
next: None,
});
self.aliases[alias_id.get() as usize - 1].next =
Expand All @@ -997,6 +1003,7 @@ impl GhwSignalTracker {
msb,
lsb,
signal_ref,
sliced_signal,
next: None,
});
self.vectors[vec_id.index()].set_alias(NonZeroU32::new(alias_id as u32).unwrap());
Expand Down
41 changes: 40 additions & 1 deletion src/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Space efficient format for a wavedump hierarchy.

use crate::FileFormat;
use std::collections::HashMap;
use std::num::{NonZeroU16, NonZeroU32, NonZeroU64};

#[derive(Debug, Clone, Copy, PartialEq)]
Expand Down Expand Up @@ -226,7 +227,7 @@ impl VarIndex {
}

/// Signal identifier in the waveform (VCD, FST, etc.) file.
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct SignalRef(NonZeroU32);

impl SignalRef {
Expand Down Expand Up @@ -274,6 +275,16 @@ pub struct Var {
next: Option<HierarchyItemId>,
}

/// Represents a slice of another signal identified by its `SignalRef`.
/// This is helpful for formats like GHW where some signals are directly defined as
/// slices of other signals and thus we only save the data of the larger signal.
#[derive(Debug, Copy, Clone)]
pub(crate) struct SignalSlice {
pub(crate) msb: u32,
pub(crate) lsb: u32,
pub(crate) sliced_signal: SignalRef,
}

const SCOPE_SEPARATOR: char = '.';

impl Var {
Expand Down Expand Up @@ -587,6 +598,7 @@ pub struct Hierarchy {
enums: Vec<EnumType>,
signal_idx_to_var: Vec<Option<VarRef>>,
meta: HierarchyMetaData,
slices: HashMap<SignalRef, SignalSlice>,
}

struct HierarchyMetaData {
Expand Down Expand Up @@ -724,6 +736,10 @@ impl Hierarchy {
let var_id = (*self.signal_idx_to_var.get(signal_idx.index())?)?;
Some(self.get(var_id).signal_tpe)
}

pub(crate) fn get_slice_info(&self, signal_idx: SignalRef) -> Option<SignalSlice> {
self.slices.get(&signal_idx).copied()
}
}

// private implementation
Expand Down Expand Up @@ -789,6 +805,7 @@ pub struct HierarchyBuilder {
enums: Vec<EnumType>,
handle_to_node: Vec<Option<VarRef>>,
meta: HierarchyMetaData,
slices: HashMap<SignalRef, SignalSlice>,
}

const EMPTY_STRING: HierarchyStringId = HierarchyStringId(unsafe { NonZeroU32::new_unchecked(1) });
Expand All @@ -811,6 +828,7 @@ impl HierarchyBuilder {
enums: Vec::default(),
handle_to_node: Vec::default(),
meta: HierarchyMetaData::new(file_type),
slices: HashMap::default(),
}
}
}
Expand All @@ -823,6 +841,7 @@ impl HierarchyBuilder {
self.source_locs.shrink_to_fit();
self.enums.shrink_to_fit();
self.handle_to_node.shrink_to_fit();
self.slices.shrink_to_fit();
Hierarchy {
vars: self.vars,
scopes: self.scopes,
Expand All @@ -832,6 +851,7 @@ impl HierarchyBuilder {
enums: self.enums,
signal_idx_to_var: self.handle_to_node,
meta: self.meta,
slices: self.slices,
}
}

Expand Down Expand Up @@ -1106,6 +1126,25 @@ impl HierarchyBuilder {
pub fn add_comment(&mut self, comment: String) {
self.meta.comments.push(comment);
}

pub(crate) fn add_slice(
&mut self,
signal_ref: SignalRef,
msb: u32,
lsb: u32,
sliced_signal: SignalRef,
) {
debug_assert!(msb >= lsb);
debug_assert!(!self.slices.contains_key(&signal_ref));
self.slices.insert(
signal_ref,
SignalSlice {
msb,
lsb,
sliced_signal,
},
);
}
}

/// finds the first not flattened parent scope
Expand Down
71 changes: 52 additions & 19 deletions src/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ impl<'a> Display for SignalValue<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match &self {
SignalValue::Binary(data, bits) => {
write!(f, "{}", n_state_to_bit_string(States::Two, data, *bits))
write!(f, "{}", two_state_to_bit_string(data, *bits))
}
SignalValue::FourValue(data, bits) => {
write!(f, "{}", n_state_to_bit_string(States::Four, data, *bits))
write!(f, "{}", four_state_to_bit_string(data, *bits))
}
SignalValue::NineValue(data, bits) => {
write!(f, "{}", n_state_to_bit_string(States::Nine, data, *bits))
write!(f, "{}", nine_state_to_bit_string(data, *bits))
}
SignalValue::String(value) => write!(f, "{}", value),
SignalValue::Real(value) => write!(f, "{}", value),
Expand All @@ -44,15 +44,9 @@ impl<'a> Display for SignalValue<'a> {
impl<'a> SignalValue<'a> {
pub fn to_bit_string(&self) -> Option<String> {
match &self {
SignalValue::Binary(data, bits) => {
Some(n_state_to_bit_string(States::Two, data, *bits))
}
SignalValue::FourValue(data, bits) => {
Some(n_state_to_bit_string(States::Four, data, *bits))
}
SignalValue::NineValue(data, bits) => {
Some(n_state_to_bit_string(States::Nine, data, *bits))
}
SignalValue::Binary(data, bits) => Some(two_state_to_bit_string(data, *bits)),
SignalValue::FourValue(data, bits) => Some(four_state_to_bit_string(data, *bits)),
SignalValue::NineValue(data, bits) => Some(nine_state_to_bit_string(data, *bits)),
other => panic!("Cannot convert {other:?} to bit string"),
}
}
Expand All @@ -62,6 +56,18 @@ const TWO_STATE_LOOKUP: [char; 2] = ['0', '1'];
const FOUR_STATE_LOOKUP: [char; 4] = ['0', '1', 'x', 'z'];
const NINE_STATE_LOOKUP: [char; 9] = ['0', '1', 'x', 'z', 'h', 'u', 'w', 'l', '-'];

fn two_state_to_bit_string(data: &[u8], bits: u32) -> String {
n_state_to_bit_string(States::Two, data, bits)
}

fn four_state_to_bit_string(data: &[u8], bits: u32) -> String {
n_state_to_bit_string(States::Four, data, bits)
}

fn nine_state_to_bit_string(data: &[u8], bits: u32) -> String {
n_state_to_bit_string(States::Nine, data, bits)
}

#[inline]
fn n_state_to_bit_string(states: States, data: &[u8], bits: u32) -> String {
let lookup = match states {
Expand Down Expand Up @@ -213,6 +219,13 @@ impl Signal {
}
}

impl Signal {
// /// Transforms a signal into a derived version.
// pub(crate) fn transform(&self, transform: ) -> Self {
//
// }
}

/// Provides file format independent access to a waveform file.
pub struct Waveform {
hierarchy: Hierarchy,
Expand Down Expand Up @@ -249,15 +262,34 @@ impl Waveform {
}

fn load_signals_internal(&mut self, ids: &[SignalRef], multi_threaded: bool) {
let ids_with_len = ids
// sort and dedup ids
let mut ids = Vec::from_iter(ids.iter().cloned());
ids.sort();
ids.dedup();

// replace any aliases by their source signal
let mut is_alias = vec![false; ids.len()];
for (ii, id) in ids.iter_mut().enumerate() {
if let Some(slice) = self.hierarchy.get_slice_info(*id) {
*id = slice.sliced_signal;
is_alias[ii] = true;
}
}

// collect meta data
let types: Vec<_> = ids
.iter()
.map(|i| (*i, self.hierarchy.get_signal_tpe(*i).unwrap()))
.collect::<Vec<_>>();
let signals = self.source.load_signals(&ids_with_len, multi_threaded);
.map(|i| self.hierarchy.get_signal_tpe(*i).unwrap())
.collect();
let signals = self.source.load_signals(&ids, &types, multi_threaded);
// the signal source must always return the correct number of signals!
assert_eq!(signals.len(), ids.len());
for (id, signal) in ids.iter().zip(signals.into_iter()) {
self.signals.insert(*id, signal);
for ((id, is_alias), signal) in ids.iter().zip(is_alias.iter()).zip(signals.into_iter()) {
if *is_alias {
todo!("deal with loading alias!")
} else {
self.signals.insert(*id, signal);
}
}
}

Expand Down Expand Up @@ -441,7 +473,8 @@ pub(crate) trait SignalSource {
/// Many implementations take advantage of loading multiple signals at a time.
fn load_signals(
&mut self,
ids: &[(SignalRef, SignalType)],
ids: &[SignalRef],
types: &[SignalType],
multi_threaded: bool,
) -> Vec<Signal>;
/// Returns the global time table which stores the time at each value change.
Expand Down
5 changes: 4 additions & 1 deletion src/wavemem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,18 @@ pub struct Reader {
impl SignalSource for Reader {
fn load_signals(
&mut self,
ids: &[(SignalRef, SignalType)],
ids: &[SignalRef],
types: &[SignalType],
multi_threaded: bool,
) -> Vec<Signal> {
if multi_threaded {
ids.par_iter()
.zip(types.par_iter())
.map(|(id, len)| self.load_signal(*id, *len))
.collect::<Vec<_>>()
} else {
ids.iter()
.zip(types.iter())
.map(|(id, len)| self.load_signal(*id, *len))
.collect::<Vec<_>>()
}
Expand Down

0 comments on commit c52bc24

Please sign in to comment.