SystemVerilog验证编写(1)

2020-07-01 11:01:17 浏览数 (1)

我错了。不立flag,不定期更新~

前面几次推送已经给出了FIFO的RTL综合设计和SV写法的ref模型

带选通信号的同步FIFO(重发)

带选通信号的同步FIFO(可综合RTL设计)

本次的Testbench就是基于这两次的代码,进行验证。

Testbench的常见组成模块如下,由复位、产生、发送、接收、计分板比对几个模块组成。

本次验证代码就是通过给上述两个FIFO发送相同的信号与指令内容,通过把两个FIFO的输出发送到check task中进行比对,确定RTL写法与时序是否正确,看其是否可以实现正确的功能。

首先要连接DUT模块和TB模块,那么使用interface接口进行连接。

一般来说,我们在接口中使用时钟块去同步TB中的信号,确定端口方向。

代码语言:javascript复制
`timescale 1ns / 100ps

//******************************************************************

// Author:SJTU_chen
// Date: 2019/10/26
// Version: v1.0
// Module Name: fifo-interface
// Project Name: SystemVerilog Lab1

//*******************************************************************

interface fifo_io(input bit clock);
    logic           reset_n,valid_in,valid_out,valid_out1,ready_in,ready_in1;
    logic [63:0]    data_in;
    logic [1:0]     wstrb;
    logic [31:0]    data_out,data_out1;

    clocking cb @(posedge clock);
        default input #1ns output #1ns;
        output reset_n;
        output valid_in;
        output data_in;
        output wstrb;
        input  valid_out,valid_out1;
        input  data_out,data_out1;
        input  ready_in,ready_in1;
    endclocking: cb
    
    modport TB(clocking cb, output reset_n);

endinterface:fifo_io

在顶层模块中把其连接起来,部分代码如下:

代码语言:javascript复制

`timescale 1ns / 100ps

//******************************************************************

// Author:SJTU_chen
// Date: 2019/10/26
// Version: v1.0
// Module Name: fifo-testbench_top
// Project Name: SystemVerilog Lab1

//*******************************************************************

module fifo_test_top();

    parameter simulation_cycle = 10;
    bit SystemClock = 0;

    fifo_io top_io(SystemClock);
    test t(top_io);

    fifo_dut    fifo_dut_inst(
        .clock(top_io.clock),
        .reset_n(top_io.reset_n),
        .valid_in(top_io.valid_in),
        .wstrb(top_io.wstrb),
        .data_in(top_io.data_in),
        .valid_out(top_io.valid_out),
        .ready_in(top_io.ready_in),
        .data_out(top_io.data_out)
    );

    fifo_ref    fifo_ref_inst(
        .clock(top_io.clock),
        .reset_n(top_io.reset_n),
        .valid_in(top_io.valid_in),
        .wstrb(top_io.wstrb),
        .data_in(top_io.data_in),
        .valid_out(top_io.valid_out1),
        .ready_in(top_io.ready_in1),
        .data_out(top_io.data_out1)
    );

    always begin
        #(simulation_cycle/2) SystemClock = ~SystemClock;
    end

endmodule

接下来就是编写TB模块了,如上图所示:

首先我们编写的是复位reset task模块:

代码语言:javascript复制
  //task reset
    task reset();
        fi_io.reset_n       = 1'b0;
        fi_io.cb.wstrb      <= '0;
        fi_io.cb.valid_in  <= '1;
        fi_io.cb.data_in   <= '0;
        repeat(2) @fi_io.cb;
        fi_io.cb.reset_n   <= 1'b1;
        repeat(15) @fi_io.cb;

    endtask: reset

上述代码请仔细看,有点儿意思,很多同学的写法不是这样的,这个在Soc设计方法学课程中会讲到~

接下来就是gen task

代码语言:javascript复制
//task gen
    task gen();
        send_data.delete();
        wstrb_quene.delete();
        repeat(120)
        begin
            wstrb_quene.push_back({$urandom});
            send_data.push_back({$urandom,$urandom});
        end
    endtask: gen

发送 send task:

代码语言:javascript复制
  task send();
        send_payload();
    endtask:send

    task send_payload();
       // static int count = 0;
        static int pkts_checked = 0;
        while(send_data.size() != 0)
        begin
            if (pkts_checked < 80)
            begin
                    fi_io.cb.data_in <= send_data.pop_front();
                    fi_io.cb.wstrb <= wstrb_quene.pop_front();
                    fi_io.cb.valid_in <= $urandom;
                 //   count  ;
            end
            else begin
                fi_io.cb.data_in <= send_data.pop_front();
                fi_io.cb.wstrb <= 2'b11;
                fi_io.cb.valid_in <= 1'b1;
             //   count  ;
            end

        end
    endtask:send_payload

接收 task

代码语言:javascript复制
 //task recv_dut
    task recv_dut();
        get_payload_fromdut();
    endtask: recv_dut

    //task recv_ref
    task recv_ref();
        get_payload_fromref();
    endtask: recv_ref

比对模块部分代码:

代码语言:javascript复制
 function void check();

        string message;
        static int pkts_checked = 0;

        if (!compare(message)) begin
          $display("n%mn[ERROR]%t Packet #
 %sn", $realtime, pkts_checked  , message);
          $finish;
        end
        $display("[NOTE]%t Packet #
 %s", $realtime, pkts_checked  , message);
    endfunction: check

通过以上比对,我们就可以看出dut设计是否正确,请注意,前提条件是保证我们设计的ref模型是没问题的。

最终的仿真截图如下:

下次,我们讲讲怎么使用面向对象的结构去验证~

0 人点赞