• Verilog基础:三段式状态机与输出寄存


    相关阅读

    Verilog基础icon-default.png?t=N7T8https://blog.csdn.net/weixin_45791458/category_12263729.html


            对于Verilog HDL而言,有限状态机(FSM)是一种重要而强大的模块,常见的有限状态机书写方式可以分为一段式,二段式和三段式,笔者强烈建议使用三段式因为这样能使状态机逻辑清晰且易于维护。

            有限状态机有两种基本类型:Mealy机和Moore机。两者的区别在于:Mealy机的下一状态和输出都取决于当前状态和当前输入,而Moore机的下一状态取决于当前状态和当前输入,输出只取决于当前状态。这两类有限状态机的下一状态和输出都是组合逻辑的形式的(指输出不直接来自寄存器的输出),两类状态机的结构如图1、图2所示。

    图1 Mealy型状态机

    图2 Moore型状态机

            下面以一个简单的例子说明三段式Moore型状态机的书写方式。图3是一个有两个状态的异步复位的Moore机。

    图3 一个简单的Moore机 

    1. module top_module (
    2. input clk,
    3. input in,
    4. input rst_n,
    5. output reg out
    6. );
    7. parameter A = 0
    8. parameter B = 1
    9. reg state, next_state; //定义寄存器变量保存状态信息
    10. //第一段,下一状态组合逻辑
    11. always@(*) begin
    12. case (state) //根据不同的状态和输入,决定下一时钟周期的状态
    13. A: next_state = in ? A : B;
    14. B: next_state = in ? B : A;
    15. endcase
    16. end
    17. //第二段,状态转移时序逻辑
    18. always @(posedge clk, negedge rst_n) begin
    19. if (!rst_n)
    20. state <= B; //异步复位到状态B
    21. else
    22. state <= next_state;
    23. end
    24. //第三段,输出组合逻辑
    25. always@(*) begin
    26. if(state == B)
    27. out = 1;
    28. else
    29. out = 0;
    30. end
    31. //因为输出比较简单,这里的第三段的输出组合逻辑也可以用assign连续赋值
    32. //但out此时不能定义为reg
    33. //assign out = (state == B);
    34. endmodule

            对于Mealy型状态机,因为输出直接受输出影响,可能在某些情况下会出现毛刺(即不在时钟边沿的输出变化),所以可以使用寄存器采集输出。对于Moore型状态机,虽然没有输出毛刺的问题,但也可以使用寄存器采集输出以避免大段组合逻辑输出。图4和图5分别给出了寄存输出的Mealy型状态机和Moore型状态机的结构。

    图4 寄存输出的Mealy型状态机

    图5 寄存输出的Moore型状态机

            上面两图不难理解,但是一个新的问题出现了,即输出会延后一个周期得到,如果既需要当前周期给出输出,又需要对输出寄存,就不能使用当前状态和输入确定输出,而是应该使用下一状态组合逻辑和输入确定输出。图6和图7给出了这种情况下的Mealy型状态机和Moore型状态机。

    图6 寄存输出的Mealy型状态机(下一状态)

     图7  寄存输出的Moore型状态机(下一状态)

            对于Mealy状态机,因为需要状态转移和相应状态的输出同时出现,输出寄存器需要保存由下一状态组合逻辑和的输入推导的输出。对于Moore状态机,输出寄存器需要保存由下一状态组合逻辑推导的输出。

            下面用一个更加复杂的有限状态机为例,说明寄存输出的具体写法。这是一个序列检测器,用于检测输入序列中三个连续的1信号,首先给出Moore型序列检测器的Verilog描述。

    1. module Seq_Rec_Moore(output reg D_out, D_out_r1, D_out_r2, input D_in, En, clk, rst_n);
    2. parameter S_idle = 3'd0;
    3. parameter S_0 = 3'd1;
    4. parameter S_1 = 3'd2;
    5. parameter S_2 = 3'd3;
    6. parameter S_3 = 3'd4;
    7. reg [2:0] state, next_state;
    8. //下一状态组合逻辑
    9. always@(*)begin
    10. case(state)
    11. S_idle: if((En == 1)&&(D_in == 1))
    12. next_state = S_1;
    13. else if((En == 1)&&(D_in == 0))
    14. next_state = S_0;
    15. else
    16. next_state = S_idle;
    17. S_0: if(D_in == 0)
    18. next_state = S_0;
    19. else if(D_in == 1)
    20. next_state = S_1;
    21. else
    22. next_state = S_idle;
    23. S_1: if(D_in == 0)
    24. next_state = S_0;
    25. else if(D_in == 1)
    26. next_state = S_2;
    27. else
    28. next_state = S_idle;
    29. S_2: if(D_in == 0)
    30. next_state = S_0;
    31. else if(D_in == 1)
    32. next_state = S_3;
    33. else
    34. next_state = S_idle;
    35. S_3: if(D_in == 0)
    36. next_state = S_0;
    37. else if(D_in == 1)
    38. next_state = S_3;
    39. else
    40. next_state = S_idle;
    41. default: next_state = S_idle;
    42. endcase
    43. end
    44. //状态转移时序逻辑
    45. always@(posedge clk, negedge rst_n)begin
    46. if(!rst_n)
    47. state <= S_idle;
    48. else
    49. state <= next_state;
    50. end
    51. //输出组合逻辑
    52. always@(*) begin
    53. D_out = (state == S_3);
    54. end
    55. //寄存输出
    56. always @(posedge clk, negedge rst_n) begin
    57. if(!rst_n)
    58. D_out_r1 <= 0;
    59. else
    60. D_out_r1 <= D_out;
    61. end
    62. //寄存输出(下一状态)
    63. always@(posedge clk, negedge rst_n)begin
    64. if(!rst_n)
    65. D_out_r2 <= 0;
    66. else
    67. D_out_r2 <= (next_state == S_3);
    68. end
    69. endmodule

            一个简单的testbench如下所示,图8所示的仿真截图显示了三种不同形式的输出。

    1. `timescale 1ns / 1ns
    2. module t_Seq();
    3. reg D_in, clk, rst_n,En;
    4. wire D_out, D_out_r1, D_out_r2;
    5. Seq_Rec_Moore Seq_Rec_Moore_1 (.D_in(D_in), .clk(clk), .rst_n(rst_n), .D_out(D_out), .En(En), .D_out_r1(D_out_r1), .D_out_r2(D_out_r2));
    6. initial begin
    7. D_in = 0;
    8. clk = 0;
    9. rst_n = 1;
    10. En = 0;
    11. end
    12. initial begin
    13. #5 rst_n = 0;
    14. #4 rst_n = 1;
    15. end
    16. always begin
    17. #5 clk = 0;
    18. #5 clk = 1;
    19. end
    20. initial begin
    21. #5 En =1;
    22. end
    23. initial begin
    24. #5 D_in = 1;
    25. end
    26. endmodule

    图8 Moore状态机仿真截图 

            下面是Mealy型序列检测器的Verilog描述。

    1. module Seq_Rec_Mealy(output reg D_out, D_out_r1, D_out_r2, input D_in, En, clk, rst_n);
    2. parameter S_idle = 3'd0;
    3. parameter S_0 = 3'd1;
    4. parameter S_1 = 3'd2;
    5. parameter S_2 = 3'd3;
    6. parameter S_3 = 3'd4;
    7. reg [2:0] state, next_state;
    8. //下一状态组合逻辑
    9. always@(*)begin
    10. case(state)
    11. S_idle: if((En == 1)&&(D_in == 1))
    12. next_state = S_1;
    13. else if((En == 1)&&(D_in == 0))
    14. next_state = S_0;
    15. else
    16. next_state = S_idle;
    17. S_0: if(D_in == 0)
    18. next_state = S_0;
    19. else if(D_in == 1)
    20. next_state = S_1;
    21. else
    22. next_state = S_idle;
    23. S_1: if(D_in == 0)
    24. next_state = S_0;
    25. else if(D_in == 1)
    26. next_state = S_2;
    27. else
    28. next_state = S_idle;
    29. S_2: if(D_in == 0)
    30. next_state = S_0;
    31. else if(D_in == 1)
    32. next_state = S_3;
    33. else
    34. next_state = S_idle;
    35. S_3: if(D_in == 0)
    36. next_state = S_0;
    37. else if(D_in == 1)
    38. next_state = S_3;
    39. else
    40. next_state = S_idle;
    41. default: next_state = S_idle;
    42. endcase
    43. end
    44. //状态转移时序逻辑
    45. always@(posedge clk, negedge rst_n)begin
    46. if(!rst_n)
    47. state <= S_idle;
    48. else
    49. state <= next_state;
    50. end
    51. //输出组合逻辑
    52. always@(*) begin
    53. D_out = (state == S_3)&(D_in == 1);
    54. end
    55. //寄存输出
    56. always @(posedge clk, negedge rst_n) begin
    57. if(!rst_n)
    58. D_out_r1 <= 0;
    59. else
    60. D_out_r1 <= D_out;
    61. end
    62. //寄存输出(下一状态)
    63. always@(posedge clk, negedge rst_n)begin
    64. if(!rst_n)
    65. D_out_r2 <= 0;
    66. else
    67. D_out_r2 <= (next_state == S_3)&(D_in == 1);
    68. end
    69. endmodule

     图9 Mealy状态机仿真截图 

    一个简单的testbench如下所示,图9的仿真截图显示了如果使用寄存输出,而输入无法维持到下个时钟沿,则会丢失寄存输出信号。

    1. `timescale 1ns / 1ns
    2. module t_Seq();
    3. reg D_in, clk, rst_n,En;
    4. wire D_out, D_out_r1, D_out_r2;
    5. Seq_Rec_Mealy Seq_Rec_Mealy_1 (.D_in(D_in), .clk(clk), .rst_n(rst_n), .D_out(D_out), .En(En), .D_out_r1(D_out_r1), .D_out_r2(D_out_r2));
    6. initial begin
    7. D_in = 0;
    8. clk = 0;
    9. rst_n = 1;
    10. En = 0;
    11. end
    12. initial begin
    13. #5 rst_n = 0;
    14. #4 rst_n = 1;
    15. end
    16. always begin
    17. #5 clk = 0;
    18. #5 clk = 1;
    19. end
    20. initial begin
    21. #5 En =1;
    22. end
    23. initial begin
    24. #5 D_in = 1;
    25. #30 D_in = 0;
    26. #10 D_in = 1;
    27. #37 D_in = 0;
    28. end
    29. endmodule

  • 相关阅读:
    快手推出快手虚拟演播助手
    物联网时代的等保测评:保障万物互联的安全
    强大好用的shell:shell的工作原理是什么
    群辉 NAS 配置 iSCSI 存储
    极验文字点选验证
    想要精通算法和SQL的成长之路 - 最长回文子序列
    最新Unity游戏主程进阶学习大纲(2个月)
    Linux进程信号
    数据结构之:数组
    关于谷歌浏览器设置打开时页面不起作用的解决方法
  • 原文地址:https://blog.csdn.net/weixin_45791458/article/details/134365162