参考文献1:Setup and Hold time and clocking block in system verilog
参考文献2:https://verificationguide.com/systemverilog/systemverilog-scheduling-semantics/
参考文献3:SystemVerilog Event Regions,Race Avoidance & Guidelines
interface内的clocking block用来进行信号的同步,具体说明如下:
Clocking blocks have been introduced in SystemVerilog to address the problem of specifying the timing and synchronisation requirements of a design in a testbench.
A clocking block is a set of signals synchronised on a particular clock. It basically separates the time related details from the structural, functional and procedural elements of a testbench. It helps the designer develop testbenches in terms of transactions and cycles. Clocking blocks can only be declared inside a module, interface or program.
先说结论:
- clocking块内的输入信号是对接口信号的采样,即clocking块内的信号是采样后的输出信号。如果input delay非0,则clocking内的采样后的信号和接口信号从仿真波形上看差1拍。
- clocking块内的输出信号由testbench进行驱动,如果output delay非0,则clocking块内的输出信号延迟输出指定的delay时间后反应在接口的输出信号上,即二者在波形上为同一拍,但是存在output delay的延迟。
即:
1. The input will be sampled before #setup_time @posedge of CLK.
2. Output will be driven after #hold_time @posedge of CLK
setup和hold非零
仿真代码如下:
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
module harness;
logic clk;
logic rst_n;
logic [31:0] prdata;
master_interface m_if();
assign m_if.pclk = clk;
assign m_if.prest_n = rst_n;
assign m_if.prdata = prdata;
always #5 clk = ~clk;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
prdata <= 32'h5a5a_5a5a;
end else begin
prdata <= ~prdata;
end
end
initial begin
clk = 'b0;
rst_n = 'b0;
#12;
rst_n = 'b1;
end
initial begin
repeat(1000) @(m_if.mon_cb);
$finish();
end
initial begin
$display("@%0t: n0", $realtime);
@(posedge rst_n);
$display("@%0t: n2", $realtime);
repeat (100) begin
repeat(1) @(m_if.drv_cb);
m_if.drv_cb.pwdata <= 32'h5555_5555;
$display("@%0t: pwdata = 32'h5555_5555", $realtime);
repeat(1) @(m_if.drv_cb);
m_if.drv_cb.pwdata <= 32'haaaa_aaaa;
$display("@%0t: pwdata = 32'haaaa_aaaa", $realtime);
end
end
initial begin
$fsdbDumpfile("wave.fsdb");
$fsdbDumpvars;
end
endmodule
仿真脚本如下:
comp:
@vcs \
-full64 \
-kdb -lca \
-sverilog \
-debug_access+all \
+libext+.sv+.v \
-timescale=1ns/1ps \
-l cmp.log \
*.sv
run:
@./simv \
+fsdb+delta \
-l simv.log
all:
@make clean && make comp && make run
verdi:
@verdi -ssf wave.fsdb &
clean:
@rm -rf simv* csrc ucli* vc_hdrs.h
仿真波形:
setup和hold全零
可以看到在monitor的clocking块内部,采到pwdata(drv_cb中的输出信号)为上一拍的值,而prdata(drv_cb中的输入信号)为当前拍的值。
打开region mode和event sequence,显示如下:
事件的调度如下:
从上面仿真波形可以看出,在NBA region,非阻塞赋值被调度,/harness/m_if/prdata[31:0]
变为0xa5a5_a5a5
,在Active(1)region,更新/harness/m_if/mon_cb/prdata[31:0]
,变为0xa5a5_a5a5
,因此波形上看到的mon_cb内的prdata的值为0xa5a5_a5a5.
而mon_cb内的pwdata在Active(1)region更新为0xaaaa_aaaa。