non trivial re-factor
This commit is contained in:
parent
cbd8be1708
commit
15a2564f13
|
@ -7,5 +7,8 @@ pub(super) use types::*;
|
|||
mod parse;
|
||||
pub(super) use parse::*;
|
||||
|
||||
mod signal;
|
||||
pub(super) use signal::*;
|
||||
|
||||
mod 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
|
||||
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)?;
|
||||
|
|
|
@ -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)
|
||||
// }
|
||||
// }?;
|
||||
// }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
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 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!()
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
// }
|
||||
|
|
Loading…
Reference in a new issue