一段式状态机:
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 cs <= WR_S1; cmd <= 3‘b011; end 13 else if (rd_req) begin cs <= RD_S1; cmd <= 3‘b011; end 14 else begin cs <= IDLE; cmd <= 3‘b111; end 15 WR_S1: begin cs <= WR_S2; cmd <= 3‘b101; end 16 WR_S2: begin cs <= IDLE; cmd <= 3‘b111; end 17 RD_S1: if (wr_req) begin cs <= WR_S2; cmd <= 3‘b101; end 18 else begin cs <= RD_S2; cmd <= 3‘b110; end 19 RD_S2: if (wr_req) begin cs <= WR_S1; cmd <= 3‘b011; end 20 else begin cs <= IDLE; cmd <= 3‘b111; 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 <= 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)三段式状态机推荐写法,代码易维护,时序逻辑输出解决了两段式写法种组合逻辑的毛刺问题,但是耗费资源多一些且三段式从输入到输出比一段式和两段式会延时一个时钟周期。