描述状态机推荐采用三段式FSM描述方法。这种写法使用3个always模块,一个always模块采用同步时序的方式描述状态转移,一个always采用组合逻辑的方式判断状态转移条件,描述状态转移规律,第三个always模块使用同步时序电路描述每个状态的输出。
这种做法好处在于便于阅读、理解、维护,更重要的是利于综合器优化代码。利于用户添加合适的时序约束条件,利于布局布线器实现设计。
三段式FSM写法参考如下程序:
module fsm(in1, in2, clk, rst_n, out1, out2, err); input in1, in2; input clk, rst_n; output out1, out2; output err; reg out1, out2; reg err; reg[2:0] CS, NS; parameter[2:0] IDLE = 3'b000, S1 = 3'b001, S2 = 3'b010, ERROR = 3'B100; //时序逻辑,状态转移 always @(posedge clk or negedge rst_n) begin if (!rst_n) CS <= IDLE; else CS <= NS; end //组合逻辑,状态转移条件判断 always @(rst_n, CS, in1, in2) begin NS = 3'bX; case (CS) IDLE: begin if (!in1) NS = IDLE; if (in1 && in2) NS = S1; if (in1 && !in2) NS = ERROR; end S1: begin if (!in2) NS = S1; if (in1 && in2) NS = S2; if (!in1 && in2) NS = ERROR; end S2: begin if (in2) NS = S2; if (in1 && !in2) NS = IDLE; if (!in1 && !in2) NS = ERROR; end ERROR: begin if (in1) NS = ERROR; if (!in1) NS = IDLE; end default: NS = IDLE; endcase; end //时序逻辑,状态机输出 always @(posedge clk or negedge rst_n) begin if (!rst_n) {out1, out2, err} <= 3'b000; else begin {out1, out2, err} <= 3'b000; case (NS) IDLE: {out1, out2, err} <= 3'b000; S1: {out1, out2, err} <= 3'b100; S2: {out1, out2, err} <= 3'b010; ERROR: {out1, out2, err} <= 3'b111; default: {out1, out2, err} <= 3'b000; endcase end end endmodule