1,單always塊結構(一段式):
always @(posedge clk ) begin
case(FSM)
st0;begin
out0;//輸出
if(case0) FSM<=st1;//狀態轉移
end
st1;begin
out1;//輸出
if(case0) FSM<=st2;//狀態轉移
end
……
default:
endcase
end
單always塊把組合邏輯和時序邏輯放在一個時序always塊描述。輸出時為寄存器輸出,所以無毛刺。但是這種方式會產生多余的觸發器(因為把組合邏輯也放在時序邏輯中實現),而且代碼難以修改調試。但對於那些簡單的狀態機,一段式還是不錯的,因為它把輸入,轉移,輸出一起體現,更方便理解。但是對於復雜狀態機就是災難了,所以最好還是養成不使用該結構的習慣。
雙always塊結構(兩段式):
//時序邏輯,這段一般是不變的,描述從現態轉移到次態
always @ (posedge clk) begin
current_state<=next_state;
end
//組合邏輯,包括轉移條件以及狀態內容(即輸出)
always @ (*) begin
case(current_state)
st0:begin
out0;
if(case0) FSM=st1; //組合邏輯使用阻塞語句
end
st1:begin
out1;
if(case1) FSM=st2;
end
……
endcase
end
二段式中,一個always塊采用同步時序描述狀態轉移;另一個采用組合邏輯判斷轉移條件,以及描述輸出。二段式便於閱讀,理解和維護,有利於綜合器優化代碼。但是由於采用的是組合邏輯輸出,容易產生毛刺,且不利於約束,也不利於綜合器和布局布線器實現高性能設計。
三always塊結構(三段式):
//第一個always塊,時序邏輯,描述現態轉移到次態
always @ (posedge clk negedge rst_n) begin
if(!rst_n) current_state<=IDLE;
else current_state<=next_state;
end
//第二個always塊,組合邏輯,描述狀態轉移的條件
always @ (current_state) begin
case(current_state)
s1:if(……) next_state=s2;//組合邏輯,采用阻塞賦值
……
endcase
end
//第三個always塊,時序邏輯,描述輸出
always @ (posedge clk negedge rst_n) begin
case(next_state) //這里有的是next_state,有的是current_state,需根據電路要求
s1: out1<=……;
s2: out2<=……;
default:……
endcase
end
三段式結構中,2個時序always塊分別用來描述現態邏輯轉移,及輸出賦值。組合always塊用於描述狀態轉移的條件。這種結構是寄存器輸出,輸出無毛刺,而且代碼更清晰易讀,特別是對於復雜的狀態機來說,但是消耗的面積也更多點。這是一種比較流行的狀態機結構。