add docs and change examples to reflect changing interfaces

This commit is contained in:
Yehowshua Immanuel 2022-09-13 19:35:23 -04:00
parent 320b0d348d
commit a0713c1f38
10 changed files with 95 additions and 85 deletions

View file

@ -2,6 +2,11 @@ Copyright - Yehowshua Immanuel
# A High performance, VCD Parser written in Rust # A High performance, VCD Parser written in Rust
Below is a screenshot of the early stages of the proprietary
viewer frontend that builds on this backend:
![](assets/viewer.png)
# Current Features # Current Features
- Robust Error Handling - Robust Error Handling
@ -55,9 +60,7 @@ The first build of the program may take some time.
``cargo run --release --example parse_vcd tests/vcd-files/aldec/SPI_Write.vcd`` ``cargo run --release --example parse_vcd tests/vcd-files/aldec/SPI_Write.vcd``
You can also run the vcd1 or vcd2 example with: You can also run the vcd example with: cargo run --release --example vcd1.
- cargo run --release --example vcd1
- cargo run --release --example vcd2
You can run all the tests with ``cargo test`` You can run all the tests with ``cargo test``
@ -73,6 +76,8 @@ Here's a command to test on a malformed VCD:
## Features and Other ## Features and Other
- [ ] add documenting comments - [ ] add documenting comments
- [ ] make signal query private until later?
- [ ] change crate name to vcd_fast_parse
- [ ] perhaps we should be looking up signal values on the VCD class - [ ] perhaps we should be looking up signal values on the VCD class
- [ ] perhaps we should be returning signal trees from the VCD class - [ ] perhaps we should be returning signal trees from the VCD class
- [ ] add lz4 compression support and compare memory perf before and after - [ ] add lz4 compression support and compare memory perf before and after

BIN
assets/viewer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

61
examples/vcd.rs Normal file
View file

@ -0,0 +1,61 @@
use std::fs::File;
use fastwave::*;
use num::{BigUint};
fn indented_print(indent : u8, name : &String) {
for _ in 0..indent {print!(" ");}
print!(" |");
print!(" ");
println!("{name}");
}
fn print_root_scope_tree(root_idx: ScopeIdx, vcd: &VCD, indent : u8) {
if vcd.child_scopes_by_idx(root_idx).is_empty() {
indented_print(indent, vcd.scope_name_by_idx(root_idx));
} else {
for child_scope_idx in vcd.child_scopes_by_idx(root_idx) {
indented_print(indent, vcd.scope_name_by_idx(child_scope_idx));
let ScopeIdx(idx) = child_scope_idx;
print_root_scope_tree(child_scope_idx, vcd.clone(), indent + 1);
}
}
}
fn ui_all_scopes(vcd: &VCD) {
for root_scope_idx in vcd.root_scopes_by_idx() {
print_root_scope_tree(root_scope_idx, vcd, 0u8);
}
}
fn main() -> std::io::Result<()> {
use std::time::Instant;
let now = Instant::now();
let file_path = "tests/vcd-files/icarus/CPU.vcd";
let file = File::open(file_path)?;
let vcd = parse_vcd(file).unwrap();
let elapsed = now.elapsed();
println!("Parsed VCD file {} : {:.2?}", file_path, elapsed);
println!("Printing Scopes");
ui_all_scopes(&vcd);
// let state_signal = vcd.
// let name = state_signal.name();
// let time = BigUint::from(57760000u32);
// let val = state_signal
// .query_string_val_on_tmln(
// &time,
// &vcd.tmstmps_encoded_as_u8s,
// &vcd.all_signals,
// )
// .unwrap();
// println!("Signal `{name}` has value `{val}` at time `{time}`");
Ok(())
}

View file

@ -1,34 +0,0 @@
use clap::Parser;
use std::fs::File;
use fastwave::*;
use num::{BigUint};
fn main() -> std::io::Result<()> {
use std::time::Instant;
let now = Instant::now();
let file_path = "tests/vcd-files/icarus/CPU.vcd";
let file = File::open(file_path).unwrap();
let vcd = parse_vcd(file).unwrap();
let elapsed = now.elapsed();
println!("Parsed VCD file {} : {:.2?}", file_path, elapsed);
// testbench -> CPU -> rs2_data[31:0] @ 4687s
let rs2_data_signal = &vcd.all_signals[51];
let name = rs2_data_signal.name();
let time = BigUint::from(4687u32);
let val = rs2_data_signal
.query_num_val_on_tmln(
&time,
&vcd.tmstmps_encoded_as_u8s,
&vcd.all_signals,
)
.unwrap();
println!("Signal `{name}` has value `{val}` at time `{time}`");
Ok(())
}

View file

@ -1,34 +0,0 @@
use clap::Parser;
use std::fs::File;
use fastwave::*;
use num::{BigUint};
fn main() -> std::io::Result<()> {
use std::time::Instant;
let now = Instant::now();
let file_path = "tests/vcd-files/amaranth/up_counter.vcd";
let file = File::open(file_path)?;
let vcd = parse_vcd(file).unwrap();
let elapsed = now.elapsed();
println!("Parsed VCD file {} : {:.2?}", file_path, elapsed);
let state_signal = &vcd.all_signals[4];
let name = state_signal.name();
let time = BigUint::from(57760000u32);
let val = state_signal
.query_string_val_on_tmln(
&time,
&vcd.tmstmps_encoded_as_u8s,
&vcd.all_signals,
)
.unwrap();
println!("Signal `{name}` has value `{val}` at time `{time}`");
Ok(())
}

View file

@ -1,2 +1,4 @@
mod vcd; mod vcd;
pub use vcd::*; pub use vcd::*;
pub use num::BigUint;

View file

@ -2,7 +2,7 @@ mod reader;
use reader::*; use reader::*;
mod types; mod types;
use types::*; pub use types::*;
mod parse; mod parse;
pub use parse::*; pub use parse::*;

View file

@ -1,5 +1,5 @@
//! 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 super::*;
pub(super) fn parse_var<'a>( pub(super) fn parse_var<'a>(

View file

@ -1,5 +1,5 @@
use super::{ScopeIdx, SignalIdx}; use super::{ScopeIdx, SignalIdx};
use num::{BigUint, Zero}; 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

View file

@ -24,7 +24,7 @@ pub(super) 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)] #[derive(Debug, Copy, Clone)]
pub struct ScopeIdx(pub(super) 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(super) usize);
@ -53,13 +53,26 @@ pub struct VCD {
// vector of u8s that constitute a timestamp value. Signals don't have to // 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 // 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 tmstmps_encoded_as_u8s: Vec<u8>, pub(super) tmstmps_encoded_as_u8s: Vec<u8>,
pub all_signals: Vec<Signal>, pub(super) all_signals: Vec<Signal>,
pub(super) all_scopes: Vec<Scope>, pub(super) all_scopes: Vec<Scope>,
pub(super) root_scopes: Vec<ScopeIdx>, pub(super) root_scopes: Vec<ScopeIdx>,
} }
impl VCD { impl VCD {
pub fn root_scopes_by_idx(&self) -> Vec<ScopeIdx> {
self.root_scopes.clone()
}
pub fn child_scopes_by_idx(&self, scope_idx: ScopeIdx) -> Vec<ScopeIdx> {
let ScopeIdx(idx) = scope_idx;
let scope = &self.all_scopes[idx];
scope.child_scopes.clone()
}
pub fn scope_name_by_idx(&self, scope_idx: ScopeIdx) -> &String {
let ScopeIdx(idx) = scope_idx;
let scope = &self.all_scopes[idx];
&scope.name
}
/// 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``
@ -119,16 +132,13 @@ impl VCD {
)), )),
} }
} }
/// Takes a signal as input and returns the signal if the signal is of the /// 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 /// Signal::Data variant, else the function follows follows the uses the
/// SignalIdx in the signal_alias field of Signal::Alias variant to index /// 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 /// 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, /// the resulting signal if that signal is a Signal::Data variant, else,
/// this function returns an Err. /// this function returns an Err.
pub fn dealiasing_signal_lookup<'a>( pub fn dealiasing_signal_lookup<'a>(&'a self, signal: &Signal) -> Result<&'a Signal, String> {
&'a self,
signal: &Signal
) -> Result<&'a Signal, String> {
// 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, Signal::Data { self_idx, .. } => *self_idx,