Skip to content

Commit

Permalink
parse var index
Browse files Browse the repository at this point in the history
  • Loading branch information
ekiwi committed Nov 9, 2023
1 parent 11023d1 commit 468b4be
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 19 deletions.
1 change: 1 addition & 0 deletions src/fst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ fn read_hierarchy<F: BufRead + Seek>(reader: &mut FstReader<F>) -> Hierarchy {
convert_var_tpe(tpe),
convert_var_direction(direction),
length,
None,
SignalRef::from_index(handle.get_index()).unwrap(),
);
}
Expand Down
18 changes: 16 additions & 2 deletions src/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ pub enum ScopeType {
pub enum VarType {
Wire,
Reg,
Parameter,
String,
Todo, // placeholder tpe
}
Expand All @@ -133,6 +134,12 @@ pub enum VarDirection {
Todo, // placeholder tpe
}

#[derive(Debug, Clone, Copy)]
pub struct VarIndex {
pub msb: i32,
pub lsb: i32,
}

/// Signal identifier in the waveform (VCD, FST, etc.) file.
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
pub struct SignalRef(NonZeroU32);
Expand Down Expand Up @@ -179,6 +186,7 @@ pub struct Var {
tpe: VarType,
direction: VarDirection,
length: SignalLength,
index: Option<VarIndex>,
signal_idx: SignalRef,
parent: Option<ScopeRef>,
next: Option<HierarchyItemId>,
Expand Down Expand Up @@ -212,6 +220,9 @@ impl Var {
pub fn direction(&self) -> VarDirection {
self.direction
}
pub fn index(&self) -> Option<VarIndex> {
self.index
}
pub fn signal_idx(&self) -> SignalRef {
self.signal_idx
}
Expand Down Expand Up @@ -651,6 +662,7 @@ impl HierarchyBuilder {
tpe: VarType,
direction: VarDirection,
raw_length: u32,
index: Option<VarIndex>,
signal_idx: SignalRef,
) {
let node_id = self.vars.len();
Expand Down Expand Up @@ -681,6 +693,7 @@ impl HierarchyBuilder {
tpe,
direction,
length,
index,
signal_idx,
next: None,
};
Expand Down Expand Up @@ -742,12 +755,13 @@ mod tests {
+ 1 // tpe
+ 1 // direction
+ 4 // length
+ 12 // bit index TODO: try to save some space here!
+ std::mem::size_of::<SignalRef>() // handle
+ std::mem::size_of::<ScopeRef>() // parent
+ std::mem::size_of::<HierarchyItemId>() // next
);
// currently this all comes out to 24 bytes (~= 3x 64-bit pointers)
assert_eq!(std::mem::size_of::<Var>(), 24);
// currently this all comes out to 36 bytes (~= 4x 64-bit pointers)
assert_eq!(std::mem::size_of::<Var>(), 36);

// Scope
assert_eq!(
Expand Down
31 changes: 30 additions & 1 deletion src/vcd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,10 @@ fn read_hierarchy(input: &mut (impl BufRead + Seek)) -> (usize, Hierarchy) {
convert_var_tpe(tpe),
VarDirection::Todo,
u32::from_str_radix(std::str::from_utf8(size).unwrap(), 10).unwrap(),
None,
SignalRef::from_index(id_to_int(id).unwrap() as usize).unwrap(),
),
HeaderCmd::VectorVar(tpe, size, id, name, _) => {
HeaderCmd::VectorVar(tpe, size, id, name, index) => {
let length = match u32::from_str_radix(std::str::from_utf8(size).unwrap(), 10) {
Ok(len) => len,
Err(_) => {
Expand All @@ -90,6 +91,7 @@ fn read_hierarchy(input: &mut (impl BufRead + Seek)) -> (usize, Hierarchy) {
convert_var_tpe(tpe),
VarDirection::Todo,
length,
parse_index(index),
SignalRef::from_index(id_to_int(id).unwrap() as usize).unwrap(),
);
}
Expand All @@ -115,6 +117,32 @@ fn read_hierarchy(input: &mut (impl BufRead + Seek)) -> (usize, Hierarchy) {
((end - start) as usize, hierarchy)
}

fn parse_index(index: &[u8]) -> Option<VarIndex> {
if index.len() < 3 {
return None;
}
assert_eq!(index[0], b'[');
assert_eq!(*index.last().unwrap(), b']');
let sep = index.iter().position(|b| *b == b':');
match sep {
None => {
let inner = &index[1..(index.len() - 1)];
let inner_str = std::str::from_utf8(inner).unwrap();
let bit = i32::from_str_radix(inner_str, 10).unwrap();
Some(VarIndex { msb: bit, lsb: bit })
}
Some(pos) => {
let msb_bytes = &index[1..pos];
let msb_str = std::str::from_utf8(msb_bytes).unwrap();
let msb = i32::from_str_radix(msb_str, 10).unwrap();
let lsb_bytes = &index[(pos + 1)..(index.len() - 1)];
let lsb_str = std::str::from_utf8(lsb_bytes).unwrap();
let lsb = i32::from_str_radix(lsb_str, 10).unwrap();
Some(VarIndex { msb, lsb })
}
}
}

fn convert_timescale_unit(name: &[u8]) -> TimescaleUnit {
match name {
b"fs" => TimescaleUnit::FemtoSeconds,
Expand All @@ -138,6 +166,7 @@ fn convert_var_tpe(tpe: &[u8]) -> VarType {
match tpe {
b"wire" => VarType::Wire,
b"reg" => VarType::Reg,
b"parameter" => VarType::Parameter,
b"string" => VarType::String,
_ => panic!("TODO: convert {}", String::from_utf8_lossy(tpe)),
}
Expand Down
29 changes: 14 additions & 15 deletions src/wavemem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -679,22 +679,21 @@ fn expand_special_vector_cases(value: &[u8], len: usize) -> Option<Vec<u8>> {
return None;
}

// sometimes an all z or all x vector is written with only a single digit
if value.len() == 1 && matches!(value[0], b'x' | b'X' | b'z' | b'Z') {
let mut repeated = Vec::with_capacity(len);
repeated.resize(len, value[0]);
return Some(repeated);
}

// check if we might want to zero extend the value
if matches!(value[0], b'1' | b'0') {
let mut zero_extended = Vec::with_capacity(len);
zero_extended.resize(len - value.len(), b'0');
zero_extended.extend_from_slice(value);
return Some(zero_extended);
// zero, x or z extend
match value[0] {
b'1' | b'0' => {
let mut zero_extended = Vec::with_capacity(len);
zero_extended.resize(len - value.len(), b'0');
zero_extended.extend_from_slice(value);
Some(zero_extended)
}
b'x' | b'X' | b'z' | b'Z' => {
let mut repeated = Vec::with_capacity(len);
repeated.resize(len, value[0]);
Some(repeated)
}
_ => None, // failed
}

None // failed
}

#[inline]
Expand Down
16 changes: 15 additions & 1 deletion tests/diff_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ fn waveform_var_type_to_string(tpe: VarType) -> &'static str {
match tpe {
VarType::Wire => "wire",
VarType::Reg => "reg",
VarType::Parameter => "parameter",
VarType::String => "string",
VarType::Todo => "todo",
}
Expand Down Expand Up @@ -113,7 +114,17 @@ fn diff_hierarchy_item(ref_item: &vcd::ScopeItem, our_item: HierarchyItem, our_h
SignalLength::Variable => {} // nothing to check
SignalLength::Fixed(size) => assert_eq!(ref_var.size, size.get()),
}
assert!(ref_var.index.is_none(), "TODO: expose index");
match ref_var.index {
None => assert!(our_var.index().is_none()),
Some(vcd::ReferenceIndex::BitSelect(bit)) => {
assert_eq!(our_var.index().unwrap().msb, bit);
assert_eq!(our_var.index().unwrap().lsb, bit);
}
Some(vcd::ReferenceIndex::Range(msb, lsb)) => {
assert_eq!(our_var.index().unwrap().msb, msb);
assert_eq!(our_var.index().unwrap().lsb, lsb);
}
}
}
(vcd::ScopeItem::Comment(_), _) => {} // we do not care about comments
(other_ref, our) => panic!(
Expand Down Expand Up @@ -163,9 +174,12 @@ fn diff_signals<R: BufRead>(ref_reader: &mut vcd::Parser<R>, our: &mut Waveform)
let suffix: String = our_value_str.chars().skip(prefix_len).collect();
assert_eq!(suffix, value.to_string());
let is_x_extended = suffix.chars().next().unwrap() == 'x';
let is_z_extended = suffix.chars().next().unwrap() == 'z';
for c in our_value_str.chars().take(prefix_len) {
if is_x_extended {
assert_eq!(c, 'x');
} else if is_z_extended {
assert_eq!(c, 'z');
} else {
assert_eq!(c, '0');
}
Expand Down

0 comments on commit 468b4be

Please sign in to comment.