【SV练习】MCDF实验2

系统框图:

知识点回顾:

 default input #1ns output #1ns;

input #1 的含义是:当tb采样dut的输出信号时,会采用时钟边沿信号的#1 之前的信号,此处应该注意的是 tb的input信号是由dut的输出信号驱动的,而dut的输出是理想的信号,不存在延迟#1。

output #1 的含义是:tb 输出信号(驱动dut)时会延迟#1。

总体上会使得输出相对于时钟上升沿有一个时钟单位的延迟,但是输入不会有一个单位的超前。

fork jion:全部执行完毕,才会继续执行;

fork join_none:执行子程序的时候,父线程也会继续执行;

fork jion_any:任一语句执行完毕,就会继续执行父线程;

1接口的使用:

使用intf.ck来驱动数据,发现在时钟上升沿的1ns后才接收数据。

设置空闲周期:

 function automatic void set_idle_cycles(int n);
    idle_cycles = n;
//.........................................
 repeat(idle_cycles) chnl_idle();

 存在空闲周期且分别设为0、1、2

2仿真的结束: 

  task automatic burst_test();
    // verification component initializationi
    chnl0_gen.initialize(0);
    chnl1_gen.initialize(1);
    chnl2_gen.initialize(2);
    chnl0_init.set_name("chnl0_init");
    chnl1_init.set_name("chnl1_init");
    chnl2_init.set_name("chnl2_init");
    chnl0_init.set_idle_cycles(0);
    chnl1_init.set_idle_cycles(0);
    chnl2_init.set_idle_cycles(0);
    $display("basic_test initialized components");
    wait (rstn === 1'b1);
    repeat(5) @(posedge clk);
    $display("basic_test started testing DUT");
    // Please check the SV book for fork-join basic knowledge
    // and get understood it is for parallel thread running
    fork
      begin
	    repeat(500) chnl0_init.chnl_write(chnl0_gen.get_data());
		chnl0_init.chnl_idle();
	  end
      begin
	    repeat(500) chnl1_init.chnl_write(chnl1_gen.get_data());
		chnl1_init.chnl_idle();
	  end
	  begin
	    repeat(500) chnl2_init.chnl_write(chnl2_gen.get_data());
		chnl2_init.chnl_idle();
	  end
    join
	fork
      wait(chnl0_init.intf.ch_margin == 'h20);
      wait(chnl1_init.intf.ch_margin == 'h20);
      wait(chnl2_init.intf.ch_margin == 'h20);
    join
    $display("basic_test finished testing DUT");
  endtask

burst_test部分代码主要模仿,最后结束测试的的代码,利用fork join语句块书写,只要三个chnl_initiator都变满了,就停止仿真,变满不需要同时。

task automatic fifo_full_test();
    // verification component initializationi
    chnl0_gen.initialize(0);
    chnl1_gen.initialize(1);
    chnl2_gen.initialize(2);
    chnl0_init.set_name("chnl0_init");
    chnl1_init.set_name("chnl1_init");
    chnl2_init.set_name("chnl2_init");
    chnl0_init.set_idle_cycles(0);
    chnl1_init.set_idle_cycles(0);
    chnl2_init.set_idle_cycles(0);
    $display("fifo_full_test started testing DUT");
    fork: fork_all_run
	  forever chnl0_init.chnl_write(chnl0_gen.get_data());
	  forever chnl1_init.chnl_write(chnl1_gen.get_data());
	  forever chnl2_init.chnl_write(chnl2_gen.get_data());
    join_none
    $display("fifo_full_test: 3 initiators running now");

    $display("fifo_full_test: waiting 3 channel fifos to be full");
    fork
      wait(chnl0_init.intf.ch_margin == 0);
      wait(chnl1_init.intf.ch_margin == 0);
      wait(chnl2_init.intf.ch_margin == 0);
    join
    $display("fifo_full_test: 3 channel fifos have reached full");

    $display("fifo_full_test: stop 3 initiators running");
    disable fork_all_run;
    $display("fifo_full_test: set and ensure all agents' initiator are idle state");
    fork
      chnl0_init.chnl_idle();
      chnl1_init.chnl_idle();
      chnl2_init.chnl_idle();
    join

    $display("fifo_full_test waiting DUT transfering all of data");
    fork
      wait(chnl0_init.intf.ch_margin == 'h20);
      wait(chnl1_init.intf.ch_margin == 'h20);
      wait(chnl2_init.intf.ch_margin == 'h20);
    join
    $display("fifo_full_test: 3 channel fifos have transferred all data");

    $display("fifo_full_test finished testing DUT");
  endtask

3:类的例化和类的成员:

主要是module中的数据转移到了class里面,两部分代码比较。module可以直接传递接口,但是class需要用set_interface把接口指针传递到组件里面,组件是在module里面例化,在class里面是在initial里面实例化。

  initial begin 
    basic_test(); 
    burst_test();
    fifo_full_test();
    $display("*****************all of tests have been finished********************");
    $finish();
  end
//...........................
  chnl_initiator chnl0_init(chnl0_if);
  chnl_initiator chnl1_init(chnl1_if);
  chnl_initiator chnl2_init(chnl2_if);

  chnl_generator chnl0_gen();
  chnl_generator chnl1_gen();
  chnl_generator chnl2_gen();
 initial begin 

	chnl0_init = new("chnl0_init");
	chnl1_init = new("chnl1_init");
	chnl2_init = new("chnl2_init");
	chnl0_gen = new(0);
	chnl1_gen = new(1);
	chnl2_gen = new(2);

    // assign the interface handle to each chnl_initiator objects
	chnl0_init.set_interface(chnl0_if);
	chnl1_init.set_interface(chnl1_if);
	chnl2_init.set_interface(chnl2_if);

    $display("*****************all of tests have been finished********************");
    basic_test();
	burst_test();
	fifo_full_test();
	$finish();
  end

4包的定义和类的继承:

tb3和tb4的最大区别是多了一个agent,agent包含了generator和initiator


  class chnl_fifo_full_test extends chnl_root_test;
    function new(int ntrans = 1_000_000, string name = "chnl_fifo_full_test");
      super.new(ntrans, name);
      foreach(agent[i]) begin
        this.agent[i].init.set_idle_cycles(0);
      end
      $display("%s configured objects", this.name);
    endfunction
	
    task run();									//开始结束都会打印信息。
      $display("%s started testing DUT", this.name);
      fork: fork_all_run
        agent[0].run();
        agent[1].run();
        agent[2].run();
      join_none														//运行三个agent,join_none会继续执行父线程,不必等待任何一个子线程。
      $display("%s: 3 agents running now", this.name);

      $display("%s: waiting 3 channel fifos to be full", this.name);	//三个fifo为满的时候,单个都拉低过的时候就结束测试,不是同时,打印信息。
      fork
        wait(agent[0].vif.ch_margin == 0);
        wait(agent[1].vif.ch_margin == 0);
        wait(agent[2].vif.ch_margin == 0);
      join
      $display("%s: 3 channel fifos have reached full", this.name);

      $display("%s: stop 3 agents running", this.name);
      disable fork_all_run;									//disable会杀死所有的进程
      $display("%s: set and ensure all agents' initiator are idle state", this.name);
      fork
        agent[0].init.chnl_idle();
        agent[1].init.chnl_idle();
        agent[2].init.chnl_idle();
      join

      $display("%s waiting DUT transfering all of data", this.name);	//容量分别到达32个的时候,打印信息,已经传输全部信息,把那个结束测试DUT
      fork
        wait(agent[0].vif.ch_margin == 'h20);
        wait(agent[1].vif.ch_margin == 'h20);
        wait(agent[2].vif.ch_margin == 'h20);
      join
      $display("%s: 3 channel fifos have transferred all data", this.name);

      $display("%s finished testing DUT", this.name);
    endtask
  endclass: chnl_fifo_full_test

endpackage: chnl_pkg


module tb4_ref;
  logic         clk;
  logic         rstn;
  logic [31:0]  mcdt_data;
  logic         mcdt_val;
  logic [ 1:0]  mcdt_id;
  
  mcdt dut(
     .clk_i       (clk                )
    ,.rstn_i      (rstn               )
    ,.ch0_data_i  (chnl0_if.ch_data   )
    ,.ch0_valid_i (chnl0_if.ch_valid  )
    ,.ch0_ready_o (chnl0_if.ch_ready  )
    ,.ch0_margin_o(chnl0_if.ch_margin )
    ,.ch1_data_i  (chnl1_if.ch_data   )
    ,.ch1_valid_i (chnl1_if.ch_valid  )
    ,.ch1_ready_o (chnl1_if.ch_ready  )
    ,.ch1_margin_o(chnl1_if.ch_margin )
    ,.ch2_data_i  (chnl2_if.ch_data   )
    ,.ch2_valid_i (chnl2_if.ch_valid  )
    ,.ch2_ready_o (chnl2_if.ch_ready  )
    ,.ch2_margin_o(chnl2_if.ch_margin )
    ,.mcdt_data_o (mcdt_data          )
    ,.mcdt_val_o  (mcdt_val           )
    ,.mcdt_id_o   (mcdt_id            )
  );
  
  // clock generation
  initial begin 
    clk <= 0;
    forever begin
      #5 clk <= !clk;
    end
  end
  
  // reset trigger
  initial begin 
    #10 rstn <= 0;
    repeat(10) @(posedge clk);
    rstn <= 1;
  end

  // import defined class from chnl_pkg
  import chnl_pkg::*;

  chnl_intf chnl0_if(.*);
  chnl_intf chnl1_if(.*);
  chnl_intf chnl2_if(.*);

  chnl_basic_test basic_test;
  chnl_burst_test burst_test;
  chnl_fifo_full_test fifo_full_test;

  initial begin 
    basic_test = new();
    burst_test = new();
    fifo_full_test = new();

    basic_test.set_interface(chnl0_if, chnl1_if, chnl2_if);
    burst_test.set_interface(chnl0_if, chnl1_if, chnl2_if);
    fifo_full_test.set_interface(chnl0_if, chnl1_if, chnl2_if);

    basic_test.run(); 
    burst_test.run();
    fifo_full_test.run();
    $display("*****************all of tests have been finished********************");
    $finish();
  end

endmodule

软件环境的运行离不开以下三个方面,创建组件、传递接口和运行

对于接口的传递,简单来说就是set_interface往上对接channel的interface,往下对接agent的interface,然后对接initiator中的数据。

验证结构参考:【SV】MCDF实验2 验证结构_呼呼而已的博客-CSDN博客_mcdf实验

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值