Verilator

Verilator

fetch150zy

Verilator

安装

Arch linux

1
yay -S verilator

一般aur上软件包更新的都很频繁,推荐使用aur来下载

Ubuntu

软件包更新的太慢了,推荐通过github手动装(反正不是滚动更新的一般软件包版本都不太新,都推荐通过手动安装)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 下面这些依赖包看着装,少啥装啥
#sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache
#sudo apt-get install libgoogle-perftools-dev numactl perl-doc
#sudo apt-get install libfl2 # Ubuntu only (ignore if gives error)
#sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
#sudo apt-get install zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error)

git clone https://github.com/verilator/verilator
unsetenv VERILATOR_ROOT # csh
unset VERILATOR_ROOT # bash
cd verilator
git pull # 同步一下,确保本地也最新
git tag # 查看软件包版本
# 切换到你想要安装的版本分支
#git checkout master # 主分支
#git checkout stable # 稳定版分支
#git checkout v{version} # 特定版本分支

autoconf # Create ./configure script
./configure # Configure and create Makefile
make -j `nproc` # 编译,主流处理器 make -j8
sudo make install # 安装
sudo make uninstall # 卸载

亲测在manjaro linux上按照上面步骤手动和通过aur来安装都没问题

使用

本人在学习一生一芯时要用到Verilator,下面给出一些简单的使用例子

二进制、C++和SystemC生成

  • --cc: 翻译成C++
  • --sc: 翻译成SystemC
  • --binary: 翻译成C++后并编译成二进制
  1. Verilator读取输入的Verilog代码,并确定所有的“顶级模块”,即没有用作其他单元下的实例的模块或程序。如果使用 --top-module ,则确定顶部模块,并删除所有其他顶部模块;否则给出 MULTITOP 警告
  2. Verilator将C++/SystemC代码写入输出文件到 --Mdir 选项指定的目录,或默认为“obj_dir”。前缀设置为 --prefix ,或默认为顶级模块的名称
  3. 如果使用 --binary--main ,Verilator将创建一个C++顶层包装器来读取命令行参数,创建模型并执行模型
  4. 如果使用 --binary--exe ,Verilator将创建makefiles以生成模拟可执行文件,否则,它将创建makefiles以生成包含对象的归档文件(.a)
  5. 如果使用 --binary--build ,它将调用GNU Make或CMake来构建模型

一般来说,--prefix用不到,使用顶级模块名即可

分层验证

Verilator在整个SoC上以分层模式运行。Verilator将创建两个模型,一个用于CPU层次块,一个用于SoC。SoC的Verilated代码将自动调用CPU Verilated模型

当前分层验证基于 --lib-create 。每个层次结构块都被验证到一个库中。层次块的用户模块将看到 --lib-create 生成的一个小包装器

这个功能暂时用不到,项目很大时才用得到

交叉编译

推荐在同一个操作系统上完成生成和编译

多线程

支持多线程验证,比如你写了多个核的cpu?

构建

GNU Make

  1. Verilator默认为模型创建GNU Make makefile。当使用:vlopt:’-build’选项时,Verilator将自动调用make
  2. 如果从makefile调用Verilator,:vlopt:’-MMD’选项将创建一个依赖文件,允许Make仅在输入Verilog文件更改时运行Verilator

当然你也可以使用CMake,感兴趣的查看原文档

连接到验证模型

验证模型结构

top_module.v同级目录下

1
verilator --cc top_module.v --Mdir dest_dir --prefix top_module

会产生如下目录结构

image-20240317180226084

主要关注top_module.htop_module.cpp两个文件,也就是我们通过--prefix指定的

连接到C++

  1. 在C++输出模式( --cc )下,Verilator生成的模型类是一个简单的C++类。用户必须为模拟编写一个C++包装器和主循环,它实例化模型类,并与Verilated模型链接
  2. 顶层IO信号作为模型的成员被读取和写入。调用模型的 eval() 方法来计算模型。当模拟完成时,调用模型的 final() 方法来执行任何SystemVerilog最终块,并完成任何断言。如果使用 --timing ,则有两个额外的功能用于检查是否有任何事件由于延迟而在模拟中挂起,以及用于检索下一个延迟事件的模拟时间

仿真例子

首先创建一个verilog和C++文件

1
touch our.v sim_main.cpp
1
2
3
4
module our;
initial begin $display("Hello World"); $finish; end
endmodule

1
2
3
4
5
6
7
8
9
10
11
12
#include "Vour.h"
#include "verilated.h"

int main(int argc, char** argv) {
VerilatedContext* contextp = new VerilatedContext;
contextp->commandArgs(argc, argv);
Vour* top = new Vour{contextp};
while (!contextp->gotFinish()) { top->eval(); }
delete top;
delete contextp;
return 0;
}

在vscode里智能提示不能正常工作,看着很不爽,可以使用bear来生成compile_commands.json

1
bear -- verilator --cc --exe --build -j 8 -Wall sim_main.cpp our.v

image-20240317195528814

这样看着舒服多了

生成波形

testbench.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vsim_module.h"

int main(int argc, char **argv) {
VerilatedContext* contextp = new VerilatedContext;

contextp->commandArgs(argc, argv);
Vsim_module* top = new Vsim_module{contextp};

// 开启波形跟踪
Verilated::traceEverOn(true);
VerilatedVcdC* vcd = new VerilatedVcdC;
// 跟踪100拍
top->trace(vcd, 100);
// 指定vcd文件的名字
vcd->open("trace.vcd");

for (int i = 0; i < 100; ++i) {
int a = rand() & 1;
int b = rand() & 1;
top->a = a;
top->b = b;
top->eval();
printf("a = %d, b = %d, f = %d\n", a, b, top->f);
vcd->dump(i);
assert(top->f == (a ^ b));
}

vcd->close();
delete top;
delete vcd;
delete contextp;
return 0;
}

top_module.v

1
2
3
4
5
6
7
8
module top_module(
input a,
input b,
output f
);
assign f = a ^ b;
endmodule

onekey

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#! /usr/bin/bash

run_simulation() {
# 检查是否提供了足够的参数
if [ "$#" -lt 1 ]; then
echo "Usage: bash $0 [VerilogFiles...]"
exit 1
fi

# 所有待仿真文件
VERILOG_FILES=""
for file in "${@:1}"; do
VERILOG_FILES+="$file "
done

# 测试文件
TESTBENCH="testbench.cpp"

verilator -Wall --cc $VERILOG_FILES --exe $TESTBENCH --trace --prefix Vsim_module && \
bear -- make -j 8 -C obj_dir -f Vsim_module.mk Vsim_module && \
./obj_dir/Vsim_module > sim.output
}

clean_up() {
echo "Cleaning up..."
rm -rf obj_dir && \
rm sim.output && \
rm compile_commands.json && \
rm trace.vcd
echo "Clean up done!"
}

case $1 in
run)
shift
run_simulation "$@"
;;
clean)
clean_up
;;
*)
echo "Unknown command: $1"
echo "Usage: bash $0 {run|clean}"
exit 1
;;
esac


目录结构

image-20240317223415345

执行bash onekey run top_module.v

image-20240317223758096

在vscode中使用TraceWave插件来查看波形

image-20240317224212631

使用gtkwave查看波形

image-20240317224319591