目录
- 前言
- 工具安装
- Verilator 安装
- GTKwave 安装
- Verilator 基础用法
- fst格式和vcd格式的wave文件
- Verilator 的使用
- Verilator 的进阶使用
- 与GDB搭配
- 与makefile搭配
- Verilator 的高阶用法
- 访问模块内部数据
前言
此教程会以ubuntu22.04为例
从如何安装,到如何使用
全程帮助你学习和使用verilator
狂肝3h,倾心之作
如有笔误、问题,欢迎指出、讨论~
点赞,收藏,长期翻看~
工具安装
Verilator 安装
利用git进行快速安装(安装方法摘自官网Verilator)
# 安装的前提:
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需要,如果报错就忽略
sudo apt-get install libfl-dev # 只有Ubuntu需要,如果报错就忽略
sudo apt-get install zlibc zlib1g zlib1g-dev # 只有Ubuntu需要,如果报错就忽略
git clone https://github.com/verilator/verilator #只需克隆一次
# Every time you need to build:
unsetenv VERILATOR_ROOT # 对csh操作,如果是使用bash就忽略
unset VERILATOR_ROOT # 对bash操作
cd verilator
git pull # 确保git的仓库是最新的
git tag # 查看可选版本
#选择以下的其中一个执行:
#git checkout master # 使用开发分支(例如最近的bug修复版本)
#git checkout stable # 使用最新的稳定版本
#git checkout v{version} # 切换到指定版本
autoconf # 创建脚本
./configure # 配置并创建makefile
make -j `nproc` # 构建verilator (如果报错试试只输入“make”)
sudo make install
然后执行
verilator --version #检查版本,检查是否安装成功
GTKwave 安装
用来查看verilator生成的波形文件
有两种安装方法:
- 直接从ubuntu自带的应用商城搜索gtkwave,即可安装
- 使用apt-get命令来安装
sudo apt-get install gtkwave
gtkwave --version //查看版本,检查是否安装成功
Verilator 基础用法
fst格式和vcd格式的wave文件
varilator可以生成两种格式的wave文件:
- fst格式
- FST格式的波形文件大致是VCD格式的1/50
- 该格式只能用gtkwave打开,其他波形查看软件不支持
- vcd格式
- 文件大小较大
- 可以用多种波形查看软件查看
鉴于fst格式的优点,以及网上很少关于生成fst格式的教程,因此我以生成fst为例,如若要生成vcd可以上网查阅资料
接下来我将介绍如何使用verilator
Verilator 的使用
以cpp为例,并介绍如何生成fst wave文件的生成
可以看官方的例程 :官方c++例程
此处我挑出其中重点的部分来讲解
假设我们用verilog写一个双控开关:
//顶层文件名为top,因此等会include的头文件为Vtop
//若顶层文件名为example,则include的头文件名为Vexample
module top(
input clk,
input rst,
input a,
input b,
output f
);
assign f = a ^ b;
endmodule
仿真过程用c++来描述,文件如下:
//与verilator无关的一些头文件
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//使用verilater必须include
#include "Vtop.h" //仿真模型的头文件,由top.v生成,如果顶层文件名更改则也需要更改
#include <verilated.h>
#define CONFIG_FST_WAVE_TRACE 1
// contextp用来保存仿真的时间
VerilatedContext *contextp = new VerilatedContext;
// 构建一个名为top的仿真模型
Vtop *top = new Vtop{contextp};
//如果生成FST格式的wave
#if CONFIG_FST_WAVE_TRACE
#include "verilated_fst_c.h" //波形文件所需的头文件
VerilatedFstC *tfp = new VerilatedFstC; // 创建一个波形文件指针
#endif
//仿真的过程
int main(int argc, char **argv)
{
Verilated::mkdir("build/logs"); // 创建一个日志文件夹
// 传递参数给verilator
contextp->commandArgs(argc, argv);
//如果生成FST格式的wave
#if CONFIG_FST_WAVE_TRACE
contextp->traceEverOn(true); // 启用跟踪
top->trace(tfp, 99); // 采样深度为99
tfp->open("build/logs/cpu_wave.fst"); // 打开波形文件,文件地址和文件名可以自定义
#endif
/***************对top端口的初始化*******************/
top->clk = 0;
top->rst = 0;
/**************verilator的仿真循环*****************/
while (!contextp->gotFinish()) // ctrl+c 可以停止仿真
{
/************设置vtop仿真的输入信号************/
int a = rand() & 1;
int b = rand() & 1;
top->a = a;
top->b = b;
top->clk = !top->clk; // 随着仿真时间倒转clk,产生时钟周期
top->eval(); //更新电路状态
printf("a = %d, b = %d, f = %d\n", a, b, top->f); //按需打印想要的
contextp->timeInc(1); //推动仿真时间
#if CONFIG_FST_WAVE_TRACE
tfp->dump(contextp->time()); // 按照时间采样
#endif
}
/*****************仿真结束,一些善后工作***************/
#if CONFIG_FST_WAVE_TRACE
tfp->close(); // 关闭波形文件
#endif
// 清理top仿真模型,并销毁相关指针,并将指针变为空指针
top->final();
delete top;
top = nullptr;
delete contextp;
contextp = nullptr;
return 0;
}
完成文件的编写后,我们要让verilator编译并运行
在命令行中输入
verilator -Wall top.v top_main.cpp --cc --trace-fst --exe --build
./obj_dir/Vtop //必须执行这个,才运行仿真,生成波形
gtkwave build/logs/cpu_wave.fst //用gtk打开波形文件
Verilator 的进阶使用
与GDB搭配
gdb可以很方便得对仿真的过程进行调试
如何使用请详见 “与makefile搭配”
与makefile搭配
如果每次使用verilator都要在命令行中输入以上命令,有点太麻烦了
因此可以利用makefile
########### 不要在变量后面加多余空格,否则会导致变量名出问题 ###########
########### 因此也不要在变量后面加注释,以避免上述情况发生 ###########
#顶层文件的名字
TOPNAME = top
#指定verilator
VERILATOR = verilator
######################## 包含相关文件 ########################
#相关文件的地址
INCLUDE_PATH = ./build/chisel ./src/main/cpp/
#对地址添加 -I的前缀
INCFLAGS = $(addprefix -I, $(INCLUDE_PATH))
######################## cxx编译选项 ########################
CXXFLAGS += $(INCFLAGS) -DTOP_NAME="\"V$(TOPNAME)\""
#生成调试信息
CXXFLAGS += -g
#让错误信息带颜色,不知道有没有用
CXXFLAGS += -fdiagnostics-color=auto
CFLAGS_TRACE += -DITRACE_COND=$(if $(CONFIG_ITRACE_COND),$(call remove_quote,$(CONFIG_ITRACE_COND)),true)
CXXFLAGS += $(CFLAGS_TRACE)
######################## 链接器编译选项 ########################
#链接器的选项,包含readline库
LDFLAGS += -lreadline
######################## 构建后的项目 ########################
#构建后的地址
BUILD_DIR = ./build/verilator
#构建后文件存放的地址
OBJ_DIR = $(BUILD_DIR)/obj_dir
#可执行文件的地址
BIN = $(OBJ_DIR)/$(TOPNAME)
######################## verilator选项 ########################
#创建生成文件的目录,存放生成的文件
VERILATOR_CFLAGS += --Mdir $(OBJ_DIR)
#优化分配
VERILATOR_CFLAGS += -x-assign fast
#将所有warning 变成error
VERILATOR_FLAGS += -Wall
#Make waveforms,fst格式
VERILATOR_CFLAGS += --trace-fst
#检查SystemVerilog断言
VERILATOR_CFLAGS += --assert
#debug模式,生成更多调试信息
VERILATOR_FLAGS += --debug
#Add this trace to get a backtrace in gdb
VERILATOR_FLAGS += --gdbbt
# 可用gdb调试
VERILATOR_FLAGS += --gdb
#加速编译
VERILATOR_CFLAGS += -j
#包含verilog中include的文件地址
VERILATOR_CFLAGS += $(INCFLAGS)
#使用DPI-C
VERILATOR_CFLAGS += --vpi
#调用工具链来构建库,不加则由verilator自己构建
VERILATOR_CFLAGS += --build
#指定顶层文件
VERILATOR_CFLAGS += --top-module $(TOPNAME)
#将cxx参数传给gcc编译
VERILATOR_CFLAGS += $(addprefix -CFLAGS , $(CXXFLAGS))
#将ld参数传给ld链接
VERILATOR_CFLAGS += $(addprefix -LDFLAGS , $(LDFLAGS))
#生成C++可执行文件,并指定文件名字
VERILATOR_CFLAGS += --cc --exe -o $(abspath $(BIN))
######################## 查找相关文件 ########################
VSRCS = $(shell find $(abspath ./build/chisel) -name "*.v" -or -name "*.sv")
CSRCS = $(shell find $(abspath ./src/main/cpp) -name "*.c" -or -name "*.cc" -or -name "*.cpp")
run:
@echo "-------- VERILATE --- AND --- BUILD --------"
#清空再创建目的地目录
@rm -rf $(OBJ_DIR)
@mkdir -p $(OBJ_DIR)
#执行命令
@$(VERILATOR) $(VERILATOR_CFLAGS) $(VSRCS) $(CSRCS)
@echo
@echo "-------------------- RUN --------------------"
#清空再创建波形文件夹并
@rm -rf $(BUILD_DIR)/logs
@mkdir -p $(BUILD_DIR)/logs
#执行可执行文件,运行并仿真,生成波形
@$(BIN) +trace
@echo
@echo "-------------------- DONE --------------------"
@echo "To see waveforms, open $(BUILD_DIR)/logs/cpu_wave.fst in a waveform viewer"
@echo
gdb:
@echo "-------- VERILATE --- AND --- BUILD --------"
#清空再创建目的地目录
@rm -rf $(OBJ_DIR)
@mkdir -p $(OBJ_DIR)
#执行命令
@$(VERILATOR) $(VERILATOR_CFLAGS) $(VSRCS) $(CSRCS)
@echo
@echo "-------------------- GDB --------------------"
#清空再创建波形文件夹并
@rm -rf $(BUILD_DIR)/logs
@mkdir -p $(BUILD_DIR)/logs
#gbd执行可执行文件,运行并仿真,生成波形
gdb -s $(BIN) --args $(BIN)
@echo
@echo "-------------------- DONE --------------------"
@echo "To see waveforms, open $(BUILD_DIR)/logs/cpu_wave.fst in a waveform viewer"
@echo
然后在当前目录下执行
make run //执行仿真
make gdb //使用gdb
即可
Verilator 的高阶用法
访问模块内部数据
前面的介绍中,我们要访问模块的数据,只能访问到顶层模块top的输入输出端口,假如我要访问其中内部的wire和reg数据该怎么办呢?
verilator为在将verilog文件编译为cpp文件进行仿真的时候,我们可以在仿真文件中访问verilator将.v文件转化后的cpp文件来访问数据
只需在上面的仿真文件中增加以下内容
#include "../build/obj_dir/Vtop___024root.h"
//然后就可以通过top来访问了
printf("data:%x",top->rootp->top__DOT__my_regfile__DOT__reg_f[1])
//my_regfile为实例化的模块名
//reg_f为模块中定义的reg型
//若你想输出你想要的数据可以在 ../build/obj_dir/Vtop___024root.h 头文件中寻找