VCS入门教程(二) debug

一、前言

本文主要介绍VCS进行verilog代码debug的基本方法。

二、三种方法(第三种最常用)

1. 使用系统函数
首先我们在编写verilog模块的testbench时,可以在里面使用一些verilog的系统函数,在运行simv文件跑仿真时,进行一些控制。例如:
$time 代表当前的仿真时间。
$display 类似C语言的printf函数,仿真时在终端上打印一些信息,比如一些变量的值。
$monitor 和$display类似,不同的是$display在被调用的时候打印一些信息,$monitor可以自动监测变量,当变量值发生变化时,便打印出信息。
$stop 调用时使仿真产生一次中断。
$finish 调用时使仿真结束。
$readmemb 用于存储器建模时的初始化,将一个文本文件里的数据,写入存储器。
$readmemh $readmemb 以二进制数的形式写入,$readmemh以十六进制数写入。

下面来看下VCS Labs 里lab1/parta 下addertb.v 的内容
module addertb;
reg [7:0] a_test, b_test;
wire [7:0] sum_test;
reg cin_test;
wire cout_test;
reg [17:0] test;

add8 u1(a_test, b_test, cin_test, sum_test, cout_test);

initial begin                
$monitor("time = %d, a = %h, b = %h, sum = %h;  cin = %h, cout = %h",
            $time, a_test, b_test, sum_test, cin_test, cout_test);
end

initial
begin
  for (test = 0; test <= 18'h1ffff; test = test +1) begin
    cin_test = test[16];
    a_test = test[15:8];
    b_test = test[7:0];
    #50;
    if ({cout_test, sum_test} !== (a_test + b_test + cin_test)) begin
      $display("***ERROR at time = %0d ***", $time);
      $display("a = %h, b = %h, sum = %h;  cin = %h, cout = %h",
               a_test, b_test, sum_test, cin_test, cout_test);
      $finish;
    end
   #50;
  end
  $display("*** Testbench Successfully completed! ***");
  $finish;
end
endmodule
上面是一个二输入加法器的testbench,

a_test和b_test 为输入,
sum_test为和,
cin_test为来自低位的进位输入,
cout_test为向高位的进位输出。
本人在里面新增了$monitor 的部分。

运行仿真时,每延迟100个时间单位,test的值变化一次,使输入发生一次变化。$monitor 监测四个变量,当任何一个发生变化时,打印出输入输出和当前仿真时间的值。当输入输出不满足加法关系时,调用$display函数打印错误信息。并使用$finish 结束仿真。若所有输入输出均满足加法关系,打印完成信息,并结束仿真。

下面看一个使用 $readmemb 的例子
`timescale1ns/10psmodulemyrom(read_data,addr,read_en_);inputread_en_;input[3:0]addr;output[3:0]read_data;reg[3:0]read_data;reg[3:0]mem[0:15];initial$readmemb("my_rom_data",mem);always@(addrorread_en_)if(!read_en_)read_data=mem[addr];endmodule

my_rom_data 文件里的内容:
0000010111000011110100100011111110001001100000011101101000011101

在上述ROM建模中,使用 $readmemb 将文本数据写入ROM来进行初始化。利用系统函数进行debug的方式大概介绍到这里。


2. 使用UCLI (用户命令行接口)
使用 lab2/partb 里面的源码,addertb.v 与上面的代码一致,就是将$monitor部分去掉了。在判断发生error的地方,将$finish 更改为 $stop。相当于每发生一次错误,终断一次仿真。

图 1

图 2

在编译指令中加入 -ucli 使用UCLI。


图 3

在仿真时会打开UCLI,并使仿真停止在 0 时刻。


图4

使用 run 继续运行仿真,当出错时,$stop被调用而使仿真停下。使用 scope 查看当前 module 名。使用 show 查看信号列表。使用 get sum_test -radix hex 查看当前某个信号的值。

使用 UCLI 进行Debug其实是非常低效的,使仿真在错误的地方停止,用命令打开一个一个“黑盒子”(module) 并查看内部信号与预期是否一致。在实际使用VCS的时候基本不用,在此简单介绍,不做过多赘述。


3. 使用DVE
在前面我们已经使用命令 ./simv -gui 。以图形化界面的方式运行仿真。以下介绍一种更为常用的方式。
还是使用lab1/parta 下的例子,修改 addertb.v 的内容。
moduleaddertb;reg[7:0]a_test,b_test;wire[7:0]sum_test;regcin_test;wirecout_test;reg[17:0]test;add8u1(a_test,b_test,cin_test,sum_test,cout_test);initialbegin`ifdefDUMP_VPD$vcdpluson();`endifendinitialbeginfor(test=0;test<=18'h1ffff;test=test+1)begincin_test=test[16];a_test=test[15:8];b_test=test[7:0];#50;if({cout_test,sum_test}!==(a_test+b_test+cin_test))begin$display("***ERROR at time = %0d ***",$time);$display("a = %h, b = %h, sum = %h; cin = %h, cout = %h",a_test,b_test,sum_test,cin_test,cout_test);$finish;end#50;end$display("*** Testbench Successfully completed! ***");$finish;endendmodule
在 addertb.v 中新增了一个 initial 块。表示如果在编译时,定义了 DUMP_VPD 这个宏,那么在仿真时,打开 $vcdpluson() 这个开关选项。

图 5

使用上图命令编译源码后仿真,+define+DUMP_VPD表示在编译时定义 DUMP_VPD 这个宏,即在仿真时,打开了$vcdpluson() 这个开关选项。

图 6

我们可以看到,在仿真完成后,生成了 vcdplus.vpd 这个文件。这个文件记录了仿真过程中所有信号的波形,可以使用 dve 打开。

图 7
通过 dve & 命令打开 dve, "&"的用途是后台打开dve,以免终端被占用。我们可以看到 dve 打开后界面为空白。
图 8
File -> Open Database
0
图 9
选择 vpd 文件并打开
0
图 10
在Hierarchy 部分,可以查看顶层模块里面的子模块,右键 -> Add to Waves 查看对应模块的波形图。
在上述方法中,在编译时通过定义一个宏,打开 testbench 中 $vcdpluson() 这个开关选项,在运行 simv 进行仿真时,VCS便把所有的波形记录下来,生成一个 .vpd 文件 (波形文件)。在dve中打开文件,即可查看仿真波形,方便之处在于波形可以发给他人查阅。
几点补充:
  1. 在编译时,将 -debug_all 选项 更改为 -debug_pp。打开生成 VPD 文件的功能,关掉UCLI的功能,节约编译时间。
  2. 在编译时,使用 +define+macro1 将宏macro1传给源代码。使用+define+macro1=value+macro2=value 将macro1和macro2 传给源文件中同名的宏。
  3. 在编译时,使用 +vpdfile+filename 可以更改生成 VPD 文件的文件名,默认为 vpdplus.vpd。
  4. 可直接使用命令: dve -vpd vcdplus.vpd & 后台打开 dve 并加载 vpd 文件,代替上面图7~图9的过程。
  5. 调用 $vcdpluson() 时可以加入一些参数,如果什么都不加,则默认记录顶层模块下所有子模块的信号波形。参数格式:$vcdpluson(level_number, module_instance, ... , ... )。比较重要的参数为前两个。数字设计里面的 module 是层次化/结构化的,类似于一层一层的黑盒子不断包含下去。module_instance 表示从哪一个module开始记录波形,level_number表示查看 module_instance 下子模块多少层的波形。下面使用一些例子来说明。
0
图 11
$vcdpluson() 或者 $vcdpluson(0, addertb) 记录 addertb 及其所有子模块的波形。
$vcdpluson(1, addertb) 只记录 addertb 层的波形。
$vcdpluson(2, addertb) 记录 addertb 层和 u1(add8) 层的波形。
$vcdpluson(3, addertb) 记录 addertb , u1(add8) ,u1(add4),low_add, high_add 层的波形。


三、对makefile的补充

在VCS入门教程(一)中,我们已经写过一个 makefile,现针对上述使用dve debug 的方法,对其做一些补充。仍使用上面 lab1/parta 内的代码。修改makefile如下:
.PHONY:comsimdebugcleanOUTPUT= adder_topALL_DEFINE= +define+DUMP_VPDVPD_NAME= +vpdfile+${OUTPUT}.vpdVCS= vcs -sverilog +v2k -timescale=1ns/1ns \ -debug_pp \ -o ${OUTPUT}\ -l compile.log \${VPD_NAME}\${ALL_DEFINE}SIM= ./${OUTPUT}${VPD_NAME} -l ${OUTPUT}.logcom:${VCS} -f verilog_file.fsim:${SIM}debug:    dve -vpd ${OUTPUT}.vpd &clean:    rm -rf ./csrc *.daidir *.log simv* *.key *.vpd ./DVEfiles

在终端上分别使用 make com ,make sim ,make debug ,make clean 来编译,仿真,查看波形和清理生成的文件和目录。


四、结束语

本文介绍了VCS 进行 debug 的三种方式,其中第三种是最常使用最有效的。在实际工程中,通常使用VCS生成 fsdb 格式的波形文件,将其导入另一个软件 Verdi 查看波形,代替DVE进行联合仿真。感兴趣的同学可以查阅相关资料进行了解。

#笔记##读书笔记#
全部评论
期待楼主继续分享
点赞 回复 分享
发布于 2022-06-07 22:00
感谢楼主分享,学到了
点赞 回复 分享
发布于 2022-06-03 22:19

相关推荐

咦哟,从去年八月份开始长跑,两处实习转正都失败了,风雨飘摇,终于拿到offer了更新一下面试记录:秋招:多部门反复面试然后挂掉然后复活,具体问了啥已经忘了,只是被反复煎炸,直至焦香😋春招:base北京抖音hr打来电话说再次复活,准备面试,gogogo北京抖音一面:六道笔试题:1.promise顺序2.定义域问题3.flat展开4.并发请求5.岛屿数量算法(力扣)深度,广度都写6.忘记了,好像也是算法,难度中等其他问题多是框架底层设计,实习项目重难点~~~秒过😇北京抖音二面:三道笔试题:(为什么只有三道是因为第三道没做出来,卡住了)1.中等难度算法(忘记啥题了,应该是个数组的)2.认识js的继承本质(手写继承模式,深入js的面相对象开发)3.手写vue的响应式(卡在了watch,导致挂掉)---后知后觉是我的注册副作用函数写得有问题,有点紧张了其他题目多是项目拷打,项目亮点,对实习项目的贡献~~~第二天,挂,but立马复活转战深圳客服当天约面深圳客服一面:六道笔试题,由于面过太多次字节,面试官叫我直接写,不用讲,快些写完😋,具体都是些继承,深拷贝(注意对数组对象分开处理,深层次对象,循环引用),加中等难度算法题~~~秒过深圳客服二面:口诉八股大战:大概囊括网络,浏览器渲染原理,动画优化,时间循环,任务队列等等(你能想到的简单八股通通拉出来鞭尸😋)算法题:笔试题6道:1:找出数组内重复的数,arr[0]-arr[n]内的数大小为[1-n],例如[1,2,2,3,3]返回[2,3],要求o(n),且不使用任何额外空间(做到了o(n),空间方面欠佳,给面试官说进入下一题,做不来了)2:原滋原味的继承(所以继承真滴很重要)3:力扣股票购买时机难度中等其他滴也忘记了,因为拿到offer后鼠鼠一下子就落地了,脑子自动过滤掉可能会攻击鼠鼠的记忆😷~~~秒过深圳客服三面:项目大战参与战斗的人员有:成员1:表单封装及其底层原理,使用成本的优化,声明式表单成员2:公司内部库生命周期管理成员3:第三方库和内部库冲突如何源码断点调试并打补丁解决成员4:埋点的艺术成员5:线上项目捷报频传如何查出内鬼成员6:大文件分片的风流趣事成员7:设计模式对对碰成员8:我构建hooks应对经理的新增的小需求的故事可能项目回答的比较流利,笔试题3道,都很简单,相信大家应该都可以手拿把掐😇~~~过过过无hr面后续煎熬等待几天直接hr打电话发offer了,希望大家也可以拿到自己心仪的offer
法力无边年:牛哇,你真是准备得充分,我对你没有嫉妒,都是实打实付出
查看19道真题和解析
点赞 评论 收藏
分享
评论
1
6
分享

创作者周榜

更多
牛客网
牛客企业服务