【IC验证】systemverilog_接口

一 .概述

systemverilog在verilog的基础上,扩展了接口(interface),将多个端口封装在一起,使代码便于维护;

二.接口的内容

1.语法:

interface 接口名(input 时钟信号、复位信号 //和testbench连接的);
	变量声明;
	参数声明;
	modport 约束各种模块信号方向;(约束首先要与接口参数列表一致)
	clocking块约束信号方向的同时,确定信号采样和被驱动的时刻;
	方法,过程块,断言,覆盖率统计等;(比较少用)
endinterface

注意:
接口包含体现其功能的modpor约束t块和clocking块,同时还可以包含同模块一样的变量、参数、方法、过程块;
module可以例化接口,接口可以例化接口,但是接口不能例化module;
模块端口连接,verilog是按照端口连接,systemverilog可以用接口进行连接;
systemverilog使用接口时,可以直接用成员变量连(iterface名.成员变量连),也可以用modport块连接(约束了信号方向,建议采用此种方法),可以直接通过接口连接(没有约束信号方向);
systemverilog每一种连接方法,只要模块定义时定义成对应方式即可;

2.modport约束块

(1)作用

约束信号方向。对于同一组信号,不同模块同一信号的输入输出方向是不一致的,所以使用modport约束各个模块中信号的输入、输出方向。

(2)语法

定义语法:

modport 约束块名字(
	input 	输入信号1,输入信号2,...,输入信号m,
	output 	输出信号1,输出信号2,...,输出信号n
);

声明语法:

	//接口实例化
	接口名 接口实例化名 (时钟信号,复位信号)//modport块实例化
	modport块名 modport块实例化名(
		//信号列表
		modprot块就按照modport块传
	);

(3)注意

mordport块中只需要指明信号方向,不需要声明信号类型和宽度;

三.接口的使用

1.步骤

(1)定义接口
(2)在各个模块中声明接口型端口;
(3)在testbech实例化接口,按照模块中的具体方式建立连接;

2.例子

(1)例子1:通过成员变量进行连接

interface my_if(input logic clk ,rst_n);
    logic flag1;
    logic flag2;
    logic flag3;
    modport my_md1(
        input clk,rst_n,flag1,
        output flag2
    );
    modport my_md2(
        input clk,rst_n,flag2,
        output flag3
    );
endinterface
module test_interface;
    logic   clk;
    logic   rst_n;
    parameter T =20;
    my_if m_if(
        .clk    (clk    ),
        .rst_n  (rst_n  )
    );
    initial begin
        clk = 1'b0;
        rst_n = 1'b0;
        m_if.flag1 = 1'b0;
        #(T);
        rst_n = 1'b1;
        #T;
        m_if.flag1 = 1'b1;
        #T;
        m_if.flag1 = 1'b0;
    end
    always#(T/2) clk = !clk;

    cnt10_1 cnt_u1(
        .clk        (m_if.clk),
        .rst_n      (m_if.rst_n),
        .flag_in    (m_if.flag1),
        .flag_out   (m_if.flag2)
    );
    cnt10_1 cnt_u2(
        .clk        (m_if.clk),
        .rst_n      (m_if.rst_n),
        .flag_in    (m_if.flag2),
        .flag_out   (m_if.flag3)
    );
endmodule
module cnt10_1(
    input           clk     ,
    input           rst_n   ,
    input           flag_in ,
    output  reg     flag_out
);
    reg [3:0] cnt_10;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            cnt_10 <= 'd0;
        else if(flag_in)
            cnt_10 <= 4'd1;
        else if((4'd0<cnt_10) && (cnt_10 < 10))
            cnt_10 <= cnt_10 + 1'd1;
        else 
            cnt_10 <= 'd0;
    end
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)
            flag_out <= 'd0;
        else if(cnt_10 == 4'd10)
            flag_out <= 1'b1;
        else
            flag_out <= 1'b0;
    end

endmodule

结果:
在这里插入图片描述

(2)例子2:通过modport块进行参数连接

interface my_if(input logic clk ,rst_n);
    logic flag1;
    logic flag2;
    modport my_md1(
        input clk,rst_n,flag1,
        output flag2
    );
endinterface
module test_interface;
    logic   clk;
    logic   rst_n;
    parameter T =20;
    my_if m_if(
        .clk    (clk    ),
        .rst_n  (rst_n  )
    );
    initial begin
        clk = 1'b0;
        rst_n = 1'b0;
        m_if.flag1 = 1'b0;
        #(T);
        rst_n = 1'b1;
        #T;
        m_if.flag1 = 1'b1;
        #T;
        m_if.flag1 = 1'b0;
    end
    always#(T/2) clk = !clk;

    cnt10_1 cnt_u1(
        .m_if   (m_if.my_md1)
    );
endmodule
module cnt10_1(
    my_if.my_md1 m_if
);
    reg [3:0] cnt_10;
    always@(posedge m_if.clk or negedge m_if.rst_n)begin
        if(!m_if.rst_n)
            cnt_10 <= 'd0;
        else if(m_if.flag1)
            cnt_10 <= 4'd1;
        else if((4'd0<cnt_10) && (cnt_10 < 10))
            cnt_10 <= cnt_10 + 1'd1;
        else 
            cnt_10 <= 'd0;
    end
    always@(posedge m_if.clk or negedge m_if.rst_n)begin
        if(!m_if.rst_n)
             m_if.flag2<= 'd0;
        else if(cnt_10 == 4'd10)
            m_if.flag2 <= 1'b1;
        else
            m_if.flag2 <= 1'b0;
    end

endmodule



结果:
在这里插入图片描述
(3)例子3:通过接口进行参数连接

interface my_if(input logic clk ,rst_n);
    logic flag1;
    logic flag2;
    modport my_md1(
        input clk,rst_n,flag1,
        output flag2
    );
endinterface
module test_interface;
    logic   clk;
    logic   rst_n;
    parameter T =20;
    my_if m_if(
        .clk    (clk    ),
        .rst_n  (rst_n  )
    );
    initial begin
        clk = 1'b0;
        rst_n = 1'b0;
        m_if.flag1 = 1'b0;
        #(T);
        rst_n = 1'b1;
        #T;
        m_if.flag1 = 1'b1;
        #T;
        m_if.flag1 = 1'b0;
    end
    always#(T/2) clk = !clk;

    cnt10_1 cnt_u1(
        .m_if   (m_if
        )
    );
endmodule
module cnt10_1(
    my_if m_if
);
    reg [3:0] cnt_10;
    always@(posedge m_if.clk or negedge m_if.rst_n)begin
        if(!m_if.rst_n)
            cnt_10 <= 'd0;
        else if(m_if.flag1)
            cnt_10 <= 4'd1;
        else if((4'd0<cnt_10) && (cnt_10 < 10))
            cnt_10 <= cnt_10 + 1'd1;
        else 
            cnt_10 <= 'd0;
    end
    always@(posedge m_if.clk or negedge m_if.rst_n)begin
        if(!m_if.rst_n)
             m_if.flag2<= 'd0;
        else if(cnt_10 == 4'd10)
            m_if.flag2 <= 1'b1;
        else
            m_if.flag2 <= 1'b0;
    end

endmodule



结果:
在这里插入图片描述

四.时钟块(clocking block)

1.采样和数据驱动

时钟触发沿到来时,触发器会采样输入信号线上的信号,经延迟后会更新输出信号线上的信号;
为了采样时输入信号更稳定,我们会设置采样时间,让触发器采样触发沿前一个微小时间段处的输入值;
为了使输出信号更符合实际硬件电路,我们设置驱动时间,让触发器在时钟触发沿到来后一个微小时间之后再驱动输出信号;

2.clocking block的作用

设置采样和驱动时间、约束信号方向;
注意1
时钟块(clcking block)可以在interface、module和program中被定义;

3.接口的工作机理

(1)时钟沿,采样沿,驱动沿
理论的数字电路中(触发器):为了满足建立时间,待采样的输入信号必须提前时钟触发沿保持稳定;而由于数字电路存在延迟,输出数据会相较时钟触发沿延迟一点时间,才会更新在输出。在clocking block中,为了和实际数字电路更一致,可以设置采样沿提前于时钟触发沿的时间,也可以设置驱动沿滞后于时钟触发沿的时间。采样沿提前时间在未设置时,默认为1step,是一个远小于1ps的微小时刻;驱动沿未设置时,默认为**#0**,这个**#0**不是数字0,也代表了一个远小于1ps微小时刻。
(2)#######注意#####
接口成员变量和时钟块中的信号同时存在;
对于输入信号,会将采样沿采集到的值,在时钟触发沿立刻更新到时钟块内部;
对于输出信号,会将时钟触发时刻更新的值,在驱动沿驱动给接口中的成员变量;

4.语法

定义语法

clocking 时钟块名字 @(posedge/negedge驱动时钟)default input #采样沿提前时间 output  #驱动沿滞后时间;
	input  采样信号名;
	output (也可以额外声明posedge)驱动信号名;
	input  #时间 信号名; //额外指定输入信号的采样沿提前时刻
	output #时间 信号名; //额外指定输出信号的驱动沿滞后时刻
endclocking关键字

使用语法:

//触发
@时钟块的名字 后续操作;
//信号索引
时钟块名字.信号

注意:
如果没有设置采样时间,默认的采样时间是1step(很小);
如果没有设置驱动时间,默认的驱动时间是#0(很小);

5.例子

(0)注意

分析前,先看四.3.(2)的注意部分;

(1)例1:未设置采样沿提前时刻和驱动沿滞后时刻

A 代码

interface my_if(input bit clk);
    bit [7:0] sig1;
    bit [7:0] sig2;
    clocking cb @(posedge clk);
        input sig1;
        output sig2;
    endclocking
endinterface
module test_blocking;
    bit clk;
    parameter T = 20;
    initial begin
        forever #(T/2) clk = !clk;
    end
    my_if mif(clk);
    
    initial begin
        #T;
        mif.sig1 = 8'h12;
        mif.cb.sig2 <= 8'h34;
        $display("sig1 is %h",mif.cb.sig1);
        @mif.cb;
        mif.sig1 = 8'h56;
        mif.cb.sig2 <= 8'h78;
        $display("sig1 is %h",mif.cb.sig1);
    end
endmodule

B结果
说明:
上面的sig1和sig2是interface中的成员变量,下面的sig1和sig2是时钟块中的输入输出信号,采样沿提前时间和驱动沿滞后时间取默认值;
可以看出:
输入信号(sig1),将成员变量采样沿采集到的值,在时钟触发沿更新给了时钟块中的输入信号;
输出信号(sig2),将时钟块中的输出信号在时钟触发时刻更新的值,在驱动沿更新给了接口中的成员变量;
在这里插入图片描述

(2)例2:设置了采样沿提前时刻和驱动沿滞后时刻

A代码

interface my_if(input bit clk);
    bit [7:0] sig1;
    bit [7:0] sig2;
    clocking cb@(posedge clk);
        default input #2ns output #2.4ns;
        input sig1;
        output sig2;
    endclocking 
endinterface 
module test_blocking1;
    bit clk;
    initial begin
        forever #3 clk = !clk;
    end
    my_if itf(clk);
    initial begin
        itf.sig1        =   8'h00;
        itf.cb.sig2     <=  8'h00;
        #4 itf.sig1     =   8'h12;
        #4 itf.sig1     =   8'h34;
        #5 itf.sig1     =   8'h56;
        #1 itf.cb.sig2  <=  8'h11;
        #7 itf.cb.sig2  <=  8'h22;
        #3 itf.cb.sig2  <=  8'h33;
    end
endmodule

B结果
说明:
上面的sig1和sig2是interface中的成员变量,下面的sig1和sig2是时钟块中的输入输出信号,采样沿提前时间为2ns和驱动沿滞后时间为2.4ns;
观察的时刻是15ns的时钟触发沿;
输入信号(sig1),将成员变量在采样沿(13ns)采集到的值,在时钟触发沿更新给了时钟块中的输入信号;
输出信号(sig2),将时钟块中的输出信号在时钟触发时刻(15ns)更新的值,在驱动沿(17.4ns)更新给了接口中的成员变量;

在这里插入图片描述

(3)例3:特殊用法(将采样沿和驱动沿设置成时钟触发沿)

A 用法
将采样沿提前时间和驱动沿滞后时间用posedgenegedge关键字替代;
B代码

interface my_if(input bit clk);
    bit [7:0] sig1;
    bit [7:0] sig2;
    clocking cb@(posedge clk);
        default input posedge output negedge;
        input sig1;
        output sig2;
    endclocking 
endinterface
module test_blocking2;
    bit clk;
    always#(3) clk = !clk;
    my_if itf(clk);
    initial begin
            itf.sig1    =   8'h00;
            itf.cb.sig2 <=  8'h00;
        #4  itf.sig1    =   8'h12;
        #4  itf.sig1    =   8'h34;
        #5  itf.sig1    =   8'h56;
        #1  itf.cb.sig2 <=  8'h11;
        #7  itf.cb.sig2 <=  8'h22;
        #3  itf.cb.sig2 <=  8'h33; 
    end
endmodule

C结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值