【一生一芯笔记】Verilator和NVBoard简单使用

前言

最近在搞一生一芯,前期还算比较顺利,但是在仿真环境搭建这部分遇到了大问题。一是因为自己之前都是直接烧录到真实的FPGA等板卡上,很少链接这样的仿真环境,二是因为Verilator和NVBoard的资料很少,尤其是NVBoard。

在摸索了好几天后,大致摸索出来一点点门路,所以希望缓一下,整理一下,也帮大家少走一些弯路。

PS:本人是微电子专业,本文中的许多用词可能并不严谨,甚至有错误,但是并不影响最终的使用,还请大家见谅。

前置条件

这里默认大家已经按照一生一芯的笔记安装好Verilator和NVBoard了,这里只讲解如何使用。

PS_1:安装NVBoard所依赖的3个包(SDL2,SDL2-image和SDL2-ttf)的时候,使用Ubuntu自带的软件源可能会报错,需要更换到其他源,我更换到阿里云源可以下载。

PS_2:查看波形文件可以直接使用VSCode里的Digital IDE插件,这个插件功能很强大推荐给大家。

Verilator的简单使用

我这里主要参考的以下这篇文章,这篇文章给出了一种Verilator简单的使用方法:

http://t.csdnimg.cn/4wioKicon-default.png?t=N7T8http://t.csdnimg.cn/4wioK接下来我主要把上面的文章总结一下,给大家一个固定的使用流程模板。我使用一个与门作为例子。

(可选)第零步:搭建工程框架

新建一个文件夹,名字随意,这里叫做my_example_andgate。然后再新建一个子文件夹名字叫做"vsrc",这里保存verilog的源代码文件。

最终框架如下:

my_example_andgate
|--vsrc
    |--top.v

第一步:编写verilog文件top.v

首先我们需要使用verilog语言编写我们希望生成的电路,并且最顶层的module名称必须为top。在“vsrc”文件夹中,新建一个top.v文件,top.v文件里我编写了一个非常简单的与门:

// 使用一个与门作为示范
module top(
	input a,
	input b,

	output f
);

	assign f = a & b;

endmodule

保存top.v代码后关闭。

第二步:使用verilator将top.v文件转换为cpp文件(verilate化)

在my_example_andgate这个目录下,打开命令行终端,输入以下代码:

verilator -Wall --trace -cc ./vsrc/top.v --exe tb_top.cpp

执行完这一步,将会自动产生一个obj_dir文件夹,obj_dir里面是top.v经过verilator转化后生成的Vtop.cpp以及各种头文件。

PS:这行代码每一个参数的具体含义请参考上面那篇文章。

此时的框架如下:

my_example_andgate
|--obj_dir
    |--...
|--vsrc
    |--top.v

其实到这里,Verilator的工作就完成了,Verilator的本质就是将verilog文件转化为cpp以及各种头文件供我们后边调用。至于编写后续测试激励文件的事情,是一个纯cpp的开发,与verilator已经没有关系了。

第三步:编写测试激励文件tb_top.cpp

我们打开obj_dir文件夹,并在这里新建一个名为tb_top.cpp的测试激励文件。

打开tb_top.cpp后,在里面输入以下代码:

#include <verilated.h>
#include <verilated_vcd_c.h>
#include "Vtop.h"
#include "Vtop___024root.h"

#define MAX_SIM_TIME 20 // 最大仿真时钟周期
vluint64_t sim_time = 0; // 实际仿真周期

int main(int argc, char** argv, char** env) {
    Vtop *dut = new Vtop; // 例化一个top模块

    // 下面4行为开启跟踪固定代码
    Verilated::traceEverOn(true);
    VerilatedVcdC *m_trace = new VerilatedVcdC;
    dut->trace(m_trace, 5);
    m_trace->open("waveform.vcd");

    while (sim_time < MAX_SIM_TIME) {
        int a = rand() & 1; // 随机生成a
        int b = rand() & 1; // 随机生成b
        dut->a = a; // 将a赋值给例化模块的a
        dut->b = b; // 将b赋值给例化模块的b
        dut->eval(); // 更新电路状态!!!切记要在while中添加,非常重要,一定不能少
        m_trace->dump(sim_time); // 将当前状态记录到trace中,后续输出波形要用
        sim_time++; // 仿真周期增加
    }

    m_trace->close();
    delete dut;
    exit(EXIT_SUCCESS);
}

可以看出,实际上main函数中的while循环就是我们之前传统verilog开发时候编写的testbench,只不过因为verilator将verilog文件转化为cpp文件了,所以我们就可以直接用cpp编写testbench了

第四步:编译测试激励文件并生成一个可执行文件

编写testbench(tp_top.cpp)后,我们再次在my_example_andgate这个目录下,打开命令行终端,输入以下代码:

make -C obj_dir -f Vtop.mk Vtop

执行完这一步,就会把第二步中转化的cpp文件按照tb_top.cpp文件中的测试激励代码进行编译,最终生成一个名为Vtop的可执行文件

第五步:执行可执行文件并生成最终的仿真波形文件

最后,我们直接在命令行中输入以下代码:

./obj_dir/Vtop

这一步就是运行Vtop这个可执行文件,执行完之后,就会发现在命令行的当前目录下(my_example_andgate),生成了一个waveform.vcd文件,这个文件就是按照激励文件生成的仿真波形。

(可选)第六步:编写一个Makefile文件,实现多步合一

上述步骤我们也可以通过编写一个Makefile文件,来快速执行。

在my_example_andgate目录下,新建一个Makefile,输入以下代码:

sim:
	verilator -Wall --trace -cc ./vsrc/top.v --exe tb_top.cpp
	# 执行完这一步,将会自动产生一个obj_dir文件夹,obj_dir里面是通过verilator将top.v转化后的Vtop.cpp以及各种头文件
	
	# 注意:执行下一步之前,需要自己手动创建一个tb_top.cpp的文件,并在这个文件中编写好测试的testbench代码
	make -C obj_dir -f Vtop.mk Vtop
	# 执行这一步,就会把第一步转化的cpp文件按照tb_top.cpp文件中的测试激励代码进行编译,最终生成一个名为Vtop的可执行文件
	
	./obj_dir/Vtop
	# 这一步就是运行Vtop这个可执行文件,执行完之后,就会发现在命令行的当前目录下,生成了一个waveform.vcd文件,这个文件就是按照激励文件生成的仿真波形

然后我们就可以直接在命令行终端中输入:

make sim

即可直接得到仿真波形文件了。

实验结果(仿真波形查看):

最终的波形如下,f表现为一个与门行为:只有当a和b同时为1时,f才输出1。

PS:一生一芯中要求的双控开关(其实就是异或门),只需要改一下top.v即可。

NVBoard的简单使用

先说踩坑记录:一定记住必须要加:dut->eval(); // 更新电路状态!!!切记要在while中添加,非常重要,一定不能少。因为这行代码没加,我卡了好几个小时,还是群里的一位大佬一眼给我指出来的(跪谢)。

我是直接复制的官方的Makefile,因为我这种菜鸡根本读不懂Makefile,更别说自己发挥了。。。

我这里继续使用上一节的与门模块,我会将与门的两个输入a,b分别连接到NVBoard的SW0和SW1上,输出链接到LD0上。最终的实验结果应该是:只有当SW0和SW1都拨动开时,LD0才会点亮。

第一步:搭建实验框架

新建一个文件夹,我这里名为“my_example_nvboard”,再新建3个子文件夹和Makefile:

第二步:vsrc中编写verilog文件

打开vsrc文件夹,把上一节中编写的与门top.v文件复制进来:

第三步:constr中进行引脚绑定

打开constr文件夹,新建一个名为top.nxdc的文件。

这个文件是引脚绑定的文件,打开后输入如下代码:

top=top

a SW0
b SW1
f LD0

这个输入的格式在NVBoard官方的README.MD中说明了。我这里就是把与门的两个输入a和b连接到NVBoard的SW0和SW1引脚,输出f连接到LD0引脚。

第四步:csrc中编写NVBoard仿真cpp文件

然后打开csrc文件夹,新建一个main.cpp文件,这个就是我们最终的NVBoard仿真cpp文件。打开main.cpp文件后,我们输入以下代码:

#include <nvboard.h>
#include <Vtop.h>

static TOP_NAME dut;

void nvboard_bind_all_pins(TOP_NAME* top);

int main() {
  nvboard_bind_all_pins(&dut);
  nvboard_init();

  while(1) {
    nvboard_update();
    dut.eval(); // 一定要加!否则就没有更新电路状态!一定要加!否则就没有更新电路状态! 一定要加!否则就没有更新电路状态!
  }
}

其实这个main.cpp类似与上一节中的tb_top.cpp文件,只不过因为我们直接使用NVBoard了,所以就不需要自己写生成激励信号的代码了。

第五步:编写Makefile

我们的Makefile直接使用官方的代码,复制以下代码到Makefile文件中:

TOPNAME = top
NXDC_FILES = constr/top.nxdc
INC_PATH ?=

VERILATOR = verilator
VERILATOR_CFLAGS += -MMD --build -cc  \
				-O3 --x-assign fast --x-initial fast --noassert

BUILD_DIR = ./build
OBJ_DIR = $(BUILD_DIR)/obj_dir
BIN = $(BUILD_DIR)/$(TOPNAME)

default: $(BIN)

$(shell mkdir -p $(BUILD_DIR))

# constraint file
SRC_AUTO_BIND = $(abspath $(BUILD_DIR)/auto_bind.cpp)
$(SRC_AUTO_BIND): $(NXDC_FILES)
	python3 $(NVBOARD_HOME)/scripts/auto_pin_bind.py $^ $@

# project source
VSRCS = $(shell find $(abspath ./vsrc) -name "*.v")
CSRCS = $(shell find $(abspath ./csrc) -name "*.c" -or -name "*.cc" -or -name "*.cpp")
CSRCS += $(SRC_AUTO_BIND)

# rules for NVBoard
include $(NVBOARD_HOME)/scripts/nvboard.mk

# rules for verilator
INCFLAGS = $(addprefix -I, $(INC_PATH))
CXXFLAGS += $(INCFLAGS) -DTOP_NAME="\"V$(TOPNAME)\""

$(BIN): $(VSRCS) $(CSRCS) $(NVBOARD_ARCHIVE)
	@rm -rf $(OBJ_DIR)
	$(VERILATOR) $(VERILATOR_CFLAGS) \
		--top-module $(TOPNAME) $^ \
		$(addprefix -CFLAGS , $(CXXFLAGS)) $(addprefix -LDFLAGS , $(LDFLAGS)) \
		--Mdir $(OBJ_DIR) --exe -o $(abspath $(BIN))

all: default

run: $(BIN)
	@$^

clean:
	rm -rf $(BUILD_DIR)

.PHONY: default all clean run

第六步:命令行终端运行make run

最后,只需要我们在my_example_nvboard目录下的命令行终端中输入:

make run

稍等片刻,NVBoard的界面就出现了。

实验结果

看窗口的左上角,只有当SW0和SW1都拨动后,LD0才变亮,说明是与门,结果正确。

总结

Verilator和NVBoard这两个工具我在之前的学习中从来没有使用过,而且资料较少,所以踩了很多坑,也有好几次都想放弃了。回首向来萧瑟处,也无风雨也无晴,解决问题的过程是痛苦的,但是解决之后的充实感确是满满的。

希望可以帮助和当初的我一样毫无头绪的同学一些帮助。

尚存问题

为了方便起见,我这里都使用的是组合电路(与门),将来应该使用时序电路仿真,主要的区别在于testbench的编写。

参考文献

http://t.csdnimg.cn/y8q47icon-default.png?t=N7T8http://t.csdnimg.cn/y8q47j额vhttp://t.csdnimg.cn/xGYMahttp://t.csdnimg.cn/xGYMahttp://t.csdnimg.cn/xGYMahttp://t.csdnimg.cn/xGYMahttp://t.csdnimg.cn/xGYMahttp://t.csdnimg.cn/xGYMaicon-default.png?t=N7T8http://t.csdnimg.cn/xGYMa

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

为人民服务的FinFET

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值