8 releases (breaking)
0.7.0 | Jul 15, 2023 |
---|---|
0.6.1 | Sep 12, 2020 |
0.6.0 | Jul 12, 2020 |
0.5.0 | Oct 3, 2019 |
0.1.0 | May 4, 2015 |
#1405 in Parser implementations
3,120 downloads per month
Used in 41 crates
(13 directly)
73KB
2K
SLoC
VCD
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.
It provides:
- A
Parser
wrapsstd::io::BufRead
and provides the ability to parse a VCDHeader
andCommand
s. - A
Writer
that allows writing VCD to astd::io::Write
. - Several structs and enums representing the elements of a VCD file that
can be used with the
Parser
orWriter
, or individually by implementingFromStr
andDisplay
.
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);