赞
踩
在进行FPGA设计时,状态机是一个经常需要用到的设计手段,究竟什么是状态机?一段式和三段式状态机又有何区别,分别如何实现?本篇文章会进行详细的介绍,帮助大家迅速掌握一段式与三段式状态机的设计
状态机可归纳为4个要素,即现态、条件、动作、次态。
①现态:是指当前所处的状态。
②条件:又称为"事件",当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
④次态:条件满足后要迁往的新状态。"次态"是相对于"现态"而言的,"次态"一旦被激活,就转变成新的"现态"了。
状态机一般分为三种类型:
1、Moore型状态机:下一状态只由当前状态决定
2、Mealy 型状态机:下一状态不但与当前状态有关,还与当前输入值有关
3、混合型状态机
A.Mealy状态机:时序逻辑的输出不但取决于状态还取决于输入,如图所示。
B.Moore状态机:时序逻辑的输出仅仅取决于上一时刻的状态,而与当前时刻的输入无关,如图所示。
在实际设计中,Mealy类型的状态机是用的最多的,Moore类型虽然清晰明了,但是状态太多,不适合大型状态机的设计。
之所以Moore状态多,我们可以举个例子:比如要判断一个数是不是4'b1100
用Moore状态机:
状态 | 内容 | 输出 |
S1 | 1 | 0 |
S2 | 11 | 0 |
S3 | 110 | 0 |
S4 | 1100 | 1 |
输出只和状态有关,而和输入无关(因为根本就没有给出输入情况),这种情况下我们需要4个状态
用Mealy状态机:
状态 | 内容 | 输入 | 输出 |
S1 | 1 | 0/1 | 10/11 |
S2 | 11 | 0/1 | 110/111 |
S3 | 110 | 0/1 | 1100/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. 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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。