Check某個信號電平保持時間的一種方案
----暨SV中Time類型變量比較大小中的注意事項
引言:在數字驗證中,我們經常會Check某個信號在某Event時,會保持多長時間,本文將介紹該Scenario涉及到的基礎知識以及一種測試方案。
一、背景知識
1.1、Timescale task list
No. | Task | Description |
1 | $printtimescale [ (hierarchical_name) ]; | displays the time scale of the specified module. When no hierarchical name is specified, it displays the time scale of the module that is in the current scope. |
2 | $timeformat [ (unit, precision, "suffix", min_field_width) ]; | defines the format used by the %t text format specifier. Unit is an integer between 0 and -15 and defines the base that time is to be displayed, precision是小數點之後的時間精度 suffix是時間數值之後的字符串 min_field_width是顯示數值的最小寬度 |
1.2、時間單位查找表(Time unit Lookuptab)
No. | Int num | Unit | No. | Int num | Unit |
1 | 0 | 1sec | 10 | -9 | 1ns |
2 | -1 | 100ms | 11 | -10 | 100ps |
3 | -2 | 10ms | 12 | -11 | 10ps |
4 | -3 | 1ms | 13 | -12 | 1ps |
5 | -4 | 100us | 14 | -13 | 100fs |
6 | -5 | 10us | 15 | -14 | 10fs |
7 | -6 | 1us | 16 | -15 | 1fs |
9 | -7 | 100ns | 17 | - | - |
9 | -8 | 10ns | 18 | - | - |
- Precision is the number of decimal digits to display(精度是要顯示的小數位數).
- Suffix is a string appended to the time(後綴是添加到時間后的字符串).
- Min field width is the minimum number of characters that will be displayed.
- 如果没有为$timeformat指定参数,则使用默认值。默认单位为仿真精度;精度为0;后缀是空字符串;min_field_width是20个字符。
1.3、應用案例
initial begin
$printtimescale(top.u1);
$timeformat(-9, 2, " ns", 15);
end
二、SystemVerilog中的時間類型變量的運算
2.1、SystemVerilog中時間類型變量比較大小
- 直接看案例,從下面的案例我們可以分析出:
- 使用Verilog的仿真時間系統函數所取得的Time數值,其實是以`timescale中指定的單位來存儲的,如本例中,a在系統中的存儲形式其實是:1.23456ns,所以第一個initial塊只會走else if分支
- 我們看到$display()打印的時間是1234567fs,那是應為$timeformat()函數起的作用
`timescale 1ns/10fs
module cmp_time_time_test();
realtime a;
realtime b = 1.234569ns;
realtime c = 1ns;
int d = 1_000_000;
initial begin
#1.234567ns; //1_124_567fs
$display("Simulation Time: %0t", $realtime);
a = $realtime();
if(a >= d) begin
$display("True a = %0t, d = %0d\n", a, d);
end
else if(a >= b) begin
$display("False a = %0t, b = %0t\n", a, b);
end
else begin
$display("Fatal a = %0t, b = %0t\n", a, b);
end
end
initial begin
#1.234567ns; //1_124_567fs
$display("Simulation Time: %0t", $realtime);
if(a >= 1_234_567) begin
$display("True a = %0t, d = %0d\n", a, d);
end
else if(a >= 1.23456789) begin
$display("False a = %0t, b = %0t\n", a, b);
end
else begin
$display("Fatal a = %0t, b = %0t\n", a, b);
end
end
initial begin
$fsdbDumpvars(0, 0);
$timeformat(15, 0, "fs", 20);
end
endmodule
2.2、結論
- 當對系統時間比較大小時,注意timescale的設定,默認保存單位是timescale設定的單位(注意:不是精度)
- 如果要使用到時間參數,請聲明為realtime類型,然後用timescale制動的單位進行賦值,不要自己做單位轉換,例如:realtime a_max = 1.1ns
- 一切不帶時間單位的延時(Delay)都是耍流氓
- 對Time類型的變量做運算,請帶上單位(timescale中指定的),不要自己做單位換算
- 在Log中看的時間打印信息其實是經過$timeformat()函數處理過的
三、Check信號電平保持時間的案例
3.1、Scenario:在@posedge sync時u,clk會keep一段時間,並且keep時間在[6:8]ns之間
3.2、代碼實現
realtime keep_time_min = 6.00000ns;
realtime keep_time_max = 8.00000ns;
realtime half_cycle = 1.0012ns;
bit [7:0] clk_keep_cnt;
task clk_keep_time_check();
realtime t1_posedge;
realtime t2_negedge;
realtime keep_time;
@(posedge sync);
clk_keep_cnt = 0;
do begin
fork
begin
@(posedge clk);
t1_posedge = $realtime();
end
begin
@(negedge clk);
t2_negedge = $realtime();
end
join
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'b1;
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 while(sync === 1'b1);
endtask : clk_keep_time_check