拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

QuestaSim仿真Vivado工程:Xilinx仿真库编译与挂载指南

QuestaSim仿真Vivado工程:Xilinx仿真库编译与挂载指南

直接说结论:QuestaSim本身不认Xilinx的仿真库,刚装好就拿来仿真Vivado工程,百分之百会报错。这不是软件没装好,而是你缺了一个很关键的环节——把Xilinx的库编译成QuestaSim能用的格式,并且在工程里正确挂载。这篇文章就专门讲这个事:怎么把Vivado/ISE那一套库(unisim、secureip、xpm等)在QuestaSim里编译好、配置好,以及功能仿真和时序仿真分别该怎么设置。

我翻了大量网上的提问,发现很多人卡在同一个地方:Vivado导出的仿真文件里带了glbl.v、unisim、xpm这些依赖,但QuestaSim不知道去哪找,于是一堆Unknown type、Cannot find module报错。所以本文会把“编译库—挂库—功能仿真—时序仿真—排查报错”这条线整个走一遍,适合刚转QuestaSim的FPGA工程师,也适合被库问题折磨了很久的老手。

1. 先搞明白:Xilinx库为什么不能直接拿去仿真

1.1 两大EDA工具的“库世界观”不一样

Vivado自带的仿真器是XSim,XSim编译出来的库格式和QuestaSim完全不同。Vivado安装目录下的data/verilog/src里存的是Xilinx提供的原始Verilog/VHDL源码(unisim、secureip、unimacro、xpm等),但QuestaSim不能直接把这些源码当成自己的“编译后库”来用。

这里我打个比方:Vivado的库像是一堆刚刚从菜市场买回来的新鲜蔬菜,XSim有自己的厨房,能直接加工;而QuestaSim是另一家餐厅,它不会直接进你的厨房做菜,它需要你先在自己的灶台上把这些蔬菜“过一遍火”——这个“过火”的过程就是编译。

所以核心思路就一句话:用QuestaSim自己的编译器(vlog/vcom)去编译Xilinx的库源码,生成QuestaSim的库格式,再告诉QuestaSim“以后这些库名字对应哪个文件夹”。这一步跑通了,后头功能仿真和时序仿真才会顺。

1.2 需要编译的库有哪些

Xilinx在Vivado里按用途把库分成了几块,各有各的用处:

  • unisim:仿真Xilinx原语(比如BUFG、IBUFDS、FDRE、SRL16等),大部分RTL仿真都绕不开它。
  • secureip:存放受保护的IP内核仿真模型,比如高速收发器、部分DSP、PCIe硬核等,这些模型以加密形式存在。
  • unimacro:一些Xilinx宏模块(CARRY4、MUXF7等的“拼装”封装),有些设计会直接例化这些宏。
  • xpm:Xilinx参数化宏,现在新的IP核非常依赖xpm库(比如FIFO、RAM、CDC、异步复位同步释放等)。xpm分xpm_cdc、xpm_memory、xpm_fifo等子库。
  • simprim:主要是时序仿真(后仿真)时要用的单元库,包含带延迟信息的原语模型。
  • glbl:严格来说不算独立库,而是一个glbl.v文件,里面是全局复位/时钟的虚拟驱动逻辑,时序仿真和很多原语仿真必须把它编译进去。

如果你用的还是老一点的ISE流程,那还有一个unisim_comp和simprim_comp的VHDL版本,思路一模一样,只是编译命令换成vcom。

1.3 消息里常见的“Cannot find unit”是什么意思

QuestaSim里出现** Error: (vcom-1136) Cannot find unit xxx或者vlog: Cannot find module xxx,本质就是编译器在当前的work库和映射库里翻了个遍,找不到那个顶层模块或单元。Xilinx的IP核在sim_1目录下生成的仿真文件,例化了一大堆unisim/xpm里的东西,这些东西不在work库里,你没有提前编译并映射这些库,QuestaSim当然一脸懵。

所以真正要解决的工程问题只有两个:库编译到哪里、仿真时怎么让QuestaSim找到这些库。

2. 编译Xilinx库的完整操作

2.1 准备工作:确认版本和文件路径

在动手编译之前,先确认三件事:

  1. Vivado安装路径:默认在C:\Xilinx\Vivado\2021.1,不同版本后头的版本号不同,注意替换。
  2. QuestaSim版本:建议使用10.7c以上或者2021.x之后的版本,否则对新版Vivado(如2022.2+)的xpm和secureip支持不友好。
  3. 操作系统位数:QuestaSim和Vivado尽量都用64位,不然仿真大工程时内存容易爆。

注意:版本太老的QuestaSim(比如10.2)编译新版Vivado的UNISIM会有大批语法报错,这不是你操作的问题,是工具版本的问题。如果遇见接二连三的语法错误,优先怀疑版本不匹配,而不是怀疑自己配置写错了。

2.2 手工编译方式:用Questasim的compile脚本

在QuestaSim的安装目录下,有一个专门用于编译Xilinx库的Tcl脚本,位置通常在这:

C:\questasim64_xxx\modelsim.ini C:\questasim64_xxx\tcllib\vendor\mentor\compile_xilinx_libs.tcl

这个脚本支持多个Xilinx版本,用法是在QuestaSim的命令窗口里执行:

vsim -c -do "source C:/questasim64_10.7c/tcllib/vendor/mentor/compile_xilinx_libs.tcl; quit"

但更常见的做法是直接调脚本的Tcl过程。比如:

compile_xilinx_libs -family vivado \ -version 2021.1 \ -src_dir C:/Xilinx/Vivado/2021.1/data \ -lib_dir C:/xilinx_sim_lib/2021.1

-family vivado指定是Vivado平台,-src_dir指向Vivado安装目录下的data文件夹,-lib_dir是你想把编译好的库输出到哪个目录。执行完之后,C:/xilinx_sim_lib/2021.1下面会生成unisim_ver、secureip、xpm等一堆文件夹,每个文件夹里都是QuestaSim格式的编译产物(_info、.dat等)。

如果你懒得折腾Tcl脚本,直接用QuestaSim的GUI菜单也行。在主界面菜单栏上打开Tools -> Compile Xilinx Simulation Library,它会弹个向导,让你选Vivado版本、库目录、输出目录,点完成后就开始批量编译。这个向导本质上就是在帮你调那个脚本,好处是不用手敲路径,缺点是自动化不够,换台机器还得重新点一遍。

2.3 关键参数选择:为什么有时要单独编译xpm

脚本默认会编译unisim和secureip,但xpm库有时候不会自动选上。很多网上的教程其实漏了这一步,导致仿真时一遇到新版Xilinx FIFO IP就报xpm_cdc模块找不到。如果你用到的IP核比较新,请务必在向导里勾上xpm,或者手动编译:

vlib xpm vlog -work xpm C:/Xilinx/Vivado/2021.1/data/ip/xpm/xpm_cdc/hdl/xpm_cdc.sv vlog -work xpm C:/Xilinx/Vivado/2021.1/data/ip/xpm/xpm_memory/hdl/xpm_memory.sv vlog -work xpm C:/Xilinx/Vivado/2021.1/data/ip/xpm/xpm_fifo/hdl/xpm_fifo.sv

乱不乱?不乱。其实就是把Xilinx的SystemVerilog源码一条条帮你在QuestaSim里编译一遍。如果脚本能自动全编最好,不能全编就手动补齐。

2.4 编译完成后必须做的事:配置modelsim.ini

库编译出来只是第一步,你的工程不会自动知道这些库在哪。需要把库路径写进modelsim.ini里。

先说一下modelsim.ini这个文件的作用。它是QuestaSim的全局配置文件,里面有一个[Library]区域块,格式是:

[Library] unisim_ver = C:/xilinx_sim_lib/2021.1/unisim_ver secureip = C:/xilinx_sim_lib/2021.1/secureip xpm = C:/xilinx_sim_lib/2021.1/xpm ...

你可以在QuestaSim里敲命令来写入映射:

vmap unisim_ver C:/xilinx_sim_lib/2021.1/unisim_ver vmap secureip C:/xilinx_sim_lib/2021.1/secureip vmap xpm C:/xilinx_sim_lib/2021.1/xpm

vmap不单是写文件,它还会建立逻辑库名和物理路径的映射关系。映射写好后,modelsim.ini里会多出这些条目,以后每次启动QuestaSim,它只要读到这个ini文件,就自动知道unisim_ver对应哪个文件夹。

提示:vmap命令对当前工程生效,其实是修改当前工作目录下的modelsim.ini。如果你在某个工作目录里敲这个命令,它会把映射写进那个目录的ini文件里。所以一定要搞清楚当前目录在哪,别到时候换了个目录又发现库全丢了。

3. 在工程里挂载Xilinx库并做功能仿真

3.1 搭一个最小仿真工程

我习惯用.do脚本把工程流程固定下来,这样每次重新拉代码、重新仿真都不用手点。一个最小脚本大概这样:

# compile_and_run.do vlib work vlib xil_defaultlib # 编译Xilinx基础库 vlog -work unisim_ver C:/xilinx_sim_lib/2021.1/unisim_ver/*.v vlog -work xpm C:/xilinx_sim_lib/2021.1/xpm/*.sv # 编译自己的源码 vlog -work xil_defaultlib ../rtl/fifo_wrapper.v vlog -work xil_defaultlib ../rtl/axis_fifo.v vlog -work xil_defaultlib ../sim/tb_fifo.v # 启动仿真 vsim -L unisim_ver -L xpm -L xil_defaultlib work.tb_fifo

这里有个细节很多人不太注意:vsim启动时加了一堆-L参数。-L的意思是允许QuestaSim在指定库里查找模块,因为仿真时testbench顶层模块里引用的FIFO IP并不是直接编译到work库里的,而是在xpm或unisim_ver库里已经编译好的单元。你不把库列出来,它搜不到。

3.2 把Vivado导出的仿真文件挪到QuestaSim

Vivado里打开一个IP核,Sources选项卡里有Simulation Sources,右键选Generate Output Products,然后在sim_1目录下会生成一个.f文件(File list),里面列了这个IP核仿真依赖的所有源文件路径。常见路径是这样的:

C:/project/project.srcs/sources_1/ip/fifo_gen_0/sim/fifo_gen_0.v C:/project/project.srcs/sources_1/ip/fifo_gen_0/sim/fifo_gen_0_sim_netlist.v

如果你不想自己手动拉一堆文件,可以直接用vlog -f参数把.f文件喂给QuestaSim:

vlog -f C:/project/project.srcs/sources_1/ip/fifo_gen_0/sim/fifo_gen_0.f

这是一条偷懒捷径,但有个前提:.f文件里的路径要和你本机的相对路径对得上。如果Vivado工程挪过位置,.f里的路径全是旧路径,得先在文本编辑器里清理一遍。

3.3 常见功能仿真流程

功能仿真不需要管延迟信息,只验证逻辑功能正确性。完整流程可以浓缩成四步,我直接把这四步写成一个run_sim.do脚本,方便以后一键跑:

# 清除之前的编译产物 if {[file exists work]} { vdel -all -lib work } vlib work vlib xil_defaultlib # 1. 编译Xilinx原语库,很多IP例化原语时要用 vlog -work unisim_ver C:/xilinx_sim_lib/2021.1/unisim_ver/unisim_comp.v vlog -work secureip C:/xilinx_sim_lib/2021.1/secureip/secureip_comp.v # 2. 编译glbl,时序仿真时代码里会例化它 vlog -work unisim_ver C:/Xilinx/Vivado/2021.1/data/verilog/src/glbl.v # 3. 编译设计代码和testbench vlog -work xil_defaultlib ../rtl/*.v vlog -work xil_defaultlib ../tb/tb_top.v # 4. 启动仿真,把库都挂上 vsim -L unisim_ver -L secureip -L xil_defaultlib -L xpm \ -t 1ps \ work.tb_top \ work.glbl # 添加信号到波形 add wave -r /* run -all

这个脚本里的work.glbl不能丢。很多人后仿真报错,就是因为忘了把glbl模块一并加载进去。glbl提供全局置位/复位信号(glbl.gsr、glbl.gts),amba总线和不少原语仿真要靠它来驱动统一的全局信号,少了它,仿真行为会变得很奇怪,甚至直接退出。

3.4 GUI方式:一步步点出来的灵活配置

如果你不太熟悉命令行,也可以全在GUI里操作。流程是这样:

  • 先选好工作目录,启动QuestaSim。
  • File -> New -> Project,填写工程名和目录。
  • Add Existing File把RTL文件和testbench加进去。
  • 右键工程里的文件,选Compile All,或者直接Ctrl+Shift+L。
  • 打开Library面板,如果之前vmap做得好,能看到unisim_ver、xpm这些逻辑库名称。
  • 在命令行里输入vsim -L unisim_ver -L xpm work.tb_top回车,启动仿真。
  • 打开Objects窗口,选中信号拖进Wave窗口,再点Run -all。

GUI的坑在于,很多人以为库只要在Library面板里“看得到”就完事了,结果vsim一启动还是报找不到模块。原因就是少了-L参数,QuestaSim默认只认work库,你在Library面板里看到的库只是“挂载”了,不代表仿真器自动搜索。切记:vsim启动时得显式列出所有需要搜索的库。

4. 时序仿真(后仿真)里库的设置细节

4.1 后仿真和功能仿真的差别

后仿真(时序仿真)比功能仿真严苛得多,因为设计里已经加入了门级延迟、布线延迟、单元延迟等信息,仿真时要把这些延迟背靠背地“标定”到仿真模型上,这就是SDF反标。

Vivado生成的SDF文件一般在工程目录里长这样:

C:/project/project.runs/impl_1/top_design.sdf

后仿真第一步,把综合后或实现后的网表文件编译进来。Vivado导出的网表是top_design.v,里面例化了大量的基本门和Xilinx原语,这些原语几乎都不在work库里,全靠simprim或unisim_ver库来提供模型。

所以后仿真时库的挂载有点不一样,通常要同时挂这三个:

vsim -L simprim_ver -L unisim_ver -L secureip -L xil_defaultlib \ -sdftyp /tb_top/dut=../impl_1/top_design.sdf \ work.tb_top \ work.glbl

-sdftyp /tb_top/dut=../impl_1/top_design.sdf的意思是:把SDF文件里的延迟信息反标到路径/tb_top/dut这个实例上。/tb_top/dut是testbench里被测试设计模块的层次路径,必须写成绝对层次路径,写错就不会反标成功。

4.2 SDF反标失败时怎么检查

反标不成功时QuestaSim通常会在transcript窗口打印类似这样的警告:

** Warning: (vsim-SDF-324) Failed to find timing annotation for cell type: LUT6 ** Warning: (vsim-SDF-325) Failed to find timing annotation for cell type: FDRE

看到这种警告,先别慌,这是常事,很多情况下是因为有些单元没有时序模型可标,不影响功能正确性,只是延迟信息不完整。但如果整片全是这个警告,那多半是simprim_ver没挂对,或者SDF路径写错了。

排查方法很简单,在QuestaSim的命令行里执行:

check -sdf

它会列出所有SDF文件的加载状态,哪些反标成功,哪些失败。再看-sdftyp的层次路径有没有打错,用find /tb_top -dut之类的指令确认一下例化名字是不是叫dut。

4.3 为什么后仿真要单独编译simprim

功能仿真用的unisim_ver库,库里的模型是不带延迟的,主要用于验证逻辑功能。但后仿真希望看到“最接近真实硬件”的表现,延时、竞争、毛刺都应该出现,所以Xilinx单独维护了一个simprim_ver库,里面全是带延迟行为描述的模型。

所以如果你后仿真时只挂了unisim没挂simprim,最常见的现象是:仿真结果看起来和功能仿真一模一样,根本没有延迟效果。那不是你设置成功,而是时序信息压根没被用上。标准做法是专门编译一次simprim:

vlib simprim_ver vlog -work simprim_ver C:/Xilinx/Vivado/2021.1/data/verilog/src/simprims/*.v

如果Vivado没有专门的simprims目录(部分新版本把它挪到了别的位置),可以在data/verilog/src下面搜一下simprims相关文件夹,找到路径即可。VHDL工程则需要编译simprim的VHDL库。

注意:后仿真的库挂载顺序尽量不要乱。业界惯例是先simprim_ver,再unisim_ver,再secureip,最后xil_defaultlib。顺序不对有时候也能跑,但出问题排查起来很头疼,按标准来最省心。

5. 常见报错和疑难杂症排查速查表

我把这几年自己和同事踩过的坑整理成了下面的速查表,每一条都是真实遇到过的问题。真遇到类似情况,建议照着表顺序排查,很多问题其实都在前三条。

报错信息原因解决方法
Cannot find module glbl没编译glbl.v,或仿真是没加载work.glbl编译Vivado安装目录下的glbl.v,vsim时加上work.glbl
Cannot find unit xpm_cdc_sync_rst没编译xpm库编译xpm源文件并在vsim时-L xpm
Failed to find timing annotation for cell typeSDF反标失败或simprim库没挂全检查-sdftyp路径,确保simprim_ver库已挂载
Error: (vlog-1902) Option -L is not a legal optionvlog命令不支持-L,-L只用于vsim库搜索路径放在vsim阶段,编译阶段用-work指定目标库
# ** Fatal: (vsim-3445) Invalid library mappingmodelsim.ini里的库路径变了或失效重新执行vmap,确认路径存在
vsim: cannot open "unisim_ver" as an alternative library逻辑库名映射丢了用vmap unisim_ver 物理路径重设
** Error: Could not find compiled library xpm没在modelsim.ini中映射xpm用vmap或在GUI里Library -> Add Existing添加
** Warning: (vsim-3736) Module not found in library某个例化的原语不在当前库搜索范围检查IP依赖的库,补充-L参数
SDF file not foundSDF路径写错,或相对路径不对用绝对路径重写-sdftyp
仿真结果全是X态但功能仿真正常后仿真的glbl或全局复位没正确驱动确认glbl已加载,检查testbench复位时序
编译IP核文件报大量语法错误QuestoSim版本与Vivado版本不兼容升级QuestaSim或换低一点的Vivado版本

这类表格放在手边,出现问题对照着看,比反复百度强多了。

6. 一个自动化的库管理习惯(随手就能用)

最后分享一个我自己的小习惯。因为Xilinx库编译一次时间不短,快则十几分钟,慢则半小时以上,换台电脑又要重来,所以我一般会在自己常用的目录下放一个setup_libs.do,内容就是编译库和映射的全套脚本。换电脑后执行一次,后续所有工程都复用这套编译产物。

# setup_libs.do set VIVADO_ROOT "C:/Xilinx/Vivado/2021.1" set LIB_OUT "C:/xilinx_sim_lib" # 建库 file mkdir $LIB_OUT vlib unisim_ver vlib secureip vlib xpm vlib simprim_ver # 编译 vlog -work unisim_ver $VIVADO_ROOT/data/verilog/src/unisims/*.v vlog -work simprim_ver $VIVADO_ROOT/data/verilog/src/simprims/*.v vlog -work secureip $VIVADO_ROOT/data/verilog/src/secureip/*.v vlog -work xpm $VIVADO_ROOT/data/ip/xpm/xpm_cdc/hdl/xpm_cdc.sv vlog -work xpm $VIVADO_ROOT/data/ip/xpm/xpm_memory/hdl/xpm_memory.sv # 映射到当前model sim.ini vmap unisim_ver $LIB_OUT/unisim_ver vmap secureip $LIB_OUT/secureip vmap xpm $LIB_OUT/xpm vmap simprim_ver $LIB_OUT/simprim_ver # 编译glbl vlog -work work $VIVADO_ROOT/data/verilog/src/glbl.v quit -f

执行方法很简单,在QuestaSim命令窗口里敲:

do setup_libs.do

之后创建新工程时直接vmap一下就能引用。我现在维护的绝大多数工程,仿真脚本也不过是把这个setup_libs.do跑一遍,再跑自己的run_sim.do,全程无脑,省掉了大量重复劳动。

我自己实际操作中踩过最大的一个坑,是贪方便直接拿Vivado生成的IP核.f文件一股脑全编译,结果有些文件是XSim专用的,有些是综合用的,混在一起就会冒出奇奇怪怪的语法报错。后来学乖了:只拿simulation目录下的文件和.f,综合目录的文件一概不碰。另一个经验是,QuestaSim版本升级后最好重新编译一遍Xilinx库,别偷懒沿用旧库,因为不同版本对SystemVerilog语法的支持程度不太一样,老库在新工具里偶尔会出一些莫名其妙的时序反标警告。把这些前置工作做扎实,后头的仿真就是水到渠成的事。

返回列表