• 以爱情规律为例,浅谈三段式描述状态机


    目录

    基础概念介绍

    状态机的要素

    FSM的分类

    Verilog描述状态机的方法

    一段式描述

    两段式描述

    三段式描述

     结语


    基础概念介绍

            今夜闲来无事,忽然想到最近准备复习一下Verilog语法,所以就侃一侃状态机吧!

            状态机根据状态的数量可以分为两种:有限状态机(Finite State Machine)和无限状态机(Infinite State Machine),本篇文章主要讨论有限状态机的一段式,二段式,和三段式的写法。

            状态机是一种思想方法,往往我们自己就是一台状态机器。

            我们常常说“唉,女友又和我吵架了,所以我最近不在状态呀”来解释自己最近情绪低落,工作不积极的原因。

            从状态机的角度来说就是从 “积极状态” 转变到了“消极状态” ,这就是所谓状态切换,状态切换的条件是“女朋友和我分手了”,对应的人在不同状态也会有不同的表现,这就是状态机的输出

            然后过了几天,当我们又找到新的女朋友时,我们又会回到积极的状态,如此往复。

            从上我们可以看出,其实状态机特别适合用来描述具有先后顺序或者逻辑规律的事情,这就是状态机的本质。

    状态机的要素

    • 状态,用来划分逻辑顺序和时序规律
    • 输入,状态改变的条件
    • 输出,某个状态特定发生的事件

    FSM的分类

             这两者的区别就在于,如果Mealy和女朋友吵架时还被女朋友打了,他会生气,如果没有被打,他会心里难过,但Moore这个人吧和女朋友吵架了无论有没有被打,只会因为吵架而心里难过。

    Verilog描述状态机的方法

            好了,扯淡时间结束,下面我们聊一点干货!

            上面的状态转移图来自HDLBits,这是一个很号的Verilog语法练习网站。描述的是一个两状态的Moore型状态机(输出只与状态有关,与输入无关)

    一段式描述

            所谓一段式描述就是将状态转移和状态输出还有状态转移判断都写在一个always块

    1. // Note the Verilog-1995 module declaration syntax here:
    2. module top_module(clk, reset, in, out);
    3. input clk;
    4. input reset; // Synchronous reset to state B
    5. input in;
    6. output out;//
    7. reg out;
    8. parameter A=1'b1,B=1'b0;
    9. reg present_state;
    10. always @(posedge clk or posedge reset) begin
    11. if (reset) begin
    12. present_state <= B;
    13. out <= 1'b1;
    14. end else begin
    15. case (present_state)
    16. A:begin
    17. if(in) begin
    18. present_state <= A; //状态转移
    19. out <=1'b0; //状态输出
    20. end
    21. else begin
    22. present_state <= B;
    23. out <= 1'b1;
    24. end
    25. end
    26. B:begin
    27. if(in) begin
    28. present_state <= B;
    29. out <=1'b1;
    30. end
    31. else begin
    32. present_state <= A;
    33. out <= 1'b0;
    34. end
    35. end
    36. endcase
    37. end
    38. end
    39. endmodule

            这样当然能够成功描述出状态转移图所示的状态机,但是因为输入进入时序电路是异步的,所以状态转移判断的电路应该写成组合逻辑,写成一段式相当于把组合逻辑和时序逻辑混写 这样不符合 Verilog组合逻辑和时序逻辑分开描述的代码风格,同时我个人理解:

    一段式状态机会延长关键路径,降低状态机性能。

    两段式描述

            两段式描述的显著特点有两个:

    1. 状态转移为时序电路
    2. 次态判断状态输出为组合电路
    1. // Note the Verilog-1995 module declaration syntax here:
    2. module top_module(clk, reset, in, out);
    3. input clk;
    4. input reset; // Synchronous reset to state B
    5. input in;
    6. output out;//
    7. reg out;
    8. parameter A = 1'b1,B=1'b0;
    9. // Fill in state name declarations
    10. reg present_state, next_state;
    11. always@(posedge clk)begin //状态转移
    12. if(reset == 1'b1)
    13. present_state <= B;
    14. else
    15. present_state <= next_state;
    16. end
    17. always @(*) begin
    18. case (present_state) //次态判断,组合逻辑
    19. A: if(in)
    20. next_state = A;
    21. else
    22. next_state = B;
    23. B:if(in)
    24. next_state = B;
    25. else
    26. next_state = A;
    27. default:
    28. next_state = B;
    29. // Fill in state transition logic
    30. endcase
    31. case (present_state) //输出,组合逻辑
    32. A: out = 1'b0;
    33. B: out = 1'b1;
    34. // Fill in output logic
    35. endcase
    36. end
    37. endmodule

    小技巧:两段式状态机的模板为两个always,一个为 状态转移(@clk)、输出与次态判断(@*) ,以及两个状态 present_statenext_state

             但是两段式的状态机也有缺点,那就是输出为组合逻辑,容易产生毛刺,因此有条件最好在输出的位置插入一个寄存器。

    三段式描述

            三段式是在两段式的基础上解决了组合逻辑输出毛刺的问题

    1. 状态转移(时序)
    2. 次态判断(组合)
    3. 电路输出(时序)

            这时总会有个聪明哥站出来说上一句:“哎呀,你把电路输出写成时序逻辑那么输出要延后了呀!”

            请大家试想一下,如果我们电路输出的组合逻辑是根据现态来决定输出的,并且我们暂定状态在每个时钟周期,从A到B再到A这样循环。当state为A时,组合逻辑输入使得next_state为B,下一次时钟沿来临时,next_state将被传递给present_state,此时如果输出的时序逻辑模块是根据现态判断输出(即case语句是判断present_state),那么在B状态的起始,输出的内容将为A状态的输出,并且直到下次时钟沿来临才会改变。

            因此,电路输出将根据next_state来决定。 

    1. // Note the Verilog-1995 module declaration syntax here:
    2. module top_module(clk, reset, in, out);
    3. input clk;
    4. input reset; // Synchronous reset to state B
    5. input in;
    6. output out;//
    7. reg out;
    8. parameter A = 1'b1,B=1'b0;
    9. // Fill in state name declarations
    10. reg present_state, next_state;
    11. always@(posedge clk)begin //状态转移
    12. if(reset == 1'b1)
    13. present_state <= B;
    14. else
    15. present_state <= next_state;
    16. end
    17. always @(*) begin//次态判断,组合逻辑
    18. case (present_state)
    19. A: if(in)
    20. next_state = A;
    21. else
    22. next_state = B;
    23. B:if(in)
    24. next_state = B;
    25. else
    26. next_state = A;
    27. default:
    28. next_state = B;
    29. // Fill in state transition logic
    30. endcase
    31. end
    32. always@(posedge clk)begin //电路输出,时序逻辑
    33. if(reset)
    34. out <= 1'b1;
    35. else
    36. begin
    37. case(next_state)
    38. A: out <= 1'b0;
    39. B: out <= 1'b1;
    40. default:
    41. out <= 1'b1;
    42. endcase
    43. end
    44. end
    45. endmodule

    小技巧:三段式状态机的要点:两个状态(present_state)与三个always(状态转移@(posedge clk)、电路输出@(posedge clk)、次态判断always@(*)) 

     结语

            正所谓,天下武功,唯快不破同样,天下代码,唯练不破。状态机是一种方法论,不仅仅存在于时序电路,更是在编程算法和现实生活中广为存在,可以说,万物本质皆为状态机,我们要保留一颗融会贯通的心,这样学习才能得心应手,游刃有余,好吧今天的成语大会到此结束!

  • 相关阅读:
    信号量Semaphore详解
    数据结构与算法_二叉搜索树
    「Python循环结构」使用for循环实现高斯求和、阶乘、斐波那契数列
    【正点原子STM32连载】第三十七章 触摸屏实验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1
    【300+精选大厂面试题持续分享】大数据运维尖刀面试题专栏(二)
    OpenHarmony网络协议通信c-ares [交叉编译]异步解析器库
    文件上传漏洞详解
    【中间件】Redis如何解决BigKey
    Excel-VBA 快速上手(一、宏、VBA、过程、类型与变量、函数)
    Layui自定义列表多选
  • 原文地址:https://blog.csdn.net/weixin_54358182/article/details/127563872