当前位置:   article > 正文

FPGA-状态机_fpga状态机

fpga状态机

状态机概念

硬件设计很讲究并行设计思想,虽然verilog描述的电路大多是并行的,但是对于实际的工程应用中,往往需要设计硬件来实现一些具有顺序的工作,就需要用到状态机的思想。

状态机:有限状态机(Finite State Machine),简称FSM。

状态机是数字系统设计中非常重要的组成部分,状态机的设计对系统的高可靠性、高速性有着至关重要的作用。

状态机由多个相互跳转的状态组成,用于对具有逻辑顺序和时序规律的事件进行描述,在任意时刻,状态机只能处于某一个状态;状态机的功能可以发分解为两个部分:第一部分根据外部输入实现状态转移;第二部分根据特定状态和输入来驱动输出。

状态机可以将待实现的复杂功能分解在各个状态中,使得整个系统的控制流程的实现变得简单化。

状态机有四个要素:现态、次态、输入、输出;

现态:状态机当前所处的状态;

次态:根据现态、输入、状态转移条件所得到的状态机将要跳转至的新状态;

输入:一般指外部事件,当一个外部事件发生后,状态机便会根据状态转移函数发生响应;

输出:由现态或现态和输入共同决定的,但是有时某一状态或者某一输入改变,输出并不一定会发生变化,带来的仅仅是状态迁移而已。

状态机模型

摩尔型状态机:

米勒型状态机:

由于摩尔型状态机的输出来自组合逻辑,可能会产生毛刺,从而产生不利的影响;

而米勒型状态机由于输入与输出有关,且输出也是组合逻辑,输出时序不佳,限制了系统的工作频率;

更好的方法时把摩尔型状态机和米勒型状态机混合起来使用,也即输出既和状态有关又与输入有关,采用时序逻辑输出。

寄存器型输出:具有更好的时序性能。

注意:一个健壮的状态机应当具备初始化状态或默认状态;即芯片上电或复位之后,状态机能够自动将所有判断条件复位,并进入初始状态。

大多数FPGA都有GSR(全局复位信号),当FPGA上电后,GSR有效,对所有寄存器、RAM等单元复位/置位。

状态机描述方法

状态机描述方法:一段式、两段式、三段式

一段式状态机:所有的状态变化以及输出变化都写在一个always块中在该always块中既描述状态的同步转移,又描述状态的输入条件和输出。

两段式状态机:用两个always块来描述状态机。其中一个模块采用同步时序逻辑描述状态转移,另一个模块采用组合逻辑判断状态转移条件。它需要两个状态——现态和次态,然后通过现态和次态的转换来实现时序逻辑。输出采用组合逻辑。

三段式状态机:用三个always块来描述状态机。其中一个模块采用同步时序逻辑描述状态转移,另一个模块采用组合逻辑判断状态转移条件(注意和两段式的区别)。第三个模块描述状态的输出(既可以用组合逻辑也可以用时序逻辑)。

可见,三段式描述法是最简单的。

状态机编码方法

状态机编码方法:独热码编码(只有一位是高电平),自然二进制编码,格雷码编码。

FPGA提供的触发器资源比组合逻辑资源多,所以使用独热码编码较好,节省组合逻辑资源,简化了比较逻辑,状态译码方便。

总结:

推荐使用独热码编码方式与三段式描述方式设计状态机。

1.三段always块中,第一个和第三个(多个)always块都是同步时序逻辑,用非阻塞(<=)赋值;第二个always块是组合逻辑,用阻塞赋值(=) ;

2.第二部分为组合逻辑always块,建议敏感列表使用always@(*)的方式;

3.第二部分组合逻辑always块中的判断条件一定要包含所有情况;

4.第二部分组合逻辑always块中的case中的条件应该为当前状态-state c;

5.状态转移的条件可以在第二段组合逻辑always块之外单独设计。

序列检测设计

基于状态机的概念,设计下面一个状态图:

此状态图是要在一段序列101101101101中检测出1101的序列,可重复检测3次1101。

设计随机输入一段序列,这个序列我们可以用按键去传达,比如这里,由于序列是二进制序列只有0个1组成,因此设计两位按键用高位和低位分别表示是否输出1/0,高位表示是否输出1,低位表示是否输出0。输出dout则规定4位,检测是否有1101的序列输出。

设计代码如下:

  1. module detect (
  2. input clk ,
  3. input rst_n ,
  4. input [1:0] key_in ,
  5. output reg [3:0] dout
  6. );
  7. //参数定义
  8. parameter S1 = 4'b0001 ,//检测‘1’
  9. S2 = 4'b0010 ,//检测‘1’
  10. S3 = 4'b0100 ,//检测‘0’
  11. S4 = 4'b1000 ;//检测‘1’
  12. //状态机信号
  13. reg [3:0] state_c ;
  14. reg [3:0] state_n ;
  15. wire s12s2 ;
  16. wire s22s3 ;
  17. wire s22s1 ;
  18. wire s32s4 ;
  19. wire s42s2 ;
  20. wire s42s1 ;
  21. //第一段 时序逻辑 状态的转移
  22. always @(posedge clk or negedge rst_n) begin
  23. if (!rst_n) begin
  24. state_c <= S1 ;
  25. end
  26. else begin
  27. state_c <= state_n ;
  28. end
  29. end
  30. //第二段 组合逻辑 描述状态转移的规律
  31. always @(*) begin
  32. case (state_c)
  33. S1:begin
  34. if(s12s2)
  35. state_n = S2 ;
  36. else
  37. state_n = state_c ;
  38. end
  39. S2:begin
  40. if(s22s3)
  41. state_n = S3 ;
  42. else if(s22s1)
  43. state_n = S1 ;
  44. else
  45. state_n = state_c ;
  46. end
  47. S3:begin
  48. if(s32s4)
  49. state_n = S4 ;
  50. else
  51. state_n = state_c ;
  52. end
  53. S4: begin
  54. if(s42s2)
  55. state_n = S2 ;
  56. else if(s42s1)
  57. state_n = S1 ;
  58. else
  59. state_n = state_c ;
  60. end
  61. default:state_n = S1 ;
  62. endcase
  63. end
  64. //状态之间的条件(状态之间有多少箭头就有多少条件)
  65. assign s12s2 = state_c == S1 && (key_in[1]);//1
  66. assign s22s3 = state_c == S2 && (key_in[1]);//1-1
  67. assign s22s1 = state_c == S2 && (key_in[0]);//1-0
  68. assign s32s4 = state_c == S3 && (key_in[0]);//1-1-0
  69. assign s42s2 = state_c == S4 && (key_in[1]);//1-1-0-1
  70. assign s42s1 = state_c == S4 && (key_in[0]);//1-1-0-0
  71. //dout
  72. always @(posedge clk or negedge rst_n) begin
  73. if (!rst_n) begin
  74. dout <= 'd0;
  75. end
  76. else if (s42s2) begin
  77. dout <= dout + 1'b1; //输出需要的结果1101
  78. end
  79. end
  80. endmodule

测试文件:

  1. `timescale 1ns/1ps
  2. module detect_tb();
  3. reg clk ;
  4. reg rst_n ;
  5. reg [1:0] key ;//两个按键0/1表示的是这两个按键是否按下,如0/1表示低位按键按下而高位按键没按下
  6. wire [3:0] dout ;
  7. //参数
  8. parameter CYCLE = 20 ;//50M时钟
  9. //模块例化
  10. detect u_detect(
  11. .clk (clk ),
  12. .rst_n (rst_n ),
  13. .key_in (key ),
  14. .dout (dout)
  15. );
  16. //激励
  17. initial begin //产生时钟
  18. clk = 1'b1 ;
  19. forever begin
  20. #(CYCLE/2);
  21. clk = ~clk ;
  22. end
  23. end
  24. integer i;
  25. initial begin
  26. rst_n = 1'b1;
  27. #(CYCLE);
  28. rst_n = 1'b0;
  29. key = 2'b00;
  30. #(CYCLE*2);
  31. #2;
  32. rst_n = 1'b1;
  33. #(CYCLE*4)
  34. for (i = 0 ;i < 10 ; i = i + 1 ) begin
  35. key[0] = {$random}%2 ;
  36. #(CYCLE);
  37. key = 2'b00;
  38. #(CYCLE);
  39. key[1] = {$random}%2 ;
  40. #(CYCLE);
  41. key = 2'b00;
  42. #(CYCLE*2);
  43. end
  44. key = 2'b00;
  45. #(CYCLE*10);
  46. $stop;
  47. end
  48. endmodule

仿真分析:

仿真结果显示,此段随机序列没有一个符合要求的1101序列。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/915476
推荐阅读
相关标签
  

闽ICP备14008679号