有限状态机(FSM)的设计_zhangxianhe
有限状态机(FSM)是一种常见的电路,由时序电路和组合电路组成。
设计有限状态机的第一步是确定采用Moore 状态机还是采用Mealy 状态机。
Mealy 型:状态的转变不仅和当前状态有关,而且跟各输入信号有关;
Moore 型:状态的转变只和当前状态有关。
从实现电路功能来讲,任何一种都可以实现同样的功能。
但他们的输出时序不同,所以,在选择使用哪种状态机时要根据具体情况而定,在此,把他们的主要区别介绍一下:
1. Moore 状态机:在时钟脉冲的有限个门延时之后,输出达到稳定。输出会在一个完整的时钟周期内
保持稳定值,即使在该时钟内输入信号变化了,输出信号也不会变化。输入对输出的影响要到下一个时钟
周期才能反映出来。把输入和输出分开,是Moore 状态机的重要特征。
2. Mealy 状态机:由于输出直接受输入影响,而输入可以在时钟周期的任一时刻变化,这就使得输出状
态比Moore 状态机的输出状态提前一个周期到达。输入信号的噪声可能会出现在输出信号上。
3. 对同一电路,使用Moore 状态机设计可能会比使用Mealy 状态机多出一些状态。
根据他们的特征和要设计的电路的具体情况,就可以确定使用那种状态机来实现功能。一旦确定状态机,
接下来就要构造状态转换图。现在还没有一个成熟的系统化状态图构造算法,所以,对于实现同一功能,可以构造出不同的状态转换图。
但一定要遵循结构化设计。在构造电路的状态转换图时,使用互补原则可以帮助我们检查设计过程中是否出现了错误。
互补原则是指离开状态图节点的所有支路的条件必须是互补的。同一节点的任何2 个或多个支路的条件不能同时为真。
同时为真是我们设计不允许的。在检查无冗余状态和错误条件后,就可以开始用verilog HDL 来设计电路了。
有限状态机(FSM)是一种常见的电路,由时序电路和组合电路组成。
设计有限状态机的第一步是确定采用Moore 状态机还是采用Mealy 状态机。
Mealy 型:状态的转变不仅和当前状态有关,而且跟各输入信号有关;
Moore 型:状态的转变只和当前状态有关。
从实现电路功能来讲,任何一种都可以实现同样的功能。
但他们的输出时序不同,所以,在选择使用哪种状态机时要根据具体情况而定,在此,把他们的主要区别介绍一下:
1. Moore 状态机:在时钟脉冲的有限个门延时之后,输出达到稳定。输出会在一个完整的时钟周期内
保持稳定值,即使在该时钟内输入信号变化了,输出信号也不会变化。输入对输出的影响要到下一个时钟
周期才能反映出来。把输入和输出分开,是Moore 状态机的重要特征。
2. Mealy 状态机:由于输出直接受输入影响,而输入可以在时钟周期的任一时刻变化,这就使得输出状
态比Moore 状态机的输出状态提前一个周期到达。输入信号的噪声可能会出现在输出信号上。
3. 对同一电路,使用Moore 状态机设计可能会比使用Mealy 状态机多出一些状态。
根据他们的特征和要设计的电路的具体情况,就可以确定使用那种状态机来实现功能。一旦确定状态机,
接下来就要构造状态转换图。现在还没有一个成熟的系统化状态图构造算法,所以,对于实现同一功能,可以构造出不同的状态转换图。
但一定要遵循结构化设计。在构造电路的状态转换图时,使用互补原则可以帮助我们检查设计过程中是否出现了错误。
互补原则是指离开状态图节点的所有支路的条件必须是互补的。同一节点的任何2 个或多个支路的条件不能同时为真。
同时为真是我们设计不允许的。在检查无冗余状态和错误条件后,就可以开始用verilog HDL 来设计电路了。
在设计的过程中要注意以下方面:
1. full_case spec:所谓 Full Case 是指:FSM 的所有编码向量都可以与case 结构的某个分支或default 默认情况匹配起来。
如果一个FSM 的状态编码是8bit,则对应的256 个状态编码都可以与 case 的某个分支或者 default映射起来。
定义完全状态,即使有的状态可能在电路中不会出现。目的是避免综合出不希望的Latch,因为Latch可能会带来:a. 额外的延时;b. 异步Timing 问题
1. full_case spec:所谓 Full Case 是指:FSM 的所有编码向量都可以与case 结构的某个分支或default 默认情况匹配起来。
如果一个FSM 的状态编码是8bit,则对应的256 个状态编码都可以与 case 的某个分支或者 default映射起来。
定义完全状态,即使有的状态可能在电路中不会出现。目的是避免综合出不希望的Latch,因为Latch可能会带来:a. 额外的延时;b. 异步Timing 问题
①没有采用full-case
always @(CurrentState)begin case(CurrentState) ST0 : NextState = ST1; ST1 : NextState = ST2; ST2 : NextState = ST0; endcase end
②采用full-case
always @(CurrentState)begin case(CurrentState) //synthesis full_case ST0 : NextState = ST1; ST1 : NextState = ST2; ST2 : NextState = ST0; default : NextState = ST0; endcase end
2. parallel_case spec:所谓 Parallel Case 是指:在case 结构中,每个case 的判断条件表达式,
有且仅有唯一的case 语句的分支与之对应,即两者关系是一一对应关系。
确保不同时出现多种状态
确保不同时出现多种状态
①没采用parallel-case
case({En3, En2, En1}) 3'b??1 : Out = In1; 3'b?1? : Out = In2; 3'b1?? : Out = In3; endcase
②采用parallel-case
case({En3, En2, En1}) //synthesis parallel_case 3'b??1 : Out = In1; 3'b?1? : Out = In2; 3'b1?? : Out = In3; endcase
3. 禁止使用casex
casex 在综合时,认为Z,X 为Dont cares,会导致前仿真和后仿真不一致。如果电路中出现X,一定要分析是否会传递。
4. 推荐在模块划分时,把状态机设计分离出来,便于使用综合根据对状态机优化。
5. 在条件表达式或附值语句中,要注意向量的宽度适配。否则,前仿真和后仿真不一致,RTL 级的功能验证很难找出问题所在。
4. 推荐在模块划分时,把状态机设计分离出来,便于使用综合根据对状态机优化。
5. 在条件表达式或附值语句中,要注意向量的宽度适配。否则,前仿真和后仿真不一致,RTL 级的功能验证很难找出问题所在。
状态机设计的其他技巧
1.FSM编码
Binary(二进制编码)、gray-code(格雷码)编码使用最少的触发器,较多的组合逻辑,而one-hot(独热码)编码反之。
one-hot 编码的最大优势在于状态比较时仅仅需要比较一个bit,一定程度上从而简化了比较逻辑,减少了毛刺产生的概率。
FPGA 更多地提供触发器资源,所以FPGA 多使用one-hot 编码。
另一方面,对于小型设计使用gray-code 和binary 编码更有效,而大型状态机使用one-hot 更高效。
2.FSM 初始化状态
大多数FPGA 有GSR(Global Set/Reset)信号,当FPGA 加电后,GSR 信号拉高,对所有的寄存器、RAM 等单元置位/复位,
这时配置于FPGA 的逻辑并未生效,所以不能保证正确地进入初始化状态。
所以使用GSR 企图进入FPGA 的初始化状态,常常会产生种种不必要的麻烦。
一般的方法是采用异步复位信号,当然也可以使用同步复位,但是要注意同步复位逻辑的设计。
解决这个问题的另一种方法是将默认的初始状态的编码设为全零,这样GSR 复位后,状态机自动进入初始状态。
3.FSM 状态编码定义
Verilog HDL描述状态机时必须由parameter分配好状态。
4.FSM 输出
如果使用 2 段式FSM 描述Mealy 状态机,输出逻辑可以用"?语句"描述,或者使用case 语句判断转移条件与输入信号即可
5.阻塞和非阻塞赋值
为了避免不必要的竞争冒险,不论是做两段式还是三段式 FSM 描述时,
必须遵循时序逻辑always 模块使用非阻塞赋值"<=",即当前状态向下一状态时序转移,和寄存FSM 输出等时序always 模块中都要使用非阻塞赋值;
而组合逻辑always 模块使用阻塞赋值"=",即状态转移条件判断,组合逻辑输出等always 模块中都要使用阻塞赋值。
6.FSM 的默认状态
完整的状态机应该包含一个默认(default)状态,当转移条件不满足,或者状态发生了突变时,要能保证逻辑不会陷入"死循环"。
这是对状态机健壮性的一个重要要求,也就是常说的要具备"自恢复"功能。
1.FSM编码
Binary(二进制编码)、gray-code(格雷码)编码使用最少的触发器,较多的组合逻辑,而one-hot(独热码)编码反之。
one-hot 编码的最大优势在于状态比较时仅仅需要比较一个bit,一定程度上从而简化了比较逻辑,减少了毛刺产生的概率。
FPGA 更多地提供触发器资源,所以FPGA 多使用one-hot 编码。
另一方面,对于小型设计使用gray-code 和binary 编码更有效,而大型状态机使用one-hot 更高效。
2.FSM 初始化状态
大多数FPGA 有GSR(Global Set/Reset)信号,当FPGA 加电后,GSR 信号拉高,对所有的寄存器、RAM 等单元置位/复位,
这时配置于FPGA 的逻辑并未生效,所以不能保证正确地进入初始化状态。
所以使用GSR 企图进入FPGA 的初始化状态,常常会产生种种不必要的麻烦。
一般的方法是采用异步复位信号,当然也可以使用同步复位,但是要注意同步复位逻辑的设计。
解决这个问题的另一种方法是将默认的初始状态的编码设为全零,这样GSR 复位后,状态机自动进入初始状态。
3.FSM 状态编码定义
Verilog HDL描述状态机时必须由parameter分配好状态。
4.FSM 输出
如果使用 2 段式FSM 描述Mealy 状态机,输出逻辑可以用"?语句"描述,或者使用case 语句判断转移条件与输入信号即可
5.阻塞和非阻塞赋值
为了避免不必要的竞争冒险,不论是做两段式还是三段式 FSM 描述时,
必须遵循时序逻辑always 模块使用非阻塞赋值"<=",即当前状态向下一状态时序转移,和寄存FSM 输出等时序always 模块中都要使用非阻塞赋值;
而组合逻辑always 模块使用阻塞赋值"=",即状态转移条件判断,组合逻辑输出等always 模块中都要使用阻塞赋值。
6.FSM 的默认状态
完整的状态机应该包含一个默认(default)状态,当转移条件不满足,或者状态发生了突变时,要能保证逻辑不会陷入"死循环"。
这是对状态机健壮性的一个重要要求,也就是常说的要具备"自恢复"功能。
组合逻辑和时序逻辑分开用不同的进程
组合逻辑包括状态译码和输出,时序逻辑则是状态寄存器的切换,
必须包括对所有状态都处理,不能出现无法处理的状态,使状态机失控
组合逻辑包括状态译码和输出,时序逻辑则是状态寄存器的切换,
必须包括对所有状态都处理,不能出现无法处理的状态,使状态机失控
Mealy状态机的例子如下:
View Code
View Code
module FSM(Clk, Rst_,In1,In2,Out1); input Clk; //system Clock input Rst_; //async Reset, active low input In1,In2; //FSM input signals output Out1; //FSM output signals //define output signals type reg Out1; // Declare the symbolic names for states Parameter S0=0,S1=1; // Declare current state and next state variables reg CurrentState; reg NextState; always@(posedge Clk or negedge Rst_)begin if (!Rst_)begin CurrentState=S0; end else begin CurrentState=NextState; end end always @(In1 or In2 or CurrentState)begin // output and state vector decode (combinational) case (CurrentState) S0:begin NextState <= S1; Out1 <= 1'b0; end S1:begin if (In1)begin NextState <= S0; Out1 <= In2; end else begin NextState <= S1; Out1 <= !In2; end endcase end endmodule
下图是一个状态机的状态转换图,在Verilog HDL 中我们可以用如下方法设计该状态机。
例:One-hot编码(FPGA 多使用one-hot 编码)
module ONE_HOT_FSM (Clock, Rst_, A, B, C, D, E,Single, Multi, Contig); input Clock; //system Clock input Rst_; //async Reset, active low input A, B, C, D, E; //FSM input signals output Single, Multi, Contig; //FSM output signals //define output signals type reg Single; reg Multi; reg Contig; // Declare the symbolic names for states parameter [6:0] // enum STATE_TYPE one-hot S1 = 7'b0000001, S2 = 7'b0000010, S3 = 7'b0000100, S4 = 7'b0001000, S5 = 7'b0010000, S6 = 7'b0100000, S7 = 7'b1000000; parameter U_DLY = 1; // Declare current state and next state variables reg [2:0] CurrentState; reg [2:0] NextState; //CurrentState assignment, sequential logic always @ (posedge Clock or posedge Reset)begin if (!Rst_)begin CurrentState <= S1; end else begin CurrentState <= #U_DLY NextState; end end //combinational logic always @ (CurrentState or A or B or C or D or E)begin case(CurrentState) S1:begin Multi = 1'b0; Contig = 1'b0; Single = 1'b0; if(A&~B&C)begin NextState=S2; end else if(A&B&~C)begin NextState=S4; end else begin NextState=S1; end end S2:begin Multi = 1'b1; Contig = 1'b0; Single = 1'b0; if(!D)begin NextState=S3; end else begin NextState=S4; end end S3:begin Multi = 1'b0; Contig = 1'b1; Single = 1'b0; if(A|D)begin NextState=S4; end else begin NextState=S3; end end S4:begin Multi = 1'b1; Contig = 1'b1; Single = 1'b0; if(A&B&~C)begin NextState=S5; end else begin NextState=S4; end end S5:begin Multi = 1'b1; Contig = 1'b0; Single = 1'b0; NextState=S6; end S6:begin Multi = 1'b0; Contig = 1'b1; Single = 1'b1; if(!E)begin NextState=S7; end else begin NextState=S6; end S7:begin Multi = 1'b0; Contig = 1'b1; Single = 1'b1; if(E)begin NextState=S1; end else begin NextState=S7; end end endcase end endmodule
例2:Binary 编码(小型设计使用gray-code 和binary 编码更有效,而大型状态机使用one-hot 更高效。)
module binary (Clock, Reset, A, B, C, D, E,Single, Multi, Contig); input Clock; //system Clock input Rst_; //async Reset, active low input A, B, C, D, E; //FSM input signals output Single, Multi, Contig; //FSM output signals //define output signals type reg Single; reg Multi; reg Contig; // Declare the symbolic names for states parameter [2:0] // enum STATE_TYPE binary S1 = 3'b001, S2 = 3'b010, S3 = 3'b011, S4 = 3'b100, S5 = 3'b101, S6 = 3'b110, S7 = 3'b111; parameter U_DLY = 1; // Declare current state and next state variables reg [2:0] CurrentState; reg [2:0] NextState; //CurrentState assignment, sequential logic always @ (posedge Clock or posedge Reset)begin if (!Rst_)begin CurrentState <= S1; end else begin CurrentState <= #U_DLY NextState; end end //combinational logic always @ (CurrentState or A or B or C or D or E)begin case(CurrentState) S1:begin Multi = 1'b0; Contig = 1'b0; Single = 1'b0; if(A&~B&C)begin NextState=S2; end else if(A&B&~C)begin NextState=S4; end else begin NextState=S1; end end S2:begin Multi = 1'b1; Contig = 1'b0; Single = 1'b0; if(!D)begin NextState=S3; end else begin NextState=S4; end end S3:begin Multi = 1'b0; Contig = 1'b1; Single = 1'b0; if(A|D)begin NextState=S4; end else begin NextState=S3; end end S4:begin Multi = 1'b1; Contig = 1'b1; Single = 1'b0; if(A&B&~C)begin NextState=S5; end else begin NextState=S4; end end S5: begin Multi = 1'b1; Contig = 1'b0; Single = 1'b0; NextState=S6; end S6: begin Multi = 1'b0; Contig = 1'b1; Single = 1'b1; if(!E) begin NextState=S7; end else begin NextState=S6; end S7:begin Multi = 1'b0; Contig = 1'b1; Single = 1'b1; if(E)begin NextState=S1; end else begin NextState=S7; end end endcase end endmodule
有限状态机的介绍就先到此,前段时间没时间更新,以后尽量多更新。