diff --git a/README.md b/README.md index 7890a1e..5dfa11b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Copyright(2023) - Yehowshua Immanuel +Copyright - Yehowshua Immanuel # Vision Imagine being able to visualize a CPU pipeline diagram by merely loading a simulation waveform dump, sprinkling in a bit of code, and dragging and dropping some diagram blocks into the visualizer. This project aims to offer such an experience. @@ -6,7 +6,10 @@ Imagine being able to visualize a CPU pipeline diagram by merely loading a simul Since this project is written in Rust, it should also be able to run in the browser via web-assembly. # Status -As of January 2024, work on the Fastwave Backend is stalled. It has been a fun journey watching Fastwave enable the first iterations of the [surfer waveform viewer](https://surfer-project.org). Now surfer uses an even better backend called [Wellen](https://github.com/ekiwi/wellen?tab=readme-ov-file). Go check it out! I hear it's really good. Perhaps I will soon archive the Fastwave Backend. +I hope to work on this more actively again soon. + +The Zoq is is working on an excellent frontend call the Surfer. Check it out +[here](https://gitlab.com/surfer-project/surfer)! Browser demo: https://app.surfer-project.org/ diff --git a/src/vcd/signal.rs b/src/vcd/signal.rs index b87e1a2..c1522f0 100644 --- a/src/vcd/signal.rs +++ b/src/vcd/signal.rs @@ -40,11 +40,6 @@ pub enum SignalValue { String(String), } -pub struct QueryResult { - pub current: Option<(TimeStamp, T)>, - pub next: Option, -} - pub struct Signal<'a>(pub(super) &'a SignalEnum); impl<'a> Signal<'a> { @@ -87,9 +82,6 @@ impl<'a> Signal<'a> { signal_enum.bits_required() } - // NOTE: (zoq) I am removing thse because they aren't used in Surfer so I can't test them - // properly - /* pub fn query_string_val_on_tmln( &self, desired_time: &BigUint, @@ -98,33 +90,32 @@ impl<'a> Signal<'a> { let Signal(signal_enum) = &self; signal_enum .query_string_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals) - .map(|QueryResult{current, next: _}| current.map(|c| c.1)) + .map(|(val, _)| val) } pub fn query_num_val_on_tmln( &self, desired_time: &BigUint, vcd: &types::VCD, - ) -> Result, SignalErrors> { + ) -> Result { let Signal(signal_enum) = &self; signal_enum .query_num_val_on_tmln(desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals) - .map(|QueryResult{current, next: _}| current.map(|c| c.1)) + .map(|(val, _)| val) } - */ pub fn query_val_on_tmln( &self, desired_time: &BigUint, vcd: &types::VCD, - ) -> Result, SignalErrors> { + ) -> Result<(TimeStamp, SignalValue), SignalErrors> { let Signal(signal_enum) = &self; - let num_query_out = signal_enum.query_num_val_on_tmln( + let num_val = signal_enum.query_num_val_on_tmln( desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals, ); - let str_query_out = signal_enum.query_string_val_on_tmln( + let str_val = signal_enum.query_string_val_on_tmln( desired_time, &vcd.tmstmps_encoded_as_u8s, &vcd.all_signals, @@ -133,44 +124,16 @@ impl<'a> Signal<'a> { // 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_query_out, str_query_out) { - (Ok(num_result), Ok(str_result)) => { - let next = match (num_result.next, str_result.next) { - (Some(n), Some(s)) => Some(n.min(s)), - (Some(n), None) => Some(n), - (None, Some(s)) => Some(s), - (None, None) => None, - }; - - match (num_result.current, str_result.current) { - (Some((num_time, num_value)), Some((str_time, str_value))) => { - if num_time > str_time { - Ok(QueryResult { - current: Some((num_time, SignalValue::BigUint(num_value))), - next, - }) - } else { - Ok(QueryResult { - current: Some((str_time, SignalValue::String(str_value))), - next, - }) - } - } - (Some((num_time, num_val)), None) => Ok(QueryResult { - current: Some((num_time, SignalValue::BigUint(num_val))), - next, - }), - (None, Some((str_time, str_value))) => Ok(QueryResult { - current: Some((str_time, SignalValue::String(str_value))), - next, - }), - (None, None) => Ok(QueryResult { - current: None, - next, - }), + 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))) } } - (_e, Err(e)) => Err(e), + (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), } } @@ -229,6 +192,10 @@ pub(super) enum SignalEnum { #[derive(Debug)] pub enum SignalErrors { + PreTimeline { + desired_time: BigUint, + timeline_start_time: BigUint, + }, EmptyTimeline, TimelineNotMultiple, StrTmlnLenMismatch, @@ -429,7 +396,7 @@ impl SignalEnum { desired_time: &BigUint, tmstmps_encoded_as_u8s: &Vec, all_signals: &Vec, - ) -> Result, SignalErrors> { + ) -> Result<(String, TimeStamp), SignalErrors> { let signal_idx = match self { Self::Data { self_idx, .. } => { let SignalIdx(idx) = self_idx; @@ -463,10 +430,7 @@ impl SignalEnum { // this signal should at least have some events, otherwise, trying to index into // an empty vector later on would fail if lsb_indxs_of_string_tmstmp_vals_on_tmln.is_empty() { - return Ok(QueryResult { - current: None, - next: None - }); + return Err(SignalErrors::EmptyTimeline); } // the vector of string timeline lsb indices should have the same @@ -480,9 +444,9 @@ impl SignalEnum { let (timeline_start_time, _) = self.time_and_str_val_at_event_idx(0, tmstmps_encoded_as_u8s)?; if *desired_time < timeline_start_time { - return Ok(QueryResult { - current: None, - next: Some(timeline_start_time), + return Err(SignalErrors::PreTimeline { + desired_time: desired_time.clone(), + timeline_start_time, }); } @@ -494,10 +458,7 @@ impl SignalEnum { // 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 *desired_time > timeline_end_time { - return Ok(QueryResult { - current: Some((timeline_end_time, timeline_end_val.to_string())), - next: None, - }); + return Ok((timeline_end_val.to_string(), timeline_end_time)); } // This while loop is the meat of the lookup. Performance is log2(n), @@ -516,21 +477,7 @@ impl SignalEnum { lower_idx = mid_idx + 1; } std::cmp::Ordering::Equal => { - let next_time = if mid_idx < lsb_indxs_of_string_tmstmp_vals_on_tmln.len() - 1 { - Some( - self.time_and_str_val_at_event_idx( - mid_idx + 1, - tmstmps_encoded_as_u8s, - )? - .0, - ) - } else { - None - }; - return Ok(QueryResult { - current: Some((curr_time, curr_val.to_string())), - next: next_time, - }); + return Ok((curr_val.to_string(), curr_time)); } std::cmp::Ordering::Greater => { upper_idx = mid_idx - 1; @@ -553,17 +500,14 @@ impl SignalEnum { }); } - Ok(QueryResult { - current: Some((left_time, left_val.to_string())), - next: Some(right_time), - }) + Ok((left_val.to_string(), left_time)) } pub fn query_num_val_on_tmln( &self, desired_time: &BigUint, tmstmps_encoded_as_u8s: &Vec, all_signals: &Vec, - ) -> Result, SignalErrors> { + ) -> Result<(BigUint, TimeStamp), SignalErrors> { let signal_idx = match self { Self::Data { self_idx, .. } => { let SignalIdx(idx) = self_idx; @@ -608,10 +552,7 @@ impl SignalEnum { // this signal should at least have some events, otherwise, trying to index into // an empty vector later on would fail if lsb_indxs_of_num_tmstmp_vals_on_tmln.is_empty() { - return Ok(QueryResult { - current: None, - next: None - }); + return Err(SignalErrors::EmptyTimeline); } // assertion that value_sequence is a proper multiple of @@ -634,9 +575,9 @@ impl SignalEnum { let (timeline_start_time, _) = self.time_and_num_val_at_event_idx(0, tmstmps_encoded_as_u8s)?; if *desired_time < timeline_start_time { - return Ok(QueryResult { - current: None, - next: Some(timeline_start_time), + return Err(SignalErrors::PreTimeline { + desired_time: desired_time.clone(), + timeline_start_time, }); } @@ -648,10 +589,7 @@ impl SignalEnum { // 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 *desired_time > timeline_end_time { - return Ok(QueryResult { - current: Some((timeline_end_time, timeline_end_val)), - next: None, - }); + return Ok((timeline_end_val, timeline_end_time)); } // This while loop is the meat of the lookup. Performance is log2(n), @@ -670,21 +608,7 @@ impl SignalEnum { lower_idx = mid_idx + 1; } std::cmp::Ordering::Equal => { - let next_time = if mid_idx < lsb_indxs_of_num_tmstmp_vals_on_tmln.len() - 1 { - Some( - self.time_and_num_val_at_event_idx( - mid_idx + 1, - tmstmps_encoded_as_u8s, - )? - .0, - ) - } else { - None - }; - return Ok(QueryResult { - current: Some((curr_time, curr_val)), - next: next_time, - }); + return Ok((curr_val, curr_time)); } std::cmp::Ordering::Greater => { upper_idx = mid_idx - 1; @@ -707,9 +631,6 @@ impl SignalEnum { }); } - return Ok(QueryResult { - current: Some((left_time, left_val)), - next: Some(right_time), - }); + Ok((left_val, left_time)) } }