sv:interface

1. Interface 初识

接口是一种将信号封装到block中的方法。

语法

interface[name]([port_list]);
	[list_of_signals]
endinterface

接口还可以具有函数、任务、变量和参数,使其更像一个类模板。它还可以通过 modport 结构定义不同模块端口的方向信息策略,以及带有时钟块的 testbench 同步功能。它还可以有断言、覆盖率记录和其他协议检查元素。它还可以包含initial过程和always过程以及连续赋值(assign)语句。

模块不能在接口中实例化! 但是接口可以在模块中实例化。

interface apb_if (input pclk);
    logic[31:0]    paddr;
    logic[31:0]    pwdata;
    logic[31:0]    prdata;
    logic           penable;
    logic           pwrite;
    logic           psel;
endinterface

1.如何定义端口方向?

接口信号可用于各种验证组件以及 DUT,使用 modport 来定义信号方向。不同的 modport 定义可以传递给不同的组件,这样我们就可以为每个组件定义不同的输入输出方向。

interface myBus (input clk);
    logic[7:0]  data;
    logic      enable;
    // From TestBench perspective, 'data' is input and 'write' is output
    modport TB  (input data, clk,output enable);
    // From DUT perspective, 'data' is output and 'enable' is input
    modport DUT (output data,input enable, clk);
endinterface

2.如何连接interface与 DUT?

接口对象应该在实例化 DUT 的顶级 testbench 模块中创建,并传递给 DUT。确保为 DUT 分配正确的模型是非常重要的。
testbench模块中,接口对象在DUT前创建。

module dut (myBus busIf);
always @(posedge busIf.clk)
if(busIf.enable)
      busIf.data <= busIf.data+1;
else
      busIf.data <=0;
endmodule

// Filename : tb_top.sv
module tb_top;
    bit clk;
    // Create a clock
    always #10 clk =~clk;

    // Create an interface object  
    myBus busIf (clk);

    // Instantiate the DUT; pass modport DUT of busIf
    dut dut0 (busIf.DUT);
    
    // Testbench code : let's wiggle enable
    initialbegin
        busIf.enable  <=0;
        #10 busIf.enable <=1;
        #40 busIf.enable <=0;
        #20 busIf.enable <=1;
        #100 $finish;
    end
endmodule

2.有什么好处?

接口可以包含任务、函数、参数、变量、函数覆盖和断言(tasks, functions, parameters, variables, functional coverage, and assertions.)。这使我们能够通过该块中的接口监视和记录事务。由于信息封装在一个接口中,不管它有多少个端口,连接到设计也变得更加容易。

3.如何参数化接口?

接口定义可以使用与模块定义相同的方式利用参数和参数重定义。下面的示例演示如何在接口定义中使用参数

interface myBus #(parameter D_WIDTH=31)(input clk);
	logic [D_WIDTH-1:0] data;
	logic enable;
endinterface

interface simple_bus #(AWIDTH = 8, DWIDTH = 8) (input logic clk); // Define the interface
	logic req, gnt;
	logic [AWIDTH-1:0] addr;
	logic [DWIDTH-1:0] data;
	logic [1:0] mode;
	logic start, rdy;
endinterface : simple_bus

clocking block

时钟块内指定的信号将相对于该时钟进行采样/驱动。在一个接口中可以有多个时钟块。
注意,这是用于 testbench 相关信号。控制 TB 何时驱动信号,何时从 DUT 采样信号。 解决了竞争条件的一部分,但不是全部。倾斜值(skew values)可以参数化。

interface my_int (inputbit clk);
	// Rest of interface code
	
	clocking cb_clk @(posedge clk);
		default input #3ns output #2ns;
		input enable;
		output data;
	endclocking
endinterface

在上面的例子中,指定默认情况下,input应该在 clk 的posedge 之前3ns 采样,output应该在clk 的posedge 之后2ns 被驱动。

// To wait for posedge of clock
@busIf.cb_clk;
// To use clocking block signals
busIf.cb_clk.enable =1;

在enable 赋值1之前,您不必等待 clk 的posedge。 这样,您可以确保在下一个posedge clk 后2ns 驱动enable。

clocking

它是与特定时钟同步的信号集合,有助于指定时钟与信号之间的定时要求。
这将使测试编写人员能够更多地关注事务,而不用担心信号什么时候会与时钟交互。一个 testbench 可以有许多时钟块,但是每个时钟只有一个时钟块。

语法

[default] clocking [identifier_name] @ [event_or_identifier]
	default input #[delay_or_edge] output #[delay_or_edge] 
	[list of signals]
endclocking

delay_value表示一个信号被采样或驱动时离时钟事件有多少个时间单位的偏移。如果没有指定默认偏移,那么在指定的事件之后,所有的输入信号将采样 # 1步,输出信号驱动0ns。

2. interface intro

在 Verilog 和 SystemVerilog 中使用相同设计的接口。

Verilog 设计的interface

如何在测试平台中使用接口,并使用端口列表连接到标准的 Verilog 设计。下面显示的代码是 Verilog 编写的上下计数器的设计。这个模块接受一个参数来决定计数器的宽度。它还接受一个输入加载值 load,该加载值仅在 load_en 为1时加载到计数器中。

当输入向下为1时,计数器开始向下计数,否则向上计数。翻转输出指示计数器何时从最大值转换为0或从0转换为最大值。
在这里插入图片描述

module counter_ud  #(parameter WIDTH =4)(
    input 					clk,
    input 					rstn,
    inputwire[WIDTH-1:0]	load,
    input 					load_en,
    input 					down,
    output 					rollover,
    outputreg[WIDTH-1:0]	count
);    
    always @(posedge clk ornegedge rstn)begin
        if(!rstn)
            count <=0;
        elseif(load_en)
            count <= load;
        else begin
            if(down)
                count <= count -1;
            else
                count <= count +1;
        end
    end
    assign rollover =&count;
endmodule

下面声明了一个名为 cnt_if 的接口,并使用可参数化的值作为计数器信号的宽度。 这个任务还有一个task init() 来赋值。

interface cnt_if #(parameter WIDTH = 4) (input bit clk);
  logic 			rstn;
  logic 			load_en;
  logic [WIDTH-1:0] load;
  logic [WIDTH-1:0] count;
  logic 			down;
  logic 			rollover;
endinterface

module tb;
  reg clk;
  
  // TB Clock Generator us
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C++中,interface(接口)是一种只包含纯虚函数的类。接口类可以被其他类继承,以实现多态性和代码重用。接口类定义了一个通用的协议,派生类必须实现该协议中的所有纯虚函数。 在C++中,使用关键字`class`声明一个接口类,然后通过将成员函数声明为纯虚函数来定义接口。纯虚函数没有函数体,派生类必须提供实现。 下面是一个使用接口的示例: ```cpp class IShape { public: virtual double getArea() const = 0; virtual double getPerimeter() const = 0; }; class Circle : public IShape { private: double radius; public: Circle(double r) : radius(r) {} double getArea() const override { return 3.14 * radius * radius; } double getPerimeter() const override { return 2 * 3.14 * radius; } }; class Rectangle : public IShape { private: double length; double width; public: Rectangle(double l, double w) : length(l), width(w) {} double getArea() const override { return length * width; } double getPerimeter() const override { return 2 * (length + width); } }; int main() { Circle circle(5); Rectangle rectangle(4, 6); IShape* shape1 = &circle; IShape* shape2 = &rectangle; std::cout << "Circle Area: " << shape1->getArea() << std::endl; std::cout << "Circle Perimeter: " << shape1->getPerimeter() << std::endl; std::cout << "Rectangle Area: " << shape2->getArea() << std::endl; std::cout << "Rectangle Perimeter: " << shape2->getPerimeter() << std::endl; return 0; } ``` 在上面的示例中,IShape是一个接口类,定义了getArea()和getPerimeter()两个纯虚函数。Circle和Rectangle类分别继承IShape,实现了这两个纯虚函数。在main()函数中,我们通过基类指针调用派生类的成员函数,实现了多态性的效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值