Verilog HDL中有限状态机的简单实例运用(两段式、三段式)

540 阅读6分钟

有限状态机

有限状态机的描述方式很多,在Verilog HDL中常用的有限状态机描述方式是两段式和三段式(一段式非常不推荐)。有限状态机三段描述方式实际上对应的是时序电路中的三个方程:状态转移方程、激励方程和输出方程。两段式描述实际上是将激励方程和输出方程合并在一段中,因此,两段式和三段式的描述方式在本质上是一致的。

图片.png 有限状态机一般包括寄存器逻辑和组合逻辑两部分,寄存器用于存储状态,组合逻辑用于状态译码和产生输出信号。状态机转移部分是存储电路,而状态的转移判断条件的判断是组合逻辑。 想掌握好状态机,以下几个要素必不可忽略:

  • 输入、输出和状态
  • 状态转移图
  • 状态编码:独热码、二进制码和格雷码的优劣

以下面这个例子展开,先从数字电路分析开始,后再使用Verilog HDL进行状态机的描述,让我们慢慢剖析其中奥秘!

例:设计一个五进制同步加法计数器,且该计数器带有进位输出。

数字电路简要分析

  1. 确定输入、输出变量个数 本设计为一个五进制计数器,并没有输入,只有一个输出进位信号z。需要设计的是同步五进制计数器,状态个数为五个(异步计数器需要六个状态),我们使用S0,S1,S2,S3,S4表示这五个状态。

  2. 确定触发器的个数。本文暂使用二进制编码方式,根据数电知识,有一个计算公式

2m1<N<2m2^m-1<N<2^m

其中N为状态数,m为所需要的触发器,很容易得知,m=3,即只要三个触发器。

  1. 状态编码。 独热码即每个状态数只有1bit为1,其余都为0。有N个状态,就要N位宽的状态变量。独热码每个状态只有1bit是不同的,综合器会将其识别为一个个比较器,而每次比较的位为1位,节省了大量组合逻辑资源,虽然使用寄存器资源有所增多,谁叫咱FPGA中寄存器资源多呢!

图片.png

但是如何状态N数目过多时,FPGA也吃不消独热码对寄存器资源的消耗。这时候,格雷码就发挥作用了,格雷码虽然也是和二进制编码一样使用的寄存器资源少,组合逻辑资源多,但是相邻状态转换时就只有一个状态发生翻转,能消除状态转换时有多条信号线的传输延时所造成的毛刺,又可以降低功耗,所以要优于二进制码编码方式。

二进制编码和独热码恰恰相反,它使用了较少的寄存器资源,但是使用的组合逻辑资源较多,虽然减少了寄存器状态,但无法进行比较器部分的优化,且不利于后面的布局布线和时序分析

通过以上分析得知,我们这里使用三位二进制编码对触发器的状态进行编码,即S0~S4编码为000、001、010、011、100,此时,我们发现三位二进制数可表示8个状态,还剩下三个状态,分别是101、110、111,将其作为无关项,下面是编码后的状态转移图:

图片.png 4. 建立触发器次态卡诺图,从中分解出各个触发器的次态卡诺图,合并相邻项。

图片.png

图片.png

  1. 对个卡诺图进行化简,根据D触发器的特性方程

图片.png 可以知晓状态方程、电路的驱动方程和输出方程:

图片.png 6. 检查电路是否能自启动。将三个无关状态带入到电路的状态方程中,易知三个无关状态的下一个状态都可以进入到主循环中,所以该电路可以自启动。完整的状态转移图如下:

图片.png

  1. 根据得到的电路输出方程和驱动方程,可以画出该时序逻辑电路的逻辑电路图,

图片.png 至此,理论部分结束,整个例子的数字电路的分析也到此为止。

图片.png

两段式状态机描述五进制同步加法计数器

module counter5_fsm(
input wire sys_clk,
input wire sys_rst_n,
output reg z
);

parameter S0 = 3'b000;
parameter S1 = 3'b001;
parameter S2 = 3'b010;
parameter S3 = 3'b011;
parameter S4 = 3'b100;
reg [2:0] pre_state,next_state;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pre_state <= S0;
    else 
        pre_state <= next_state;
        
always@(pre_state) begin
    next_state = 3'bxxx;   // 全都定义为x态,仿真的时候可以检查其完备性,下面有分析
    z =1'b0;
    case(pre_state)
        S0 : begin next_state = S1; z =0;end
        S1 : begin next_state = S2; z =0;end
        S2 : begin next_state = S3; z =0;end
        S3 : begin next_state = S4; z =0;end
        S4 : begin next_state = S0; z =1;end
    default : begin next_state = S0;z= 0;end
    endcase
    end
endmodule 

程序中使用了两个always语句块,第一个always语句块为同步时序always模块,描述的是状态转移方程;第二个为组合逻辑always模块,描述的是激励方程和输出方程。

值得注意的是,在上面的程序中,第二个always块中对下一个状态进行了默认赋值,即“next_state= 3'bxxx”,通常对下一状态进行默认赋值有三种方式:全部设置为不定态x;设置成预先规定的初始状态;设置成状态机的某一有效状态。通常推荐默认将状态设置成不定态x,这样做的好处是在仿真时可以很好的检查所设计的状态机的完备性,若设计的状态机不完备,则会进入任意状态,仿真时很容易发现。

三段式状态机描述五进制同步加法计数器

程序中使用了三个always语句块,第一个always语句块为同步时序always模块,描述的是状态转移方程;第二个过程块为组合逻辑always模块,描述的是激励方程,第三个过程块为同步时序always模块,描述的是输出方程。

module counter5_fsm(
input wire sys_clk,
input wire sys_rst_n,
output reg z
);
parameter S0 = 3'b000;
parameter S1 = 3'b001;
parameter S2 = 3'b010;
parameter S3 = 3'b011;
parameter S4 = 3'b100;
reg [2:0] pre_state,next_state;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pre_state <= S0;
    else    
        pre_state <= next_state;
        
always@(pre_state)
    begin
    next_state = 3'bxxx;
    case(pre_state)
        S0 : begin next_state = S1; end
        S1 : begin next_state = S2; end
        S2 : begin next_state = S3; end
        S3 : begin next_state = S4; end
        S4 : begin next_state = S0; end
    default : begin next_state = S0;end
    endcase
    end

always@(pre_state)
    begin
    z = 1'b0;
    case(pre_state)
        S0 : begin z=0; end
        S1 : begin z=0; end
        S2 : begin z=0; end
        S3 : begin z=0; end
        S4 : begin z=1; end
    default : begin z=0;end
    endcase
    end
endmodule

仿真文件、波形如下

`timescale 1ns/1ns
module tb_counter5_fsm();
reg sys_clk;
reg sys_rst_n;
wire z;

initial
    begin
    sys_clk = 1'b1;
    sys_rst_n <= 1'b0;
    #20
    sys_rst_n <= 1'b1;
    end

always #10 sys_clk = ~sys_clk;
counter5_fsm counter5_fsm_inst(
    .sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),
    .z(z)
);
endmodule

图片.png 在输出z的波形图上,很容易得知整个计数器模块契合了我们的设计!!!

                                                                            未完待续......