sv实验2

验证框架

 

 

 

 1.接口的使用

 

 1.1-1.2

复制代码
interface chnl_intf(input clk, input rstn);
  logic [31:0] ch_data;
  logic        ch_valid;
  logic        ch_ready;
  logic [ 5:0] ch_margin;
  clocking drv_ck @(posedge clk);
    default input #1ns output #1ns;
    output ch_data, ch_valid;
    input ch_ready, ch_margin;
  endclocking
endinterface

module chnl_initiator(chnl_intf intf);
  string name;
  int idle_cycles = 1;
  function automatic void set_idle_cycles(int n);
    idle_cycles = n;
  endfunction
  function automatic void set_name(string s);
    name = s;
  endfunction
  task automatic chnl_write(input logic[31:0] data);
    @(posedge intf.clk);
    // USER TODO 1.1
    // Please use the clocking drv_ck of chnl_intf to drive data
    intf.drv_ck.ch_valid <= 1;
    intf.drv_ck.ch_data <= data;
    //intf.ch_valid <= 1;
    //intf.ch_data <= data;
    @(negedge intf.clk);
    wait(intf.ch_ready === 'b1);
    $display("%t channel initiator [%s] sent data %x", $time, name, data);
    // USER TODO 1.2
    // Apply variable idle_cycles and decide how many idle cycles to be
    // inserted between two sequential data
    repeat(idle_cycles) chnl_idle();
  endtask
  task automatic chnl_idle();
    @(posedge intf.clk);
    // USER TODO 1.1
    // Please use the clocking drv_ck of chnl_intf to drive data
    intf.drv_ck.ch_valid <= 0;
    intf.drv_ck.ch_data <= 0;
    //intf.ch_valid <= 0;
    //intf.ch_data <= 0;
  endtask
endmodule
复制代码

 

 加入时钟延迟后,valid和data与clk存在1ns的延迟,方便分析波形。

在initiator模块中引入set_idle_cycles函数灵活设置空闲周期。

仿真的结束

 

 2.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("burst_test initialized components");
    wait (rstn === 1'b1);
    repeat(5) @(posedge clk);
    $display("burst_test started testing DUT");
    // Please check the SV book for fork-join basic knowledge
    // and get understood it is for parallel thread running
    fork
      repeat(500) chnl0_init.chnl_write(chnl0_gen.get_data());
      repeat(500) chnl1_init.chnl_write(chnl1_gen.get_data());
      repeat(500) chnl2_init.chnl_write(chnl2_gen.get_data());
    join
    $display("burst_test finished testing DUT");
  endtask
复制代码
复制代码
 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($urandom_range(1, 3));
    chnl1_init.set_idle_cycles($urandom_range(1, 3));
    chnl2_init.set_idle_cycles($urandom_range(1, 3));
    $display("fifo_full_test initialized components");
    wait (rstn === 1'b1);
    repeat(5) @(posedge clk);
    $display("fifo_full_test started testing DUT");
    // Please check the SV book for fork-join basic knowledge
    // and get understood it is for parallel thread running
    fork
      repeat(100) chnl0_init.chnl_write(chnl0_gen.get_data());
      repeat(100) chnl1_init.chnl_write(chnl1_gen.get_data());
      repeat(100) chnl2_init.chnl_write(chnl2_gen.get_data());
    join_none
    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 finished testing DUT");
  endtask
复制代码

1.SV中数据的生命周期分为动态(automatic)和静态(static)。class中成员和方法默认为automatic,program、module、interface、package中函数和任务和变量默认为静态的。

在讨论静态变量和动态变量之前,我们先说全局变量和局部变量的概念。

局部变量的生命周期同其所在域,例如function/task中的变量,在方法调用结束后,这些变量的也将消失,所以它们是动态生命周期;
全局变量是从仿真开始到结束一直存在的,例如module中的变量默认情况下全部为全局变量,这也可以理解为module中的变量是硬件电路中实际存在的信号和连接,所以它们是静态生命周期
此处module中的方法默认为静态,所以需要加上automatica

2.fork-join中的线程会同时进行,且全部执行完毕后顺序执行下面的语句。fork-join_none中的线程会同时进行,但不会等待其执行完毕,会直接执行下面的语句。

3.类的例化和类的成员

3.1-3.2

复制代码
initial begin 
    // USER TODO 3.1
    // instantiate the components chn0/1/2_init chnl0/1/2_gen
    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);
    // USER TODO 3.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);
    // USER TODO 3.3
    // START TESTs
    $display("*****************all of tests have been finished********************");
    basic_test();
    burst_test();
    fifo_full_test();
   $finish();
  end
复制代码

 

 4.包的定义和类的继承

 

 

 4.1

import chnl_pkg::*;

4.2

复制代码
  class chnl_root_test;
    chnl_agent agent[3];
    protected string name;
    function new(int ntrans = 100, string name = "chnl_root_test");
      foreach(agent[i]) begin
        this.agent[i] = new($sformatf("chnl_agent%0d",i), i, ntrans);
      end
      this.name = name;
      $display("%s instantiate objects", this.name);
    endfunction
    task run();
      $display("%s started testing DUT", this.name);
      fork
        agent[0].run();
        agent[1].run();
        agent[2].run();
      join
      $display("%s waiting DUT transfering all of data", this.name);
      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
    function void set_interface(virtual chnl_intf ch0_vif, virtual chnl_intf ch1_vif, virtual chnl_intf ch2_vif);
      agent[0].set_interface(ch0_vif);
      agent[1].set_interface(ch1_vif);
      agent[2].set_interface(ch2_vif);
    endfunction
  endclass

  // each channel send data with idle_cycles inside [1:3]
  // each channel send out 200 data
  // then to finish the test
  class chnl_basic_test extends chnl_root_test;
    function new(int ntrans = 200, string name = "chnl_basic_test");
      super.new(ntrans, name);
      foreach(agent[i]) begin
        this.agent[i].init.set_idle_cycles($urandom_range(1, 3));
      end
      $display("%s configured objects", this.name);
    endfunction
  endclass: chnl_basic_test

  // USER TODO 4.2
  // Refer to chnl_basic_test, and extend another 2 tests
  // chnl_burst_test, chnl_fifo_full_test
  // each channel send data with idle_cycles == 0
  // each channel send out 500 data
  // then to finish the test
  class chnl_burst_test extends chnl_root_test;
    //USER TODO
    function new(int ntrans = 500, string name = "chnl_burst_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
  endclass: chnl_burst_test

  class chnl_fifo_full_test extends chnl_root_test;
    // USER TODO
    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
      $display("%s: 3 agents running now", this.name);

      $display("%s: waiting 3 channel fifos to be full", this.name);
      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;
      $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);
      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
复制代码

4.3-4.4-4.5

例化3个test;传递接口;调用test

复制代码
 initial begin 
    basic_test = new();
    burst_test = new();
    fifo_full_test = new();

    // USER TODO 4.4
    // assign the interface handle to each chnl_initiator objects
    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);

    // USER TODO 4.5
    // START TESTs
    @(posedge rstn); repeat(10) @(posedge clk);
    basic_test.run(); 
    burst_test.run();
    fifo_full_test.run();
    $display("*****************all of tests have been finished********************");
    $finish();
  end
复制代码

 

posted @   继续加仓  阅读(93)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示