2022-04-14 04:50:37 +00:00
|
|
|
use std::io::prelude::*;
|
|
|
|
use std::io;
|
|
|
|
use std::fs::File;
|
2022-05-18 02:04:32 +00:00
|
|
|
use std::collections::BTreeMap;
|
2022-05-19 07:44:24 +00:00
|
|
|
use chrono::prelude::*;
|
2022-05-24 03:45:14 +00:00
|
|
|
use ::function_name::named;
|
2022-04-14 04:50:37 +00:00
|
|
|
|
|
|
|
use num::*;
|
|
|
|
use clap::Parser;
|
|
|
|
|
|
|
|
#[derive(Parser)]
|
|
|
|
struct Cli {
|
|
|
|
/// The path to the file to read
|
|
|
|
#[clap(parse(from_os_str))]
|
2022-05-21 02:52:26 +00:00
|
|
|
path: std::path::PathBuf}
|
2022-04-14 04:50:37 +00:00
|
|
|
|
2022-05-19 07:44:24 +00:00
|
|
|
|
|
|
|
// TODO: implement any timescales greater than a second
|
2022-05-23 03:00:03 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum Timescale {ps, ns, us, ms, s, unit}
|
2022-05-19 07:44:24 +00:00
|
|
|
|
2022-05-23 03:00:03 +00:00
|
|
|
#[derive(Debug)]
|
2022-05-21 02:52:26 +00:00
|
|
|
struct Scope_Idx(usize);
|
2022-05-23 03:00:03 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
2022-05-21 02:52:26 +00:00
|
|
|
struct Signal_Idx(usize);
|
|
|
|
|
2022-05-23 03:00:03 +00:00
|
|
|
#[derive(Debug)]
|
2022-05-23 23:19:17 +00:00
|
|
|
struct Version(String);
|
2022-05-19 07:44:24 +00:00
|
|
|
|
2022-05-23 03:00:03 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct Metadata {
|
2022-05-23 23:19:17 +00:00
|
|
|
date : Option<DateTime<Utc>>,
|
|
|
|
version : Option<Version>,
|
2022-05-28 00:48:17 +00:00
|
|
|
timescale : (Option<u32>, Timescale)}
|
2022-05-19 07:44:24 +00:00
|
|
|
|
2022-05-23 03:00:03 +00:00
|
|
|
#[derive(Debug)]
|
2022-05-19 07:44:24 +00:00
|
|
|
enum SignalGeneric{
|
2022-05-23 03:00:03 +00:00
|
|
|
Signal{
|
|
|
|
name : String,
|
|
|
|
timeline : BTreeMap<BigInt, BigInt>,
|
|
|
|
scope_parent : Scope_Idx},
|
|
|
|
SignalAlias{
|
|
|
|
name : String,
|
|
|
|
signal_alias : Signal_Idx}
|
|
|
|
}
|
2022-05-18 02:04:32 +00:00
|
|
|
|
2022-05-23 03:00:03 +00:00
|
|
|
#[derive(Debug)]
|
2022-05-19 07:44:24 +00:00
|
|
|
struct Scope {
|
2022-05-21 02:52:26 +00:00
|
|
|
name : String,
|
|
|
|
child_signals : Vec<Signal_Idx>,
|
|
|
|
child_scopes : Vec<Scope_Idx>}
|
2022-05-19 07:44:24 +00:00
|
|
|
|
2022-05-23 03:00:03 +00:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
2022-05-19 07:44:24 +00:00
|
|
|
struct VCD {
|
2022-05-21 02:52:26 +00:00
|
|
|
metadata : Metadata,
|
|
|
|
all_signals : Vec<SignalGeneric>,
|
|
|
|
// the root scope should always be placed at index 0
|
|
|
|
all_scopes : Vec<Scope>}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2022-05-24 03:45:14 +00:00
|
|
|
enum Date_Parser_State {Begin, Parsing}
|
2022-05-23 23:19:17 +00:00
|
|
|
#[derive(Debug)]
|
2022-05-24 03:45:14 +00:00
|
|
|
enum Version_Parser_State {Begin, Parsing}
|
|
|
|
#[derive(Debug)]
|
|
|
|
enum Timescale_Parser_State {Begin, Parsing}
|
2022-05-28 00:48:17 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
enum Signal_Tree_Parser_State {Begin, Parsing}
|
2022-05-23 03:00:03 +00:00
|
|
|
|
2022-05-22 00:40:46 +00:00
|
|
|
|
2022-05-21 02:52:26 +00:00
|
|
|
#[derive(Debug)]
|
2022-05-24 03:45:14 +00:00
|
|
|
enum Parser_State {
|
2022-05-21 02:52:26 +00:00
|
|
|
Date(Date_Parser_State),
|
2022-05-24 03:45:14 +00:00
|
|
|
Version(Version_Parser_State),
|
|
|
|
Timescale(Timescale_Parser_State),
|
2022-05-28 00:48:17 +00:00
|
|
|
Signal_Tree(Signal_Tree_Parser_State),
|
2022-05-22 00:40:46 +00:00
|
|
|
Parse_Signal_Values}
|
2022-05-21 02:52:26 +00:00
|
|
|
|
|
|
|
struct VCD_Parser<'a> {
|
2022-05-24 03:45:14 +00:00
|
|
|
vcd_parser_state : Parser_State,
|
|
|
|
buffer : Option<String>,
|
2022-05-21 02:52:26 +00:00
|
|
|
|
2022-05-22 00:40:46 +00:00
|
|
|
vcd : &'a mut VCD,
|
2022-05-23 03:00:03 +00:00
|
|
|
curr_scope : Option<&'a Scope>,
|
|
|
|
curr_parent_scope : Option<&'a Scope>}
|
2022-05-21 02:52:26 +00:00
|
|
|
|
|
|
|
impl VCD {
|
|
|
|
pub fn new() -> Self {
|
|
|
|
let metadata = Metadata {
|
2022-05-23 23:19:17 +00:00
|
|
|
date : None,
|
|
|
|
version : None,
|
2022-05-28 00:48:17 +00:00
|
|
|
timescale : (None, Timescale::unit)};
|
2022-05-21 02:52:26 +00:00
|
|
|
VCD {
|
|
|
|
metadata : metadata,
|
|
|
|
all_signals : Vec::<SignalGeneric>::new(),
|
2022-05-24 03:59:57 +00:00
|
|
|
all_scopes : Vec::<Scope>::new()}
|
|
|
|
}
|
|
|
|
}
|
2022-05-21 02:52:26 +00:00
|
|
|
|
|
|
|
impl<'a> VCD_Parser<'a> {
|
2022-05-23 03:00:03 +00:00
|
|
|
pub fn new(vcd : &'a mut VCD) -> Self {
|
|
|
|
VCD_Parser {
|
2022-05-24 03:45:14 +00:00
|
|
|
vcd_parser_state : Parser_State::Date(Date_Parser_State::Begin),
|
|
|
|
|
|
|
|
buffer : None,
|
2022-05-23 03:00:03 +00:00
|
|
|
vcd : vcd,
|
|
|
|
curr_scope : None,
|
|
|
|
curr_parent_scope : None
|
|
|
|
}
|
|
|
|
}
|
2022-05-21 02:52:26 +00:00
|
|
|
|
|
|
|
pub fn parse_word(&mut self, word : &str) -> Result<(), String> {
|
|
|
|
let mut state = &mut self.vcd_parser_state;
|
2022-05-23 03:00:03 +00:00
|
|
|
let t = &self.vcd;
|
2022-05-21 02:52:26 +00:00
|
|
|
match state {
|
2022-05-24 03:45:14 +00:00
|
|
|
Parser_State::Date(_) => self.parse_date(word),
|
|
|
|
Parser_State::Version(_) => self.parse_version(word),
|
2022-05-28 00:48:17 +00:00
|
|
|
Parser_State::Timescale(_) => self.parse_timescale(word),
|
2022-05-23 03:00:03 +00:00
|
|
|
// TODO : Enable the following in production
|
2022-05-28 00:48:17 +00:00
|
|
|
// _ => Err(format!("parser in bad state : {state:?}"))
|
2022-05-23 03:00:03 +00:00
|
|
|
// TODO : Disable the following in production
|
2022-05-24 03:59:57 +00:00
|
|
|
_ => {
|
|
|
|
Err(format!("parser in bad state : {state:?}; {t:?}"))
|
|
|
|
}
|
2022-05-23 03:00:03 +00:00
|
|
|
}
|
2022-05-21 02:52:26 +00:00
|
|
|
}
|
2022-05-19 07:44:24 +00:00
|
|
|
|
2022-05-24 03:45:14 +00:00
|
|
|
#[named]
|
2022-05-21 02:52:26 +00:00
|
|
|
pub fn parse_date(&mut self, word : &str) -> Result<(), String> {
|
2022-05-21 19:22:05 +00:00
|
|
|
let mut state = &mut self.vcd_parser_state;
|
|
|
|
match state {
|
2022-05-24 03:45:14 +00:00
|
|
|
Parser_State::Date(Date_Parser_State::Begin) =>
|
|
|
|
match word {
|
|
|
|
"$date" => {
|
|
|
|
*state = Parser_State::Date(Date_Parser_State::Parsing);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
*state = Parser_State::Version(Version_Parser_State::Begin);
|
2022-05-24 03:59:57 +00:00
|
|
|
self.parse_version(word)
|
2022-05-24 03:45:14 +00:00
|
|
|
}
|
2022-05-22 00:40:46 +00:00
|
|
|
}
|
2022-05-24 03:45:14 +00:00
|
|
|
Parser_State::Date(Date_Parser_State::Parsing) =>
|
|
|
|
match word {
|
|
|
|
"$end" => {
|
|
|
|
let s = self.buffer.take().unwrap();
|
|
|
|
let dt = Utc.datetime_from_str(s.as_str(), "%a %b %e %T %Y")
|
2022-05-28 00:48:17 +00:00
|
|
|
.expect(&format!("invalid date {s}").as_str());
|
|
|
|
*state = Parser_State::Version(Version_Parser_State::Begin);
|
2022-05-24 03:45:14 +00:00
|
|
|
self.vcd.metadata.date = Some(dt);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if let Some(ref mut buffer) = self.buffer {
|
|
|
|
buffer.push_str(" ");
|
|
|
|
buffer.push_str(word);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
self.buffer = Some(word.to_string());
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-05-22 00:40:46 +00:00
|
|
|
}
|
2022-05-24 03:45:14 +00:00
|
|
|
_ => Err(format!("{state:?} should be unreachable within {}.",function_name!())),
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[named]
|
|
|
|
pub fn parse_version(&mut self, word : &str) -> Result<(), String> {
|
|
|
|
let mut state = &mut self.vcd_parser_state;
|
|
|
|
match state {
|
|
|
|
Parser_State::Version(Version_Parser_State::Begin) =>
|
2022-05-23 03:00:03 +00:00
|
|
|
match word {
|
2022-05-24 03:45:14 +00:00
|
|
|
"$version" => {
|
|
|
|
*state = Parser_State::Version(Version_Parser_State::Parsing);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
*state = Parser_State::Timescale(Timescale_Parser_State::Begin);
|
2022-05-23 23:19:17 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2022-05-23 03:00:03 +00:00
|
|
|
}
|
2022-05-24 03:45:14 +00:00
|
|
|
Parser_State::Version(Version_Parser_State::Parsing) =>
|
|
|
|
match word {
|
|
|
|
"$end" => {
|
|
|
|
let s = self.buffer.take().unwrap();
|
|
|
|
self.vcd.metadata.version = Some(Version(s));
|
2022-05-28 00:48:17 +00:00
|
|
|
*state = Parser_State::Timescale(Timescale_Parser_State::Begin);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if let Some(ref mut buffer) = self.buffer {
|
|
|
|
buffer.push_str(" ");
|
|
|
|
buffer.push_str(word);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
self.buffer = Some(word.to_string());
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => Err(format!("{state:?} should be unreachable within {}.",function_name!())),
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[named]
|
|
|
|
pub fn parse_timescale(&mut self, word : &str) -> Result<(), String> {
|
|
|
|
let mut state = &mut self.vcd_parser_state;
|
|
|
|
match state {
|
|
|
|
Parser_State::Timescale(Timescale_Parser_State::Begin) =>
|
|
|
|
match word {
|
|
|
|
"$timescale" => {
|
|
|
|
*state = Parser_State::Timescale(Timescale_Parser_State::Parsing);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
*state = Parser_State::Signal_Tree(Signal_Tree_Parser_State::Begin);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Parser_State::Timescale(Timescale_Parser_State::Parsing) =>
|
|
|
|
match word {
|
|
|
|
"$end" => {
|
|
|
|
let s = self.buffer.take().unwrap();
|
|
|
|
let s = s.split_ascii_whitespace();
|
|
|
|
let s = s.collect::<Vec<&str>>();
|
|
|
|
|
|
|
|
let scalar = s[0].to_string().parse::<u32>().unwrap();
|
|
|
|
let unit = s[1];
|
|
|
|
let unit = match unit {
|
|
|
|
"ps" => Ok(Timescale::ps),
|
|
|
|
"ns" => Ok(Timescale::ns),
|
|
|
|
"us" => Ok(Timescale::us),
|
|
|
|
"ms" => Ok(Timescale::ms),
|
|
|
|
"s" => Ok(Timescale::s),
|
|
|
|
// TODO : see if there is a way to easily print out all enum variants
|
|
|
|
// _ => Err(format!("{word} is not a valid unit of time in {Timescale}"))
|
|
|
|
_ => Err(format!("{unit} is not a valid unit"))
|
|
|
|
}.unwrap();
|
|
|
|
|
|
|
|
dbg!(s);
|
|
|
|
self.vcd.metadata.timescale = (Some(scalar), unit);
|
|
|
|
*state = Parser_State::Timescale(Timescale_Parser_State::Begin);
|
2022-05-24 03:45:14 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if let Some(ref mut buffer) = self.buffer {
|
|
|
|
buffer.push_str(" ");
|
|
|
|
buffer.push_str(word);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
self.buffer = Some(word.to_string());
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-05-23 03:00:03 +00:00
|
|
|
}
|
2022-05-24 03:45:14 +00:00
|
|
|
_ => Err(format!("{state:?} should be unreachable within {}.",function_name!())),
|
|
|
|
|
2022-05-21 19:22:05 +00:00
|
|
|
}
|
2022-05-21 02:52:26 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-14 04:50:37 +00:00
|
|
|
|
2022-05-23 03:00:03 +00:00
|
|
|
fn yield_word_and_apply(file : File, mut f : impl FnMut(&str) -> Result<(), String>) {
|
2022-04-14 04:50:37 +00:00
|
|
|
let mut reader = io::BufReader::new(file);
|
|
|
|
|
2022-05-19 01:32:41 +00:00
|
|
|
let mut buffer = String::new();
|
2022-05-19 02:57:42 +00:00
|
|
|
let mut EOF = false;
|
2022-05-19 01:32:41 +00:00
|
|
|
let line_chunk_size = 25;
|
2022-04-14 04:50:37 +00:00
|
|
|
|
2022-05-19 02:57:42 +00:00
|
|
|
while {!EOF} {
|
2022-05-19 01:32:41 +00:00
|
|
|
for _ in 0..line_chunk_size {
|
|
|
|
let bytes_read = reader.read_line(&mut buffer).unwrap();
|
|
|
|
if bytes_read == 0 {
|
2022-05-19 02:57:42 +00:00
|
|
|
EOF = true;
|
2022-05-19 01:32:41 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2022-05-19 00:47:55 +00:00
|
|
|
|
2022-05-19 01:32:41 +00:00
|
|
|
let words = buffer.split_ascii_whitespace();
|
|
|
|
|
|
|
|
for word in words {
|
2022-05-23 03:00:03 +00:00
|
|
|
f(word).unwrap();
|
2022-05-19 01:32:41 +00:00
|
|
|
}
|
2022-05-19 00:47:55 +00:00
|
|
|
|
2022-05-19 01:32:41 +00:00
|
|
|
buffer.clear();
|
2022-04-14 04:50:37 +00:00
|
|
|
}
|
2022-05-19 01:32:41 +00:00
|
|
|
|
2022-05-19 02:57:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn main() -> std::io::Result<()> {
|
|
|
|
let args = Cli::parse();
|
|
|
|
|
2022-05-19 07:44:24 +00:00
|
|
|
let file = File::open(&args.path)?;
|
2022-05-19 02:57:42 +00:00
|
|
|
|
2022-05-23 03:00:03 +00:00
|
|
|
let mut vcd = VCD::new();
|
|
|
|
let mut parser = VCD_Parser::new(&mut vcd);
|
|
|
|
|
|
|
|
yield_word_and_apply(file, |word| {parser.parse_word(word)});
|
|
|
|
dbg!(&vcd);
|
|
|
|
|
2022-04-14 04:50:37 +00:00
|
|
|
Ok(())
|
2022-05-21 19:22:05 +00:00
|
|
|
}
|