SV中虚拟接口的作用及仿真

        验证的环境可以分为软件和硬件两部分,分别对应动态和静态。接口更加偏向于硬件的module,在硬件世界中实例化。

虚接口的必要性

        在验证环境中,硬件部分(DUT和Interface)属于静态范畴,意味着在编译的时候就要被分配内存进行初始化;软件部分(class)属于动态范畴,在仿真运行时才会被分配空间初始化。二者之间的关系类似动态变量和静态变量。

        由此会产生的问题是:当在class中调用接口与DUT链接时时,如果不加virtual关键字,则意味着在编译的时候就要为接口开辟内存初始化,而编译的时候,作为软件部分的class是不会被分配空间的。因此导致矛盾的出现(通俗说法:妈妈还没出生,孩子先出生了)

        因此,为了解决矛盾,需要将class中的接口声明为virtual,将物理的接口替换为句柄,编译时不占用内存空间,在仿真跑起来的时候再传入接口实例,从而解决冲突。

        就像绿皮书中说的:“虚接口是唯一链接动态对象和静态模块、接口的一种机制”。

虚接口的作用

        为了方便的将软件世界的tb产生的激励输送给硬件module,需要一个媒介,即虚拟接口,本质上是一个指向硬件接口的指针,即是物理接口的句柄

仿真代码:

class transaction;//用rand来生成随机化激励
  rand logic load_valid;
  rand logic [3:0] load_value;
endclass

class driver;
  virtual counter_if vif;//生成一个virtual interface句柄
  function new(input virtual counter_if vif);//该new函数用来使虚接口句柄指向interface
    this.vif=vif;
  endfunction
 
  transaction tr;
  task run(int n);//产生n次激励
    for(int i=0;i<n;i++)begin
      tr=new;
      assert(tr.randomize());//
      $display("tr.load_valid=%0d,tr.load_value=%0d",tr.load_valid,tr.load_value);
      @(posedge vif.clk)begin//在clk上升沿,通过虚接口将transaction中的随机激励传送到interface上
        vif.load_valid<=tr.load_valid;
        vif.load_value<=tr.load_value;
      end
    end
  endtask
endclass
module tb_top;
  logic clk,rstn;
  logic[3:0]q;
  
  counter_if dutif(clk);//实例化interface
  driver my_driver;//声明句柄
  counter u_counter(.resetn(rstn),
                    .clk(clk),
                    .load_valid(dutif.load_valid),
                    .load_value(dutif.load_value),
                    .q(out));//实例化DUT
 
  initial begin
    my_driver=new(dutif);//实例化驱动,使虚接口句柄指向interface
    repeat(2) @(posedge clk);
    @(posedge rstn);
    repeat(5) @(posedge clk);
    my_driver.run(20);//产生20次随机激励
  end
 
  initial begin//生成T=10的时钟
    clk=1'b0;
    forever #5 clk=~clk;
  end
  initial begin//复位信号的生成
    rstn=1;repeat(2) @(posedge clk);
    rstn=0;repeat(5) @(posedge clk);
    rstn=1;repeat(50) @(posedge clk);
    $finish;
  end
endmodule

interface counter_if(input logic clk);
  logic load_valid;
  logic [3:0] load_value;
endinterface

module counter(input clk,resetn,
               input [3:0] load_value,
               input load_valid,
               output reg [3:0] q);
  always@(posedge clk or negedge resetn)begin
    if(!resetn)
      q<=4d'0;
    else if(load_valid)
      q<=load_value;
    else
      q<=q+4'd1; 
  end
endmodule

仿真详细流程:

在Linux终端中依次输入以下命令启动VCS:

vcs -full64 -kb -debug_access+all -sverilog 文件名

/.simv -gui

在VCS的dve中依次输入以下命令启动仿真:

dump -deltaCycle on

run

仿真输出如下:

仿真波形如下:

我对于counter计数到6的这个时钟上升沿有疑问,不确定在这个posedge clk边沿,counter会执行q<=q+4'd1,还是q<=load_value。因此,调用Delta Cycle查看

结果如下:

可见,在该时钟上升沿,q的+1操作先于load_value的变化,因此counter会在当前clk周期变为6,在下一个clk上升沿变为12(load_value的值)。

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值