ARTICLE DETAIL

资讯详情

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

VCS跑Vivado FIFO IP仿真:库编译、XPM与testbench全流程

VCS跑Vivado FIFO IP仿真:库编译、XPM与testbench全流程 1. 为什么非要用VCS跑Vivado的FIFO IP绕不开的库编译问题先说个场景你应该也遇到过在Vivado里生成了一个FIFO IP用自带的xsim跑仿真代码一多、数据一长波形刷新就开始卡跑个大位宽异步FIFO的满空翻转测试动不动就是几分钟甚至更久。如果只是验证一个FIFO还好一旦你打算在同一个验证环境里挂UVM、做覆盖率、或者把FPGA里的模块复用到ASIC流程里xsim基本就撑不住了。这时候很多人第一反应就是换VCS。VCS跑Xilinx的IP核核心痛点从来不是VCS本身而是Xilinx的仿真库必须先针对VCS完成pre-compile。FIFO这种看似不起眼的IP仿真模型底层依赖的是unisims、secureip、xpm这几套库。你没有提前把这些库编译成VCS能用的形式VCS一跑就直接报Unknown module或者一堆莫名其妙的加密模块错误然后你就会陷入明明文件都加了为什么还是不行的循环。这篇文章就把我实际踩过一遍的完整流程写出来从pre-compile libraries配置到FIFO IP生成到testbench设计和VCS编译运行再到最常见的几个报错怎么定位全程按可复现的标准来写。适合刚接触VCSFPGA仿真、或者已经在用但一直被库问题卡住的人参考。2. 环境准备版本匹配与两个关键环境变量动手之前先确认版本这是很多人忽略的第一关。VCS和Vivado之间没有严格的相互认证关系但版本跨太大一定会出问题。我这里用的是Vivado 2020.2 VCS 2018.06这个组合属于比较经典、社区验证过的搭配。如果你用的是Vivado 2022.2以上建议VCS至少2020.12起步太老的VCS解析不了新版IP生成的SystemVerilog语法。安装路径建议规整后面所有脚本都依赖这两个路径export XILINX_VIVADO/tools/Xilinx/Vivado/2020.2 export VCS_HOME/tools/synopsys/vcs/O-2018.06-SP2 export PATH$VCS_HOME/bin:$XILINX_VIVADO/bin:$PATH export LM_LICENSE_FILE27000license-server环境变量配好之后先各跑一条命令确认工具能起来vcs -ID vivado -version这两条命令输出的版本信息建议截个图或者记下来。后面一旦遇到诡异的仿真行为第一件事就是回来看版本匹配关系。然后是整个流程最关键的一步搞清楚Xilinx仿真库到底由哪几部分组成。用VCS跑FIFO IP仿真你至少需要以下四类库库名作用典型路径unisims通用原语仿真模型几乎所有IP的底层都依赖$XILINX_VIVADO/data/verilog/src/unisimsunifastunisims的快速仿真版本行为级建模速度更快$XILINX_VIVADO/data/verilog/src/unifastsecureip加密IP模型高速收发器、部分复杂IP会引用$XILINX_VIVADO/data/verilog/src/secureipxpmXilinx Parameterized Macro新版IP大量使用$XILINX_VIVADO/data/ip/xpmFIFO IP在Vivado 2019之后生成的仿真模型几乎全都改成了XPM实现所以xpm库编译不全会是最高频的报错来源。这一点先记在心里后面排障部分我还会专门讲。3. pre-compile libraries实操一条龙脚本与手动编译两条路pre-compile libraries的配置有两条路一条是Vivado自带的compile_simlib省心另一条是手动用VCS编译源库可控。我的建议是两条都掌握因为compile_simlib偶尔会翻车翻车的时候你只能靠手动编译来救命。3.1 路径一compile_simlib一键编译GUI方式我就不多说了Tools - Compile Simulation Libraries勾选VCS、选择器件族、指定输出目录点编译就行。但命令行方式更适合脚本化和反复使用我实际用的Tcl脚本长这样# compile_vcs_lib.tcl compile_simlib \ -tool vcs \ -family virtex7 \ -language all \ -library all \ -dir /home/user/work/vcs_lib然后批量执行vivado -mode batch -source compile_vcs_lib.tcl这里有几个值得注意的点。-family不用选太多按你项目实际用的FPGA型号所属家族来选就行全选会拉长编译时间。我习惯用virtex7因为大部分项目的器件族都兼容。-language all表示同时编译Verilog和VHDL如果你确定只用Verilog改成-language verilog速度会快不少。编译完成后输出目录的结构大概是这样的vcs_lib/ ├── unisims_ver/ ├── unifast_ver/ ├── secureip/ └── xpm/每个子目录里是VCS可以直接引用的库文件。注意这个输出结构在不同Vivado版本里略有差异有的版本会直接生成一个总的.v文件有的会拆成多个子库而且secureip目录在部分版本里会编译出加密的二进制库。不用慌记住一个原则最终你要的是一组VCS能通过-v或-y参数引用的库文件。3.2 路径二手动VCS编译源库compile_simlib版本不兼容或者编译到一半报错的时候手动编译是最后的兜底方案。其实原理很简单就是把Vivado自带的源库用VCS编译成可引用的形式。手动编译unisims和unifastcd /home/user/work/vcs_lib vcs -sverilog v2k -full64 \ -y $XILINX_VIVADO/data/verilog/src/unisims libext.v \ -y $XILINX_VIVADO/data/verilog/src/unifast libext.v \ -timescale1ns/1ps -o unisim_lib_simv这条命令实际上是利用VCS的-y目录扫描机制把unisims目录下所有的.v文件都拉进来编译。编译完会生成一个unisim_lib_simv可执行文件这个文件本身没用真正有用的是编译过程中生成的库文件。这种方式比较粗暴但至少能让你确认源库本身没有语法问题。更干净的做法是直接编译XPM的SystemVerilog源文件vcs -sverilog -full64 \ $XILINX_VIVADO/data/ip/xpm/xpm_cdc/hdl/xpm_cdc.sv \ $XILINX_VIVADO/data/ip/xpm/xpm_fifo/hdl/xpm_fifo.sv \ $XILINX_VIVADO/data/ip/xpm/xpm_memory/hdl/xpm_memory.sv \ -timescale1ns/1ps -o xpm_lib_simv注意xpm库是SystemVerilog写的必须加-sverilog这是它的硬性要求。手动编译的价值在于当compile_simlib某个子库失败时你能够精确定位是哪一套源库出了问题然后单独重新编译那一套而不是整个推倒重来。3.3 验证库编译结果库编完先别急着写testbench花两分钟验证一下。最简单的验证方法是找一个简单原语写个空实例来编译// smoke_test.v module smoke_test; wire [3:0] dout; LUT4 #(.INIT(16hAAAA)) u_lut ( .I0(1b0), .I1(1b0), .I2(1b0), .I3(1b0), .O(dout[0]) ); endmodule然后执行vcs -sverilog -full64 \ -y /home/user/work/vcs_lib/unisims_ver libext.v \ smoke_test.v -o smoke_simv如果这一步能通过说明你的-y路径和libext设置没问题pre-compile libraries这块的基座就算打好了。4. FIFO IP生成与仿真文件清单VCS真正需要的几个文件库编译完成接下来回到Vivado工程里把FIFO IP生成好。这里有个常见的认知误区以为VCS需要的是Vivado导出的仿真网表文件就算完事了其实FIFO的仿真模型不止一个文件漏了任何一个都会在VCS阶段报错。4.1 IP配置同步还是异步IP Catalog里搜FIFO会看到FIFO Generator和FIFO Generator (XPM)两个入口。老版本强烈建议选XPM版本因为它的仿真模型是纯SystemVerilog调试方便老版FIFO Generator的仿真模型层级深、底层依赖老式unisims组件编译容易出幺蛾子。配置的时候注意几个点接口类型选Standard FIFO还是AXI4-Stream这会直接影响testbench的读写时序读模式建议选First Word Fall Through调试时不用手动等valid拉高省很多事异步FIFO务必勾上wr_rst_busy和rd_rst_busy输出否则复位释放后的首拍行为很难把控。4.2 Output Products里的sim目录长什么样IP配置完成右键IP - Generate Output Products把Simulation和Synthesis都勾上。生成完成后打开/工程目录/工程名.gen/sources_1/ip/fifo_ip/你会看到这样的结构fifo_ip/ ├── fifo_ip.xci ├── fifo_ip.xdc ├── fifo_ip.v # 顶层wrapper ├── synth/ └── sim/ ├── fifo_ip_sim_netlist.v # 仿真模型 └── fifo_ip.vhdVCS编译的时候核心文件是这个fifo_ip_sim_netlist.v但你直接拿它去VCS编十有八九会报Unknown module xpm_fifo_async。原因我在开头说过这个仿真模型是XPM例化的XPM的底层实现不在这个文件里而在xpm库里。4.3 glbl.v为什么每次都漏还有一个每次都会被漏掉的文件glbl.v。它在$XILINX_VIVADO/data/verilog/src/glbl.v是一个描述FPGA全局信号GSR、GTS、GCLK等的模块。几乎所有采用unisims模型的IP在仿真时都需要这个模块存在否则你会看到类似GSR信号未定义或者行为仿真空翻的怪问题。我的固定做法是把这个文件复制到项目仿真目录下并且保证它和testbench在同一编译单元里cp $XILINX_VIVADO/data/verilog/src/glbl.v ./sim/glbl.v注意glbl.v本身不是直接被例化的它是靠VCS编译时的模块级联自动带进去的。你必须把它放在VCS的编译文件列表里不是放进IP目录就完事了。5. testbench设计与VCS完整编译运行流程库和IP都准备好了到了真正跑仿真的时候。这一节我把testbench的关键点和VCS的三步流程一起讲因为很多人在这一步栽跟头不是因为不会写testbench而是不清楚VCS编译和运行之间的边界。5.1 testbench的关键点写testbench之前先打开fifo_ip.v看一遍顶层端口名因为不同配置生成的端口名差异很大不要凭记忆写。以我的标准FIFO配置为例端口大概是clk、srst、din、wr_en、rd_en、dout、full、empty、valid、wr_rst_busy、rd_rst_busy。一个能验证基本读写功能的testbench骨架timescale 1ns/1ps module tb_fifo; localparam DATA_WIDTH 32; localparam DEPTH 16; logic clk; logic srst; logic [DATA_WIDTH-1:0] din; logic wr_en; logic rd_en; logic [DATA_WIDTH-1:0] dout; logic full; logic empty; logic valid; fifo_ip dut ( .clk (clk), .srst (srst), .din (din), .wr_en (wr_en), .rd_en (rd_en), .dout (dout), .full (full), .empty (empty), .valid (valid) ); always #5 clk ~clk; initial begin clk 0; srst 1; wr_en 0; rd_en 0; din 0; repeat (10) (posedge clk); srst 0; // 写5个数据 for (int i 0; i 5; i) begin (posedge clk); wr_en 1; din i 1; end wr_en 0; // 等数据有效再读5个 wait (!empty); for (int i 0; i 5; i) begin (posedge clk); rd_en 1; $display(read data %0d, dout); end rd_en 0; #100; $display(TEST PASSED); $finish; end endmodule几点经验srst是高有效复位时间至少给够10个时钟周期否则FIFO内部指针和flag不一定能正确初始化对于异步FIFO写侧和读侧各需要一个时钟testbench里要分别产生两个频率的时钟如果用了First Word Fall Through模式读侧等valid拉高后再rd_en置1时序更稳。5.2 compile、elaboration、simv三步走VCS的编译分为compile和elaboration两个阶段但通常一条命令把两件事一起做了。我用的命令是这样vcs -sverilog -full64 -debug_accessall \ -timescale1ns/1ps \ -y /home/user/work/vcs_lib/unisims_ver libext.v \ -y /home/user/work/vcs_lib/unifast_ver libext.v \ -y /home/user/work/vcs_lib/secureip libext.v \ -y /home/user/work/vcs_lib/xpm libext.v libext.sv \ glbl.v \ tb_fifo.sv \ /path/to/工程.gen/sources_1/ip/fifo_ip/sim/fifo_ip_sim_netlist.v \ -o simv拆开解读一下每个参数-sverilog是因为XPM和testbench都用了SystemVerilog语法-full64以64位模式编译不用的话大设计内存不够-debug_accessall是为了能把全部信号dump进波形调试阶段必加等回归测试稳定后可以去掉以提升性能-timescale1ns/1ps保证testbench和IP模型的时延精度一致不加会导致部分时序断言行为异常。-y参数后面跟的是pre-compile库目录libext.v和libext.sv告诉VCS在这个目录里扫描哪些后缀的文件。这里必须两者都写因为xpm库里同时存在.v和.sv文件。5.3 波形生成与Verdi联调仿真跑起来之后你得能看到波形才能调FIFO的时序。如果用的是VCS自带的DVE在testbench里加initial begin $vcdpluson; end编译命令不变运行./simv后会在当前目录生成vcdplus.vpd用DVE打开即可。如果你像我一样日常用Verdi看波形那就用fsdb格式。testbench里改成initial begin $fsdbDumpfile(fifo.fsdb); $fsdbDumpvars(0, tb_fifo); end编译命令需要加-fsdb参数让VCS链接Verdi的PLI库vcs -sverilog -full64 -debug_accessall -fsdb \ -y /home/user/work/vcs_lib/unisims_ver libext.v \ ...运行结束后直接verdi -f fifo.fsdb就能看到完整的波形树调试体验比DVE舒服很多。运行simv的时候我习惯加上自动结束的时间控制./simv vcsfinish20000意思是在20000个时间单位后强制结束仿真避免testbench里忘了$finish导致仿真挂死。这是一个能救命的小习惯。6. 高频报错排障从错误信息反推配置问题无论配置多仔细VCS第一次跑Xilinx IP的时候总会遇到几个高频报错。我把最常见的四类整理出来每一类都按根因-排查链路-解决的格式写方便你照着排查。6.1 Unknown module xpm_fifo_async / xpm_cdc_*这是最高频的报错没有之一。错误信息一般是Error-[UKNOWN-MODULE] Unknown module xpm_fifo_async instance ... in unit fifo_ip_sim_netlist根因就一个xpm库没有正确编译进VCS。可能是pre-compile时xpm没编也可能是编译命令里没有包含xpm库的-y路径。排查链路是这样先确认$XILINX_VIVADO/data/ip/xpm目录存在且包含xpm_fifo子目录再确认你的compile_simlib输出目录里有没有xpm子目录最后确认vcs命令里的-y参数确实指向了xpm库目录而且libext.sv没丢。如果xpm的源文件直接被编进去了却仍然报错检查是否用了v2k而不是-sverilog——XPM是SystemVerilog的v2k模式下它不会被正确解析。6.2 glbl与GSR相关的怪异报错这类报错更隐蔽常见的是Error-[XMR-XMOD] Cross-module reference found to a variable GSR或者仿真跑起来FIFO复位释放后数据乱跳怎么看都不是testbench的问题。这时候大概率就是glbl.v没编进去。gsr只是全局复位信号glbl模块在仿真器里负责给所有原语的GSR信号提供默认驱动。没有它原语内部的行为仿真就是未定义状态。解决方式就是我前面说的把glbl.v加进编译文件列表放在所有其他文件之前。如果你加了还报错检查是否多个glbl例化冲突有些工程会从别的地方又引了一份glbl.v进来。6.3 secureip加密模型加载失败FIFO IP本身一般不需要secureip但老版FIFO Generator或者你在同一个仿真环境里还挂了其他复杂IP时就会遇到Error-[SFCB] Secure(foo) cell cannot be found or loadedsecureip目录里很多是加密源文件VCS对加密源的支持依赖正确的-y扫描和版本匹配。先确认secureip目录在这个Vivado版本里确实存在其次确认pre-compile输出的secureip子目录里有内容。如果编译时一直卡在secureip我的建议是暂时不用secureip把FIFO换成XPM版本XPM没有secureip依赖能绕开大量隐藏问题。6.4 GCC/C编译器版本不匹配这个错误发生在VCS本身启动阶段和IP库无关Error: g not found or version mismatchVCS的编译阶段需要调用C编译器来处理SystemVerilog的DTSDirect Testbench Interface部分它对gcc版本敏感。解决方法是给VCS指定匹配的编译器版本比如export VCS_CCgcc-4.8 export VCS_CXXg-4.8或者直接用-cpp和-cc参数强制指定。VCS安装文档里会写明它支持哪些gcc版本按那个来配就行。为了这个问题重装VCS是最不值得的。6.5 我的几条经验总结最后分享几条基于我个人经历的经验。第一pre-compile libraries不要只编译一次就再也不管Vivado升级、VCS升级、换器件族三者任一变化都必须重新编译这也是为什么推荐脚本化管理编译流程的原因。第二vcs命令建议写成脚本而不是每次手敲因为库路径、文件列表一旦拼错排查成本远高于写脚本的成本。第三遇到诡异仿真行为先加-debug_accessall把内部信号全部dump出来很多时候问题其实出在你的testbench激励时序而不是IP本身。这套流程跑通一次之后后面换成AXI-Stream FIFO、换成BRAM、甚至换成DDR接口IP思路完全一样库里编译好、IP仿真模型找到、glbl带上、testbench写好跑通只是时间问题。
返回列表