盡管接觸Verilog已經兩年多了,但似乎沒有很系統地區學習過。一接觸的時候就在學習別人寫的程序,終于再次拿起書本,發現很多知識點,只是知道而已,卻不怎么熟悉。今天學習的一個重點就是狀態機。
1 有限狀態機 有限狀態機(Finite State Machine,FSM)在數字系統設計中應用十分廣泛。根據狀態機的輸出是否與輸入有關,可將狀態機分為兩大類:摩爾(Moore)型狀態機和米莉 (Mealy)型狀態機。Moore型狀態機的輸出僅與現態有關;Mealy型狀態機的輸出不僅與現態有關,而且和輸入也有關。 有限狀態機一般包括三個部分,其中組合邏輯部分包括狀態譯碼器和輸出譯碼器,狀態譯碼器確定狀態機的下一個狀態,輸出譯碼器確定狀態機的輸出,狀態寄存器屬于時序邏輯部分,用來存儲狀態機的內部狀態。 2 好的狀態機標準 好的狀態機的標準很多,最重要的幾個方面如下: 第一,狀態機要安全,是指FSM不會進入死循環,特別是不會進入非預知的狀態,而且由于某些擾動進入非設計狀態,也能很快的恢復到正常的狀態循環中來。這里面有兩層含義。其一要求該FSM的綜合實現結果無毛刺等異常擾動,其二要求FSM要完備,即使受到異常擾動進入非設計狀態,也能很快恢復到正常狀態。 第二,狀態機的設計要滿足設計的面積和速度的要求。 第三,狀態機的設計要清晰易懂、易維護。 在芯片設計中,對綜合結果評判的兩個基本標準為:面積和速度。“面積”是指設計所占用的邏輯資源數量;“速度”指設計在芯片上穩定運行所能夠達到的最高頻率。兩者是對立統一的矛盾體,要求一個設計同時具備設計面積最小,運行頻率最高,這是不現實的。科學的設計目標應該是:在滿足設計時序要求(包含對設計最高頻率的要求)的前提下,占用最小的芯片面積,或者在所規定的面積下,使設計的時序余量更大,頻率更高。另外,如果要求FSM安全,則很多時候需要使用full case的編碼方式,即將狀態轉移變量的所有向量組合情況都在FSM 中有相應的處理,這經常勢必意味著要多花更多的設計資源,有時也會影響FSM的頻率所以,上述的標準要綜合考慮,根據設計的要求進行權衡。 3 狀態機描述方法 狀態機描述時關鍵是要描述清楚幾個狀態機的要素,即如何進行狀態轉移,每個狀態的輸出是什么,狀態轉移的條件等。具體描述時方法各種各樣,最常見的有三種描述方式: (1)一段式:整個狀態機寫到一個always模塊里面,在該模塊中既描述狀態轉移,又描述狀態的輸入和輸出; (2)二段式:用兩個always模塊來描述狀態機,其中一個always模塊采用同步時序描述狀態轉移;另一個模塊采用組合邏輯判斷狀態轉移條件,描述狀態轉移規律以及輸出; (3)三段式:在兩個always模塊描述方法基礎上,使用三個always模塊,一個always模塊采用同步時序描述狀態轉移,一個always采用組合邏輯判斷狀態轉移條件,描述狀態轉移規律,另一個always模塊描述狀態輸出(可以用組合電路輸出,也可以時序電路輸出)。 一般推薦的FSM 描述方法是后兩種。因為FSM和其他設計一樣,最好使用同步時序方式設計,以提高設計的穩定性,消除毛刺。狀態機實現后,一般來說,狀態轉移部分是同步時序電路而狀態的轉移條件的判斷是組合邏輯。 第二種描述方法同第一種描述方法相比,將同步時序和組合邏輯分別放到不同的always模塊中實現,這樣做的好處不僅僅是便于閱讀、理解、維護,更重要的是利于綜合器優化代碼,利于用戶添加合適的時序約束條件,利于布局布線器實現設計。在第二種方式的描述中,描述當前狀態的輸出用組合邏輯實現,組合邏輯很容易產生毛刺,而且不利于約束,不利于綜合器和布局布線器實現高性能的設計。 第三種描述方式與第二種相比,關鍵在于根據狀態轉移規律,在上一狀態根據輸入條件判斷出當前狀態的輸出,從而在不插入額外時鐘節拍的前提下,實現了寄存器輸出。 4 狀態機的編碼 二進制編碼(Binary)、格雷碼(Gray-code)編碼使用最少的觸發器,較多的組合邏輯,而獨熱碼(One-hot)編碼反之。獨熱碼編碼的最大優勢在于狀態比較時僅僅需要比較一個位,從而一定程度上簡化了比較邏輯,減少了毛刺產生的概率。由于CPLD更多地提供組合邏輯資源,而FPGA更多地提供觸發器資源,所以CPLD多使用二進制編碼或格雷碼,而FPGA多使用獨熱碼編碼。另一方面,對于小型設計使用二進制和格雷碼編碼更有效,而大型狀態機使用獨熱碼更高效。 5 避免從case語句中綜合出鎖存器 不完整的case語句會生成鎖存器。 解決方法: (1)在case語句中對變量賦初值。 always @ (state or A or B) begin q=0; case(state) s0: q=A & B; s1: q=A| B; endcase end (2)在case語句中增加default語句。 always @ (state or A or B) begin case(state) s0: q=A & B; s1: q=A| B; default: q=0; endcase end (3)在case語句中使用full_case綜合指令。 always @ (state or A or B) begin case(state) /* synthesis full_case*/ s0: q=A & B; s1: q=A| B; endcase end 附加說明:當case語句中的所有選擇項是互斥的,為了簡化電路,不出現優先級解碼邏輯,可以使用 “synthesis parallel_case”綜合指令,減少不必要的邏輯資源。 6 狀態機例子 設計一個自動飲料售賣機,飲料10分錢,硬幣有5分和10分兩種,并考慮找零。 (1)點路變量分析:投入5分硬幣為一個變量,定義為A,為輸入;投入10分硬幣為一個變量,定義為B,為輸入;售貨機給出飲料為一變量,定義為Y,為輸出;售貨機找零為一變量,定義為Z,為輸出。 (2)狀態確定:電路共有兩個狀態:狀態S0,表示未投入任何硬幣;狀態S1,表示投入了5分硬幣。 (3)設計過程:設當前為S0狀態,當接收到5分硬幣時,轉換到S1狀態,等待繼續投入硬幣;當接收到10分硬幣時,保持S0狀態,彈出飲料,不找零。當前狀態為S1時,表示已經有5分硬幣,若再接收5分硬幣,轉換到S0狀態,彈出飲料,不找零;若接收到10分硬幣,轉換到S0狀態,彈出飲料,找零。 
module machine(clk,rst,A,B,Y,Z);
input clk,rst,A,B;
output Y,Z;
parameter S0=2’b01;
parameter S1=2’b10;
reg Y,Z;
reg [1:0] ns,cs;
always @ (posedge clk or negedge rst)
begin
if(!rst)
cs<=2'd0;
else
cs<=ns;
end always @ (cs,A,B,rst)
begin
if(!rst)
begin
ns=2'd0;Y=1'd0;Z=1'd0;
end
else
begin
case(cs)
S0:
begin
if(A) //5
begin
ns=S1; Y=1'd0;Z=1'd0;
end
else if(B) //10
begin
ns=S0;Y=1'd1;Z=1'd0;
end
else
begin
ns=S0;Y=1'd0;Z=1'd0;
end
end
S1:
begin
if(A) //5
begin
ns=S0; Y=1'd1;Z=1'd0;
end
else if(B) //10
begin
ns=S0; Y=1'd1;Z=1'd1;
end
else
begin
ns=S1; Y=1'd0;Z=1'd0;
end
end
endcase
end
end endmodule
|