FPGA状态机详解

在进行FPGA设计时,状态机是一个经常需要用到的设计手段,究竟什么是状态机?一段式和三段式状态机又有何区别,分别如何实现?本篇文章会进行详细的介绍,帮助大家迅速掌握一段式与三段式状态机的设计


状态机介绍

状态机可归纳为4个要素,即现态、条件、动作、次态。

现态:是指当前所处的状态

条件:又称为"事件",当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。

动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

次态:条件满足后要迁往的新状态。"次态"是相对于"现态"而言的,"次态"一旦被激活,就转变成新的"现态"了。

状态机分类

状态机一般分为三种类型:
  1、Moore型状态机:下一状态只由当前状态决定
  2、Mealy 型状态机:下一状态不但与当前状态有关,还与当前输入值有关
  3、混合型状态机

A.Mealy状态机:时序逻辑的输出不但取决于状态还取决于输入,如图所示。

B.Moore状态机:时序逻辑的输出仅仅取决于上一时刻的状态,而与当前时刻的输入无关,如图所示。

在实际设计中,Mealy类型的状态机是用的最多的,Moore类型虽然清晰明了,但是状态太多,不适合大型状态机的设计。

之所以Moore状态多,我们可以举个例子:比如要判断一个数是不是4'b1100

用Moore状态机:

状态内容输出
S110
S2110
S31100
S411001

输出只和状态有关,而和输入无关(因为根本就没有给出输入情况),这种情况下我们需要4个状态

用Mealy状态机:

状态内容输入输出
S110/110/11
S2110/1110/111
S31100/11100/1101

输出不仅和状态有关,也和输入的数有关,在这种情况下我们需要3个状态

可见 用Mealy状态机可以减少状态的个数

状态机设计步骤

状态机的设计步骤主要分为以下4个步骤:

A.逻辑抽象:得出状态转换图:就是把给出的一个实际问题表示为时序逻辑函数。可以用状态转换表来描述,也可以用状态转换图来描述。

B.状态化简:如果在状态转换图中出现这样两个状态:它们在相同的输入下转换到同一个状态中,并得到相同的输出,或称它们为等价状态。显然等价状态是重复的,可以合并为一个(电路的状态越少,存储电路也就越简单)。

C.状态分配:状态分配又称状态编码。通常有很多编码方法,编码方案选择得当,设计的电路简单,反之,选得不好,则设计的电路就会复杂许多

D.用逻辑描述语言进行描述

  Ps编码方式常见的有

二进制码binary_code、格雷码gray_code 、独热码one_hot_code

1.binary_code

二进制码,编码按照二进制数进行递加,容易产生亚稳态,代码不稳定

2. gray_code

在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。Gray码不容易产生亚稳态。

3. one_hot_code

独热编码即 One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。虽然使用较多的触发器,但由于状态译码简单,可减少组合逻辑且速度较快, 这种编码方式还易于修改,增加状态或改变状态转换条件都可以在不影响状态机的其它部分的情况下很方便地实现。另外,它的速度独立于状态数量。与之相比,压缩状态编码在状态增加时速度会明显下降。独热码值每个码元值只有一位是'1',其他位都是'0'

eg:分别用3种编码方式实现4个编码

        独热         格雷        二进制

       4'b0001       2'b00      2’b00

       4'b0010       2'b01      2’b01

       4'b0100       2'b11      2’b10

       4'b1000       2'b10      2’b11

状态机的描述方式

状态机的描述方式有很多种,但是最常用的主要有3中,分别是一段式(always)、两段式(2 always)、三段式(3 always)

A.单always块把组合逻辑和时序逻辑用同一个时序always块描述,其输出是寄存器输出,无毛刺;但是这种方式可能会产生多余的触发器,代码难于修改和调试,应该尽量避免使用。

B.双always块大多用于描述Mealy状态机和组合输出的Moore状态机。

时序always块描述当前状态逻辑,组合逻辑always块描述次态逻辑并给输出赋值。

这种方式结构清晰,综合后的面积和时间性能好。但组合逻辑输出往往会有毛刺,当输出向量作为时钟信号时,这些毛刺会对电路产生致命的影响。

C.三always块大多用于同步Mealy状态机。

两个时序always块分别用来描述现态逻辑和对输出赋值,组合always块用于产生下一状态。

时序电路的状态是一个状态变量集合,这些状态变量在任意时刻的值都包含了为确定电路的未来行为而必需考虑的所有历史信息。

这种方式的状态机也是寄存器输出,输出无毛刺,并且代码比单always块清晰易读,但是面积大于双always块。随着芯片资源和速度的提高,目前这种方式得到了广泛应用。

一段式状态机

在一个always块下完成:条件判断+本状态动作+跳转下个状态

eg 用状态机实现流水灯: 

always @(posedge clk_25m)begin
11.	     if(reset)begin
12.	      led_out<=4'b0000;  //初始状态led灯全亮,检验灯是否完好
13.	      state<=3'd0;       //初始状态state=0
14.	     end
15.	     else begin
16.	      case(state)           //state作为敏感信号
17.	       3'd0:begin           //state=0状态
18.	        if(time_en)begin   //条件T满足时
19.	         led_out<=4'b0111; //灯1点亮
20.	         state<=3'd1;      //state进入1状态
21.	        end
22.	        else begin         //否则state还在0状态
23.	         led_out<=4'b0000;
24.	         state<=3'd0;
25.	        end
26.	       end
27.	       3'd1:begin                //state=1状态
28.	        if(time_en)begin        //若条件T满足
29.	         led_out<=4'b1011;      //灯2点亮
30.	         state<=3'd2;           //state进入2状态
31.	        end
32.	        else begin
33.	         led_out<=4'b0111;         //否则state还在1状态
34.	         state<=3'd1;
35.	        end
36.	       end
37.	       3'd2:begin
38.	        if(time_en)begin
39.	         led_out<=4'b1101;
40.	         state<=3'd3;
41.	        end
42.	        else begin
43.	         led_out<=4'b1011;
44.	         state<=3'd2;
45.	        end
46.	       end
47.	       3'd3:begin
48.	        if(time_en)begin
49.	         led_out<=4'b1110;
50.	         state<=3'd4;
51.	        end
52.	        else begin
53.	         led_out<=4'b1101;
54.	         state<=3'd3;
55.	        end
56.	       end
57.	       3'd4:begin
58.	        if(time_en)begin
59.	         led_out<=4'b0111;
60.	         state<=3'd1;
61.	        end
62.	        else begin
63.	         led_out<=4'b1110;
64.	         state<=3'd4;
65.	        end
66.	       end
67.	       default:begin          //2^3=8,state有没有用到的数,需要写default
68.	        state<=3'd0;          //让state回到初始值
69.	        led_out<=4'b0000;
70.	       end
71.	      endcase
72.	     end
73.	    end

三段式状态机

第一段:时序逻辑

将下个将发生的状态赋值给当前状态,将next_state赋值给current_state

第二段:组合逻辑

      根据current_state对next_state进行操作, 第二段只根据判断条件对 next_state 赋值

注意:

1组合逻辑的赋值号是=而不是<=

2

3是根据当前状态进行判断:

4只对下一个状态赋值:

5若出错则回到初始状态:

第三段:时序逻辑

对输出结果进行操作,根据current_state 对被操作的变量进行赋值

注意:

  1. 是根据当前状态判断:
  2. 只对输出结果赋值:

  1. 记得写default:

1.	module water_led(
2.	input clk,
3.	input reset,
4.	input time_en,
5.	output reg [3:0]led_out
6.	    );
7.	    
8.	    reg [2:0]current_state;//定义当前状态
9.	    reg [2:0]next_state;   //定义下一个状态
10.	    
11.	    parameter IDLE=3'd0;  //定义初始状态IDLE
12.	    parameter LED1=3'd1;  //定义第一盏灯
13.	    parameter LED2=3'd2;
14.	    parameter LED3=3'd3;
15.	    parameter LED4=3'd4;
16.	    //第一段:将下个将发生的状态赋值给当前状态(时序逻辑)
17.	 always@(posedge clk)begin
18.	  current_state<=next_state;
19.	 end
20.	 //第二段:根据current_state对next_state进行操作(组合逻辑)
21.	 always @(*)begin // (*)在组合逻辑中代表任何一个变量
22.	  if(reset)begin
23.	   next_state=IDLE; //组合逻辑变量的赋值号用=
24.	  end
25.	  else begin
26.	   case (current_state) //当前状态
27.	    IDLE:begin
28.	     if(time_en)begin
29.	      next_state=LED1; //只对state进行操作
30.	     end
31.	     else begin
32.	      next_state=IDLE;
33.	     end
34.	    end
35.	    LED1:begin
36.	     if(time_en)begin
37.	      next_state=LED2;
38.	     end
39.	     else begin
40.	      next_state=LED1;
41.	     end
42.	    end
43.	    LED2:begin
44.	     if(time_en)begin
45.	      next_state=LED3;
46.	     end
47.	     else begin
48.	      next_state=LED2;
49.	     end
50.	    end
51.	    LED3:begin
52.	     if(time_en)begin
53.	      next_state=LED4;
54.	     end
55.	     else begin
56.	      next_state=LED3;
57.	     end
58.	    end
59.	    LED4:begin
60.	     if(time_en)begin
61.	      next_state=LED1;
62.	     end
63.	     else begin
64.	      next_state=LED4;
65.	     end
66.	    end
67.	    default:begin
68.	     next_state=IDLE;
69.	    end
70.	   endcase
71.	  end
72.	 end
73.	 //第三段:对输出结果进行操作,根据current_state 对被操作的变量进行赋值(时序逻辑)
74.	 always @(posedge clk)begin
75.	  if(reset)begin
76.	   led_out<=4'b0000;
77.	  end
78.	  else begin
79.	   case (current_state) //当前状态
80.	    IDLE:begin
81.	     if(time_en)begin
82.	      led_out<=4'b0111;  //只对输出变量操作
83.	     end
84.	     else begin
85.	      led_out<=4'b0000;
86.	     end
87.	    end
88.	    LED1:begin
89.	     if(time_en)begin
90.	      led_out<=4'b1011;
91.	     end
92.	     else begin
93.	      led_out<=4'b0111;
94.	     end
95.	    end
96.	    LED2:begin
97.	     if(time_en)begin
98.	      led_out<=4'b1101;
99.	     end
100.	     else begin
101.	      led_out<=4'b1011;
102.	     end
103.	    end
104.	    LED3:begin
105.	     if(time_en)begin
106.	      led_out<=4'b1110;
107.	     end
108.	     else begin
109.	      led_out<=4'b1101;
110.	     end
111.	    end
112.	    LED4:begin
113.	     if(time_en)begin
114.	      led_out<=4'b0111;
115.	     end
116.	     else begin
117.	      led_out<=4'b1110;
118.	     end
119.	    end
120.	    default:begin
121.	     led_out<=4'b0000;
122.	    end
123.	   endcase
124.	  end
125.	 end
126.	endmodule

三段式状态机与一段式区别与联系

1三段式是一段式的三个部分,就是把一段式的三个关系分别独立出来

2.三段式要定义两个 state 变量;一个是 current_state(当前状态);一个是 next_state(下一个状态)

3.三段式中稳定性强,适用于时钟频率很高的程序中,并且一个时钟下只对一个变量进行操作。一段式中整个程序都在一个时钟下操作所以容易出错。

4. 三段式可以把稳定区域的current_state赋值给next_state


本篇文章介绍了状态机原理,Mealy和Moore状态机分类,一段式状态机与三段式状态机写法,并用流水灯举例分析了一段式状态机和三段式状态机的异同

创作不易,点赞支持!thank

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值