当前位置:首页 > 新闻资讯 > FPGA之家动态 >

FPGA入门系列9--状态机及do文件

时间:2024-07-26      来源:网络搜集 关于我们 0

文章

简介

本系列文章主要针对FPGA初学者编写,包括FPGA的模块书写、基础语法、状态机、RAM、UART、SPI、VGA、以及功能验证等。将每一个知识点作为一个章节进行讲解,旨在更快速的提升初学者在FPGA开发方面的能力,每一个章节中都有针对性的代码书写以及代码的讲解,可作为读者参考。

第十章:状态机

        Verilog HDL 的语句块都是并行执行的, 但是在很多情况下,我们希望执行按照顺序的方式进行,而状态机就可以很好的实现顺序执行。

        有限状态机(Finite State Machine, FSM) 又简称为状态机, 是我们用Verilog HDL 描述数字电路的重要组成方式。状态机分为 mealy 型和 moore 型,其中 mealy 型指的是输出不仅与当前状态有关,还与输入有关, moore 型指的是输出只与当前状态有关。

        状态机的设计基本上采取 always 块加上 case 语句的结构,一般分为三种描述方式,即一段式、二段式、三段式。简单的说,一段式指的是在一个 always

块内使用时序逻辑既描述状态的转移,同时也描述数据的输出;二段式指一个always 块使用时序逻辑描述状态转移,另外一个 always 块使用组合逻辑描述数据输出;三段式指使用三个 always 块,一个 always 模块采用时序逻辑描述状态转移,一个 always 块采用组合逻辑判断状态转移条件,描述状态转移规律,另一个 always 块描述状态输出(可以用组合电路输出,也可以时序电路输出)。

        在使用 Verilog HDL 描述状态机时,习惯性的使用两个均采用时序逻辑的 always 块,第一个 always 块描述状态的转移, 第二个 always 块描述数据的输出, 这样既消除了组合逻辑可能产生的毛刺, 又减小了代码量。组合逻辑产生毛刺可由图 1 说明,输入两个变量 a 和 b 进行相与, 理论上认定 a 和 b 在①处同时变化,这样相与的结果一直为低,然而由于布线的差异, a 和 b 同时变化的可能性很低,这样就会出现图 1 所示的情况,此时 a 和 b 相与的结果就会造成如图 1 所示的结果, ②处为组合逻辑产生的毛刺。

图 1 组合逻辑产生毛刺

        毛刺的产生对于数字系统设计的有效性和可靠性有严重的影响, 因此我们在设计数字电路时应该尽量避免毛刺的产生,而时序逻辑可以很好的消除毛刺,如图 2 所示,当我们使用时序逻辑时, c 的产生不仅跟 a 和 b 有关,还与clk 的沿有关系, 当 clk 的沿采集不到该毛刺时,则可以消掉该毛刺,而 clk 的沿采集到毛刺的概率极小。

图 2 时序逻辑消除毛刺

        综上所述,采用两个时序逻辑 always 块,不仅可以描述清楚状态转移和数据输出,又能消除组合逻辑带来的毛刺。下面给出该状态机描述方法的模板。

        模板中20行为异步复位,即复位的触发条件不仅与clk 的上升沿有关,还与 rst_n 的下降沿有关。如图 3 所示,当 clk 上升沿采到rst_n 为低时可复位,同时当遇到 rst_n 下降沿时也可进行复位, 其中 or 可以改

成19行所示的半角逗号(,)。异步复位时, 若使用复位的下降沿, 则第一个 if 条件必须写成复位为 0, 若使用复位的上升沿,则第一个 if 条件必须写成复位为 1。

图 3 异步复位

        了解了对应的模板后,我们可以举例说明状态机的写法。我们使用状态机描述一个简单的自动售货机,该售货机中的商品 3 元一件,每次投币只能投入

1 元。在我们描述状态机之前,一般会先画出对应的状态转移图,该状态转移图如图 4 所示。

图 4 状态转移图

        根据状态转移图,我们可以得到如下所示的 Verilog HDL 代码。

代码示例 1:

代码解析 1:

        ①第 10 行定义状态变量, 由于此处有三个状态,并且使用独热码(onehot), 所以该状态变量位宽定义为 3 位。独热码指的是每一个数据只有一位是1, 其他位均为 0,由于独热码的变化只需要一位转变即可,所以使用独热码具有可以提高运行速度的优势;

        ②第 13、 14、 15 行定义三个状态的参数, Verilog HDL 是区分字母的大小写的, 一般来说变量是由小写字母组成,为了便于与变量区分开, 我们可以将参数定义成大写;

        ③第 18 行开始的 always 块按照状态转移图描述了状态的转移;

        ④第 42 行开始的 always 块描述了数据的输出产生。

        根据给出的代码示例可以写出对应的测试代码,如下所示。

测试代码示例 1:

        使用 modelsim 对该状态机模块进行仿真,可以得到如图 5 所示的波形。

图 5 错误的状态机仿真波形

        由图 5 中的黄线处看到, 该处 clk 的上升沿采到pi_money 为 1, state 在IDLE 状态(001), 但是状态却没有跳转到 ONE 状态(010), 造成此种结果的原因是测试代码写的有问题,为了得到寄存器的特性,我们在写测试代码时, 除了时钟(clk), 其他由 always 产生的变量均采用非阻塞赋值(<=)。更改后的测试代码如下:

        我们将对应的地方改成非阻塞赋值后可以得到如图 6 所示的波形。

图 6 正确的状态机仿真波形

        根据图 6 的黄线处可以看出满足了寄存器的特性, 但是还存在一个问题,状态还是由数字表示的,若是在波形图上, 状态可以由我们定义的参数表示会

非常方便我们查看对应的信息,下面我们讲解一种可以实现该效果的方法。

        我们已经学过如何使用 modelsim 进行仿真,也了解了操作中的每一步的意思,在使用 modelsim 仿真时,我们还可以将每一步的操作写入一个 modelsim可以识别的脚本文件中,在我们使用 modelsim 进行仿真时,只需要执行该脚本文件即可。Modelsim 可识别的脚本文件包括 do 文件,我们可以在 sim 文件夹中新建一个 do 文件(同建立 V 文件一样,将文本文档后缀改为 do), 例如run.do,用 notepad++ 打开该文件编译,下面给出该 do 文件的内容。

do 文件代码解析:

        ①第 1 行退出当前仿真。在使用 modelsim 进行仿真时,若打开了 sim,则是无法进行新建工程的,此处退出仿真是为了防止 modelsim 处于 sim 时建立工程失败;

        ②第 3 行清空信息栏的信息, 仿真信息栏记录的历史信息干扰我们对此处仿真信息的判断;

        ③第 5 行为建立新的工程,此处无需写工程名称;

        ④第 7、 8 行分别对测试文件和功能文件进行仿真,其中./指的是当前文件夹内部, ../指的是当前文件夹的上一级路径, *.v 指的是所有的 V 文件;

        ⑤第 10 行建立仿真(sim);

        ⑥第 12~16 行建立一个结构体,该结构体类似于 c 语言中的结构体, 将3’001 与 IDLE 关联,其他两个类似,后面的 abc 为该结构体的名称;

        ⑦第 18 行将结构体 abc 与 state 关联, 若要到 state 需要从最顶层开始,此时最顶层为测试模块,在测试模块中功能模块被重新命名为 fsm_inst, 所以

需要按照 tb_fsm/fsm_inst/state 路径才能找到 state 变量, new_state 为 state 关联该结构体之后的名称;

        ⑧第 20 行为添加波形;

        ⑨第 21 行运行该仿真 1us。

        该 do 文件可以作为模板,后期若是不需要结构体可删除。按照以下步骤运行 do 文件:

   ①打开 modelsim,选择 File>>Change Directory…, 如图 7 所示, 找到 do 文件的路径;

图 7 改变 modelsim 指向路径

        ②在 Transcript 窗口输入 do run.do, 如图 8 所示, 敲击回车键运行该 do 文件。

图 8 运行 do 文件

        运行后波形如图 9 所示, 参数名称已经显示在波形图中,方便我们对代码的分析。

图 9 运行 do 文件后的波形图

在第十一章中将对Verilog HDL 中按键消抖进行讲解。

往期回顾

FPGA入门系列1--模块书写&电路综合

FPGA入门系列2--仿真验证

FPGA入门系列3--wire与reg

FPGA入门系列4--赋值语句

FPGA入门系列5--运算符号

FPGA入门系列6--判断语句

FPGA入门系列7--时钟分频

FPGA入门系列8--Top_Down设计

未完待续

 关注我们了解更多资讯


注明:本内容来源网络,不用于商业使用,禁止转载,如有侵权,请来信到邮箱:429562386ⓐqq.com 或联系本站客服处理,感谢配合!

用户登陆

    未注册用户登录后会自动为您创建账号

提交留言