转载出处:https://blog.csdn.net/m0_61298445/article/details/128602340

1. VCS 介绍

VCS是编译型 Verilog 模拟器,它完全支持 OVI 标准的 Verilog HDL 语言、PLI 和 SDF。VCS 具有行业中较高的模拟性能,其出色的内存管理能力足以支持千万门级的 ASIC 设计,而其模拟精度也完全满足深亚微米 ASIC Sign-Off 的要求。

VCS 对文件的处理主要分为以下几个部分:

原始的 .v 文件输入。

转换成 .c 文件。

编译成可执行的二进制文件。

最后生成 simv,即可查看仿真的结果。

VCS 有三步法和两步法,三步法用于仿真混合语言,比如 Verilog 和 VHDL 的混合,而两步法用于仿真单种语言,一般都只仿真 Verilog 语言,因此这里只介绍两步法。

两步法分为:

Compilation 编译。编译是仿真设计的第一步。在这个阶段,VCS 构建实例层次结构并生成一个二进制可执行文件 simv。这个二进制可执行文件稍后将用于仿真。

Simulation 仿真。在编译过程中,VCS生成一个二进制可执行文件simv。可以使用 simv 来运行仿真。

2. 常用的编译指令

编译命令的格式:vcs sourcefile [compile_time_option] (编译选项用来控制编译过程),可以另外加一些命令,比如:debug_all(加入单步调试功能)、-sverilog(提供对systemverilog的支持)等

常见的编译命令如下:

-v lib_file:lib_file 是 Verilog 文件,包含了引用的 module 的定义,可以是绝对路径,也可以是相对路径。

-y lib_dir:lib_dir 是参考库的目录,vcs 从该目录下寻找包含引用的 module 的 Verilog 文件,这些文件的文件名必须和引用的 module 的名一样。

-full64:vcs 以 64 位模式编译,生成 64 位的 simv,如果不加这条命令则无法生成 simv。

-R:编译后立即进行仿真。

+v2k:支持 Verilog 2001 标准。

-sverilog:提供对 Systemverilog 的支持。

-l log_file:用于将编译产生的信息放在 log 文件内。

-debug_all:用于产生debug所需的文件。

-Mupdate:源文件有修改时,只重新编译有改动的.v文件,节约编译时间。

-timescale=1ns/1ns 设置仿真精度,可以根据实际需要进行更改。

-kdb:-kdb 选项支持输出 kdb 格式的数据,用于与 Verdi 在交互模式交换数据,而 kdb 格式属于 "Limited Customer Availability" 特性,必须通过 -lca 选项开启。

3. Verdi 介绍

Verdi 和 VCS 一样也是 Synopsys 公司的软件,它是一款强大的仿真波形查看器,通过查看波形进行 debug 会更高效,配合着 VCS 共同进行仿真验证是众多公司的选择,因此学习 VCS 联合 Verdi 进行仿真很有必要。

在 testbench 中添加以下系统函数,用于生成 .fsdb 文件,fsdb文件是 Verdi 可识别的波形文件。

initial begin

$fsdbDumpfile("*.fsdb");

$fsdbDumpvars(0);

end

以下为常见的fsdb波形文件的系统函数及其含义。

如果要Dump FSDB波形,将以下语句选择性加在TB中。

initial begin

$fsdbDumpfile(“dump.fsdb”) ; //fsdbDumpfile - 指定FSDB文件名

$fsdbDumpvars(level,start_module) ; //要记录的信号,level=0表示记录所有

$dumpvars(2, top. u1); // Dump实例top. u1及其下一层的信号

$fsdbDumpMDA(); //fsdb dump波形时会记录二维数组2D array signal的值,

便于在verdi中debug查memory内部信号。

$fsdbDumpSingle;           //Dump指定的信号

$fsdbDumpvariable;          //Dump指定的VHDL变量

$fsdbSwitchDumpFile(“<newFSDBname>”); //将dumping切换到另一个FSDB文件

$fsdbAutoSwitchDumpfile(<filesize>, “<FSDBname>”,< numberoffile>);

//限制文件大小并在数据量过大时自动创建新的FSDB文件

$fsdbDumpMem(<regname>, [<startaddr>, [<size>]]);

$fsdbDumpoff; //停止记录

$fsdbDumpon; //重新开始记录

$fsdbDumplimit(); //限制VCD文件的大小(以字节为单位)

$fsdbDumpall; //记录所有指定的信号值

end

4. makefile 书写

如果使用终端手敲命令的方法进行 VCS 和 Verdi 的仿真,会显得过于麻烦,不仅费时间而且容易出错,因此可以通过 makefile 脚本的形式对整个过程的命令自动化,在对不同的文件进行仿真时,只需要修改部分内容即可重复使用,非常便捷。

以下为 Makefile 的脚本,可以使用 “make all” 命令实现从 VCS 编译到 Verdi 查看波形等一系列操作的自动化。

PRJ = /home/ICer/Project/prj

FILENAME = $(PRJ)/*.v

OUTPUT = sync_fifo

#仿真并打开vcs verdi界面

all:clean elab run verdi

elab:

vcs -full64 -LDFLAGS -Wl,-no-as-needed -debug_acc+all -timescale=1ns/1ns -fsdb -sverilog -l comp.log ${FILENAME}

run:

./simv -l ${OUTPUT}.log ${FILENAME}

rung:

./simv -gui -l run.log ${FILENAME}

verdi:

verdi ${FILENAME} -ssf ./*.fsdb &

clean:

rm -rf ./csrc *.daidir *.log simv* *.key *.vpd ./DVEfiles verdiLog novas*

5. 文件准备

现在用一个实际例子,用来演示 VCS 联合 Verdi 进行仿真,这里以一个简单的同步 FIFO 为例,以下为同步 FIFO 的 Verilog 实现。

`timescale1ns/1ps

//

// Company:

// Engineer: Linest-5

// Create Date: 2022/05/07

// Design Name:

// Module Name: Sync_FIFO

// Project Name:

// Target Devices:

// Tool Versions:

// Description: 同步FIFO的verilog实现

// Dependencies:

// Revision:

// Additional Comments:

//

//

moduleSync_FIFO#(

parameter DATA_WIDTH =8, //数据位宽

parameter FIFO_DEPTH =8, //FIFO的深度

parameter ALMOST_FULL_DEPTH =7, //将满的深度

parameter ALMOST_EMPTY_DEPTH =1, //将空的深度

parameter ADDR_WIDTH =3, //地址位宽

parameter READ_DATA_MODE =0 //读取的模式,0为组合逻辑。1为时序逻辑

)(

input clk,

input rst_n,

input wr_en,

input rd_en,

input [DATA_WIDTH-1:0] wr_data,

output reg[DATA_WIDTH-1:0] rd_data,

output almost_full,

output almost_empty,

output full,

output empty,

output reg overflow, //上溢出信号

output reg underflow //下溢出信号

);

reg [ADDR_WIDTH-1:0] wr_ptr; //写指针

reg [ADDR_WIDTH-1:0] rd_ptr; //读指针

reg [ADDR_WIDTH:0] fifo_cnt; //使用的FIFO空间计数

reg [DATA_WIDTH-1:0] buf_mem[FIFO_DEPTH-1:0]; //创建数组作存储

//对FIFO空间使用作计数

always @(posedgeclkornegedgerst_n)begin

if(!rst_n)begin

fifo_cnt <='d0;

end

elseif(wr_en&&~full&&rd_en&&~empty)begin

fifo_cnt <=fifo_cnt;

end

elseif(wr_en&&~full)begin

fifo_cnt <=fifo_cnt+'d1;

end

elseif(rd_en&&~empty)begin

fifo_cnt <=fifo_cnt-'d1;

end

elsebegin

fifo_cnt <=fifo_cnt;

end

end

//写指针

always @(posedgeclkornegedgerst_n)begin

if(!rst_n)begin

wr_ptr <='d0;

end

elseif(wr_en&&~full)begin

wr_ptr <=wr_ptr+'d1;

end

elseif(wr_ptr==FIFO_DEPTH-1)begin

wr_ptr <='d0;

end

elsebegin

wr_ptr <=wr_ptr;

end

end

//读指针

always @(posedgeclkornegedgerst_n)begin

if(!rst_n)begin

rd_ptr <='d0;

end

elseif(rd_ptr==FIFO_DEPTH-1)begin

rd_ptr <='d0;

end

elseif(rd_en&&~empty)begin

rd_ptr <=rd_ptr+'d1;

end

elsebegin

rd_ptr <=rd_ptr;

end

end

//数据写入

always @(posedgeclkornegedgerst_n)begin

if(!rst_n)begin

buf_mem[wr_ptr] <='d0;

end

elseif(wr_en&&~full)begin

buf_mem[wr_ptr] <=wr_data;

end

elsebegin

buf_mem[wr_ptr] <=buf_mem[wr_ptr];

end

end

//根据模式的选择将数据读出,模式0为组合逻辑输出,模式1为时序逻辑输出

generate

if(READ_DATA_MODE=='d0)begin

always @(*)

rd_data=buf_mem[rd_ptr]; //组合逻辑输出

end

elsebegin

always @(posedgeclkornegedgerst_n)begin

if(!rst_n)begin

rd_data <='d0;

end

elseif(rd_en&&~empty)begin

rd_data <=buf_mem[rd_ptr]; //时序逻辑输出

end

elsebegin

rd_data <=rd_data;

end

end

end

endgenerate

//上溢出信号

always @(posedgeclkornegedgerst_n)begin

if(!rst_n)begin

overflow <='d0;

end

elseif(wr_en&&full)begin

overflow <='d1;

end

end

//下溢出信号

always @(posedgeclkornegedgerst_n)begin

if(!rst_n)begin

underflow <='d0;

end

elseif(rd_en&&empty)begin

underflow <='d1;

end

end

//定义将满、将空、满、空信号

assignalmost_full=(fifo_cnt >=ALMOST_FULL_DEPTH);

assignalmost_empty=(fifo_cnt <=ALMOST_EMPTY_DEPTH);

assignfull=(fifo_cnt==FIFO_DEPTH);

assignempty=(fifo_cnt=='d0);

endmodule

此外,还需要准备其对应的 testbench,如下所示。

//

// Company:

// Engineer: Linest-5

// Create Date: 2022/05/07

// Design Name:

// Module Name: tb_Sync_FIFO

// Project Name:

// Target Devices:

// Tool Versions:

// Description: 同步FIFO的testbench文件

// Dependencies:

// Revision:

// Additional Comments:

//

//

`timescale1ns/1ns

moduletb_Sync_FIFO();

parameter DATA_WIDTH=8;

parameter FIFO_DEPTH=8;

parameter ALMOST_FULL_DEPTH=7;

parameterALMOST_EMPTY_DEPTH=1;

parameter ADDR_WIDTH=3;

parameter READ_DATA_MODE=1;

reg clk;

reg rst_n;

reg wr_en;

reg rd_en;

reg [DATA_WIDTH-1:0] wr_data;

wire[DATA_WIDTH-1:0] rd_data;

wire almost_full;

wire almost_empty;

wire full;

wire empty;

wire overflow;

wire underflow;

initialbegin

clk=0;

rst_n=0;

#50

rst_n=1;

end

always#10clk=~clk;

initialbegin

wr_en=0;

rd_en=0;

wr_data=0;

end

initialbegin

#100

send_wr;

end

initialbegin

#400

send_rd;

#1000;

$finish;

end

//创建写任务

integeri;

tasksend_wr;

begin

for(i=0;i<8;i=i+1)begin

@ (posedgeclk)begin

wr_en <='d1;

wr_data <=i+1;

end

end

@ (posedgeclk)begin

wr_en <='d0;

wr_data <='d0;

end

repeat(10)@ (posedgeclk);

end

endtask

//创建读任务

tasksend_rd;

begin

for(i=0;i<8;i=i+1)begin

@ (posedgeclk)begin

rd_en <='d1;

end

end

@ (posedgeclk)begin

rd_en <='d0;

end

end

endtask

Sync_FIFO#(

.DATA_WIDTH (DATA_WIDTH),

.FIFO_DEPTH (FIFO_DEPTH),

.ALMOST_FULL_DEPTH (ALMOST_FULL_DEPTH),

.ALMOST_EMPTY_DEPTH(ALMOST_EMPTY_DEPTH),

.ADDR_WIDTH (ADDR_WIDTH),

.READ_DATA_MODE (READ_DATA_MODE)

)inst_Sync_FIFO(

.clk (clk),

.rst_n (rst_n),

.wr_en (wr_en),

.rd_en (rd_en),

.wr_data (wr_data),

.rd_data (rd_data),

.almost_full (almost_full),

.almost_empty (almost_empty),

.full (full),

.empty (empty),

.overflow (overflow),

.underflow (underflow)

);

initialbegin

$fsdbDumpfile("tb_Sync_FIFO.fsdb");

$fsdbDumpvars(0);

$fsdbDumpMDA();

end

endmodule

有几点需要注意:

添加仿真精度和仿真单位。

`timescale 1ns/1ns

添加停止仿真系统函数。如果不加的话仿真会一直仿真不停止,导致无法观察仿真波形。

$finish

添加仿真需要的系统函数,$fsdbDumpfile 表示生成的 fsdb 文件名,用于 Verdi 查看波形;$fsdbDumpvars 表示需要查看的信号,0 表示所有信号都将纳入观察;$fsdbDumpMDA 表示 fsdb dump 波形时会记录二维数组 2D array signal 的值,便于在 Verdi 中 debug 查 memory 内部信号。

initial begin

$fsdbDumpfile("tb_Sync_FIFO.fsdb");

$fsdbDumpvars(0);

$fsdbDumpMDA();

end

6. 实操练习

接下来直接进行最后的实操仿真,打开终端进入到工程目录下。

ls 查看当前目录所含的文件,可以看到包含有同步 FIFO 的 .v 文件以及对应的 TB 文件,另外还有实现自动化的 makefile 脚本文件。

根据前面 makefile 的说明,直接使用 make all 命令即可实现自动仿真。

随后会显示一些信息,如顶层文件,仿真精度和单位等。

同时也会打印 VCS 仿真报告。

随后会自动弹出 Verdi 的 GUI 界面。

第一部分为菜单栏部分,这里可以进行查看电路图、加载源文件等操作。

第二部分为当前加载的文件层次结构,可以看到顶层文件为 sync_fifo,因为当前只有一个文件,所以毫无疑问顶层文件只能是它,如果包含多个设计文件,含有顶层及子模块,这里就会清晰的显示出来。

第三部分为设计文件的内容显示,同时在后续会介绍可以直接通过这里查看相应信号的波形。

第四部分为波形显示区,这里就是 Verdi 最重要的区域,我们就是通过这里查看信号波形进行 debug 的。

但是这是可以看到在波形显示区并没有波形出现,这时需要我们手动选择添加观察信号,鼠标选择要观察的模块信号,并按下快捷键“CTRL + 4”,即可将选中模块所包含的信号加入到波形观察区中。

此外在前面埋下伏笔说了可以在代码观察区添加观察信号,在 debug 时,有时需要观察非端口信号,比如在内部定义的 reg/wire 信号,这时就可以在代码观察区添加,比如我要观察在内部定义的写使能信号 wr_en,鼠标选中此信号,按下快捷键“CTRL + w”即可将信号添加至观察区进行 debug。

可以看到当前的波形太大,不利于我们观察,可以按 F 键,便会自动将波形整形成最适合当前的比例。

另外可以通过上方的按钮将波形进行放大和缩小,也可以通过按住 CTRL 键在滑动鼠标滚轮将波形进行放大和缩小。

当添加的模块信号太多时,会显得很杂乱,可以将其分组分类进行观察,只需要将同组的信号选中向下拖拽即可。下图将信号分为五组。

过多的信号都是同一种颜色容易看花,可以将不同类的信号设置成不同的颜色,便于区分,只需选中信号,按 T 键即可切换颜色。

另外选中信号右击鼠标会出现一列菜单栏,在这里可以更改信号的进制、形式(数字或模拟)、重命名等操作,这里就不一一操作了,如果之前使用过 Vivado、Modelsim等工具,相信这些操作还是很容易上手的。

7. 总结

这篇文章只介绍,VCS 和 Verdi 最基本的操作,更多高阶的操作可以查看其官方手册,也可以在平时的练习中不断加强对软件操作的熟练度,工具学起来还是比较容易的,难的是如何对设计进行快速的仿真并找出其中的 bug,这需要在未来长期学习训练与总结。

————————————————

版权声明:本文为CSDN博主「Linest-5」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/m0_61298445/article/details/128602340

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐