#vcd #verilog #eda

bin+lib vcd

Read and write VCD (Value Change Dump) files

7 releases (breaking)

new 0.6.1 Sep 12, 2020
0.6.0 Jul 12, 2020
0.5.0 Oct 3, 2019
0.4.0 Aug 24, 2018
0.1.0 May 4, 2015

#168 in Parser implementations

Download history 53/week @ 2020-05-29 65/week @ 2020-06-05 128/week @ 2020-06-12 45/week @ 2020-06-19 35/week @ 2020-06-26 51/week @ 2020-07-03 91/week @ 2020-07-10 49/week @ 2020-07-17 33/week @ 2020-07-24 33/week @ 2020-07-31 48/week @ 2020-08-07 37/week @ 2020-08-14 46/week @ 2020-08-21 44/week @ 2020-08-28 71/week @ 2020-09-04 47/week @ 2020-09-11

228 downloads per month
Used in vcdump

MIT license

53KB
1.5K SLoC

VCD

Documentation | Changelog

Build Status

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 streaming wrappers around the io::Read and io::Write traits to read and write VCD commands and data.


lib.rs:

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

Example

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

/// Write out a clocked signal to a VCD file
fn write_clocked_vcd(shift_reg: u32, w: &mut 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 io::Read) -> 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 {
     use vcd::Command::*;
     let command = command_result?;
     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);

No runtime deps