non trivial re-factor
This commit is contained in:
parent
cbd8be1708
commit
15a2564f13
|
@ -7,5 +7,8 @@ pub(super) use types::*;
|
||||||
mod parse;
|
mod parse;
|
||||||
pub(super) use parse::*;
|
pub(super) use parse::*;
|
||||||
|
|
||||||
|
mod signal;
|
||||||
|
pub(super) use signal::*;
|
||||||
|
|
||||||
mod utilities;
|
mod utilities;
|
||||||
use utilities::*;
|
use utilities::*;
|
||||||
|
|
|
@ -31,11 +31,10 @@ pub fn parse_vcd(file: File) -> Result<VCD, String> {
|
||||||
// after we parse metadata, we form the VCD object
|
// after we parse metadata, we form the VCD object
|
||||||
let mut vcd = VCD {
|
let mut vcd = VCD {
|
||||||
metadata: header,
|
metadata: header,
|
||||||
timeline: vec![],
|
tmstmps_encoded_as_u8s: vec![],
|
||||||
timeline_markers: vec![],
|
|
||||||
all_signals: vec![],
|
all_signals: vec![],
|
||||||
all_scopes: vec![],
|
all_scopes: vec![],
|
||||||
scope_roots: vec![],
|
root_scopes: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
parse_scopes(&mut word_gen, &mut vcd, &mut signal_map)?;
|
parse_scopes(&mut word_gen, &mut vcd, &mut signal_map)?;
|
||||||
|
|
|
@ -5,6 +5,8 @@ pub(super) fn parse_events<'a>(
|
||||||
vcd: &'a mut VCD,
|
vcd: &'a mut VCD,
|
||||||
signal_map: &mut HashMap<String, SignalIdx>,
|
signal_map: &mut HashMap<String, SignalIdx>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
let mut curr_tmstmp_lsb_idx = 0u32;
|
||||||
|
let mut curr_tmstmp_len_u8 = 0u8;
|
||||||
loop {
|
loop {
|
||||||
let next_word = word_reader.next_word();
|
let next_word = word_reader.next_word();
|
||||||
|
|
||||||
|
@ -36,18 +38,36 @@ pub(super) fn parse_events<'a>(
|
||||||
let mut value = value.to_bytes_le();
|
let mut value = value.to_bytes_le();
|
||||||
// TODO : u32 helps with less memory, but should ideally likely be
|
// TODO : u32 helps with less memory, but should ideally likely be
|
||||||
// configurable.
|
// configurable.
|
||||||
let (f, l) = (file!(), line!());
|
curr_tmstmp_len_u8 = u8::try_from(value.len()).map_err(|_| {
|
||||||
let start_idx = u32::try_from(vcd.timeline.len()).map_err(|_| {
|
format!(
|
||||||
format!("Error near {f}:{l}. Failed to convert from usize to u32.")
|
"Error near {}:{}. Failed to convert from usize to u8.",
|
||||||
|
file!(),
|
||||||
|
line!()
|
||||||
|
)
|
||||||
})?;
|
})?;
|
||||||
vcd.timeline_markers.push(StartIdx(start_idx));
|
vcd.tmstmps_encoded_as_u8s.append(&mut value);
|
||||||
vcd.timeline.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
|
// handle the case of an n bit signal whose value must be parsed
|
||||||
"b" => {
|
"b" => {
|
||||||
let binary_value = &word[1..];
|
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_u8: Vec<u8> = Vec::new();
|
||||||
let mut value_string = String::new();
|
let mut value_string = String::new();
|
||||||
|
@ -81,7 +101,7 @@ pub(super) fn parse_events<'a>(
|
||||||
let (word, cursor) = next_word!(word_reader)?;
|
let (word, cursor) = next_word!(word_reader)?;
|
||||||
|
|
||||||
// lookup signal idx
|
// 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!(
|
format!(
|
||||||
"Error near {}:{}. Failed to lookup signal {word} at {cursor:?}",
|
"Error near {}:{}. Failed to lookup signal {word} at {cursor:?}",
|
||||||
file!(),
|
file!(),
|
||||||
|
@ -89,34 +109,29 @@ pub(super) fn parse_events<'a>(
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// account for fact that signal idx could be an alias, so there
|
let signal = vcd.try_dereference_alias_mut(signal_idx)?;
|
||||||
// could be one step of indirection
|
|
||||||
let signal_idx = {
|
// we may have to dereference a signal if it's pointing at an alias
|
||||||
let signal = vcd.all_signals.get(*signal_idx).unwrap();
|
// let signal = &vcd.all_signals[*signal_idx];
|
||||||
match signal {
|
// let signal = signal.try_dereference_alias_mut(&vcd.all_signals)?;
|
||||||
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 {
|
match signal {
|
||||||
Signal::Data {
|
Signal::Data {
|
||||||
name,
|
name,
|
||||||
sig_type,
|
sig_type,
|
||||||
ref mut signal_error,
|
ref mut signal_error,
|
||||||
num_bits,
|
num_bits,
|
||||||
u8_timeline,
|
self_idx,
|
||||||
u8_timeline_markers,
|
nums_encoded_as_fixed_width_le_u8,
|
||||||
string_timeline,
|
string_vals,
|
||||||
string_timeline_markers,
|
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() {
|
if signal_error.is_some() {
|
||||||
continue;
|
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 {
|
if store_as_string {
|
||||||
string_timeline_markers.push(timeline_idx);
|
lsb_indxs_of_string_tmstmp_vals_on_tmln
|
||||||
string_timeline.push(value_string);
|
.push(LsbIdxOfTmstmpValOnTmln(curr_tmstmp_lsb_idx));
|
||||||
|
string_vals.push(value_string);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
u8_timeline_markers.push(timeline_idx);
|
let mut curr_num_bytes =
|
||||||
|
u8::try_from(value_u8.len()).map_err(|_| {
|
||||||
let mut curr_num_bytes = value_u8.len();
|
format!(
|
||||||
u8_timeline.append(&mut value_u8);
|
"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
|
// we may need to zero extend values
|
||||||
// so that we end up storing all values
|
// so that we end up storing all values
|
||||||
// of a particular signal in a consistent
|
// of a particular signal in a consistent
|
||||||
// amount of bytes
|
// amount of bytes
|
||||||
let num_bits = num_bits.unwrap();
|
let bytes_required = signal.bytes_required()?;
|
||||||
let bytes_required =
|
|
||||||
(num_bits / 8) + if (num_bits % 8) > 0 { 1 } else { 0 };
|
|
||||||
|
|
||||||
while curr_num_bytes < bytes_required {
|
while curr_num_bytes < bytes_required {
|
||||||
// TODO: remove once library is known to be stable
|
// TODO: remove once library is known to be stable
|
||||||
|
@ -187,7 +204,7 @@ pub(super) fn parse_events<'a>(
|
||||||
// for signal {name}");
|
// for signal {name}");
|
||||||
// Err(err)?;
|
// Err(err)?;
|
||||||
|
|
||||||
u8_timeline.push(0u8);
|
byte_len_of_num_tmstmp_vals_on_tmln.push(0u8);
|
||||||
curr_num_bytes += 1;
|
curr_num_bytes += 1;
|
||||||
}
|
}
|
||||||
Ok(())
|
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`
|
// handle the case of a one bit signal whose value is set to `0`
|
||||||
"0" => {
|
// "0" => {
|
||||||
// lookup signal idx
|
// // lookup signal idx
|
||||||
let hash = &word[1..];
|
// let hash = &word[1..];
|
||||||
let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
|
// let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
|
||||||
format!(
|
// format!(
|
||||||
"Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
|
// "Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
|
||||||
file!(),
|
// file!(),
|
||||||
line!()
|
// line!()
|
||||||
)
|
// )
|
||||||
})?;
|
// })?;
|
||||||
|
|
||||||
// account for fact that signal idx could be an alias, so there
|
// // account for fact that signal idx could be an alias, so there
|
||||||
// could be one step of indirection
|
// // could be one step of indirection
|
||||||
let signal_idx = {
|
// let signal_idx = {
|
||||||
let signal = vcd.all_signals.get(*signal_idx).unwrap();
|
// let signal = vcd.all_signals.get(*signal_idx).unwrap();
|
||||||
match signal {
|
// match signal {
|
||||||
Signal::Data { .. } => *signal_idx,
|
// Signal::Data { .. } => *signal_idx,
|
||||||
Signal::Alias { signal_alias, .. } => {
|
// Signal::Alias { signal_alias, .. } => {
|
||||||
let SignalIdx(ref signal_idx) = signal_alias;
|
// let SignalIdx(ref signal_idx) = signal_alias;
|
||||||
signal_idx.clone()
|
// signal_idx.clone()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
// after handling potential indirection, go ahead and update the timeline
|
// // after handling potential indirection, go ahead and update the timeline
|
||||||
// of the signal signal_idx references
|
// // of the signal signal_idx references
|
||||||
let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
|
// let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
|
||||||
match signal {
|
// match signal {
|
||||||
Signal::Data {
|
// Signal::Data {
|
||||||
name,
|
// name,
|
||||||
sig_type,
|
// sig_type,
|
||||||
ref mut signal_error,
|
// ref mut signal_error,
|
||||||
num_bits,
|
// num_bits,
|
||||||
u8_timeline,
|
// u8_timeline,
|
||||||
u8_timeline_markers,
|
// u8_timeline_markers,
|
||||||
..
|
// ..
|
||||||
} => {
|
// } => {
|
||||||
// if this is a bad signal, go ahead and skip it
|
// // if this is a bad signal, go ahead and skip it
|
||||||
if signal_error.is_some() {
|
// if signal_error.is_some() {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Get bitwidth and verify that it is 1.
|
// // Get bitwidth and verify that it is 1.
|
||||||
// Also account for the error case of a bitwidth of `None`
|
// // Also account for the error case of a bitwidth of `None`
|
||||||
match num_bits {
|
// match num_bits {
|
||||||
Some(ref num_bits) => {
|
// Some(ref num_bits) => {
|
||||||
if *num_bits != 1 {
|
// if *num_bits != 1 {
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let msg = format!(
|
// let msg = format!(
|
||||||
"\
|
// "\
|
||||||
Error near {f}:{l}. The bitwidth for signal {name} \
|
// Error near {f}:{l}. The bitwidth for signal {name} \
|
||||||
of sig_type {sig_type:?} is expected to be `1` not \
|
// of sig_type {sig_type:?} is expected to be `1` not \
|
||||||
`{num_bits}`. \
|
// `{num_bits}`. \
|
||||||
This error occurred while parsing the vcd file at \
|
// This error occurred while parsing the vcd file at \
|
||||||
{cursor:?}"
|
// {cursor:?}"
|
||||||
);
|
// );
|
||||||
*signal_error = Some(msg);
|
// *signal_error = Some(msg);
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
None => {
|
// None => {
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let msg = format!(
|
// let msg = format!(
|
||||||
"\
|
// "\
|
||||||
Error near {f}:{l}. The bitwidth for signal {name} \
|
// Error near {f}:{l}. The bitwidth for signal {name} \
|
||||||
must be specified for a signal of type {sig_type:?}. \
|
// must be specified for a signal of type {sig_type:?}. \
|
||||||
This error occurred while parsing the vcd file at \
|
// This error occurred while parsing the vcd file at \
|
||||||
{cursor:?}"
|
// {cursor:?}"
|
||||||
);
|
// );
|
||||||
Err(msg)?;
|
// Err(msg)?;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| {
|
// let timeline_idx = u32::try_from(vcd.tmstmps_encoded_as_u8s.len())
|
||||||
format!("Error near {f}:{l}. Failed to convert from usize to u32.")
|
// .map_err(|_| {
|
||||||
})?;
|
// format!("Error near {f}:{l}. Failed to convert from usize to u32.")
|
||||||
let timeline_idx = TimelineIdx(timeline_idx);
|
// })?;
|
||||||
|
// let timeline_idx = TimelineIdx(timeline_idx);
|
||||||
|
|
||||||
u8_timeline_markers.push(timeline_idx);
|
// u8_timeline_markers.push(timeline_idx);
|
||||||
u8_timeline.push(0u8);
|
// u8_timeline.push(0u8);
|
||||||
Ok(())
|
// Ok(())
|
||||||
}
|
// }
|
||||||
Signal::Alias { .. } => {
|
// Signal::Alias { .. } => {
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let msg = format!(
|
// let msg = format!(
|
||||||
"Error near {f}:{l}, a signal alias should not point to a signal alias.\n\
|
// "Error near {f}:{l}, a signal alias should not point to a signal alias.\n\
|
||||||
This error occurred while parsing vcd file at {cursor:?}");
|
// This error occurred while parsing vcd file at {cursor:?}");
|
||||||
Err(msg)
|
// Err(msg)
|
||||||
}
|
// }
|
||||||
}?;
|
// }?;
|
||||||
}
|
// }
|
||||||
|
|
||||||
"1" => {
|
// "1" => {
|
||||||
// lokup signal idx
|
// // lokup signal idx
|
||||||
let hash = &word[1..];
|
// let hash = &word[1..];
|
||||||
let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
|
// let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
|
||||||
format!(
|
// format!(
|
||||||
"Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
|
// "Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
|
||||||
file!(),
|
// file!(),
|
||||||
line!()
|
// line!()
|
||||||
)
|
// )
|
||||||
})?;
|
// })?;
|
||||||
|
|
||||||
// account for fact that signal idx could be an alias, so there
|
// // account for fact that signal idx could be an alias, so there
|
||||||
// could be one step of indirection
|
// // could be one step of indirection
|
||||||
let signal_idx = {
|
// let signal_idx = {
|
||||||
let signal = vcd.all_signals.get(*signal_idx).unwrap();
|
// let signal = vcd.all_signals.get(*signal_idx).unwrap();
|
||||||
match signal {
|
// match signal {
|
||||||
Signal::Data { .. } => *signal_idx,
|
// Signal::Data { .. } => *signal_idx,
|
||||||
Signal::Alias { signal_alias, .. } => {
|
// Signal::Alias { signal_alias, .. } => {
|
||||||
let SignalIdx(ref signal_idx) = signal_alias;
|
// let SignalIdx(ref signal_idx) = signal_alias;
|
||||||
signal_idx.clone()
|
// signal_idx.clone()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
// after handling potential indirection, go ahead and update the timeline
|
// // after handling potential indirection, go ahead and update the timeline
|
||||||
// of the signal signal_idx references
|
// // of the signal signal_idx references
|
||||||
let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
|
// let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
|
||||||
match signal {
|
// match signal {
|
||||||
Signal::Data {
|
// Signal::Data {
|
||||||
name,
|
// name,
|
||||||
sig_type,
|
// sig_type,
|
||||||
ref mut signal_error,
|
// ref mut signal_error,
|
||||||
num_bits,
|
// num_bits,
|
||||||
u8_timeline,
|
// u8_timeline,
|
||||||
u8_timeline_markers,
|
// u8_timeline_markers,
|
||||||
..
|
// ..
|
||||||
} => {
|
// } => {
|
||||||
// if this is a bad signal, go ahead and skip it
|
// // if this is a bad signal, go ahead and skip it
|
||||||
if signal_error.is_some() {
|
// if signal_error.is_some() {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Get bitwidth and verify that it is 1.
|
// // Get bitwidth and verify that it is 1.
|
||||||
// Also account for the error case of a bitwidth of `None`
|
// // Also account for the error case of a bitwidth of `None`
|
||||||
match num_bits {
|
// match num_bits {
|
||||||
Some(ref num_bits) => {
|
// Some(ref num_bits) => {
|
||||||
if *num_bits != 1 {
|
// if *num_bits != 1 {
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let msg = format!(
|
// let msg = format!(
|
||||||
"\
|
// "\
|
||||||
Error near {f}:{l}. The bitwidth for signal {name} \
|
// Error near {f}:{l}. The bitwidth for signal {name} \
|
||||||
of sig_type {sig_type:?} is expected to be `1` not \
|
// of sig_type {sig_type:?} is expected to be `1` not \
|
||||||
`{num_bits}`. \
|
// `{num_bits}`. \
|
||||||
This error occurred while parsing the vcd file at \
|
// This error occurred while parsing the vcd file at \
|
||||||
{cursor:?}"
|
// {cursor:?}"
|
||||||
);
|
// );
|
||||||
*signal_error = Some(msg);
|
// *signal_error = Some(msg);
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
None => {
|
// None => {
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let msg = format!(
|
// let msg = format!(
|
||||||
"\
|
// "\
|
||||||
Error near {f}:{l}. The bitwidth for signal {name} \
|
// Error near {f}:{l}. The bitwidth for signal {name} \
|
||||||
must be specified for a signal of type {sig_type:?}. \
|
// must be specified for a signal of type {sig_type:?}. \
|
||||||
This error occurred while parsing the vcd file at \
|
// This error occurred while parsing the vcd file at \
|
||||||
{cursor:?}"
|
// {cursor:?}"
|
||||||
);
|
// );
|
||||||
Err(msg)?;
|
// Err(msg)?;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| {
|
// let timeline_idx = u32::try_from(vcd.tmstmps_encoded_as_u8s.len())
|
||||||
format!("Error near {f}:{l}. Failed to convert from usize to u32.")
|
// .map_err(|_| {
|
||||||
})?;
|
// format!("Error near {f}:{l}. Failed to convert from usize to u32.")
|
||||||
let timeline_idx = TimelineIdx(timeline_idx);
|
// })?;
|
||||||
|
// let timeline_idx = TimelineIdx(timeline_idx);
|
||||||
|
|
||||||
u8_timeline_markers.push(timeline_idx);
|
// u8_timeline_markers.push(timeline_idx);
|
||||||
u8_timeline.push(1u8);
|
// u8_timeline.push(1u8);
|
||||||
Ok(())
|
// Ok(())
|
||||||
}
|
// }
|
||||||
Signal::Alias { .. } => {
|
// Signal::Alias { .. } => {
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let msg = format!(
|
// let msg = format!(
|
||||||
"Error near {f}:{l}, a signal alias should not point to a signal alias.\n\
|
// "Error near {f}:{l}, a signal alias should not point to a signal alias.\n\
|
||||||
This error occurred while parsing vcd file at {cursor:?}");
|
// This error occurred while parsing vcd file at {cursor:?}");
|
||||||
Err(msg)
|
// Err(msg)
|
||||||
}
|
// }
|
||||||
}?;
|
// }?;
|
||||||
}
|
// }
|
||||||
// other one bit cases
|
// // other one bit cases
|
||||||
"x" | "X" | "z" | "Z" | "u" | "U" => {
|
// "x" | "X" | "z" | "Z" | "u" | "U" => {
|
||||||
let val = word.to_string();
|
// let val = word.to_string();
|
||||||
// lokup signal idx
|
// // lokup signal idx
|
||||||
let hash = &word[1..];
|
// let hash = &word[1..];
|
||||||
let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
|
// let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| {
|
||||||
format!(
|
// format!(
|
||||||
"Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
|
// "Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}",
|
||||||
file!(),
|
// file!(),
|
||||||
line!()
|
// line!()
|
||||||
)
|
// )
|
||||||
})?;
|
// })?;
|
||||||
|
|
||||||
// account for fact that signal idx could be an alias, so there
|
// // account for fact that signal idx could be an alias, so there
|
||||||
// could be one step of indirection
|
// // could be one step of indirection
|
||||||
let signal_idx = {
|
// let signal_idx = {
|
||||||
let signal = vcd.all_signals.get(*signal_idx).unwrap();
|
// let signal = vcd.all_signals.get(*signal_idx).unwrap();
|
||||||
match signal {
|
// match signal {
|
||||||
Signal::Data { .. } => *signal_idx,
|
// Signal::Data { .. } => *signal_idx,
|
||||||
Signal::Alias { signal_alias, .. } => {
|
// Signal::Alias { signal_alias, .. } => {
|
||||||
let SignalIdx(ref signal_idx) = signal_alias;
|
// let SignalIdx(ref signal_idx) = signal_alias;
|
||||||
signal_idx.clone()
|
// signal_idx.clone()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
// after handling potential indirection, go ahead and update the timeline
|
// // after handling potential indirection, go ahead and update the timeline
|
||||||
// of the signal signal_idx references
|
// // of the signal signal_idx references
|
||||||
let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
|
// let signal = vcd.all_signals.get_mut(signal_idx).unwrap();
|
||||||
match signal {
|
// match signal {
|
||||||
Signal::Data {
|
// Signal::Data {
|
||||||
name,
|
// name,
|
||||||
sig_type,
|
// sig_type,
|
||||||
ref mut signal_error,
|
// ref mut signal_error,
|
||||||
num_bits,
|
// num_bits,
|
||||||
string_timeline,
|
// string_timeline,
|
||||||
string_timeline_markers,
|
// string_timeline_markers,
|
||||||
..
|
// ..
|
||||||
} => {
|
// } => {
|
||||||
// if this is a bad signal, go ahead and skip it
|
// // if this is a bad signal, go ahead and skip it
|
||||||
if signal_error.is_some() {
|
// if signal_error.is_some() {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Get bitwidth and verify that it is 1.
|
// // Get bitwidth and verify that it is 1.
|
||||||
// Also account for the error case of a bitwidth of `None`
|
// // Also account for the error case of a bitwidth of `None`
|
||||||
match num_bits {
|
// match num_bits {
|
||||||
Some(ref num_bits) => {
|
// Some(ref num_bits) => {
|
||||||
if *num_bits != 1 {
|
// if *num_bits != 1 {
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let msg = format!(
|
// let msg = format!(
|
||||||
"\
|
// "\
|
||||||
Error near {f}:{l}. The bitwidth for signal {name} \
|
// Error near {f}:{l}. The bitwidth for signal {name} \
|
||||||
of sig_type {sig_type:?} is expected to be `1` not \
|
// of sig_type {sig_type:?} is expected to be `1` not \
|
||||||
`{num_bits}`. \
|
// `{num_bits}`. \
|
||||||
This error occurred while parsing the vcd file at \
|
// This error occurred while parsing the vcd file at \
|
||||||
{cursor:?}"
|
// {cursor:?}"
|
||||||
);
|
// );
|
||||||
*signal_error = Some(msg);
|
// *signal_error = Some(msg);
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
None => {
|
// None => {
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let msg = format!(
|
// let msg = format!(
|
||||||
"\
|
// "\
|
||||||
Error near {f}:{l}. The bitwidth for signal {name} \
|
// Error near {f}:{l}. The bitwidth for signal {name} \
|
||||||
must be specified for a signal of type {sig_type:?}. \
|
// must be specified for a signal of type {sig_type:?}. \
|
||||||
This error occurred while parsing the vcd file at \
|
// This error occurred while parsing the vcd file at \
|
||||||
{cursor:?}"
|
// {cursor:?}"
|
||||||
);
|
// );
|
||||||
Err(msg)?;
|
// Err(msg)?;
|
||||||
}
|
// }
|
||||||
};
|
// };
|
||||||
|
|
||||||
let (f, l) = (file!(), line!());
|
// let (f, l) = (file!(), line!());
|
||||||
let timeline_idx = u32::try_from(vcd.timeline.len()).map_err(|_| {
|
// let timeline_idx = u32::try_from(vcd.tmstmps_encoded_as_u8s.len())
|
||||||
format!("Error near {f}:{l}. Failed to convert from usize to u32.")
|
// .map_err(|_| {
|
||||||
})?;
|
// format!("Error near {f}:{l}. Failed to convert from usize to u32.")
|
||||||
let timeline_idx = TimelineIdx(timeline_idx);
|
// })?;
|
||||||
|
// 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)
|
|
||||||
}
|
|
||||||
}?;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
// }
|
||||||
|
// }?;
|
||||||
|
// }
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,12 +100,14 @@ pub(super) fn parse_var<'a>(
|
||||||
name: full_signal_name,
|
name: full_signal_name,
|
||||||
sig_type: var_type,
|
sig_type: var_type,
|
||||||
signal_error: None,
|
signal_error: None,
|
||||||
num_bits: no_bits,
|
num_bits: None,
|
||||||
self_idx: signal_idx,
|
self_idx: signal_idx,
|
||||||
u8_timeline: vec![],
|
nums_encoded_as_fixed_width_le_u8: vec![],
|
||||||
u8_timeline_markers: vec![],
|
string_vals: vec![],
|
||||||
string_timeline: vec![],
|
lsb_indxs_of_num_tmstmp_vals_on_tmln: vec![],
|
||||||
string_timeline_markers: 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,
|
scope_parent: parent_scope_idx,
|
||||||
};
|
};
|
||||||
(signal, signal_idx)
|
(signal, signal_idx)
|
||||||
|
@ -155,7 +157,7 @@ fn parse_orphaned_vars<'a>(
|
||||||
child_signals: vec![],
|
child_signals: vec![],
|
||||||
child_scopes: 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
|
// 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();
|
let parent_scope = vcd.all_scopes.get_mut(parent_scope_idx).unwrap();
|
||||||
parent_scope.child_scopes.push(curr_scope_idx);
|
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
|
// add this scope to list of existing scopes
|
||||||
|
|
|
@ -115,7 +115,8 @@ macro_rules! curr_word {
|
||||||
($word_reader:ident) => {
|
($word_reader:ident) => {
|
||||||
$word_reader.curr_word().ok_or(()).map_err(|_| {
|
$word_reader.curr_word().ok_or(()).map_err(|_| {
|
||||||
format!(
|
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!(),
|
file!(),
|
||||||
line!()
|
line!()
|
||||||
)
|
)
|
||||||
|
|
193
src/vcd/signal.rs
Normal file
193
src/vcd/signal.rs
Normal 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()))
|
||||||
|
}
|
||||||
|
}
|
172
src/vcd/types.rs
172
src/vcd/types.rs
|
@ -1,6 +1,5 @@
|
||||||
use super::utilities::{ordered_binary_lookup_u8, LookupErrors};
|
use super::Signal;
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use num::{BigUint, Zero};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) struct Version(pub String);
|
pub(super) struct Version(pub String);
|
||||||
|
@ -23,77 +22,13 @@ pub(super) struct Metadata {
|
||||||
pub(super) timescale: (Option<u32>, Timescale),
|
pub(super) timescale: (Option<u32>, Timescale),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We do a lot of arena allocation in this codebase.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub(super) struct ScopeIdx(pub(super) usize);
|
pub(super) struct ScopeIdx(pub(super) usize);
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||||
pub(super) struct SignalIdx(pub(super) usize);
|
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)]
|
#[derive(Debug)]
|
||||||
pub(super) struct Scope {
|
pub(super) struct Scope {
|
||||||
pub(super) name: String,
|
pub(super) name: String,
|
||||||
|
@ -105,82 +40,63 @@ pub(super) struct Scope {
|
||||||
pub(super) child_scopes: Vec<ScopeIdx>,
|
pub(super) child_scopes: Vec<ScopeIdx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: document how timeline is represented
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VCD {
|
pub struct VCD {
|
||||||
pub(super) metadata: Metadata,
|
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
|
// 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.
|
// of u8.
|
||||||
pub timeline: Vec<u8>,
|
// We essentially fill ``tmstmps_encoded_as_u8s`` with BigUints converted
|
||||||
// we need to keep track of where a given time t sequence of u8 begins
|
// to sequences of little endian u8s.
|
||||||
// and ends in the timeline vector.
|
// It is up to the signals to keep track of the start/stop indices in the
|
||||||
pub timeline_markers: Vec<StartIdx>,
|
// 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_signals: Vec<Signal>,
|
||||||
pub(super) all_scopes: Vec<Scope>,
|
pub(super) all_scopes: Vec<Scope>,
|
||||||
pub(super) scope_roots: Vec<ScopeIdx>,
|
pub(super) root_scopes: Vec<ScopeIdx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VCD {
|
impl VCD {
|
||||||
// TODO : make this a generic traversal function that applies specified
|
/// We take in a Signal and attempt to dereference that signal if it is of
|
||||||
// functions upon encountering scopes and signals
|
/// variant Signal::Alias. If it is of variant Signal::Alias and points to
|
||||||
fn print_scope_tree(&self, root_scope_idx: ScopeIdx, depth: usize) {
|
/// another alias, that's an error. Otherwise, we return the Signal::Data
|
||||||
let all_scopes = &self.all_scopes;
|
/// pointed to by the Signal::Alias.
|
||||||
let all_signals = &self.all_signals;
|
/// 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);
|
// dereference signal if Signal::Alias, or keep idx if Signal::Data
|
||||||
let ScopeIdx(root_scope_idx) = root_scope_idx;
|
let signal_idx = match signal {
|
||||||
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 { .. } => {}
|
|
||||||
Signal::Data {
|
Signal::Data {
|
||||||
name,
|
name,
|
||||||
|
sig_type,
|
||||||
|
signal_error,
|
||||||
|
num_bits,
|
||||||
self_idx,
|
self_idx,
|
||||||
u8_timeline,
|
|
||||||
..
|
..
|
||||||
} => {
|
} => *self_idx,
|
||||||
if u8_timeline.len() > max_len {
|
Signal::Alias { name, signal_alias } => *signal_alias,
|
||||||
max_len = u8_timeline.len();
|
};
|
||||||
let SignalIdx(idx_usize) = self_idx;
|
|
||||||
idx = *idx_usize;
|
|
||||||
signal_name = name.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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!()
|
||||||
|
)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,100 +80,107 @@ use num::{BigUint, Zero};
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum LookupErrors {
|
pub(super) enum LookupErrors {
|
||||||
PreTimeline {
|
PreTimeline {
|
||||||
desired_time: TimelineIdx,
|
desired_time: BigUint,
|
||||||
timeline_start_time: TimelineIdx,
|
timeline_start_time: BigUint,
|
||||||
},
|
},
|
||||||
EmptyTimeline,
|
EmptyTimeline,
|
||||||
TimelineNotMultiple,
|
TimelineNotMultiple,
|
||||||
OrderingFailure,
|
OrderingFailure,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn ordered_binary_lookup_u8(
|
// pub(super) fn ordered_binary_lookup_u8(
|
||||||
value_sequence_as_bytes: &Vec<u8>,
|
// //(REMOVE THIS COMMENT)below is from self
|
||||||
bytes_per_value: usize,
|
// lsb_indxs_of_num_tmstmp_vals_on_tmln: &Vec<LsbIdxOfTmstmpValOnTmln>,
|
||||||
timeline_cursors: &Vec<TimelineIdx>,
|
// tmstmps_encoded_as_u8s: &Vec<u8>,
|
||||||
desired_time: TimelineIdx,
|
// //(REMOVE THIS COMMENT)below is from self
|
||||||
) -> Result<BigUint, LookupErrors> {
|
// nums_encoded_as_fixed_width_le_u8: &Vec<u8>,
|
||||||
// timeline must not be empty
|
// // TODO : should this be usize?
|
||||||
if timeline_cursors.is_empty() {
|
// bytes_per_value: usize,
|
||||||
return Err(LookupErrors::EmptyTimeline);
|
// 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
|
// // assertion that value_sequence is a proper multiple of
|
||||||
// timeline_markers
|
// // timeline_markers
|
||||||
if value_sequence_as_bytes.len() != (timeline_cursors.len() * bytes_per_value) {
|
// if lsb_indxs_of_num_tmstmp_vals_on_tmln.len()
|
||||||
return Err(LookupErrors::TimelineNotMultiple);
|
// != (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
|
// // check if we're requesting a value that occurs before the recorded
|
||||||
// start of the timeline
|
// // start of the timeline
|
||||||
let TimelineIdx(timeline_start_time) = timeline_cursors.first().unwrap();
|
// let TimelineIdx(timeline_start_time) = timeline_cursors.first().unwrap();
|
||||||
if desired_time < *timeline_start_time {
|
// if desired_time < *timeline_start_time {
|
||||||
return Err(LookupErrors::PreTimeline {
|
// return Err(LookupErrors::PreTimeline {
|
||||||
desired_time: TimelineIdx(desired_time),
|
// desired_time: TimelineIdx(desired_time),
|
||||||
timeline_start_time: TimelineIdx(*timeline_start_time),
|
// timeline_start_time: TimelineIdx(*timeline_start_time),
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
let mut lower_idx = 0usize;
|
// let mut lower_idx = 0usize;
|
||||||
let mut upper_idx = timeline_cursors.len() - 1;
|
// let mut upper_idx = timeline_cursors.len() - 1;
|
||||||
|
|
||||||
// check if we're requesting a value that occurs beyond the end of the timeline,
|
// // check if we're requesting a value that occurs beyond the end of the timeline,
|
||||||
// if so, return the last value in this timeline
|
// // if so, return the last value in this timeline
|
||||||
let TimelineIdx(timeline_end_time) = timeline_cursors.last().unwrap();
|
// let TimelineIdx(timeline_end_time) = timeline_cursors.last().unwrap();
|
||||||
if desired_time > *timeline_end_time {
|
// if desired_time > *timeline_end_time {
|
||||||
let range = (value_sequence_as_bytes.len() - bytes_per_value)..;
|
// let range = (value_sequence_as_bytes.len() - bytes_per_value)..;
|
||||||
let value_by_bytes = &value_sequence_as_bytes[range];
|
// let value_by_bytes = &value_sequence_as_bytes[range];
|
||||||
let value = BigUint::from_bytes_le(value_by_bytes);
|
// 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),
|
// // This while loop is the meat of the lookup. Performance is log2(n),
|
||||||
// where n is the number of events on the timeline.
|
// // where n is the number of events on the timeline.
|
||||||
// We can assume that by the time we get here, that the desired_time
|
// // 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
|
// // 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.
|
// // occuring after or before the recorded tiimeline in the code above.
|
||||||
while lower_idx <= upper_idx {
|
// while lower_idx <= upper_idx {
|
||||||
let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
|
// let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2);
|
||||||
let TimelineIdx(curr_time) = timeline_cursors[mid_idx];
|
// let TimelineIdx(curr_time) = timeline_cursors[mid_idx];
|
||||||
let ordering = curr_time.cmp(&desired_time);
|
// let ordering = curr_time.cmp(&desired_time);
|
||||||
|
|
||||||
match ordering {
|
// match ordering {
|
||||||
std::cmp::Ordering::Less => {
|
// std::cmp::Ordering::Less => {
|
||||||
lower_idx = mid_idx + 1;
|
// lower_idx = mid_idx + 1;
|
||||||
}
|
// }
|
||||||
std::cmp::Ordering::Equal => {
|
// std::cmp::Ordering::Equal => {
|
||||||
let u8_timeline_start_idx = mid_idx * bytes_per_value;
|
// let u8_timeline_start_idx = mid_idx * bytes_per_value;
|
||||||
let u8_timeline_end_idx = u8_timeline_start_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 range = u8_timeline_start_idx..u8_timeline_end_idx;
|
||||||
let value_by_bytes = &value_sequence_as_bytes[range];
|
// let value_by_bytes = &value_sequence_as_bytes[range];
|
||||||
let value = BigUint::from_bytes_le(value_by_bytes);
|
// let value = BigUint::from_bytes_le(value_by_bytes);
|
||||||
return Ok(value);
|
// return Ok(value);
|
||||||
}
|
// }
|
||||||
std::cmp::Ordering::Greater => {
|
// std::cmp::Ordering::Greater => {
|
||||||
upper_idx = mid_idx - 1;
|
// upper_idx = mid_idx - 1;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
let idx = lower_idx - 1;
|
// let idx = lower_idx - 1;
|
||||||
let TimelineIdx(left_time) = timeline_cursors[idx];
|
// let TimelineIdx(left_time) = timeline_cursors[idx];
|
||||||
let TimelineIdx(right_time) = timeline_cursors[idx + 1];
|
// let TimelineIdx(right_time) = timeline_cursors[idx + 1];
|
||||||
|
|
||||||
let ordered_left = left_time < desired_time;
|
// let ordered_left = left_time < desired_time;
|
||||||
let ordered_right = desired_time < right_time;
|
// let ordered_right = desired_time < right_time;
|
||||||
if !(ordered_left && ordered_right) {
|
// if !(ordered_left && ordered_right) {
|
||||||
return Err(LookupErrors::OrderingFailure);
|
// return Err(LookupErrors::OrderingFailure);
|
||||||
}
|
// }
|
||||||
|
|
||||||
let u8_timeline_start_idx = idx * bytes_per_value;
|
// let u8_timeline_start_idx = idx * bytes_per_value;
|
||||||
let u8_timeline_end_idx = u8_timeline_start_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 range = u8_timeline_start_idx..u8_timeline_end_idx;
|
||||||
let value_by_bytes = &value_sequence_as_bytes[range];
|
// let value_by_bytes = &value_sequence_as_bytes[range];
|
||||||
let value = BigUint::from_bytes_le(value_by_bytes);
|
// let value = BigUint::from_bytes_le(value_by_bytes);
|
||||||
|
|
||||||
return Ok(value);
|
// return Ok(value);
|
||||||
}
|
// }
|
||||||
|
|
Loading…
Reference in a new issue