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.
Example
use std::io;
use std::io::ErrorKind::InvalidInput;
use vcd_ng::{ self, Value, TimescaleUnit, SimulationCommand };
/// Write out a clocked signal to a VCD file
fn write_clocked_vcd(shift_reg: u32, w: &mut impl io::Write) -> io::Result<()> {
let mut writer = vcd_ng::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 impl io::Read) -> io::Result<u32> {
let mut parser = vcd_ng::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_ng::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);
Structs
A value change token.
Fast token stream of timestamp and value changes.
See the module-level documentation for details.
Structure containing the data from the header of a VCD file.
An ID used within the file to refer to a particular variable.
Error wrapping a static string message explaining why parsing failed.
VCD parser. Wraps an
io::Read
and acts as an iterator of Command
s.Information on a VCD scope as represented by a
$scope
command and its children.Information on a VCD variable as represented by a
$var
command.An iterator over bits in a
VecValue
.Struct wrapping an
io::Write
with methods for writing VCD commands and data.Enums
An element in a VCD file.
An enum of tokens that fast flow supports.
Index of a VCD variable reference, either a bit select index
[i]
or a range index [msb:lsb]
An item in a scope – either a child scope or a variable.
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.