有限狀態機 寫RTL的時候,實現一個功能的時候有很多種方法 將系統劃分為多個狀態,狀態之間有狀態的轉移,第一步,第二步,,,,形成有限狀態機 流水線技術設計,從輸入到輸出有多個步驟 有限狀態機,狀態是有限的,比如8個狀態,16個狀態等,在進行設計的時候,狀態機的狀態不要太多,狀態超過10個,就會造成 ...
有限狀態機
寫RTL的時候,實現一個功能的時候有很多種方法
- 將系統劃分為多個狀態,狀態之間有狀態的轉移,第一步,第二步,,,,形成有限狀態機
- 流水線技術設計,從輸入到輸出有多個步驟
有限狀態機,狀態是有限的,比如8個狀態,16個狀態等,在進行設計的時候,狀態機的狀態不要太多,狀態超過10個,就會造成設計複雜度和驗證複雜度都變高.
有限狀態機分類
- Moore FSM
輸出只與當前的狀態有關,與輸入沒有關係 - Mealy FSM
輸出不僅與當前的狀態有關,還與輸入有關
Moore FSM-設計自動售貨機
分析輸入輸出信號
- 自動售貨機,輸入的就是硬幣,輸出的是飲料和找零 (確定輸入,輸出)
- 假設飲料只有一種價格2.5元,輸入的零錢只有一元和五角(兩種狀態,用1bit表示),找零的情況只有兩種0元和5角(用1bit表示)(確定輸出輸出的狀態,用幾位的信號表示)
定義介面
- 狀態機要存儲一些狀態,肯定會有一些寄存器,會有時鐘和複位信號
- 在設計一個模塊的時候,最先確定輸入輸出的埠和位寬以及時序
定義時序
- 輸入的一元和五角不能同時為1(確定輸入的約束)
內部實現--畫出狀態轉移圖
要存儲當前已經存儲了多少錢,初始狀態時0,可以收到1元和5角
- IDLE就是當前系統是空閑狀態,沒有收到任何的投幣
- 這是一個Moore類型的有限狀態機,輸出只與當前的狀態有關
Moore有限狀態機電路特點
- 輸入與當前的狀態有關,所以需要一個寄存器存儲當前的狀態
- 寄存器存儲的狀態輸入給組合邏輯之後,進行輸出
- 輸入與當前的狀態值,經過組合邏輯之後,輸入給寄存器
- 時序清晰,輸入和輸出,沒有一條直接的組合邏輯路徑;如果輸入經過組合邏輯,沒有經過寄存器,直接輸出,這樣的設計不好;因為不知道周圍環境的組合邏輯的時序是多少
Code
module drink_status_moore(
input clk,
input reset,
input half,
input one,
output out,
output cout
);
parameter [2:0] s0 = 3'b000,
s1 = 3'b001,
s2 = 3'b010,
s3 = 3'b011,
s4 = 3'b100,
s5 = 3'b101,
s6 = 3'b110; //定義6個狀態
reg [2:0] curr_state; //當前狀態 CS
reg [2:0] next_state; //下一個狀態 NS reg定義的信號不一定是寄存器
//第一段:聲明一個寄存器,state transfer
always @ (posedge clk ,negedge reset) begin
if(~reset)
curr_state <= s0; //這裡時鐘來了之後,就寄存器傳輸,寄存器功耗比較大,需要給寄存器傳輸添加條件
else
curr_state <= #1 next_state;
end
//第二段,根據條件寫出中間狀態轉移
always @ (curr_state,half,one) begin
case(curr_state)
s0:begin
if(half) next_state = s1; //如果兩個投幣口,就會出現問題,一次投入可能為1.5元,所以要給輸入添加約束
else of(one) next_state = s2; //文件和文件之間需要進行一些約束
else next_state = S0;
end
s1:begin
if(half) next_state = s2;
else of(one) next_state = s3;
else next_state = S1;
end
s2:begin
if(half) next_state = s3;
else of(one) next_state = s4;
else next_state = S2;
end
s3:begin
if(half) next_state = s4;
else of(one) next_state = s5;
else next_state = S3;
end
s4:begin
if(half) next_state = s5;
else of(one) next_state = s6;
else next_state = S4;
end
s5:begin
next_state = s0;
end
s6:begin
next_state = s0;
end
default: next_state = s0;
end
//第三段,寫出輸出
assign out = (curr_state == s5) || (curr_State = s6) ? 1:0;
assign cout = (curr_state == s6) ? 1:0;
endmodule
FSM 三段式的書寫方式
mealy FSM-自動售貨機
- 相當於在當前狀態,考慮之後輸入的狀態
- 輸入經過組合邏輯之後直接得到輸出
module drink_status_moore(
input clk,
input reset,
input half,
input one,
output out,
output cout
);
parameter [2:0] s0 = 3'b000,
s1 = 3'b001,
s2 = 3'b010,
s3 = 3'b011,
s4 = 3'b100; //定義6個狀態,變數名需要更加具有含義
reg [2:0] curr_state; //當前狀態 CS
reg [2:0] next_state; //下一個狀態 NS reg定義的信號不一定是寄存器
//第一段:聲明一個寄存器,state transfer
always @ (posedge clk ,negedge reset) begin
if(~reset)
curr_state <= s0; //這裡時鐘來了之後,就寄存器傳輸,寄存器功耗比較大,需要給寄存器傳輸添加條件
else
curr_state <= #1 next_state;
end
//第二段,根據條件寫出中間狀態轉移
always @ (*) begin
case(curr_state)
s0:begin
if(half) next_state = s1; //如果兩個投幣口,就會出現問題,一次投入可能為1.5元,所以要給輸入添加約束
else of(one) next_state = s2; //文件和文件之間需要進行一些約束
else next_state = S0;
end
s1:begin
if(half) next_state = s2;
else of(one) next_state = s3;
else next_state = S1;
end
s2:begin
if(half) next_state = s3;
else of(one) next_state = s4;
else next_state = S2;
end
s3:begin
if(half) next_state = s4;
else of(one) next_state = s0;
else next_state = S3;
end
s4:begin
if(half) next_state = s0;
else of(one) next_state = s0;
else next_state = S4;
end
default: next_state = s0;
endcase
end
//第三段,寫出輸出
assign out = ((curr_state == s4) & (half | one)) ? 1:
((curr_state == s3) & (one)) ? 1 : 0;
assign cout = (curr_state == s4) & (one) ? 1 : 0;
endmodule
FSM有限狀態機的設計步驟
- 介面定義(信號\位寬\約束)
- 狀態定義和編碼
- 狀態轉換圖
- 按照三段式風格實現RTL代碼
- 編寫Testbench
- 使用QuestaSim進行編譯和模擬
- 通過波形工具查看激勵\狀態信號和輸出信號
- Moore機輸出只與當前狀態有關
- Mealy輸出不僅與當前的狀態有關,還與當前的輸入有關
狀態機的電路邏輯圖
FSM要註意的問題
- case語句,要將所有的case列全
- 使用default語句還原狀態;如果不寫default,就需要寫夠所有可能
序列檢測器
- 輸入就是1bit的x,輸出的y也是1bity
- 定義當前的狀態,存儲之前存儲的序列是怎樣的狀態,初始為IDLE,中間狀態可能會出現中間狀態
- IDLE在定義的時候,檢測的序列是從1開始的,IDLE可以直接設計為初始值為1,中間狀態出現01,10等不對的狀態,可以取消掉
module seq(in,out,clk,reset,state);
input in;
input clk;
input reset;
output out;
output [2:0] state;
reg [2:0] curr_state;
reg [2:0] next_state;
parameter [2:0] s0 = 3'b000,
s1 = 3'b001,
s2 = 3'b010,
s3 = 3'b011,
s4 = 3'b100,
s5 = 3'b101,
s6 = 3'b110,
s7 = 3'b111;
// 定義寄存器
always @ (posedge clk , negedge reset)
begin
if(~reset)
curr_state <= S0;
else
curr_state <= next_state;
end
// 寫狀態轉移
always @ (in,curr_state)
begin
case(curr_state)
s0 : begin
if(in == 0) next_state <= s0;
else next_state <= s1;
end
s1 : begin
if(in == 0) next_state <= s0;
else next_state <= s2;
end
s2 : begin
if(in == 0) next_state <= s0;
else next_state <= s3;
end
s3 : begin
if(in == 0) next_state <= s4;
else next_state <= s3;
end
s4 : begin
if(in == 0) next_state <= s5;
else next_state <= s1;
end
s5 : begin
if(in == 0) next_state <= s0;
else next_state <= s6;
end
s6 : begin
if(in == 0) next_state <= s7;
else next_state <= s2;
end
s7 : begin
if(in == 0) next_state <= s0;
else next_state <= s1;
end
default: next_state <= s0;
endcase
end
// 輸出
assign out = (curr_state == s7) ? 1 : 0 ;
endmodule