“硬件设计很讲究并行设计思想,虽然用Verilog描述的电路大都是并行实现的,但是对于实际的工程应用,往往需要让硬件来实现一些具有一定顺序的工作,这就要用到状态机思想。什么是状态机呢?简单的说,就是通过不同的状态迁移来完成一些特定的顺序逻辑。硬件的并行性决定了用Verilog描述的硬件实现(臂如不同的always语句)都是并行执行的,那么如果希望分多个时间完成一个任务,怎么办?也许可以用多个使能信号来衔接多个不同的模块,但是这样做多少显得繁琐。状态机的提出会大大简化这一工作。”——特权同学《深入浅出玩转FPGA》
一、状态机分类:
1.Moore型:状态机的状态变化仅和当前状态有关(特权同学《深入浅出玩转FPGA》);时序逻辑电路的输出只取决于当前状态(夏宇闻《Verilog数字系统设计》)。设计高速电路时常用此类状态机,把状态变化直接用作输出。
2.Mealy型:状态机的状态变化不仅与当前的状态有关,还取决于当前的输入条件(特权同学《深入浅出玩转FPGA》);时序逻辑的输出不但取决于状态还取决于输入(夏宇闻《Verilog数字系统设计》)。平常使用较多的是此类状态机。
“其实这几种状态机之间,只要做一些改变,便可以从一种形式转变为另一种形式。把状态机精确的分为这类或那类,其实并不重要,重要的是设计者如何把握输出的结构能满足设计的整体目标,包括定时的准确性和灵活性。”——夏宇闻《Verilog数字系统设计》
二、状态机编码:
状态机的参数定义采用的都是独热码,和格雷码相比,虽然独热码多用了触发器,但所用组合电路可以省一些,因而使电路的速度和可靠性有显著提高,而总的单元数并无显著增加。采用独热编码后有了多余的状态,就有一些不可达到的状态。为此在case语句的最后需要增加default分支向。这可以用默认项表示该项,也可以用确定项表示,以确保回到初始状态。一般综合器都可以通过综合指令的控制来合理地处理默认项。
三、实例分析
状态机一般有三种不同的写法,即一段式、两段式和三段式的状态机写法,他们在速度、面积、代码可维护性等各个方面互有优劣,不要对任何一种写法给出“一棍子打死”的定论。手头上刚好有一个状态机的例子,借此记录一下三种状态机的Verilog写法。
要求:
售货机里有价值4元的脉动饮料,支持1元和2元硬币。请设计一个状态机,检测投入的硬币,当累计投入币值大于等于脉动价格时,售货机自动找零并弹出1瓶脉动饮料。硬币和商品都是一个一个的进出,不会出现一次性投很多个硬币弹出很多瓶脉动的情况。
信号 | 含义 |
clk | 时钟信号 |
rst_n | 复位信号 |
in | 输入信号,币值,有1和2两种,投钱 |
out | 输出信号,币值,有1和2两种,找零 |
out_vld | 输出信号,脉动,为1则输出1瓶脉动 |
状态转移图:
根据要求,我们先把状态转移图画出来,绘画软件:Visio,如果没有安装也可以用wps自带应用的“流程图”功能:
1. 一段式状态机
只定义一个转移状态:state,总体结构是一段always时序逻辑,用于描述状态转移和输出。由于是时序逻辑能够自动保持,所以可以省略else。但建议在初始状态时(例如下文的S0),else处赋一下初始值。
1 //====================================================================== 2 // --- 名称 : FSM_1 3 // --- 作者 : xianyu_FPGA 4 // --- 日期 : 2018-12-15 5 // --- 描述 : 售货机练习,采用一段式状态机 6 //====================================================================== 7 8 module FSM_1 9 //---------------------<端口声明>--------------------------------------- 10 ( 11 input clk , 12 input rst_n , 13 input [1:0] in , 14 output reg [1:0] out , 15 output reg out_vld 16 ); 17 //---------------------<信号定义>--------------------------------------- 18 reg [3:0] state ; 19 //---------------------<状态机参数>------------------------------------- 20 localparam S0 = 4'b0001 ; 21 localparam S1 = 4'b0010 ; 22 localparam S2 = 4'b0100 ; 23 localparam S3 = 4'b1000 ; 24 25 //---------------------------------------------------------------------- 26 //-- 状态机第1段 27 //---------------------------------------------------------------------- 28 always@(posedge clk or negedge rst_n)begin 29 if(!rst_n)begin 30 state <= S0; 31 out <= 0 ; 32 out_vld <= 0 ; 33 end 34 else begin 35 case(state) 36 S0: begin 37 if(in==1)begin 38 state <= S1; 39 end 40 else if(in==2)begin 41 state <= S2; 42 end 43 else begin 44 out <= 0 ; 45 out_vld <= 0 ; 46 end 47 end 48 S1: begin 49 if(in==1)begin 50 state <= S2; 51 end 52 else if(in==2)begin 53 state <= S3; 54 end 55 end 56 S2: begin 57 if(in==1)begin 58 state <= S3; 59 end 60 else if(in==2)begin 61 state <= S0; 62 out_vld <= 1 ; 63 end 64 end 65 S3: begin 66 if(in==1)