8 个版本 (破坏性)

0.7.0 2023 年 7 月 15 日
0.6.1 2020 年 9 月 12 日
0.6.0 2020 年 7 月 12 日
0.5.0 2019 年 10 月 3 日
0.1.0 2015 年 5 月 4 日

#1234解析器实现

Download history 524/week @ 2024-03-13 942/week @ 2024-03-20 561/week @ 2024-03-27 643/week @ 2024-04-03 1137/week @ 2024-04-10 829/week @ 2024-04-17 689/week @ 2024-04-24 750/week @ 2024-05-01 648/week @ 2024-05-08 769/week @ 2024-05-15 533/week @ 2024-05-22 754/week @ 2024-05-29 785/week @ 2024-06-05 805/week @ 2024-06-12 876/week @ 2024-06-19 714/week @ 2024-06-26

3,347 每月下载次数
40 包 (12 直接)

MIT 许可证

73KB
2K SLoC

VCD

文档 | 变更日志

此包读取和写入 VCD (值变化转储) 文件,这是一种常见的与逻辑分析仪、HDL 模拟器和其它 EDA 工具一起使用的格式。它提供了围绕 io::Readio::Write 特性的流式包装,以读取和写入 VCD 命令和数据。


lib.rs:

此包读取和写入 VCD (值变化转储) 文件,这是一种常见的与逻辑分析仪、HDL 模拟器和其它 EDA 工具一起使用的格式。

它提供了

  • Parser 包装 std::io::BufRead 并提供了解析 VCD HeaderCommand 的能力。
  • Writer 允许将 VCD 写入到 std::io::Write
  • 表示VCD文件元素的几个结构和枚举,可以与ParserWriter一起使用,或者通过实现FromStrDisplay接口单独使用。

示例

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);

无运行时依赖