有限状态机(FSM)的设计

有限状态机(FSM)的设计_zhangxianhe
 有限状态机(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 问题
①没有采用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 级的功能验证很难找出问题所在。
状态机设计的其他技巧 
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状态机的例子如下:
 
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            
View Code

例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    
View Code

有限状态机的介绍就先到此,前段时间没时间更新,以后尽量多更新。

猜你喜欢

转载自www.cnblogs.com/zhangxianhe/p/10073599.html