interface clocking block使用 及 verdi capture delta cycle

clocking block

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.
interface clocking block使用 及 verdi capture delta cycle_第1张图片

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 &

如上示例:

  1. input skew output skew各1ns。
  2. task driver()驱动,task monitor()采样。
  3. 15ns, 25ns, 35ns, 45ns 四个观察结点。
  4. 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.pwdataX态,因为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.pwdatavif.drv_cb.pwdata晚1ns,因为clocking block drv_cboutput skew

35ns
见 delta cycle分析。

45ns

结论

  1. interface中尽量使用clocking来sync采样和驱动信号,避免冒险。一些TB中不使用也没有出错,只能说明这种情况下没有问题,无法保证和其他RTL连接时这种方式不会出错。
  2. vif.drv_cb.pwdata vif.mon_cb.pwdata要使用vif.drv_cbvif.mon推进时间,避免与vif.pclk混用。同理vif.pwdata避免与vif.drv_cb vif.mon_cb混用。
  3. 如果采样clocking block中的output信号,会报错。不可以采样驱动信号。可以改用inout类型。inout类型的信号相当于input output

Verdi capture delta cycle

delta cycle: 时钟采样时数据发生跳变,存在冒险。比如glitch发生,nwave上显示一个实线 |,此时glitch的上升沿和下降沿的$realtime差值为delta = 0。实际仿真器根据IEEE SV协议中的Scheduling semantics章节内容进行Event simulation。可参考:【system verilog】time-slot,仿真的竞争与冒险,对齐与采样
interface clocking block使用 及 verdi capture delta cycle_第2张图片

使用

对于delta cycle的debug,verdi支持三种方式,在 ./simv时加上

  1. +fsdb+glitch=0 : 查看glitch
  2. +fsdb+sequential: 查看 event sequence
  3. +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生效。
interface clocking block使用 及 verdi capture delta cycle_第3张图片
event sequence : nWave中 Tools - Event Sequence
interface clocking block使用 及 verdi capture delta cycle_第4张图片
clk先跳变,vif.mon_cb.pwdata采样得到2,随后DUT中wdata被2驱动,然后vif.pwdata跳变为3。
DUT中的wdata发生在vif.pwdata之前,所以被驱动时,vif.pwdata还是旧值2。

接下一篇 : dump glitch 毛刺分析 及 异步复位同步释放

你可能感兴趣的:(systemverilog,EDA,systemverilog,delta,cycle)