1use anyhow::{Result, bail};
6use std::io;
7use thiserror::Error;
8
9use crate::io::gpio::{Edge, MonitoringEvent, MonitoringReadResponse};
10
11#[derive(Debug)]
13pub struct Header {
14 pub timescale_ps: Option<u128>,
15 pub date: Option<String>,
16 pub version: Option<String>,
17}
18
19#[derive(Debug)]
22pub struct Signal {
23 pub signal_type: String,
24 pub width: u32,
25 pub reference: String,
26}
27
28#[derive(Debug)]
31pub enum ScopeItem {
32 Scope {
33 scope_type: String,
34 identifier: String,
35 items: Vec<Self>,
36 },
37 VarDef {
38 signal: Signal,
39 identifier: String,
40 },
41}
42
43impl ScopeItem {
44 pub fn var_names(&self) -> Vec<&str> {
46 match self {
47 ScopeItem::Scope { items, .. } => {
48 let mut identifiers = Vec::new();
49 for item in items {
50 identifiers.extend(item.var_names())
51 }
52 identifiers
53 }
54 ScopeItem::VarDef { identifier, .. } => {
55 vec![identifier]
56 }
57 }
58 }
59}
60
61#[derive(Debug)]
64pub struct VarDefs {
65 scopes: Vec<ScopeItem>,
66}
67
68impl VarDefs {
69 pub fn var_names(&self) -> Vec<&str> {
71 let mut identifiers = Vec::new();
72 for scope in &self.scopes {
73 identifiers.extend(scope.var_names());
74 }
75 identifiers
76 }
77}
78
79#[derive(Debug)]
81pub enum ScalarValue {
82 Zero,
83 One,
84 X,
86 Z,
88}
89
90#[derive(Debug)]
94pub enum ValueChangeItem {
95 Timestamp {
96 step: u128,
97 },
98 Scalar {
99 identifier: String,
100 value: ScalarValue,
101 },
102 }
104
105#[derive(Debug)]
108pub struct ValueChangeSection {
109 pub changes: Vec<ValueChangeItem>,
110}
111
112#[derive(Debug)]
115pub struct Vcd {
116 pub header: Header,
117 pub vardefs: VarDefs,
118 pub value_changes: ValueChangeSection,
119}
120
121impl Vcd {
122 pub fn var_names(&self) -> Vec<&str> {
124 self.vardefs.var_names()
125 }
126}
127
128#[derive(Debug, Error)]
130pub enum VcdDumpError {
131 #[error("Cannot represent VCD timescale {0}ps")]
132 InvalidTimescale(u128),
133 #[error("Timestamps out of order: {0} and {1}")]
134 TimestampsOutOfOrder(u128, u128),
135}
136
137#[derive(Debug)]
139pub struct VcdWriter<W: io::Write> {
140 pub writer: W,
141}
142
143impl<W: io::Write> VcdWriter<W> {
144 pub fn new(writer: W) -> Self {
145 VcdWriter { writer }
146 }
147
148 pub fn flush(&mut self) -> Result<()> {
149 self.writer.flush()?;
150 Ok(())
151 }
152
153 pub fn write_vcd(&mut self, vcd: &Vcd) -> Result<()> {
154 self.write_header(&vcd.header)?;
155 self.write_vardefs(&vcd.vardefs)?;
156 self.write_value_change_section(&vcd.value_changes, 0u128)?;
157 writeln!(self.writer)?;
158 Ok(())
159 }
160
161 pub fn write_header(&mut self, header: &Header) -> Result<()> {
162 if let Some(timescale_ps) = &header.timescale_ps {
165 if *timescale_ps < 1 {
166 bail!(VcdDumpError::InvalidTimescale(*timescale_ps));
167 }
168 writeln!(self.writer, "$timescale {}ps $end", timescale_ps)?;
169 }
170 if let Some(date) = &header.date {
171 writeln!(self.writer, "$date {} $end", date)?;
172 }
173 if let Some(version) = &header.version {
174 writeln!(self.writer, "$version {} $end", version)?;
175 }
176 Ok(())
177 }
178
179 pub fn write_vardefs(&mut self, vardefs: &VarDefs) -> Result<()> {
180 for scope in &vardefs.scopes {
181 self.write_scope_item(scope)?;
182 }
183 writeln!(self.writer, "$enddefinitions $end")?;
184 Ok(())
185 }
186
187 pub fn write_scope_item(&mut self, scope: &ScopeItem) -> Result<()> {
188 match scope {
189 ScopeItem::Scope {
190 scope_type,
191 identifier,
192 items,
193 } => {
194 writeln!(self.writer, "$scope {} {} $end", &scope_type, &identifier)?;
195 for item in items {
196 self.write_scope_item(item)?;
197 }
198 writeln!(self.writer, "$upscope $end")?;
199 }
200 ScopeItem::VarDef { signal, identifier } => {
201 writeln!(
202 self.writer,
203 "$var {} {} {} {} $end",
204 &signal.signal_type, signal.width, &identifier, &signal.reference
205 )?;
206 }
207 }
208 Ok(())
209 }
210
211 pub fn write_value_change_section(
212 &mut self,
213 vcs: &ValueChangeSection,
214 initial_timestamp: u128,
215 ) -> Result<()> {
216 let mut current_timestamp = initial_timestamp;
217 for (i, value_change_item) in vcs.changes.iter().enumerate() {
218 if let ValueChangeItem::Timestamp { step } = value_change_item {
219 if *step < current_timestamp {
220 bail!(VcdDumpError::TimestampsOutOfOrder(current_timestamp, *step));
221 }
222 current_timestamp = *step;
223 if i != 0 {
224 writeln!(self.writer)?;
225 }
226 }
227 self.write_value_change_item(value_change_item)?;
228 write!(self.writer, " ")?;
229 }
230 Ok(())
231 }
232
233 pub fn write_value_change_item(&mut self, item: &ValueChangeItem) -> Result<()> {
234 match item {
235 ValueChangeItem::Timestamp { step } => {
236 write!(self.writer, "#{}", step)?;
237 }
238 ValueChangeItem::Scalar { identifier, value } => {
239 self.write_scalar_change(identifier, value)?;
240 }
241 }
242 Ok(())
243 }
244
245 pub fn write_scalar_change(&mut self, identifier: &str, value: &ScalarValue) -> Result<()> {
246 let value = match value {
247 ScalarValue::Zero => "0",
248 ScalarValue::One => "1",
249 ScalarValue::X => "X",
250 ScalarValue::Z => "Z",
251 };
252 write!(self.writer, "{}{}", value, identifier)?;
253 Ok(())
254 }
255}
256
257pub fn dump_vcd(vcd: &Vcd) -> Result<String> {
260 let mut vcd_bytes = Vec::new();
261 let mut writer = VcdWriter::new(&mut vcd_bytes);
262 writer.write_vcd(vcd)?;
263 writer.flush()?;
264 Ok(String::from_utf8(vcd_bytes).expect("Generated VCD should be UTF-8 compatible"))
265}
266
267#[derive(Debug, Error)]
269pub enum VcdParseError {
270 #[error("Missing required {0} value")]
271 MissingValue(String),
272 #[error("Missing required definition {0}")]
273 MissingDefinition(String),
274 #[error("Missing $end for definition {0}")]
275 MissingDefinitionEnd(String),
276 #[error("Multiple definitions for {0}")]
277 MultipleDefinitions(String),
278 #[error("Found $end when there was no definition to end")]
279 MismatchedEnd,
280 #[error("Found a $scope after already parsing $enddefinitions")]
281 DefinitionAfterEnd,
282 #[error("{0} is not yet supported by VCD parsing")]
283 UnsupportedFeature(String),
284 #[error("VCD timestamps #{0} and #{1} are out of order!")]
285 TimestampsOutOfOrder(u128, u128),
286 #[error("Unrecognized value {0}")]
287 UnknownToken(String),
288 #[error("Supplied identifier {0} does not match any defined identifier")]
289 UnknownVariable(String),
290}
291
292#[derive(Debug)]
295struct WhitespaceTokenizer<R: io::BufRead> {
296 reader: R,
297 line_buf: String,
298 tokens: Vec<String>,
299}
300
301impl<R: io::BufRead> WhitespaceTokenizer<R> {
302 fn new(reader: R) -> Self {
303 Self {
304 reader,
305 line_buf: String::new(),
306 tokens: Vec::new(),
307 }
308 }
309}
310
311impl<R: io::BufRead> Iterator for WhitespaceTokenizer<R> {
312 type Item = io::Result<String>;
313
314 fn next(&mut self) -> Option<Self::Item> {
315 loop {
316 if let Some(token) = self.tokens.pop() {
317 return Some(Ok(token));
318 }
319 self.line_buf.clear();
320 match self.reader.read_line(&mut self.line_buf) {
321 Ok(0) => return None, Ok(_) => {}
323 Err(e) => return Some(Err(e)),
324 };
325 self.tokens = self
328 .line_buf
329 .split_whitespace()
330 .map(|s| s.to_string())
331 .rev()
332 .collect();
333 }
334 }
335}
336
337#[derive(Debug)]
339pub struct VcdParser<R: io::BufRead> {
340 tokenizer: WhitespaceTokenizer<R>,
341 identifiers: Vec<String>,
342}
343
344impl<R: io::BufRead> VcdParser<R> {
345 pub fn new(reader: R) -> Self {
346 VcdParser {
347 tokenizer: WhitespaceTokenizer::new(reader),
348 identifiers: Vec::new(),
349 }
350 }
351
352 pub fn next_token(&mut self) -> Result<Option<String>, io::Error> {
354 self.tokenizer.next().transpose()
355 }
356
357 pub fn parse_vcd(&mut self) -> Result<Vcd> {
358 Ok(Vcd {
359 header: self.parse_header()?,
360 vardefs: self.parse_vardefs()?,
361 value_changes: self.parse_value_change_section()?,
362 })
363 }
364
365 pub fn parse_header(&mut self) -> Result<Header> {
366 let mut header = Header {
367 timescale_ps: None,
368 date: None,
369 version: None,
370 };
371 while let Some(token) = self.next_token()?.as_deref() {
372 match token {
373 "$timescale" => {
374 if header.timescale_ps.is_some() {
375 bail!(VcdParseError::MultipleDefinitions("timescale".into()));
376 }
377 let timescale_str = self.parse_header_str("timescale")?;
380 header.timescale_ps = if timescale_str.ends_with("ps") {
381 Some(
382 timescale_str
383 .strip_suffix("ps")
384 .unwrap()
385 .trim()
386 .parse::<u128>()?,
387 )
388 } else {
389 Some(humantime::parse_duration(×cale_str)?.as_nanos() * 1000)
390 }
391 }
392 "$date" => {
393 if header.date.is_some() {
394 bail!(VcdParseError::MultipleDefinitions("date".into()));
395 }
396 header.date = Some(self.parse_header_str("date")?)
397 }
398 "$version" => {
399 if header.version.is_some() {
400 bail!(VcdParseError::MultipleDefinitions("version".into()));
401 }
402 header.version = Some(self.parse_header_str("version")?)
403 }
404 "$scope" => {
405 return Ok(header);
406 }
407 _ => (),
408 }
409 }
410 bail!(VcdParseError::MissingDefinition("scope".into()))
411 }
412
413 pub fn parse_header_str(&mut self, field: &str) -> Result<String> {
414 let Some(mut value) = self.next_token()? else {
415 bail!(VcdParseError::MissingValue(field.into()));
416 };
417 loop {
418 match self.next_token()?.as_deref() {
419 Some("$end") => return Ok(value),
420 Some(next_val) => {
421 value.push(' ');
422 value.push_str(next_val);
423 }
424 None => bail!(VcdParseError::MissingDefinitionEnd(field.into())),
425 }
426 }
427 }
428
429 pub fn parse_vardefs(&mut self) -> Result<VarDefs> {
430 let mut scopes = Vec::new();
431 scopes.push(self.parse_scope()?);
432 let mut end_seen = false;
433 while let Some(token) = self.next_token()?.as_deref() {
434 match (token, end_seen) {
435 ("$scope", false) => {
436 scopes.push(self.parse_scope()?);
437 }
438 ("$scope", true) => bail!(VcdParseError::DefinitionAfterEnd),
439 ("$enddefinitions", false) => {
440 end_seen = true;
441 }
442 ("$enddefinitions", true) => {
443 bail!(VcdParseError::MultipleDefinitions("$enddefinitions".into()))
444 }
445 ("$end", false) => bail!(VcdParseError::MismatchedEnd),
446 ("$end", true) => return Ok(VarDefs { scopes }),
447 _ => (),
448 }
449 }
450 bail!(VcdParseError::MissingDefinition("$enddefinitions".into()))
451 }
452
453 pub fn parse_scope(&mut self) -> Result<ScopeItem> {
454 let Some(scope_type) = self.next_token()? else {
455 bail!(VcdParseError::MissingValue("scope type".into()));
456 };
457 let Some(identifier) = self.next_token()? else {
458 bail!(VcdParseError::MissingValue("scope name".into()));
459 };
460 match self.next_token()?.as_deref() {
461 Some("$end") => (),
462 _ => bail!(VcdParseError::MissingDefinitionEnd("scope".into())),
463 };
464 let mut items = Vec::new();
465 while let Some(token) = self.next_token()?.as_deref() {
466 match token {
467 "$scope" => {
468 items.push(self.parse_scope()?);
469 }
470 "$var" => {
471 items.push(self.parse_variable()?);
472 }
473 "$end" => {
474 return Ok(ScopeItem::Scope {
475 scope_type,
476 identifier,
477 items,
478 });
479 }
480 _ => (),
481 }
482 }
483 bail!(VcdParseError::MissingDefinitionEnd("scope".into()))
484 }
485
486 pub fn parse_variable(&mut self) -> Result<ScopeItem> {
487 let Some(signal_type) = self.next_token()? else {
488 bail!(VcdParseError::MissingValue("signal type".into()));
489 };
490 let Some(var_width) = self.next_token()? else {
491 bail!(VcdParseError::MissingValue("signal width".into()));
492 };
493 let width = var_width.parse::<u32>()?;
494 let Some(identifier) = self.next_token()? else {
495 bail!(VcdParseError::MissingValue("identifier".into()));
496 };
497 let Some(reference) = self.next_token()? else {
498 bail!(VcdParseError::MissingValue("signal name".into()));
499 };
500 match self.next_token()?.as_deref() {
501 Some("$end") => {
502 self.identifiers.push(identifier.to_string());
503 Ok(ScopeItem::VarDef {
504 signal: Signal {
505 signal_type,
506 width,
507 reference,
508 },
509 identifier,
510 })
511 }
512 _ => bail!(VcdParseError::MissingDefinitionEnd("var".into())),
513 }
514 }
515
516 pub fn parse_value_change_section(&mut self) -> Result<ValueChangeSection> {
517 let mut changes = Vec::new();
518 let current_step: u128 = 0;
519 while let Some(token) = self.next_token()? {
520 match token.as_str() {
521 "$dumpvars" => {
523 bail!(VcdParseError::UnsupportedFeature("$dumpvars".into()));
524 }
525 "$end" => bail!(VcdParseError::MismatchedEnd),
526 v if v.starts_with("$") => {
527 bail!(VcdParseError::UnsupportedFeature("commands".into()));
528 }
529 v if v.starts_with("#") => {
531 let step = v.strip_prefix("#").unwrap().parse::<u128>()?;
532 if step < current_step {
533 bail!(VcdParseError::TimestampsOutOfOrder(current_step, step));
534 }
535 changes.push(ValueChangeItem::Timestamp { step });
536 }
537 v if v.starts_with(['0', '1', 'z', 'Z', 'x', 'X']) => {
539 changes.push(self.parse_scalar(token)?);
540 }
541 v if v.starts_with(['b', 'B']) => {
543 bail!(VcdParseError::UnsupportedFeature("vector signals".into()))
544 }
545 v if v.starts_with(['r', 'R']) => {
546 bail!(VcdParseError::UnsupportedFeature("real vars".into()))
547 }
548 v if v.starts_with(['s', 'S']) => {
549 bail!(VcdParseError::UnsupportedFeature("strings".into()))
550 }
551 v => bail!(VcdParseError::UnknownToken(v.into())),
552 }
553 }
554 Ok(ValueChangeSection { changes })
555 }
556
557 pub fn parse_scalar(&self, token: String) -> Result<ValueChangeItem> {
558 let value = match &token[0..1] {
559 "0" => ScalarValue::Zero,
560 "1" => ScalarValue::One,
561 "z" | "Z" => ScalarValue::Z,
562 "x" | "X" => ScalarValue::X,
563 v => bail!(VcdParseError::UnknownToken(v.into())),
564 };
565 let identifier = token[1..].to_string();
566 if !self.identifiers.contains(&identifier) {
567 bail!(VcdParseError::UnknownVariable(identifier));
568 }
569 Ok(ValueChangeItem::Scalar { identifier, value })
570 }
571}
572
573pub fn load_vcd(vcd: &str) -> Result<Vcd> {
576 let cursor = io::Cursor::new(vcd.as_bytes());
577 let mut parser = VcdParser::new(cursor);
578 parser.parse_vcd()
579}
580
581fn dump_vcd_sample(
586 pin_vars: &[String],
587 timestamp: u128,
588 sample: &[u8],
589 prev_sample: Option<&[u8]>,
590) -> Vec<ValueChangeItem> {
591 let mut changes = Vec::with_capacity(pin_vars.len());
592 for (i, var) in pin_vars.iter().enumerate() {
593 let byte_index = i / 8;
595 let bit_index = i % 8;
596 let sample_byte = sample.get(byte_index).unwrap_or(&0x00);
597 let bit = (sample_byte >> bit_index) & 0x01;
598 if let Some(prev_bytes) = prev_sample {
599 let prev_byte = prev_bytes.get(byte_index).unwrap_or(&0x00);
600 let prev_bit = (prev_byte >> bit_index) & 0x01;
601 if prev_bit == bit {
602 continue;
603 }
604 }
605 if changes.is_empty() {
608 changes.push(ValueChangeItem::Timestamp { step: timestamp });
609 }
610 changes.push(ValueChangeItem::Scalar {
611 identifier: var.to_string(),
612 value: if bit != 0 {
613 ScalarValue::One
614 } else {
615 ScalarValue::Zero
616 },
617 });
618 }
619 changes
620}
621
622pub fn dump_vcd_wire_vardefs(scope: String, pin_vars: Vec<(String, Option<String>)>) -> VarDefs {
626 let opentitanlib_scope = ScopeItem::Scope {
627 scope_type: String::from("module"),
628 identifier: scope,
629 items: pin_vars
630 .into_iter()
631 .enumerate()
632 .map(|(i, (identifier, pin))| ScopeItem::VarDef {
633 signal: Signal {
634 signal_type: String::from("wire"),
635 width: 1,
636 reference: pin.unwrap_or(format!("pin_{}", i)),
637 },
638 identifier,
639 })
640 .collect::<Vec<_>>(),
641 };
642 VarDefs {
643 scopes: vec![opentitanlib_scope],
644 }
645}
646
647pub fn vcd_from_samples(
653 pin_names: Vec<Option<String>>,
654 timescale_ps: u128,
655 samples: &[&[u8]],
656) -> Result<Vcd> {
657 let header = Header {
659 timescale_ps: Some(timescale_ps),
660 date: None,
661 version: None,
662 };
663 let vars = &(0..pin_names.len())
664 .map(|c| format!("'{}", c))
665 .collect::<Vec<_>>();
666 let vardefs = dump_vcd_wire_vardefs(
667 String::from("opentitanlib"),
668 vars.clone().into_iter().zip(pin_names).collect::<Vec<_>>(),
669 );
670
671 let mut changes = Vec::new();
674 let mut prev_sample = None;
675 let mut last_sample_index = 0;
676 let num_samples = samples.len();
677 for (i, sample) in samples.iter().enumerate() {
678 let value_change_items = dump_vcd_sample(vars, i as u128, sample, prev_sample);
679 prev_sample = Some(sample);
680 if !value_change_items.is_empty() {
681 changes.extend(value_change_items);
682 last_sample_index = i;
683 }
684 }
685
686 if (last_sample_index + 1) < num_samples {
688 changes.push(ValueChangeItem::Timestamp {
689 step: num_samples as u128 - 1,
690 });
691 }
692 let value_changes = ValueChangeSection { changes };
693
694 Ok(Vcd {
696 header,
697 vardefs,
698 value_changes,
699 })
700}
701
702fn timestamp_to_picos(initial: u64, timestamp: u64, clock_res: u64) -> u128 {
705 let delta = (timestamp - initial) as u128;
706 delta * 1_000_000_000_000u128 / (clock_res as u128)
707}
708
709fn timestamp_from_picos(initial: u64, picos: u128, clock_res: u64) -> u64 {
712 let delta = picos * clock_res as u128 / 1_000_000_000_000u128;
713 initial + delta as u64
714}
715
716pub fn vcd_from_edges(
721 pin_names: Vec<Option<String>>,
722 clock_resolution: u64,
723 initial_timestamp: u64,
724 initial_values: &[bool],
725 events: &[MonitoringEvent],
726 final_timestamp: u64,
727) -> Result<Vcd> {
728 let header = Header {
732 timescale_ps: Some(1),
733 date: None,
734 version: None,
735 };
736 let vars = &(0..pin_names.len())
737 .map(|c| format!("'{}", c))
738 .collect::<Vec<_>>();
739 let vardefs = dump_vcd_wire_vardefs(
740 String::from("opentitanlib"),
741 vars.clone().into_iter().zip(pin_names).collect::<Vec<_>>(),
742 );
743
744 let mut changes = Vec::new();
746 changes.push(ValueChangeItem::Timestamp { step: 0 });
748 for (&bit, var) in initial_values.iter().zip(vars.iter()) {
749 changes.push(ValueChangeItem::Scalar {
750 identifier: var.to_string(),
751 value: if bit {
752 ScalarValue::One
753 } else {
754 ScalarValue::Zero
755 },
756 });
757 }
758 let mut timestamp: u128 = 0;
760 for event in events.iter() {
761 let edge_time = timestamp_to_picos(initial_timestamp, event.timestamp, clock_resolution);
762 if edge_time > timestamp {
763 timestamp = edge_time;
764 changes.push(ValueChangeItem::Timestamp { step: edge_time });
765 }
766 let index = event.signal_index as usize;
767 changes.push(ValueChangeItem::Scalar {
768 identifier: vars[index].clone(),
769 value: if event.edge == Edge::Rising {
770 ScalarValue::One
771 } else {
772 ScalarValue::Zero
773 },
774 });
775 }
776
777 let end_time = timestamp_to_picos(initial_timestamp, final_timestamp, clock_resolution);
779 if end_time > timestamp {
780 changes.push(ValueChangeItem::Timestamp { step: end_time });
781 }
782 let value_changes = ValueChangeSection { changes };
783
784 Ok(Vcd {
786 header,
787 vardefs,
788 value_changes,
789 })
790}
791
792pub struct UniformVcdSampler {
796 pub step: u128,
797 pin_vars: Vec<String>,
798 value_changes: std::vec::IntoIter<ValueChangeItem>,
799 current_timestamp: u128,
800 next_timestamp: u128,
801 current_values: Vec<u8>,
802 depleted: bool,
803}
804
805impl UniformVcdSampler {
806 pub fn new(vcd: Vcd, step: u128) -> Self {
808 let pin_vars = vcd
809 .var_names()
810 .iter()
811 .map(|n| n.to_string())
812 .collect::<Vec<_>>();
813 let num_bytes = pin_vars.len().div_ceil(8);
814 Self {
815 step,
816 pin_vars,
817 value_changes: vcd.value_changes.changes.into_iter(),
818 current_timestamp: 0u128,
819 next_timestamp: 0u128,
820 current_values: std::iter::repeat_n(0x00, num_bytes).collect::<Vec<_>>(),
821 depleted: false,
822 }
823 }
824}
825
826impl Iterator for UniformVcdSampler {
827 type Item = Result<Vec<u8>>;
828
829 fn next(&mut self) -> Option<Self::Item> {
830 loop {
831 if self.next_timestamp > self.current_timestamp {
833 self.current_timestamp += self.step;
834 return Some(Ok(self.current_values.clone()));
835 }
836 match self.value_changes.next() {
837 Some(ValueChangeItem::Timestamp { step }) => {
839 self.next_timestamp = step;
840 }
841 Some(ValueChangeItem::Scalar { identifier, value }) => {
843 let value = match value {
844 ScalarValue::Zero => 0,
845 ScalarValue::One => 1,
846 _ => {
847 return Some(Err(VcdParseError::UnsupportedFeature(
848 "non-binary scalars".into(),
849 )
850 .into()));
851 }
852 };
853 let Some(index) = self.pin_vars.iter().position(|id| *id == identifier) else {
854 return Some(Err(VcdParseError::UnknownVariable(identifier).into()));
855 };
856 let byte_index = index / 8;
857 let bit_index = index % 8;
858 self.current_values[byte_index] &= !(1 << bit_index);
859 self.current_values[byte_index] |= value << bit_index;
860 }
861 None => {
864 if self.depleted {
865 return None;
866 }
867 self.depleted = true;
868 return Some(Ok(self.current_values.clone()));
869 }
870 }
871 }
872 }
873}
874
875pub struct ParsedVcdEdges {
878 pub pin_vars: Vec<String>,
879 pub events: MonitoringReadResponse,
880}
881
882pub fn vcd_to_edges(
885 vcd: Vcd,
886 clock_resolution: u64,
887 initial_timestamp: u64,
888) -> Result<ParsedVcdEdges> {
889 let pin_vars = vcd.var_names();
890 let timescale = vcd
891 .header
892 .timescale_ps
893 .expect("VCD must contain a timescale to parse to edges");
894
895 let mut events = Vec::new();
897 let mut current_time: u128 = 0;
898 let num_bytes = pin_vars.len().div_ceil(8);
899 let mut current_values: Vec<u8> = std::iter::repeat_n(0x00, num_bytes).collect();
901
902 for change in &vcd.value_changes.changes {
903 match change {
904 ValueChangeItem::Timestamp { step } => {
905 current_time = *step;
906 }
907 ValueChangeItem::Scalar { identifier, value } => {
908 let value = match value {
909 ScalarValue::Zero => 0,
910 ScalarValue::One => 1,
911 _ => bail!(VcdParseError::UnsupportedFeature(
912 "non-binary scalars".into()
913 )),
914 };
915 let Some(index) = pin_vars.iter().position(|id| id == identifier) else {
916 bail!(VcdParseError::UnknownVariable(identifier.into()));
917 };
918 let byte_index = index / 8;
919 let bit_index = index % 8;
920 let current_value = current_values[byte_index] >> bit_index & 0x01;
921 if value != current_value {
923 current_values[byte_index] &= !(1 << bit_index);
924 current_values[byte_index] |= value << bit_index;
925 if current_time == 0 {
927 continue;
930 }
931 let picos = current_time * timescale;
932 let timestamp =
933 timestamp_from_picos(initial_timestamp, picos, clock_resolution);
934 events.push(MonitoringEvent {
935 signal_index: index as u8,
936 edge: if value == 1 {
937 Edge::Rising
938 } else {
939 Edge::Falling
940 },
941 timestamp,
942 });
943 }
944 }
945 }
946 }
947
948 let last_picos = current_time * timescale;
950 let last_timestamp = timestamp_from_picos(initial_timestamp, last_picos, clock_resolution);
951 let events = MonitoringReadResponse {
952 events,
953 timestamp: last_timestamp,
954 };
955 Ok(ParsedVcdEdges {
956 pin_vars: pin_vars.iter().map(|n| n.to_string()).collect(),
957 events,
958 })
959}
960
961#[cfg(test)]
962mod test {
963 use super::*;
964 use std::time::Duration;
965
966 fn edge(signal_index: u8, edge: Edge, timestamp: u64) -> MonitoringEvent {
968 MonitoringEvent {
969 signal_index,
970 edge,
971 timestamp,
972 }
973 }
974
975 fn samples_encode_decode(
978 samples: &[&[u8]],
979 pin_names: Vec<Option<String>>,
980 clock_tick: Duration,
981 ) -> Result<()> {
982 let vcd = dump_vcd(&vcd_from_samples(
983 pin_names,
984 clock_tick.as_nanos() * 1000,
985 samples,
986 )?)?;
987 assert!(!vcd.is_empty());
988 let vcd = load_vcd(&vcd)?;
991 let decoded = UniformVcdSampler::new(vcd, 1).collect::<Result<Vec<_>>>()?;
992 for (decoded_sample, sample) in decoded.iter().zip(samples) {
993 assert_eq!(decoded_sample, sample);
994 }
995 Ok(())
996 }
997
998 fn edges_encode_decode(
1001 clock_resolution: u64,
1002 initial_timestamp: u64,
1003 initial_values: &[bool],
1004 events: &[MonitoringEvent],
1005 final_timestamp: u64,
1006 pin_names: Vec<Option<String>>,
1007 ) -> Result<()> {
1008 let vcd = dump_vcd(&vcd_from_edges(
1009 pin_names,
1010 clock_resolution,
1011 initial_timestamp,
1012 initial_values,
1013 events,
1014 final_timestamp,
1015 )?)?;
1016 assert!(!vcd.is_empty());
1017 let vcd = load_vcd(&vcd)?;
1020 let decoded = vcd_to_edges(vcd, clock_resolution, initial_timestamp)?;
1021 assert_eq!(decoded.events.timestamp, final_timestamp);
1022 assert_eq!(decoded.events.events, events);
1023 Ok(())
1024 }
1025
1026 #[test]
1027 fn samples_waveform() -> Result<()> {
1028 let samples = [
1030 4, 5, 3, 4, 1, 3, 6, 0, 2, 4, 5, 1, 7, 2, 3, 4, 0, 0, 1, 4, 0, 1, 2, 3, 4, 6,
1031 ];
1032 let sample_slices = samples.iter().map(std::slice::from_ref).collect::<Vec<_>>();
1033 let pin_names = Vec::from([const { None }; 3]);
1034 let clock_tick = Duration::from_nanos(3000);
1035 samples_encode_decode(&sample_slices, pin_names.clone(), clock_tick)?;
1036
1037 let pin_names = vec![
1039 Some("spi_sck".into()),
1040 Some("spi_cs".into()),
1041 Some("spi_copi".into()),
1042 ];
1043 let samples = [
1044 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 4,
1045 5, 4, 5, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1046 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1047 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1048 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1049 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1050 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1051 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1052 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
1053 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
1054 2,
1055 ];
1056 let sample_slices = samples.iter().map(std::slice::from_ref).collect::<Vec<_>>();
1057 samples_encode_decode(&sample_slices, pin_names, clock_tick)
1058 }
1059
1060 #[test]
1061 fn raw_vcd_to_samples() -> Result<()> {
1062 let vcd = "
1063$timescale 1345ns $end\n\
1064$scope module opentitanlib $end\n\
1065$var wire 1 # CN_04_2 $end\n\
1066$var wire 1 ! CN_05_3 $end\n\
1067$var wire 1 ; CN_05_4 $end\n\
1068$var wire 1 ? CN_15_4 $end\n\
1069$upscope $end\n\
1070$enddefinitions $end\n\
1071#0 0# 0! 1; 0?\n\
1072#1 1# 1! 0;\n\
1073#2 0#\n\
1074#3 1# 0!\n\
1075#4 0# 1! 1;\n\
1076#5 1#\n\
1077#6 0# 0! 0; 1?\n\
1078#7 1# 1! 1;\n\
1079#8 0#\n\
1080#9 1# 0; 0?\n\
1081#10 0# 0! 1;\n\
1082#11 1# 1! 0;\n\
1083#12 0# 0!\n\
1084#13 1# 1!\n\
1085#14 0# 0! 1; 1?\n\
1086#15 1# 0;\n\
1087#16 0#\n\
1088#17 1# 1! 0?\n\
1089#18 0# 0!\n\
1090#19 1#\n\
1091#20 0#\n\
1092#21 1#\n\
1093#22 0#\n\
1094#23 1#\n\
1095#24 0#\n\
1096#33 1;\n\
1097#34 1# 1! 1?\n\
1098#35 0#\n\
1099#36 1# 0! 0; 0?\n\
1100#37 0#";
1101 let expected_pin_vars = [
1102 String::from("#"),
1103 String::from("!"),
1104 String::from(";"),
1105 String::from("?"),
1106 ];
1107 let expected_timescale = Some(1345 * 1000); let expected_samples: [u8; 38] = [
1109 4, 3, 2, 1, 6, 7, 8, 15, 14, 3, 4, 3, 0, 3, 12, 9, 8, 3, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0,
1110 0, 0, 0, 0, 0, 4, 15, 14, 1, 0,
1111 ];
1112
1113 let vcd = load_vcd(vcd)?;
1115 let decoded_pin_vars = vcd
1116 .var_names()
1117 .iter()
1118 .map(|n| n.to_string())
1119 .collect::<Vec<_>>();
1120 let decoded_timescale_ps = vcd.header.timescale_ps;
1121 let decoded_samples = UniformVcdSampler::new(vcd, 1).collect::<Result<Vec<_>>>()?;
1122 for expected in expected_pin_vars {
1123 assert!(decoded_pin_vars.contains(&expected));
1124 }
1125 assert_eq!(decoded_timescale_ps, expected_timescale);
1126 for (decoded_sample, sample) in decoded_samples.iter().zip(expected_samples) {
1127 assert_eq!(decoded_sample, std::slice::from_ref(&sample));
1128 }
1129 Ok(())
1130 }
1131
1132 #[test]
1133 fn edges_waveform() -> Result<()> {
1134 let clock_resolution = 1_000_000;
1136 let initial_timestamp = 536;
1137 let initial_values = vec![true, false, true];
1138 let events = vec![
1139 edge(2, Edge::Falling, 562),
1140 edge(1, Edge::Rising, 621),
1141 edge(0, Edge::Falling, 754),
1142 edge(2, Edge::Rising, 832),
1143 edge(2, Edge::Falling, 855),
1144 edge(2, Edge::Rising, 912),
1145 edge(0, Edge::Rising, 1012),
1146 edge(1, Edge::Falling, 1058),
1147 edge(2, Edge::Falling, 1123),
1148 edge(2, Edge::Rising, 1157),
1149 edge(0, Edge::Falling, 1210),
1150 edge(1, Edge::Rising, 1258),
1151 edge(0, Edge::Rising, 1315),
1152 edge(2, Edge::Falling, 1415),
1153 edge(1, Edge::Falling, 1510),
1154 edge(0, Edge::Falling, 1633),
1155 edge(0, Edge::Rising, 1901),
1156 ];
1157 let final_timestamp = 1947;
1158 let pin_names = Vec::from([const { None }; 3]);
1159 edges_encode_decode(
1160 clock_resolution,
1161 initial_timestamp,
1162 &initial_values,
1163 &events,
1164 final_timestamp,
1165 pin_names,
1166 )?;
1167
1168 let initial_timestamp = 0;
1170 let initial_values = vec![true];
1171 let event_timestamps = [
1172 5889252340, 5889252358, 5889252375, 5889252392, 5889252410, 5889252427, 5889252445,
1173 5889252462, 5889252479, 5889252497, 5889252514, 5889252532, 5889252549, 5889252636,
1174 5889252654, 5889252671, 5889252688, 5889252723, 5889252740, 5889252775, 5889252793,
1175 5889252810, 5889252827, 5889252845, 5889252862, 5889252914, 5889252932, 5889252949,
1176 5889252967, 5889252984, 5889253001, 5889253019, 5889253036, 5889253141, 5889253158,
1177 5889253193, 5889253210, 5889253245, 5889253263, 5889253315, 5889253349, 5889253367,
1178 5889253386, 5889253402, 5889253419, 5889253454, 5889253471, 5889253489, 5889253523,
1179 5889253541, 5889253558, 5889253610, 5889253628, 5889253645, 5889253697, 5889253715,
1180 5889253732, 5889253767, 5889253784, 5889253837, 5889253871, 5889253889, 5889253906,
1181 5889253924, 5889253941, 5889254011, 5889254046, 5889254063, 5889254080, 5889254115,
1182 5889254167, 5889254185, 5889254219, 5889254238, 5889254254, 5889254272, 5889254324,
1183 5889254359, 5889254393, 5889254411, 5889254428, 5889254533, 5889254550, 5889254585,
1184 5889254603, 5889254655, 5889254672, 5889254689, 5889254741, 5889254759, 5889254776,
1185 5889254794, 5889254811, 5889254828, 5889254846, 5889254881, 5889254915, 5889254933,
1186 5889254950, 5889254968, 5889255002, 5889255037, 5889255089, 5889255107, 5889255124,
1187 5889255176, 5889255194, 5889255211, 5889255264, 5889255281, 5889255298, 5889255455,
1188 ];
1189 let edges = [Edge::Falling, Edge::Rising];
1190 let events = event_timestamps
1191 .into_iter()
1192 .enumerate()
1193 .map(|(i, t)| edge(0, edges[i % 2], t))
1194 .collect::<Vec<_>>();
1195 let final_timestamp = 5889262827;
1196 let pin_names = vec![Some("uart_rx".into())];
1197 edges_encode_decode(
1198 clock_resolution,
1199 initial_timestamp,
1200 &initial_values,
1201 &events,
1202 final_timestamp,
1203 pin_names,
1204 )
1205 }
1206
1207 #[test]
1208 fn raw_vcd_to_edges() -> Result<()> {
1209 let vcd = "
1210$timescale 1ns $end\n\
1211$scope module opentitanlib $end\n\
1212$var wire 1 # a $end\n\
1213$var wire 1 ! b $end\n\
1214$var wire 1 ; c $end\n\
1215$var wire 1 ? d $end\n\
1216$upscope $end\n\
1217$enddefinitions $end\n\
1218#0 0# 0! 1; 0?\n\
1219#10000 1# 1! 0;\n\
1220#20000 0#\n\
1221#30000 1# 0!\n\
1222#40000 0# 1! 1;\n\
1223#50000 1#\n\
1224#60000 0# 0! 0; 1?\n\
1225#70000 1# 1! 1;\n\
1226#80000 0#\n\
1227#90000 1# 0; 0?\n\
1228#100000 0# 0! 1;\n\
1229#110000 1# 1! 0;\n\
1230#120000 0# 0!\n\
1231#130000 1# 1!\n\
1232#140000 0# 0! 1; 1?\n\
1233#150000 1# 0;\n\
1234#160000 0#\n\
1235#170000 1# 1! 0?\n\
1236#180000 0# 0!\n\
1237#190000 1#\n\
1238#200000 0#\n\
1239#210000 1#\n\
1240#220000 0#\n\
1241#230000 1#\n\
1242#240000 0#\n\
1243#330000 1;\n\
1244#340000 1# 1! 1?\n\
1245#350000 0#\n\
1246#360000 1# 0! 0; 0?\n\
1247#100000000 0#";
1248 let clock_resolution = 1_000_000; let initial_timestamp = 536;
1250 let vcd = load_vcd(vcd)?;
1251 let decoded = vcd_to_edges(vcd, clock_resolution, initial_timestamp)?;
1252
1253 let expected_pin_vars = [
1254 String::from("#"),
1255 String::from("!"),
1256 String::from(";"),
1257 String::from("?"),
1258 ];
1259 let expected_edges = vec![
1260 edge(0, Edge::Rising, 546),
1261 edge(1, Edge::Rising, 546),
1262 edge(2, Edge::Falling, 546),
1263 edge(0, Edge::Falling, 556),
1264 edge(0, Edge::Rising, 566),
1265 edge(1, Edge::Falling, 566),
1266 edge(0, Edge::Falling, 576),
1267 edge(1, Edge::Rising, 576),
1268 edge(2, Edge::Rising, 576),
1269 edge(0, Edge::Rising, 586),
1270 edge(0, Edge::Falling, 596),
1271 edge(1, Edge::Falling, 596),
1272 edge(2, Edge::Falling, 596),
1273 edge(3, Edge::Rising, 596),
1274 edge(0, Edge::Rising, 606),
1275 edge(1, Edge::Rising, 606),
1276 edge(2, Edge::Rising, 606),
1277 edge(0, Edge::Falling, 616),
1278 edge(0, Edge::Rising, 626),
1279 edge(2, Edge::Falling, 626),
1280 edge(3, Edge::Falling, 626),
1281 edge(0, Edge::Falling, 636),
1282 edge(1, Edge::Falling, 636),
1283 edge(2, Edge::Rising, 636),
1284 edge(0, Edge::Rising, 646),
1285 edge(1, Edge::Rising, 646),
1286 edge(2, Edge::Falling, 646),
1287 edge(0, Edge::Falling, 656),
1288 edge(1, Edge::Falling, 656),
1289 edge(0, Edge::Rising, 666),
1290 edge(1, Edge::Rising, 666),
1291 edge(0, Edge::Falling, 676),
1292 edge(1, Edge::Falling, 676),
1293 edge(2, Edge::Rising, 676),
1294 edge(3, Edge::Rising, 676),
1295 edge(0, Edge::Rising, 686),
1296 edge(2, Edge::Falling, 686),
1297 edge(0, Edge::Falling, 696),
1298 edge(0, Edge::Rising, 706),
1299 edge(1, Edge::Rising, 706),
1300 edge(3, Edge::Falling, 706),
1301 edge(0, Edge::Falling, 716),
1302 edge(1, Edge::Falling, 716),
1303 edge(0, Edge::Rising, 726),
1304 edge(0, Edge::Falling, 736),
1305 edge(0, Edge::Rising, 746),
1306 edge(0, Edge::Falling, 756),
1307 edge(0, Edge::Rising, 766),
1308 edge(0, Edge::Falling, 776),
1309 edge(2, Edge::Rising, 866),
1310 edge(0, Edge::Rising, 876),
1311 edge(1, Edge::Rising, 876),
1312 edge(3, Edge::Rising, 876),
1313 edge(0, Edge::Falling, 886),
1314 edge(0, Edge::Rising, 896),
1315 edge(1, Edge::Falling, 896),
1316 edge(2, Edge::Falling, 896),
1317 edge(3, Edge::Falling, 896),
1318 edge(0, Edge::Falling, 100536),
1319 ];
1320 for expected in expected_pin_vars {
1321 assert!(decoded.pin_vars.contains(&expected));
1322 }
1323 assert_eq!(decoded.events.events, expected_edges);
1324 assert!(decoded.events.timestamp >= expected_edges.last().unwrap().timestamp);
1325 Ok(())
1326 }
1327
1328 #[test]
1329 fn many_signals() -> Result<()> {
1330 const NUM_PINS: usize = 1024;
1333 const NUM_SAMPLES: usize = 10;
1334 let mut samples = Vec::new();
1335 let mut prng = 0x0ACECAFE;
1336 for _ in 0..NUM_SAMPLES {
1337 let mut sample = Vec::new();
1338 for _ in 0..NUM_PINS.div_ceil(32) {
1339 prng ^= prng << 13;
1341 prng ^= prng >> 17;
1342 prng ^= prng << 5;
1343 sample.push(prng as u8);
1344 sample.push((prng >> 8) as u8);
1345 sample.push((prng >> 16) as u8);
1346 sample.push((prng >> 24) as u8);
1347 }
1348 samples.push(sample);
1349 }
1350 let sample_slices = samples.iter().map(|s| s.as_ref()).collect::<Vec<_>>();
1351 let pin_names = Vec::from([const { None }; NUM_PINS]);
1352 let clock_tick = Duration::from_nanos(3000);
1353 samples_encode_decode(&sample_slices, pin_names, clock_tick)
1354 }
1355}