Skip to content

Commit

Permalink
expand signal length to signal type
Browse files Browse the repository at this point in the history
  • Loading branch information
ekiwi committed Nov 10, 2023
1 parent 5055bc9 commit 790362d
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 67 deletions.
2 changes: 1 addition & 1 deletion src/fst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl<R: BufRead + Seek> FstWaveDatabase<R> {
}

impl<R: BufRead + Seek> SignalSource for FstWaveDatabase<R> {
fn load_signals(&mut self, ids: &[(SignalRef, SignalLength)]) -> Vec<Signal> {
fn load_signals(&mut self, ids: &[(SignalRef, SignalType)]) -> Vec<Signal> {
// create a FST filter
let fst_ids = ids
.iter()
Expand Down
81 changes: 44 additions & 37 deletions src/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,33 +192,27 @@ impl SignalRef {
}

#[derive(Debug, Clone, Copy)]
pub enum SignalLength {
Variable,
Fixed(NonZeroU32),
}

impl Default for SignalLength {
fn default() -> Self {
SignalLength::Variable
}
pub enum SignalType {
String,
Real,
BitVector(NonZeroU32, Option<VarIndex>),
}

impl SignalLength {
pub fn from_uint(len: u32) -> Self {
impl SignalType {
pub fn from_uint(len: u32, index: Option<VarIndex>) -> Self {
match NonZeroU32::new(len) {
None => SignalLength::Variable,
Some(value) => SignalLength::Fixed(value),
None => SignalType::String,
Some(value) => SignalType::BitVector(value, index),
}
}
}

#[derive(Debug, Clone)]
pub struct Var {
name: HierarchyStringId,
tpe: VarType,
var_tpe: VarType,
direction: VarDirection,
length: SignalLength,
index: Option<VarIndex>,
signal_tpe: SignalType,
signal_idx: SignalRef,
parent: Option<ScopeRef>,
next: Option<HierarchyItemId>,
Expand Down Expand Up @@ -247,35 +241,45 @@ impl Var {
}

pub fn var_type(&self) -> VarType {
self.tpe
self.var_tpe
}
pub fn direction(&self) -> VarDirection {
self.direction
}
pub fn index(&self) -> Option<VarIndex> {
self.index
match &self.signal_tpe {
SignalType::BitVector(_, index) => *index,
_ => None,
}
}
pub fn signal_idx(&self) -> SignalRef {
self.signal_idx
}
pub fn length(&self) -> SignalLength {
self.length
pub fn length(&self) -> Option<u32> {
match &self.signal_tpe {
SignalType::String => None,
SignalType::Real => None,
SignalType::BitVector(len, _) => Some(len.get()),
}
}
pub fn is_real(&self) -> bool {
todo!()
matches!(self.signal_tpe, SignalType::Real)
}
pub fn is_string(&self) -> bool {
todo!()
matches!(self.signal_tpe, SignalType::String)
}
pub fn is_bit_vector(&self) -> bool {
true
matches!(self.signal_tpe, SignalType::BitVector(_, _))
}
pub fn is_1bit(&self) -> bool {
match self.length {
SignalLength::Fixed(l) => l.get() == 1,
match self.length() {
Some(l) => l == 1,
_ => false,
}
}
pub(crate) fn signal_tpe(&self) -> SignalType {
self.signal_tpe
}
}

#[derive(Debug, Clone, Copy)]
Expand Down Expand Up @@ -508,9 +512,9 @@ impl Hierarchy {

/// Retrieves the length of a signal identified by its id by looking up a
/// variable that refers to the signal.
pub(crate) fn get_signal_length(&self, signal_idx: SignalRef) -> Option<SignalLength> {
pub(crate) fn get_signal_tpe(&self, signal_idx: SignalRef) -> Option<SignalType> {
let var_id = (*self.signal_idx_to_var.get(signal_idx.index())?)?;
Some(self.get(var_id).length)
Some(self.get(var_id).signal_tpe)
}
}

Expand Down Expand Up @@ -713,19 +717,19 @@ impl HierarchyBuilder {
self.handle_to_node[handle_idx] = Some(var_id);

// for strings, the length is always flexible
let length = match tpe {
VarType::String => SignalLength::Variable,
_ => SignalLength::from_uint(raw_length),
let signal_tpe = match tpe {
VarType::String => SignalType::String,
VarType::Real => SignalType::Real,
_ => SignalType::from_uint(raw_length, index),
};

// now we can build the node data structure and store it
let node = Var {
parent,
name: self.add_string(name),
tpe,
var_tpe: tpe,
direction,
length,
index,
signal_tpe,
signal_idx,
next: None,
};
Expand Down Expand Up @@ -780,20 +784,23 @@ mod tests {
// unfortunately this one is pretty big
assert_eq!(std::mem::size_of::<HierarchyItemId>(), 8);

// 4 byte length, 8 byte index + tag + padding
assert_eq!(std::mem::size_of::<SignalType>(), 16);

// Var
assert_eq!(
std::mem::size_of::<Var>(),
std::mem::size_of::<HierarchyStringId>() // name
+ 1 // tpe
+ 1 // direction
+ 4 // length
+ 8 // bit index
+ 16 // signal tpe
+ std::mem::size_of::<SignalRef>() // handle
+ std::mem::size_of::<ScopeRef>() // parent
+ std::mem::size_of::<HierarchyItemId>() // next
+ 4 // padding
);
// currently this all comes out to 32 bytes (~= 4x 64-bit pointers)
assert_eq!(std::mem::size_of::<Var>(), 32);
// currently this all comes out to 40 bytes (~= 5x 64-bit pointers)
assert_eq!(std::mem::size_of::<Var>(), 40);

// Scope
assert_eq!(
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub mod vcd;
mod wavemem;

pub use hierarchy::{
Hierarchy, HierarchyItem, Scope, ScopeRef, ScopeType, SignalLength, SignalRef, Timescale,
TimescaleUnit, Var, VarDirection, VarRef, VarType,
Hierarchy, HierarchyItem, Scope, ScopeRef, ScopeType, SignalRef, Timescale, TimescaleUnit, Var,
VarDirection, VarRef, VarType,
};
pub use signals::{SignalValue, Waveform};
6 changes: 3 additions & 3 deletions src/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// released under BSD 3-Clause License
// author: Kevin Laeufer <[email protected]>

use crate::hierarchy::{Hierarchy, SignalLength, SignalRef};
use crate::hierarchy::{Hierarchy, SignalRef, SignalType};
use std::collections::HashMap;
use std::fmt::{Debug, Display, Formatter};

Expand Down Expand Up @@ -206,7 +206,7 @@ impl Waveform {
pub fn load_signals(&mut self, ids: &[SignalRef]) {
let ids_with_len = ids
.iter()
.map(|i| (*i, self.hierarchy.get_signal_length(*i).unwrap()))
.map(|i| (*i, self.hierarchy.get_signal_tpe(*i).unwrap()))
.collect::<Vec<_>>();
let signals = self.source.load_signals(&ids_with_len);
// the signal source must always return the correct number of signals!
Expand Down Expand Up @@ -303,7 +303,7 @@ impl SignalChangeData {
pub(crate) trait SignalSource {
/// Loads new signals.
/// Many implementations take advantage of loading multiple signals at a time.
fn load_signals(&mut self, ids: &[(SignalRef, SignalLength)]) -> Vec<Signal>;
fn load_signals(&mut self, ids: &[(SignalRef, SignalType)]) -> Vec<Signal>;
/// Returns the global time table which stores the time at each value change.
fn get_time_table(&self) -> Vec<Time>;
}
Expand Down
47 changes: 28 additions & 19 deletions src/wavemem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// Fast and compact wave-form representation inspired by the FST on disk format.

use crate::hierarchy::{Hierarchy, SignalLength, SignalRef};
use crate::hierarchy::{Hierarchy, SignalRef, SignalType};
use crate::signals::{Signal, SignalEncoding, SignalSource, Time};
use crate::vcd::{u32_div_ceil, usize_div_ceil};
use bytesize::ByteSize;
Expand All @@ -17,7 +17,7 @@ pub struct Reader {
}

impl SignalSource for Reader {
fn load_signals(&mut self, ids: &[(SignalRef, SignalLength)]) -> Vec<Signal> {
fn load_signals(&mut self, ids: &[(SignalRef, SignalType)]) -> Vec<Signal> {
let mut signals = Vec::with_capacity(ids.len());
for (id, len) in ids.iter() {
let sig = self.load_signal(*id, *len);
Expand Down Expand Up @@ -119,14 +119,14 @@ impl Reader {
}
}

fn load_signal(&self, id: SignalRef, len: SignalLength) -> Signal {
fn load_signal(&self, id: SignalRef, tpe: SignalType) -> Signal {
let meta = self.collect_signal_meta_data(id);
let mut time_indices: Vec<u32> = Vec::new();
let mut data_bytes: Vec<u8> = Vec::new();
let mut strings: Vec<String> = Vec::new();
for (time_idx_offset, data_block, meta_data) in meta.blocks.into_iter() {
match len {
SignalLength::Variable => {
match tpe {
SignalType::String => {
let (mut new_strings, mut new_time_indices) = match meta_data.compression {
SignalCompression::Compressed(uncompressed_len) => {
let data = lz4_flex::decompress(data_block, uncompressed_len).unwrap();
Expand All @@ -139,7 +139,7 @@ impl Reader {
time_indices.append(&mut new_time_indices);
strings.append(&mut new_strings);
}
SignalLength::Fixed(signal_len) => {
SignalType::BitVector(signal_len, _) => {
let (mut new_data, mut new_time_indices) = match meta_data.compression {
SignalCompression::Compressed(uncompressed_len) => {
let data = lz4_flex::decompress(data_block, uncompressed_len).unwrap();
Expand All @@ -160,15 +160,18 @@ impl Reader {
time_indices.append(&mut new_time_indices);
data_bytes.append(&mut new_data);
}
SignalType::Real => {
todo!("Implement real!")
}
}
}

match len {
SignalLength::Variable => {
match tpe {
SignalType::String => {
assert!(data_bytes.is_empty());
Signal::new_var_len(id, time_indices, strings)
}
SignalLength::Fixed(len) => {
SignalType::BitVector(len, _) => {
assert!(strings.is_empty());
let (encoding, bytes_per_entry) = if meta.is_two_state {
(
Expand All @@ -183,6 +186,9 @@ impl Reader {
};
Signal::new_fixed_len(id, time_indices, encoding, bytes_per_entry, data_bytes)
}
SignalType::Real => {
todo!("Implement real!")
}
}
}
}
Expand Down Expand Up @@ -369,12 +375,12 @@ impl Encoder {
pub fn new(hierarchy: &Hierarchy) -> Self {
let mut signals = Vec::with_capacity(hierarchy.num_unique_signals());
for var in hierarchy.get_unique_signals_vars() {
let len = match var {
None => SignalLength::Variable, // we do not know!
Some(var) => var.length(),
let tpe = match var {
None => SignalType::String, // we do not know!
Some(var) => var.signal_tpe(),
};
let pos = signals.len();
signals.push(SignalEncoder::new(len, pos));
signals.push(SignalEncoder::new(tpe, pos));
}

Encoder {
Expand Down Expand Up @@ -541,18 +547,18 @@ impl SignalEncodingMetaData {
#[derive(Debug, Clone)]
struct SignalEncoder {
data: Vec<u8>,
len: SignalLength,
tpe: SignalType,
prev_time_idx: u16,
is_two_state: bool,
/// Same as the index of this encoder in a Vec<_>. Used for debugging purposes.
signal_idx: u32,
}

impl SignalEncoder {
fn new(len: SignalLength, pos: usize) -> Self {
fn new(tpe: SignalType, pos: usize) -> Self {
SignalEncoder {
data: Vec::default(),
len,
tpe,
prev_time_idx: 0,
is_two_state: true,
signal_idx: pos as u32,
Expand All @@ -568,8 +574,8 @@ const SKIP_COMPRESSION: bool = false;
impl SignalEncoder {
fn add_vcd_change(&mut self, time_index: u16, value: &[u8]) {
let time_idx_delta = time_index - self.prev_time_idx;
match self.len {
SignalLength::Fixed(len) => {
match self.tpe {
SignalType::BitVector(len, _) => {
if len.get() == 1 {
let digit = if value.len() == 1 { value[0] } else { value[1] };
self.is_two_state &=
Expand Down Expand Up @@ -622,7 +628,7 @@ impl SignalEncoder {
};
}
}
SignalLength::Variable => {
SignalType::String => {
assert!(
matches!(value[0], b's' | b'S'),
"expected a string, not {}",
Expand All @@ -633,6 +639,9 @@ impl SignalEncoder {
leb128::write::unsigned(&mut self.data, (value.len() - 1) as u64).unwrap();
self.data.extend_from_slice(&value[1..]);
}
SignalType::Real => {
todo!("Implement real!")
}
}
self.prev_time_idx = time_index;
}
Expand Down
17 changes: 12 additions & 5 deletions tests/diff_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@
// author: Kevin Laeufer <[email protected]>

use std::io::{BufRead, BufReader};
use waveform::{
Hierarchy, HierarchyItem, ScopeType, SignalLength, SignalRef, TimescaleUnit, VarType, Waveform,
};
use waveform::{Hierarchy, HierarchyItem, ScopeType, SignalRef, TimescaleUnit, VarType, Waveform};

fn run_diff_test(vcd_filename: &str, fst_filename: &str) {
{
Expand Down Expand Up @@ -127,8 +125,8 @@ fn diff_hierarchy_item(ref_item: &vcd::ScopeItem, our_item: HierarchyItem, our_h
waveform_var_type_to_string(our_var.var_type())
);
match our_var.length() {
SignalLength::Variable => {} // nothing to check
SignalLength::Fixed(size) => assert_eq!(ref_var.size, size.get()),
None => {} // nothing to check
Some(size) => assert_eq!(ref_var.size, size),
}
match ref_var.index {
None => assert!(our_var.index().is_none()),
Expand Down Expand Up @@ -355,6 +353,15 @@ fn diff_model_sim_cpu_design() {
);
}

#[test]
#[ignore] // TODO: add real support
fn diff_my_hdl_sigmoid_tb() {
run_diff_test(
"inputs/my-hdl/sigmoid_tb.vcd",
"inputs/my-hdl/sigmoid_tb.vcd.fst",
);
}

#[test]
fn diff_treadle_gcd() {
run_diff_test("inputs/treadle/GCD.vcd", "inputs/treadle/GCD.vcd.fst");
Expand Down

0 comments on commit 790362d

Please sign in to comment.