为什么要使用Makefile?
在IC设计和验证中,脚本的使用会大大提高办公效率,编写脚本是一个一劳永逸的事,能够免除你每次仿真重复的输入相同的命令,有了脚本以后你只需要简单的执行脚本命令即可。Makefile可以根据指定的依赖规则和文件是否有修改来执行命令。常用来编译软件源代码,只需要重新编译修改过的文件,使得编译速度大大加快。
常用操作指令
VCS对代码进行编译,在终端中输入
vcs -sverilog -debug_all -timescale1ns/1ps led.v tb_led.v -l com.log
接下来输入指令来跑仿真
./simv -l sim.log
dve中查看波形,&表示后台运行
dve -vpd vcdplus.vpd &
仿真脚本Makefile的目标
-
编译compile:编译设计、验证环境、验证用例
-
仿真run:执行仿真
-
调试debug:查看波形
-
回归regression:批量执行仿真用例
-
m清空clear:清空工作目录、临时文件
Makefile编写实例
all: make_lib compile simulate
make_lib:
vlib work // vlib:关键词,创建工程库,名为work
compile:
vlog -l comp.log full_addr.v full_addr_tb.v
//-l comp.log:将编译结果放于comp.log文件中;full_addr.v full_addr_tb.v DUT文件和TB文件的路径,这里使用的是相对路径
simulate:
vsim -novopt -l sim.log work.full_addr_tb -c -do "log -r *;run -all;quit -f"
//-novopt:不进行优化;-l sim.log:将仿真结果置于sim.log文件中;vsim -novopt -l sim.log work.full_addr_tb 对创建的work库下面的TB文件进行仿真。
//-do:执行""里面的内容;log -r:生成波形文件;run -all运行仿真;quit -f:强制退出
clean:
rm *.log *.wlf work -fr
Makefile脚本编译好,可以直接通过命令:" more Makefile文件名” 查看脚本内容;
如果脚本名为"Makefile. * ",则可通过命令 make -f Makefile.*来运行脚本;
例如:脚本名为:Makefile.questasim
则执行命令:make -f Makefile.Questasim
以上两个命令默认执行“all”,如果要单一的执行某一个编译或者仿真命令则需加上标识符,如针对上述例子,只进行编译命令执行:make compile -f Makefile.questasim
VCS的Makefile编写
Makefile编写实例一:插入随机种子seed
图中黄色框部分代表将随机种子变量seed与激励数量变量stimulus_num植入TB文件中,而此部分在TB文件中对应的引入脚本中的seed与stimulus_num变量的代码如下
//Get random seed and stimulus numbers from external scripts
initial begin
if(!$value$plusargs("seed=%0d",seed))begin //获取由脚本传递进来的随机种子
seed = 100; //如果未获取到脚本中的seed变量,则直接对其赋值100;
end
else begin //打印获取到的seed变量值
$display("@%0t: seed = %0d",$time,seed);
end
if(!$value$plusargs("stimulus_num=%0d",stimulus_num))begin //获取由脚本传递进来的激励数量
stimulus_num = 50; //如果未获取到脚本中的stimulus_num变量,则直接对其赋值50;
end
else begin
$display("@%0t: stimulus_num = %0d",$time,stimulus_num);
end
vcs的Makefile脚本的编译仿真,辅助查询同Questasim的Makefile脚本的编译仿真,辅助查询方法形式一样。
如果上述脚本名字为Makefile,则直接通过命令:“ make”,即可直接执行Makefile脚本;
如果脚本名为"Makefile. * ",则可通过命令 make -f Makefile.*来运行脚本;
例如:脚本名为:Makefile.rand
则执行命令:make -f Makefile.rand
以上两个命令默认执行“all”,如果要单一的执行某一个编译或者仿真命令则需加上标识符,如针对上述例子,只进行编译命令执行: make compile -f Makefile.rand;如果脚本名字为Makefile,则编译命令为: make compile。
Makefile编写实例二 :灵活指定编译文件
下面是一个简单的通用型Makefile自动编译仿真脚本:可以灵活指定要编译和仿真的文件。
如果上述脚本名字为Makefile,则直接通过命令:“ make comp_file=当前目录下要编译的文件名”,即可直接执行Makefile脚本;
如果脚本名为"Makefile. * ",则可通过命令 make -f Makefile.* comp_file=要编译的文件名来运行脚本;
例如:脚本名为:Makefile.v
则执行命令:make -f Makefile.v comp_file=编译文件名
Makefile编写实例三 :DVE软件查看波形和覆盖率
Makefile编写实例四 :项目应用
Makefile编写实例五 :应用AHB—SRAMC
注意区别随机种子添加方式:
+seed = $(seed)
显式添加,添加时需使用$
random函数,即$
random(seed)生成随机数+ntb_random_seed = $(rnd_seed)
隐式添加,通过randomize( )函数生成随机种子,不需要在函数中写出。
Makefile编写实例六:应用SPI Master Core
cvs格式的文件如下:(描述寄存器)
make指令
-
make all 进行上述所有的操作
-
make 不带参数直接运行
-
make com 编译
-
make sim 运行sim
-
make run_dve 打开DVE
-
make clean 删除仿真中间文件
常用编译命令
-sverilog | 打开对System verilog的支持,编译System verilog文件使用 |
-timescale=time_unit/time_precision | 添加仿真时间单位、精度 |
-debug | 用于产生debug所需的文件同时打开一些debug相关的开关。 |
-debug_pp | 用于产生debug所需的文件同时打开不影响仿真速度的debug相关开关。 |
-ntb_opts keyword_argument | 常用参数uvm,-ntb_opts uvm表示加载uvm库文件 |
-l filename | 指定vcs编译信息的存储文件 |
-f filename | 指定源文件的路径名列表 |
vcs file.v | 编译.v文件,得到可执行的simv文件 |
vcs file1.v file2.v -o test1 | 编译.v文件,得到一个名称为test1的可执行的simv文件 |
vcs file1.v file2.v -l readme.log +v2k -debug_all | -l readme.log 用于将编译产生的信息放在log文件内; +v2k 是使VCS兼容verilog2001以前的标准; -debug_all 用于产生debug所需的文件同时打开全部debug相关的开关 |
vcs addertb.v add8.v –y …/…/lib +libext+.v -R | -y 搜索路径,指定编译的verilog代码 在什么路径下; lib+libext+.v 是指该路径下所有的.v文件; -R 表示编译后立即执行 |
vcs –f adder.f -R | -f 通过使用-f编译时开关简化命令行条目。 编译设计时,使用-f开关引用该文件。 adder.f文件通过编辑器创建,内容包括:file1.v file2.v |
-y …/…/lib _libext+.v -R | shell>vcs -h 该命令将为您提供一个常用的vcs编译时和运行时开关的列表,以及它们的功能的简要说明 |
+incdir+inc+.v | 在指定的文件夹内搜索指定类型文件 |
-Mupdate | 源文件有修改时,只重新编译有改动的.v文件,节约编译时间 |
-debug | 用于产生debug所需的文件同时打开一些debug相关的开关。 |
-debug_pp | 用于产生debug所需的文件同时打开不影响仿真速度的debug相关开关。 |
-timescale=1ns/1ns | 设置仿真精度 |
shell>./simv | 执行simv文件 |
shell>./test1 | 执行名为test1的simv文件 |
shell>./simv -gui | 命令打开图形化界面DVE |
shell>./simv -l run.log -l run.log | 记录终端上产生的信息 |
覆盖率收集
VCS在统计代码覆盖率的过程中,我们通常在编译和仿真命令上添加对应的开关选项,生成一个.vdb文件记录覆盖率的情况,在使用DVE打开该文件查看。
shell> -cm < coveragetype >
lin+tgl+cond+fsm+path | 行+翻转+条件+状态机+路径 |
-cm_name cov1 | 设置记录有覆盖率信息文件的名字cov1。 |
-cm_dir | 指定生成文件的目录 |
dve -covdir *.vdb & | 使用DVE查看覆盖率收集文件 |
-cm_nocasedef | 排除对在case块中default语句的统计 |
-cm_log +filename.log .log | 文件记录仿真过程中统计覆盖率的信息。 |
-cm_nocasedef | 在统计case语句的条件覆盖率时,不考虑default条件未达到的情况。 |
-cm_hier vcs_cov1.cfg | 通过.cfg 文件选择要查看的覆盖率模块/文件。 |
+表示查看;-表示不查看;tree代表查看某个模块调用的子模块。
在文件内部可以使用特殊的注释打开和关闭代码覆盖率的统计
// VCS coverage off
......
// VCS coverage on
仿真常用
+notimingcheck | 关闭模块中的时序检查 |
+nospecify | 关闭模块的时序检查和路径延时设置 |
+delay_mode_unit | 忽略所有的路经延时 |
+ntb_random+seed=value | 在仿真开始时设置随机种子的值 |
debug的三种方法
1)UCLI
使用UCLI进行debug非常低效,使仿真在错误的地方停止,用命令打开一个一个“黑盒子”并查看内部信号与预期是否一致。
shell> simv +monitoroff | 用" monitoroff " +参数重新模拟。这将告诉VCS跳过测试台上的$monitor行。 |
shell> vcs –f adder.f –R –debug_all -ucli | -ucli 是启用UCLI调试器. ucli% help 可用的UCLI命令,获取UCLI命令的快速摘要。 ucli% scope 查看当前module名 ucli% show 查看信号列表 ucli% get sum_test -radix hex 查看当前某个信号的值 |
2)使用系统函数
3)使用DVE
在tb文件中新增加一个initial块,表示如果在编译时,定义了DUMP_VPD这个宏,那么在仿真时,打开$ vcdpluson这个开关选项。
initial begin
`ifdef DUMP_VPD
$vcdpluson();
`endif
end
shell>vcs -f file.f -R -debug_all +define+DUMP_VPD:
使用上面的命令编码以后仿真,+define+DUMP_VPD 表示在编译时定义了DUMP_VPD这个宏,即在仿真时,打开了$vcdpluson()这个开关选项。
在仿真完成后,生成了vcdplus.vpd文件,这个文件记录了仿真过程中所有的信号的波形,可以使用dve打开。
shell> dve & 打开dve,& 用途是后台打开dve,以免终端被占用。
+vpdfile+filename | 可以更改生成VPD文件的文件名,默认为vpdplus.vpd |
+race | 报告竞争冒险存在的情况 |
$vcdpluson(level number,module_instance,…,…) | level number表示查看module_instance下子模块多少层的波形。module_instance表示从哪个module开始记录波形 |
VCD/VPD | 是用VCS的DVE可以打开的波形文件,VPD是VCD的压缩版;FSDB是用Verdi打开的波形文件。 |
在系统函数display( )打印的信息中,在最后加入下面两个宏,可以显示该语句属于哪个模块,第几行。
$display( "hello world!", `__FILE__ , `__LINE__ );