SystemVerilog多線程採樣的案例分析
---- 兩個線程相互影響,交替出現漏採樣的情況
一、多線程採樣代碼段 ---- 兩個線程相互影響,交替出現漏採樣的情況
- 在下面的代碼中,在clk第一個pulse的negedge到來時,線程:measure_pulse_width_of_if_ck(以後稱之為Thread1)結束,同時線程:interval_between_teo_if_ck_pulse(以後稱之為Thread2)開始。
- 當第二個pulse的posedge到來時,Thread2結束,同時第二輪循環開始。--> (Thread1看不到第二個pulse的posedge)
- 進入第二輪循環后,Thread1在等posedge,Thread2在等negedge,此時Thread2先等到第二個pulse的negedge,Thread2先開始執行
- 當第三個pulse到來時,Thread2結束,同時Thread1開始,當negedge到來時,Thread1結束,開始下一輪循環。--> (Thread2看不到第三個pulse的negedge)
class if_ck_check_monitor extends uvm_monitor;
realtime keep_time_min = 6.00000ns;
realtime keep_time_max = 8.00000ns;
realtime half_cycle = 1.0012ns;
bit [7:0] clk_keep_cnt;
extern virtual task clk_keep_time_check();
endclass : if_ck_check_monitor;
task if_ck_check_monitor::clk_keep_time_check();
realtime t1_posedge;
realtime t2_negedge;
realtime t4_posedge;
realtime t3_negedge;
realtime keep_time;
@(posedge sync);
clk_keep_cnt = 0;
do begin
fork
begin : measure_pulse_width_of_if_ck
@(posedge clk);
t1_posedge = $realtime();
@(negedge clk);
t2_negedge = $realtime();
if(t1_posedge >= t2_negedge) begin
keep_time = t1_posedge - t2_negedge;
end
eles if(t1_posedge < t2_negedge) begin
keep_time = t2_negedge - t1_posedge;
end
if((keep_time >= keep_time_min) && (keep_time <= keep_time_max)) begin
clk_keep_cnt += 1;
end
else if((keep_time >= half_cycle + 1ps) && (keep_time <= keep_time_min - 1ps)) begin
`uvm_error()
end
else if(keep_time > keep_time_max) begin
`uvm_error()
end
else begin
`uvm_info()
end
end
begin : interval_between_teo_if_ck_pulse
@(negedge clk);
t3_negedge = $realtime();
@(posedge clk);
t4_negedge = $realtime();
if(t4_posedge >= t3_negedge) begin
keep_time = t4_posedge - t3_negedge;
end
eles if(t4_posedge < t3_negedge) begin
keep_time = t3_negedge - t4_posedge;
end
if((keep_time >= keep_time_min) && (keep_time <= keep_time_max)) begin
clk_keep_cnt += 1;
end
else if((keep_time >= half_cycle + 1ps) && (keep_time <= keep_time_min - 1ps)) begin
`uvm_error()
end
else if(keep_time > keep_time_max) begin
`uvm_error()
end
else begin
`uvm_info()
end
end
join
end while(sync === 1'b1);
endtask : clk_keep_time_check
二、解決方案一
2.1、再複製一個clk信號:clk_d2,并插入一些Delay時間
- 再造一個clk信號,Delay 2T @clk_ck + 0.08ns,這樣線程:measure_pulse_width_of_if_ck與interval_between_teo_if_ck_pulse就不會同時進行。
logic clk_d2;
logic [7:0] clk_d2_cnt;
always @ (posedge clk_ck or negedge rst_n) begin
if(!rst_n)
clk_d2_cnt <= #0.08 'h0;
else
clk_d2_cnt <= #0.08 {clk_d2_cnt[0], clk};
end
assign clk_d2 = clk_d2_cnt[1];
三、解決方案二
2.1、把fork join放到循環體之外
- 這樣的話兩個循環體各自執行,不會出現互相影響的情況
- 結論:不要在循環體裡面放置fork ... join塊,
class if_ck_check_monitor extends uvm_monitor;
realtime keep_time_min = 6.00000ns;
realtime keep_time_max = 8.00000ns;
realtime half_cycle = 1.0012ns;
bit [7:0] clk_keep_cnt;
extern virtual task clk_keep_time_check();
endclass : if_ck_check_monitor;
task if_ck_check_monitor::clk_keep_time_check();
realtime t1_posedge;
realtime t2_negedge;
realtime t4_posedge;
realtime t3_negedge;
realtime keep_time;
@(posedge sync);
clk_keep_cnt = 0;
fork
do begin
begin : measure_pulse_width_of_if_ck
@(posedge clk);
t1_posedge = $realtime();
@(negedge clk);
t2_negedge = $realtime();
if(t1_posedge >= t2_negedge) begin
keep_time = t1_posedge - t2_negedge;
end
eles if(t1_posedge < t2_negedge) begin
keep_time = t2_negedge - t1_posedge;
end
if((keep_time >= keep_time_min) && (keep_time <= keep_time_max)) begin
clk_keep_cnt += 1;
end
else if((keep_time >= half_cycle + 1ps) && (keep_time <= keep_time_min - 1ps)) begin
`uvm_error()
end
else if(keep_time > keep_time_max) begin
`uvm_error()
end
else begin
`uvm_info()
end
end
end while(sync === 1'b1);
do begin
begin : interval_between_teo_if_ck_pulse
@(negedge clk);
t3_negedge = $realtime();
@(posedge clk);
t4_negedge = $realtime();
if(t4_posedge >= t3_negedge) begin
keep_time = t4_posedge - t3_negedge;
end
eles if(t4_posedge < t3_negedge) begin
keep_time = t3_negedge - t4_posedge;
end
if((keep_time >= keep_time_min) && (keep_time <= keep_time_max)) begin
clk_keep_cnt += 1;
end
else if((keep_time >= half_cycle + 1ps) && (keep_time <= keep_time_min - 1ps)) begin
`uvm_error()
end
else if(keep_time > keep_time_max) begin
`uvm_error()
end
else begin
`uvm_info()
end
end
end while(sync === 1'b1);
join
endtask : clk_keep_time_check
四、SV案例一:2個Event同時發生,用@等待
- 結論:當兩個@event_a,@event_b串行時,若event_a與event_b同時發生,則只有@event_a會被觸發,此時程序才會往下走,當event_b再次發生時,@event_b才能捕獲到。
program event_test();
logic sig_a;
logic sig_b;
initial begin
#10ns;
sig_a = 0;
sig_b = 0;
repeat(100) begin
#10ns;
sig_a = ~sig_a;
sig_b = ~sig_b;
end
end
initial begin
repeat(10) begin
@sig_a;
$display("Event sig_a occurred at %0t", $realtime());
@sig_b;
$display("Event sig_b occurred at %0t", $realtime());
end
end
endprogram
- Simulation Output
Event sig_a occurred at 20!
Event sig_b occurred at 30!
Event sig_a occurred at 40!
Event sig_b occurred at 50!
..........