Verilog HDL設計進(jìn)階:有限狀態(tài)機的設計原理及其代碼風(fēng)格
由于Verilog HDL和 VHDL 行為描述用于綜合的歷史還只有短短的幾年,可綜合風(fēng)格的Verilog HDL 和VHDL的語(yǔ)法只是它們各自語(yǔ)言的一個(gè)子集。又由于HDL的可綜合性研究近年來(lái)非?;钴S,可綜合子集的國際標準目前尚未最后形成,因此各廠(chǎng)商的綜合器所支持的HDL子集也略有所不同。
本文引用地址:http://dyxdggzs.com/article/201610/308584.htm本書(shū)中有關(guān)可綜合風(fēng)格的Verilog HDL的內容,我們只著(zhù)重介紹RTL級、算法級和門(mén)級邏輯結構的描述,而系統級(數據流級)的綜合由于還不太成熟,暫不作介紹。
由于寄存器傳輸級(RTL)描述是以時(shí)序邏輯抽象所得到的有限狀態(tài)機為依據的,所以把一個(gè)時(shí)序邏輯抽象成一個(gè)同步有限狀態(tài)機是設計可綜合風(fēng)格的Verilog HDL模塊的關(guān)鍵。
在本章中我們將通過(guò)各種實(shí)例由淺入深地來(lái)介紹各種可綜合風(fēng)格的Verilog HDL模塊,并把重點(diǎn)放在時(shí)序邏輯的可綜合有限狀態(tài)機的Verilog HDL設計要點(diǎn)。至于組合邏輯,因為比較簡(jiǎn)單,只需閱讀典型的用Verilog HDL描述的可綜合的組合邏輯的例子就可以掌握。
為了更好地掌握可綜合風(fēng)格,還需要較深入地了解阻塞和非阻塞賦值的差別和在不同的情況下正確使用這兩種賦值的方法。只有深入地理解阻塞和非阻塞賦值語(yǔ)句的細微不同,才有可能寫(xiě)出不僅可以仿真也可以綜合的Verilog HDL模塊。
只要按照一定的原則來(lái)編寫(xiě)代碼就可以保證Verilog模塊綜合前和綜合后仿真的一致性。符合這樣條件的可綜合模塊是我們設計的目標,因為這種代碼是可移植的,可綜合到不同的FPGA和不同工藝的ASIC中,是具有知識產(chǎn)權價(jià)值的軟核。
4.4.1 有限狀態(tài)機(FSM)設計原理
有限狀態(tài)機是由寄存器組和組合邏輯構成的硬件時(shí)序電路。有限狀態(tài)機的狀態(tài)(即由寄存器組的1和0的組合狀態(tài)所構成的有限個(gè)狀態(tài))只可能在同一時(shí)鐘跳變沿的情況下才能從一個(gè)狀態(tài)轉向另一個(gè)狀態(tài)。
有限狀態(tài)機的下一個(gè)狀態(tài)不但取決于各個(gè)輸入值,還取決于當前所在狀態(tài)。這里指的是米里Mealy型有限狀態(tài)機,而莫爾Moore型有限狀態(tài)機的下一個(gè)狀態(tài)只決于當前狀態(tài)。
Verilog HDL中可以用許多種方法來(lái)描述有限狀態(tài)機,最常用的方法是用always語(yǔ)句和case語(yǔ)句。如圖4.1所示的狀態(tài)轉移圖表示了一個(gè)有限狀態(tài)機,例4.1的程序就是該有限狀態(tài)機的多種Verilog HDL模型之一。

圖4.1的狀態(tài)轉移圖表示了一個(gè)四狀態(tài)的有限狀態(tài)機。它的同步時(shí)鐘是Clock,輸入信號是A和Reset,輸出信號是F和G。
狀態(tài)的轉移只能在同步時(shí)鐘(Clock)的上升沿時(shí)發(fā)生,往哪個(gè)狀態(tài)的轉移則取決于目前所在的狀態(tài)和輸入的信號(Reset和A)。下面的例子是該有限狀態(tài)機的Verilog HDL模型之一。
例4.1:Gray碼有限狀態(tài)機模型1。
module fsm (Clock, Reset, A, F, G); //模塊聲明
input Clock, Reset, A;
output F,G;
reg F,G;
reg [1:0] state ;
parameter //狀態(tài)聲明
Idle = 2’b00, Start = 2’b01,
Stop = 2’b10, Clear = 2’b11;
always @(posedge Clock)
if (!Reset) begin
state = Idle; F=0; G=0; //默認狀態(tài)
end
else case (state)
idle: begin //Idle狀態(tài)
if (A) begin
state = Start;
G=0;
end
elsestate = idle;
end
start: //Start狀態(tài)
if (!A) state = Stop;
else state = start;
Stop: begin //Stop狀態(tài)
if (A) begin
state = Clear;
F = 1;
end
else state = Stop;
end
Clear: begin //Clear狀態(tài)
if (!A) begin
state =Idle;
F =0; G =1;
end
else state = Clear;
end
endcase
endmodule
也可以用下面的Verilog HDL模型來(lái)表示同一個(gè)有限狀態(tài)。
例4.2:獨熱碼有限狀態(tài)和模型。
module fsm (Clock, Reset, A, F, G); //模塊聲明
input Clock, Reset, A;
output F,G;
reg F,G;
reg [3:0] state ;
parameter //狀態(tài)聲明
Idle = 4’b1000,
Start = 4’b0100,
Stop = 4’b0010,
Clear = 4’b0001;
always @(posedge clock)
if (!Reset) begin
state = Idle; F=0; G=0; //默認狀態(tài)
end
else case (state)
Idle: begin //Idel狀態(tài)
if (A) begin
state = Start;
G=0;
end
else state = Idle;
end
Start: //Start狀態(tài)
if (!A) state = Stop;
else state = Start;
Stop: begin //Stop狀態(tài)
if (A) begin
state = Clear;
F = 1;
end
else state = Stop;
end
Clear: begin //Clear狀態(tài)
if (!A) begin
state =Idle;
F=0; G=1;
end
else state = Clear;
end
default: state =Idle; //默認狀態(tài)
endcase
endmodule
例4.2與例4.1的主要不同點(diǎn)是狀態(tài)編碼方式。例4.2采用了獨熱編碼,而例4.1則采用Gray碼,究竟采用哪一種編碼好要看具體情況而定。
對于用FPGA實(shí)現的有限狀態(tài)機建議采用獨熱碼。因為雖然采用獨熱編碼多用了兩個(gè)觸發(fā)器,但所用組合電路可省下許多,因而使電路的速度和可靠性有顯著(zhù)提高,而總的單元數并無(wú)顯著(zhù)增加。
采用了獨熱碼后有了多余的狀態(tài),就有一些不可到達的狀態(tài),為此在CASE語(yǔ)句的最后需要增加default分支項,以確保多余狀態(tài)能回到Idle狀態(tài)。
另外還可以用另一種風(fēng)格的Verilog HDL模型來(lái)表示同一個(gè)有限狀態(tài)。在這個(gè)模型中,我們用always語(yǔ)句和連續賦值語(yǔ)句把狀態(tài)機的觸發(fā)器部分和組合邏輯部分分成兩部分來(lái)描述,如下所示。
例4.3:有限狀態(tài)機模型3
module fsm (Clock, Reset, A, F, G); //模塊聲明
input Clock, Reset, A;
output F,G;
reg [1:0] state ;
wire [1:0] Nextstate;
parameter //狀態(tài)聲明
Idle = 2’b00, Start = 2’b01,
Stop = 2’b10, Clear = 2’b11;
always @(posedge Clock)
if (!Reset) begin
state = Idle; //復位狀態(tài)
end
else
state = Nextstate; //狀態(tài)轉換
assign Nextstate = //狀態(tài)變換條件
(state == Idle ) ? (A ? Start : Idle):
(state==Start ) ? (!A ? Stop : Start ):
(state== Stop ) ? (A ? Clear : Stop ):
(state== Clear) ? (!A ? Idle : Clear) : Idle;
assign F = (( state == Stop) A ); //狀態(tài)輸出
assign G = (( state == Clear) (!A || !Reset)) //狀態(tài)輸出
endmodule
下面是第4種風(fēng)格的Verilog HDL模型來(lái)表示同一個(gè)有限狀態(tài)。在這個(gè)模型中,我們分別用沿觸發(fā)的always語(yǔ)句和電平敏感的always語(yǔ)句把狀態(tài)機的觸發(fā)器部分和組合邏輯部分分成兩部分來(lái)描述。
例4.4:有限狀態(tài)機模型4。
module fsm (Clock, Reset, A, F, G); //模塊聲明
input Clock, Reset, A;
output F,G;
reg [1:0] state, Nextstate;
parameter //狀態(tài)聲明
Idle = 2’b00, Start = 2’b01,
Stop = 2’b10, Clear = 2’b11;
always @(posedge Clock)
if (!Reset) begin
state = Idle; //默認狀態(tài)
end
else
state = Nextstate; //狀態(tài)轉換
always @( state or A ) begin
F=0;
G=0;
if (state == Idle) begin //處于Idel狀態(tài)時(shí),對A判斷
if (A)
Nextstate = Start; //Start狀態(tài)
else
Nextstate = Idle; //保持Idel狀態(tài)
G=1;
end
else if (state == Start) //處于Start狀態(tài)時(shí),對!A判斷
if (!A)
Nextstate = Stop; //Stop狀態(tài)
else
Nextstate = Start; //保持Start狀態(tài)
else if (state == Stop) //處于Stop狀態(tài)時(shí),對A判斷
if (A)
Nextstate = Clear; //Clear狀態(tài)
else
Nextstate = Stop; //保持Stop狀態(tài)
else if (state == Clear) begin //處于Clear狀態(tài)時(shí),對!A判斷
if (!A)
Nextstate = Idle; //Idel狀態(tài)
else
Nextstate = Clear; //保持Clear狀態(tài)
F=1;
end
else
Nextstate= Idle; //默認狀態(tài)
End
endmodule
上面4個(gè)例子是同一個(gè)狀態(tài)機的4種不同的Verilog HDL模型,它們都是可綜合的,在設計復雜程度不同的狀態(tài)機時(shí)有它們各自的優(yōu)勢。如用不同的綜合器對這4個(gè)例子進(jìn)行綜合,綜合出的邏輯電路可能會(huì )有些不同,但邏輯功能是相同的。
下面講解有限狀態(tài)機設計的一般步驟。
(1)邏輯抽象,得出狀態(tài)轉換圖。
就是把給出的一個(gè)實(shí)際邏輯關(guān)系表示為時(shí)序邏輯函數,可以用狀態(tài)轉換表來(lái)描述,也可以用狀態(tài)轉換圖來(lái)描述,這就需要完成以下任務(wù)。
① 分析給定的邏輯問(wèn)題,確定輸入變量、輸出變量以及電路的狀態(tài)數。通常是取原因(或條件)作為輸入變量,取結果作為輸出變量。
② 定義輸入、輸出邏輯狀態(tài)的含意,并將電路狀態(tài)順序編號。
③ 按照要求列出電路的狀態(tài)轉換表或畫(huà)出狀態(tài)轉換圖。
這樣,就把給定的邏輯問(wèn)題抽象到一個(gè)時(shí)序邏輯函數了。
(2)狀態(tài)化簡(jiǎn)。
如果在狀態(tài)轉換圖中出現這樣兩個(gè)狀態(tài),它們在相同的輸入下轉換到同一狀態(tài)去,并得到一樣的輸出,則稱(chēng)它們?yōu)榈葍r(jià)狀態(tài)。顯然等價(jià)狀態(tài)是重復的,可以合并為一個(gè)。電路的狀態(tài)數越少,存儲電路也就越簡(jiǎn)單。狀態(tài)化簡(jiǎn)的目的就在于將等價(jià)狀態(tài)盡可能地合并,以得到最簡(jiǎn)的狀態(tài)轉換圖。
(3)狀態(tài)分配。
狀態(tài)分配又稱(chēng)狀態(tài)編碼。通常有很多編碼方法,編碼方案選擇得當,設計的電路可以很簡(jiǎn)單。反之,若編碼方案選得不好,則設計的電路就會(huì )復雜許多。
實(shí)際設計時(shí),需綜合考慮電路復雜度與電路性能之間的折衷。在觸發(fā)器資源豐富的FPGA或ASIC設計中,采用獨熱編碼(one-hot-coding)既可以使電路性能得到保證,又可充分利用其觸發(fā)器數量多的優(yōu)勢。
(4)選定觸發(fā)器的類(lèi)型并求出狀態(tài)方程、驅動(dòng)方程和輸出方程。
(5)按照方程得出邏輯圖。
用Verilog HDL來(lái)描述有限狀態(tài)機,可以充分發(fā)揮硬件描述語(yǔ)言的抽象建模能力,使用always塊語(yǔ)句和case(if)等條件語(yǔ)句及賦值語(yǔ)句即可方便實(shí)現。具體的邏輯化簡(jiǎn)及邏輯電路到觸發(fā)器映射均可由計算機自動(dòng)完成。上述設計步驟中的第(2)、(4)、(5)步不再需要很多的人為干預,使電路設計工作得到簡(jiǎn)化,效率也有很大的提高。
4.4.2 FSM設計實(shí)例
例4.5:宇宙飛船控制器的狀態(tài)機。
module statmch1( launch_shuttle, land_shuttle, start_countdown,
start_trip_meter, clk, all_systems_go,
just_launched, is_landed, cnt, abort_mission
);
// I/O說(shuō)明
output launch_shuttle, land_shuttle, start_countdown,start_trip_meter;
input clk, just_launched, is_landed, abort_mission,all_systems_go;
input [3:0] cnt;
reg launch_shuttle, land_shuttle, start_countdown,start_trip_meter;
reg [4:0] present_state, next_state;
//設置獨熱碼狀態(tài)的參數
parameter HOLD=5'h1, SEQUENCE=5'h2, LAUNCH=5'h4;
parameter ON_MISSION=5'h8, LAND=5'h10;
always @(negedge clk or posedge abort_mission) begin
//把輸出設置成某個(gè)缺省值,在下面的case語(yǔ)句中就不必再設置輸出的缺省值
{launch_shuttle, land_shuttle, start_trip_meter, start_countdown} = 4'b0;
//檢查異步reset的值,即abort_mission的值
if(abort_mission)
next_state = LAND;
else begin
//如果abort_mission為零,把next_state賦值為present_state
next_state = present_state;
//根據 present_state 和輸入信號,設置 next_state和輸出output
case ( present_state )
HOLD: //HOLD狀態(tài)
if(all_systems_go) begin
next_state = SEQUENCE;
start_countdown = 1;
end
SEQUENCE: //SEQUENCE狀態(tài)
if(cnt==0)
next_state = LAUNCH;
LAUNCH: begin //LAUNCH狀態(tài)
next_state = ON_MISSION;
launch_shuttle = 1;
end
ON_MISSION: //ON_MISSION狀態(tài)
if(just_launched)
start_trip_meter = 1; //取消使命前,一直留在使命狀態(tài)
LAND: //LAND狀態(tài)
if(is_landed)
next_state = HOLD;
else land_shuttle = 1;
default: next_state = 'bx;//把缺省狀態(tài)設置為'bx(無(wú)關(guān))或某種已
//知狀態(tài),使其在做仿真時(shí),在復位前就
//與實(shí)際情況相一致
endcase
end // if-else語(yǔ)句結束
present_state = next_state; //把當前狀態(tài)變量設置為下一狀態(tài),
//待下一有效時(shí)鐘沿來(lái)到時(shí),當前狀
//態(tài)變量已設置了正確的狀態(tài)值
end //always塊結束
endmodule
4.4.3 設計可綜合狀態(tài)機的指導原則
(1)獨熱碼。
因為大多數FPGA內部的觸發(fā)器數目相當多,又加上獨熱碼狀態(tài)機(one hot state machine)的譯碼邏輯最為簡(jiǎn)單,所以在設計采用FPGA實(shí)現的狀態(tài)機時(shí),往往采用獨熱碼狀態(tài)機(即每個(gè)狀態(tài)只有一個(gè)寄存器置位的狀態(tài)機)。
(2)case語(yǔ)句。
建議采用case、casex或casez語(yǔ)句來(lái)建立狀態(tài)機的模型。因為這些語(yǔ)句表達清晰明了,可以方便地從當前狀態(tài)分支轉向下一個(gè)狀態(tài)并設置輸出。
采用這些語(yǔ)句設計狀態(tài)機時(shí),不要忘記寫(xiě)上case語(yǔ)句的最后一個(gè)分支default,并將狀態(tài)變量設為'bx。這就等于告知綜合器:case語(yǔ)句已經(jīng)指定了所有的狀態(tài)。這樣綜合器就可以刪除不需要的譯碼電路,使生成的電路簡(jiǎn)潔,并與設計要求一致。
如果將缺省狀態(tài)設置為某一確定的狀態(tài)(例如:設置default:state = state1),行不行呢?”這樣做有一個(gè)問(wèn)題需要注意:因為盡管綜合器產(chǎn)生的邏輯和設置“default:state='bx”時(shí)相同,但是狀態(tài)機的Verilog HDL模型綜合前和綜合后的仿真結果會(huì )不一致。
為什么會(huì )是這樣呢?因為啟動(dòng)仿真器時(shí),狀態(tài)機所有的輸入都不確定,因此立即進(jìn)入default狀態(tài)。如果通過(guò)設置將狀態(tài)變量設為state1,但是實(shí)際硬件電路的狀態(tài)機在通電之后,進(jìn)入的狀態(tài)是不確定的,很可能不是state1的狀態(tài),這樣就會(huì )產(chǎn)生不必要的沖突。
因此,還是設置“default:state='bx”與實(shí)際硬件電路相一致。但在有多余狀態(tài)的情況下還是應將缺省狀態(tài)設置為某一確定的有效狀態(tài),因為這樣做能使狀態(tài)機若偶然進(jìn)入多余狀態(tài)后仍能在下一時(shí)鐘跳變沿時(shí)返回正常工作狀態(tài),否則會(huì )引起死鎖。
(3)復位。
狀態(tài)機應該有一個(gè)異步或同步復位端,以便在通電時(shí)將硬件電路復位到有效狀態(tài),也可以在操作中將硬件電路復位(大多數FPGA結構都允許使用異步復位端)。
(4)惟一觸發(fā)。
目前大多數綜合器往往不支持在一個(gè)always塊中由多個(gè)事件觸發(fā)的狀態(tài)機(即隱含狀態(tài)機,implicit state machines)。因此為了能綜合出有效的電路,用Verilog HDL描述的狀態(tài)機應明確地由惟一時(shí)鐘觸發(fā)。
(5)異步狀態(tài)機。
異步狀態(tài)機是沒(méi)有確定時(shí)鐘的狀態(tài)機,它的狀態(tài)轉移不是由惟一的時(shí)鐘跳變沿所觸發(fā)。目前大多數綜合器不能綜合采用Verilog HDL描述的異步狀態(tài)機。
因此應盡量不要使用綜合工具來(lái)設計異步狀態(tài)機。因為目前大多數綜合工具在對異步狀態(tài)機進(jìn)行邏輯優(yōu)化時(shí)會(huì )胡亂地簡(jiǎn)化邏輯,使綜合后的異步狀態(tài)機不能正常工作。如果一定要設計異步狀態(tài)機,建議采用電路圖輸入的方法,而不要用Verilog HDL輸入的方法。
(6)狀態(tài)賦值。
Verilog HDL中,狀態(tài)必須明確賦值,通常使用參數parameters或宏定義define語(yǔ)句加上賦值語(yǔ)句來(lái)實(shí)現。
使用參數parameters語(yǔ)句賦狀態(tài)值如下所示:
parameter state1 = 2 'h1, state2 = 2 'h2;
...
current_state = state2; //把current state設置成 2'h2
...
使用宏定義define語(yǔ)句賦狀態(tài)值如下所示:
'define state1 2 'h1
'define state2 2 'h2
...
current_state = 'state2; //把current state設置成 2 'h2
評論