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应用程序的“流程图”功能:
======================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================== --- 名称 : 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 仿真