Input (or inout) signals are sampled at the designated clock event. If an input skew is specified, then the signal is sampled at skew time units before the clock event. Similarly, output (or inout) signals are driven skew simulation time units after the corresponding clock event. Below Figure shows the basic sample and drive timing for a positive edge clock.
clocking block是sv中引入的语法,采样信号发生在时钟沿之前的input skew units
,驱动信号发生在时钟沿之后的output skew units
。避免TB与RTL接口上的冒险,相当于模拟实际器件的setup time
, hold time
。若实际器件timing不满足,则会产生亚稳态。实际仿真中就是X
态,无法确定高低电平。
# top.sv
interface master_interface();
logic pclk;
logic prest_n;
logic [31:0] pwdata;
logic [31:0] prdata;
clocking drv_cb @(posedge pclk);
default input #1 output #1;
output pwdata;
input prdata;
endclocking
clocking mon_cb @(posedge pclk);
default input #1 output #1;
input pwdata;
input prdata;
endclocking
endinterface
class master;
logic [31:0] data;
virtual master_interface vif;
task driver();
vif.pwdata = 0;
wait(vif.prest_n == 1);
@(posedge vif.pclk);
vif.pwdata <= 1;
$display("%0t [driver]",$realtime);
#5;
@(posedge vif.pclk);
vif.drv_cb.pwdata <= 2;
$display("%0t [driver]",$realtime);
#5;
@(vif.drv_cb);
vif.pwdata <= 3;
$display("%0t [driver]",$realtime);
#5;
@(vif.drv_cb);
vif.drv_cb.pwdata <= 4;
$display("%0t [driver]",$realtime);
#10;
endtask
task monitor();
wait(vif.prest_n == 1);
//@(posedge vif.pclk); // vif.pwdata = 0 | vif.mon_cb.pwdata = 0
@(vif.mon_cb); // vif.pwdata = 1 | vif.mon_cb.pwdata = 0
$display("%0t [monitor] vif.pwdata:%0h",$realtime,vif.pwdata);
$display("%0t [monitor] vif.mon_cb.pwdata:%0h",$realtime,vif.mon_cb.pwdata);
#5;
//@(posedge vif.pclk); // vif.pwdata = 1 | vif.mon_cb.pwdata = 0
@(vif.mon_cb); // vif.pwdata = 1 | vif.mon_cb.pwdata = 1
$display("%0t [monitor] vif.pwdata:%0h",$realtime,vif.pwdata);
$display("%0t [monitor] vif.mon_cb.pwdata:%0h",$realtime,vif.mon_cb.pwdata);
#5;
//@(posedge vif.pclk); // vif.pwdata = 2 | vif.mon_cb.pwdata = 1
@(vif.mon_cb); // vif.pwdata = 2 | vif.mon_cb.pwdata = 2
$display("%0t [monitor] vif.pwdata:%0h",$realtime,vif.pwdata);
$display("%0t [monitor] vif.mon_cb.pwdata:%0h",$realtime,vif.mon_cb.pwdata);
#5;
//@(posedge vif.pclk); // vif.pwdata = 3 | vif.mon_cb.pwdata = 2
@(vif.mon_cb); // vif.pwdata = 3 | vif.mon_cb.pwdata = 3
$display("%0t [monitor] vif.pwdata:%0h",$realtime,vif.pwdata);
$display("%0t [monitor] vif.mon_cb.pwdata:%0h",$realtime,vif.mon_cb.pwdata);
#10;
endtask
endclass
module top;
logic clk;
logic rst_n;
logic [31:0] rdata,wdata;
logic [31:0] cnt = 0;
master_interface m_if();
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0)
wdata <= 'h0;
else
wdata <= m_if.pwdata;
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 1'b0)
m_if.prdata <= 'h0;
else
m_if.prdata <= cnt++;
end
always #5 clk = ~clk;
assign m_if.pclk = clk;
assign m_if.prest_n = rst_n;
initial begin
clk = 'b0;
rst_n = 'b0;
#12;
rst_n = 'b1;
end
initial begin
master m_inst;
m_inst = new();
m_inst.vif = m_if;
fork
m_inst.driver();
m_inst.monitor();
join_any
$finish();
end
initial begin
$fsdbDumpfile("wave.fsdb");
$fsdbDumpvars;
end
endmodule
# Makefile
all: clean comp run
clean:
@rm .[a-zA-Z0-9]* -rf
@ls | grep -v Makefile | grep -v top.sv | xargs rm -rf
@echo clean done
comp:
vcs -full64\
-kdb -lca \
-debug_access+all \
-sverilog \
-timescale=1ns/1ns \
top.sv \
-l compile.lg
run:
./simv \
+fsdb+delta \
-l sim.log
wave:
verdi -ssf wave.fsdb &
如上示例:
input skew
output skew
各1ns。task driver()
驱动,task monitor()
采样。15ns, 25ns, 35ns, 45ns
四个观察结点。vif.pclk
vif.drv_cb
vif.mon_cb
vif.pwdata
vif.drv_cb.pwdata
vif.mon_cb.pwdata
混用。
15ns:
DUT中的wdata
为0,采样到的是前一拍的值。
Driver中的vif.drv_cb.pwdata
为X
态,因为task driver
中15ns驱动的信号是vif.pwdata
,并不会影响vif.drv_cb
scope中的pwdata
信号,所以是X
态。
Sample中vif.pwdata
为1,采样发生在vif.pwdata
跳变之后。而vif.mon_cb.pwdtata
为0,采样时钟沿前1ns的值。
25ns:
DUT中的wdata
为1,采样到的是前一拍的值。
Driver中vif.pwdata
比vif.drv_cb.pwdata
晚1ns,因为clocking block
drv_cb
的output skew
。
35ns
见 delta cycle分析。
45ns
略
interface
中尽量使用clocking
来sync采样和驱动信号,避免冒险。一些TB中不使用也没有出错,只能说明这种情况下没有问题,无法保证和其他RTL连接时这种方式不会出错。vif.drv_cb.pwdata
vif.mon_cb.pwdata
要使用vif.drv_cb
和vif.mon
推进时间,避免与vif.pclk
混用。同理vif.pwdata
避免与vif.drv_cb
vif.mon_cb
混用。clocking block
中的output
信号,会报错。不可以采样驱动信号。可以改用inout
类型。inout
类型的信号相当于input
output
。delta cycle: 时钟采样时数据发生跳变,存在冒险。比如glitch
发生,nwave上显示一个实线 |
,此时glitch
的上升沿和下降沿的$realtime
差值为delta = 0。实际仿真器根据IEEE SV协议中的Scheduling semantics
章节内容进行Event simulation
。可参考:【system verilog】time-slot,仿真的竞争与冒险,对齐与采样
对于delta cycle的debug,verdi支持三种方式,在 ./simv
时加上
+fsdb+glitch=0
: 查看glitch+fsdb+sequential
: 查看 event sequence+fsdb+region
: 查看event region使用+fsdb+delta
默认同时采集上述三种。
To enable delta cycle dumping capability in interactive mode, use the +fsdb+delta=1|2 option at runtime.
Following is the syntax:
+fsdb+delta=1|2
1: Enables delta cycle dumping capability
2: Enables delta cycle dumping, but disables cycle dumping at time 0
Use the +fsdb+delta=0 option at runtime to disable the delta cycle dumping capability.
以上述波形35ns处为例:
event region : nWave中 View
- Expand Delta
第一绿色区域为Active
区,第二个红色区域为NBA
区,非阻塞赋值<=
在NBA生效。
event sequence : nWave中 Tools
- Event Sequence
clk先跳变,vif.mon_cb.pwdata
采样得到2,随后DUT中wdata
被2驱动,然后vif.pwdata
跳变为3。
DUT中的wdata
发生在vif.pwdata
之前,所以被驱动时,vif.pwdata
还是旧值2。
接下一篇 : dump glitch 毛刺分析 及 异步复位同步释放