Merge pull request #6 from ThePerfectComputer/refactor-signal

Refactor signal
This commit is contained in:
ThePerfectComputer 2022-10-26 02:23:08 -04:00 committed by GitHub
commit f95db0cd2d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 177 additions and 195 deletions

View file

@ -95,11 +95,8 @@ Here's a command to test on a malformed VCD:
- [ ] once the access patterns of the GUI frontend are well understood, - [ ] once the access patterns of the GUI frontend are well understood,
create specific functions and restrict as many types to private create specific functions and restrict as many types to private
as possible as possible
- [ ] be explicit with imports, remove exports as possible
once FastWave is known to be fairly stable.
- [ ] Print out git commit or release number. - [ ] Print out git commit or release number.
- [ ] do a read through all the code - look for uneeded code - [ ] do a read through all the code - look for uneeded code
- [ ] Take a look at GTKWave parser to compare efficiency.
- [ ] Move part of the performance section to another markdown file. - [ ] Move part of the performance section to another markdown file.
## Repairs ## Repairs
@ -111,7 +108,6 @@ Here's a command to test on a malformed VCD:
able to successfully parse all sample VCDs. able to successfully parse all sample VCDs.
## Code Consistency ## Code Consistency
- [ ] split impls in signal.rs into groups
- [ ] Change error messages to line and filenames. Go through all calls to unwrap. - [ ] Change error messages to line and filenames. Go through all calls to unwrap.
- [ ] search for any unwraps or any direct vectors indexing - [ ] search for any unwraps or any direct vectors indexing
- [ ] Handle TODOs - [ ] Handle TODOs

View file

@ -5,9 +5,7 @@
use clap::Parser; use clap::Parser;
use std::fs::File; use std::fs::File;
use fastwave_backend::*; use fastwave_backend::parse_vcd;
use num::{BigUint};
#[derive(Parser)] #[derive(Parser)]
struct Cli { struct Cli {
@ -23,7 +21,7 @@ fn main() -> std::io::Result<()> {
let now = Instant::now(); let now = Instant::now();
let file = File::open(&args.path)?; let file = File::open(&args.path)?;
let vcd = parse_vcd(file).unwrap(); parse_vcd(file).unwrap();
let elapsed = now.elapsed(); let elapsed = now.elapsed();
println!("Parsed VCD file {} : {:.2?}", &args.path.as_os_str().to_str().unwrap(), elapsed); println!("Parsed VCD file {} : {:.2?}", &args.path.as_os_str().to_str().unwrap(), elapsed);

View file

@ -4,9 +4,7 @@
// 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; use std::fs::File;
use fastwave_backend::*; use fastwave_backend::{ScopeIdx, VCD, parse_vcd, SignalIdx};
use num::{BigUint};
fn indented_print(indent : u8, name : &String) { fn indented_print(indent : u8, name : &String) {
for _ in 0..indent {print!(" |");} for _ in 0..indent {print!(" |");}
@ -14,21 +12,26 @@ fn indented_print(indent : u8, name : &String) {
println!("{name}"); println!("{name}");
} }
fn print_root_scope_tree(root_idx: ScopeIdx, vcd: &VCD, indent : u8) { // TODO: refactor into more general visitor pattern that takes a
// function as an argument.
fn visit_all_scopes(vcd: &VCD) {
fn visit_all_scope_children(root_idx: ScopeIdx, vcd: &VCD, indent : u8) {
if vcd.child_scopes_by_idx(root_idx).is_empty() { if vcd.child_scopes_by_idx(root_idx).is_empty() {
} else { } else {
for child_scope_idx in vcd.child_scopes_by_idx(root_idx) { for child_scope_idx in vcd.child_scopes_by_idx(root_idx) {
indented_print(indent, vcd.scope_name_by_idx(child_scope_idx)); indented_print(indent, vcd.scope_name_by_idx(child_scope_idx));
let ScopeIdx(idx) = child_scope_idx; for signal_idx in vcd.get_children_signal_idxs(child_scope_idx) {
print_root_scope_tree(child_scope_idx, vcd.clone(), indent + 1); let signal = vcd.signal_from_signal_idx(signal_idx);
let SignalIdx(idx) = signal_idx;
indented_print(indent + 1, &format!("{},{}", signal.name(), idx));
}
visit_all_scope_children(child_scope_idx, vcd.clone(), indent + 1);
}
} }
} }
}
fn ui_all_scopes(vcd: &VCD) {
for root_scope_idx in vcd.root_scopes_by_idx() { for root_scope_idx in vcd.root_scopes_by_idx() {
indented_print(0, vcd.scope_name_by_idx(root_scope_idx)); indented_print(0, vcd.scope_name_by_idx(root_scope_idx));
print_root_scope_tree(root_scope_idx, vcd, 1u8); visit_all_scope_children(root_scope_idx, vcd, 1u8);
} }
} }
@ -36,6 +39,8 @@ fn main() -> std::io::Result<()> {
use std::time::Instant; use std::time::Instant;
// we start by printing out the entire signal tree of
// a parsed VCD
let now = Instant::now(); let now = Instant::now();
let file_path = "tests/vcd-files/icarus/CPU.vcd"; let file_path = "tests/vcd-files/icarus/CPU.vcd";
let file = File::open(file_path)?; let file = File::open(file_path)?;
@ -44,21 +49,36 @@ fn main() -> std::io::Result<()> {
println!("Parsed VCD file {} : {:.2?}", file_path, elapsed); println!("Parsed VCD file {} : {:.2?}", file_path, elapsed);
println!("Printing Scopes"); println!("Printing Scopes");
ui_all_scopes(&vcd); visit_all_scopes(&vcd);
println!("Done Printing Scopes");
println!();
// let state_signal = vcd. // we then parse another VCD, print its signal tree and
// let name = state_signal.name(); // query some values on its timeline
// let time = BigUint::from(57760000u32); let now = Instant::now();
// let val = state_signal let file_path = "tests/vcd-files/amaranth/up_counter.vcd";
// .query_string_val_on_tmln( let file = File::open(file_path)?;
// &time, let vcd = parse_vcd(file).unwrap();
// &vcd.tmstmps_encoded_as_u8s, let elapsed = now.elapsed();
// &vcd.all_signals, println!("Parsed VCD file {} : {:.2?}", file_path, elapsed);
// )
// .unwrap();
// println!("Signal `{name}` has value `{val}` at time `{time}`");
println!("Printing Scopes");
visit_all_scopes(&vcd);
println!("Done Printing Scopes");
let state_signal = vcd.signal_from_signal_idx(SignalIdx(4));
let name = state_signal.name();
let timestamps = vec![31499_000u32, 31500_000u32, 57760_000u32];
for timestamp in timestamps {
let time = num::BigUint::from(timestamp);
let val = state_signal
.query_string_val_on_tmln(&time, &vcd)
.unwrap();
println!("Signal `{name}` has value `{val}` at time `{time}`");
}
Ok(()) Ok(())
} }

View file

@ -2,7 +2,11 @@
// 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.
mod vcd; mod vcd;
pub use vcd::*; pub use vcd::parse::parse_vcd;
pub use vcd::types::{ScopeIdx, SignalIdx, VCD};
pub use vcd::types::{Metadata, Timescale, Version};
pub use vcd::signal::{Signal};
pub use num::BigUint; pub use num::BigUint;

View file

@ -2,17 +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.
mod reader; mod reader;
use reader::*; pub(crate) mod types;
pub(crate) mod parse;
mod types; pub(crate) mod signal;
pub use types::*;
mod parse;
pub use parse::*;
mod signal;
pub use signal::*;
mod utilities; mod utilities;
use utilities::*;

View file

@ -2,38 +2,26 @@
// 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 num::BigUint;
use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use super::*;
mod combinator_atoms; mod combinator_atoms;
use combinator_atoms::*;
mod types; mod types;
use types::*;
mod metadata; mod metadata;
use metadata::*;
mod scopes; mod scopes;
use scopes::*;
mod events; mod events;
use events::*;
pub fn parse_vcd(file: File) -> Result<VCD, String> {
let mut word_gen = WordReader::new(file);
let header = parse_metadata(&mut word_gen)?; pub fn parse_vcd(file: File) -> Result<super::types::VCD, String> {
let mut word_gen = super::reader::WordReader::new(file);
let header = metadata::parse_metadata(&mut word_gen)?;
// later, we'll need to map parsed ascii symbols to their // later, we'll need to map parsed ascii symbols to their
// respective signal indexes // respective signal indexes
let mut signal_map = std::collections::HashMap::new(); let mut signal_map = std::collections::HashMap::new();
// 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 = super::types::VCD {
metadata: header, metadata: header,
tmstmps_encoded_as_u8s: vec![], tmstmps_encoded_as_u8s: vec![],
all_signals: vec![], all_signals: vec![],
@ -41,8 +29,8 @@ pub fn parse_vcd(file: File) -> Result<VCD, String> {
root_scopes: vec![], root_scopes: vec![],
}; };
parse_scopes(&mut word_gen, &mut vcd, &mut signal_map)?; scopes::parse_scopes(&mut word_gen, &mut vcd, &mut signal_map)?;
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

@ -2,7 +2,7 @@
// 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::reader::{next_word, WordReader}; use super::super::reader::{next_word, WordReader};
use super::types::ParseResult; use super::types::ParseResult;
pub(super) fn digit(chr: u8) -> bool { pub(super) fn digit(chr: u8) -> bool {

View file

@ -2,9 +2,15 @@
// 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 num::Zero;
use super::*; use std::collections::HashMap;
use num::BigUint;
use super::super::utilities::{BinaryParserErrTypes, binary_str_to_vec_u8};
use super::super::signal::{SignalEnum, LsbIdxOfTmstmpValOnTmln};
use super::super::reader::{WordReader, Cursor, Line, Word, next_word};
use super::super::types::{SignalIdx, VCD};
pub(super) fn parse_events<'a>( pub(super) fn parse_events<'a>(
word_reader: &mut WordReader, word_reader: &mut WordReader,
@ -13,7 +19,6 @@ pub(super) fn parse_events<'a>(
) -> Result<(), String> { ) -> Result<(), String> {
let mut curr_tmstmp_lsb_idx = 0u32; let mut curr_tmstmp_lsb_idx = 0u32;
let mut curr_tmstmp_len_u8 = 0u8; let mut curr_tmstmp_len_u8 = 0u8;
let mut curr_time = BigUint::zero();
loop { loop {
let next_word = word_reader.next_word(); let next_word = word_reader.next_word();
@ -42,7 +47,6 @@ pub(super) fn parse_events<'a>(
"Error near {f}:{l}. Failed to parse {value} as BigInt at {cursor:?}" "Error near {f}:{l}. Failed to parse {value} as BigInt at {cursor:?}"
) )
})?; })?;
curr_time = value.clone();
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.
@ -119,7 +123,7 @@ pub(super) fn parse_events<'a>(
let signal = vcd.dealiasing_signal_idx_to_signal_lookup_mut(signal_idx)?; let signal = vcd.dealiasing_signal_idx_to_signal_lookup_mut(signal_idx)?;
match signal { match signal {
Signal::Data { SignalEnum::Data {
name, name,
sig_type, sig_type,
ref mut signal_error, ref mut signal_error,
@ -207,7 +211,7 @@ pub(super) fn parse_events<'a>(
Ok(()) Ok(())
} }
} }
Signal::Alias { .. } => { SignalEnum::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\
@ -232,7 +236,7 @@ pub(super) fn parse_events<'a>(
let signal = vcd.dealiasing_signal_idx_to_signal_lookup_mut(signal_idx)?; let signal = vcd.dealiasing_signal_idx_to_signal_lookup_mut(signal_idx)?;
match signal { match signal {
Signal::Data { SignalEnum::Data {
name, name,
sig_type, sig_type,
ref mut signal_error, ref mut signal_error,
@ -299,7 +303,7 @@ pub(super) fn parse_events<'a>(
} }
Ok(()) Ok(())
} }
Signal::Alias { .. } => { SignalEnum::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\
@ -323,7 +327,7 @@ pub(super) fn parse_events<'a>(
let signal = vcd.dealiasing_signal_idx_to_signal_lookup_mut(signal_idx)?; let signal = vcd.dealiasing_signal_idx_to_signal_lookup_mut(signal_idx)?;
match signal { match signal {
Signal::Data { SignalEnum::Data {
name, name,
sig_type, sig_type,
ref mut signal_error, ref mut signal_error,
@ -390,7 +394,7 @@ pub(super) fn parse_events<'a>(
} }
Ok(()) Ok(())
} }
Signal::Alias { .. } => { SignalEnum::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\
@ -416,13 +420,12 @@ pub(super) fn parse_events<'a>(
let signal = vcd.dealiasing_signal_idx_to_signal_lookup_mut(signal_idx)?; let signal = vcd.dealiasing_signal_idx_to_signal_lookup_mut(signal_idx)?;
match signal { match signal {
Signal::Data { SignalEnum::Data {
name, name,
sig_type, sig_type,
ref mut signal_error, ref mut signal_error,
num_bits, num_bits,
string_vals, string_vals,
byte_len_of_num_tmstmp_vals_on_tmln,
byte_len_of_string_tmstmp_vals_on_tmln, byte_len_of_string_tmstmp_vals_on_tmln,
lsb_indxs_of_string_tmstmp_vals_on_tmln, lsb_indxs_of_string_tmstmp_vals_on_tmln,
.. ..
@ -472,7 +475,7 @@ pub(super) fn parse_events<'a>(
string_vals.push(val); string_vals.push(val);
Ok(()) Ok(())
} }
Signal::Alias { .. } => { SignalEnum::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\
@ -496,13 +499,9 @@ pub(super) fn parse_events<'a>(
let signal = vcd.dealiasing_signal_idx_to_signal_lookup_mut(signal_idx)?; let signal = vcd.dealiasing_signal_idx_to_signal_lookup_mut(signal_idx)?;
match signal { match signal {
Signal::Data { SignalEnum::Data {
name,
sig_type,
ref mut signal_error, ref mut signal_error,
num_bits,
string_vals, string_vals,
byte_len_of_num_tmstmp_vals_on_tmln,
byte_len_of_string_tmstmp_vals_on_tmln, byte_len_of_string_tmstmp_vals_on_tmln,
lsb_indxs_of_string_tmstmp_vals_on_tmln, lsb_indxs_of_string_tmstmp_vals_on_tmln,
.. ..
@ -521,7 +520,7 @@ pub(super) fn parse_events<'a>(
string_vals.push(val); string_vals.push(val);
Ok(()) Ok(())
} }
Signal::Alias { .. } => { SignalEnum::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\

View file

@ -2,10 +2,14 @@
// 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 chrono::prelude::*; use chrono::prelude::{DateTime, Utc, TimeZone};
use itertools::Itertools; use itertools::Itertools;
use super::*; use super::super::reader::{Cursor, WordReader, next_word};
use super::super::types::{Timescale, Version, Metadata};
use super::combinator_atoms::{take_until, take_while, digit, tag};
use super::types::{ParseResult};
pub(super) fn parse_date( pub(super) fn parse_date(
word_and_ctx1: (&str, &Cursor), word_and_ctx1: (&str, &Cursor),

View file

@ -5,7 +5,15 @@
/// part of the vcd parser that handles parsing the signal tree and /// part of the vcd parser that handles parsing the signal tree and
/// building the resulting signal tree /// building the resulting signal tree
use super::*;
use std::collections::HashMap;
use super::super::reader::{WordReader, next_word, curr_word};
use super::super::types::{VCD, Scope, ScopeIdx, SignalIdx};
use super::super::signal::{SigType, SignalEnum};
use super::combinator_atoms::{tag, ident};
use super::types::{ParseResult};
pub(super) fn parse_var<'a>( pub(super) fn parse_var<'a>(
word_reader: &mut WordReader, word_reader: &mut WordReader,
@ -95,7 +103,7 @@ pub(super) fn parse_var<'a>(
let full_signal_name = full_signal_name.join(" "); let full_signal_name = full_signal_name.join(" ");
let num_bytes = if num_bits.is_some() { let num_bytes = if num_bits.is_some() {
let bytes_required = Signal::bytes_required(num_bits.unwrap(), &full_signal_name)?; let bytes_required = SignalEnum::bytes_required(num_bits.unwrap(), &full_signal_name)?;
Some(bytes_required) Some(bytes_required)
} else { } else {
None None
@ -107,7 +115,7 @@ pub(super) fn parse_var<'a>(
let (signal, signal_idx) = match signal_map.get(&signal_alias) { let (signal, signal_idx) = match signal_map.get(&signal_alias) {
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 = Signal::Alias { let signal = SignalEnum::Alias {
name: full_signal_name, name: full_signal_name,
signal_alias: *ref_signal_idx, signal_alias: *ref_signal_idx,
}; };
@ -116,7 +124,7 @@ pub(super) fn parse_var<'a>(
None => { None => {
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 = Signal::Data { let signal = SignalEnum::Data {
name: full_signal_name, name: full_signal_name,
sig_type: var_type, sig_type: var_type,
signal_error: None, signal_error: None,
@ -322,7 +330,7 @@ pub(super) fn parse_scopes<'a>(
signal_map: &mut HashMap<String, SignalIdx>, signal_map: &mut HashMap<String, SignalIdx>,
) -> Result<(), String> { ) -> Result<(), String> {
// get the current word // get the current word
let (word, cursor) = curr_word!(word_reader)?; let (word, _) = curr_word!(word_reader)?;
// we may have orphaned vars that occur before the first scope // we may have orphaned vars that occur before the first scope
if word == "$var" { if word == "$var" {

View file

@ -5,7 +5,7 @@
use std::collections::VecDeque; use std::collections::VecDeque;
use std::fs::File; use std::fs::File;
use std::io; use std::io;
use std::io::prelude::*; use std::io::BufRead;
use std::slice; use std::slice;
use std::str; use std::str;

View file

@ -2,7 +2,8 @@
// 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::{ScopeIdx, SignalIdx}; use super::types::{ScopeIdx, SignalIdx};
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
@ -28,8 +29,33 @@ pub(super) enum TimelineQueryResults {
String(String), String(String),
} }
pub struct Signal<'a>(pub(super) &'a SignalEnum);
impl<'a> Signal<'a> {
pub fn name(&self) -> String {
let Signal(signal_enum) = &self;
signal_enum.name()
}
pub fn query_string_val_on_tmln(
&self,
desired_time: &BigUint,
vcd: &types::VCD,
) -> Result<String, SignalErrors> {
let Signal(signal_enum) = &self;
signal_enum.query_string_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals)
}
pub fn query_num_val_on_tmln(
&self,
desired_time: &BigUint,
vcd: &types::VCD,
) -> Result<BigUint, SignalErrors> {
let Signal(signal_enum) = &self;
signal_enum.query_num_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals)
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum Signal { pub(super) enum SignalEnum {
Data { Data {
name: String, name: String,
sig_type: SigType, sig_type: SigType,
@ -99,30 +125,18 @@ type TimeStamp = BigUint;
type SignalValNum = BigUint; type SignalValNum = BigUint;
// getter functions // getter functions
impl Signal { impl SignalEnum {
pub fn self_idx(&self) -> Result<SignalIdx, String> {
match self {
Signal::Data { self_idx, ..} => {return Ok(self_idx.clone())},
Signal::Alias { .. } => Err(format!(
"Error near {}:{}. A signal alias shouldn't \
point to a signal alias.",
file!(),
line!()
)),
}
}
pub fn name(&self) -> String { pub fn name(&self) -> String {
match self { match self {
Signal::Data { name, ..} => name, SignalEnum::Data { name, ..} => name,
Signal::Alias { name, .. } => name SignalEnum::Alias { name, .. } => name
}.clone() }.clone()
} }
} }
// helper functions ultimately used by Signal's query functions later on // helper functions ultimately used by Signal's query functions later on
impl Signal { impl SignalEnum {
/// Computes the bytes required to store a signal's numerical value /// Computes the bytes required to store a signal's numerical value
/// using the num_bits which another function would provide from /// using the num_bits which another function would provide from
/// the num_bits field of the Signal::Data variant. /// the num_bits field of the Signal::Data variant.
@ -145,7 +159,7 @@ impl Signal {
/// string_vals field of an instance of the Signal::Data variant /// string_vals field of an instance of the Signal::Data variant
/// and gets a string value. /// and gets a string value.
/// The function returns a tuple of the timestamp and string value. /// The function returns a tuple of the timestamp and string value.
pub(super) fn time_and_str_val_at_event_idx( fn time_and_str_val_at_event_idx(
&self, &self,
event_idx: usize, event_idx: usize,
tmstmps_encoded_as_u8s: &Vec<u8>, tmstmps_encoded_as_u8s: &Vec<u8>,
@ -155,7 +169,7 @@ impl Signal {
lsb_indxs_of_string_tmstmp_vals_on_tmln, lsb_indxs_of_string_tmstmp_vals_on_tmln,
byte_len_of_string_tmstmp_vals_on_tmln, byte_len_of_string_tmstmp_vals_on_tmln,
) = match self { ) = match self {
Signal::Data { SignalEnum::Data {
string_vals, string_vals,
lsb_indxs_of_string_tmstmp_vals_on_tmln, lsb_indxs_of_string_tmstmp_vals_on_tmln,
byte_len_of_string_tmstmp_vals_on_tmln, byte_len_of_string_tmstmp_vals_on_tmln,
@ -165,7 +179,7 @@ impl Signal {
lsb_indxs_of_string_tmstmp_vals_on_tmln, lsb_indxs_of_string_tmstmp_vals_on_tmln,
byte_len_of_string_tmstmp_vals_on_tmln, byte_len_of_string_tmstmp_vals_on_tmln,
)), )),
Signal::Alias { .. } => Err(SignalErrors::PointsToAlias), SignalEnum::Alias { .. } => Err(SignalErrors::PointsToAlias),
}?; }?;
// get index // get index
@ -193,7 +207,7 @@ impl Signal {
/// numerical value at the time pointed at by event_didx. /// numerical value at the time pointed at by event_didx.
/// The function returns a tuple of the timestamp and numerical /// The function returns a tuple of the timestamp and numerical
/// value. /// value.
pub(super) fn time_and_num_val_at_event_idx( fn time_and_num_val_at_event_idx(
&self, &self,
event_idx: usize, event_idx: usize,
tmstmps_encoded_as_u8s: &Vec<u8>, tmstmps_encoded_as_u8s: &Vec<u8>,
@ -204,7 +218,7 @@ impl Signal {
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,
) = match self { ) = match self {
Signal::Data { SignalEnum::Data {
num_bytes, num_bytes,
nums_encoded_as_fixed_width_le_u8, nums_encoded_as_fixed_width_le_u8,
lsb_indxs_of_num_tmstmp_vals_on_tmln, lsb_indxs_of_num_tmstmp_vals_on_tmln,
@ -216,7 +230,7 @@ impl Signal {
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,
)), )),
Signal::Alias { .. } => Err(SignalErrors::PointsToAlias), SignalEnum::Alias { .. } => Err(SignalErrors::PointsToAlias),
}?; }?;
// get index // get index
@ -245,12 +259,12 @@ impl Signal {
// Function that take in a desired time on the timeline for a // Function that take in a desired time on the timeline for a
// specific signal and return a numerical or string value in a Result, // specific signal and return a numerical or string value in a Result,
// or an error in a Result. // or an error in a Result.
impl Signal { impl SignalEnum {
pub fn query_string_val_on_tmln( pub fn query_string_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<Signal>, all_signals: &Vec<SignalEnum>,
) -> Result<String, SignalErrors> { ) -> Result<String, SignalErrors> {
let signal_idx = match self { let signal_idx = match self {
Self::Data { self_idx, .. } => { Self::Data { self_idx, .. } => {
@ -274,7 +288,7 @@ impl Signal {
// else we propagate Err(..). // else we propagate Err(..).
let (string_vals, lsb_indxs_of_string_tmstmp_vals_on_tmln) = let (string_vals, lsb_indxs_of_string_tmstmp_vals_on_tmln) =
match &all_signals[signal_idx] { match &all_signals[signal_idx] {
Signal::Data { SignalEnum::Data {
ref string_vals, ref string_vals,
ref lsb_indxs_of_string_tmstmp_vals_on_tmln, ref lsb_indxs_of_string_tmstmp_vals_on_tmln,
.. ..
@ -284,7 +298,7 @@ impl Signal {
lsb_indxs_of_string_tmstmp_vals_on_tmln, lsb_indxs_of_string_tmstmp_vals_on_tmln,
)) ))
} }
Signal::Alias { .. } => Err(SignalErrors::PointsToAlias), SignalEnum::Alias { .. } => Err(SignalErrors::PointsToAlias),
}?; }?;
// this signal should at least have some events, otherwise, trying to index into // this signal should at least have some events, otherwise, trying to index into
// an empty vector later on would fail // an empty vector later on would fail
@ -365,7 +379,7 @@ impl Signal {
&self, &self,
desired_time: &BigUint, desired_time: &BigUint,
tmstmps_encoded_as_u8s: &Vec<u8>, tmstmps_encoded_as_u8s: &Vec<u8>,
all_signals: &Vec<Signal>, all_signals: &Vec<SignalEnum>,
) -> Result<BigUint, SignalErrors> { ) -> Result<BigUint, SignalErrors> {
let signal_idx = match self { let signal_idx = match self {
Self::Data { self_idx, .. } => { Self::Data { self_idx, .. } => {
@ -390,7 +404,7 @@ impl Signal {
// else we propagate Err(..). // else we propagate Err(..).
let (nums_encoded_as_fixed_width_le_u8, lsb_indxs_of_num_tmstmp_vals_on_tmln, num_bytes) = let (nums_encoded_as_fixed_width_le_u8, lsb_indxs_of_num_tmstmp_vals_on_tmln, num_bytes) =
match &all_signals[signal_idx] { match &all_signals[signal_idx] {
Signal::Data { SignalEnum::Data {
num_bytes, num_bytes,
ref nums_encoded_as_fixed_width_le_u8, ref nums_encoded_as_fixed_width_le_u8,
ref lsb_indxs_of_num_tmstmp_vals_on_tmln, ref lsb_indxs_of_num_tmstmp_vals_on_tmln,
@ -405,7 +419,7 @@ impl Signal {
num_bytes, num_bytes,
)) ))
} }
Signal::Alias { .. } => Err(SignalErrors::PointsToAlias), SignalEnum::Alias { .. } => Err(SignalErrors::PointsToAlias),
}?; }?;
// this signal should at least have some events, otherwise, trying to index into // this signal should at least have some events, otherwise, trying to index into
// an empty vector later on would fail // an empty vector later on would fail

View file

@ -1,15 +1,17 @@
// use crate::Signal;
// Copyright (C) 2022 Yehowshua Immanuel // Copyright (C) 2022 Yehowshua Immanuel
// 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::Signal; use chrono::prelude::{DateTime, Utc};
use chrono::prelude::*; use super::signal::{Signal, SignalEnum};
#[derive(Debug)] #[derive(Debug)]
pub(super) struct Version(pub String); pub struct Version(pub String);
#[derive(Debug)] #[derive(Debug)]
pub(super) enum Timescale { pub enum Timescale {
Fs, Fs,
Ps, Ps,
Ns, Ns,
@ -20,10 +22,10 @@ pub(super) enum Timescale {
} }
#[derive(Debug)] #[derive(Debug)]
pub(super) struct Metadata { pub struct Metadata {
pub(super) date: Option<DateTime<Utc>>, pub date: Option<DateTime<Utc>>,
pub(super) version: Option<Version>, pub version: Option<Version>,
pub(super) timescale: (Option<u32>, Timescale), pub timescale: (Option<u32>, Timescale),
} }
// We do a lot of arena allocation in this codebase. // We do a lot of arena allocation in this codebase.
@ -31,7 +33,7 @@ pub(super) struct Metadata {
pub struct ScopeIdx(pub usize); pub struct ScopeIdx(pub usize);
#[derive(Debug, Copy, Clone, PartialEq)] #[derive(Debug, Copy, Clone, PartialEq)]
pub struct SignalIdx(pub(super) usize); pub struct SignalIdx(pub usize);
#[derive(Debug)] #[derive(Debug)]
pub(super) struct Scope { pub(super) struct Scope {
@ -46,7 +48,7 @@ pub(super) struct Scope {
#[derive(Debug)] #[derive(Debug)]
pub struct VCD { pub struct VCD {
pub(super) metadata: Metadata, pub 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/encoded as the minimum length sequence // event occurs. Time t is always stored/encoded as the minimum length sequence
@ -58,7 +60,7 @@ pub struct VCD {
// keep track of all timestamp values, a given signal only needs to keep // keep track of all timestamp values, a given signal only needs to keep
// track of the timestamps at which the given signal value changes. // track of the timestamps at which the given signal value changes.
pub(super) tmstmps_encoded_as_u8s: Vec<u8>, pub(super) tmstmps_encoded_as_u8s: Vec<u8>,
pub(super) all_signals: Vec<Signal>, 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>,
} }
@ -72,11 +74,21 @@ impl VCD {
let scope = &self.all_scopes[idx]; let scope = &self.all_scopes[idx];
scope.child_scopes.clone() scope.child_scopes.clone()
} }
pub fn get_children_signal_idxs(&self, scope_idx: ScopeIdx) -> Vec<SignalIdx> {
let ScopeIdx(idx) = scope_idx;
let scope = &self.all_scopes[idx];
scope.child_signals.clone()
}
pub fn scope_name_by_idx(&self, scope_idx: ScopeIdx) -> &String { pub fn scope_name_by_idx(&self, scope_idx: ScopeIdx) -> &String {
let ScopeIdx(idx) = scope_idx; let ScopeIdx(idx) = scope_idx;
let scope = &self.all_scopes[idx]; let scope = &self.all_scopes[idx];
&scope.name &scope.name
} }
pub fn signal_from_signal_idx<'a>(&'a self, idx: SignalIdx) -> Signal<'a> {
let SignalIdx(idx) = idx;
let signal_enum = &self.all_signals[idx];
return Signal(signal_enum);
}
/// We take in a Signal and attempt to de-alias that signal if it is of /// We take in a Signal and attempt to de-alias that signal if it is of
/// variant ``Signal::Alias``. If it is of variant ``Signal::Alias`` and points to /// 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`` /// another alias, that's an error. Otherwise, we return the ``Signal::Data``
@ -85,76 +97,23 @@ impl VCD {
pub(super) fn dealiasing_signal_idx_to_signal_lookup_mut<'a>( pub(super) fn dealiasing_signal_idx_to_signal_lookup_mut<'a>(
&'a mut self, &'a mut self,
idx: &SignalIdx, idx: &SignalIdx,
) -> Result<&'a mut Signal, String> { ) -> Result<&'a mut SignalEnum, String> {
// get the signal pointed to be SignalIdx from the arena // get the signal pointed to be SignalIdx from the arena
let SignalIdx(idx) = idx; let SignalIdx(idx) = idx;
let signal = &self.all_signals[*idx]; let signal = &self.all_signals[*idx];
// dereference signal if Signal::Alias, or keep idx if Signal::Data // dereference signal if Signal::Alias, or keep idx if Signal::Data
let signal_idx = match signal { let signal_idx = match signal {
Signal::Data { self_idx, .. } => *self_idx, SignalEnum::Data { self_idx, .. } => *self_idx,
Signal::Alias { name, signal_alias } => *signal_alias, SignalEnum::Alias {signal_alias, .. } => *signal_alias,
}; };
// Should now point to Signal::Data variant, or else there's an error // Should now point to Signal::Data variant, or else there's an error
let SignalIdx(idx) = signal_idx; let SignalIdx(idx) = signal_idx;
let signal = self.all_signals.get_mut(idx).unwrap(); let signal = self.all_signals.get_mut(idx).unwrap();
match signal { match signal {
Signal::Data { .. } => Ok(signal), SignalEnum::Data { .. } => Ok(signal),
Signal::Alias { .. } => Err(format!( SignalEnum::Alias { .. } => Err(format!(
"Error near {}:{}. A signal alias shouldn't \
point to a signal alias.",
file!(),
line!()
)),
}
}
pub(super) fn dealiasing_signal_idx_to_signal_lookup<'a>(
&'a self,
idx: &SignalIdx,
) -> Result<&'a Signal, String> {
// get the signal pointed to be SignalIdx from the arena
let SignalIdx(idx) = idx;
let signal = &self.all_signals[*idx];
// dereference signal if Signal::Alias, or keep idx if Signal::Data
let signal_idx = match signal {
Signal::Data { self_idx, .. } => *self_idx,
Signal::Alias { name, signal_alias } => *signal_alias,
};
// Should now point to Signal::Data variant, or else there's an error
let SignalIdx(idx) = signal_idx;
let signal = self.all_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!()
)),
}
}
/// Takes a signal as input and returns the signal if the signal is of the
/// Signal::Data variant, else the function follows follows the uses the
/// SignalIdx in the signal_alias field of Signal::Alias variant to index
/// into the signal arena in the all_signals field of the vcd, and returns
/// the resulting signal if that signal is a Signal::Data variant, else,
/// this function returns an Err.
pub fn dealiasing_signal_lookup<'a>(&'a self, signal: &Signal) -> Result<&'a Signal, String> {
// dereference signal if Signal::Alias, or keep idx if Signal::Data
let signal_idx = match signal {
Signal::Data { self_idx, .. } => *self_idx,
Signal::Alias { name, signal_alias } => *signal_alias,
};
// Should now point to Signal::Data variant, or else there's an error
let SignalIdx(idx) = signal_idx;
let signal = self.all_signals.get(idx).unwrap();
match signal {
Signal::Data { .. } => Ok(signal),
Signal::Alias { .. } => Err(format!(
"Error near {}:{}. A signal alias shouldn't \ "Error near {}:{}. A signal alias shouldn't \
point to a signal alias.", point to a signal alias.",
file!(), file!(),