SystemVerilog中interface的几点理解

2020-06-30 16:43:33 浏览数 (2)

最近吃了没文化的亏,想来就把interface好好看看。


在SV中常用interface连接端口,它的好处在于,方便了在sv中模块声明中不需要一个个的写端口,直接在端口中实例化一个interface即可。接口中还可以包含任务函数、断言等等。说多了咱也记不住,就说这点吧。不过我觉得最好用的还是第一点哈。

interface的推荐写法

代码语言:javascript复制
interface
 v_if
(
input bit clk
);

    logic 
[
31
:
0
]
 data
;

    
.....

    clocking cb@
(
posedge clk
)

        
//需要包含resetn

    endclocking
:
cb

    
......
//需要几个写几个,个人觉得是有几个component写几个时钟块



    modport TB
(
clocking cb
,
output resetn
);

    
......
//modport和clocking块对应

endinterface

下面就是个人的几点扯淡了...

1.为什么clk要写在括号里?

我的理解是,clk是在顶层testbench中驱动的,其他component只会使用clk作为input,这样可以减少不必要的接口层次。而且,虽然clk和interface中的其他端口定义的位置不一样,但是在仿真环境中还是可以使用<接口实例名>.clk。这个仍然代表着interface中的clk信号。但是除了对DUT模块使用上述clk信号,对于在testbench,不建议使用这个clk,要用时钟块的名称替换,这样做的好处是避免在仿真时发生竞争冒险,使得各个信号是时钟同步信号。但是需要注意的是,使用时钟块时,不再需要添加上升沿或者下降沿关键字,给时钟块中的变量赋值时应当使用<=而不是=。

2.为什么resetn需要定义两次?一次在时钟块中,一次在modport中?

为了做到异步复位,同步释放。因此resetn有效时应当直接使用<接口实例名>.resetn。释放时为<接口实例名>..resetn。

3.时钟块什么时候采样?

时钟块默认输入偏斜为1step,也就是在上一个时钟片的结束部分。换句话说,就是在紧接着时钟上升沿之前采样信号,或者说是本时钟片的preponed区域。

如果显示使用#0输入,则会在相应的时钟事件同步进行采样,但是是在observed区域采样,这样可以避免竞争情况。同样的,在re-NBA区域进行输出。忘了的,不懂的看这个SystemVerilog中scheduler(调度)

如下代码所示:

代码语言:javascript复制
    clocking cb_0 
@(
posedge clk
);

      input 
#0  gnt;

    endclocking



    clocking cb_1 
@(
posedge clk
);

      input 
#1step gnt;

    endclocking



        
begin

          
@(
if0
.
cb_0
);

          $display 
(
"cb_0.gnt = 0x%0h"
,
 if0
.
cb_0
.
gnt
);

        
end

        
begin

          
@(
if0
.
cb_1
);

          $display 
(
"cb_1.gnt = 0x%0h"
,
 if0
.
cb_1
.
gnt
);

        
end

最终结果是不一样的:

0 人点赞