前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >硬件电路仿真中的VCD格式以及pyvcd模块

硬件电路仿真中的VCD格式以及pyvcd模块

作者头像
hunterzju
发布2021-12-09 13:58:45
1.8K0
发布2021-12-09 13:58:45
举报
文章被收录于专栏:编译器开发编译器开发

之前尝试用CIRCT中的llhd-sim进行了一个简单电路的仿真,但是llhd-sim目前的输出是自定义格式,无法通过gtkwave这样的工具查看仿真结果。本文记录将该格式转换为gtkwave支持的vcd格式的过程。

vcd格式

VCD(Value change dump)是一种基于ASCII码的文件格式,用于记录由EDA仿真工具产生的信号信息。一个VCD文件通常包含了3个段,分别是:头信息(日期,仿真器,时间精度)、变量定义、值变化信息。这里以之前计数器数字电路仿真结果的vcd文件为例做一下介绍:

代码语言:javascript
复制
$version
llhd-sim 0.16.0
$end
$timescale 1ps $end
$scope module @updowncounter_tb $end
$var wire 1 ! clk $end
$var wire 1 " reset $end
$var wire 1 # up_down $end
$var wire 4 $ counter $end
$scope module @up_down_counter_param1 $end
$var wire 1 % clk $end
$var wire 1 & reset $end
$var wire 1 ' up_down $end
$var wire 4 ( counter $end
$var wire 4 ) counter_up_down $end
......
$upscope $end
$upscope $end
$enddefinitions $end
$dumpvars
b0 )
b0 -
b0 #
b0 '
b0 ,
b0 0
b0 "
b0 &
b0 +
b0 /
b0 $
b0 (
b0 !
b0 %
b0 *
b0 .
$end
#0
b1 "
b1 &
b1 +
......

上述vcd文件中,头信息段包含了版本信息和时间精度,分别包含在version和timescale关键字之内,每一部分通过end关键字指示结尾。变量定义部分,在scope和upscope关键字之间构成一个模块层级,通过这两个关键字的嵌套可以构成不同的模块层级;变量定义部分通过enddefinitions关键字指示变量定义结束。值变化区域先通过

LLHD-SIM输出格式

CIRCT中的llhd-sim目前的输出为各个信号在不同时刻的取值,输出的每一行中都包含了时间、信号、信号取值三部分信息。这种格式包含大量重复信息,占用空间大,应该只是在开发调试阶段一种临时输出,我们想要采用gtkwave查看仿真波形需要自己写脚本转换一下。

代码语言:javascript
复制
0ps 0d 0e  updowncounter_tb/clk  0x00
0ps 0d 0e  updowncounter_tb/counter  0x00
0ps 0d 0e  updowncounter_tb/inst/clk  0x00
0ps 0d 0e  updowncounter_tb/inst/counter  0x00
0ps 0d 0e  updowncounter_tb/inst/counter_up_down  0x00

上述数据中,0ps 0d 0e表示时间信息,ps为时间单位,另外的de是两个时间的微分(没找到相关资料,盲猜是可以用来保存建立时间和保持时间等参数,LLHD在设计上考虑得还是很完善的)。updowncounter_tb/clk表示信号所在的电路模块以及信号名,采用/分割后,最后一个值为信号名,前面的字符代表模块间的层级关系。最后一个值0x00表示信号在当前时刻的取值为0。

格式转换

了解了vcd格式和llvm的原生格式后,可以考虑编写脚本进行转换。python中有现成的模块pyvcd可以用来读取或者创建vcd格式的文件,我们就可以不用重复造轮子了,只要看下pyvcd的api怎么调用就好了。

参考pyvcd给出的使用示例:

代码语言:javascript
复制
>>> import sys
>>> from vcd import VCDWriter
>>> with VCDWriter(sys.stdout, timescale='1 ns', date='today') as writer:
...     counter_var = writer.register_var('a.b.c', 'counter', 'integer', size=8)
...     real_var = writer.register_var('a.b.c', 'x', 'real', init=1.23)
...     for timestamp, value in enumerate(range(10, 20, 2)):
...         writer.change(counter_var, timestamp, value)
...     writer.change(real_var, 5, 3.21)

可以发现只要简单三个API就可以创建一个vcd格式的文件: 1. 使用VCDWriter()创建一个写入对象writer; 2. 使用register_var()创建信号; 3. 使用change()改变信号值。

这三个API的具体使用参数可以参考文档:

代码语言:javascript
复制
classvcd.writer.VCDWriter(file: IO[str], timescale: Union[vcd.common.Timescale, Tuple[int, str], str] = '1 us', date: Optional[str] = None, comment: str = '', version: str = '', default_scope_type: Union[vcd.common.ScopeType, str] = <ScopeType.module: 'module'>, scope_sep: str = '.', check_values: bool = True, init_timestamp: Union[int, float] = 0)

register_var(scope: Union[str, Sequence[str]], name: str, var_type: Union[vcd.common.VarType, str], size: Union[int, Sequence[int], None] = None, init: Union[bool, int, float, str, None, Sequence[Union[int, bool, str, None]]] = None) → vcd.writer.Variable

change(var: vcd.writer.Variable, timestamp: Union[int, float], value: Union[bool, int, float, str, None, Sequence[Union[int, bool, str, None]]]) → None

另外还需要注意的一点是,vcd格式要求信号的定义必须在改变之前(VCD格式的所有信号定义需要在变量定义过程中完成),因此在将LLHD格式转换成VCD格式时需要先把所有信号提取出来,然后再根据时间先后顺序修改各个变量的值。一个简单的转换脚本放在github上了。转换后的vcd文件可以用gtkwave查看,以之前仿真的计数器为例,CIRCT中的llhd-sim目前也能基本实现正确的逻辑仿真。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • vcd格式
  • LLHD-SIM输出格式
  • 格式转换
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档