状态机的verilog写法

这篇具有很好参考价值的文章主要介绍了状态机的verilog写法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

“硬件设计很讲究并行设计思想,虽然用Verilog描述的电路大都是并行实现的,但是对于实际的工程应用,往往需要让硬件来实现一些具有一定顺序的工作,这就要用到状态机思想。什么是状态机呢?简单的说,就是通过不同的状态迁移来完成一些特定的顺序逻辑。硬件的并行性决定了用Verilog描述的硬件实现(臂如不同的always语句)都是并行执行的,那么如果希望分多个时间完成一个任务,怎么办?也许可以用多个使能信号来衔接多个不同的模块,但是这样做多少显得繁琐。状态机的提出会大大简化这一工作。”
   ——特权同学《深入浅出玩转FPGA》
一、状态机分类
  1.Moore型:状态机的状态变化仅和当前状态有关(特权同学《深入浅出玩转FPGA》);时序逻辑电路的输出只取决于当前状态(夏宇闻《Verilog数字系统设计》)。设计高速电路时常用此类状态机,把状态变化直接用作输出。

2.Mealy型:状态机的状态变化不仅与当前的状态有关,还取决于当前的输入条件(特权同学《深入浅出玩转FPGA》);时序逻辑的输出不但取决于状态还取决于输入(夏宇闻《Verilog数字系统设计》)。平常使用较多的是此类状态机。

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

二、状态机编码
   状态机的参数定义采用的都是独热码,和格雷码相比,虽然独热码多用了触发器,但所用组合电路可以省一些,因而使电路的速度和可靠性有显著提高,而总的单元数并无显著增加。采用独热编码后有了多余的状态,就有一些不可达到的状态。为此在case语句的最后需要增加default分支向。这可以用默认项表示该项,也可以用确定项表示,以确保回到初始状态。一般综合器都可以通过综合指令的控制来合理地处理默认项。

三、实例分析
  状态机一般有三种不同的写法,即一段式、两段式和三段式的状态机写法,他们在速度、面积、代码可维护性等各个方面互有优劣,不要对任何一种写法给出“一棍子打死”的定论。手头上刚好有一个状态机的例子,借此记录一下三种状态机的Verilog写法。

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

信号 含义
clk 时钟信号
rst_n 复位信号
in 输入信号,币值,有1和2两种,投钱
out 输出信号,币值,有1和2两种,找零
out_vld 输出信号,脉动,为1则输出1瓶脉动

3.2 状态转移图
根据要求,我们先把状态转移图画出来,绘画软件:Visio,如果没有安装也可以用wps自带应用的“流程图”功能:
状态机verilog,fpga开发,经验分享
3.3 代码设计
(1)一段式状态机
  只定义一个转移状态:state,总体结构是一段always时序逻辑,用于描述状态转移和输出。由于是时序逻辑能够自动保持,所以可以省略else。但建议在初始状态时(例如下文的S0),else处赋一下初始值。

//======================================================================
// --- 描述 : 售货机练习,采用一段式状态机
//======================================================================

module FSM_1
//---------------------<端口声明>---------------------------------------
(
input                   clk                 ,
input                   rst_n               ,
input      [1:0]        in                  ,
output reg [1:0]        out                 ,
output reg              out_vld
);
//---------------------<信号定义>---------------------------------------
reg  [3:0]              state               ;
//---------------------<状态机参数>-------------------------------------
localparam S0           = 4'b0001           ;
localparam S1           = 4'b0010           ;
localparam S2           = 4'b0100           ;
localparam S3           = 4'b1000           ;

//----------------------------------------------------------------------
//--   状态机第1段
//----------------------------------------------------------------------
always@(posedge clk or negedge rst_n)begin
    if(!rst_n)begin
        state   <= S0;
        out     <= 0 ;
        out_vld <= 0 ;
    end
    else begin
        case(state)
            S0: begin
                if(in==1)begin
                    state   <= S1;
                end
                else if(in==2)begin
                    state   <= S2;
                end
                else begin
                    out     <= 0 ;
                    out_vld <= 0 ;
                end
            end
            S1: begin
                if(in==1)begin
                    state   <= S2;
                end
                else if(in==2)begin
                    state   <= S3;
                end
            end
            S2: begin
                if(in==1)begin
                    state   <= S3;
                end
                else if(in==2)begin
                    state   <= S0;
                    out_vld <= 1 ;
                end
            end
            S3: begin
                if(in==1)begin
                    state   <= S0;
                    out_vld <= 1 ;
                end
                else if(in==2)begin
                    state   <= S0;
                    out     <= 1 ;
                    out_vld <= 1 ;
                end
            end
            default:state   <= S0;
        endcase
    end
end



endmodule

仿真波形如下:
 状态机verilog,fpga开发,经验分享
结论:波形和预想一致!

(2)二段式状态机
  二段式状态机,第一段用时序逻辑描述state_c(现态)和state_n(次态),第二段用组合逻辑描述状态转移和输出。由于是组合逻辑,为避免产生锁存器,else处一定要写上 if 中说使用了的信号。

//======================================================================
// --- 描述 : 售货机练习,采用二段式状态机
//======================================================================

module FSM_2
//---------------------<端口声明>---------------------------------------
(
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           ;

//----------------------------------------------------------------------
//--   状态机第1段
//----------------------------------------------------------------------
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)begin
                state_n = S1;
            end
            else if(in==2)begin
                state_n = S2;
            end
            else begin
                state_n = state_c;
                out     = 0 ;
                out_vld = 0 ;
            end
        end
        S1: begin
            if(in==1)begin
                state_n = S2;
            end
            else if(in==2)begin
                state_n = S3;
            end
            else begin
                state_n = state_c;
            end
        end
        S2: begin
            if(in==1)begin
                state_n = S3;
            end
            else if(in==2)begin
                state_n = S0;
                out_vld = 1 ;
            end
            else begin
                state_n = state_c;
                out_vld = 0;
            end
        end
        S3: begin
            if(in==1)begin
                state_n = S0;
                out_vld = 1 ;
            end
            else if(in==2)begin
                state_n = S0;
                out     = 1 ;
                out_vld = 1 ;
            end
            else begin
                state_n = state_c;
                out     = 0;
                out_vld = 0;
            end
        end
        default:state_n = S0;
    endcase
end


endmodule

仿真波形如下所示:
状态机verilog,fpga开发,经验分享
结论:波形和预想一致!但是产生了毛刺,这也是二段式状态机的缺点。

毛刺产生原因:状态机通常包含主控时序进程、主控组合进程和辅助进程三个部分。其中,主控组合进程的任务是根据外部输入的控制信号和当前状态的状态值确定下一 状态的取向,并确定对外输出内容和对内部其他组合或时序进程输出控制信号的内容。一方面,由于有组合逻辑进程的存在,状态机输出信号会出现毛刺——竞争冒险现象;另一方面,如果状态信号是多位值的,则在电路中对应了多条信号线。由于存在传输延迟,各信号线上的值发生改变的时间则存在先后,从而使得状态迁移时在初始状态和目的状态之间出现临时状态——毛刺。

简单理解为:state_n 会因为组合逻辑原因不断出现临时状态,这些状态是无效的,而输出也因为组合逻辑原因产生这些临时状态,即毛刺。

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

//======================================================================
// --- 描述 : 售货机练习,采用三段式状态机
//======================================================================

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           ;

//----------------------------------------------------------------------
//--   状态机第1段
//----------------------------------------------------------------------
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;
    endcase
end

//----------------------------------------------------------------------
//--   状态机第3段
//----------------------------------------------------------------------
//找零钱
always @(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;
end


endmodule

仿真波形如下所示:
状态机verilog,fpga开发,经验分享
(4)一段式和三段式结合的状态机(by 威三学院FPGA教程)

V3学院状态机,只定义一个转移状态:state。第一段用时序逻辑描述state状态转移,第二段用时序逻辑描述输出,第二段可以是多个always块。由于是时序逻辑能够自动保持,所以可以省略else。这种状态机的优点是既消除了组合逻辑可能产生的毛刺,又减少了代码量。

//======================================================================
// --- 描述 : 售货机练习,采用V3学院的状态机
//======================================================================

module FSM_V3
//---------------------<端口声明>---------------------------------------
(
input                   clk                 ,
input                   rst_n               ,
input      [1:0]        in                  ,
output reg [1:0]        out                 ,
output reg              out_vld
);
//---------------------<信号定义>---------------------------------------
reg  [3:0]              state               ;
//---------------------<状态机参数>-------------------------------------
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 <= S0;
    else begin
        case(state)
            S0: begin
                if(in==1)
                    state <= S1;
                else if(in==2)
                    state <= S2;
            end
            S1: begin
                if(in==1)
                    state <= S2;
                else if(in==2)
                    state <= S3;
            end
            S2: begin
                if(in==1)
                    state <= S3;
                else if(in==2)
                    state <= S0;
            end
            S3: begin
                if(in==1 || in==2)      // in != 0也行
                    state <= S0;
            end
            default:state <= S0;
        endcase
    end
end

//----------------------------------------------------------------------
//--   输出
//----------------------------------------------------------------------
//找零钱
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        out <= 0;
    else if(state==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==S2 && in==2) || (state==S3 && in!=0))
        out_vld <= 1;
    else
        out_vld <= 0;
end


endmodule

仿真波形如下所示:
状态机verilog,fpga开发,经验分享
结论:波形和预想一致!

3.4testbench

`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字符16位
reg [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";
    endcase
end

//----------------------------------------------------------------------
//--   时钟信号和复位信号
//----------------------------------------------------------------------
initial begin
    clk = 1;
    forever
    #(`Clock/2) clk = ~clk;
end

initial begin
    rst_n = 0; #(`Clock*20+1);
    rst_n = 1;
end

//----------------------------------------------------------------------
//--   设计输入信号
//----------------------------------------------------------------------
initial begin
    #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;
end


endmodule

四、状态机名称查看器
  可以看到,我的Modelsim波形中出现了一个信号state_name,里面显示了状态机的名称,这是怎么做到的呢?方法有很多种,这里介绍两种。

4.1 testbench法
  testbench里增加一段参数转ASCII码的代码,如下所示:

//----------------------------------------------------------------------
//--   状态机名称查看器
//----------------------------------------------------------------------
localparam S0           = 4'b0001           ;
localparam S1           = 4'b0010           ;
localparam S2           = 4'b0100           ;
localparam S3           = 4'b1000           ;
//2字符16位
reg [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";
    endcase
end

在Modelsim中点击信号state_name,右键选择用ASSIC码查看就可以看到状态机的名称,而不再是头疼的的0001、0010等字符。编写时注意一下位宽,一个ASSIC码字符宽度是8位,例如“S0”有2个字符则需要16位宽。
 
 4.2 do/tcl文件法
  首先你得学会怎么使用Modelsim的自动化脚本仿真,那么我们只要再do文件中加入这段代码即可:

# ======================================================================
# ==   状态机名称查看器
# ======================================================================

# 结构体设置
virtual type {
    {4'b0001 S0}
    {4'b0010 S1}
    {4'b0100 S2}
    {4'b1000 S3}
} fsm_type;

# 结构体和信号名关联,命名为state_name
virtual function {(fsm_type)/fsm_tb/u_fsm/state} state_name

参考资料:

[1]小梅哥FPGA教程

[2]威三学院FPGA教程

[3]咸鱼IC教程

[4]吴厚航. 深入浅出玩转FPGA[M]. 北京航空航天大学出版社, 2013.

[5]夏宇闻. Verilog数字系统设计教程.第3版[M]. 北京航空航天大学出版社, 2013.

[6]韩彬, 于潇宇, 张雷鸣. FPGA设计技巧与案例开发详解[M]. 电子工业出版社, 2014.文章来源地址https://www.toymoban.com/news/detail-773021.html

到了这里,关于状态机的verilog写法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Verilog写状态机的三种描述方式之三段式

    状态机的设计思路: 一是从状态机变量入手,分析各个状态的输入、状态转移和输出; 二是先确定电路的输出关系,再回溯规划每个状态的条件、输入等; 状态机的三要素是状态、输入和输出 , 根据状态机状态是否和输入条件相关,可以分为Moore型状态机(与输入无关)和

    2024年02月14日
    浏览(42)
  • FPGA实验三:状态机的设计

    目录 一、实验目的 二、实验要求 三、实验代码 1.design source文件部分代码

    2024年02月12日
    浏览(33)
  • FPGA状态机的理解与设计

    FPGA状态机的理解 功能框图: 功能框图 moore型状态机的输出G只与当前的状态有关,而mealy状态机的输出不但与当前的状态有关还与输入有关 注:在实际的生活中,mealy型状态机的出现场景较多。 无论是moore型状态机还是mealy型的状态机,一般都使用三段式状态机来设计。在设

    2024年02月04日
    浏览(35)
  • zynq学习之fpga篇(三)状态机的使用

    可乐机每次投1枚一块硬币,每瓶可乐3块钱,投3个硬币就可以出可乐。 状态转移图 分析 一个简单的状态转移图,由此编写代码。  这篇想找一个简单的状态机实例,没有找到,下一篇开始进一阶,数码管驱动。 不啻微芒,造炬成阳。

    2024年02月22日
    浏览(56)
  • FPGA中有限状态机的状态编码采用格雷码还是独热码?

            有限状态机是由寄存器组和组合逻辑构成的硬件时序电路,其状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只可能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态,究竟转向哪一状态还是留在原状态不但取决于各个输入值,还取决于当前

    2024年02月05日
    浏览(75)
  • FPGA学习经验分享——入门篇

    FPGA是一个高度集成化的芯片,其学习过程既需要编程,又需要弄懂硬件电路和计算机架构。涉及到的知识和基础非常多,如果不合理地安排学习内容,学习过程会非常漫长和枯燥。这篇文章主要阐述了对于入门FPGA的一些经验分享,希望能够给想学FPGA的人一些引导,少走一些

    2024年02月03日
    浏览(40)
  • 成为一名FPGA工程师:面试题与经验分享

    在现代科技领域,随着数字电子技术的迅猛发展,FPGA(可编程逻辑器件)工程师成为了备受瞩目的职业之一。FPGA工程师不仅需要掌握硬件设计的基本原理,还需要具备良好的编程能力和解决问题的实践经验。面对如此竞争激烈的行业,通过面试成为一名FPGA工程师是一项具有

    2024年02月04日
    浏览(40)
  • FPGA经验谈系列文章——FPGA开发方向以及算法开发模型

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 FPGA开发笼统的说可以分为两个方向,一个是接口方向、一个是算法方向。 接口方向可不是简单的uart、IIC、SPI等这些简单接口,这些东西不足以支撑一个方向,大部分都是基于serdes的高速复杂接口,例如

    2023年04月10日
    浏览(62)
  • 实战经验分享:开发同城外卖跑腿小程序

    下文,小编将与大家一同探究同城外卖跑腿小程序的开发实战,包括但不限于技术选型、开发流程、用户体验等多个方面。 1.技术选型 在同城外卖跑腿小程序的开发中,技术选型是至关重要的一环。对于前端,选择了使用Vue.js框架,其灵活性和生态系统的支持使得开发过程更

    2024年02月03日
    浏览(47)
  • 使用Unity开发手机AR项目经验分享

           AR技术发展到现在也不新鲜了,开发AR的SDK也是五花八门,怎么选择是个问题。这篇文章提供了一套整体开发AR思路,还有后续兼容性问题的解决思路。         Unity开发手机AR项目主要是集成的ARCore和ARKit,ARCore面向Android手机而ARKit面向IOS,从Unity2019后Unity官方使用

    2024年02月11日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包