数字asic流程实验(EX)VCS+Verdi前仿真&后仿真

Posted sasasatori

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数字asic流程实验(EX)VCS+Verdi前仿真&后仿真相关的知识,希望对你有一定的参考价值。

数字asic流程实验(EX)VCS+Verdi前仿真&后仿真

1. 前言

写数字asic流程实验系列博客已经过去一年多了,现在也算结束了纯小白的状态,稍微有了一些数字前端开发经验。在老的系列教程里面用的前仿后仿工具还是modelsim,实际上业界主流工具还是功能更强大的VCS和Verdi。两个也都是synopsys家的工具,VCS是编译器,Verdi是波形查看工具。为什么主流会是这两个工具我就不去复读了,网上有很多解释,而且确实功能强大,谁用过谁知道。我自己切换到VCS+Verdi上做完两次数字设计了,这里share一下一些开发经验。

2. 前仿真

还是使用cic_filter的那个case。先来一个小插曲,那份代码最后梳状器的部分的逻辑有点问题,存在竞争冒险,后仿真出来的波形有毛刺就是因为这个原因。如果直接用原来的代码的话虽然modelsim里面能把波形仿出来,VCS里面却是不行的,所以我插了一级寄存器来处理,修改后的代码为:

module cic_filter(
    input clk,
    input rst_n,
    input in,
    output [18:0] out
);
    reg [18:0]out_reg;
    wire clk_div;
    reg [18:0]sum1,sum2,sum3;
    wire [18:0]sum1_nxt,sum2_nxt,sum3_nxt;

    assign sum1_nxt = sum1 + in;
    assign sum2_nxt = sum2 + sum1;
    assign sum3_nxt = sum3 + sum2;

    always @(posedge clk or negedge rst_n) begin
        if (rst_n == 0) begin
            sum1 <= 19\'b0;
            sum2 <= 19\'b0;
            sum3 <= 19\'b0;
        end
        else begin
            sum1 <= sum1_nxt;
            sum2 <= sum2_nxt;
            sum3 <= sum3_nxt;
        end
    end

    divider div(
        .clk(clk),
        .rst_n(rst_n),
        .clk_div(clk_div)
    );

    reg [18:0]sub1,sub2,sub3;
    reg [18:0]sub1_nxt,sub2_nxt,sub3_nxt;

     always @(posedge clk_div or negedge rst_n) begin
        if (rst_n == 0) begin
            sub1_nxt <= 19\'b0;
            sub2_nxt <= 19\'b0;
            sub3_nxt <= 19\'b0;
        end
        else begin
            sub1_nxt <= sum3_nxt - sub1;
            sub2_nxt <= sub1_nxt - sub2;
            sub3_nxt <= sub2_nxt - sub3;
        end
    end

    always @(posedge clk_div or negedge rst_n) begin
        if (rst_n == 0) begin
            sub1 <= 19\'b0;
            sub2 <= 19\'b0;
            sub3 <= 19\'b0;
        end
        else begin
            sub1 <= sum3_nxt;
            sub2 <= sub1_nxt;
            sub3 <= sub2_nxt;
        end
    end

    always @(posedge clk_div or negedge rst_n) begin
        if (rst_n == 0) begin
            out_reg <= 0;
        end
        else begin
            out_reg <= sub3_nxt;
        end
    end

    assign out = out_reg;

endmodule

VCS分成编译(compile)和仿真(simulation)两步,编译步骤会把verilog代码编译到可执行文件,仿真步骤会执行编译步骤输出的可执行文件。由于VCS的调用命令相对复杂,这里写了一个makefile的脚本:

.PHONY:vcs_com vcs_sim verdi

OUTPUT = cic_filter
TIMESCALE = 1ns/1ns

#start vcs compile
vcs_com:
	cd ../vcs && vcs -full64 +v2k -debug_pp -timescale=$TIMESCALE -cpp g++ -cc gcc -LDFLAGS -no-pie -LDFLAGS -Wl,--no-as-needed -CFLAGS -fPIE -fsdb -f file_list.f -o $OUTPUT -l compile.log

#start vcs sim
vcs_sim:
	cd ../vcs && ./$OUTPUT -l sim.log

#start verdi
verdi:
	cd ../verdi && verdi -f ../vcs/file_list.f -ssf ../vcs/tb_$OUTPUT.fsdb

脚本里OUTPUT和TIMESCALE两个变量可以根据自己的情况来修改。为了简化输入,这里读取文件使用了file_list.f这个文件来标记所有设计文件的路径:

//Macro define
+define+FSDB

// Source
../src/cic_filter.v
../src/divider64.v

// Netlist
//../icc/outputs/cic_filter_post_layout.v

// Library
//../lib/verilog/smic18.v

// Testbench
../tb/tb_cic_filter.v

在前仿真时保留Source和Testbench下的内容即可,Netlist和Library下的内容无关,直接注释掉。

testbench也针对VCS和Verdi的工具需求做了一下修改,主要是Verdi要吃fsdb文件(记录了信号波形),所以要用Dump命令把信号抽取出来。最后还有一段吃sdf文件来跑后仿真的代码,在前仿真时可以把post_sim的宏定义给注释掉,另外因为VCS仿真的结束需要在testbench里面控制,在initial块中记得加入$finish命令,否则到了vcs_sim那一步会一直卡住:

`define period 78.125

module testbench;
    // input
    reg clk,rst_n,in;
    // output
    wire [18:0]out;

    // 设置时钟周期为156.25ns
    always #`period clk <= ~clk;

    // 初始化
    initial begin
        rst_n <= 1\'b0;
        clk <= 1\'b0;
        #500;
        rst_n <= 1\'b1;
        #(10*12800*`period);
        $finish;
    end

    integer i;
    
    // 定义存储器mem
    reg mem[0:3000000];
    
    // 将1k1000mv.txt文件读入mem
    initial $readmemb("../src/1k1000mv.txt",mem);

    // 将mem中数据次序输出到in
    always @(posedge clk or negedge rst_n) begin
        if(rst_n == 0) begin
            i = 0;
            in <= 0;
        end
        else begin
            in <= mem[i];
            i = i + 1;
        end
    end

    // 调用cic滤波器
    cic_filter cic(
        .clk(clk),
        .rst_n(rst_n),
        .in(in),
        .out(out)
    );

    `ifdef FSDB
    initial begin
    	$fsdbDumpfile("tb_cic_filter.fsdb");
    	$fsdbDumpvars;
        $fsdbDumpMDA();
    end
    `endif

    //`define post_sim

    `ifdef post_sim
    // sdf
    initial begin
        $sdf_annotate("../icc/outputs/cic_filter_post_layout.sdf", cic);
    end
    `endif
endmodule

我的路径处理上,将makefile放到了新创建的和src以及tb(testbench专门摆到这个里面来)平级的prj目录里,再平级创建一个vcs文件夹和一个verdi文件夹分别作为vcs和verdi的执行目录。运行整个脚本需要到达prj目录下,执行三步shell命令

make vcs_com
make vcs_sim
make verdi

执行每步命令后都可以看一下工具的输出,如果有报错就处理一下然后再重复步骤即可。Verdi内部可以读取代码,并直接选中要观察的变量,右键Add to waveform加到波形监视窗口。也可以在Instance中选中要观察的Instance,右键Add to waveform将其所有端口信号加到波形监视窗口。

至此前仿真结束。

3. 后仿真

后仿真的步骤很简单,首先修改一下file_list.f,改成吃网表和单元库:

//Macro define
+define+FSDB

// Source
//../src/cic_filter.v
//../src/divider64.v

// Netlist
../icc/outputs/cic_filter_post_layout.v

// Library
../lib/verilog/smic18.v

// Testbench
../tb/tb_cic_filter.v

其次取消testbench中对post_sim宏定义的注释,使得仿真时能够吃到sdf文件来反标延时信息。然后还是那三步shell命令即可:

`define period 78.125

module testbench;
    // input
    reg clk,rst_n,in;
    // output
    wire [18:0]out;

    // 设置时钟周期为156.25ns
    always #`period clk <= ~clk;

    // 初始化
    initial begin
        rst_n <= 1\'b0;
        clk <= 1\'b0;
        #500;
        rst_n <= 1\'b1;
        #(10*12800*`period);
        $finish;
    end

    integer i;
    
    // 定义存储器mem
    reg mem[0:3000000];
    
    // 将1k1000mv.txt文件读入mem
    initial $readmemb("../src/1k1000mv.txt",mem);

    // 将mem中数据次序输出到in
    always @(posedge clk or negedge rst_n) begin
        if(rst_n == 0) begin
            i = 0;
            in <= 0;
        end
        else begin
            in <= mem[i];
            i = i + 1;
        end
    end

    // 调用cic滤波器
    cic_filter cic(
        .clk(clk),
        .rst_n(rst_n),
        .in(in),
        .out(out)
    );

    `ifdef FSDB
    initial begin
    	$fsdbDumpfile("tb_cic_filter.fsdb");
    	$fsdbDumpvars;
        $fsdbDumpMDA();
    end
    `endif

    `define post_sim

    `ifdef post_sim
    // sdf
    initial begin
        $sdf_annotate("../icc/outputs/cic_filter_post_layout.sdf", cic);
    end
    `endif
endmodule

实验文件我就不再打包上传了,所需的代码/脚本上面都已经有了。

VCS仿真生成fsdb文件

VCS仿真生成fsdb文件(Verilog)

一、环境

  • Linux 平台
  • VCS 64bit
  • Verdi3

二、开始仿真

1、 联合仿真环境配置

a.在testbench中加入如下语句:

1 initial begin
2     $fsdbDumpfile("tb.fsdb");
3     $fsdbDumpvars;
4 end

b.注意verdi接口库的路径(脚本中体现)

2、仿真脚本

 1 #!/bin/csh -f
 2 
 3 setenv NOVAS_HOME  /user/EDA_Tools/Synopsys/verdi3-I-201403-SP1
 4 setenv NOVAS_PLI ${NOVAS_HOME}/share/PLI/VCS/LINUX64
 5 setenv LD_LIBRARY_PATH $NOVAS_PLI
 6 
 7 setenv NOVAS  "${NOVAS_HOME}/share/PLI/VCS/LINUX64"
 8 
 9 setenv novas_args  "-P $NOVAS/novas.tab   $NOVAS/pli.a "
10 
11 vcs +v2k -sverilog +vcs+lic+wait -full64 -debug_pp 12        +warn=noCDNYI,noIPDW,noILLGO,noTMR,noPHNE,noIRIID-W 13        -Mupdate +notimingcheck +nospecify 14        ${novas_args}15        -f file.f 16 
17 ./simv 

当前目录下生成tb.fsdb文件

3、使用verdi查看波形

verdi -f file.f -ssf tb.fsdb &

 

以上是关于数字asic流程实验(EX)VCS+Verdi前仿真&后仿真的主要内容,如果未能解决你的问题,请参考以下文章

Verdi 不加载filelist,load design方法

Verdi 不加载filelist,load design方法

文档+视频Verdi基础教程

数字ic设计|ASIC芯片开发过程

数字ic设计|ASIC芯片开发过程

VCS仿真生成fsdb文件