1. 程式人生 > >三種不同狀態機寫法

三種不同狀態機寫法

begin 狀態機 nbsp OS 時鐘 pre 組合 cmd 周期

一段式狀態機:

 1 reg[3:0]  cs, ns;
 2 always @(posedge clk or negedge rst_n) begin
 3     if (!rst_n) begin
 4         cs    <=  IDLE;
 5         cmd <=  3b111;
 6     end
 7     else begin
 8         case (cs)
 9             IDLE :   if (wr_req) begin cs <= WR_S1; cmd <= 3b011; end
10                 else
if (rd_req) begin cs <= RD_S1; cmd <= 3b011; end 11 else begin cs <= IDLE; cmd <= 3b111; end 12 WR_S1: begin cs <= WR_S2; cmd <= 3b101; end 13 WR_S2: begin cs <= IDLE; cmd <= 3b111; end 14 RD_S1: if
(wr_req) begin cs <= WR_S2; cmd <= 3b101; end 15 else begin cs <= RD_S2; cmd <= 3b110; end 16 RD_S2: if (wr_req) begin cs <= WR_S1; cmd <= 3b011; end 17 else begin cs <= IDLE; cmd <= 3b111; end 18 default
: cs <= IDLE; 19 endcase 20 end 21 end

兩段式狀態機:

 1 reg[3:0]  cs, ns;
 2 //----------   時序邏輯   ------------------
 3 always @(posedge clk or negedge rst_n) begin
 4     if (!rst_n)
 5         cs    <=  IDLE;
 6     else 
 7         cs    <=  ns;
 8 end
 9 //----------   組合邏輯   ------------------
10 always @(*) begin
11     case (cs)
12         IDLE :   if (wr_req) begin cs <= WR_S1; cmd <= 3b011; end
13             else if (rd_req) begin cs <= RD_S1; cmd <= 3b011; end
14             else             begin cs <= IDLE;  cmd <= 3b111; end
15         WR_S1:               begin cs <= WR_S2; cmd <= 3b101; end
16         WR_S2:               begin cs <= IDLE;  cmd <= 3b111; end
17         RD_S1:   if (wr_req) begin cs <= WR_S2; cmd <= 3b101; end
18                  else        begin cs <= RD_S2; cmd <= 3b110; end
19         RD_S2:   if (wr_req) begin cs <= WR_S1; cmd <= 3b011; end
20                  else        begin cs <= IDLE;  cmd <= 3b111; end
21         default :                  cs <= IDLE;
22     endcase
23 end

三段式狀態機:

 1 reg[3:0]  cs, ns;
 2 //----------   時序邏輯   ------------------
 3 always @(posedge clk or negedge rst_n) begin
 4     if (!rst_n)
 5         cs    <=  IDLE;
 6     else 
 7         cs    <=  ns;
 8 end
 9 //----------   組合邏輯   ------------------
10 always @(*) begin
11     case (cs)  //現態
12         IDLE :   if (wr_req) begin cs <= WR_S1; end
13             else if (rd_req) begin cs <= RD_S1; end
14             else             begin cs <= IDLE;  end
15         WR_S1:               begin cs <= WR_S2; end
16         WR_S2:               begin cs <= IDLE;  end
17         RD_S1:   if (wr_req) begin cs <= WR_S2; end
18                  else        begin cs <= RD_S2; end
19         RD_S2:   if (wr_req) begin cs <= WR_S1; end
20                  else        begin cs <= IDLE;  end
21         default :                  cs <= IDLE;
22     endcase
23 end
24 //----------   時序邏輯   ------------------
25 always @(posedge clk or negedge rst_n) begin
26     if (!rst_n)
27         cmd    <=  3b011;
28     else begin
29         case (ns)  //次態
30             IDLE :   if (wr_req) begin cmd <= 3b011; end
31                 else if (rd_req) begin cmd <= 3b011; end
32                 else             begin cmd <= 3b111; end
33             WR_S1:               begin cmd <= 3b101; end
34             WR_S2:               begin cmd <= 3b111; end
35             RD_S1:   if (wr_req) begin cmd <= 3b101; end
36                      else        begin cmd <= 3b110; end
37             RD_S2:   if (wr_req) begin cmd <= 3b011; end
38                      else        begin cmd <= 3b111; end
39             default : ;
40         endcase 
41     end
42 end

三種寫法對比:

(1)一段式狀態機不利於維護(簡單狀態機可以用);

(2)兩段式狀態機是常見寫法,時序邏輯進行狀態切換,時序邏輯實現各個輸入、輸出以及狀態判斷,利於維護,不過組合邏輯容易出現毛刺等常見問題;

(3)三段式狀態機推薦寫法,代碼易維護,時序邏輯輸出解決了兩段式寫法種組合邏輯的毛刺問題,但是耗費資源多一些且三段式從輸入到輸出比一段式和兩段式會延時一個時鐘周期。

三種不同狀態機寫法