在Verilog的建模中,時間尺度和延遲是非常重要的概念,設置好時間尺度和延遲,可以充分模擬邏輯電路發生的各種情況和事件發生的時間點,來評估數字IC設計的各種要求,達到充分評估和仿真的作用。注意延遲語句是不可綜合的,只是用來數據建模或仿真。
1. 時間尺度
語法格式: `timescale 10ns/1ns
用關鍵字 `timescale標識,后面跟時間刻度,如:10ns/1ns,其中10ns表示基本時間刻度,就是每10ns作為一個刻度。1ns是精度,一般在仿真軟件中的最小刻度。不同的仿真工具的精度不同,在modelsim中一般時間刻度為1ps,與`timescale 10 ns/1 ps的1 ps的設置是等效的。
例:在testbench 中時鍾的建模:
`timescale 1ns/1ps //時間刻度為1 ns
module top_sim
(
);
reg CLK;
initial
begin
CLK = 1'b0;
#5;
forever
#5 CLK = ~CLK; //duty cycle 50%, period 10 ns; Frequency 100Mhz;
end
endmodule
Modelsim 波形

`timescale 1ns/1ps //時間刻度為1 ns
module top_sim
(
);
reg CLK;
initial
begin
CLK = 1'b0;
#4;
forever
#4 CLK = ~CLK; //duty cycle 50%, period 8 ns; frequency 125Mhz
end
endmodule
Modelsim 仿真波形

在設置時間尺度是也可直接指定時間單位或由關鍵字parameter定義的參數指定,修改缺省的 由`timeschale定義的時間尺度。
例:
parameter PERIOD = 10 ; reg CLK; initial begin CLK = 1'b0; #(PERIOD/2); forever #(PERIOD/2) CLK = ~CLK; end
2. 延遲:
賦值延時語句中的延時,用於控制任意操作數發生變化到語句左端變量賦值之間的時間延時。
-
賦值延時分類:
-
-
根據信號類型可分為連續賦值延時和寄存器賦值延時,
-
根據延遲特性分為內部延遲和外部延遲
-
連續賦值時延:一般可分為普通賦值時延、隱式時延、聲明時延;只有 外部時延。
-
寄存器賦值延時:只有在使用時可分為內部時延 和 外部時延, 但沒有聲明延時。
-
-
-
普通賦值時延
例:
wire [3:0] a, b, c;
assign #10 c = a + b;
含義:a,b中有任意一個發生變化,將a+b的結果延時10個時間單位,賦值給變量c。
作用:在連續賦值期間,如果a+b的結果不斷變化,c並不跟隨a+b 結果的變化,直到a,b變量穩定后,在指定的10個時間單位延遲到達后才賦值。
`timescale 1 ns/1 ps
module tb
(
);
reg [3:0] ta,tb;
wire [3:0] tc ,td;
assign #10 tc = ta + tb;
assign #10 td = ta - tb;
initial
begin
ta = 4'b0000;
tb = 4'b0000;
#2
tb = 4'b0001;
#2
ta = 4'b0010;
#2
tb = 4'b0100;
#2
ta = 4'b0010;
tb = 4'b1000;
#2
ta = 4'b0110;
tb = 4'b0001;
#20
tb = 4'b0111;
tb = 4'b0110;
#20
tb = 4'b1111;
tb = 4'b0110;
end
endmodule
仿真波形如下:

從波形可以看出,雖然開始ta,tb 有多次變化,由於變化的時間間隔都不足10個單位,因此tc並沒有得到ta+tb的結果,只有在ta==4’b0110, tb==4’b0001的時刻開始,ta,tb穩定持續10個時間單位后,tc才得到ta+tb的值。所以連續賦值語句能否更新,是從參與計算的變量最近的時刻是否滿足延遲時間的需求而定。
-
-
隱式延時聲明:
wire A, B; wire #10 Z = A & B;
聲明一個wire型變量時對其進行包含一定時延的連續賦值。
-
-
變量聲明延時
wire A, B; wire #5 Z ; assign Z =A + B;
聲明時延,聲明一個wire型變量時指定一個時延。因此對該變量所有的連續賦值都會被推遲到指定的時間。除非門級建模中,一般不推薦使用此類方法建模。
-
-
慣性延遲
慣性延遲,如上面的例子
reg [3:0] ta, tb ;
wire [3:0] tc ,td;
assign #10 tc = ta + tb;
assign #10 td = ta – tb;
如果在這 10 個時間單位內,即在 td 獲取新的值之前,ta 或 tb 任意一個值又發生了變化,那么計算 tc, td 的新值時會取 ta 或 tb 當前的新值。所以稱之為慣性時延,即信號脈沖寬度小於時延時,對輸出沒有影響。
因此仿真時,時延一定要合理設置,防止某些信號不能進行有效的延遲。
按時延特性 可以分為:
延遲還分內部延遲(intra _delay)和外部延遲(inter_delay)兩種。上面介紹的例子都是外部延遲。
內部延遲
intra_delay: 是指在賦值語句內部的延遲。看下面三條語句就可以明白intra_delay 和inter_delay的區別。
例1:
wire co, y; assign {co, y} = a + b + ci; assign # inter_delay {co, y} = a + b + ci;
語句assign {co, y} = a + b + ci; 是連續賦值語句,賦值語句的左邊LHS(left hand side) {co,y}始終追隨右邊RHS的變化,右邊任何一個變量發生變化,賦值語句立即評估結果,並賦給左邊變量。
語句assign # inter_delay {co, y} = a + b + ci;是外部延時語句,當RHS變量有變化時,等待 # inter_delay時間后評估RHS的值,並賦給LHS變量。
例2:
reg co, y;
always@(*)
{co, y} = #intra_delay a + b + ci;
語句{co, y} = #intra_delay a + b + ci;是內部延時語句,用在賦值語句內部,當RHS變量有變化時,立即評估a+b+ci的結果,延遲#intra_delay時間后,將評估的結果賦給LHS變量。
注:內部延時語句只能用在順序語句中。
例: module tb
(
);
reg [3:0] ta,tb;
wire [3:0] tc_inter, tc_intra ,td;
assign #10 tc_inter = ta + tb;
assign #10 td = ta - tb;
initial
begin
ta = 4'b0000;
tb = 4'b0000;
#2
tb = 4'b0001;
#2
ta = 4'b0010;
#2
tb = 4'b0100;
#2
ta = 4'b0010;
tb = 4'b1000;
#2
ta = 4'b0110;
tb = 4'b0001;
#5
tb = 4'b0111;
tb = 4'b0110;
#20
tb = 4'b1111;
tb = 4'b0110;
end
always@(*)
tc_intra = #10 ta + tb;
endmodule
仿真波形如下:

從仿真波形可以清楚看出,內部延遲與外部延遲的區別。
在建模時應注意各種delay的選擇與使用。