Synopsys 功能仿真入门:Makefile、VCS 与 Verdi 协同使用及 IP 核调用

📅 发布时间:2026/7/13 16:45:30
Synopsys 功能仿真入门:Makefile、VCS 与 Verdi 协同使用及 IP 核调用 1. 数字IC设计流程在正式介绍 Synopsys 功能仿真之前有必要先对数字 IC 设计的全流程建立一个整体认识。下表按照流程顺序自上而下列出了数字 IC 设计的主要阶段以及各阶段常用的工具、输入和输出内容。需要说明的是表中大部分工具来自Synopsys工具链而物理验证工具Calibre则属于Siemens EDA。数字 IC 设计流程可以理解为一个从 RTL 功能描述到版图物理实现的过程。简单来说芯片设计就是将最初较为抽象的功能需求逐步转化为能够在硅片上真实制造的电路。首先通过 RTL 描述模块功能、时序关系和接口行为随后经过综合将这些功能描述映射为由触发器、组合逻辑等标准单元构成的门级网表再通过布局布线将网表中的逻辑单元映射到芯片版图中的具体物理位置并利用金属互连完成它们之间的实际连接最终形成满足工艺规则、可用于流片制造的版图数据。从这个角度看数字 IC 设计流程的核心就是不断降低设计抽象层次将“代码中的功能”逐步落实为“芯片上的真实电路”。2. 功能仿真功能仿真是数字IC前端验证的核心环节旨在RTL阶段尽早发现功能缺陷验证设计行为是否满足预期规格。在实际工程中功能仿真通常借助Synopsys VCS 编译器完成 RTL 代码的编译与仿真并通过Verdi 波形调试工具对仿真结果进行可视化快速定位信号时序问题。为了提升仿真效率、规范操作流程工程师通常会将 VCS 编译、仿真运行、波形转储等命令封装在 Makefile 中实现一键编译仿真、自动生成带时间戳的波形文件大幅简化了日常调试的重复性操作。2.1 规范化工程目录好的工程目录是高效开发的基础更是工程规范化的起点。在功能仿真之前根据个人习惯搭建规范的工程目录随后一切操作都会变得更加清晰。目录Proj是整个工程的最顶层目录项目中的所有相关文件都应该放在该目录下。目录rtl主要存放工程中的设计文件包括模块的RTL代码以及filelist.f文件列表。目录tb主要存放测试激励文件包括各个模块仿真用的任务、函数等辅助文件。目录sim主要存放仿真相关的脚本与输出文件包括Makefile、编译生成的simv可执行文件、各种仿真日志.log、波形文件.fsdb以及各种临时文件等。随着设计流程的推进后续的综合、布局布线等阶段同样需要在Proj下创建各自独立的目录。每个阶段拥有独立的目录既能避免不同工具产生的文件相互干扰也便于在流程回溯时快速定位特定阶段的输入与输出。2.2 案例驱动从设计到仿真以一个简单的RTL设计作为案例要求是设计一个10进制计数器模块并基于VCS和Verdi完成功能仿真。2.2.1 RTL设计切换到rtl目录下创建文件cnt10.v规范文件名与模块名保持一致其内容如下module cnt10( clk, rst_n, en, cnt_out, carry_out ); input clk; input rst_n; input en; output reg [3:0]cnt_out; output carry_out; always(posedge clk or negedge rst_n) if(!rst_n) cnt_out 4d0; else if(en) cnt_out (cnt_out 4d9) ? 4d0 : (cnt_out4d1); assign carry_out en (cnt_out 4d9); endmodule2.2.2 TestBench编写切换到tb目录下创建测试激励文件cnt10_tb.v规范文件名和模块名均以被测模块名加_tb后缀来命名其内容如下timescale 1ns/1ps module cnt10_tb; parameter clk_period 10; reg clk; reg rst_n; reg en; wire [3:0]cnt_out; wire carry_out; cnt10 cnt10_inst( .clk(clk), .rst_n(rst_n), .en(en), .cnt_out(cnt_out), .carry_out(carry_out) ); ifdef DUMP_FSDB // 条件编译通过宏定义控制是否生成波形文件 initial begin $fsdbDumpfile(cnt10.fsdb);// 波形文件名{模块名}.fsdb $fsdbDumpvars(0,cnt10_tb); // 记录cnt10_tb及其所有层级的信号 end endif initial clk 1b1; always #(clk_period/2) clk ~clk; initial begin rst_n 1b0; en 1b0; #21; rst_n 1b1; #20; (posedge clk); en 1b1; #(clk_period*5); en 1b0; #(clk_period*3); en 1b1; #(clk_period*20); en 1b0; #(clk_period); $finish; end endmodule注释ifdef是条件编译指令只有当定义了DUMP_FSDB这个宏时中间的代码才会被编译进仿真中否则整个代码块被忽略。在后续VCS编译时会在Makefile文件中定义这个宏。$fsdbDumpfile(cnt10.fsdb)指定波形输出文件名后缀fsdb为Verdi专用波形格式。文件名建议与被测模块同名方便在多模块工程中快速识别。$fsdbDumpvars(0,cnt10_tb)用于指定波形记录的范围。第一个参数表示记录的层级深度0表示完全展开即从指定实例开始递归记录其下所有层次的模块信号1表示只记录当前这一层的信号不再深入子模块2表示继续记录到下一层子模块以此类推数值每增加1就多向下展开一层。第二个参数表示从哪个模块实例开始记录通常都是从顶层的TestBench模块开始。$finish用于结束仿真进程仿真器会完全退出并释放资源。而$stop用于暂停仿真命令行显示ucli%用于交互式调试用户输入quit后退出仿真。因此在自动化仿真流程中使用$finish更合适。2.2.3 filelist.f编写切换到sim目录下创建文件filelist.f其内容如下../tb/cnt10_tb.v ../rtl/cnt10.v文件filelist.f是VCS编译时的源文件列表作用是统一列出本次仿真需要编译的设计文件和测试文件后续在Makefile命令行中通过-f选项读取方便后续维护和扩展。2.2.4 Makefile编写切换到sim目录下创建文件Makefile其内容如下# 基本变量MODULEcnt10 TB_TOP$(MODULE)_tb WAVE_NAME$(MODULE).fsdb FILELISTfilelist.f SIMVsimv#伪目标.PHONY: all com sim verdi clean all:com sim verdi# 编译com: vcs-full64\-sverilog\v2k\-timescale1ns/1ps\-debug_accessall\-f$(FILELIST)\defineDUMP_FSDB\-fsdb\-o$(SIMV)\-lcompile.log# 仿真sim: ./$(SIMV)-lsim.log# 调试verdi: verdi-sverilog\-f$(FILELIST)\-top$(TB_TOP)\-ssf$(WAVE_NAME)\-nologo# 清理clean:rm-rfcsrc DVEfiles *.daidir *.log simv* *.key *.vpd *.fsdb verdiLog *.conf novas* ucli.keyMakefile的作用是把编译、仿真、波形查看和工程清理等常用操作统一组织起来避免每次手动输入冗长命令。通过这种方式可以将VCS编译、仿真运行、Verdi调试等流程封装成固定目标执行时只需在命令行输入make com、make sim、make com等指令即可。基本变量用来统一管理被测设计模块名、测试激励模块名、波形文件名、文件列表名以及仿真可执行文件名。各文件和模块在创建时需保持命名的规范性一致性。如果后续需要仿真其它设计只需修改MODULE值即可。.PHONY用于声明伪目标这里共计声明了5个伪目标。在终端命令行中输入make xxx例如make simmake会定位到Makefile中对应的伪目标并依次执行该目标下所定义的命令。若直接输入make不带参数则默认执行第一个目标all。目标all是Makefile文件中的第一个目标因此在命令行输入make或make all时会默认执行它。all本身一般不包含具体命令而是依赖于com、sim和verdi三个目标因此执行all时实际上会先后触发这些依赖目标的执行。目标com的作用是调用vcs对设计文件和测试激励文件进行编译与链接最终生成一个可执行的仿真程序simv。注意在Makefile中目标下面的命令行必须以一个[TAB]键开头不能随意用空格代替。下面对编译选项进行解释-full64使用64 位模式编译和生成仿真程序。-sverilog开启SystemVerilog语法支持。v2k开启Verilog-2001语法支持。-timescale1ns/1ps指定仿真时间单位和时间精度。-debug_accessall开启全部调试访问权限方便后续在Verdi中查看和追踪信号。-f $(FILELIST)从filelist.f文件列表中读取待编译的源文件。defineDUMP_FSDB在编译时定义宏DUMP_FSDB配合测试激励文件中的条件编译使用。-fsdb开启对FSDB波形格式的支持使后续仿真过程中能够生成.fsdb波形文件供Verdi查看。-o $(SIMV)指定编译后生成的仿真可执行文件名。-l compile.log把编译过程中的终端输出写入日志文件compile.log。目标sim的作用是执行前面com阶段生成的仿真可执行文件运行测试激励并得到仿真结果。若在VCS编译时开启了FSDB支持且测试激励文件中包含$fsdbDumpfile等波形转储语句则仿真过程中会生成.fsdb波形文件。-l sim.log把仿真运行过程中的输出信息保存到sim.log中。目标verdi的作用是启动Verdi图形界面用于查看波形、浏览层次结构、跟踪信号和调试设计。-sverilog按SystemVerilog工程来解析源码。-f $(FILELIST)从文件列表$(FILELIST)中读取工程源码文件使Verdi知道工程包含的设计和测试文件。-top $(TB_TOP)指定顶层模块名通常是TestBench顶层模块名。告诉Verdi从哪个模块开始构建整个仿真工程的层次结构。-ssf $(WAVE_NAME)加载指定的.fsdb波形文件。-nologo启动时不显示工具的logo或欢迎信息。非Verdi的选项而是Linux shell的后台运行符号。作用是让Verdi在后台启动不占用当前终端。目标clean用于删除编译和仿真过程中产生的中间文件、日志文件、波形文件和调试文件方便重新编译和保持工程目录整洁。删除的内容通常包括csrcvcs生成的中间C源码目录*.daidirvcs编译时生成的工作目录*.log编译和仿真产生的日志文件simv*仿真可执行文件及其相关文件*.fsdb仿真生成的波形文件verdiLog、novas*、*.confVerdi调试过程中生成的日志、配置和辅助文件2.2.5 仿真过程和结果切换到sim目录下初始文件为Makefile和filelist.f。按照先后顺序依次执行编译、仿真和调试。输入make com执行编译过程。编译完后生成了可执行文件simv、编译日志和其他中间文件。输入make sim执行仿真过程。仿真运行完后生成了波形文件cnt10.fsdb、仿真日志和其他配置文件。输入make verdi执行调试过程。调试过程中生成了Verdi日志目录、波形转储配置文件及转储日志等辅助文件。通过Verdi加载cnt10.fsdb波形文件可以查看设计各模块的信号波形变化追踪信号传播路径定位设计中的逻辑错误。输入make clean清理编译和仿真产生的中间文件及日志。注意每次重新编译、仿真和调试前都应先执行清理避免旧文件干扰。输入make执行目标allMake工具按照依赖顺序依次执行com、sim和verdi三个目标最终自动弹出Verdi调试界面实现从源码编译到波形查看的一键式完整流程。3. IP核的调用3.1 DesignWare库介绍DesignWare是Synopsys提供的常用标准IP库里面包含加法器、乘法器、存储单元等基础模块。在RTL设计阶段提供现成、可靠的功能单元减少重复开发工作。在后续综合过程中这些IP会被工具自动映射并替换为优化后的门级实现。在使用DesignWare IP库之前需要先确认其安装路径。由于不同版本的Synopsys软件安装位置可能不同。本文所用版本中DesignWare的路径为/soft/synopsys/syn2019.12/dw。该目录下的内容如下doc目录中包含各类IP的数据手册主要用于查阅其功能特性及接口时序等信息。dw01~dw06是DesignWare Building Block的6个主分类库不同目录下收录了不同类型的基础IP模块。每个分类目录下面通常又包含lib、src和src_ver三个子目录。其中lib目录主要保存综合相关的库描述和架构映射信息src目录主要是VHDL形式的源文件src_ver目录则主要提供Verilog版本的模型文件用于Verilog仿真。dw01主要包含基础组合逻辑与位操作类IP如加减、比较、移位、编码与译码等模块。dw02主要包含算术运算与浮点运算相关IP如乘法、除法、开方、流水算术及浮点运算模块。dw03主要包含时序、同步、控制及部分DSP相关IP如计数器、FIFO控制、跨时钟域处理和时序算术模块。dw04主要包含编码、纠错、DFT、JTAG以及MBIST等测试与辅助功能相关IP。dw05主要包含仲裁器相关IP。dw06主要包含存储器的相关IP如RAM、Memory、FIFO、异步FIFO等模块。examples该目录提供官方示例文件.v和.vhd可作为DesignWare组件例化和参数配置的参考模板。fpga_ip并不是额外的一套功能IP库而是Synopsys为FPGA综合、原型验证等流程提供的适配层主要用于支持工具对DesignWare模块的推断、映射和兼容处理。scripts目录中包含Synopsys官方提供的辅助脚本主要用于重新分析DesignWare的仿真库和综合库以及检查工具环境是否配置正确。sim_ver是Verilog仿真模型的总目录可以看作dw01~dw06/src_ver的聚合版本。在实际使用时通常直接将sim_ver作为统一的仿真模型入口在filelist.f中加入所需的相关模型.v文件即可无需再分别到各个目录中查找。。syn_ver目录中的文件主要用于支持综合工具对datapath功能进行识别、推断和映射更偏向综合阶段的内部支持文件而不是供用户直接阅读或调用的RTL源码。3.2 RAM IP核介绍DesignWare IP核的调用与仿真通常比较简单。对于前端Verilog仿真只需将sim_ver目录中对应的仿真模型.v文件路径加入filelist.f即可让仿真工具正确识别并调用相关IP。一般来说在正式将某个IP核集成到项目中之前建议先对其进行单独仿真验证以便熟悉该IP的功能特性、接口定义和时序关系这样在后续工程中使用时会更加稳妥。与此同时examples目录下通常还提供了对应IP的官方例化模板可作为实例化写法和参数配置的参考。下面简单介绍一下DesignWare常用的RAM IP核并对一些IP进行仿真示例。端口命名含义r1 个读端口w1 个写端口2r2 个读端口2w2 个写端口rw读写共用一个端口即读写共用同一组访问接口时序命名含义a异步型通常表示写操作不依赖时钟边沿触发s同步型写操作通常由时钟控制2c双时钟型读和写使用不同的时钟常用于跨时钟场景实现方式含义dff用触发器flip-flop实现lat用锁存器latch实现对于不熟悉的IP核建议优先查阅doc目录下的数据手册datasheets其中对端口定义、功能以及时序行为都有完整且权威的说明。3.3 RAM IP核仿真下面我们对IP核DW_ram_r_w_s_dff进行仿真示例。数据手册中的接口定义和读写时序如下我们继续沿用2.2小节中已创建好的工程目录并在此前保留的Makefile、filelist.f等文件基础上完成本次仿真。切换到tb目录编写测试激励文件DW_ram_r_w_s_dff_tb.vtimescale 1ns/1ps module DW_ram_r_w_s_dff_tb; parameter clk_period 10; parameter data_width 8; parameter depth 128; parameter rst_mode 0; define bit_width_depth 7// ceil(log2(depth)) reg inst_clk; reg inst_rst_n; reg inst_cs_n; reg inst_wr_n; reg [bit_width_depth-1 : 0] inst_rd_addr; reg [bit_width_depth-1 : 0] inst_wr_addr; reg [data_width-1 : 0] inst_data_in; wire [data_width-1 : 0] data_out_inst; // Instance of DW_ram_r_w_s_dff DW_ram_r_w_s_dff #(data_width, depth, rst_mode) U1 (.clk(inst_clk), .rst_n(inst_rst_n), .cs_n(inst_cs_n), .wr_n(inst_wr_n), .rd_addr(inst_rd_addr), .wr_addr(inst_wr_addr), .data_in(inst_data_in), .data_out(data_out_inst) ); ifdef DUMP_FSDB initial begin $fsdbDumpfile(DW_ram_r_w_s_dff.fsdb); $fsdbDumpvars(0,DW_ram_r_w_s_dff); end endif initial inst_clk 1b1; always #(clk_period/2) inst_clk ~inst_clk; integer i; initial begin inst_rst_n 1b0; inst_cs_n 1b1; inst_wr_n 1b1; inst_wr_addr 8d0; inst_data_in 128d0; inst_rd_addr 8d0; #101; inst_rst_n 1b1; #20; inst_cs_n 1b0; for(i0;i128;i)begin inst_wr_n 1b0; inst_wr_addr i; inst_data_in i1; #clk_period; end inst_wr_n 1b1; inst_cs_n 1b1; #clk_period; for(i0;i128;i)begin inst_rd_addr i; #clk_period; end #100; inst_rst_n 1b0; #clk_period; inst_rst_n 1b1; #clk_period; for(i0;i128;i)begin inst_rd_addr i; #clk_period; end #100; $finish; end endmodule切换到sim目录编写filelist.f文件../tb/DW_ram_r_w_s_dff_tb.v /soft/synopsys/syn2019.12/dw/sim_ver/DW_ram_r_w_s_dff.v继续修改Makefile文件只需要修改第1行MODULE DW_ram_r_w_s_dff即可其他内容始终保持不变。在终端键入make完成编译、仿真和调试通过Verdi对波形进行查看。写入波形如下。在时钟上升沿检测写使能信号wr_n并将输入数据写入对应的地址单元中。需要注意的是只有在片选信号cs_n为低电平、芯片被选通时写操作才会生效。读出波形如下。采用组合读出方式读数据不需要时钟触发地址变化后输出会经过组合延迟直接更新。注意读操作不受片选信号cs_n控制。当然仿真中还有许多情况值得进一步观察和验证读者可以自行探索与分析。