用Tcl脚本启动QuestaSim(ModelSim)进行仿真
用Tcl脚本启动QuestaSim(ModelSim)进行仿真
用Tcl脚本启动QuestaSim(ModelSim)对文件进行仿真是一种很方便的方法,接下来介绍一下具体的使用方法。QuestaSim其实就是高配版的ModelSim,两个软件的界面布置和操作都是一样的,所以脚本也同样适用,因为我用的是questasim,所以下面我就直接说queatasim了。
在用tcl命令之前,需要在电脑上安装有tcl解释器,这样电脑才能认识你的tcl脚本,我用的是ActiveTcl8.5,这里是下载链接,需要可以自取:
链接:https://pan.baidu.com/s/1OiNNVVrbxS_ms-xSWF3NHw
提取码:1234
首先介绍一下tcl脚本会用到的一些命令,方便我们编写脚本时更好的理解。
命令:
puts:
输出命令,将字符串输出,如果字符串中间有空格,需要用双引号将字符串扩起来。
例:puts “start simulation”
[]:
方括号“[]”完成命令置换。用“[]”将一条命令括起来,命令执行完成后,返回结果。
exec:
exec就是执行一条命令,可以执行任何系统命令,一些命令需要在Linux系统中执行,在tcl脚本中无法执行,可以用exec调用该命令在系统中执行。
source:
读一个路径的文件并把这个文件的内容作为一个脚本执行。
set:
普通置换,会把所有的参数看作是字符串,把后面的字符串赋给前面的变量。
例:set x 1+2+3
执行命令后x的值为“1+2+3”这个字符串,而不是数字6。
$:
变量置换,在变量名之前加上$,功能是返回该变量的内容。
例:set a 3
puts $a
返回结果为3。
expr:
运算表达式,将命令后的运算求值。
例:set a 1
expr $a+2
返回结果为3。
proc:
过程函数,语法规则为:proc processname {参数} {过程体}
例:proc my_proc {x} {expr $x+2}
my_proc 3
返回结果为5。
if:
语法规则:if {判断语句} {脚本语句} elseif {
判断语句} {脚本语句} else {脚本语句}
注意:语句分行写时, { 一定要写在上一行,如果不这样TCL解释器会认为if命令在换行符处已经结束,下一行会被当成新命令,从而导致错误。
例:set a 4
set b 6
if {$a > $b} {puts $a} else {puts $b}
输出结果为6。
file:
对文件进行操作,后面跟不同的命令对文件进行不同的操作。
例:file exists name
返回文件或目录name是否存在
file isdirectory name
检查name是否为目录
具体可以参考tcl脚本语言之file的常见用法_tcl file-CSDN博客
vlog:
vlog [options] <filename>
对文件进行编译,option表示可以输入一些命令在编译文件时进行一些操作。如下所示:
-cover进行覆盖率分析,-cover[=<spec>],<spec>可指定为{b|c|e|s|f|t}。
+define+<macro_name>[=<macro_name>],该选项等同于在编译源文件时添加`define <macro_name> <macro_text>
也可以在一个+define后添加多个宏定义(也可以分开)
例:vlog +define+one=r1+two=r2+three=r3 text.v
(-f|file) <filename>对应一个参数文件,文件内可添加更多的编译选项内容。
-incr指启用增量编译功能,也就是说如果我们的一些文件修改之后,重新编译文件的时候仅编译修改的文件,而不会把所有文件重新编译一便,这样节省我们的编译时间。
+incdir+<directory>指明对于源文件中使用`include编译导向时将会查找对应文件的文件夹。
(-l|-logfile) <filename>生成编译时的log记录文件。
-L <libname>指定在哪些库中搜索预先编译的模块,在运行vsim 命令时,必须指定在此处要搜索的库。
-novopt编译时不作优化。
-lint编译时作语义检查(例如,为input端口赋值、访问未声明的变量、访问数组的范围越界等)
{+initmem|+initreg}[=<spec>] [+{0|1|x|z}]初始化{数组|变量},<spec>可以为(r|b|e),只对静态变量(例如硬件信号或者static变量)起作用。
-quiet过滤一些加载库的信息,使得log信息更简洁。
-timescale[=]|[ ]<time_units>/<time_precision>指明那些未指定时间单位的module/interface/program/package等。
-warning <msg_number> [,<msg_number>,...]将指定消息严重级别将为warning级别。
-work <library_name>在编译时将目标编译到指定的库中,库名可以是逻辑库名或者库的对应路径。
vcom:
和vlog差不多,都是编译文件的意思,不过vlog编译的是.v文件和.sv文件,vcom编译的是.vhd文件。
-93:后面接.vhd文件所在的路径。
vlib:
vlib <library_name>按照库指定路径和库名去创建库,也就是创建一个文件夹目录,用来存放questasim的一些文件。
vdir:
vdir -all显示当前所有编译库,预编译库中的内容。
vdir [-lib <library_name>] [<design_unit>]显示指定库(库名或路径)的内容,或者指定模块的信息。
verror:
verror [-fmt|-full] [-kind <tool>] {-all | <msgnum>}显示{全部|指定msgnum},有关某一个指令<tool>的错误描述内容,便于理解错误。
vsim:
vsim [options]
options代表后面跟不同的命令进行不同的操作,如下所示:
[-batch | -c | -gui | -i]采用后台模式(-batch)、命令行模式(-c)、用户界面模式(-gui)、交互模式(-i)运行questasim(modelsim)仿真器。
-voptargs=+acc指定特定的参数进行优化。
-do “<command_string>” | <do_file_name>传入并执行tcl命令或者脚本文件。
-f <filename>传入带有仿真选项的文件,可在仿真过程中解析并采用这些仿真选项。
[-g | -G] <Name>=<Value>... -g可以覆盖那些没有被显式赋值(采取默认值)的参数,而-G则可以覆盖那些已经被显式赋值的参数。
-immedassert | -noimmedassert使能或禁止立即断言(immediate assertion)。
-solvefaildebug=<value>使能随机化失败调试,如果value不给值,则使能基本调试功能。
-sv_lib <shared_obj>导入DPI共享对象(shared object),用于导入DPI方法。
-sv_seed <integer> | random用于指定仿真时的随机种子。
-title <title>在仿真窗口指定当前仿真的“标题”,便于调试多个同时进行的仿真窗口。
-wlf <file_name>指定保存的保存文件,默认输出vsim.wlf。
-coverage对覆盖率进行收集,但前提是在编译文件时要添加+cover命令。
-viewcov [<dataset_name>=]<UCDB_filename>调用coverage view模式查看UCDB覆盖率数据。
-coverstore <dir_path> -testname <name>在仿真结束时保存覆盖率数据结果,必须要单独调用coverage save命令。
-default_radix <radix>在仿真时指定变量显示的默认格式({ascii | binary | decimal | hexadecimal | octal | symbolic | unsigned})。
-uvmcontrol={all | certe | disable | msglog | none | struct | trlog | verbose}使能uvm有关调试功能。
-classdebug -msgmode both -uvmcontrol=all(应用方式)。
mem:
mem list [-r] [<path>]:显示目标路径下的数组信号/变量。
mem display:显示目标mem的内容。
vmap:
vmap <逻辑库> <物理库>
定义逻辑库名称和目录之间的映射,在questasim界面library里有个work的路径,我们每次编译后的文件都会存放在work路径下,这个路径称为逻辑库。因为我们的.v文件questasim是不能直接用的,它需要把.v文件编译成自己可以直接使用的文件,所以把编译后的文件都存在逻辑库里,但是这些文件在电脑上总要有个文件夹存放,所以我们在电脑存储目录里建的文件夹work(其它名字也可以)就称为物理库,vmap就是建立逻辑库与物理库的连接,就是说questasim编译后的文件就存在我们电脑上建的work文件夹目录下。
脚本
接下来介绍脚本的具体写法,我这里针对我的一个工程写了两个tcl脚本,一个文件是start.tcl,一个是do.tcl,两个文件跟仿真tb文件放在一起,操作是直接双击文件start.tcl,就会自动调起questasim,然后执行文件do.tcl。
首先看一下start.tcl的写法:
exec vsim -gui -do "source ./do.tcl"
exit
这两句的意思就是以gui的方式打开questasim,并且打开后把do.tcl这个文件作为一个脚本执行。questasim打开并开始执行do.tcl时退出start.tcl的执行。
接下来是do.tcl的写法:
#第一部分
set DIR [pwd]
set SIMCODE $DIR
set SRCCODE $DIR/../../sources_1/new
set IPCODE $DIR/../../sources_1/ip
set FIFOSIM $DIR/../../../38prj_class.ip_user_files/ipstatic
set XILINX_LIB $DIR/../../../../../../../../AppInstall/QuestaSim_Xlib
#第二部分
proc check_lib {lib} {if {![file isdirectory $lib]} {vlib $lib}}
check_lib ./work
#第三部分
vmap work ./work
#第四部分
vlog -incr -work work -sv \
"C:/FPGA/Vivado/2020.1/data/ip/xpm/xpm_cdc/hdl/xpm_cdc.sv" \
"C:/FPGA/Vivado/2020.1/data/ip/xpm/xpm_memory/hdl/xpm_memory.sv" \
vcom -work work -93 \
"C:/FPGA/Vivado/2020.1/data/ip/xpm/xpm_VCOMP.vhd" \
vlog -incr -work work \
"$IPCODE/gtwizard_0/gtwizard_0/example_design/gtwizard_0_tx_startup_fsm.v" \
"$IPCODE/gtwizard_0/gtwizard_0/example_design/gtwizard_0_rx_startup_fsm.v" \
"$IPCODE/gtwizard_0/gtwizard_0_init.v" \
"$IPCODE/gtwizard_0/gtwizard_0_gt.v" \
"$IPCODE/gtwizard_0/gtwizard_0_multi_gt.v" \
"$IPCODE/gtwizard_0/gtwizard_0/example_design/gtwizard_0_sync_block.v" \
"$IPCODE/gtwizard_0/gtwizard_0.v" \
#第五部分
vlog -incr -work work \
"$FIFOSIM/simulation/fifo_generator_vlog_beh.v" \
vcom -work fifo_generator_v13_2_5 -93 \
"$FIFOSIM/hdl/fifo_generator_v13_2_rfs.vhd" \
vlog -incr -work fifo_generator_v13_2_5 \
"$FIFOSIM/hdl/fifo_generator_v13_2_rfs.v" \
vlog -incr -work work $IPCODE/txfifo_32x1024/sim/txfifo_32x1024.v
#第六部分
vlog -incr -work work $SRCCODE/*.v
#第七部分
vlog -incr -work work $SIMCODE/top_tb.v
#第八部分
vlog -incr -work work $DIR/glbl.v
#第九部分
vsim -voptargs=+acc=npr \
-L $XILINX_LIB/fifo_generator_v13_2_5 -L $XILINX_LIB/unisims_ver -L $XILINX_LIB/unimacro_ver\
-L $XILINX_LIB/secureip\
-L work work.top_tb work.glbl
#第十部分
log -r /*
#第十一部分
run -all
第一部分:
第一句就是打开当前文件(do.tcl)的绝对路径,然后把绝对路径赋值给DIR变量。
接下来几句就是根据当前文件的绝对路径找到我们仿真过程中用到的其它文件的相对路径,解释一下比如$DIR/../../sources_1/new指的就是do.tcl文件所在的文件夹向上一级,再向上一级文件夹下的sources_1文件夹下的new文件夹,其中两个点..指的就是向上一级,如果是一个点.指的就是当前文件夹,斜杠/指的就是在某文件夹下。这几句就是把这些路径分别赋值给不同的变量,以便我们后面使用。
最后一句是Xilinx的库文件存放的位置,有的人不知道库文件是什么东西,简单来说就是工程中我们会用到一些IP核,原语之类的,那questasim怎么知道这些IP核和原语代表什么意思呢,它就要结合库文件才能把IP核和原语实际的作用仿真出来。仿真库需要我们用vivado编译出来,怎么去编译仿真库,大家如果不知道的话可以搜一下,教程还是挺多的。
第二部分:
检查当前文件夹下有没有名字为work的文件夹,如果没有就创建一个work文件夹。
第三部分:
将逻辑库work和我们刚创建的文件夹work建立映射,联系起来。具体可以看前面的vmap命令介绍。
第四、五部分:
这两部分是对我们用到的IP核相关文件进行编译,我的这个工程用了FIFO IP核和GT IP核,所以需要对相关的文件进行编译,那具体需要编译那些文件呢?
我们可以在电脑上找到存储我们工程的文件夹,在文件夹里有个ip_user_files的文件夹,里面有个sim_scripts的文件夹,再打开找到里面用到的IP文件夹,里面找到对应的仿真工具文件夹,打开里面的compile.do文件,里面编译了哪些文件我们照抄过来就行了,然后把编译文件的相对路径改一下,改成我们当前文件能够找到的路径就行了。
这几条语句里有用到反斜杠\,反斜杠的意思就是这条命令没写完,下一行接着写,但是切记反斜杠后面不能有空格或任何字符,不然下一行就会被看作是另外一条命令了,从而引起报错什么的。
如果在我们的工程文件夹下没有找到compile.do文件,那就把对应IP核的示例工程打开,跑一跑示例工程的仿真,去示例工程的路径文件夹找compile.do文件就可以了。
第六部分:
编译我们的工程文件,其中*为通配符,指编译该文件夹下的所有.v文件。
第七部分:
编译tb仿真文件。
第八部分:
编译glbl.v文件,这个文件在compile.do文件里也有说明要编译。
第九部分:
对我们的顶层文件进行仿真,在界面上操作就是对tb文件执行simulate。
这里有几个-L命令,后面跟了不同的文件夹,就是把我们的库文件和我们编译完成的工程文件链接起来,也就是仿真需要用到这些文件夹下的内容,把路径给它指明,除了我们存放编译工程文件的work文件夹我们还需要链接哪些库文件呢?这里跟第四、五部分步骤一样找到elaborate.do文件,里面链接了哪些库,我们对应链接哪些库就行了,把路径改为我们当前文件的相对路径就行了。
如果有些库文件编译不全或者有些库没有链接到的话在运行时就会围绕着IP核报错,说找不到这文件那文件之类的,类似于下面这种:

语句最后的work.top_tb work.glbl指仿真work文件夹下的top_tb和glbl文件,这个glbl文件是我复制到tb文件的同一文件夹下的,原本跟elaborate.do文件在同一文件夹。按理说只仿真tb文件就行了,为什么还要仿真这个glbl文件呢?因为不仿真的话运行时就会出现下面这种报错:

就是需要将glbl也作为顶层的仿真模块,跟我们的tb文件一样通过vsim命令启动仿真。在elaborate.do文件里也对其进行了仿真。
第十部分:
记录所有的信号,运行这个命令后即使在仿真前没有把信号加入wave窗口,仿真完成后把想观察的信号直接拖入wave窗口就可以查看波形,比较方便。
第十一部分:
运行仿真,这个时候仿真就开始运行了,运行多久我们可以自己掌控,在界面点停止就行。还有一种方法就是把命令写为run 1ms,意思就是运行1ms后就停止,时间自己定,写多少运行多久。
更多推荐




所有评论(0)