引言
有两种方法可以使用 Modelsim 对 Vivado 工程进行仿真,即级联仿真和独立仿真。
级联仿真就是通过设置使 Vivado 调出 Modelsim 仿真界面并启动仿真,这种方法的好处是当使用 IP 时不用自己添加 Xilinx 的 IP 库;缺点是仿真效率极低,每次修改代码后需要综合,然后在 Vivado 中调出 Modelsim 进行仿真,并且考虑到 Vivado 的优化问题,其综合速度远没有 Modelsim 编译快。
独立仿真是在 Modelsim 中建立工程,摆脱 Vivado 速度慢的困扰,这种方法的优点是完全使用 Modelsim 操作,速度很快;缺点是需要添加各种文件和工作区,非常复杂,一不小心就会报错。
所以我们可以采取一种更方便又迅速的方法来让 Modelsim 能够独立仿真 Vivado 工程而又不会产生上面的困扰。
软件版本:Vivado 2019.2
Modelsim 2019.2
Pycharm 2020.3.3(Python 3.7)
参考手册:UG835(Vivado Design Suite Tcl Command Reference Guide)
一、级联仿真过程分析
我们先来看一下使用 Vivado 级联 Modelsim 仿真的过程中都会发生些什么。
首先在Vivado 的 Setting->Simulation 中设置 Xilinx 编译库的路径。如果还没有编译库文件,请看 芯王国写的 https://blog.csdn.net/weixin_40377195/article/details/89038414 这篇文章。
然后在 Setting->3rd Party Simulators 中设置 Modelsim 的启动路径和前面的编译库路径。
设置完成后点击左侧的 Run Simulation->Run Behavioral Simulation 启动 Modelsim 仿真。启动完成后回到 Vivado 中,查看下方的 Tcl Console ,可以看到这样一条描述信息:“Command:launch_simulation” 这说明当 Vivado 调用 Modelsim 时使用了 launch_simulation 这个 Tcl 命令。
查阅 UG835 手册可以发现存在 launch_simulation 这个命令。
跳转到定义后可以发现,此命令使用 -mode 选项来选择仿真类型,我们进行的是行为级仿真,所以使用 behavioral 。因为我们之前是点击 Run simulation 而直接进入仿真,如果想要让仿真更快更方便就不能让 Vivado 直接启动仿真,所以使用 -scripts_only 选项来指定 Vivado 只生成相关仿真脚本,而不启动仿真。
由上面的分析可知, 最后在 Vivado 的 Tcl 控制台输入的命令应该是 “launch_simulation -mode behavioral -scripts_only”。但这个命令太长了,不容易记住也不容易输入,故把这条命令写到一个 tcl 文件中再在 Vivado 控制台执行。
建立一个名为 sim.tcl 的文件,并在文件中输入:
launch_simulation -mode behavioral -scripts_only
然后将 sim.tcl 文件放在工程的根目录下(和.xpr文件一个目录),在 Vivado 控制台输入命令 source sim.tcl 即可将相关仿真脚本导入工程目录下:
仿真相关的脚本文件夹路径为:xxxxx\xxxxx.sim\sim_1\behav\modelsim (xxxxx为自己起的工程名)。目录结构如下图所示,包含了两个批处理(.bat)文件和三个 Tcl 文件(.do)
由 source sim.tcl 命令生成的批处理文件 simulate.bat 中的内容如下:
@echo off
REM ****************************************************************************
REM Vivado (TM) v2019.2 (64-bit)
REM
REM Filename : simulate.bat
REM Simulator : Mentor Graphics ModelSim Simulator
REM Description : Script for simulating the design by launching the simulator
REM
REM Generated by Vivado on Wed Feb 10 19:45:01 +0800 2021
REM SW Build 2708876 on Wed Nov 6 21:40:23 MST 2019
REM
REM Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
REM
REM usage: simulate.bat
REM
REM ****************************************************************************
set bin_path=D:\\modeltech64_2019.2\\win64
call %bin_path%/vsim -c -do "do {pll_test_tb_simulate.do}" -l simulate.log
if "%errorlevel%"=="1" goto END
if "%errorlevel%"=="0" goto SUCCESS
:END
exit 1
:SUCCESS
exit 0
而由 Vivado 启动仿真按钮生成的 simulate.bat 文件中内容则如下:
@echo off
REM ****************************************************************************
REM Vivado (TM) v2019.2 (64-bit)
REM
REM Filename : simulate.bat
REM Simulator : Mentor Graphics ModelSim Simulator
REM Description : Script for simulating the design by launching the simulator
REM
REM Generated by Vivado on Wed Feb 10 19:43:53 +0800 2021
REM SW Build 2708876 on Wed Nov 6 21:40:23 MST 2019
REM
REM Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
REM
REM usage: simulate.bat
REM
REM ****************************************************************************
set bin_path=D:\\modeltech64_2019.2\\win64
call %bin_path%/vsim -do "do {pll_test_tb_simulate.do}" -l simulate.log
if "%errorlevel%"=="1" goto END
if "%errorlevel%"=="0" goto SUCCESS
:END
exit 1
:SUCCESS
exit 0
由上面两个 simulate.bat 文件的对比可见,区别在于 由 source sim.tcl 命令生成的 simulate.bat 中多了一个 -c 选项 。查询 Modelsim 手册可知, -c 选项是以命令行模式执行 vsim 命令,而不会打开软件,所以需要将 -c 选项删除。
从 simulate.bat 的内容中可以看出,此脚本启动了 Modelsim 后执行了 xxxxx_simulate.do 脚本,我们打开 xxxxx_simulate.do 内容如下。可见 xxxxx_simulate.do 设置了仿真启动选项、启动仿真器、加入波形文件 xxxxx_wave.do 等操作。我们可以在工程的根目录下创建一个自定义波形文件 wave.do 来记录想要查看的波形和显示格式,然后把它覆写到 xxxxx_wave.do 中,这样可以避免当仿真文件夹更新时自定义波形文件丢失。
其中最后一句的 quit -force 会导致执行完do文件后退出程序,所以需要删除它。前一句 run 1000ns 是指定仿真时长,因为我们对每个工程的仿真时长需求都不一定一致,所以不需要提前指定仿真时长,故删除它。由于我们常常在仿真启动后需要查看某些没被加入到波形列表中的波形,导致加入这些波形后没有被提前记录,所以需要加入命令 log -r ./* ,让仿真器记录全部波形(*为通配符,指代全部信号名)。
######################################################################
#
# File name : pll_test_tb_simulate.do
# Created on: Wed Feb 10 19:45:01 +0800 2021
#
# Auto generated by Vivado for 'behavioral' simulation
#
######################################################################
vsim -voptargs="+acc" -L xil_defaultlib -L unisims_ver -L unimacro_ver -L secureip -L xpm -lib xil_defaultlib xil_defaultlib.pll_test_tb xil_defaultlib.glbl
set NumericStdNoWarnings 1
set StdArithNoWarnings 1
do {pll_test_tb_wave.do}
view wave
view structure
view signals
do {pll_test_tb.udo}
run 1000ns
quit -force
但有一个问题,xxxxx_simulate.do 文件并没有编译源文件。在目录中我们还可以发现一个叫做 compile.bat 的文件,从名字看应该是和编译相关的,内容如下。可见这个 compile.bat 打开了 Modelsim 并执行了 xxxxx_compile.do 文件,当然,和 simulate.bat 一样,vsim 命令中需要删除 -c 选项。
@echo off
REM ****************************************************************************
REM Vivado (TM) v2019.2 (64-bit)
REM
REM Filename : compile.bat
REM Simulator : Mentor Graphics ModelSim Simulator
REM Description : Script for compiling the simulation design source files
REM
REM Generated by Vivado on Wed Feb 10 19:45:01 +0800 2021
REM SW Build 2708876 on Wed Nov 6 21:40:23 MST 2019
REM
REM Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
REM
REM usage: compile.bat
REM
REM ****************************************************************************
set bin_path=D:\\modeltech64_2019.2\\win64
call %bin_path%/vsim -c -do "do {pll_test_tb_compile.do}" -l compile.log
if "%errorlevel%"=="1" goto END
if "%errorlevel%"=="0" goto SUCCESS
:END
exit 1
:SUCCESS
exit 0
xxxxx_compile.do 文件内容如下所示。可见此脚本建立了工作区 work、msim 和 xil_defaultlib ,编译了源文件和IP核文件。同 xxxxx_simulate.do 文件相同,需要删除 quite -force 命令,同时为了编译结束后可以直接启动仿真器,需要在 xxxxx_compile.do 文件中调用 xxxxx_simulate.do 文件,故在本文件尾部添加命令 “do xxxxx_simulate.do” 。
######################################################################
#
# File name : pll_test_tb_compile.do
# Created on: Wed Feb 10 19:45:01 +0800 2021
#
# Auto generated by Vivado for 'behavioral' simulation
#
######################################################################
vlib modelsim_lib/work
vlib modelsim_lib/msim
vlib modelsim_lib/msim/xil_defaultlib
vmap xil_defaultlib modelsim_lib/msim/xil_defaultlib
vlog -64 -incr -work xil_defaultlib "+incdir+../../../../pll_test.srcs/sources_1/ip/clk_wiz_0" \
"../../../../pll_test.srcs/sources_1/ip/clk_wiz_0/clk_wiz_0_clk_wiz.v" \
"../../../../pll_test.srcs/sources_1/ip/clk_wiz_0/clk_wiz_0.v" \
"../../../../pll_test.srcs/sources_1/new/pll_test.v" \
"../../../../pll_test.srcs/sim_1/new/pll_test_tb.v" \
# compile glbl module
vlog -work xil_defaultlib "glbl.v"
quit -force
总结一下,步骤是:
1、在 Vivado 的 Tcl Console 中输入 source sim.tcl ,导出仿真脚本文件。
2、删除 simulate.dat 和 compile.bat 中的 -c 选项。
3、删除 xxxxx_simulate.do 文件中的 quit -force 和 run 1000ns ,并且加入 log -r/* 。
4、删除 xxxxx_compile.do 文件中的 quit -force ,并且加入 do xxxxx_simulate.do 。
5、执行 compile.bat 脚本。
二、Python脚本编写
我们编写 Python 脚本,以便上面的步骤可以自动地执行。在此基础之上,还添加了 仿真脚本文件所在路径的自动识别 和 顶层tb文件名的自动识别 。
这样将 Python 脚本扔在 Vivado 工程根目录下就可以自动完成路径和名称的识别从而不用进行任何设置直接更改好相关文件并启动 Modelsim 和仿真器。
Python 代码如下:
import os
import pathlib
# 先在Vivado Tcl中执行 ” launch_simulation -mode behavioral -scripts_only “
# 或者
# 在工程路径下加入sim.tcl脚本,再在Vivado Tcl中执行 ” source sim.tcl “
########################################################################################################################
##-------------------- 默认设置,Vivado 仿真无特殊设置无需更改此处 --------------------##
# 仿真文件夹 默认后续路径
FollowPath = '/sim_1/behav/modelsim/'
# compile 批处理脚本名称
CompileBatName = 'compile.bat'
# simulate 批处理脚本名称
SimulateBatName = 'simulate.bat'
# 自定义信号文件名称
WaveFileName = 'wave.do'
########################################################################################################################
# 标志位,防止同一语句多次写入
sim_flag = True
comp_flag = True
# 仿真目录路径自动识别
usrpath = pathlib.Path() # 声明工程所在路径为根路径
search_xpr = usrpath.glob('*.sim') # 查找 sim 文件夹
for item in search_xpr:
SimName = str(item)
SimDirPath = SimName + FollowPath # 合成本工程仿真目录路径
# 待仿真tb文件名称自动识别
usrpath = pathlib.Path(SimDirPath) # 进入仿真脚本所在文件夹
search_xpr = usrpath.glob('*_compile.do') # 搜索以 _compile.do 结尾的文件绝对路径
for item in search_xpr:
TbName = str(item)
TbName = TbName.replace('\\','/') # Windows 路径格式转换为 Python 路径格式
TbFileName = TbName.replace(SimDirPath,'') # 掐头去尾,只保留待仿真tb文件名称
TbFileName = TbFileName.replace('_compile.do','')
# 删除 simulate.bat 脚本的-c选项
print('***** 正在修改文件 simulate.bat...... *****\n')
SimulateBatFile = open(SimDirPath + SimulateBatName, 'r')
SimulateBatFileAllLines = SimulateBatFile.readlines()
SimulateBatFile.close()
SimulateBatFile = open(SimDirPath + SimulateBatName, 'w')
for EachLine in SimulateBatFileAllLines:
if EachLine.find('%bin_path%/vsim -c -do') != -1:
EachLine = EachLine.replace('%bin_path%/vsim -c -do', '%bin_path%/vsim -do')
SimulateBatFile.writelines(EachLine)
SimulateBatFile.close()
print('***** simulate.bat ,修改完毕! *****\n')
# 删除 compile.bat 脚本的-c选项
print('***** 正在修改文件 compile.bat...... *****\n')
CompileBatFile = open(SimDirPath + CompileBatName, 'r')
CompileBatFileAllLines = CompileBatFile.readlines()
CompileBatFile.close()
CompileBatFile = open(SimDirPath + CompileBatName, 'w')
for EachLine in CompileBatFileAllLines:
if EachLine.find('%bin_path%/vsim -c -do') != -1:
EachLine = EachLine.replace('%bin_path%/vsim -c -do', '%bin_path%/vsim -do')
CompileBatFile.writelines(EachLine)
CompileBatFile.close()
print('***** compile.bat ,修改完毕! *****\n')
# 修改 simulate.do 脚本
print('***** 正在修改文件 simulate.do...... *****\n')
SimulateDoFile = open(SimDirPath + TbFileName +'_simulate.do', 'r')
SimulateDoFileAllLines = SimulateDoFile.readlines()
SimulateDoFile.close()
SimulateDoFile = open(SimDirPath + TbFileName +'_simulate.do', 'w')
for EachLine in SimulateDoFileAllLines:
if EachLine.find('run 1000ns') == -1 and EachLine.find('quit -force') == -1:
SimulateDoFile.writelines(EachLine)
if EachLine.find('log -r ./*') != -1:
sim_flag = False
if sim_flag == True:
SimulateDoFile.writelines('\nlog -r ./*\n')
SimulateDoFile.close()
print('***** simulate.do ,修改完毕! *****\n')
# 修改 compile.do 脚本
print('***** 正在修改文件 compile.do...... *****\n')
CompileDoFile = open(SimDirPath + TbFileName +'_compile.do', 'r')
CompileDoFileAllLines = CompileDoFile.readlines()
CompileDoFile.close()
CompileDoFile = open(SimDirPath + TbFileName +'_compile.do', 'w')
for EachLine in CompileDoFileAllLines:
if EachLine.find('quit -force') == -1:
CompileDoFile.writelines(EachLine)
if EachLine.find('do ' + TbFileName + '_simulate.do') != -1:
comp_flag = False
if comp_flag == True:
CompileDoFile.writelines('\ndo ' + TbFileName + '_simulate.do\n')
CompileDoFile.close()
print('***** compile.do ,修改完毕! *****\n')
# 将当前目录下自定义信号文件 wave.do 中的内容覆写到仿真目录下自动生成的波形文件中
print('***** 正在添加自定义波形文件...... *****\n')
SimWaveDoFile = open(WaveFileName,'r')
SimWaveDoFileAllLines = SimWaveDoFile.readlines()
SimWaveDoFile.close()
SimWaveDoFile = open(SimDirPath + TbFileName + '_wave.do','w')
SimWaveDoFile.writelines(SimWaveDoFileAllLines)
SimWaveDoFile.close()
print('***** 自定义波形文件添加完毕! *****\n')
# 执行 compile.bat 脚本,启动 Modelsim
print('***** 编译工程文件,启动 Modelsim!*****\n')
os.system('cd ' + SimDirPath + ' && ' + 'call ' + CompileBatName)
三、使用步骤
1、在 Vivado 的工程目录下放入 Python 脚本、 Tcl 脚本 sim.tcl 和自己定义好的波形文件 wave.do 。
2、在 Vivado 的 Tcl Console 中输入命令 source sim.tcl 。
3、 双击 Python 脚本,等待自动启动完成。
4、输入想仿真的时长,启动仿真
因为执行 Python 脚本会再次打开 Modelsim ,所以如果后续修改工程时没有增减IP核,只需要在 Modelsim 的控制台中执行命令 do xxxxx_compile.do 即可重新开始自动编译并仿真。如果后续增减了IP核,则重复上述四个步骤即可。