当前位置:   article > 正文

Verilog状态机_verilog 状态机

verilog 状态机

状态机定义

  • 有限状态机 Finite State Machine,表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。有限状态机是指输出取决于过去输入部分和当前输入部分的时序逻辑电路。一般来说,除了输入部分和输出部分外,有限状态机还含有一组具有“记忆”功能的寄存器,这些寄存器的功能是记忆有限状态机的内部状态,它们常被称为状态寄存器。在有限状态机中,状态寄存器的的下一个状态不仅与输入信号有关,而且还与该寄存器的当前状态有关,因此有限状态机又可以认为是组合逻辑和寄存器逻辑的一种组合。其中,寄存器逻辑的功能是存储有限状态机的内部状态;而组合逻辑有可以分为次态逻辑和输出逻辑两部分,次态逻辑的功能是确定有限状态机的下一个状态,输出逻辑的功能是确定有限状态机的输出。有限状态机是由寄存器和组合逻辑构成的硬件时序电路。有限状态机的状态只可能在同一时钟变沿情况下才能从一个状态跳转到另一个状态。

状态转移

状态转移表示当发生指定事件且满足指定条件时,第 1 个状态中的对象将执行某些操作并进入第 2 个状态,即“触发”了转移。将触发转移之前的状态定义为“源状态”(当前状态,current_state),而触发转移之后的状态定义为“目标状态”(下一状态,next_state)。状态的转换由时钟信号驱动。

(1)Moore 型状态机

Moore 型状态机输出为当前状态的函数,由于状态的变化与时钟同步,因此输出的变

化也与时钟同步,属于同步输出电路模型。我们可以用图 2 所示的状态转换图来描述

Moore 型状态机,其电路结构框图如图 3 所示。

(2) Mealy 型状态机

Mealy 型状态机的输出为当前状态和所有输入信号的函数,由于输入信号与时钟信号无关,因此其输出在输入变化后将立即发生变化,不依赖时钟,因此 Mealy 型状态机属于异步输出电路模型。我们可以用图 4 所示的状态转换图来描述 Mealy 型状态机,其电路结构框图如图 5 所示。

  • Moore 型有限状态机其输出信号仅与当前状态有关,即可以把 Moore 型有限状态的输出看成是当前状态的函数。Mealy 型有限状态机其输出信号不仅与当前状态有关,而且还与所有的输入信号有关,即可以把 Mealy 型有限状态机的输出看成是当前状态和所有输入信号的函数。

同步状态机和异步状态机

  • 异步状态机是没有确定时钟的状态机,其状态转移不由唯一的时钟边沿触发。因此,应尽量不要使用综合工具来设计异步状态机。目前大多数综合工具对异步状态机进行逻辑优化时会胡乱的简化逻辑,是综合后的异步状态机不能正常工作。如果一定要设计异步状态机,建议采用电路图输入的方法,而不要用 Verilog 输入的方法。为了能综合出有效的电路,用 Verilog 描述的状态机应明确地由唯一时钟触发,称之为同步状态机,它是设计复杂时序逻辑电路最有效、最常用的方法之一。

单进程、双进程和多进程状态机

可以有 3 种不同的方式实现对状态机的描述。

1 3 个模块用一个进程实现,也就是说 3 个模块均在一个 always 块内,这种状态机描

述称为单进程有限状态机,它既描述状态转移,又描述状态的寄存和输出。

2 3 个模块对应着 2 个 always 块,“状态译码”“输出译码”分配在一个进程中,“状态

寄存器”用另一个进程描述。这种状态机描述称为双进程有限状态机。

③ 每一个模块分别用一个进程实现,也就是说 3 个模块对应着 3 个 always 块,这种状

态机描述称为三进程有限状态机。

  • 1.一段式状态机:一段式状态机只选择一个状态标志位,这个状态标志位会在输入的决定下选择跳转到下一个状态还是维持原有状态,在每一个状态下检测状态标志位及输入来决定其状态的跳转及输出。其输出和状态的切换在一个 always 循环块中执行。

  • 2.二段式状态机:二段式状态机将状态分为当前状态和此状态,其系统会自动将次状态更新到当前状态,其输入更新在次状态上,其决定系统的状态切换和输出。其输出和状态的切换在两个 always 循环块中执行,第一个 always 块决定系统状态标志的自动跳转,第二个 always 块决定系统根据不同状态下的输入进行状态的跳转及输出。

  • 3.三段式状态机:二段式状态机将状态分为当前状态和此状态,其系统会自动将次状态更新到当前状态,系统的输入更新在次状态上,其决定系统的状态切换,系统会根据其当前状态决定输出的值。其输出和状态更新和状态切换在三个 always 块中,第一个always 块决定系统状态标志的自动跳转,第二个 always 块决定系统根据不同状态下的输入进行状态的切换,第三个 always 块根据系统的当前状态决定输出的值。

关于三段式状态机的总结:

①确定输入输出信号,及其类型(是 wire 还是 reg);

②声明内部信号,一般需要定义 current_state 和 next_state;

③用 3 个 always 语句描述状态机;第一个用来次态和现态的转换,第二个 always 用于现态在输入情况下转换为次态的组合逻辑;第三个语句用于现态到输出的组合逻辑输出。

有限状态机设计流程

一个有限状态机的结构总是可以被分为以下几项。

(1)状态译码:根据外部输入的控制信号及当前状态(current_state)确定下一状态(next_state)的取值。采用组合逻辑判断状态转移条件,描述状态转移规律。

(2)状态寄存器:采用同步时序描述状态转移。负责状态机运行和在时钟驱动下状态转换的过程:当时钟信号的有效边沿到达时,主控时序过程将代表次态的信号next_state中的内容送入现态的信号current_state中,而信号next_state中的内容完全由其他过程根据实际情况来决定。

(3)输出译码:描述每个状态的输出。

通过单always模块方式、双always模块方式和三always模块方式实现单进程、双进程和三进程状态机。

单always模块方式

将整个状态机的设计写到一个always模块中,既描述状态输入和输出,又描述状态转移,其特点是利用寄存器完成输出从而不易产生毛刺,易于进行逻辑综合,缺点是代码可读性差,不利于修改、完善及维护,且状态向量和输出向量均由寄存器实现,会消耗较大的芯片资源,无法实现Mealy状态机。

双always模块方式

双always模块方式有2个always块,其中一个always模块采用同步时序描述状态转移,另一个always模块采用组合逻辑判断状态转移条件,描述状态转移规律及输出。其优点是面积和时序的优势,但由于输出是当前状态的组合函数,又存在下述问题:输出会产生毛刺;状态机的输出向量必须由状态向量译码,增加了状态向量到输出的延迟;组合逻辑占用了一定的传输时间,增加了驱动下一模块的输入延迟,不利于系统的综合优化

三always模块方式

将“状态译码”“状态寄存器”“输出译码”分别写出一个always模块,即称为“三always模块方式”。

  • 上述的3个always模块中,一个always模块采用同步时序描述状态转移;一个always模块采用组合逻辑判断转移条件,描述转移规律;另一个always模块描述状态的输出。其优点是程序可读性强,占用芯片面积适中,无毛刺,有利于综合。

实际问题要求与分析

自动售货机是有限状态机的经典实例,现在就一个可乐售货机来进行分析。

要求:售货机里有价值4元的可乐,支持1元和2元硬币。请设计一个状态机,检测投入的硬币,当累计投入币值大于等于可乐价格时,售货机自动找零并弹出1瓶可乐。硬币和商品都是一个一个的进出,不会出现一次性投很多个硬币弹出很多瓶可乐的情况。

  • 三段式状态机:

三段式状态机,第一段用时序逻辑描述state_c(现态);第二段用组合逻辑描述状态转移,也即确定state_n(次态);第三段用时序逻辑描述输出,第三段可以是多个always块。

  1. module FSM_3
  2. //---------------------<端口声明>---------------------------------------
  3. (input clk ,
  4. input rst_n ,
  5. input [1:0] in ,
  6. output reg [1:0] out ,
  7. output reg out_vld
  8. );
  9. //---------------------<信号定义>---------------------------------------
  10. reg [3:0] state_c ;
  11. reg [3:0] state_n ;
  12. //---------------------<状态机参数>-------------------------------------
  13. localparam S0 = 4'b0001 ;
  14. localparam S1 = 4'b0010 ;
  15. localparam S2 = 4'b0100 ;
  16. localparam S3 = 4'b1000 ;
  17. //----------------------------------------------------------------------
  18. //-- 状态机第1段
  19. //----------------------------------------------------------------------
  20. always @(posedge clk or negedge rst_n)begin
  21. if(!rst_n)
  22. state_c <= S0;
  23. else
  24. state_c <= state_n;
  25. end
  26. //----------------------------------------------------------------------
  27. //-- 状态机第2段
  28. //----------------------------------------------------------------------
  29. always @(*)begin
  30. case(state_c)
  31. S0: begin
  32. if(in==1)
  33. state_n = S1;
  34. else if(in==2)
  35. state_n = S2;
  36. else
  37. state_n = state_c;
  38. end
  39. S1: begin
  40. if(in==1)
  41. state_n = S2;
  42. else if(in==2)
  43. state_n = S3;
  44. else
  45. state_n = state_c;
  46. end
  47. S2: begin
  48. if(in==1)
  49. state_n = S3;
  50. else if(in==2)
  51. state_n = S0;
  52. else
  53. state_n = state_c;
  54. end
  55. S3: begin
  56. if(in==1 || in==2) // in != 0也行
  57. state_n = S0;
  58. else
  59. state_n = state_c;
  60. end
  61. default:state_n = S0;
  62. endcase
  63. end
  64. //----------------------------------------------------------------------
  65. //-- 状态机第3段
  66. //----------------------------------------------------------------------
  67. //找零钱
  68. always @(posedge clk or negedge rst_n)begin
  69. if(!rst_n)
  70. out <= 0;
  71. else if(state_c==S3 && in==2)
  72. out <= 1;
  73. else
  74. out <= 0;
  75. end
  76. //输出可乐
  77. always @(posedge clk or negedge rst_n)begin
  78. if(rst_n==1'b0)
  79. out_vld <= 0;
  80. else if((state_c==S2 && in==2) || (state_c==S3 && in!=0))
  81. out_vld <= 1;
  82. else
  83. out_vld <= 0;
  84. end
  85. endmodule

编写测试文件testbech:

  1. `timescale 1ns/1ps //时间精度
  2. `define Clock 20 //时钟周期
  3. module FSM_3_tb;
  4. //--------------------< 端口 >------------------------------------------
  5. reg clk ;
  6. reg rst_n ;
  7. reg [1:0] in ;
  8. wire [1:0] out ;
  9. wire out_vld ;
  10. //----------------------------------------------------------------------
  11. //-- 模块例化
  12. //----------------------------------------------------------------------
  13. FSM_3 u_FSM_3
  14. (
  15. .clk (clk ),
  16. .rst_n (rst_n ),
  17. .in (in ),
  18. .out (out ),
  19. .out_vld (out_vld )
  20. );
  21. //----------------------------------------------------------------------
  22. //-- 状态机名称查看器
  23. //----------------------------------------------------------------------
  24. localparam S0 = 4'b0001 ;
  25. localparam S1 = 4'b0010 ;
  26. localparam S2 = 4'b0100 ;
  27. localparam S3 = 4'b1000 ;
  28. //2字符16位
  29. reg [15:0] state_name ;
  30. always@(*)begin
  31. case(u_FSM_3.state_c)
  32. S0: state_name = "S0";
  33. S1: state_name = "S1";
  34. S2: state_name = "S2";
  35. S3: state_name = "S3";
  36. default:state_name = "S0";
  37. endcase
  38. end
  39. //----------------------------------------------------------------------
  40. //-- 时钟信号和复位信号
  41. //----------------------------------------------------------------------
  42. initial begin
  43. clk = 1;
  44. forever
  45. #(`Clock/2) clk = ~clk;
  46. end
  47. initial begin
  48. rst_n = 0; #(`Clock*20+1);
  49. rst_n = 1;
  50. end
  51. //----------------------------------------------------------------------
  52. //-- 设计输入信号
  53. //----------------------------------------------------------------------
  54. initial begin
  55. #1;
  56. in = 0;
  57. #(`Clock*20+1); //初始化完成
  58. //情况1--------------------------
  59. in = 1; //1块钱
  60. #(`Clock*1);
  61. in = 0;
  62. #(`Clock*1);
  63. in = 1; //1块钱
  64. #(`Clock*1);
  65. in = 0;
  66. #(`Clock*1);
  67. in = 1; //1块钱
  68. #(`Clock*1);
  69. in = 0;
  70. #(`Clock*1);
  71. in = 1; //1块钱
  72. #(`Clock*1);
  73. in = 0;
  74. #(`Clock*10);
  75. //情况2--------------------------
  76. in = 1; //1块钱
  77. #(`Clock*1);
  78. in = 0;
  79. #(`Clock*1);
  80. in = 1; //1块钱
  81. #(`Clock*1);
  82. in = 0;
  83. #(`Clock*1);
  84. in = 1; //1块钱
  85. #(`Clock*1);
  86. in = 0;
  87. #(`Clock*1);
  88. in = 2; //2块钱
  89. #(`Clock*1);
  90. in = 0;
  91. #(`Clock*10);
  92. //情况3--------------------------
  93. in = 1; //1块钱
  94. #(`Clock*1);
  95. in = 0;
  96. #(`Clock*1);
  97. in = 1; //1块钱
  98. #(`Clock*1);
  99. in = 0;
  100. #(`Clock*1);
  101. in = 2; //2块钱
  102. #(`Clock*1);
  103. in = 0;
  104. #(`Clock*10);
  105. //情况4--------------------------
  106. in = 1; //1块钱
  107. #(`Clock*1);
  108. in = 0;
  109. #(`Clock*1);
  110. in = 2; //2块钱
  111. #(`Clock*1);
  112. in = 0;
  113. #(`Clock*1);
  114. in = 2; //2块钱
  115. #(`Clock*1);
  116. in = 0;
  117. #(`Clock*10);
  118. //情况5--------------------------
  119. in = 2; //2块钱
  120. #(`Clock*1);
  121. in = 0;
  122. #(`Clock*1);
  123. in = 2; //2块钱
  124. #(`Clock*1);
  125. in = 0;
  126. #(`Clock*10);
  127. $stop;
  128. end
  129. endmodule

三段式状态机RTL视图如下:

三三段式状态机引脚框图如下:

小结

三段式状态机和二段式状态机是非常类似的,只不过是多加了一个 always 块来实现FSM状态的一个寄存,使FSM做到了同步寄存器输出,消除了组合逻辑输出的不稳定与毛刺的隐患,而且更利于时序路径分组,一般来说在FPGA等可编程逻辑器件上的综合与布局布线效果更佳。一段式状态机不利于维护,尽量不使用。一般而言,推荐的FSM 描述方法是后两种。这是因为:FSM和其他设计一样,最好使用同步时序方式设计,以提高设计的稳定性,消除毛刺。状态机实现后,一般来说,状态转移部分是同步时序电路而状态的转移条件的判断是组合逻辑。第二种描述方法同第一种描述方法相比,将同步时序和组合逻辑分别放到不同的always模块中实现,这样做的好处不仅仅是便于阅读、理解、维护,更重要的是利于综合器优化代码,利于用户添加合适的时序约束条件,利于布局布线器实现设计。在第二种方式的描述中,描述当前状态的输出用组合逻辑实现,组合逻辑很容易产生毛刺,而且不利于约束,不利于综合器和布局布线器实现高性能的设计。第三种描述方式与第二种相比,关键在于根据状态转移规律,在上一状态根据输入条件判断出当前状态的输出,从而在不插入额外时钟节拍的前提下,实现了寄存器输出。

Moore型:状态机的状态变化仅和当前状态有关;时序逻辑电路的输出只取决于当前状态。设计高速电路时常用此类状态机,把状态变化直接用作输出。

Mealy型:状态机的状态变化不仅与当前的状态有关,还取决于当前的输入条件(时序逻辑的输出不但取决于状态还取决于输入。平常使用较多的是此类状态机。

“其实这几种状态机之间,只要做一些改变,便可以从一种形式转变为另一种形式。把状态机精确的分为这类或那类,其实并不重要,重要的是设计者如何把握输出的结构能满足设计的整体目标,包括定时的准确性和灵活性。”

状态机设计判断标准:

第一,状态机要安全,是指FSM不会进入死循环,特别是不会进入非预知的状态,而且由于某些扰动进入非设计状态,也能很快的恢复到正常的状态循环中来。(三段式状态机可以尽可能的避免状态输出的不稳定和毛刺的问题)

第二,状态机的设计要满足设计的面积和速度的要求。

第三,状态机的设计要清晰易懂、易维护。

  • 注意,用always模块写组合逻辑时,采用阻塞赋值,而在always块中建立时序电路时,用非阻塞赋值。这样才能保证有限状态机综合前和综合后仿真的一致

//https://blog.csdn.net/weixin_42455055/article/details/119118162

状态机基本概念:
  • 状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。

  • 如何写一个高质量的状态机:

1、安全性:综合实现无毛刺异常扰动,状态机要完备,既不会进入死循环,哪怕偶然跑偏也能恢复到正常状态(三度段式+状态完备);

2、速度:速度要快,满足设计频率的要求;

3、面积:面积要小,满足设计的面积要求;

4、易懂易维护性:FSM设计要清晰易懂,易维护(采用三段式)。

2、3需要有较强的电路时序分析功底才能比较好的优化,要非常熟悉verilog综合(DC)出来的电路情况,要有一定的静态时序分析(STA)和优化的能力,初学者能做好1、4就很不错了。

FSM实现实现11010110序列输出

  1. module FSM_gener(
  2. input clk,
  3. input rst_n,
  4. output reg data_current
  5. );
  6. //变量分配定义
  7. reg [3:0] state_current;
  8. reg [3:0] state_next;
  9. reg data_next;
  10. localparam //使用格雷码,减少数据翻转,减小误码率和功耗
  11. IDEL = 4'b0000,
  12. ONE = 4'b0001,
  13. TWO = 4'b0011,
  14. THREE = 4'b0010,
  15. FOUR = 4'b0110,
  16. FIVE = 4'b0111,
  17. SIX = 4'b0101,
  18. SEVEN = 4'b0100,
  19. EIGHT = 4'b1100;
  20. //第一段状态机,时序逻辑状态更新
  21. always@( posedge clk or negedge rst_n ) begin
  22. if( !rst_n )
  23. state_current <= IDEL;
  24. else
  25. state_current <= state_next;
  26. end
  27. //第二段状态机,组合逻辑状态判断跳转
  28. always@( * ) begin
  29. case( state_current )
  30. IDEL:begin
  31. state_next <= ONE;
  32. data_next <= 1'b0;
  33. end
  34. ONE:begin
  35. state_next <= TWO;
  36. data_next <= 1'b1;
  37. end
  38. TWO: begin
  39. state_next <= THREE;
  40. data_next <= 1'b1;
  41. end
  42. THREE:begin
  43. state_next <= FOUR;
  44. data_next <= 1'b0;
  45. end
  46. FOUR:begin
  47. state_next <= FIVE;
  48. data_next <= 1'b1;
  49. end
  50. FIVE:begin
  51. state_next <= SIX;
  52. data_next <= 1'b0;
  53. end
  54. SIX: begin
  55. state_next <= SEVEN;
  56. data_next <= 1'b1;
  57. end
  58. SEVEN:begin
  59. state_next <= EIGHT;
  60. data_next <= 1'b1;
  61. end
  62. EIGHT:begin
  63. state_next <= IDEL;
  64. data_next <= 1'b0;
  65. end
  66. default:begin
  67. state_next <= IDEL;
  68. data_next <= 1'b0;
  69. end
  70. endcase
  71. end
  72. //第三段状态机,时序逻辑数据输出
  73. always@( posedge clk or negedge rst_n ) begin
  74. if( !rst_n )
  75. data_current <= 1'b0;
  76. else
  77. data_current <= data_next;
  78. end
  79. endmodule
  1. `timescale 1ns/1ns
  2. `define clock_period 20
  3. module FSM_gener_tb();
  4. reg clk;
  5. reg rst_n;
  6. wire data_current;
  7. FSM_gener FSM_gener0
  8. (
  9. .clk(clk),
  10. .rst_n(rst_n),
  11. .data_current(data_current)
  12. );
  13. initial begin clk = 1'b1; end
  14. always#( `clock_period ) clk = ~clk;
  15. initial begin
  16. rst_n = 0;
  17. #( `clock_period*10 );
  18. rst_n = 1;
  19. #( `clock_period*10 + 1'b1 );
  20. #( `clock_period*50 );
  21. $stop;
  22. end
  23. endmodule

连续序列1101检测案例

2.1 需求分析

(1) 检测任意数字序列,若连续出现1101则表示检测到目标序列命令,输出标识信号flag,此处以“11101101011010”为例,设计三段式FSM进行检测。

(2)其状态转移图如下所示,一共分为5个状态,IDEL下状态为xxxx未知态,同理S1:1xxx S2:11xx S3:110x S4:1101

(3)单次循环有四种链路传输状态:

1)首先最简单的链路就是输入d_in连续检测成功,第一拍为d_in = 1'b1,依次分别为1'b1、1'b0、 1'b1,进入S4后在下一拍检测到d_in = 1'b0,则返回IDEL准备新一轮检测。

2)其次,有可能在S1和S3检测到d_in = 1'b0返回IDEL。

3)最后,抵达S4后如果下一拍上升沿检测到d_in = 1’b1,则返回S2,当时状态为11xx。

  1. module FSM_1101(
  2. input clk,
  3. input rst_n,
  4. input FSM_1101_in, //一位输入
  5. output reg Match_Flag //1101检测成功标志信号
  6. );
  7. //***********************parameter************************
  8. reg [2:0] next_state; //下一拍执行状态
  9. reg [2:0] state; //当前拍未执行最新状态
  10. localparam //一共五个状态,使用Gray码提高翻转效率
  11. IDEL = 3'b000,
  12. NUM_1xxx = 3'b001,
  13. NUM_11xx = 3'b011,
  14. NUM_110x = 3'b010,
  15. NUM_1101 = 3'b110; //110=>000翻转了两位,不够好
  16. //***********************FSM 1101************************
  17. //第一段 下一状态更新
  18. always@( posedge clk or negedge rst_n ) begin
  19. if( !rst_n )
  20. next_state <= IDEL;
  21. else
  22. next_state <= state;
  23. end
  24. //第二段 状态判断跳转
  25. always@(*) begin
  26. case(next_state)
  27. IDEL: begin
  28. if( FSM_1101_in == 1'b1 )
  29. state <= NUM_1xxx;
  30. else
  31. state <= IDEL;
  32. end
  33. NUM_1xxx:begin
  34. if( FSM_1101_in == 1'b1 )
  35. state <= NUM_11xx;
  36. else
  37. state <= IDEL;
  38. end
  39. NUM_11xx:begin
  40. if( FSM_1101_in == 1'b0 )
  41. state <= NUM_110x;
  42. else
  43. state <= NUM_11xx;
  44. end
  45. NUM_110x:begin
  46. if( FSM_1101_in == 1'b1 )
  47. state <= NUM_1101;
  48. else
  49. state <= IDEL;
  50. end
  51. NUM_1101:begin
  52. if( FSM_1101_in == 1'b1 )
  53. state <= NUM_11xx;
  54. else
  55. state <= IDEL;
  56. end
  57. default:state <= IDEL;
  58. endcase
  59. end
  60. //第三段 标志信号输出
  61. always@( posedge clk or negedge rst_n ) begin
  62. if( !rst_n )
  63. Match_Flag <= 0;
  64. else if( next_state == NUM_1101 )
  65. Match_Flag <= 1'b1;
  66. else
  67. Match_Flag <= 1'b0;
  68. end
  69. endmodule
  1. `timescale 1ns/1ns
  2. `define clock_period 20
  3. module FSM_1101_tb();
  4. //参数
  5. reg clk;
  6. reg rst_n;
  7. reg FSM_1101_in;
  8. wire Match_Flag;
  9. //调用
  10. FSM_1101 FSM_1101
  11. (
  12. .clk(clk),
  13. .rst_n(rst_n),
  14. .FSM_1101_in(FSM_1101_in), //一位输入
  15. .Match_Flag(Match_Flag) //1101检测成功标志信号
  16. );
  17. //Initial
  18. initial
  19. begin
  20. clk = 1;
  21. rst_n = 0;
  22. FSM_1101_in = 0;
  23. end
  24. //Clock
  25. always#(`clock_period/2) clk = ~clk;
  26. //1101101011010 Generate
  27. initial begin
  28. #( `clock_period*20 );
  29. rst_n = 1;
  30. #( `clock_period*20 + 1'b1 );
  31. FSM_1101_in = 1;
  32. #( `clock_period );
  33. FSM_1101_in = 1;
  34. #( `clock_period );
  35. FSM_1101_in = 0;
  36. #( `clock_period );
  37. FSM_1101_in = 1;
  38. #( `clock_period );
  39. FSM_1101_in = 1;
  40. #( `clock_period );
  41. FSM_1101_in = 0;
  42. #( `clock_period );
  43. FSM_1101_in = 1;
  44. #( `clock_period );
  45. FSM_1101_in = 0;
  46. #( `clock_period );
  47. FSM_1101_in = 1;
  48. #( `clock_period );
  49. FSM_1101_in = 1;
  50. #( `clock_period );
  51. FSM_1101_in = 0;
  52. #( `clock_period );
  53. FSM_1101_in = 1;
  54. #( `clock_period );
  55. FSM_1101_in = 0;
  56. #( `clock_period*50 );
  57. $stop;
  58. end
  59. endmodule

// 数字电路面试题目笔记 https://blog.csdn.net/H19981118/article/details/125071753

Moore型状态机实现序列“1101”从右到左的不重叠检测

1、请画出状态转移图,其中状态用S1,S2,…来标识。

2、针对这个具体设计,如何衡量验证的完备性?

Moore型:状态机的状态变化仅和当前状态有关。

Mealy型:不仅和当前状态有关,也和输入有关。

  1. //序列检测器1011,不重叠检测
  2. module test(
  3. input clk,
  4. input rst_n,
  5. input d, //序列输入
  6. output reg done //检测完成
  7. );
  8. parameter S1 = 3'd1,S2 = 3'd2,S3 = 3'd3,S4 = 3'd4,S5 = 3'd5;
  9. reg [2:0] state,next_state;
  10. //三段式状态机
  11. //第一段,状态寄存器
  12. always@(posedge clk)
  13. if(!rst_n)
  14. state <= S1;
  15. else
  16. state <= next_state;
  17. //第二段,组合逻辑描述状态转移
  18. always @ (*)begin
  19. case(state)
  20. S1: next_state = d ? S2:S1;
  21. S2: next_state = d ? S2:S3;
  22. S3: next_state = d ? S4:S1;
  23. S4: next_state = d ? S5:S3;
  24. S5: next_state = d ? S2:S1;
  25. default: next_state = S1;
  26. endcase
  27. end
  28. //第三段,状态输出
  29. always@(*)
  30. done = (state == S5) ;
  31. endmodule

可重叠的 代码差不多,自己✍

  1. `timescale 1ns/1ns
  2. module test_tb;
  3. reg clk;
  4. reg rst_n;
  5. reg d; //序列输入
  6. wire done ; //检测完成
  7. test u1 (
  8. .clk(clk),
  9. .rst_n(rst_n),
  10. .d(d), //序列输入
  11. .done(done) //检测完成
  12. );
  13. //
  14. initial clk = 0;
  15. always #1 clk = ~clk;
  16. //
  17. initial begin
  18. rst_n = 0;
  19. #1;
  20. rst_n = 1;
  21. end
  22. //
  23. initial begin
  24. d = 0;
  25. #2;
  26. d = 1;
  27. #2;
  28. d = 0;
  29. #2;
  30. d = 1;
  31. #2;
  32. d = 1;
  33. #2;
  34. d = 0;
  35. #2;
  36. d = 1;
  37. #2;
  38. d = 1;
  39. #3;
  40. d= 0;
  41. #20;
  42. $stop;
  43. end
  44. endmodule

用移位操作实现循环序列发生器

题目要求:

循环产生如下序列:0010_1101_11。

解题:可采用状态机实现,但为了简化操作,这里采用移位操作来实现序列的循环发生

  1. module test(
  2. input clk,
  3. input rst_n,
  4. input [9:0] in,
  5. output reg out
  6. );
  7. reg [9:0] out_r;
  8. //移位
  9. always@(posedge clk or negedge rst_n)
  10. if(!rst_n)
  11. out_r <= in; //0010_1101_11
  12. else
  13. out_r <= {out_r[8:0],out_r[9] };
  14. //逐高位输出
  15. always@(posedge clk or negedge rst_n)
  16. if(!rst_n)
  17. out <= 0;
  18. else
  19. out <= out_r[9];
  20. endmodule
  1. `timescale 1ns/1ns
  2. module test_tb;
  3. reg clk;
  4. reg rst_n;
  5. reg [9:0] in;
  6. wire out ; //检测完成
  7. test u1 (
  8. .clk(clk),
  9. .rst_n(rst_n),
  10. .in(in),
  11. .out(out)
  12. );
  13. initial clk = 0;
  14. always #1 clk = ~clk;
  15. initial begin
  16. rst_n= 0;
  17. in = 10'b0010_1101_11;
  18. #10;
  19. rst_n= 1;
  20. #5;
  21. #50;
  22. $stop;
  23. end
  24. endmodule

  • 如何衡量设备的完备性

  • 设备完备性的衡量是用来验证的,对于状态机来说,会出现各种状态跳转错误等,因此我们要确保状态之间的正确跳转,同时本题中是不重叠检测,因此也要明确这点,确保当出现重叠序列的时候,不会误检。另外可以从定向测试、随机测试两种方式产生激励,从代码覆盖率的角度保证覆盖率达到100%。

  • 最高工作频率与最小工作周期

找到电路的关键路径。

同时最小工作周期公式:Tmin = Tco + Tcmob + Tsu - Tskew。

组合逻辑电路则最小工作周期:Tmin = Tco + Tcmob + Tsu。

本题中,Tco为触发器输出的延时,为这里的逻辑延时6ns,组合逻辑的延时为反相器INV2的延时2ns,Tsu为建立时间2ns。这里没有考虑INV1的延迟,因为关键路径的延迟是从源触发器的Tco开始算。

因此最小工作周期 Tmin = 6 + 2 +2 = 10ns。

最高工作频率 = 1 / 10ns = 0.1 GHZ = 100 MHZ

补充:1ns = 10^-9 s

  • 跨时钟域处理——格雷码

在前面的笔记中,我们已经详细介绍了握手信号等,这里主要介绍跨时钟域处理中的格雷码。

格雷码:可以解决多bit跨时钟域信号传输。

  • 本题目中第四种方法不常见,自己也不太懂,可参考其他博文的解释,我这里主要来分析第三种格雷码的方式。

  • 格雷码:相邻的两个编码之间只有一位是不一样的。

  • 独热码:每个编码只有一位是1。

为什么格雷码能用于跨时钟域处理?

由于格雷码相邻数据只有一个bit不同,因此,在进行跨时钟域传输时,只有发生变化的那个bit有可能处于亚稳态,而其余bit保持不变,因此是稳定的,故多比特格雷码的跨时钟域传输就相当于单比特信号的跨时钟域传输,这样的话,我们即可采用两级同步来处理。

但本题中是0-6的计数,对应的二进制码和格雷码如下,可看到转换后不符合题目0-6的要求,因此不能用格雷码

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

闽ICP备14008679号