non trivial re-factor

This commit is contained in:
Yehowshua Immanuel 2022-08-19 20:13:46 -04:00
parent cbd8be1708
commit 15a2564f13
8 changed files with 668 additions and 528 deletions

View file

@ -7,5 +7,8 @@ pub(super) use types::*;
mod parse;
pub(super) use parse::*;
mod signal;
pub(super) use signal::*;
mod utilities;
use utilities::*;

View file

@ -31,11 +31,10 @@ pub fn parse_vcd(file: File) -> Result<VCD, String> {
// after we parse metadata, we form the VCD object
let mut vcd = VCD {
metadata: header,
timeline: vec![],
timeline_markers: vec![],
tmstmps_encoded_as_u8s: vec![],
all_signals: vec![],
all_scopes: vec![],
scope_roots: vec![],
root_scopes: vec![],
};
parse_scopes(&mut word_gen, &mut vcd, &mut signal_map)?;

View file

@ -5,6 +5,8 @@ pub(super) fn parse_events<'a>(
vcd: &'a mut VCD,
signal_map: &mut HashMap<String, SignalIdx>,
) -> Result<(), String> {
let mut curr_tmstmp_lsb_idx = 0u32;
let mut curr_tmstmp_len_u8 = 0u8;
loop {
let next_word = word_reader.next_word();
@ -36,18 +38,36 @@ pub(super) fn parse_events<'a>(
let mut value = value.to_bytes_le();
// TODO : u32 helps with less memory, but should ideally likely be
// configurable.
let (f, l) = (file!(), line!());
let start_idx = u32::try_from(vcd.timeline.len()).map_err(|_| {
format!("Error near {f}:{l}. Failed to convert from usize to u32.")
curr_tmstmp_len_u8 = u8::try_from(value.len()).map_err(|_| {
format!(
"Error near {}:{}. Failed to convert from usize to u8.",
file!(),
line!()
)
})?;
vcd.timeline_markers.push(StartIdx(start_idx));
vcd.timeline.append(&mut value);
vcd.tmstmps_encoded_as_u8s.append(&mut value);
curr_tmstmp_lsb_idx =
u32::try_from(vcd.tmstmps_encoded_as_u8s.len()).map_err(|_| {
format!(
"Error near {}:{}. Failed to convert from usize to u8.",
file!(),
line!()
)
})?;
// curr_tmstmp_lsb_idx = vcd.tmstmps_encoded_as_u8s.len();
}
// handle the case of an n bit signal whose value must be parsed
"b" => {
let binary_value = &word[1..];
let observed_num_bits = binary_value.len();
let observed_num_bits = u16::try_from(binary_value.len()).map_err(|_| {
format!(
"Error near {}:{}, {cursor:?}. \
Found signal with more than 2^16 - 1 bits.",
file!(),
line!()
)
})?;
let mut value_u8: Vec<u8> = Vec::new();
let mut value_string = String::new();
@ -81,7 +101,7 @@ pub(super) fn parse_events<'a>(
let (word, cursor) = next_word!(word_reader)?;
// lookup signal idx
let SignalIdx(ref signal_idx) = signal_map.get(word).ok_or(()).map_err(|_| {
let signal_idx = signal_map.get(word).ok_or(()).map_err(|_| {
format!(
"Error near {}:{}. Failed to lookup signal {word} at {cursor:?}",
file!(),
@ -89,34 +109,29 @@ pub(super) fn parse_events<'a>(
)
})?;
// account for fact that signal idx could be an alias, so there
// could be one step of indirection
let signal_idx = {
let signal = vcd.all_signals.get(*signal_idx).unwrap();
match signal {
Signal::Data { .. } => *signal_idx,
Signal::Alias { signal_alias, .. } => {
let SignalIdx(ref signal_idx) = signal_alias;
signal_idx.clone()
}
}
};
let signal = vcd.try_dereference_alias_mut(signal_idx)?;
// we may have to dereference a signal if it's pointing at an alias
// let signal = &vcd.all_signals[*signal_idx];
// let signal = signal.try_dereference_alias_mut(&vcd.all_signals)?;
// after handling potential indirection, go ahead and update the timeline
// of the signal signal_idx references
let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
match signal {
Signal::Data {
name,
sig_type,
ref mut signal_error,
num_bits,
u8_timeline,
u8_timeline_markers,
string_timeline,
string_timeline_markers,
..
self_idx,
nums_encoded_as_fixed_width_le_u8,
string_vals,
lsb_indxs_of_num_tmstmp_vals_on_tmln,
byte_len_of_num_tmstmp_vals_on_tmln,
lsb_indxs_of_string_tmstmp_vals_on_tmln,
byte_len_of_string_tmstmp_vals_on_tmln,
scope_parent,
} => {
// we've already identified in a prior loop iteration that the signal has
// an error
if signal_error.is_some() {
continue;
}
@ -152,29 +167,31 @@ pub(super) fn parse_events<'a>(
}
};
let (f, l) = (file!(), line!());
let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| {
format!("Error near {f}:{l}. Failed to convert from usize to u32.")
})?;
let timeline_idx = TimelineIdx(timeline_idx);
if store_as_string {
string_timeline_markers.push(timeline_idx);
string_timeline.push(value_string);
lsb_indxs_of_string_tmstmp_vals_on_tmln
.push(LsbIdxOfTmstmpValOnTmln(curr_tmstmp_lsb_idx));
string_vals.push(value_string);
Ok(())
} else {
u8_timeline_markers.push(timeline_idx);
let mut curr_num_bytes = value_u8.len();
u8_timeline.append(&mut value_u8);
let mut curr_num_bytes =
u8::try_from(value_u8.len()).map_err(|_| {
format!(
"Error near {}:{}. \
Found signal {name} with with value change of greater \
than 2^16 - 1 bits on {cursor:?}.",
file!(),
line!()
)
})?;
lsb_indxs_of_num_tmstmp_vals_on_tmln
.push(LsbIdxOfTmstmpValOnTmln(curr_tmstmp_lsb_idx));
byte_len_of_num_tmstmp_vals_on_tmln.push(curr_num_bytes);
// we may need to zero extend values
// so that we end up storing all values
// of a particular signal in a consistent
// amount of bytes
let num_bits = num_bits.unwrap();
let bytes_required =
(num_bits / 8) + if (num_bits % 8) > 0 { 1 } else { 0 };
let bytes_required = signal.bytes_required()?;
while curr_num_bytes < bytes_required {
// TODO: remove once library is known to be stable
@ -187,7 +204,7 @@ pub(super) fn parse_events<'a>(
// for signal {name}");
// Err(err)?;
u8_timeline.push(0u8);
byte_len_of_num_tmstmp_vals_on_tmln.push(0u8);
curr_num_bytes += 1;
}
Ok(())
@ -204,286 +221,288 @@ pub(super) fn parse_events<'a>(
}
// handle the case of a one bit signal whose value is set to `0`
"0" => {
// lookup signal idx
let hash = &word[1..];
let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
format!(
"Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
file!(),
line!()
)
})?;
// "0" => {
// // lookup signal idx
// let hash = &word[1..];
// let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
// format!(
// "Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
// file!(),
// line!()
// )
// })?;
// account for fact that signal idx could be an alias, so there
// could be one step of indirection
let signal_idx = {
let signal = vcd.all_signals.get(*signal_idx).unwrap();
match signal {
Signal::Data { .. } => *signal_idx,
Signal::Alias { signal_alias, .. } => {
let SignalIdx(ref signal_idx) = signal_alias;
signal_idx.clone()
}
}
};
// // account for fact that signal idx could be an alias, so there
// // could be one step of indirection
// let signal_idx = {
// let signal = vcd.all_signals.get(*signal_idx).unwrap();
// match signal {
// Signal::Data { .. } => *signal_idx,
// Signal::Alias { signal_alias, .. } => {
// let SignalIdx(ref signal_idx) = signal_alias;
// signal_idx.clone()
// }
// }
// };
// after handling potential indirection, go ahead and update the timeline
// of the signal signal_idx references
let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
match signal {
Signal::Data {
name,
sig_type,
ref mut signal_error,
num_bits,
u8_timeline,
u8_timeline_markers,
..
} => {
// if this is a bad signal, go ahead and skip it
if signal_error.is_some() {
continue;
}
// // after handling potential indirection, go ahead and update the timeline
// // of the signal signal_idx references
// let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
// match signal {
// Signal::Data {
// name,
// sig_type,
// ref mut signal_error,
// num_bits,
// u8_timeline,
// u8_timeline_markers,
// ..
// } => {
// // if this is a bad signal, go ahead and skip it
// if signal_error.is_some() {
// continue;
// }
// Get bitwidth and verify that it is 1.
// Also account for the error case of a bitwidth of `None`
match num_bits {
Some(ref num_bits) => {
if *num_bits != 1 {
let (f, l) = (file!(), line!());
let msg = format!(
"\
Error near {f}:{l}. The bitwidth for signal {name} \
of sig_type {sig_type:?} is expected to be `1` not \
`{num_bits}`. \
This error occurred while parsing the vcd file at \
{cursor:?}"
);
*signal_error = Some(msg);
continue;
}
}
None => {
let (f, l) = (file!(), line!());
let msg = format!(
"\
Error near {f}:{l}. The bitwidth for signal {name} \
must be specified for a signal of type {sig_type:?}. \
This error occurred while parsing the vcd file at \
{cursor:?}"
);
Err(msg)?;
}
};
// // Get bitwidth and verify that it is 1.
// // Also account for the error case of a bitwidth of `None`
// match num_bits {
// Some(ref num_bits) => {
// if *num_bits != 1 {
// let (f, l) = (file!(), line!());
// let msg = format!(
// "\
// Error near {f}:{l}. The bitwidth for signal {name} \
// of sig_type {sig_type:?} is expected to be `1` not \
// `{num_bits}`. \
// This error occurred while parsing the vcd file at \
// {cursor:?}"
// );
// *signal_error = Some(msg);
// continue;
// }
// }
// None => {
// let (f, l) = (file!(), line!());
// let msg = format!(
// "\
// Error near {f}:{l}. The bitwidth for signal {name} \
// must be specified for a signal of type {sig_type:?}. \
// This error occurred while parsing the vcd file at \
// {cursor:?}"
// );
// Err(msg)?;
// }
// };
let (f, l) = (file!(), line!());
let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| {
format!("Error near {f}:{l}. Failed to convert from usize to u32.")
})?;
let timeline_idx = TimelineIdx(timeline_idx);
// let (f, l) = (file!(), line!());
// let timeline_idx = u32::try_from(vcd.tmstmps_encoded_as_u8s.len())
// .map_err(|_| {
// format!("Error near {f}:{l}. Failed to convert from usize to u32.")
// })?;
// let timeline_idx = TimelineIdx(timeline_idx);
u8_timeline_markers.push(timeline_idx);
u8_timeline.push(0u8);
Ok(())
}
Signal::Alias { .. } => {
let (f, l) = (file!(), line!());
let msg = format!(
"Error near {f}:{l}, a signal alias should not point to a signal alias.\n\
This error occurred while parsing vcd file at {cursor:?}");
Err(msg)
}
}?;
}
// u8_timeline_markers.push(timeline_idx);
// u8_timeline.push(0u8);
// Ok(())
// }
// Signal::Alias { .. } => {
// let (f, l) = (file!(), line!());
// let msg = format!(
// "Error near {f}:{l}, a signal alias should not point to a signal alias.\n\
// This error occurred while parsing vcd file at {cursor:?}");
// Err(msg)
// }
// }?;
// }
"1" => {
// lokup signal idx
let hash = &word[1..];
let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
format!(
"Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
file!(),
line!()
)
})?;
// "1" => {
// // lokup signal idx
// let hash = &word[1..];
// let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
// format!(
// "Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
// file!(),
// line!()
// )
// })?;
// account for fact that signal idx could be an alias, so there
// could be one step of indirection
let signal_idx = {
let signal = vcd.all_signals.get(*signal_idx).unwrap();
match signal {
Signal::Data { .. } => *signal_idx,
Signal::Alias { signal_alias, .. } => {
let SignalIdx(ref signal_idx) = signal_alias;
signal_idx.clone()
}
}
};
// // account for fact that signal idx could be an alias, so there
// // could be one step of indirection
// let signal_idx = {
// let signal = vcd.all_signals.get(*signal_idx).unwrap();
// match signal {
// Signal::Data { .. } => *signal_idx,
// Signal::Alias { signal_alias, .. } => {
// let SignalIdx(ref signal_idx) = signal_alias;
// signal_idx.clone()
// }
// }
// };
// after handling potential indirection, go ahead and update the timeline
// of the signal signal_idx references
let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
match signal {
Signal::Data {
name,
sig_type,
ref mut signal_error,
num_bits,
u8_timeline,
u8_timeline_markers,
..
} => {
// if this is a bad signal, go ahead and skip it
if signal_error.is_some() {
continue;
}
// // after handling potential indirection, go ahead and update the timeline
// // of the signal signal_idx references
// let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
// match signal {
// Signal::Data {
// name,
// sig_type,
// ref mut signal_error,
// num_bits,
// u8_timeline,
// u8_timeline_markers,
// ..
// } => {
// // if this is a bad signal, go ahead and skip it
// if signal_error.is_some() {
// continue;
// }
// Get bitwidth and verify that it is 1.
// Also account for the error case of a bitwidth of `None`
match num_bits {
Some(ref num_bits) => {
if *num_bits != 1 {
let (f, l) = (file!(), line!());
let msg = format!(
"\
Error near {f}:{l}. The bitwidth for signal {name} \
of sig_type {sig_type:?} is expected to be `1` not \
`{num_bits}`. \
This error occurred while parsing the vcd file at \
{cursor:?}"
);
*signal_error = Some(msg);
continue;
}
}
None => {
let (f, l) = (file!(), line!());
let msg = format!(
"\
Error near {f}:{l}. The bitwidth for signal {name} \
must be specified for a signal of type {sig_type:?}. \
This error occurred while parsing the vcd file at \
{cursor:?}"
);
Err(msg)?;
}
};
// // Get bitwidth and verify that it is 1.
// // Also account for the error case of a bitwidth of `None`
// match num_bits {
// Some(ref num_bits) => {
// if *num_bits != 1 {
// let (f, l) = (file!(), line!());
// let msg = format!(
// "\
// Error near {f}:{l}. The bitwidth for signal {name} \
// of sig_type {sig_type:?} is expected to be `1` not \
// `{num_bits}`. \
// This error occurred while parsing the vcd file at \
// {cursor:?}"
// );
// *signal_error = Some(msg);
// continue;
// }
// }
// None => {
// let (f, l) = (file!(), line!());
// let msg = format!(
// "\
// Error near {f}:{l}. The bitwidth for signal {name} \
// must be specified for a signal of type {sig_type:?}. \
// This error occurred while parsing the vcd file at \
// {cursor:?}"
// );
// Err(msg)?;
// }
// };
let (f, l) = (file!(), line!());
let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| {
format!("Error near {f}:{l}. Failed to convert from usize to u32.")
})?;
let timeline_idx = TimelineIdx(timeline_idx);
// let (f, l) = (file!(), line!());
// let timeline_idx = u32::try_from(vcd.tmstmps_encoded_as_u8s.len())
// .map_err(|_| {
// format!("Error near {f}:{l}. Failed to convert from usize to u32.")
// })?;
// let timeline_idx = TimelineIdx(timeline_idx);
u8_timeline_markers.push(timeline_idx);
u8_timeline.push(1u8);
Ok(())
}
Signal::Alias { .. } => {
let (f, l) = (file!(), line!());
let msg = format!(
"Error near {f}:{l}, a signal alias should not point to a signal alias.\n\
This error occurred while parsing vcd file at {cursor:?}");
Err(msg)
}
}?;
}
// other one bit cases
"x" | "X" | "z" | "Z" | "u" | "U" => {
let val = word.to_string();
// lokup signal idx
let hash = &word[1..];
let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
format!(
"Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
file!(),
line!()
)
})?;
// u8_timeline_markers.push(timeline_idx);
// u8_timeline.push(1u8);
// Ok(())
// }
// Signal::Alias { .. } => {
// let (f, l) = (file!(), line!());
// let msg = format!(
// "Error near {f}:{l}, a signal alias should not point to a signal alias.\n\
// This error occurred while parsing vcd file at {cursor:?}");
// Err(msg)
// }
// }?;
// }
// // other one bit cases
// "x" | "X" | "z" | "Z" | "u" | "U" => {
// let val = word.to_string();
// // lokup signal idx
// let hash = &word[1..];
// let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
// format!(
// "Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
// file!(),
// line!()
// )
// })?;
// account for fact that signal idx could be an alias, so there
// could be one step of indirection
let signal_idx = {
let signal = vcd.all_signals.get(*signal_idx).unwrap();
match signal {
Signal::Data { .. } => *signal_idx,
Signal::Alias { signal_alias, .. } => {
let SignalIdx(ref signal_idx) = signal_alias;
signal_idx.clone()
}
}
};
// // account for fact that signal idx could be an alias, so there
// // could be one step of indirection
// let signal_idx = {
// let signal = vcd.all_signals.get(*signal_idx).unwrap();
// match signal {
// Signal::Data { .. } => *signal_idx,
// Signal::Alias { signal_alias, .. } => {
// let SignalIdx(ref signal_idx) = signal_alias;
// signal_idx.clone()
// }
// }
// };
// after handling potential indirection, go ahead and update the timeline
// of the signal signal_idx references
let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
match signal {
Signal::Data {
name,
sig_type,
ref mut signal_error,
num_bits,
string_timeline,
string_timeline_markers,
..
} => {
// if this is a bad signal, go ahead and skip it
if signal_error.is_some() {
continue;
}
// // after handling potential indirection, go ahead and update the timeline
// // of the signal signal_idx references
// let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
// match signal {
// Signal::Data {
// name,
// sig_type,
// ref mut signal_error,
// num_bits,
// string_timeline,
// string_timeline_markers,
// ..
// } => {
// // if this is a bad signal, go ahead and skip it
// if signal_error.is_some() {
// continue;
// }
// Get bitwidth and verify that it is 1.
// Also account for the error case of a bitwidth of `None`
match num_bits {
Some(ref num_bits) => {
if *num_bits != 1 {
let (f, l) = (file!(), line!());
let msg = format!(
"\
Error near {f}:{l}. The bitwidth for signal {name} \
of sig_type {sig_type:?} is expected to be `1` not \
`{num_bits}`. \
This error occurred while parsing the vcd file at \
{cursor:?}"
);
*signal_error = Some(msg);
continue;
}
}
None => {
let (f, l) = (file!(), line!());
let msg = format!(
"\
Error near {f}:{l}. The bitwidth for signal {name} \
must be specified for a signal of type {sig_type:?}. \
This error occurred while parsing the vcd file at \
{cursor:?}"
);
Err(msg)?;
}
};
// // Get bitwidth and verify that it is 1.
// // Also account for the error case of a bitwidth of `None`
// match num_bits {
// Some(ref num_bits) => {
// if *num_bits != 1 {
// let (f, l) = (file!(), line!());
// let msg = format!(
// "\
// Error near {f}:{l}. The bitwidth for signal {name} \
// of sig_type {sig_type:?} is expected to be `1` not \
// `{num_bits}`. \
// This error occurred while parsing the vcd file at \
// {cursor:?}"
// );
// *signal_error = Some(msg);
// continue;
// }
// }
// None => {
// let (f, l) = (file!(), line!());
// let msg = format!(
// "\
// Error near {f}:{l}. The bitwidth for signal {name} \
// must be specified for a signal of type {sig_type:?}. \
// This error occurred while parsing the vcd file at \
// {cursor:?}"
// );
// Err(msg)?;
// }
// };
let (f, l) = (file!(), line!());
let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| {
format!("Error near {f}:{l}. Failed to convert from usize to u32.")
})?;
let timeline_idx = TimelineIdx(timeline_idx);
string_timeline_markers.push(timeline_idx);
string_timeline.push(val);
Ok(())
}
Signal::Alias { .. } => {
let (f, l) = (file!(), line!());
let msg = format!(
"Error near {f}:{l}, a signal alias should not point to a signal alias.\n\
This error occurred while parsing vcd file at {cursor:?}");
Err(msg)
}
}?;
}
// let (f, l) = (file!(), line!());
// let timeline_idx = u32::try_from(vcd.tmstmps_encoded_as_u8s.len())
// .map_err(|_| {
// format!("Error near {f}:{l}. Failed to convert from usize to u32.")
// })?;
// let timeline_idx = TimelineIdx(timeline_idx);
// string_timeline_markers.push(timeline_idx);
// string_timeline.push(val);
// Ok(())
// }
// Signal::Alias { .. } => {
// let (f, l) = (file!(), line!());
// let msg = format!(
// "Error near {f}:{l}, a signal alias should not point to a signal alias.\n\
// This error occurred while parsing vcd file at {cursor:?}");
// Err(msg)
// }
// }?;
// }
_ => {}
}
}

View file

@ -100,12 +100,14 @@ pub(super) fn parse_var<'a>(
name: full_signal_name,
sig_type: var_type,
signal_error: None,
num_bits: no_bits,
num_bits: None,
self_idx: signal_idx,
u8_timeline: vec![],
u8_timeline_markers: vec![],
string_timeline: vec![],
string_timeline_markers: vec![],
nums_encoded_as_fixed_width_le_u8: vec![],
string_vals: vec![],
lsb_indxs_of_num_tmstmp_vals_on_tmln: vec![],
byte_len_of_num_tmstmp_vals_on_tmln: vec![],
lsb_indxs_of_string_tmstmp_vals_on_tmln: vec![],
byte_len_of_string_tmstmp_vals_on_tmln: vec![],
scope_parent: parent_scope_idx,
};
(signal, signal_idx)
@ -155,7 +157,7 @@ fn parse_orphaned_vars<'a>(
child_signals: vec![],
child_scopes: vec![],
});
vcd.scope_roots.push(scope_idx);
vcd.root_scopes.push(scope_idx);
}
// we can go ahead and parse the current var as we've already encountered
@ -224,7 +226,7 @@ fn parse_scopes_inner<'a>(
let parent_scope = vcd.all_scopes.get_mut(parent_scope_idx).unwrap();
parent_scope.child_scopes.push(curr_scope_idx);
}
None => vcd.scope_roots.push(curr_scope_idx),
None => vcd.root_scopes.push(curr_scope_idx),
}
// add this scope to list of existing scopes

View file

@ -115,7 +115,8 @@ macro_rules! curr_word {
($word_reader:ident) => {
$word_reader.curr_word().ok_or(()).map_err(|_| {
format!(
"Error near {}:{}. A call to curr_word! shouldn't fail unless next_word has not yet been invoked.",
"Error near {}:{}. A call to curr_word! shouldn't \
fail unless next_word has not yet been invoked.",
file!(),
line!()
)

193
src/vcd/signal.rs Normal file
View file

@ -0,0 +1,193 @@
// use super::utilities::{ordered_binary_lookup_u8, LookupErrors};
use super::{ScopeIdx, SignalIdx};
use num::{BigUint, Zero};
// Index to the least significant byte of a timestamp
// value on the timeline
#[derive(Debug, Copy, Clone)]
pub struct LsbIdxOfTmstmpValOnTmln(pub(super) u32);
#[derive(Debug)]
pub(super) enum SigType {
Integer,
Parameter,
Real,
Reg,
Str,
Wire,
Tri1,
Time,
}
#[derive(Debug)]
pub(super) enum TimelineQueryResults {
BigUint(BigUint),
String(String),
}
#[derive(Debug)]
pub(super) enum Signal {
Data {
name: String,
sig_type: SigType,
// I've seen a 0 bit signal parameter in a xilinx
// simulation before that gets assigned 1 bit values.
// I consider this to be bad behavior. We capture such
// errors in the following type:
signal_error: Option<String>,
num_bits: Option<u16>,
// TODO : may be able to remove self_idx
self_idx: SignalIdx,
// A signal may take on a new value and hold that value
// for sometime. We only need to record the value of a signal
// when it changes(the is what VCDs tend to do).
// A signal may need x amount of bytes to record its largest possible
// value, so we record every single value of a given signal as a sequence
// of x number of u8s.
// For example, we might find that `my_signal.nums_encoded_as_fixed_width_le_u8`
// has two 32 bit values, namely, 1 and 2, encoded as follows:
// my_signal.nums_encoded_as_fixed_width_le_u8 = vec![1u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8];
nums_encoded_as_fixed_width_le_u8: Vec<u8>,
string_vals: Vec<String>,
// we could do Vec<(LsbIdxOfTmstmpValOnTmln, u8)>, but I suspect that
// Vec<LsbIdxOfTmstmpValOnTmln> is more cache friendly.
// We use ``LsbIdxOfTmstmpValOnTmln`` to index into the LSB of a particular
// timestamp encoded as the minimu length u8 sequence within
// ``vcd.tmstmps_encoded_as_u8s``, and we use the values in
// ``byte_len_of_num_tmstmp_vals_on_tmln`` to determine how many u8 values
// a particular timestamp is composed of.
lsb_indxs_of_num_tmstmp_vals_on_tmln: Vec<LsbIdxOfTmstmpValOnTmln>,
byte_len_of_num_tmstmp_vals_on_tmln: Vec<u8>,
lsb_indxs_of_string_tmstmp_vals_on_tmln: Vec<LsbIdxOfTmstmpValOnTmln>,
byte_len_of_string_tmstmp_vals_on_tmln: Vec<u8>,
scope_parent: ScopeIdx,
},
Alias {
name: String,
signal_alias: SignalIdx,
},
}
impl Signal {
pub(super) fn try_dereference_alias<'a>(
&'a self,
signals: &'a Vec<Signal>,
) -> Result<&Signal, String> {
// dereference a signal if we need to and return a signal, else return
// the signal itself
let signal = match self {
Signal::Data { .. } => self,
Signal::Alias { name, signal_alias } => {
let SignalIdx(idx) = signal_alias;
&signals[*idx]
}
};
match signal {
Signal::Data { .. } => Ok(signal),
Signal::Alias { .. } => Err(format!(
"Error near {}:{}. A signal alias shouldn't \
point to a signal alias.",
file!(),
line!()
)),
}
}
// pub(super) fn try_dereference_alias_mut<'a>(
// &'a self,
// signals: &'a mut Vec<Signal>,
// ) -> Result<&mut Signal, String> {
// // dereference a signal if we need to and return a signal, else return
// // the signal itself
// let signal = match self {
// Signal::Data {
// name,
// sig_type,
// signal_error,
// num_bits,
// self_idx,
// ..
// } => {
// let SignalIdx(idx) = self_idx;
// signals.get(*idx).unwrap()
// }
// Signal::Alias { name, signal_alias } => {
// let SignalIdx(idx) = signal_alias;
// signals.get(*idx).unwrap()
// }
// };
// match signal {
// Signal::Data { .. } => Ok(signal),
// Signal::Alias { .. } => Err(format!(
// "Error near {}:{}. A signal alias shouldn't \
// point to a signal alias.",
// file!(),
// line!()
// )),
// }
// }
pub(super) fn bytes_required(&self) -> Result<u8, String> {
match self {
Signal::Data {
name,
sig_type,
signal_error,
num_bits,
..
} => {
let num_bits = num_bits.ok_or_else(|| {
format!("Error near {}:{}. num_bits empty.", file!(), line!())
})?;
let bytes_required = (num_bits / 8) + if (num_bits % 8) > 0 { 1 } else { 0 };
let bytes_required = u8::try_from(bytes_required).map_err(|_| {
format!(
"Error near {}:{}. Signal {name} of length num_bits requires \
{bytes_required} > 256 bytes.",
file!(),
line!()
)
})?;
Ok(bytes_required)
}
Signal::Alias { name, signal_alias } => {
let msg = format!(
"Error near {}:{}. Bytes required should not be called on the signal alias {name}",
file!(),
line!()
);
Err(msg)
}
}
// let bytes_required = (num_bits / 8) + if (num_bits % 8) > 0 { 1 } else { 0 };
}
// fn u8_tmstmp_to_biguint(&self, idx: usize) -> BigUint {
// // let lsb_idx = self.
// match self {
// Signal::Data {
// name,
// sig_type,
// signal_error,
// num_bits,
// self_idx,
// nums_encoded_as_fixed_width_le_u8,
// string_vals,
// lsb_indxs_of_num_tmstmp_vals_on_tmln,
// byte_len_of_num_tmstmp_vals_on_tmln,
// lsb_indxs_of_string_tmstmp_vals_on_tmln,
// byte_len_of_string_tmstmp_vals_on_tmln,
// scope_parent,
// } => {}
// }
// BigUint::zero()
// }
pub(super) fn query_value(&self, time: BigUint) -> Result<TimelineQueryResults, String> {
// match
// assert
// ordered_binary_lookup_u8(
// &value_sequence_as_bytes_u8,
// 4,
// &timeline_cursors,
// TimelineIdx(scrubbing_cursor),
// );
Ok(TimelineQueryResults::String("".to_string()))
}
}

View file

@ -1,6 +1,5 @@
use super::utilities::{ordered_binary_lookup_u8, LookupErrors};
use super::Signal;
use chrono::prelude::*;
use num::{BigUint, Zero};
#[derive(Debug)]
pub(super) struct Version(pub String);
@ -23,77 +22,13 @@ pub(super) struct Metadata {
pub(super) timescale: (Option<u32>, Timescale),
}
// We do a lot of arena allocation in this codebase.
#[derive(Debug, Copy, Clone)]
pub(super) struct ScopeIdx(pub(super) usize);
#[derive(Debug, Copy, Clone, PartialEq)]
pub(super) struct SignalIdx(pub(super) usize);
#[derive(Debug, Copy, Clone)]
pub(super) struct TimelineIdx(pub(super) u32);
#[derive(Debug, Copy, Clone)]
pub struct StartIdx(pub(super) u32);
#[derive(Debug)]
pub(super) enum SigType {
Integer,
Parameter,
Real,
Reg,
Str,
Wire,
Tri1,
Time,
}
#[derive(Debug)]
pub(super) enum Signal {
Data {
name: String,
sig_type: SigType,
// I've seen a 0 bit signal parameter in a xilinx
// simulation before that gets assigned 1 bit values.
// I consider this to be bad behavior. We capture such
// errors in the following type.
signal_error: Option<String>,
num_bits: Option<usize>,
// TODO : may be able to remove self_idx
self_idx: SignalIdx,
// we could encounter a mix of pure values and strings
// for the same signal timeline
u8_timeline: Vec<u8>,
u8_timeline_markers: Vec<TimelineIdx>,
string_timeline: Vec<String>,
string_timeline_markers: Vec<TimelineIdx>,
scope_parent: ScopeIdx,
},
Alias {
name: String,
signal_alias: SignalIdx,
},
}
#[derive(Debug)]
pub(super) enum TimelineQueryResults {
BigUint(BigUint),
String(String),
}
impl Scope {
pub(super) fn query_value(&self, time: TimelineIdx) -> Result<TimelineQueryResults, String> {
// match
// assert
// ordered_binary_lookup_u8(
// &value_sequence_as_bytes_u8,
// 4,
// &timeline_cursors,
// TimelineIdx(scrubbing_cursor),
// );
Ok(TimelineQueryResults::String("".to_string()))
}
}
#[derive(Debug)]
pub(super) struct Scope {
pub(super) name: String,
@ -105,82 +40,63 @@ pub(super) struct Scope {
pub(super) child_scopes: Vec<ScopeIdx>,
}
// TODO: document how timeline is represented
#[derive(Debug)]
pub struct VCD {
pub(super) metadata: Metadata,
// since we only need to store values when there is an actual change
// Since we only need to store values when there is an actual change
// in the timeline, we keep a vector that stores the time at which an
// event occurs. Time t is always stored as the minimum length sequence
// event occurs. Time t is always stored/encoded as the minimum length sequence
// of u8.
pub timeline: Vec<u8>,
// we need to keep track of where a given time t sequence of u8 begins
// and ends in the timeline vector.
pub timeline_markers: Vec<StartIdx>,
// We essentially fill ``tmstmps_encoded_as_u8s`` with BigUints converted
// to sequences of little endian u8s.
// It is up to the signals to keep track of the start/stop indices in the
// vector of u8s that constitute a timestamp value. Signals don't have to
// keep track of all timestamp values, a given signal only needs to keep
// track of the timestamps at which the given signal value changes.
pub tmstmps_encoded_as_u8s: Vec<u8>,
pub(super) all_signals: Vec<Signal>,
pub(super) all_scopes: Vec<Scope>,
pub(super) scope_roots: Vec<ScopeIdx>,
pub(super) root_scopes: Vec<ScopeIdx>,
}
impl VCD {
// TODO : make this a generic traversal function that applies specified
// functions upon encountering scopes and signals
fn print_scope_tree(&self, root_scope_idx: ScopeIdx, depth: usize) {
let all_scopes = &self.all_scopes;
let all_signals = &self.all_signals;
/// We take in a Signal and attempt to dereference that signal if it is of
/// variant Signal::Alias. If it is of variant Signal::Alias and points to
/// another alias, that's an error. Otherwise, we return the Signal::Data
/// pointed to by the Signal::Alias.
/// If the Signal is of varint Signal::Data, then that can be returned directly.
pub(super) fn try_dereference_alias_mut<'a>(
&'a mut self,
idx: &SignalIdx,
) -> Result<&'a mut Signal, String> {
// get the signal pointed to be SignalIdx from the arena
let SignalIdx(idx) = idx;
let signal = &self.all_signals[*idx];
let indent = " ".repeat(depth * 4);
let ScopeIdx(root_scope_idx) = root_scope_idx;
let root_scope = &all_scopes[root_scope_idx];
let root_scope_name = &root_scope.name;
println!("{indent}scope: {root_scope_name}");
for SignalIdx(ref signal_idx) in &root_scope.child_signals {
let child_signal = &all_signals[*signal_idx];
let name = match child_signal {
Signal::Data { name, .. } => name,
Signal::Alias { name, .. } => name,
};
println!("{indent} - sig: {name}")
}
println!();
for scope_idx in &root_scope.child_scopes {
self.print_scope_tree(*scope_idx, depth + 1);
}
}
pub fn print_scopes(&self) {
for scope_root in &self.scope_roots {
self.print_scope_tree(*scope_root, 0);
}
}
pub fn print_longest_signal(&self) {
let mut idx = 0usize;
let mut max_len = 0usize;
let mut signal_name = String::new();
for signal in &self.all_signals {
match signal {
Signal::Alias { .. } => {}
// dereference signal if Signal::Alias, or keep idx if Signal::Data
let signal_idx = match signal {
Signal::Data {
name,
sig_type,
signal_error,
num_bits,
self_idx,
u8_timeline,
..
} => {
if u8_timeline.len() > max_len {
max_len = u8_timeline.len();
let SignalIdx(idx_usize) = self_idx;
idx = *idx_usize;
signal_name = name.clone();
}
}
}
}
} => *self_idx,
Signal::Alias { name, signal_alias } => *signal_alias,
};
dbg!((idx, max_len, signal_name));
// Should now point to Signal::Data variant, or else there's an error
let SignalIdx(idx) = signal_idx;
let signal = self.all_signals.get_mut(idx).unwrap();
match signal {
Signal::Data { .. } => Ok(signal),
Signal::Alias { .. } => Err(format!(
"Error near {}:{}. A signal alias shouldn't \
point to a signal alias.",
file!(),
line!()
)),
}
}
}

View file

@ -80,100 +80,107 @@ use num::{BigUint, Zero};
#[derive(Debug)]
pub(super) enum LookupErrors {
PreTimeline {
desired_time: TimelineIdx,
timeline_start_time: TimelineIdx,
desired_time: BigUint,
timeline_start_time: BigUint,
},
EmptyTimeline,
TimelineNotMultiple,
OrderingFailure,
}
pub(super) fn ordered_binary_lookup_u8(
value_sequence_as_bytes: &Vec<u8>,
bytes_per_value: usize,
timeline_cursors: &Vec<TimelineIdx>,
desired_time: TimelineIdx,
) -> Result<BigUint, LookupErrors> {
// timeline must not be empty
if timeline_cursors.is_empty() {
return Err(LookupErrors::EmptyTimeline);
}
// pub(super) fn ordered_binary_lookup_u8(
// //(REMOVE THIS COMMENT)below is from self
// lsb_indxs_of_num_tmstmp_vals_on_tmln: &Vec<LsbIdxOfTmstmpValOnTmln>,
// tmstmps_encoded_as_u8s: &Vec<u8>,
// //(REMOVE THIS COMMENT)below is from self
// nums_encoded_as_fixed_width_le_u8: &Vec<u8>,
// // TODO : should this be usize?
// bytes_per_value: usize,
// desired_time: BigUint,
// ) -> Result<BigUint, LookupErrors> {
// // this signal should at least have some events, otherwise, trying to index into
// // an empty vector later on would fail
// if lsb_indxs_of_num_tmstmp_vals_on_tmln.is_empty() {
// return Err(LookupErrors::EmptyTimeline);
// }
// assertion that value_sequence is a proper multiple of
// timeline_markers
if value_sequence_as_bytes.len() != (timeline_cursors.len() * bytes_per_value) {
return Err(LookupErrors::TimelineNotMultiple);
}
// // assertion that value_sequence is a proper multiple of
// // timeline_markers
// if lsb_indxs_of_num_tmstmp_vals_on_tmln.len()
// != (nums_encoded_as_fixed_width_le_u8.len() * bytes_per_value)
// {
// return Err(LookupErrors::TimelineNotMultiple);
// }
let TimelineIdx(desired_time) = desired_time;
// // let TimelineIdx(desired_time) = desired_time;
// check if we're requesting a value that occurs before the recorded
// start of the timeline
let TimelineIdx(timeline_start_time) = timeline_cursors.first().unwrap();
if desired_time < *timeline_start_time {
return Err(LookupErrors::PreTimeline {
desired_time: TimelineIdx(desired_time),
timeline_start_time: TimelineIdx(*timeline_start_time),
});
}
// // check if we're requesting a value that occurs before the recorded
// // start of the timeline
// let TimelineIdx(timeline_start_time) = timeline_cursors.first().unwrap();
// if desired_time < *timeline_start_time {
// return Err(LookupErrors::PreTimeline {
// desired_time: TimelineIdx(desired_time),
// timeline_start_time: TimelineIdx(*timeline_start_time),
// });
// }
let mut lower_idx = 0usize;
let mut upper_idx = timeline_cursors.len() - 1;
// let mut lower_idx = 0usize;
// let mut upper_idx = timeline_cursors.len() - 1;
// check if we're requesting a value that occurs beyond the end of the timeline,
// if so, return the last value in this timeline
let TimelineIdx(timeline_end_time) = timeline_cursors.last().unwrap();
if desired_time > *timeline_end_time {
let range = (value_sequence_as_bytes.len() - bytes_per_value)..;
let value_by_bytes = &value_sequence_as_bytes[range];
let value = BigUint::from_bytes_le(value_by_bytes);
// // check if we're requesting a value that occurs beyond the end of the timeline,
// // if so, return the last value in this timeline
// let TimelineIdx(timeline_end_time) = timeline_cursors.last().unwrap();
// if desired_time > *timeline_end_time {
// let range = (value_sequence_as_bytes.len() - bytes_per_value)..;
// let value_by_bytes = &value_sequence_as_bytes[range];
// let value = BigUint::from_bytes_le(value_by_bytes);
return Ok(value);
}
// return Ok(value);
// }
// This while loop is the meat of the lookup. Performance is log2(n),
// where n is the number of events on the timeline.
// We can assume that by the time we get here, that the desired_time
// is an event that occurs on the timeline, given that we handle any events
// occuring after or before the recorded tiimeline in the code above.
while lower_idx <= upper_idx {
let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
let TimelineIdx(curr_time) = timeline_cursors[mid_idx];
let ordering = curr_time.cmp(&desired_time);
// // This while loop is the meat of the lookup. Performance is log2(n),
// // where n is the number of events on the timeline.
// // We can assume that by the time we get here, that the desired_time
// // is an event that occurs on the timeline, given that we handle any events
// // occuring after or before the recorded tiimeline in the code above.
// while lower_idx <= upper_idx {
// let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
// let TimelineIdx(curr_time) = timeline_cursors[mid_idx];
// let ordering = curr_time.cmp(&desired_time);
match ordering {
std::cmp::Ordering::Less => {
lower_idx = mid_idx + 1;
}
std::cmp::Ordering::Equal => {
let u8_timeline_start_idx = mid_idx * bytes_per_value;
let u8_timeline_end_idx = u8_timeline_start_idx + bytes_per_value;
let range = u8_timeline_start_idx..u8_timeline_end_idx;
let value_by_bytes = &value_sequence_as_bytes[range];
let value = BigUint::from_bytes_le(value_by_bytes);
return Ok(value);
}
std::cmp::Ordering::Greater => {
upper_idx = mid_idx - 1;
}
}
}
// match ordering {
// std::cmp::Ordering::Less => {
// lower_idx = mid_idx + 1;
// }
// std::cmp::Ordering::Equal => {
// let u8_timeline_start_idx = mid_idx * bytes_per_value;
// let u8_timeline_end_idx = u8_timeline_start_idx + bytes_per_value;
// let range = u8_timeline_start_idx..u8_timeline_end_idx;
// let value_by_bytes = &value_sequence_as_bytes[range];
// let value = BigUint::from_bytes_le(value_by_bytes);
// return Ok(value);
// }
// std::cmp::Ordering::Greater => {
// upper_idx = mid_idx - 1;
// }
// }
// }
let idx = lower_idx - 1;
let TimelineIdx(left_time) = timeline_cursors[idx];
let TimelineIdx(right_time) = timeline_cursors[idx + 1];
// let idx = lower_idx - 1;
// let TimelineIdx(left_time) = timeline_cursors[idx];
// let TimelineIdx(right_time) = timeline_cursors[idx + 1];
let ordered_left = left_time < desired_time;
let ordered_right = desired_time < right_time;
if !(ordered_left && ordered_right) {
return Err(LookupErrors::OrderingFailure);
}
// let ordered_left = left_time < desired_time;
// let ordered_right = desired_time < right_time;
// if !(ordered_left && ordered_right) {
// return Err(LookupErrors::OrderingFailure);
// }
let u8_timeline_start_idx = idx * bytes_per_value;
let u8_timeline_end_idx = u8_timeline_start_idx + bytes_per_value;
let range = u8_timeline_start_idx..u8_timeline_end_idx;
let value_by_bytes = &value_sequence_as_bytes[range];
let value = BigUint::from_bytes_le(value_by_bytes);
// let u8_timeline_start_idx = idx * bytes_per_value;
// let u8_timeline_end_idx = u8_timeline_start_idx + bytes_per_value;
// let range = u8_timeline_start_idx..u8_timeline_end_idx;
// let value_by_bytes = &value_sequence_as_bytes[range];
// let value = BigUint::from_bytes_le(value_by_bytes);
return Ok(value);
}
// return Ok(value);
// }