当前位置:   article > 正文

【验证小白】只有SV+modelsim学验证(5)——先将嗷嗷待验的DUT加入环境,至此就只遗留环境的灵魂RM了_.v后缀和.sv后缀的dut

.v后缀和.sv后缀的dut

今天我们继续向前大步迈进,把待验证的DUT加入到环境中来!为此我写了一个非常复杂的模块~~主要的功能把输入的数据打两拍然后送出去。。。。当然这只是level1.0版本,后续在添加reference module时,我一定会补充更加复杂的场景代码的!其实急着把DUT放进来主要是为了下一个博客——验证环境module与program中的time slot做准备。

闲话不多说了,先来看看我的待验证DUT模块。目前功能实在是太简单了,我就不多说啥了,最后的三个fb接口是为之后预留的,可以先不管他们。那么从代码上要连接这个dut只需要两组接口,数据输入interface和数据输出interface。

`ifndef FLOW_PROC_V
`define FLOW_PROC_V
 
module flow_proc #(
    parameter DATA_WIDTH = 8
)(
    input            clk            ,
    input            rst_n            ,
    input            data_in_vld        ,
    input            sop_in_vld        ,
    input            eop_in_vld        ,
    input  [DATA_WIDTH-1:0]    data_in            ,
    
    output reg            data_out_vld            ,
    output reg            sop_out_vld        ,
    output reg            eop_out_vld        ,
    output reg [DATA_WIDTH-1:0]    data_out        ,
    
    output            fb_vld            ,
    output            fb_eop            ,
    output            fb_cnt            
);
 
reg            data_out_vld_ff1    ;
reg            sop_out_vld_ff1        ;
reg            eop_out_vld_ff1        ;
reg [DATA_WIDTH-1:0]    data_out_ff1        ;
    
always @(posedge clk) begin
    if(rst_n == 1'b0)begin
    data_out_vld_ff1 <= 1'b0;
    sop_out_vld_ff1  <= 1'b0;
    eop_out_vld_ff1  <= 1'b0;
    data_out_ff1     <= {DATA_WIDTH{1'b0}};
    end
    else begin
    data_out_vld_ff1 <= data_in_vld;
    sop_out_vld_ff1  <= sop_in_vld;
    eop_out_vld_ff1  <= eop_in_vld;
    data_out_ff1     <= data_in;
    end
end
 
always @(posedge clk) begin
    if(rst_n == 1'b0)begin
    data_out_vld <= 1'b0;
    sop_out_vld  <= 1'b0;
    eop_out_vld  <= 1'b0;
    data_out     <= {DATA_WIDTH{1'b0}};
    end
    else begin
    data_out_vld <= data_out_vld_ff1;
    sop_out_vld <= sop_out_vld_ff1;
    eop_out_vld <= eop_out_vld_ff1;
    data_out <= data_out_ff1;
    end
end    
    
endmodule
 
`endif
?那我们来改造下验证环境,把DUT加入验证环境中。

改造1.用interface pkt_in_bus和pkt_out_bus分别连接DUT的入口和出口;

改造2.用in_mon采集pkt_in_bus上的信号,out_mon采集pkt_out_bus上的信号,转化为pkt格式traction;

改造3.chk不再与gen相连接,改为与in_mon和out_mon通过channnel连接;

改造4.in_mon的pkt包作为预期,out_mon的包为实际处理结果,由于DUT没有做逻辑处理因此暂时不需要RM;

改造后的验证环境如下图所示。

根据我们设计的验证环境,我们开始轰轰烈烈的改造工程。

首先来组织一下interface,可以预见到我们的模块后面的接口肯定会越来越多,那么我们不能每次加一个接口就从顶层一直加到env里面去,这种方式实在是太费力了,因此我将已有的pkt_if又封装了一层代码如下:

`include "pkt_if.sv"
 
`ifndef PKT_INTERFACE_SV
`define PKT_INTERFACE_SV
 
interface pkt_if_pack(
    input logic        clk,
    input logic        rst_n
);
    
    pkt_if        pkt_in_bus  (clk, rst_n);
    pkt_if        pkt_out_bus (clk, rst_n);
    
endinterface : pkt_if_pack
 
//class pkt_interface;
 
//    virtual pkt_if pkt_in_bus  = pkt_if_pack.pkt_in_bus;
//    virtual pkt_if pkt_out_bus = pkt_if_pack.pkt_out_bus;
    
//endclass : pkt_interface
 
`endif
(注释掉的class部分可以暂时不用关注,本来是一种通过virtual来更简洁的做法但是不知道为啥modelsim编译可以过仿真时候会报错,看来我还是要早点把虚拟机里的VCS用起来才是正道。)

把两个pkt_in_bus和pkt_out_out封装在这里,之后进行例化和传递时会简单很多。

封装好interface后我们就可以把DUT例化到环境中了,直接将DUT例化在top顶层即可,这里还想吐槽下modelsim,为啥我想include rtl_link文件也要报错呢,是我不会用么?不多说了,下面是在top中的例化代码,完整代码附在最后面。

    //`include “rtl_link”
        //part1
    wire                 data_in_vld        ;
    wire                 sop_in_vld        ;
    wire                 eop_in_vld        ;
    wire [8            -1:0]   data_in            ;
    wire                 data_out_vld            ;
    wire                 sop_out_vld        ;
    wire                 eop_out_vld        ;
    wire [8            -1:0]   data_out        ;
    wire                 fb_vld            ;
    wire                 fb_eop            ;
    wire                 fb_cnt            ;
    
        //part2
    pkt_if_pack pkt_bus(clk, rst_n);
 
        //part3
    flow_proc   #(.DATA_WIDTH(8))
    U_flow_proc(
        .clk              (clk)        ,
        .rst_n            (rst_n)        ,
        .data_in_vld            (data_in_vld)    ,
        .sop_in_vld        (sop_in_vld)    ,
        .eop_in_vld        (eop_in_vld)    ,
        .data_in        (data_in)    ,
    
        .data_out_vld            (data_out_vld)    ,
        .sop_out_vld            (sop_out_vld)    ,
        .eop_out_vld            (eop_out_vld)    ,
        .data_out        (data_out)    ,
    
        .fb_vld            (fb_vld)    ,
        .fb_eop            (fb_eop)    ,
        .fb_cnt            (fb_cnt)
    );
        
        //part4
    assign data_in_vld = pkt_bus.pkt_in_bus.vld    ;
    assign sop_in_vld  = pkt_bus.pkt_in_bus.sop    ;
    assign eop_in_vld  = pkt_bus.pkt_in_bus.eop    ;
    assign data_in        = pkt_bus.pkt_in_bus.data    ;
 
    assign pkt_bus.pkt_out_bus.vld  = data_out_vld    ;
    assign pkt_bus.pkt_out_bus.sop  = sop_out_vld    ;
    assign pkt_bus.pkt_out_bus.eop  = eop_out_vld    ;
    assign pkt_bus.pkt_out_bus.data = data_out    ;
 
        //part5
        test u_test(pkt_bus);
例化分为四个部分,part1定义wire信号,part2例化interface(与例化module方式一致),part3例化DUT,part4将interface与module相连接,part5将interface作为接口传参传入test,实现验证环境与DUT的互连。

当然每个人有自己的代码风格,这里我写的比较繁琐,主要是这样用惯了。

继续进行,接下来是最大的改动点env(test new()也有改动,看最后的代码好啦)。

改动1.if例化改为例化一份pkt_if_pack bus(之后所有的接口增减都到pkt_if_pack里面去做),例化两份mom,channel也对应的修改下;

    virtual pkt_if_pack bus;
    pkt_gen gen;
    pkt_drv drv;
    pkt_mon in_mon;
    pkt_mon out_mon;
    pkt_chk chk;
    env_cfg cfg;
    mailbox gen2drv_chan;
    mailbox in_mon2chk_chan;
    mailbox out_mon2chk_chan;
改动2.new函数微调下;

function environment::new(input virtual pkt_if_pack bus);
    $display("At %0t, [ENV NOTE]: environment::new() start!", $time);
    this.bus = bus;
    this.cfg = new();    
    gen2drv_chan = new(1);
    in_mon2chk_chan = new(1);
    out_mon2chk_chan = new(1);
endfunction
改动3.bulid()中改变组件的连接方式,gen减少一个gen2chk channel传参,最终连接与图示一致;

task environment::build();
    $display("At %0t, [ENV NOTE]: environment::build() start!", $time);
    gen = new(cfg, gen2drv_chan);
    drv = new(cfg, this.bus.pkt_in_bus, gen2drv_chan);
    in_mon = new(cfg, this.bus.pkt_in_bus, this.in_mon2chk_chan);
    out_mon = new(cfg, this.bus.pkt_out_bus, this.out_mon2chk_chan);
    chk = new(cfg, in_mon2chk_chan, out_mon2chk_chan);    
endtask
再对照一下这个图;

改动4.微调run(),主要涉及in_mon和out_mon;

好的至此主要改动基本完成,不过别忘记调整pkt_gen内部代码,毕竟少了一个通道嘛。

最终的编译文件和编译顺序如下图:

编译完成后,run个100000ns啥的发100个包

看看波形和打印log:

太完美了!附上截至目前为止的代码,睡觉~~~

附目前为止所有文件
`include "pkt_dec.sv"
 
module top();
    
    logic clk;
    logic rst_n;
    
    initial begin
           #0ns clk = 0;
        forever #5ns clk = ~clk;
    end
        
    initial begin
        #0ns rst_n = 0;
        #225ns rst_n = 1;    
    end
 
    //`include “rtl_link”
    wire                     data_in_vld        ;
    wire                     sop_in_vld        ;
    wire                     eop_in_vld        ;
    wire [8            -1:0]   data_in            ;
    wire                     data_out_vld    ;
    wire                     sop_out_vld        ;
    wire                     eop_out_vld        ;
    wire [8            -1:0]   data_out        ;
    wire                     fb_vld            ;
    wire                     fb_eop            ;
    wire                     fb_cnt            ;
    
    pkt_if_pack pkt_bus(clk, rst_n);
 
    flow_proc   #(.DATA_WIDTH(8))
    U_flow_proc(
        .clk              (clk)                ,
        .rst_n            (rst_n)                ,
        .data_in_vld    (data_in_vld)        ,
        .sop_in_vld        (sop_in_vld)        ,
        .eop_in_vld        (eop_in_vld)        ,
        .data_in        (data_in)            ,
    
        .data_out_vld    (data_out_vld)        ,
        .sop_out_vld    (sop_out_vld)        ,
        .eop_out_vld    (eop_out_vld)        ,
        .data_out        (data_out)            ,
    
        .fb_vld            (fb_vld)            ,
        .fb_eop            (fb_eop)            ,
        .fb_cnt            (fb_cnt)
    );
 
    assign data_in_vld = pkt_bus.pkt_in_bus.vld        ;
    assign sop_in_vld  = pkt_bus.pkt_in_bus.sop        ;
    assign eop_in_vld  = pkt_bus.pkt_in_bus.eop        ;
    assign data_in        = pkt_bus.pkt_in_bus.data    ;
 
    assign pkt_bus.pkt_out_bus.vld  = data_out_vld    ;
    assign pkt_bus.pkt_out_bus.sop  = sop_out_vld    ;
    assign pkt_bus.pkt_out_bus.eop  = eop_out_vld    ;
    assign pkt_bus.pkt_out_bus.data = data_out        ;
 
    test u_test(pkt_bus);
    
endmodule
`ifndef PKT_DATA_SV
`define PKT_DATA_SV
 
class pkt_data;
 
    rand bit [7:0]   payload_q[$];
    rand int         interval;
    rand int         pkt_len;
    
    bit                 send_over;
    
    bit [10:0] data[$];
    
    constraint data_size_cons{
        payload_q.size() == pkt_len;
    };
 
    constraint pkt_len_cons{
        pkt_len inside {[1:50]};
        //pkt_len == 5;
    };
    
    constraint interval_cons{
        interval inside {[3:6]};
    };
    
    extern function new();
    extern virtual function string psprintf(string preset = "");
    extern virtual function bit compare(pkt_data to);
    extern virtual function void pack();
    extern virtual function void unpack();
    extern virtual function pkt_data copy(pkt_data to=null);
    
endclass
 
function pkt_data::new();
 
endfunction
 
function bit pkt_data::compare(pkt_data to);
    bit match = 1;
    if(this.pkt_len != to.pkt_len) match = 0;
    foreach(payload_q[i]) if(this.payload_q[i] != to.payload_q[i])
        match = 0;
    return match;
endfunction:compare
 
function void pkt_data::pack();
    foreach (this.payload_q[i]) begin
        if (i==0 & i==pkt_len-1) //modify!!!!!
            this.data.push_back({1'b1, 1'b1, 1'b1, payload_q[i]});
        else if (i==0)
            this.data.push_back({1'b1, 1'b1, 1'b0, payload_q[i]});        
        else if (i==pkt_len-1)
            this.data.push_back({1'b1, 1'b0, 1'b1, payload_q[i]});
        else
            this.data.push_back({1'b1, 1'b0, 1'b0, payload_q[i]});        
    end
    for(int i=0; i         this.data.push_front({'0});
    end
endfunction
function string pkt_data::psprintf(string preset = "");
    psprintf = {preset, $psprintf("pkt_len = %0d", pkt_len)};
    foreach(payload_q[i])
        psprintf = {psprintf, ",", $psprintf("payload[%0d] = 'h%0h", i, payload_q[i])};
endfunction
function pkt_data pkt_data::copy(pkt_data to=null);
    pkt_data tmp;
    if (to == null)
        tmp = new();
    else
        $cast(tmp, to);
    tmp.interval = this.interval;
    tmp.pkt_len  = this.pkt_len;
    tmp.send_over= this.send_over;
    foreach(this.payload_q[i])begin
        tmp.payload_q.push_back(this.payload_q[i]);
    end
    return tmp;
endfunction
function void pkt_data::unpack();
    this.pkt_len = payload_q.size();
endfunction
`endif
`ifndef ENV_CFG_SV
`define ENV_CFG_SV
 
class env_cfg;
    bit chk_idle;
    bit gen_idle;
    bit drv_idle;
    bit mon_idle;
    
    int env_wait_pkt_time = 10000;
    int mon_wait_pkt_time = 1000;
    int drv_wait_pkt_time = 1000;
    int chk_wait_pkt_time = 1000;
endclass:env_cfg
 
`endif
`include "pkt_if.sv"
`include "environment.sv"
program automatic test(pkt_if_pack bus);
    
    environment env;
    
    initial begin
        env = new(bus);
        env.build();
        env.gen.send_num = 100;
        env.run();
        $display("At %0t, [TESt NOTE]: simulation finish~~~~~~~~~~~~~~~~~~", $time);
        $finish;
    end    
endprogram
`ifndef ENV_SV
`define ENV_SV
 
`include "pkt_gen.sv"
`include "pkt_drv.sv"
`include "pkt_mon.sv"
`include "pkt_chk.sv"
`include "pkt_if.sv"
`include "env_cfg.sv"
`include "pkt_if_pack.sv"
 
class environment;
    virtual pkt_if_pack bus;
    pkt_gen gen;
    pkt_drv drv;
    pkt_mon in_mon;
    pkt_mon out_mon;
    pkt_chk chk;
    env_cfg cfg;
    mailbox gen2drv_chan;
    mailbox in_mon2chk_chan;
    mailbox out_mon2chk_chan;
    
    int send_pkt_num;    
    //for finish fimu
    int wait_time;
 
    extern function new(input virtual pkt_if_pack bus);
    extern virtual task build();
    extern virtual task run();
    extern virtual task report();    
endclass
 
function environment::new(input virtual pkt_if_pack bus);
    $display("At %0t, [ENV NOTE]: environment::new() start!", $time);
    this.bus = bus;
    this.cfg = new();    
    gen2drv_chan = new(1);
    in_mon2chk_chan = new(1);
    out_mon2chk_chan = new(1);
endfunction
 
task environment::build();
    $display("At %0t, [ENV NOTE]: environment::build() start!", $time);
    gen = new(cfg, gen2drv_chan);
    drv = new(cfg, this.bus.pkt_in_bus, gen2drv_chan);
    in_mon = new(cfg, this.bus.pkt_in_bus, this.in_mon2chk_chan);
    out_mon = new(cfg, this.bus.pkt_out_bus, this.out_mon2chk_chan);
    chk = new(cfg, in_mon2chk_chan, out_mon2chk_chan);    
endtask
    
task environment::run();
    
    fork
        drv.run();
        gen.run();
        in_mon.run();
        out_mon.run();
        chk.run();
    join_none
    
    #100;
    fork
        //$display("At %0t, [ENV NOTE]: wait for end............", $time);
        begin
            wait(cfg.gen_idle);
            wait(cfg.drv_idle);
            wait(cfg.mon_idle);
            wait(cfg.chk_idle);
            $display("At %0t, [ENV NOTE]: normal finish", $time);
        end
        begin
            while(1)begin
                @(negedge top.clk);
                if(this.bus.pkt_in_bus.vld) wait_time = 0;
                else wait_time++;
                if(wait_time > this.cfg.env_wait_pkt_time) break;
            end
            $display("At %0t, [ENV ERROR]: time out!!!!!", $time);
        end        
    join_any
    
    #1000;    
    report();
endtask
 
task environment::report();    
    $display("At %0t, [ENV NOTE]: report start", $time);
    repeat(100) @top.clk;
    chk.report();
    $display("At %0t, [ENV NOTE]: report over", $time);
endtask
`endif
`ifndef PKT_GEN_SV
`define PKT_GEN_SV
`include "pkt_data.sv"
`include "env_cfg.sv"
 
class pkt_gen;
    env_cfg cfg;
    mailbox gen2drv_chan;
    pkt_data pkt;
    int send_num;
    
    extern function new(env_cfg cfg, mailbox gen2drv_chan);
    extern virtual task run();
    
endclass
function pkt_gen::new(env_cfg cfg, mailbox gen2drv_chan);
    this.cfg = cfg;
    this.gen2drv_chan  = gen2drv_chan;
    this.pkt      = new();
endfunction
task pkt_gen::run();
    pkt_data send_pkt;
    pkt_data chk_pkt;
    
    $display("At %0t, [GEN NOTE]: send_num = %0d", $time, send_num);
    repeat(send_num) begin
        assert(pkt.randomize());
        $cast(send_pkt, pkt.copy());
        $cast(chk_pkt, pkt.copy());
        gen2drv_chan.put(send_pkt);
    end
    
    this.cfg.gen_idle = 1;
    //$display("At %0t, [GEN NOTE]: gen over pkt", $time);
endtask
`endif
`ifndef PKT_DRV_SV
`define PKT_DRV_SV
`include "pkt_data.sv"
`include "pkt_if.sv"
`include "env_cfg.sv"
 
class pkt_drv;
    env_cfg cfg;
    mailbox gen2drv_chan;
    vdrv dif;
    
    //for finish simu    
    int idle_cnt;
    
    int get_num;
    
    extern function new(env_cfg cfg,
                        vdrv dif,
                        mailbox gen2drv_chan
                        );
    extern virtual task run();
    extern virtual task my_run();
    extern virtual task rst_sig();
    extern virtual task pkt_send(input pkt_data pkt);
    extern virtual task set_idle();
 
endclass
 
function pkt_drv::new(env_cfg cfg,
                      vdrv dif,
                      mailbox gen2drv_chan
                     );
    this.cfg = cfg;
    this.dif = dif;
    this.gen2drv_chan = gen2drv_chan;
    this.get_num = 0;
endfunction
 
task pkt_drv::run();
    fork
        my_run();
        set_idle();
    join_none
endtask
 
task pkt_drv::my_run();
    pkt_data send_pkt;
    
    //$display("At %0t, [DRV NOTE]: pkt_drv run start!", $time);
    rst_sig();
    //$display("At %0t, [DRV NOTE]: after rst_n", $time);
    while(1) begin
        gen2drv_chan.peek(send_pkt);
        //$display("At %0t, [DRV NOTE]: get no.%0d pkt from gen", $time, this.get_num++);        
        send_pkt.pack();
        pkt_send(send_pkt);
        gen2drv_chan.get(send_pkt);
        rst_sig();
    end
endtask:my_run
 
task pkt_drv::rst_sig();
    wait(top.rst_n == 1'b1);
    @(posedge top.clk);
    this.dif.vld <= '0;
    this.dif.sop <= '0;
    this.dif.eop <= '0;
    this.dif.data<= '0;
endtask
 
task pkt_drv::pkt_send(input pkt_data pkt);
    foreach(pkt.data[i]) begin
        @(posedge top.clk);
        this.dif.vld <= pkt.data[i][10];
        this.dif.sop <= pkt.data[i][9];
        this.dif.eop <= pkt.data[i][8];
        this.dif.data<= pkt.data[i][7:0];
    end    
endtask
 
task pkt_drv::set_idle();
    while(1)begin
        @(negedge top.clk);
        if(this.dif.vld == 1) idle_cnt = 0;
        else idle_cnt++;
        if(idle_cnt > this.cfg.drv_wait_pkt_time) this.cfg.drv_idle = 1;
        else this.cfg.drv_idle = 0;
    end
endtask:set_idle
 
`endif
`ifndef PKT_MON_SV
`define PKT_MON_SV
 
`include "pkt_data.sv"
`include "pkt_if.sv"
`include "env_cfg.sv"
 
class pkt_mon;
    env_cfg cfg;
    vmon mif;
    mailbox mon2chk_chan;
    bit rec_status;//0:wait sop, 1:wait eop
    int wait_pkt_time = 1000;
    
    extern function new(env_cfg cfg,
                        vmon mif,
                        mailbox mon2chk_chan);
    extern virtual task run();
    extern virtual task send_chk(pkt_data pkt);
endclass
 
function pkt_mon::new(env_cfg cfg,
                      vmon mif,
                      mailbox mon2chk_chan
                     );
    this.cfg = cfg;
    this.mif = mif;
    this.mon2chk_chan = mon2chk_chan;
    this.wait_pkt_time = cfg.mon_wait_pkt_time;
    this.rec_status = 0;
endfunction : new
 
task pkt_mon::run();
    pkt_data  rec_pkt;
    int       wait_time;
    int          i = 0;
    
    //$display("At %0t, [MON NOTE]: run start!", $time);
    while(1) begin
        while(1) begin
            @(posedge top.clk);
            if(mif.vld == 1)begin
                wait_time = 0;
                if(rec_status == 0) begin//wait sop
                    rec_pkt = new();
                    if(mif.sop == 0) begin
                        $display("At %0t, [MON ERROR]: ERROR! The first pkt cycle is not sop!", $time);
                        break;
                    end
                    else begin
                        rec_pkt.payload_q.push_back(mif.data);
                        if(mif.eop == 1) begin
                            rec_status = 0;
                            //$display("At %0t, [MON NOTE]: get no.%0d pkt!", $time, i++);
                            send_chk(rec_pkt);
                        end
                        else
                            rec_status = 1;
                    end
                end
                else if(rec_status == 1) begin//wait eop
                    if(mif.sop == 1) begin
                        $display("At %0t, [MON ERROR]: ERROR! SOP????", $time);
                        break;
                    end
                    else begin
                        rec_pkt.payload_q.push_back(mif.data);
                        if(mif.eop == 1) begin
                            rec_status = 0;
                            //$display("At %0t, [MON NOTE]: get no.%0d pkt!", $time, i++);
                            send_chk(rec_pkt);
                        end
                        else
                            rec_status = 1;
                    end
                end
            end
            else begin
                wait_time++;
                if(wait_time <= wait_pkt_time) begin
                    wait_time++;
                end
                else break;
            end
        end
        this.cfg.mon_idle = 1;
        //$display("At %0t, [MON NOTE]: mon run over!", $time);
        break;
    end
endtask : run
    
task pkt_mon::send_chk(pkt_data pkt);
    pkt.unpack();
    mon2chk_chan.put(pkt);
endtask : send_chk    
`endif
 
 
 
 
 
 
 
`ifndef PKT_CHK_SV
`define PKT_CHK_SV
 
`include "pkt_data.sv"
`include "env_cfg.sv"
 
class pkt_chk;
    env_cfg cfg;
    pkt_data expect_q[$];
    int in_expect, in_actual;
    int match, not_match;
    mailbox gen2chk_chan;
    mailbox mon2chk_chan;
    
    //for finish simu
    int idle_cnt;
    
    extern function new(env_cfg cfg, 
                        mailbox gen2chk_chan, 
                        mailbox mon2chk_chan);
    extern virtual task run();
    extern virtual task expect_gain();
    extern virtual task actual_gain();
    extern virtual task set_idle();
    extern virtual function report();
 
endclass:pkt_chk
function pkt_chk::new(env_cfg cfg, 
                      mailbox gen2chk_chan, 
                      mailbox mon2chk_chan);
    this.cfg = cfg;
    this.gen2chk_chan = gen2chk_chan;
    this.mon2chk_chan = mon2chk_chan;
endfunction:new
 
task pkt_chk::run();
    fork
        expect_gain();
        actual_gain();
        set_idle();
    join_none
endtask:run
task pkt_chk::expect_gain();
    pkt_data expect_data;
    while(1) begin
        gen2chk_chan.get(expect_data);
        this.expect_q.push_back(expect_data);
        in_expect++;
        idle_cnt = 0;
        //$display("At %0t, [CHK NOTE]: get a expect pkt", $time);
    end
endtask:expect_gain
task pkt_chk::actual_gain();
    pkt_data expect_data;
    pkt_data actual_data;
    while(1) begin
        mon2chk_chan.get(actual_data);
        in_actual++;
        idle_cnt = 0;
        if(this.expect_q.size == 0) $display("At %0t, [CHK ERROR]: expect_q==0???", $time);
        else begin
            expect_data = expect_q[0];
            if(!expect_data.compare(actual_data)) begin
                $display("At %0t, [CHK ERROR]: no match, \nexpect data:%s \nactual data:%s ", $time, expect_data.psprintf(), actual_data.psprintf());
                expect_q.pop_front();
                not_match++;
            end
            else begin
                expect_q.pop_front();
                //$display("At %0t, [CHK NOTE]: match, \nexpect data:%s \nactual data:%s ", $time, expect_data.psprintf(), actual_data.psprintf());
                match++;
            end
        end
    end
endtask:actual_gain
task pkt_chk::set_idle();
    while(1)begin
        @(negedge top.clk);
        idle_cnt++;
        if(idle_cnt > this.cfg.chk_wait_pkt_time) this.cfg.chk_idle = 1;
        else this.cfg.chk_idle = 0;
    end
endtask:set_idle
function pkt_chk::report();
    $display("----------------------------------------------------------------------------------------------------");
    $display("[CHECKER REPORT]expect pkt_num=%0d, actual pkt_num=%0d, match pkt_num=%0d, not match pkt_num=%0d", in_expect, in_actual, match, not_match);
    $display("----------------------------------------------------------------------------------------------------");
endfunction:report
 
`endif
`ifndef PKT_IF_SV
`define PKT_IF_SV
 
interface pkt_if(input clk, rst_n);
        
    logic [7:0] data;
    logic         sop;
    logic        eop;
    logic        vld;
    
    clocking drv @(posedge clk);
        output     data;
        output    sop, eop, vld;
    endclocking : drv
    modport pkt_drv (clocking drv);
    
    clocking mon @(posedge clk);
        input     data;
        input    sop, eop, vld;
    endclocking : mon
    modport pkt_mon (clocking mon);
    
endinterface
 
typedef virtual pkt_if.drv vdrv;
typedef virtual pkt_if.mon vmon;
 
`endif
`ifndef FLOW_PROC_V
`define FLOW_PROC_V
 
module flow_proc #(
    parameter DATA_WIDTH = 8
)(
    input                        clk                ,
    input                        rst_n            ,
    input                        data_in_vld        ,
    input                        sop_in_vld        ,
    input                        eop_in_vld        ,
    input  [DATA_WIDTH-1:0]        data_in            ,
    
    output reg                    data_out_vld    ,
    output reg                    sop_out_vld        ,
    output reg                    eop_out_vld        ,
    output reg [DATA_WIDTH-1:0]    data_out        ,
    
    output                        fb_vld            ,
    output                        fb_eop            ,
    output                        fb_cnt            
);
 
    reg                        data_out_vld_ff1    ;
    reg                        sop_out_vld_ff1        ;
    reg                        eop_out_vld_ff1        ;
    reg [DATA_WIDTH-1:0]    data_out_ff1        ;
    
    always @(posedge clk) begin
        if(rst_n == 1'b0)begin
            data_out_vld_ff1 <= 1'b0;
            sop_out_vld_ff1  <= 1'b0;
            eop_out_vld_ff1  <= 1'b0;
            data_out_ff1     <= {DATA_WIDTH{1'b0}};
        end
        else begin
            data_out_vld_ff1 <= data_in_vld;
            sop_out_vld_ff1  <= sop_in_vld;
            eop_out_vld_ff1  <= eop_in_vld;
            data_out_ff1     <= data_in;
        end
    end
 
    always @(posedge clk) begin
        if(rst_n == 1'b0)begin
            data_out_vld <= 1'b0;
            sop_out_vld  <= 1'b0;
            eop_out_vld  <= 1'b0;
            data_out     <= {DATA_WIDTH{1'b0}};
        end
        else begin
            data_out_vld <= data_out_vld_ff1;
            sop_out_vld <= sop_out_vld_ff1;
            eop_out_vld <= eop_out_vld_ff1;
            data_out <= data_out_ff1;
        end
    end    
    
endmodule
 
`endif
 

`include "pkt_if.sv"
 
`ifndef PKT_INTERFACE_SV
`define PKT_INTERFACE_SV
 
interface pkt_if_pack(
    input logic        clk        ,
    input logic        rst_n
    );
    
    pkt_if        pkt_in_bus    (clk, rst_n);
    pkt_if        pkt_out_bus (clk, rst_n);
    
endinterface : pkt_if_pack
 
//class pkt_interface;
 
//    virtual pkt_if pkt_in_bus  = pkt_if_pack.pkt_in_bus;
//    virtual pkt_if pkt_out_bus = pkt_if_pack.pkt_out_bus;
    
//endclass : pkt_interface
 
`endif
 
 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/598067
推荐阅读
相关标签
  

闽ICP备14008679号