Crate vcd

source ·
Expand description

This crate reads and writes VCD (Value Change Dump) files, a common format used with logic analyzers, HDL simulators, and other EDA tools.

It provides:

Example

use std::io;
use std::io::ErrorKind::InvalidInput;
use vcd::{ self, Value, TimescaleUnit, SimulationCommand };

/// Write out a clock and data signal to a VCD file
fn write_clocked_vcd(shift_reg: u32, w: &mut dyn io::Write) -> io::Result<()> {
  let mut writer = vcd::Writer::new(w);

  // Write the header
  writer.timescale(1, TimescaleUnit::US)?;
  writer.add_module("top")?;
  let clock = writer.add_wire(1, "clock")?;
  let data = writer.add_wire(1, "data")?;
  writer.upscope()?;
  writer.enddefinitions()?;

  // Write the initial values
  writer.begin(SimulationCommand::Dumpvars)?;
  writer.change_scalar(clock, Value::V0)?;
  writer.change_scalar(data, Value::V0)?;
  writer.end()?;

  // Write the data values
  let mut t = 0;
  for i in 0..32 {
    t += 4;
    writer.timestamp(t)?;
    writer.change_scalar(clock, Value::V1)?;
    writer.change_scalar(data, ((shift_reg >> i) & 1) != 0)?;

    t += 4;
    writer.timestamp(t)?;
    writer.change_scalar(clock, Value::V0)?;
  }
  Ok(())
}

/// Parse a VCD file containing a clocked signal and decode the signal
fn read_clocked_vcd(r: &mut dyn io::BufRead) -> io::Result<u32> {
   let mut parser = vcd::Parser::new(r);

   // Parse the header and find the wires
   let header = parser.parse_header()?;
   let clock = header.find_var(&["top", "clock"])
      .ok_or_else(|| io::Error::new(InvalidInput, "no wire top.clock"))?.code;
   let data = header.find_var(&["top", "data"])
      .ok_or_else(|| io::Error::new(InvalidInput, "no wire top.data"))?.code;

   // Iterate through the remainder of the file and decode the data
   let mut shift_reg = 0;
   let mut data_val = Value::X;
   let mut clock_val = Value::X;

   for command_result in parser {
     let command = command_result?;
     use vcd::Command::*;
     match command {
       ChangeScalar(i, v) if i == clock => {
         if clock_val == Value::V1 && v == Value::V0 { // falling edge on clock
            let shift_bit = match data_val { Value::V1 => (1 << 31), _ => 0 };
            shift_reg = (shift_reg >> 1) | shift_bit;
         }
         clock_val = v;
       }
       ChangeScalar(i, v) if i == data => {
         data_val = v;
       }
       _ => (),
     }
   }

   Ok(shift_reg)
}

let mut buf = Vec::new();
let data = 0xC0DE1234;
write_clocked_vcd(data, &mut buf).expect("Failed to write");
let value = read_clocked_vcd(&mut &buf[..]).expect("Failed to read");
assert_eq!(value, data);

Structs

Enums

  • An element in a VCD file.
  • Parse error for invalid ID code.
  • Errors that can be encountered while parsing.
  • Index of a VCD variable reference: either a bit select index [i] or a range index [msb:lsb]
  • An item in a scope
  • A type of scope, as used in the $scope command.
  • A simulation command type, used in Command::Begin and Command::End.
  • A unit of time for the $timescale command.
  • A four-valued logic scalar value.
  • A type of variable, as used in the $var command.