鎖存器(Latch),是電平觸發(fā)的存儲(chǔ)單元,數(shù)據(jù)存儲(chǔ)的動(dòng)作取決于輸入時(shí)鐘(或者使能)信號(hào)的電平值。僅當(dāng)鎖存器處于使能狀態(tài)時(shí),輸出才會(huì)隨著數(shù)據(jù)輸入發(fā)生變化。
當(dāng)電平信號(hào)無效時(shí),輸出信號(hào)隨輸入信號(hào)變化,就像通過了緩沖器;當(dāng)電平有效時(shí),輸出信號(hào)被鎖存。激勵(lì)信號(hào)的任何變化,都將直接引起鎖存器輸出狀態(tài)的改變,很有可能會(huì)因?yàn)樗矐B(tài)特性不穩(wěn)定而產(chǎn)生振蕩現(xiàn)象。
鎖存器示意圖如下:
觸發(fā)器(flip-flop),是邊沿敏感的存儲(chǔ)單元,數(shù)據(jù)存儲(chǔ)的動(dòng)作(狀態(tài)轉(zhuǎn)換)由某一信號(hào)的上升沿或者下降沿進(jìn)行同步的(限制存儲(chǔ)單元狀態(tài)轉(zhuǎn)換在一個(gè)很短的時(shí)間內(nèi))。
觸發(fā)器示意圖如下:
寄存器(register),在 Verilog 中用來暫時(shí)存放參與運(yùn)算的數(shù)據(jù)和運(yùn)算結(jié)果的變量。一個(gè)變量聲明為寄存器時(shí),它既可以被綜合成觸發(fā)器,也可能被綜合成 Latch,甚至是 wire 型變量。但是大多數(shù)情況下我們希望它被綜合成觸發(fā)器,但是有時(shí)候由于代碼書寫問題,它會(huì)被綜合成不期望的 Latch 結(jié)構(gòu)。
Latch 的主要危害有:
Latch 多用于門控時(shí)鐘(clock gating)的控制,一般設(shè)計(jì)時(shí),我們應(yīng)當(dāng)避免 Latch 的產(chǎn)生。
組合邏輯中,不完整的 if - else 結(jié)構(gòu),會(huì)產(chǎn)生 latch。
例如下面的模型,if 語句中缺少 else 結(jié)構(gòu),系統(tǒng)默認(rèn) else 的分支下寄存器 q 的值保持不變,即具有存儲(chǔ)數(shù)據(jù)的功能,所以寄存器 q 會(huì)被綜合成 latch 結(jié)構(gòu)。
module module1_latch1(
input data,
input en ,
output reg q) ;
always @(*) begin
if (en) q = data ;
end
endmodule
避免此類 latch 的方法主要有 2 種,一種是補(bǔ)全 if-else 結(jié)構(gòu),或者對(duì)信號(hào)賦初值。
例如,上面模型中的always語句,可以改為以下兩種形式:
// 補(bǔ)全條件分支結(jié)構(gòu)
always @(*) begin
if (en) q = data ;
else q = 1'b0 ;
end
//賦初值
always @(*) begin
q = 1'b0 ;
if (en) q = data ; //如果en有效,改寫q的值,否則q會(huì)保持為0
end
但是在時(shí)序邏輯中,不完整的 if - else 結(jié)構(gòu),不會(huì)產(chǎn)生 latch,例如下面模型。
這是因?yàn)?,q 寄存器具有存儲(chǔ)功能,且其值在時(shí)鐘的邊沿下才會(huì)改變,這正是觸發(fā)器的特性。
module module1_ff(
input clk ,
input data,
input en ,
output reg q) ;
always @(posedge clk) begin
if (en) q <= data ;
end
endmodule
在組合邏輯中,當(dāng)條件語句中有很多條賦值語句時(shí),每個(gè)分支條件下賦值語句的不完整也是會(huì)產(chǎn)生 latch。
其實(shí)對(duì)每個(gè)信號(hào)的邏輯拆分來看,這也相當(dāng)于是 if-else 結(jié)構(gòu)不完整,相關(guān)寄存器信號(hào)缺少在其他條件下的賦值行為。例如:
module module1_latch11(
input data1,
input data2,
input en ,
output reg q1 ,
output reg q2) ;
always @(*) begin
if (en) q1 = data1 ;
else q2 = data2 ;
end
endmodule
這種情況也可以通過補(bǔ)充完整賦值語句或賦初值來避免 latch。例如:
always @(*) begin
//q1 = 0; q2 = 0 ; //或在這里對(duì) q1/q2 賦初值
if (en) begin
q1 = data1 ;
q2 = 1'b0 ;
end
else begin
q1 = 1'b0 ;
q2 = data2 ;
end
end
case 語句產(chǎn)生 Latch 的原理幾乎和 if 語句一致。在組合邏輯中,當(dāng) case 選項(xiàng)列表不全且沒有加 default 關(guān)鍵字,或有多個(gè)賦值語句不完整時(shí),也會(huì)產(chǎn)生 Latch。例如:
module module1_latch2(
input data1,
input data2,
input [1:0] sel ,
output reg q ) ;
always @(*) begin
case(sel)
2'b00: q = data1 ;
2'b01: q = data2 ;
endcase
end
endmodule
當(dāng)然,消除此種 latch 的方法也是 2 種,將 case 選項(xiàng)列表補(bǔ)充完整,或?qū)π盘?hào)賦初值。
補(bǔ)充完整 case 選項(xiàng)列表時(shí),可以羅列所有的選項(xiàng)結(jié)果,也可以用 default 關(guān)鍵字來代替其他選項(xiàng)結(jié)果。
例如,上述 always 語句有以下 2 種修改方式。
always @(*) begin
case(sel)
2'b00: q = data1 ;
2'b01: q = data2 ;
default: q = 1'b0 ;
endcase
end
always @(*) begin
case(sel)
2'b00: q = data1 ;
2'b01: q = data2 ;
2'b10, 2'b11 :
q = 1'b0 ;
endcase
end
在組合邏輯中,如果一個(gè)信號(hào)的賦值源頭有其信號(hào)本身,或者判斷條件中有其信號(hào)本身的邏輯,則也會(huì)產(chǎn)生 latch。因?yàn)榇藭r(shí)信號(hào)也需要具有存儲(chǔ)功能,但是沒有時(shí)鐘驅(qū)動(dòng)。此類問題在 if 語句、case 語句、問號(hào)表達(dá)式中都可能出現(xiàn),例如:
//signal itself as a part of condition
reg a, b ;
always @(*) begin
if (a & b) a = 1'b1 ; //a -> latch
else a = 1'b0 ;
end
//signal itself are the assigment source
reg c;
wire [1:0] sel ;
always @(*) begin
case(sel)
2'b00: c = c ; //c -> latch
2'b01: c = 1'b1 ;
default: c = 1'b0 ;
endcase
end
//signal itself as a part of condition in "? expression"
wire d, sel2;
assign d = (sel2 && d) ? 1'b0 : 1'b1 ; //d -> latch
避免此類 Latch 的方法,就只有一種,即在組合邏輯中避免這種寫法,信號(hào)不要給信號(hào)自己賦值,且不要用賦值信號(hào)本身參與判斷條件邏輯。
例如,如果不要求立刻輸出,可以將信號(hào)進(jìn)行一個(gè)時(shí)鐘周期的延時(shí)再進(jìn)行相關(guān)邏輯的組合。上述第一個(gè)產(chǎn)生 Latch 的代碼可以描述為:
reg a, b ;
reg a_r ;
always (@posedge clk)
a_r <= a ;
always @(*) begin
if (a_r & b) a = 1'b1 ; //there is no latch
else a = 1'b0 ;
end
如果組合邏輯中 always@() 塊內(nèi)敏感列表沒有列全,該觸發(fā)的時(shí)候沒有觸發(fā),那么相關(guān)寄存器還是會(huì)保存之前的輸出結(jié)果,因而會(huì)生成鎖存器。
這種情況,把敏感信號(hào)補(bǔ)全或者直接用 always@(*) 即可消除 latch。
總之,為避免 latch 的產(chǎn)生,在組合邏輯中,需要注意以下幾點(diǎn):
點(diǎn)擊這里下載源碼
更多建議: