三种不同状态机写法

一段式状态机:

 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 <=  3'b111;
 6     end
 7     else begin
 8         case (cs)
 9             IDLE :   if (wr_req) begin cs <= WR_S1; cmd <= 3'b011; end
10                 else if (rd_req) begin cs <= RD_S1; cmd <= 3'b011; end
11                 else             begin cs <= IDLE;  cmd <= 3'b111; end
12             WR_S1:               begin cs <= WR_S2; cmd <= 3'b101; end
13             WR_S2:               begin cs <= IDLE;  cmd <= 3'b111; end
14             RD_S1:   if (wr_req) begin cs <= WR_S2; cmd <= 3'b101; end
15                      else        begin cs <= RD_S2; cmd <= 3'b110; end
16             RD_S2:   if (wr_req) begin cs <= WR_S1; cmd <= 3'b011; end
17                      else        begin cs <= IDLE;  cmd <= 3'b111; 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 ns <= WR_S1; cmd <= 3'b011; end
13             else if (rd_req) begin ns <= RD_S1; cmd <= 3'b011; end
14             else             begin ns <= IDLE;  cmd <= 3'b111; end
15         WR_S1:               begin ns <= WR_S2; cmd <= 3'b101; end
16         WR_S2:               begin ns <= IDLE;  cmd <= 3'b111; end
17         RD_S1:   if (wr_req) begin ns <= WR_S2; cmd <= 3'b101; end
18                  else        begin ns <= RD_S2; cmd <= 3'b110; end
19         RD_S2:   if (wr_req) begin ns <= WR_S1; cmd <= 3'b011; end
20                  else        begin ns <= IDLE;  cmd <= 3'b111; end
21         default :                  ns <= 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 ns <= WR_S1; end
13             else if (rd_req) begin ns <= RD_S1; end
14             else             begin ns <= IDLE;  end
15         WR_S1:               begin ns <= WR_S2; end
16         WR_S2:               begin ns <= IDLE;  end
17         RD_S1:   if (wr_req) begin ns <= WR_S2; end
18                  else        begin ns <= RD_S2; end
19         RD_S2:   if (wr_req) begin ns <= WR_S1; end
20                  else        begin ns <= IDLE;  end
21         default :                  ns <= IDLE;
22     endcase
23 end
24 //----------   时序逻辑   ------------------
25 always @(posedge clk or negedge rst_n) begin
26     if (!rst_n)
27         cmd    <=  3'b011;
28     else begin
29         case (ns)  //次态
30             IDLE :   if (wr_req) begin cmd <= 3'b011; end
31                 else if (rd_req) begin cmd <= 3'b011; end
32                 else             begin cmd <= 3'b111; end
33             WR_S1:               begin cmd <= 3'b101; end
34             WR_S2:               begin cmd <= 3'b111; end
35             RD_S1:   if (wr_req) begin cmd <= 3'b101; end
36                      else        begin cmd <= 3'b110; end
37             RD_S2:   if (wr_req) begin cmd <= 3'b011; end
38                      else        begin cmd <= 3'b111; end
39             default : ;
40         endcase 
41     end
42 end

 

三种写法对比:

    (1)一段式状态机不利于维护(简单状态机可以用);

    (2)两段式状态机是常见写法,时序逻辑进行状态切换,时序逻辑实现各个输入、输出以及状态判断,利于维护,不过组合逻辑容易出现毛刺等常见问题;

    (3)三段式状态机推荐写法,代码易维护,时序逻辑输出解决了两段式写法种组合逻辑的毛刺问题,但是耗费资源多一些且第三段 always 如果判断条件是 cs 从输入到输出比一段式和两段式会延时一个时钟周期。

注意:

  1. 三段式并不是一定要写为3个always块,如果状态机更复杂,就不止3段了。
  2. 三段always模块中,第一个和第三个always模块是同步时序always模块,用非阻塞赋值(“ <= ”);第二个always模块是组合逻辑always模块,用阻塞赋值(“ = ”)。
  3. 第二部分为组合逻辑always模块,为了抑制warning信息,对于always的敏感列表建议采用always@(*)的方式。
  4. 第二部分,组合逻辑always模块,里面判断条件一定要包含所有情况!可以用else保证包含完全。
  5. 第二部分,组合逻辑电平要维持超过一个clock,仿真时注意。
  6. 需要注意:第二部分case中的条件应该为当前态(cs)。
  7. 第三部分case中的条件为次态(ns)或者当前态(cs),根据需求,若为当前态(cs)则延时一个时钟周期。
  8. 编码原则,binary和gray-code适用于触发器资源较少,组合电路资源丰富的情况(CPLD),对于FPGA,适用one-hot code。这样不但充分利用FPGA丰富的触发器资源,还因为只需比较一个bit,速度快,组合电路简单。

 

参考:

《深入浅出玩转FPGA_第二版》P27 - P34

verilog 三段式状态机的技巧

[资料] 彻底搞懂状态机(一段式、两段式、三段式)!一个实例,三种方法对比看!!!(程序)

转载于:https://www.cnblogs.com/yllinux/p/8641634.html

你可能感兴趣的:(三种不同状态机写法)