Expose stuff #8

Merged
TheZoq2 merged 6 commits from expose_stuff into main 2023-07-02 00:20:05 +00:00
9 changed files with 146 additions and 61 deletions

View file

@ -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;

View file

@ -2,7 +2,6 @@
// This program is distributed under both the GPLV3 license // This program is distributed under both the GPLV3 license
// 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 std::fs::File;
mod combinator_atoms; mod combinator_atoms;
mod types; mod types;
@ -11,7 +10,7 @@ mod scopes;
mod events; mod events;
pub fn parse_vcd(file: File) -> Result<super::types::VCD, String> { pub fn parse_vcd(file: impl std::io::Read) -> Result<super::types::VCD, String> {
let mut word_gen = super::reader::WordReader::new(file); let mut word_gen = super::reader::WordReader::new(file);
let header = metadata::parse_metadata(&mut word_gen)?; let header = metadata::parse_metadata(&mut word_gen)?;
@ -27,10 +26,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)
} }

View file

@ -69,7 +69,10 @@ pub(super) fn tag<'a>(word: &'a str, pattern: &'a str) -> ParseResult<'a> {
}; };
} }
pub(super) fn ident(word_reader: &mut WordReader, keyword: &str) -> Result<(), String> { pub(super) fn ident<R: std::io::Read>(
word_reader: &mut WordReader<R>,
keyword: &str,
) -> Result<(), String> {
// let keyword = "module"; // let keyword = "module";
let (word, cursor) = next_word!(word_reader)?; let (word, cursor) = next_word!(word_reader)?;

View file

@ -12,8 +12,8 @@ use super::super::reader::{WordReader, Cursor, Line, Word, next_word};
use super::super::types::{SignalIdx, VCD}; use super::super::types::{SignalIdx, VCD};
pub(super) fn parse_events<'a>( pub(super) fn parse_events<'a, R: std::io::Read>(
word_reader: &mut WordReader, word_reader: &mut WordReader<R>,
vcd: &'a mut VCD, vcd: &'a mut VCD,
signal_map: &mut HashMap<String, SignalIdx>, signal_map: &mut HashMap<String, SignalIdx>,
) -> Result<(), String> { ) -> Result<(), String> {
@ -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 {

View file

@ -145,7 +145,7 @@ pub(super) fn parse_date(
)) ))
} }
pub(super) fn parse_version(word_reader: &mut WordReader) -> Result<Version, String> { pub(super) fn parse_version<R: std::io::Read>(word_reader: &mut WordReader<R>) -> Result<Version, String> {
let mut version = String::new(); let mut version = String::new();
loop { loop {
@ -162,8 +162,8 @@ pub(super) fn parse_version(word_reader: &mut WordReader) -> Result<Version, Str
} }
} }
pub(super) fn parse_timescale( pub(super) fn parse_timescale<R: std::io::Read>(
word_reader: &mut WordReader, word_reader: &mut WordReader<R>,
) -> Result<(Option<u32>, Timescale), String> { ) -> Result<(Option<u32>, Timescale), String> {
// we might see `1ps $end` or `1 ps $end` // we might see `1ps $end` or `1 ps $end`
// first get timescale // first get timescale
@ -220,7 +220,7 @@ pub(super) fn parse_timescale(
return Ok(timescale); return Ok(timescale);
} }
pub(super) fn parse_metadata(word_reader: &mut WordReader) -> Result<Metadata, String> { pub(super) fn parse_metadata<R: std::io::Read>(word_reader: &mut WordReader<R>) -> Result<Metadata, String> {
let mut metadata = Metadata { let mut metadata = Metadata {
date: None, date: None,
version: None, version: None,

View file

@ -15,11 +15,12 @@ use super::super::signal::{SigType, SignalEnum};
use super::combinator_atoms::{tag, ident}; use super::combinator_atoms::{tag, ident};
use super::types::{ParseResult}; use super::types::{ParseResult};
pub(super) fn parse_var<'a>( pub(super) fn parse_var<'a, R: std::io::Read>(
word_reader: &mut WordReader, word_reader: &mut WordReader<R>,
parent_scope_idx: ScopeIdx, parent_scope_idx: ScopeIdx,
vcd: &'a mut VCD, vcd: &'a mut VCD,
signal_map: &mut HashMap<String, SignalIdx>, signal_map: &mut HashMap<String, SignalIdx>,
path: &Vec<String>,
) -> Result<(), String> { ) -> Result<(), String> {
let (word, cursor) = next_word!(word_reader)?; let (word, cursor) = next_word!(word_reader)?;
let expected_types = [ let expected_types = [
@ -97,7 +98,11 @@ pub(super) fn parse_var<'a>(
let (word, _) = next_word!(word_reader)?; let (word, _) = next_word!(word_reader)?;
match word { match word {
"$end" => break, "$end" => break,
_ => full_signal_name.push(word.to_string()), other => {
if !other.starts_with("[") {
full_signal_name.push(word.to_string())
}
}
} }
} }
let full_signal_name = full_signal_name.join(" "); let full_signal_name = full_signal_name.join(" ");
@ -116,7 +121,8 @@ pub(super) fn parse_var<'a>(
Some(ref_signal_idx) => { Some(ref_signal_idx) => {
let signal_idx = SignalIdx(vcd.all_signals.len()); let signal_idx = SignalIdx(vcd.all_signals.len());
let signal = SignalEnum::Alias { let signal = SignalEnum::Alias {
name: full_signal_name, name: full_signal_name.clone(),
path: path.iter().cloned().chain([full_signal_name]).collect::<Vec<String>>(),
signal_alias: *ref_signal_idx, signal_alias: *ref_signal_idx,
}; };
(signal, signal_idx) (signal, signal_idx)
@ -125,11 +131,12 @@ pub(super) fn parse_var<'a>(
let signal_idx = SignalIdx(vcd.all_signals.len()); let signal_idx = SignalIdx(vcd.all_signals.len());
signal_map.insert(signal_alias.to_string(), signal_idx); signal_map.insert(signal_alias.to_string(), signal_idx);
let signal = SignalEnum::Data { let signal = SignalEnum::Data {
name: full_signal_name, name: full_signal_name.clone(),
path: path.iter().cloned().chain([full_signal_name]).collect::<Vec<String>>(),
sig_type: var_type, sig_type: var_type,
signal_error: None, signal_error: None,
num_bits: num_bits, num_bits,
num_bytes: num_bytes, num_bytes,
self_idx: signal_idx, self_idx: signal_idx,
nums_encoded_as_fixed_width_le_u8: vec![], nums_encoded_as_fixed_width_le_u8: vec![],
string_vals: vec![], string_vals: vec![],
@ -137,7 +144,6 @@ pub(super) fn parse_var<'a>(
byte_len_of_num_tmstmp_vals_on_tmln: vec![], byte_len_of_num_tmstmp_vals_on_tmln: vec![],
byte_len_of_string_tmstmp_vals_on_tmln: vec![], byte_len_of_string_tmstmp_vals_on_tmln: vec![],
lsb_indxs_of_string_tmstmp_vals_on_tmln: vec![], lsb_indxs_of_string_tmstmp_vals_on_tmln: vec![],
scope_parent: parent_scope_idx,
}; };
(signal, signal_idx) (signal, signal_idx)
} }
@ -153,8 +159,8 @@ pub(super) fn parse_var<'a>(
/// Sometimes, variables can be listed outside of scopes. /// Sometimes, variables can be listed outside of scopes.
/// We call these orphaned vars. /// We call these orphaned vars.
fn parse_orphaned_vars<'a>( fn parse_orphaned_vars<'a, R: std::io::Read>(
word_reader: &mut WordReader, word_reader: &mut WordReader<R>,
vcd: &'a mut VCD, vcd: &'a mut VCD,
signal_map: &mut HashMap<String, SignalIdx>, signal_map: &mut HashMap<String, SignalIdx>,
) -> Result<(), String> { ) -> Result<(), String> {
@ -181,7 +187,6 @@ fn parse_orphaned_vars<'a>(
if !scope_already_exists { if !scope_already_exists {
vcd.all_scopes.push(Scope { vcd.all_scopes.push(Scope {
name: scope_name.to_string(), name: scope_name.to_string(),
parent_idx: None,
self_idx: scope_idx, self_idx: scope_idx,
child_signals: vec![], child_signals: vec![],
child_scopes: vec![], child_scopes: vec![],
@ -191,14 +196,14 @@ fn parse_orphaned_vars<'a>(
// 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
// "$var" before now. // "$var" before now.
parse_var(word_reader, scope_idx, vcd, signal_map)?; parse_var(word_reader, scope_idx, vcd, signal_map, &vec![])?;
loop { loop {
let (word, cursor) = next_word!(word_reader)?; let (word, cursor) = next_word!(word_reader)?;
match word { match word {
"$var" => { "$var" => {
parse_var(word_reader, scope_idx, vcd, signal_map)?; parse_var(word_reader, scope_idx, vcd, signal_map, &vec![])?;
} }
"$scope" => break, "$scope" => break,
_ => { _ => {
@ -217,11 +222,12 @@ fn parse_orphaned_vars<'a>(
Ok(()) Ok(())
} }
fn parse_scopes_inner<'a>( fn parse_scopes_inner<'a, R: std::io::Read>(
word_reader: &mut WordReader, word_reader: &mut WordReader<R>,
parent_scope_idx: Option<ScopeIdx>, parent_scope_idx: Option<ScopeIdx>,
vcd: &'a mut VCD, vcd: &'a mut VCD,
signal_map: &mut HashMap<String, SignalIdx>, signal_map: &mut HashMap<String, SignalIdx>,
path: &Vec<String>
) -> Result<(), String> { ) -> Result<(), String> {
// $scope module reg_mag_i $end // $scope module reg_mag_i $end
// ^^^^^^ - module keyword // ^^^^^^ - module keyword
@ -245,6 +251,9 @@ fn parse_scopes_inner<'a>(
// ^^^^^^^^^ - scope name // ^^^^^^^^^ - scope name
let (scope_name, _) = next_word!(word_reader)?; let (scope_name, _) = next_word!(word_reader)?;
let mut path = path.clone();
path.push(scope_name.to_string());
let curr_scope_idx = ScopeIdx(vcd.all_scopes.len()); let curr_scope_idx = ScopeIdx(vcd.all_scopes.len());
// register this scope as a child of the current parent scope // register this scope as a child of the current parent scope
@ -261,7 +270,6 @@ fn parse_scopes_inner<'a>(
// add this scope to list of existing scopes // add this scope to list of existing scopes
vcd.all_scopes.push(Scope { vcd.all_scopes.push(Scope {
name: scope_name.to_string(), name: scope_name.to_string(),
parent_idx: parent_scope_idx,
self_idx: curr_scope_idx, self_idx: curr_scope_idx,
child_signals: vec![], child_signals: vec![],
child_scopes: vec![], child_scopes: vec![],
@ -271,6 +279,8 @@ fn parse_scopes_inner<'a>(
// ^^^^ - end keyword // ^^^^ - end keyword
ident(word_reader, "$end")?; ident(word_reader, "$end")?;
loop { loop {
let (word, cursor) = next_word!(word_reader)?; let (word, cursor) = next_word!(word_reader)?;
let ParseResult { matched, residual } = tag(word, "$"); let ParseResult { matched, residual } = tag(word, "$");
@ -280,10 +290,10 @@ fn parse_scopes_inner<'a>(
match residual { match residual {
"scope" => { "scope" => {
// recursive - parse inside of current scope tree // recursive - parse inside of current scope tree
parse_scopes_inner(word_reader, Some(curr_scope_idx), vcd, signal_map)?; parse_scopes_inner(word_reader, Some(curr_scope_idx), vcd, signal_map, &path)?;
} }
"var" => { "var" => {
parse_var(word_reader, curr_scope_idx, vcd, signal_map)?; parse_var(word_reader, curr_scope_idx, vcd, signal_map, &path)?;
} }
"upscope" => { "upscope" => {
ident(word_reader, "$end")?; ident(word_reader, "$end")?;
@ -324,8 +334,8 @@ fn parse_scopes_inner<'a>(
Ok(()) Ok(())
} }
pub(super) fn parse_scopes<'a>( pub(super) fn parse_scopes<'a, R: std::io::Read>(
word_reader: &mut WordReader, word_reader: &mut WordReader<R>,
vcd: &'a mut VCD, vcd: &'a mut VCD,
signal_map: &mut HashMap<String, SignalIdx>, signal_map: &mut HashMap<String, SignalIdx>,
) -> Result<(), String> { ) -> Result<(), String> {
@ -356,7 +366,7 @@ pub(super) fn parse_scopes<'a>(
} }
// now for the interesting part // now for the interesting part
parse_scopes_inner(word_reader, None, vcd, signal_map)?; parse_scopes_inner(word_reader, None, vcd, signal_map, &vec![])?;
// let err = format!("reached end of file without parser leaving {}", function_name!()); // let err = format!("reached end of file without parser leaving {}", function_name!());
let expected_keywords = ["$scope", "$enddefinitions"]; let expected_keywords = ["$scope", "$enddefinitions"];
@ -370,7 +380,7 @@ pub(super) fn parse_scopes<'a>(
match word { match word {
"$scope" => { "$scope" => {
parse_scopes_inner(word_reader, None, vcd, signal_map)?; parse_scopes_inner(word_reader, None, vcd, signal_map, &vec![])?;
} }
"$enddefinitions" => { "$enddefinitions" => {
ident(word_reader, "$end")?; ident(word_reader, "$end")?;

View file

@ -3,7 +3,6 @@
// 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 std::collections::VecDeque; use std::collections::VecDeque;
use std::fs::File;
use std::io; use std::io;
use std::io::BufRead; use std::io::BufRead;
use std::slice; use std::slice;
@ -16,8 +15,8 @@ pub(super) struct Word(pub(super) usize);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(super) struct Cursor(pub(super) Line, pub(super) Word); pub(super) struct Cursor(pub(super) Line, pub(super) Word);
pub(super) struct WordReader { pub(super) struct WordReader<R: io::Read> {
reader: io::BufReader<File>, reader: io::BufReader<R>,
eof: bool, eof: bool,
buffers: Vec<String>, buffers: Vec<String>,
curr_line: usize, curr_line: usize,
@ -25,11 +24,11 @@ pub(super) struct WordReader {
curr_slice: Option<(*const u8, usize, Cursor)>, curr_slice: Option<(*const u8, usize, Cursor)>,
} }
impl WordReader { impl<R: std::io::Read> WordReader<R> {
pub(super) fn new(file: File) -> WordReader { pub(super) fn new(file: R) -> WordReader<R> {
let reader = io::BufReader::new(file); let reader = io::BufReader::new(file);
WordReader { WordReader {
reader: reader, reader,
eof: false, eof: false,
buffers: vec![], buffers: vec![],
curr_line: 0, curr_line: 0,

View file

@ -2,9 +2,9 @@
// This program is distributed under both the GPLV3 license // This program is distributed under both the GPLV3 license
// 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 super::types::{ScopeIdx, SignalIdx}; use super::types::SignalIdx;
use super::types; use super::types;
use num::{BigUint}; use num::BigUint;
// Index to the least significant byte of a timestamp // Index to the least significant byte of a timestamp
// value on the timeline // value on the timeline
@ -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,26 @@ impl<'a> Signal<'a> {
let Signal(signal_enum) = &self; let Signal(signal_enum) = &self;
signal_enum.name() signal_enum.name()
} }
pub fn path(&self) -> &[String] {
match self.0 {
SignalEnum::Data {path, ..} => path,
SignalEnum::Alias { path, .. } => path,
}
}
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 +63,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<(TimeStamp, 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((num_time, SignalValue::BigUint(num_val)))
}
else {
Ok((str_time, SignalValue::String(str_val)))
}
}
(Ok((num_val, time)), Err(_)) => Ok((time, SignalValue::BigUint(num_val))),
(Err(_), Ok((str_val, time))) => Ok((time, SignalValue::String(str_val))),
(Err(e), _e) => Err(e)
}
} }
} }
@ -58,6 +108,7 @@ impl<'a> Signal<'a> {
pub(super) enum SignalEnum { pub(super) enum SignalEnum {
Data { Data {
name: String, name: String,
path: Vec<String>,
sig_type: SigType, sig_type: SigType,
/// I've seen a 0 bit signal parameter in a xilinx /// I've seen a 0 bit signal parameter in a xilinx
/// simulation before that gets assigned 1 bit values. /// simulation before that gets assigned 1 bit values.
@ -93,10 +144,10 @@ pub(super) enum SignalEnum {
byte_len_of_num_tmstmp_vals_on_tmln: Vec<u8>, byte_len_of_num_tmstmp_vals_on_tmln: Vec<u8>,
byte_len_of_string_tmstmp_vals_on_tmln: Vec<u8>, byte_len_of_string_tmstmp_vals_on_tmln: Vec<u8>,
lsb_indxs_of_string_tmstmp_vals_on_tmln: Vec<LsbIdxOfTmstmpValOnTmln>, lsb_indxs_of_string_tmstmp_vals_on_tmln: Vec<LsbIdxOfTmstmpValOnTmln>,
scope_parent: ScopeIdx,
}, },
Alias { Alias {
name: String, name: String,
path: Vec<String>,
signal_alias: SignalIdx, signal_alias: SignalIdx,
}, },
} }
@ -187,6 +238,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 +308,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 { .. } => None,
}
}
} }
// Val and string query functions. // Val and string query functions.
@ -265,7 +328,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;
@ -274,6 +337,7 @@ impl SignalEnum {
Self::Alias { Self::Alias {
name: _, name: _,
signal_alias, signal_alias,
path: _
} => { } => {
let SignalIdx(idx) = signal_alias; let SignalIdx(idx) = signal_alias;
*idx *idx
@ -319,7 +383,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 +395,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 +414,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 +437,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;
@ -388,6 +452,7 @@ impl SignalEnum {
} }
Self::Alias { Self::Alias {
name: _, name: _,
path: _,
signal_alias, signal_alias,
} => { } => {
let SignalIdx(idx) = signal_alias; let SignalIdx(idx) = signal_alias;
@ -449,7 +514,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 +526,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 +545,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 +568,6 @@ impl SignalEnum {
}); });
} }
return Ok(left_val); Ok((left_val, left_time))
} }
} }

View file

@ -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)]
@ -29,17 +30,16 @@ pub struct Metadata {
} }
// We do a lot of arena allocation in this codebase. // We do a lot of arena allocation in this codebase.
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ScopeIdx(pub usize); pub struct ScopeIdx(pub usize);
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct SignalIdx(pub usize); pub struct SignalIdx(pub usize);
#[derive(Debug)] #[derive(Debug)]
pub(super) struct Scope { pub(super) struct Scope {
pub(super) name: String, pub(super) name: String,
pub(super) parent_idx: Option<ScopeIdx>,
pub(super) self_idx: ScopeIdx, pub(super) self_idx: ScopeIdx,
pub(super) child_signals: Vec<SignalIdx>, pub(super) child_signals: Vec<SignalIdx>,
@ -63,6 +63,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 +122,8 @@ impl VCD {
)), )),
} }
} }
pub fn max_timestamp(&self) -> &Option<BigUint> {
&self.largest_timestamp
}
} }