Add more timing information
This commit is contained in:
parent
b162d67a9d
commit
3da3579213
|
@ -7,6 +7,6 @@ mod vcd;
|
||||||
pub use vcd::parse::parse_vcd;
|
pub use vcd::parse::parse_vcd;
|
||||||
pub use vcd::types::{ScopeIdx, SignalIdx, VCD};
|
pub use vcd::types::{ScopeIdx, SignalIdx, VCD};
|
||||||
pub use vcd::types::{Metadata, Timescale, Version};
|
pub use vcd::types::{Metadata, Timescale, Version};
|
||||||
pub use vcd::signal::{Signal};
|
pub use vcd::signal::{Signal, SignalValue};
|
||||||
|
|
||||||
pub use num::BigUint;
|
pub use num::BigUint;
|
||||||
|
|
|
@ -27,10 +27,11 @@ pub fn parse_vcd(file: File) -> Result<super::types::VCD, String> {
|
||||||
all_signals: vec![],
|
all_signals: vec![],
|
||||||
all_scopes: vec![],
|
all_scopes: vec![],
|
||||||
root_scopes: vec![],
|
root_scopes: vec![],
|
||||||
|
largest_timestamp: None
|
||||||
};
|
};
|
||||||
|
|
||||||
scopes::parse_scopes(&mut word_gen, &mut vcd, &mut signal_map)?;
|
scopes::parse_scopes(&mut word_gen, &mut vcd, &mut signal_map)?;
|
||||||
events::parse_events(&mut word_gen, &mut vcd, &mut signal_map)?;
|
events::parse_events(&mut word_gen, &mut vcd, &mut signal_map)?;
|
||||||
|
|
||||||
Ok(vcd)
|
Ok(vcd)
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,14 +40,14 @@ pub(super) fn parse_events<'a>(
|
||||||
"#" => {
|
"#" => {
|
||||||
let value = &word[1..];
|
let value = &word[1..];
|
||||||
let (f, l) = (file!(), line!());
|
let (f, l) = (file!(), line!());
|
||||||
let value = BigUint::parse_bytes(value.as_bytes(), 10)
|
let value_biguint = BigUint::parse_bytes(value.as_bytes(), 10)
|
||||||
.ok_or(())
|
.ok_or(())
|
||||||
.map_err(|_| {
|
.map_err(|_| {
|
||||||
format!(
|
format!(
|
||||||
"Error near {f}:{l}. Failed to parse {value} as BigInt at {cursor:?}"
|
"Error near {f}:{l}. Failed to parse {value} as BigInt at {cursor:?}"
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
let mut value = value.to_bytes_le();
|
let mut value = value_biguint.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.
|
||||||
curr_tmstmp_len_u8 = u8::try_from(value.len()).map_err(|_| {
|
curr_tmstmp_len_u8 = u8::try_from(value.len()).map_err(|_| {
|
||||||
|
@ -66,6 +66,7 @@ pub(super) fn parse_events<'a>(
|
||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
vcd.tmstmps_encoded_as_u8s.append(&mut value);
|
vcd.tmstmps_encoded_as_u8s.append(&mut value);
|
||||||
|
vcd.largest_timestamp = Some(value_biguint);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -134,6 +135,7 @@ pub(super) fn parse_events<'a>(
|
||||||
lsb_indxs_of_num_tmstmp_vals_on_tmln,
|
lsb_indxs_of_num_tmstmp_vals_on_tmln,
|
||||||
byte_len_of_num_tmstmp_vals_on_tmln,
|
byte_len_of_num_tmstmp_vals_on_tmln,
|
||||||
lsb_indxs_of_string_tmstmp_vals_on_tmln,
|
lsb_indxs_of_string_tmstmp_vals_on_tmln,
|
||||||
|
byte_len_of_string_tmstmp_vals_on_tmln,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
// we've already identified in a prior loop iteration that the signal has
|
// we've already identified in a prior loop iteration that the signal has
|
||||||
|
@ -176,6 +178,7 @@ pub(super) fn parse_events<'a>(
|
||||||
if store_as_string {
|
if store_as_string {
|
||||||
lsb_indxs_of_string_tmstmp_vals_on_tmln
|
lsb_indxs_of_string_tmstmp_vals_on_tmln
|
||||||
.push(LsbIdxOfTmstmpValOnTmln(curr_tmstmp_lsb_idx));
|
.push(LsbIdxOfTmstmpValOnTmln(curr_tmstmp_lsb_idx));
|
||||||
|
byte_len_of_string_tmstmp_vals_on_tmln.push(curr_tmstmp_len_u8);
|
||||||
string_vals.push(value_string);
|
string_vals.push(value_string);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -23,8 +23,8 @@ pub enum SigType {
|
||||||
Time,
|
Time,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub(super) enum TimelineQueryResults {
|
pub enum SignalValue {
|
||||||
BigUint(BigUint),
|
BigUint(BigUint),
|
||||||
String(String),
|
String(String),
|
||||||
}
|
}
|
||||||
|
@ -36,13 +36,19 @@ impl<'a> Signal<'a> {
|
||||||
let Signal(signal_enum) = &self;
|
let Signal(signal_enum) = &self;
|
||||||
signal_enum.name()
|
signal_enum.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn num_bits(&self) -> Option<u16> {
|
||||||
|
let Signal(signal_enum) = &self;
|
||||||
|
signal_enum.bits_required()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn query_string_val_on_tmln(
|
pub fn query_string_val_on_tmln(
|
||||||
&self,
|
&self,
|
||||||
desired_time: &BigUint,
|
desired_time: &BigUint,
|
||||||
vcd: &types::VCD,
|
vcd: &types::VCD,
|
||||||
) -> Result<String, SignalErrors> {
|
) -> Result<String, SignalErrors> {
|
||||||
let Signal(signal_enum) = &self;
|
let Signal(signal_enum) = &self;
|
||||||
signal_enum.query_string_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals)
|
signal_enum.query_string_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals).map(|(val, _)| val)
|
||||||
}
|
}
|
||||||
pub fn query_num_val_on_tmln(
|
pub fn query_num_val_on_tmln(
|
||||||
&self,
|
&self,
|
||||||
|
@ -50,7 +56,44 @@ impl<'a> Signal<'a> {
|
||||||
vcd: &types::VCD,
|
vcd: &types::VCD,
|
||||||
) -> Result<BigUint, SignalErrors> {
|
) -> Result<BigUint, SignalErrors> {
|
||||||
let Signal(signal_enum) = &self;
|
let Signal(signal_enum) = &self;
|
||||||
signal_enum.query_num_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals)
|
signal_enum.query_num_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals).map(|(val, _)| val)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn query_val_on_tmln(
|
||||||
|
&self,
|
||||||
|
desired_time: &BigUint,
|
||||||
|
vcd: &types::VCD,
|
||||||
|
) -> Result<SignalValue, SignalErrors> {
|
||||||
|
let Signal(signal_enum) = &self;
|
||||||
|
let num_val = signal_enum
|
||||||
|
.query_num_val_on_tmln(
|
||||||
|
desired_time,
|
||||||
|
&vcd.tmstmps_encoded_as_u8s,
|
||||||
|
&vcd.all_signals
|
||||||
|
);
|
||||||
|
let str_val = signal_enum
|
||||||
|
.query_string_val_on_tmln(
|
||||||
|
desired_time,
|
||||||
|
&vcd.tmstmps_encoded_as_u8s,
|
||||||
|
&vcd.all_signals
|
||||||
|
);
|
||||||
|
|
||||||
|
// Both num and str will return the newest value that is closest to
|
||||||
|
// the desired time. If both have valid values, select the most recent
|
||||||
|
// one
|
||||||
|
match (num_val, str_val) {
|
||||||
|
(Ok((num_val, num_time)), Ok((str_val, str_time))) => {
|
||||||
|
if num_time > str_time {
|
||||||
|
Ok(SignalValue::BigUint(num_val))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Ok(SignalValue::String(str_val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(Ok((num_val, _)), Err(_)) => Ok(SignalValue::BigUint(num_val)),
|
||||||
|
(Err(_), Ok((str_val, _))) => Ok(SignalValue::String(str_val)),
|
||||||
|
(Err(e), _e) => Err(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +230,10 @@ impl SignalEnum {
|
||||||
lsb_indxs_of_string_tmstmp_vals_on_tmln[event_idx];
|
lsb_indxs_of_string_tmstmp_vals_on_tmln[event_idx];
|
||||||
let timestamp_idx = timestamp_idx as usize;
|
let timestamp_idx = timestamp_idx as usize;
|
||||||
|
|
||||||
|
if byte_len_of_string_tmstmp_vals_on_tmln.is_empty() {
|
||||||
|
return Err(SignalErrors::EmptyTimeline);
|
||||||
|
}
|
||||||
|
|
||||||
// form timestamp
|
// form timestamp
|
||||||
let byte_len = byte_len_of_string_tmstmp_vals_on_tmln[event_idx] as usize;
|
let byte_len = byte_len_of_string_tmstmp_vals_on_tmln[event_idx] as usize;
|
||||||
let timestamp = &tmstmps_encoded_as_u8s[timestamp_idx..(timestamp_idx + byte_len)];
|
let timestamp = &tmstmps_encoded_as_u8s[timestamp_idx..(timestamp_idx + byte_len)];
|
||||||
|
@ -253,6 +300,14 @@ impl SignalEnum {
|
||||||
|
|
||||||
Ok((timestamp, signal_val))
|
Ok((timestamp, signal_val))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bits_required(&self) -> Option<u16> {
|
||||||
|
match self {
|
||||||
|
SignalEnum::Data {num_bits, ..} => num_bits.clone(),
|
||||||
|
// TODO: Follow aliases?
|
||||||
|
SignalEnum::Alias { name, signal_alias } => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Val and string query functions.
|
// Val and string query functions.
|
||||||
|
@ -265,7 +320,7 @@ impl SignalEnum {
|
||||||
desired_time: &BigUint,
|
desired_time: &BigUint,
|
||||||
tmstmps_encoded_as_u8s: &Vec<u8>,
|
tmstmps_encoded_as_u8s: &Vec<u8>,
|
||||||
all_signals: &Vec<SignalEnum>,
|
all_signals: &Vec<SignalEnum>,
|
||||||
) -> Result<String, SignalErrors> {
|
) -> Result<(String, TimeStamp), SignalErrors> {
|
||||||
let signal_idx = match self {
|
let signal_idx = match self {
|
||||||
Self::Data { self_idx, .. } => {
|
Self::Data { self_idx, .. } => {
|
||||||
let SignalIdx(idx) = self_idx;
|
let SignalIdx(idx) = self_idx;
|
||||||
|
@ -319,7 +374,7 @@ impl SignalEnum {
|
||||||
if *desired_time < timeline_start_time {
|
if *desired_time < timeline_start_time {
|
||||||
return Err(SignalErrors::PreTimeline {
|
return Err(SignalErrors::PreTimeline {
|
||||||
desired_time: desired_time.clone(),
|
desired_time: desired_time.clone(),
|
||||||
timeline_start_time: timeline_start_time,
|
timeline_start_time,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +386,7 @@ impl SignalEnum {
|
||||||
// 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
|
||||||
if *desired_time > timeline_end_time {
|
if *desired_time > timeline_end_time {
|
||||||
return Ok(timeline_end_val.to_string());
|
return Ok((timeline_end_val.to_string(), timeline_end_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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),
|
||||||
|
@ -350,7 +405,7 @@ impl SignalEnum {
|
||||||
lower_idx = mid_idx + 1;
|
lower_idx = mid_idx + 1;
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Equal => {
|
std::cmp::Ordering::Equal => {
|
||||||
return Ok(curr_val.to_string());
|
return Ok((curr_val.to_string(), curr_time));
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Greater => {
|
std::cmp::Ordering::Greater => {
|
||||||
upper_idx = mid_idx - 1;
|
upper_idx = mid_idx - 1;
|
||||||
|
@ -373,14 +428,14 @@ impl SignalEnum {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(left_val.to_string());
|
Ok((left_val.to_string(), left_time))
|
||||||
}
|
}
|
||||||
pub fn query_num_val_on_tmln(
|
pub fn query_num_val_on_tmln(
|
||||||
&self,
|
&self,
|
||||||
desired_time: &BigUint,
|
desired_time: &BigUint,
|
||||||
tmstmps_encoded_as_u8s: &Vec<u8>,
|
tmstmps_encoded_as_u8s: &Vec<u8>,
|
||||||
all_signals: &Vec<SignalEnum>,
|
all_signals: &Vec<SignalEnum>,
|
||||||
) -> Result<BigUint, SignalErrors> {
|
) -> Result<(BigUint, TimeStamp), SignalErrors> {
|
||||||
let signal_idx = match self {
|
let signal_idx = match self {
|
||||||
Self::Data { self_idx, .. } => {
|
Self::Data { self_idx, .. } => {
|
||||||
let SignalIdx(idx) = self_idx;
|
let SignalIdx(idx) = self_idx;
|
||||||
|
@ -449,7 +504,7 @@ impl SignalEnum {
|
||||||
if *desired_time < timeline_start_time {
|
if *desired_time < timeline_start_time {
|
||||||
return Err(SignalErrors::PreTimeline {
|
return Err(SignalErrors::PreTimeline {
|
||||||
desired_time: desired_time.clone(),
|
desired_time: desired_time.clone(),
|
||||||
timeline_start_time: timeline_start_time,
|
timeline_start_time,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,7 +516,7 @@ impl SignalEnum {
|
||||||
// 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
|
||||||
if *desired_time > timeline_end_time {
|
if *desired_time > timeline_end_time {
|
||||||
return Ok(timeline_end_val);
|
return Ok((timeline_end_val, timeline_end_time));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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),
|
||||||
|
@ -480,7 +535,7 @@ impl SignalEnum {
|
||||||
lower_idx = mid_idx + 1;
|
lower_idx = mid_idx + 1;
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Equal => {
|
std::cmp::Ordering::Equal => {
|
||||||
return Ok(curr_val);
|
return Ok((curr_val, curr_time));
|
||||||
}
|
}
|
||||||
std::cmp::Ordering::Greater => {
|
std::cmp::Ordering::Greater => {
|
||||||
upper_idx = mid_idx - 1;
|
upper_idx = mid_idx - 1;
|
||||||
|
@ -503,6 +558,6 @@ impl SignalEnum {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(left_val);
|
Ok((left_val, left_time))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
// and the YEHOWSHUA license, both of which can be found at
|
// and the YEHOWSHUA license, both of which can be found at
|
||||||
// the root of the folder containing the sources for this program.
|
// the root of the folder containing the sources for this program.
|
||||||
use chrono::prelude::{DateTime, Utc};
|
use chrono::prelude::{DateTime, Utc};
|
||||||
|
use num::BigUint;
|
||||||
use super::signal::{Signal, SignalEnum};
|
use super::signal::{Signal, SignalEnum};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -63,6 +64,7 @@ pub struct VCD {
|
||||||
pub(super) all_signals: Vec<SignalEnum>,
|
pub(super) all_signals: Vec<SignalEnum>,
|
||||||
pub(super) all_scopes: Vec<Scope>,
|
pub(super) all_scopes: Vec<Scope>,
|
||||||
pub(super) root_scopes: Vec<ScopeIdx>,
|
pub(super) root_scopes: Vec<ScopeIdx>,
|
||||||
|
pub(super) largest_timestamp: Option<BigUint>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VCD {
|
impl VCD {
|
||||||
|
@ -121,4 +123,8 @@ impl VCD {
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn max_timestamp(&self) -> &Option<BigUint> {
|
||||||
|
&self.largest_timestamp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue