参数化的Interfaces和可重用VIP(2/3)

本篇是讨论SystemVerilog接口和接口参数化处理策略的三部分系列的第二部分。

在本系列的第一部分中,介绍了SystemVerilog接口的基本概念,并介绍了接口的参数化会给测试平台代码带来的问题。这篇文章将描述这个问题的一个可能的解决方法,但是要付出一定的代价...

特洛伊木马:偷袭方法

虚拟接口不支持多态,因为它们与静态设计元素相关联。但是,SystemVerilog类确实支持多态,这个事实可用于创建接口访问器类。

创建一个虚拟类,声明用于在SystemVerilog接口上执行特定操作的纯虚访问方法。然后,参数化类拓展此类以执行对强类型接口的实际访问。VIP代码仅与非参数化的基本访问器类进行交互,因此不需要对VIP代码进行参数化以使用强类型接口。测试平台必须设置强类型访问器类并将其传递给VIP,但在此之后,可以执行与VIP的所有交互,而无需参数化VIP。以下代码段演示了如何设置它。

首先,我们定义参数化虚拟接口,它与上一篇文章代码段中使用的接口相同:

interface param_if#(int width = 8);
  logic clk;
  logic[width-1:0] data;
 
  clocking active_cb @(posedge clk);
    default input #1 output #1;
    output data;
  endclocking
 
  modport active_mp (clocking active_cb);
endinterface
 
typedef virtual param_if param_vif

接下来,我们定义非参数化接口访问类和参数化的扩展类,以使用参数化接口:

//=======================================================================
virtual class port_wrapper extends uvm_object;
  pure virtual task do_write(logic[31:0] data);
  pure virtual task do_read(output logic[31:0] data);
  pure virtual task sync_driver_cb();
endclass
 
//=======================================================================
class port_wrapper_typed#(type vif_t=param_vif) extends port_wrapper;
  vif_t vif;
 
  function new(vif_t vif);
    this.vif = vif;
  endfunction
 
  virtual task do_write(logic[31:0] data);
    vif.active_cb.data <= data;
  endtask
 
  virtual task do_read(output logic[31:0] data);
    data = vif.active_cb.data;
  endtask
 
  virtual task sync_driver_cb();
    @(vif.active_cb);
  endtask
 
endclass

在此之后,实现VIP代码以使用此访问者类而不是直接访问虚拟接口。下面的代码段展示了驱动程序和代理类,并演示了必须使用访问方法的各个位置。有关此VIP代码的一点需要注意的是,它通过config DB而不是接口接受非参数化的访问者类:

  //=======================================================================
  class cust_driver extends uvm_driver#(cust_data);
    `uvm_component_utils(cust_driver)
 
    port_wrapper port;
 
    task consume_from_seq_item_port();
      forever begin
        seq_item_port.get_next_item(req);
        port.do_write(req.data);
        port.sync_driver_cb();
…
    task sample_signals();
      forever begin
        bit[31:0] sampled_data;
 
        port.do_read(sampled_data);
        port.sync_driver_cb();
…
    function void build_phase(uvm_phase phase);
      if (!uvm_config_db#(port_wrapper)::get(this, "", "port", port))
        `uvm_fatal("build", "A valid port wrapper was not received.");
…
 
  //=======================================================================
  class cust_agent extends uvm_agent;
    `uvm_component_utils(cust_agent)
 
    cust_driver driver;
 
    function void build_phase(uvm_phase phase);
      port_wrapper port;
 
      if (!uvm_config_db#(port_wrapper)::get(this, "", "port", port))
        `uvm_fatal("build", "A valid port wrapper was not received.");
 
      uvm_config_db#(port_wrapper)::set(this, "driver", "port", port);
      driver = cust_driver::type_id::create("driver", this);
…

 

最后,介绍测试平台代码。测试用例可以在不参数化的情况下访问VIP,但是实例化接口的顶层模块必须实现一些额外的步骤。它不仅必须实例化参数化接口,还必须创建参数化接口访问者类并将其传递给VIP实例:

//=======================================================================
class cust_test extends uvm_test;
  `uvm_component_utils(cust_test)
 
  cust_agent agent8;
  cust_agent agent16;
  cust_agent agent32;
 
  virtual function void build_phase(uvm_phase phase);
    agent8 = cust_agent::type_id::create("agent8", this)
    agent16 = cust_agent::type_id::create("agent16", this);
    agent32 = cust_agent::type_id::create("agent32", this);
  endfunction
endclass
 
//=======================================================================
module test_top;
  param_if#(8) if8();
  param_if#(16) if16();
  param_if#(32) if32();
 
  initial begin
    port_wrapper_typed#(virtual param_if#(8)) port_wrapper8;
    port_wrapper_typed#(virtual param_if#(16)) port_wrapper16;
    port_wrapper_typed#(virtual param_if#(32)) port_wrapper32;
 
    port_wrapper8 = new(if8);
    port_wrapper16 = new(if16);
    port_wrapper32 = new(if32);
 
    uvm_config_db#(port_wrapper)::set(uvm_root::get(), "uvm_test_top.agent8", "port", port_wrapper8);
    uvm_config_db#(port_wrapper)::set(uvm_root::get(), "uvm_test_top.agent16", "port", port_wrapper16);
    uvm_config_db#(port_wrapper)::set(uvm_root::get(), "uvm_test_top.agent32", "port", port_wrapper32);
 
    run_test("cust_test");
  end
endmodule

如您所见,此解决方案确实解决了参数化接口的使用模型问题。创建正确类型的端口包装器需要一些额外的代码,但是测试平台编写者可以访问使用不同专用接口的代理,而无需知道这些接口是如何规范化的。

但是,该解决方案对VIP如何利用虚拟接口施加了严格的限制。驱动程序和监视器类不能直接与接口交互,而必须将这些访问推迟到强类型包装类。通过将驱动程序和监视器类的大部分功能移动到强类型包装类,可以抵消这种生产力损失; 然而,这种更复杂的结构可能会造成混淆并且不够灵活。上面的代码段只显示了驱动程序类可能需要的一些访问方法,但在实际环境中,此列表有可能增长许多倍,监视器类也需要一整套访问者方法。

经过反思,蛮力方法和特洛伊木马处理参数化接口的方法都不是理想的。使用前一种方法,向类添加参数使VIP的使用模型复杂化。使用后一种方法,必须提前规划接口包装器类支持的访问方法,并限制对虚拟接口的VIP访问。如果VIP代码可以启用与参数化接口类似的功能而不实际使用参数化接口,该怎么办?这导致了第三个也是最后一个解决方案,将在最后的帖子中进行描述。

您可以在Synopsys Verification IP  和  VC Verification IP数据表中获得更多信息。 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值