当前位置: 首页 > 图灵资讯 > 技术篇> verilog状态机 三段式 状态机 (代码 可以运行)

verilog状态机 三段式 状态机 (代码 可以运行)

来源:图灵教育
时间:2023-05-23 09:30:30

git中的代码

link

“硬件设计非常注重并行设计理念。虽然Verilog描述的大多数电路都是并行实现的,但对于实际的工程应用程序,硬件往往需要实现一些有一定顺序的工作,这需要使用状态机器的想法。什么是状态机?简单地说,一些特定的顺序逻辑是通过不同的状态迁移来完成的。硬件的并行性决定了Verilog描述的硬件实现(手臂如不同的always语句)是并行执行的,那么如果你想在多个时间内完成一项任务呢?也许可以用多个使能信号连接多个不同的模块,但这样做有多麻烦。提出状态机将极大地简化这项工作。”

——特权同学《深入浅出玩FPGA》

一、状态机分类:

1.Moore型:状态机的状态变化仅与当前状态有关(特权同学《简单玩FPGA》);时序逻辑电路的输出仅取决于当前状态(夏宇文的Verilog数字系统设计)。这种状态机常用于设计高速电路,直接用于输出状态变化。

2.Mealy型:状态机的状态变化不仅与当前状态有关,还取决于当前的输入条件(特权学生FPGA);时序逻辑的输出不仅取决于状态,还取决于输入(夏宇文的Verilog数字系统设计)。这种状态机通常用得更多。

“事实上,只要这些状态机器之间有一些变化,它们就可以从一种形式转变为另一种形式。准确地将状态机器分为这类或那类并不重要。重要的是设计师如何掌握输出结构,以满足设计的总体目标,包括定期的准确性和灵活性。”

——夏宇闻《Verilog数字系统设计》

二、状态机编码:

状态机的参数定义采用独热代码。与格雷代码相比,虽然独热代码使用更多的触发器,但使用的组合电路可以节省一些,因此电路的速度和可靠性显著提高,总单元数量没有显著增加。使用独热编码后,会出现多余的状态,会出现一些无法达到的状态。因此,default分支方向需要在case语句的最后增加。这个项目可以用默认项表示,也可以用确定项表示,以保证回到初始状态。一般综合器可以通过控制综合指令合理处理默认项目。

三、实例分析

状态机一般有三种不同的写作方法,即一段、两段和三段状态机写作方法。它们在速度、面积、代码可维护性等方面都有优缺点。不要对任何写作方法给出“用棍子杀死”的结论。手头碰巧有一个状态机的例子,以记录三种状态机的Verilog写作方法。

要求:

自动售货机有一种价值4元的脉动饮料,支持1元和2元的硬币。请设计一个状态机来检测投资的硬币。当累计投资价值大于或等于脉动价格时,自动售货机会自动更换并弹出一瓶脉动饮料。硬币和商品一个接一个地进出,不会有很多硬币一次弹出很多瓶脉动。

信号

含义

clk

时钟信号

rst_n

复位信号

in

输入信号,货币价值,有1和2种,投资

out

输出信号,货币值,有1和2两种,零

out_vld

输出信号,脉动,输出1瓶脉动

状态转移图:

根据要求,我们首先将图片转移到状态,绘画软件:Visio,如果没有安装,也可以使用wps应用程序的“流程图”功能:

verilog状态机 三段式 状态机 (代码 可以运行)_Verilog

======================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================== --- 名称 : FSM_3// --- 作者 : xianyu_FPGA// --- 日期 : 2018-12-15// --- 描述 : 自动售货机练习,采用三级状态机///======================================================================module FSM_3//---------------------<端口声明>---------------------------------------(input                   clk                 ,input                   rst_n               ,input      [1:0]        in                  ,output reg [1:0]        out                 ,output reg              out_vld);//---------------------<信号定义>---------------------------------------reg  [3:0]              state_c             ;reg  [3:0]              state_n             ;//---------------------<状态机参数>-------------------------------------localparam S0           = 4'b0001           ;localparam S1           = 4'b0010           ;localparam S2           = 4'b0100           ;localparam S3           = 4'b1000           ;//----------------------------------------------------------------------//--   状态机第一段////----------------------------------------------------------------------always @(posedge clk or negedge rst_n)begin    if(!rst_n)        state_c <= S0;    else        state_c <= state_n;end//----------------------------------------------------------------------//--   状态机第2段////----------------------------------------------------------------------always @(*)begin    case(state_c)        S0: begin            if(in==1)                state_n = S1;            else if(in==2)                state_n = S2;            else                state_n = state_c;        end        S1: begin            if(in==1)                state_n = S2;            else if(in==2)                state_n = S3;            else                state_n = state_c;        end        S2: begin            if(in==1)                state_n = S3;            else if(in==2)                state_n = S0;            else                state_n = state_c;        end        S3: begin            if(in==1 || in==2)      // in != 0也行                state_n = S0;            else                state_n = state_c;        end        default:state_n = S0;    endcaseend//----------------------------------------------------------------------//--   状态机第三段//////找到零钱alwaysaysays @(posedge clk or negedge rst_n)begin    if(!rst_n)        out <= 0;    else if(state_c==S3 && in==2)        out <= 1;    else        out <= 0;end//输出脉动always @(posedge clk or negedge rst_n)begin    if(rst_n==1'b0)        out_vld <= 0;    else if((state_c==S2 && in==2) || (state_c==S3 && in!=0))        out_vld <= 1;    else        out_vld <= 0;endendmodule`timescale 1ns/1ps  //时间精度`define    Clock 20 ///时钟周期module FSM_3_tb;//--------------------< 端口 >------------------------------------------reg                     clk                 ;reg                     rst_n               ;reg  [1:0]              in                  ;wire [1:0]              out                 ;wire                    out_vld             ;//----------------------------------------------------------------------//--   模块例化////----------------------------------------------------------------------FSM_3 u_FSM_3(    .clk                (clk                ),    .rst_n              (rst_n              ),    .in                 (in                 ),    .out                (out                ),    .out_vld            (out_vld            ));//----------------------------------------------------------------------//--   状态机名称查看器///----------------------------------------------------------------------localparam S0           = 4'b0001           ;localparam S1           = 4'b0010           ;localparam S2           = 4'b0100           ;localparam S3           = 4'b1000           ;//2字符16reg [15:0]              state_name          ;always@(*)begin    case(u_FSM_3.state_c)        S0:     state_name = "S0";        S1:     state_name = "S1";        S2:     state_name = "S2";        S3:     state_name = "S3";        default:state_name = "S0";    endcaseend//----------------------------------------------------------------------//--   时钟信号和复位信号///----------------------------------------------------------------------initial begin    clk = 1;    forever    #(`Clock/2) clk = ~clk;endinitial begin    rst_n = 0; #(`Clock*20+1);    rst_n = 1;end//----------------------------------------------------------------------//--   设计输入信号////----------------------------------------------------------------------initial begin    $dumpfile("test.vcd");    $dumpvars(0,FSM_3_tb);    #1;    in = 0;    #(`Clock*20+1); ///初始化完成//情况1--------------------------    in = 1;         //1块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 1;         //1块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 1;         //1块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 1;         //1块钱    #(`Clock*1);    in = 0;    #(`Clock*10);//情况2--------------------------    in = 1;         //1块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 1;         //1块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 1;         //1块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 2;         //2块钱    #(`Clock*1);    in = 0;    #(`Clock*10);//情况3--------------------------    in = 1;         //1块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 1;         //1块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 2;         //2块钱    #(`Clock*1);    in = 0;    #(`Clock*10);//情况4--------------------------    in = 1;         //1块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 2;         //2块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 2;         //2块钱    #(`Clock*1);    in = 0;    #(`Clock*10);//情况5--------------------------    in = 2;         //2块钱    #(`Clock*1);    in = 0;    #(`Clock*1);    in = 2;         //2块钱    #(`Clock*1);    in = 0;    #(`Clock*10);    $stop;endendmodule

我用的是 vivado 21 秒学会 vivado 仿真

verilog状态机 三段式 状态机 (代码 可以运行)_fpga开发_02