FPGA学习日志——简易状态机simple_fsm

简易状态机simple_fsm

实验目的

实现一个简易状态机,实现一个可乐售卖机,达到三块钱一瓶,实现投入一元硬币实现输出可乐的状态。

实验框图与波形
在这里插入图片描述

状态图

由上图所示的状态图,可以更直观形象地表示出时序电路运行中的全部状态、各状态间相互转换的关系以及转换的条件和结果。图中每一个圆圈都对应着一个状态,圆圈中标出状态名;每个带箭头的方向线都表示一个转换,箭头指示出状态转换的方向。引起该状态转换的输入变量逻辑值标再方向线旁斜线左侧,输出变量的逻辑值标在方向线旁斜线的右侧。

二进制码、格雷码和独热码

格雷码
在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code),另外由于最大数与最小数之间也仅一位数不同,即“首尾相连”,因此又称循环码或反射码。

当状态多时,采用格雷码,介于二进制码与独热码的折中

    parameter   IDLE    =   2'b00;
    parameter   ONE     =   2'b01;
    parameter   TWO     =   2'b11;        

独热码
独热编码即 One-Hot 编码,又称一位有效编码,其方法是使用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候,其中只有一位有效。虽然使用较多的触发器,但由于状态译码简单,可减少组合逻辑且速度较快, 这种编码方式还易于修改,增加状态或改变状态转换条件都可以在不影响状态机的其它部分的情况下很方便地实现。另外,它的速度独立于状态数量。与之相比,压缩状态编码在状态增加时速度会明显下降。

FPGA中组合逻辑资源较少,寄存器资源较多,独热码编码状态机可以在高速下运行

    parameter   IDLE    =   3'b001;
    parameter   ONE     =   3'b010;
    parameter   TWO     =   3'b100;

二进制码

二进制码占用资源刚好与独热码相反,会在高速运行下产生不稳定效果

    parameter   IDLE    =   2'b00;
    parameter   ONE     =   2'b01;
    parameter   TWO     =   2'b10;

​ **二进制编码、格雷码编码使用最少的触发器,消耗较多的组合逻辑,而独热码编码反之。**独热码编码的最大优势在于状态比较时仅仅需要比较一个位,从而一定程度上简化了译码逻辑。虽然在需要表示同样的状态数时,独热编码占用较多的位,也就是消耗较多的触发器,但这些额外触发器占用的面积可与译码电路省下来的面积相抵消。
​ 为了进一步提高独热编码的速度,可以使用并行 CASE语句"即在case(1‘b1) 后添加综合器可以辨认的并行CASE注释语句。注意:并行CASE 只推荐在独热编码时使用,在二进制编码和格雷编码时使用有时反而会增大面积降低速度。
​ 在CPLD中,由于器件拥有较多的地提供组合逻辑资源,所以CPLD多使用二进制编码或格雷码,而FPGA更多地提供触发器资源,所以在FPGA中多使用独热码编码。当然,这并不是说在FPGA中就非得用独热编码,在CPLD中不能用独热编码,一般的,对于小型设计(状态数小于4)使用二进制编码,当状态数处于4-24之间时,宜采用独热码编码,而大型状态机(状态数大于24)使用格雷码更高效。

case语句

第一段描述状态变化第二段赋值

形式:
case(控制表达式/值)
分支表达式:执行语句
default:执行语句
endcase

功能:
自上而下,按照顺序逐个对分支表达式进行判断,如果这一分支表达式等于控制表达式的值,就执行其对应操作;均不相等时,执行default操作;

注意:
分支表达式不能重复,否则会出现冲突;
执行完某一操作后,跳出case语句;
控制表达式与多个分支表达式匹配,只执行从上至下首个匹配项(判断顺序进行,执行一次后就跳出case语句了);

新式二段式,第一段描述状态变化第二段赋值!!!!!!重要语法
always@(posedge sys_clk or negedge sys_rst_n)   
    if(sys_rst_n==1'b0)   
       state<=IDLE;
    else    case(state)
            IDLE:   if(pi_money==1'b1)
                    state<=ONE;
                    else
                    state<=IDLE;
            ONE :   if(pi_money==1'b1)
                    state<=TWO;
                    else
                    state<=ONE;
            TWO :   if(pi_money==1'b1)
                    state<=IDLE;
                    else
                    state<=TWO;
            default state<=IDLE;
            endcase

实验代码

module  simple_fsm
(
    input   wire    sys_clk,
    input   wire    sys_rst_n,
    input   wire    pi_money,
    output  reg    po_cola
);
    parameter   IDLE    =   3'b001;
    parameter   ONE     =   3'b010;
    parameter   TWO     =   3'b100;
    
reg     [2:0]   state;
    
always@(posedge sys_clk or negedge sys_rst_n)   
    if(sys_rst_n==1'b0)   
       state<=IDLE;
    else    case(state)
            IDLE:   if(pi_money==1'b1)
                    state<=ONE;
                    else
                    state<=IDLE;
            ONE :   if(pi_money==1'b1)
                    state<=TWO;
                    else
                    state<=ONE;
            TWO :   if(pi_money==1'b1)
                    state<=IDLE;
                    else
                    state<=TWO;
            default state<=IDLE;
            endcase
always@(posedge sys_clk or negedge sys_rst_n)   
    if(sys_rst_n==1'b0)             
        po_cola<=1'b0;
    else    if((state==TWO)&&(pi_money==1'b1))
            po_cola<=1'b1;
            else    po_cola<=1'b0;
endmodule

仿真代码

`timescale  1ns/1ns
module  tb_simple_fsm();
reg     sys_clk;
reg     sys_rst_n;
reg     pi_money;
wire    po_cola;

initial 
    begin
        sys_clk=1'b0;
        sys_rst_n=1'b0;
        #20
        sys_rst_n=1'b1;
    end
always #10 sys_clk=~sys_clk;

always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n==1'b0)
        pi_money<=1'b0;
    else    pi_money<={$random}%2;//求模取余法

wire    [2:0]   state=simple_fsm_inst.state;
    
initial
    begin
        $timeformat(-9,0,"ns",6);
        $monitor("@time %t:pi_money:%b,state:%b,po_cola:%b",$time,pi_money,state,po_cola);
     
    end
simple_fsm  simple_fsm_inst
(
. sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.pi_money(pi_money),
.po_cola(po_cola)
);
endmodule

对某一模块变量进行监测

对模块内部变量进行检测,采用该语句

wire    [2:0]   state=simple_fsm_inst.state;//simple_fsm_inst中的state通过.连接,这样可以在仿真代码中读取内部变量进行检测
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Chendy_00

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值