Verilog HDL基礎(chǔ)知識(shí)4之阻塞賦值 & 非阻塞賦值
阻塞賦值語句
串行塊語句中的阻塞賦值語句按順序執(zhí)行,它不會(huì)阻塞其后并行塊中語句的執(zhí)行。阻塞賦值語句使用“=”作為賦值符。
例子 阻塞賦值語句 reg x, y, z;
reg [15:0] reg_a, reg_b;
integer count; // 所有行為語句必須放在 initial 或 always 塊內(nèi)部
initial
begin
x = 0; y = 1; z = 1; // 標(biāo)量賦值
count = 0; // 整形變量賦值
reg_a = 16'b0; reg_b = reg_a; // 向量的初始化
#15 reg_a[2] = 1'b1; // 帶延遲的位選賦值
#10 reg_b[15:13] = {x, y, z} // 把拼接操作的結(jié)果賦值給向量的部分位(域)
count = count + 1; // 給整形變量賦值(遞增)
end
在例子中,只有在語句x=0執(zhí)行完成后,才會(huì)執(zhí)行y=1,而語句count=count+1按順序在最后執(zhí)行。由于阻塞賦值語句是按順序執(zhí)行的,因此如果在一個(gè)begin-end塊中使用了阻塞賦值語句,那么這個(gè)塊語句表現(xiàn)的是串行行為。例子中,begin-end塊中各條語句執(zhí)行的仿真時(shí)間為:
1.x=0到regb = rega之間的語句在仿真0時(shí)刻執(zhí)行;
2.語句rega[2]=0在仿真時(shí)刻15執(zhí)行; * 語句regb[15:13]={x,y,z}在仿真時(shí)刻25執(zhí)行;
3.語句count=count+1在仿真時(shí)刻25執(zhí)行;
4.由于前面的語句分別包含了15和10個(gè)時(shí)間單位的延遲,因此語句count=count+1將在第25個(gè)單位時(shí)刻執(zhí)行。
注意,在對(duì)寄存器類型變量進(jìn)行過程賦值時(shí),如果賦值符兩側(cè)的位寬不相等,則采用以下原則:
1.如果右側(cè)表達(dá)式的位寬較寬,則將保留從最低位開始的右側(cè)值,把超過左側(cè)位寬的高位丟棄;
2.如果左側(cè)位寬大于右側(cè)位寬,則不足的高位補(bǔ)0;
非阻塞賦值語句
非阻塞賦值語句允許賦值調(diào)度,但它不會(huì)阻塞位于同一個(gè)順序塊中其后語句的執(zhí)行。非阻塞賦值使用“?”作為賦值符。讀者會(huì)注意到,它與“小于等于”關(guān)系操作符是同一個(gè)符號(hào),但在表達(dá)式中它被解釋為關(guān)系操作符,而在非阻塞賦值的環(huán)境下被解釋成非阻塞賦值。為了說明非阻塞賦值的意義以及阻塞賦值的區(qū)別,讓我們來考慮將阻塞賦值例子中的部分阻塞賦值改為非阻塞賦值后的結(jié)果,修改后語句如下:
例 非阻塞賦值語句 reg x, y, z;
reg [15:0] reg_a, reg_b;
integer count; // 所有的行為語句必須寫在initial 和 always塊內(nèi)
initial
begin
x = 0; y = 1; z = 1; // 標(biāo)量賦值;
count = 0; // 整形變量賦值
reg_a = 16'b0; reg_b = reg_a; // 向量的初始化
reg_a[2] <= #15 1'b1; // 帶延遲的位選賦值
reg_b[15:13] <= #10 {x, y, z} // 把拼接操作的結(jié)果賦值給向量的部分位(域)
count <= count + 1; // 給整形變量賦值(遞增)
end
在這個(gè)例子中,從x=0到regb=rega之間的語句是在仿真0時(shí)刻順序執(zhí)行的,之后的三條非阻塞賦值語句在regb=rega執(zhí)行完成后并發(fā)執(zhí)行。
1.rega[2]=0被調(diào)度到15個(gè)時(shí)間單位之后執(zhí)行,即仿真時(shí)刻為15; * regb[15:13]={x,y,z}被調(diào)度到10個(gè)時(shí)間單位之后執(zhí)行,即仿真時(shí)刻為10;
2.count=count+1被調(diào)度到無任何延遲執(zhí)行,即仿真時(shí)刻為0。
從上面的分析中可以看到,仿真器將非阻塞賦值調(diào)度到相應(yīng)的仿真時(shí)刻,然后繼續(xù)執(zhí)行后面的語句,而不是停下來等待賦值的完成。一般情況下,非阻塞賦值是在當(dāng)前仿真時(shí)刻的最后一個(gè)時(shí)間步,即阻塞賦值完成之后才執(zhí)行的。
在上面的例子中,我們把阻塞和非阻塞賦值語句混合在一起使用,目的是想更清楚地比較和說明它們的行為。需要提醒大家注意的是,不要在同一個(gè)always塊中混合使用阻塞和非阻塞賦值語句。
非阻塞賦值語句的應(yīng)用
描述了非阻塞賦值的行為之后,理解究竟為什么要在硬件設(shè)計(jì)中使用非阻塞賦值是很重要的。非阻塞賦值可以被用來為常見的硬件電路行為建立模型,例如當(dāng)某一事件發(fā)生后,多個(gè)數(shù)據(jù)并發(fā)傳輸?shù)男袨?。在下面的例子中,?dāng)時(shí)鐘信號(hào)的上升沿到來之后,執(zhí)行三個(gè)數(shù)據(jù)的并發(fā)傳輸:
always @(posedge clock)
begin
reg1 <= #1 in1;
reg2 <= @(negedge clock) in2 ^ in3;
reg3 <= #1 reg1; // reg1 的“舊值”
end
每當(dāng)一個(gè)時(shí)鐘上升沿到來時(shí),其中的非阻塞賦值語句按下面的順序執(zhí)行:
1.在每個(gè)時(shí)鐘上升沿到來時(shí)讀取操作數(shù)變量in1, in2, in3和reg1,計(jì)算右側(cè)表達(dá)式的值,該值由仿真器臨時(shí)保存;
2.對(duì)左值的賦值由仿真器調(diào)度到相應(yīng)的仿真時(shí)刻,延遲時(shí)間由語句中內(nèi)嵌的延遲值確定。在本例中,對(duì)reg1的賦值需要等一個(gè)時(shí)間單位,對(duì)reg2的賦值需要等到時(shí)鐘信號(hào)下降沿到來的時(shí)刻,對(duì)reg3的賦值需要等待一個(gè)時(shí)間單位;
3.每個(gè)賦值操作在被調(diào)度的仿真時(shí)刻完成。注意,對(duì)左側(cè)變量的賦值使用的是由仿真器保存的表達(dá)式“舊值”,因此賦值完成的實(shí)際順序并不重要。在本例中,對(duì)reg3賦值使用的是reg1 的“舊值”,而不是在此之前對(duì)reg1賦予的新值,reg1的“舊值”是在賦值事件調(diào)度時(shí)由仿真器保存的。
由上面的分析可見,reg1,reg2和reg3的最終值與賦值完成的順序無關(guān),體現(xiàn)了非阻塞賦值并行的特點(diǎn)。
為了進(jìn)一步理解阻塞和非阻塞賦值,讓我們來看以下例子。這個(gè)例子的目的是在每個(gè)時(shí)鐘上升延處交換a和b這兩個(gè)寄存器變量的值,其中使用了兩個(gè)always語句。
例 使用非阻塞賦值來避免競(jìng)爭(zhēng) // 說明1:使用阻塞語句的兩個(gè)并行的always塊
always @(posedge clock)
a = b; always @(posedge clock)
b = a; // 說明2:使用非阻塞語句的兩個(gè)并行的always塊
always @(posedge clock)
a <= b; always @(posedge clock)
b <= a;
在第一種描述中我們使用了阻塞賦值,這樣就產(chǎn)生了競(jìng)爭(zhēng)的情況:a=b和b=a,具體執(zhí)行順序的先后取決于所使用的仿真器。因此這段代碼達(dá)不到交換a和b值的目的,而是使得兩者具有相同的值(在時(shí)鐘上升沿到來之前a或b的值),具體是哪一個(gè)值與使用的仿真器有關(guān)。
在第二種描述中,我們通過使用非阻塞賦值語句來避免競(jìng)爭(zhēng):在每個(gè)時(shí)鐘上升沿到來的時(shí)候,仿真器讀取每個(gè)操作數(shù)的值,進(jìn)而計(jì)算表達(dá)式的值并保存在臨時(shí)變量中;當(dāng)賦值的時(shí)候,仿真器將保存的值賦予非阻塞賦值語句的左側(cè)變量。這樣就將讀和寫分開來了,達(dá)到了交換數(shù)據(jù)的目的,并且不受語句執(zhí)行順序的影響。以下例子介紹了如何使用阻塞賦值實(shí)現(xiàn)說明2中使用非阻塞語句才能實(shí)現(xiàn)的數(shù)值交換。
例 使用阻塞賦值來達(dá)到非阻塞賦值的目的 // 使用臨時(shí)變量和阻塞賦值來模仿非阻塞賦值的行為
always @(posedge clock)
begin
// 讀操作
// 把右側(cè)表達(dá)式的值放在臨時(shí)變量中
temp_a = a;
temp_b = b;
// 寫操作
// 把臨時(shí)變量的值放到左側(cè)變量中
a = temp_b;
b = temp_a;
end
在數(shù)字電路設(shè)計(jì)中,如果某事件發(fā)生后將產(chǎn)生多個(gè)數(shù)據(jù)的并發(fā)傳輸,我們強(qiáng)烈建議讀者使用非阻塞賦值來描述這種情形。如果我們使用阻塞賦值來描述這種情形,由于最終結(jié)果依賴于語句的具體執(zhí)行順序,有可能引起競(jìng)爭(zhēng)風(fēng)險(xiǎn);而非阻塞賦值語句的執(zhí)行結(jié)果是與執(zhí)行順序無關(guān)的,因此它能夠準(zhǔn)確地描述這種情況。非阻塞賦值的典型應(yīng)用包括流水線建模和多個(gè)互斥(mutually exclusive)數(shù)據(jù)傳輸?shù)慕!J褂梅亲枞x值所帶來的問題是,它會(huì)引起仿真速度的下降以及內(nèi)存使用量的增加。
評(píng)論