diff --git a/README.md b/README.md index 320a5f7..b1e3b16 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,8 @@ Here's a command to test on a malformed VCD: # TODO ## Features + - [ ] be explicit with imports, remove exports as possible + once FastWave is known to be fairly stable. - [ ] macro for getting line number when propagating errors - [ ] search for any ok_or's - [ ] search for any unwraps or any direct vectors indexing diff --git a/src/main.rs b/src/main.rs index aab1585..c69e331 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,17 @@ -use std::{fs::File}; use clap::Parser; +use std::fs::File; pub mod test; pub mod vcd; use vcd::parse_vcd; -use std::mem::size_of_val; - #[derive(Parser)] struct Cli { /// The path to the file to read #[clap(parse(from_os_str))] - path: std::path::PathBuf} + path: std::path::PathBuf, +} fn main() -> std::io::Result<()> { let args = Cli::parse(); @@ -21,19 +20,9 @@ fn main() -> std::io::Result<()> { let now = Instant::now(); let file = File::open(&args.path)?; - let vcd = parse_vcd(file).unwrap(); - + parse_vcd(file).unwrap(); let elapsed = now.elapsed(); println!("Elapsed: {:.2?}", elapsed); - vcd.print_longest_signal(); - dbg!(size_of_val(&*vcd.timeline)); - // unsafe { - // let sz = size_of_val(&*vcd.timeline); - // } - - // println!("printing signal tree"); - // vcd.print_scopes(); - Ok(()) -} \ No newline at end of file +} diff --git a/src/vcd.rs b/src/vcd.rs index 19f1a6c..b4dcc83 100644 --- a/src/vcd.rs +++ b/src/vcd.rs @@ -1,8 +1,11 @@ mod reader; -pub use reader::*; +use reader::*; mod types; -pub use types::*; +pub(super) use types::*; mod parse; -pub use parse::*; \ No newline at end of file +pub(super) use parse::*; + +mod utilities; +use utilities::*; diff --git a/src/vcd/parse.rs b/src/vcd/parse.rs index 813a9eb..1ae3bf2 100644 --- a/src/vcd/parse.rs +++ b/src/vcd/parse.rs @@ -19,65 +19,6 @@ use scopes::*; mod events; use events::*; -use std::cmp::Ordering; - -fn compare_strs(a: &str, b: &str) -> Ordering { - // choose the smaller of the two indices - let upper_bound = if a.len() > b.len() { b.len() } else { a.len() }; - let a_as_bytes = a.as_bytes(); - let b_as_bytes = b.as_bytes(); - - for i in 0..upper_bound { - let a_byte = a_as_bytes[i]; - let b_byte = b_as_bytes[i]; - if a_byte > b_byte { - return Ordering::Greater; - } - if b_byte > a_byte { - return Ordering::Less; - } - } - - if a.len() > b.len() { - return Ordering::Greater; - } - - if a.len() < b.len() { - return Ordering::Less; - } - - return Ordering::Equal; -} - -fn ordered_binary_lookup(map: &Vec<(String, SignalIdx)>, key: &str) -> Result { - let mut upper_idx = map.len() - 1; - let mut lower_idx = 0usize; - - while lower_idx <= upper_idx { - let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2); - let (str_val, signal_idx) = map.get(mid_idx).unwrap(); - let ordering = compare_strs(key, str_val.as_str()); - - match ordering { - Ordering::Less => { - upper_idx = mid_idx - 1; - } - Ordering::Equal => { - return Ok(*signal_idx); - } - Ordering::Greater => { - lower_idx = mid_idx + 1; - } - } - } - - return Err(format!( - "Error near {}:{}. Unable to find key: `{key}` in the map.", - file!(), - line!() - )); -} - pub fn parse_vcd(file: File) -> Result { let mut word_gen = WordReader::new(file); @@ -98,51 +39,6 @@ pub fn parse_vcd(file: File) -> Result { }; parse_scopes(&mut word_gen, &mut vcd, &mut signal_map)?; - - // the signal map should not contain any empty string - for (k, v) in &signal_map { - if k.len() == 0 { - return Err(format!("Critical error near {}:{}. There should be no empty strings in vcd string -> SignalIdx hashmap.", file!(), line!())); - } - } - - // now that we've parsed all scopes and filled the hashmap - // with signals, we convert hashmap to an ordered vector - let mut signal_map1: Vec<(String, SignalIdx)> = signal_map - .iter() - .map(|(string, idx)| (string.clone(), idx.clone())) - .collect(); - signal_map1.sort_by(|a: &(String, SignalIdx), b: &(String, SignalIdx)| { - let a = &a.0; - let b = &b.0; - compare_strs(a, b) - }); - - for (k, v) in &signal_map1 { - let signal_idx = ordered_binary_lookup(&signal_map1, k.as_str())?; - assert!(*v == signal_idx); - } - - // let now = std::time::Instant::now(); - // for (k, v) in &signal_map1 { - // let signal_idx = ordered_binary_lookup(&signal_map1, k.as_str())?; - // assert!(*v == signal_idx); - // } - // let ordered_binary_search_elapsed = now.elapsed(); - // println!( - // "ordered_binary_search_elapsed: {:.2?}", - // ordered_binary_search_elapsed - // ); - - // let now = std::time::Instant::now(); - // for (k, v) in &signal_map1 { - // // let signal_idx = ordered_binary_lookup(&signal_map1, k.as_str())?; - // let signal_idx = signal_map.get(k).unwrap(); - // assert!(*v == *signal_idx); - // } - // let hashmap_search_elapsed = now.elapsed(); - // println!("hashmap_search_elapsed: {:.2?}", hashmap_search_elapsed); - parse_events(&mut word_gen, &mut vcd, &mut signal_map)?; Ok(vcd) diff --git a/src/vcd/parse/events.rs b/src/vcd/parse/events.rs index e280e14..1ff5829 100644 --- a/src/vcd/parse/events.rs +++ b/src/vcd/parse/events.rs @@ -1,84 +1,5 @@ -//! part of the vcd parser that handles parsing the signal tree and -//! building the resulting signal tree -use core::time; - use super::*; -#[derive(Debug)] -pub(super) enum BinaryParserErrTypes { - XValue, - ZValue, - UValue, - OtherValue(char), - TooLong, -} - -// We build a quick and not so dirty bit string parser. -fn base2_str_to_byte(word: &[u8]) -> Result { - let mut val = 0u8; - - // shouldn't have more than 8 chars in str - let len = word.len(); - if len > 8 { - return Err(BinaryParserErrTypes::TooLong); - } - - let bit_lut = [ - 0b0000_0001u8, - 0b0000_0010u8, - 0b0000_0100u8, - 0b0000_1000u8, - 0b0001_0000u8, - 0b0010_0000u8, - 0b0100_0000u8, - 0b1000_0000u8, - ]; - - for (idx, chr) in word.iter().rev().enumerate() { - match chr { - b'1' => val = bit_lut[idx] | val, - b'0' => {} - b'x' | b'X' => return Err(BinaryParserErrTypes::XValue), - b'z' | b'Z' => return Err(BinaryParserErrTypes::ZValue), - b'u' | b'U' => return Err(BinaryParserErrTypes::UValue), - _ => return Err(BinaryParserErrTypes::OtherValue(*chr as char)), - } - } - - Ok(val) -} - -fn binary_str_to_vec_u8(binary_str: &str) -> Result, BinaryParserErrTypes> { - let mut vec_u8: Vec = Vec::new(); - let binary_str_as_bytes = binary_str.as_bytes(); - - let mut tail_idx = binary_str_as_bytes.len(); - // clamp head if provided binary str is less than 8 long - let mut head_idx = if tail_idx >= 8 { - binary_str_as_bytes.len() - 8 - } else { - 0 - }; - while tail_idx > 0 { - let curr_b_val = &binary_str_as_bytes[head_idx..tail_idx]; - let val_u8 = base2_str_to_byte(curr_b_val)?; - vec_u8.push(val_u8); - - if head_idx < 8 { - head_idx = 0 - } else { - head_idx = head_idx - 8; - } - - if tail_idx < 8 { - tail_idx = 0 - } else { - tail_idx = tail_idx - 8; - } - } - Ok(vec_u8) -} - pub(super) fn parse_events<'a>( word_reader: &mut WordReader, vcd: &'a mut VCD, @@ -284,7 +205,6 @@ pub(super) fn parse_events<'a>( "0" => { // lookup signal idx let hash = &word[1..]; - let (f, l) = (file!(), line!()); let SignalIdx(ref signal_idx) = signal_map.get(hash).ok_or(()).map_err(|_| { format!( "Error near {}:{}. Failed to lookup signal {hash} at {cursor:?}", diff --git a/src/vcd/utilities.rs b/src/vcd/utilities.rs new file mode 100644 index 0000000..cb050d8 --- /dev/null +++ b/src/vcd/utilities.rs @@ -0,0 +1,137 @@ +use super::*; + +use std::cmp::Ordering; + +#[derive(Debug)] +pub(super) enum BinaryParserErrTypes { + XValue, + ZValue, + UValue, + OtherValue(char), + TooLong, +} + +// We build a quick and not so dirty bit string parser. +pub(super) fn base2_str_to_byte(word: &[u8]) -> Result { + let mut val = 0u8; + + // shouldn't have more than 8 chars in str + let len = word.len(); + if len > 8 { + return Err(BinaryParserErrTypes::TooLong); + } + + let bit_lut = [ + 0b0000_0001u8, + 0b0000_0010u8, + 0b0000_0100u8, + 0b0000_1000u8, + 0b0001_0000u8, + 0b0010_0000u8, + 0b0100_0000u8, + 0b1000_0000u8, + ]; + + for (idx, chr) in word.iter().rev().enumerate() { + match chr { + b'1' => val = bit_lut[idx] | val, + b'0' => {} + b'x' | b'X' => return Err(BinaryParserErrTypes::XValue), + b'z' | b'Z' => return Err(BinaryParserErrTypes::ZValue), + b'u' | b'U' => return Err(BinaryParserErrTypes::UValue), + _ => return Err(BinaryParserErrTypes::OtherValue(*chr as char)), + } + } + + Ok(val) +} + +pub(super) fn binary_str_to_vec_u8(binary_str: &str) -> Result, BinaryParserErrTypes> { + let mut vec_u8: Vec = Vec::new(); + let binary_str_as_bytes = binary_str.as_bytes(); + + let mut tail_idx = binary_str_as_bytes.len(); + // clamp head if provided binary str is less than 8 long + let mut head_idx = if tail_idx >= 8 { + binary_str_as_bytes.len() - 8 + } else { + 0 + }; + while tail_idx > 0 { + let curr_b_val = &binary_str_as_bytes[head_idx..tail_idx]; + let val_u8 = base2_str_to_byte(curr_b_val)?; + vec_u8.push(val_u8); + + if head_idx < 8 { + head_idx = 0 + } else { + head_idx = head_idx - 8; + } + + if tail_idx < 8 { + tail_idx = 0 + } else { + tail_idx = tail_idx - 8; + } + } + Ok(vec_u8) +} + +// TODO : modify ordered_binary_lookup to support VCD timeline lookup +// and return time in signature +fn compare_strs(a: &str, b: &str) -> Ordering { + // choose the smaller of the two indices + let upper_bound = if a.len() > b.len() { b.len() } else { a.len() }; + let a_as_bytes = a.as_bytes(); + let b_as_bytes = b.as_bytes(); + + for i in 0..upper_bound { + let a_byte = a_as_bytes[i]; + let b_byte = b_as_bytes[i]; + if a_byte > b_byte { + return Ordering::Greater; + } + if b_byte > a_byte { + return Ordering::Less; + } + } + + if a.len() > b.len() { + return Ordering::Greater; + } + + if a.len() < b.len() { + return Ordering::Less; + } + + return Ordering::Equal; +} + +fn ordered_binary_lookup(map: &Vec<(String, SignalIdx)>, key: &str) -> Result { + let mut upper_idx = map.len() - 1; + let mut lower_idx = 0usize; + + while lower_idx <= upper_idx { + let mid_idx = lower_idx + ((upper_idx - lower_idx) / 2); + let (str_val, signal_idx) = map.get(mid_idx).unwrap(); + let ordering = compare_strs(key, str_val.as_str()); + + match ordering { + Ordering::Less => { + upper_idx = mid_idx - 1; + } + Ordering::Equal => { + return Ok(*signal_idx); + } + Ordering::Greater => { + lower_idx = mid_idx + 1; + } + } + } + + return Err(format!( + "Error near {}:{}. Unable to find key: `{key}` in the map.", + file!(), + line!() + )); +}