Verilator入门笔记
Verilator入门笔记
前言
verilator是用于verilog仿真的工具,它将HDL描述的代码编译为C++后运行,在效率上比传统的仿真器高出很多。同时作为开源工具,体量比较小,使用也比较灵活,不用每次都开一个大家伙。
但是,它的文档实在是写的太简略了,C++的类型和接口都没有详细的reference,只能自己去代码里翻。而且veripool.org的官方文档在国内连接也不是很稳定,有时候开了代理都上不去,verilator.org更是无法连接……所以总结一些摸索出的经验以备查阅。
安装过程略。
C++ wrapper
假设我们需要仿真的是一个加法器模块:
|
|
为了调用verilator进行仿真,我们还需要编写仿真的测试文件,即testbench,对于verilator而言也叫做C++ wrapper,其作用就是调用编译后的电路C++模型并执行。如下所示是一个简单的测试文件示例。
|
|
有这样几个细节需要注意:
- verilator对电路编译后生成的模型名称是
V[module name]
,就是简单地在模块名称前方添加一个大写V。例如本例中模块名称是adder,则生成的就是Vadder。这个名称包含第二行的include和代码中用于实例化的类名称,以及默认情况下后续步骤会生成的可执行文件名称。 - 对输入端口进行赋值后需要调用
tb->eval()
进行计算。verilator不是精确时序的仿真器,不能指定延时,因此只会在每次调用eval后重新计算更新内部状态。
Verilating & Run
在编写完成verilog文件和C++ wrapper后即可调用verilator进行编译,官方说法是“verilating”。例如目前有如下两个文件:
|
|
可以通过如下命令执行verilating:
|
|
其中–build参数是自动执行构建过程。如果不加这个参数,verilator只会生成对应的C++源文件和mk脚本,需要自行调用make进行构建。
verilator默认的生成目录是当前目录下的obj_dir
,如果编译过程没有错误,将会在其中生成Vadder(或者Vadder.exe)可执行文件。运行该文件即可执行仿真,并查看输出结果。
|
|
常用verilator参数
verilator支持的所有参数可以在文档页面查看,这里列出常用的几项。
添加查找目录
使用-y [dir]
可以添加在编译时的模块查找路径。例如你的adder和其他公用模块都存放在/path/to/lib
目录,而当前项目的top模块调用了adder的话,可以在verilator命令追加参数-y /path/to/lib
,这样verilator就会正确识别到adder,并且top.v中无需显式include。
指定顶层模块
使用--top-module [module]
可以显式指定顶层模块,一般在模块包含关系图中有多个树根的时候需要用到。
覆盖顶层参数
verilog的一项语法是支持通过参数实例化。在verilating时就可以通过-G[param]=[value]
覆盖参数值。注意这里G和参数名称之间没有空格。
例如对于支持改变位宽的adder:
|
|
代码中指定参数n的默认值为32,这时在verilating时就可以通过-Gn=10
来强制实例化为10位的adder。
不显示编译信息
严格而言这不是verilator的参数。verilator在生成完毕调用C++编译器时会在终端输出大量编译信息,影响观感,#可以通过输出重定向使得终端更加干净:
|
|
这样终端输出就安静了许多。当然,这里只重定向标准输出流,编译的错误信息等属于错误流,仍然可以显示。
周期时序仿真 & 波形生成
verilator虽然不支持精确时序仿真,但仍然能够处理周期时序的情况。例如现有如下一个简单的脉冲计数器:
|
|
要对其进行周期时序仿真,首先在C++wrapper中需要启用相关功能。
|
|
在编写完成wrapper后,verilating时还要追加--trace
参数。
|
|
正常编译运行结束后,生成的vcd波形可以使用gtkwave查看。从左侧的面板可以选取和添加需要查看的信号。
默认情况波形数据包括所有层级、每个实例的内部信号,因此即使你的电路并不包含时钟/时序逻辑,也可以通过查看这些数据进行调试和排错,避免来回修改电路端口或插入多余的C++输出语句等操作。
注意: 启用波形追踪会显著降低仿真运行速度。
特殊数据输入/输出
在模块端口位宽较短时都可以通过直接将unsigned int/long long等赋值给它实现输入。对于输出数据,也可以通过强制类型转换为这些类型进行后续处理和输出。
浮点数
如果你编写了一个浮点数运算模块,用于处理32位IEEE754标准的浮点数据,在测试时直接赋值C++中的float变量是无法正确传递数据的。可以用强制无检查类型转换的方式将float类型转换为输入所需的32位二进制数据,输出时也可以通过同样的方法转换为浮点数类型(该方法来自stackoverflow):
|
|
长位宽数据
内容较多,见另一篇笔记。
Verilator c++ wrapper兼容不同名称的verilog模块
见另一篇笔记。
End
verilator的功能十分强大,这里只列出了目前接触的一部分。如果后续使用中了解了其他功能会追加更新。