Verilog语法_3(同步有限状态机)

September 21, 2016
作者:dengshuai_super
出处:http://blog.csdn.net/dengshuai_super/article/details/52571372
声明:转载请注明作者及出处。


同步有限状态机的设计

1. 什么是有限状态机(FSM)

在FPGA里面做有限状态机的原因:因为FPGA都是并行处理的,想要做一些有前后顺序的事件处理的时候,我们就引入这种状态的机制。因此状态机在FPGA里面应用这么广。
在软件里面也是有状态机的思想,但是软件它是一个顺序执行的方法,所以状态机的存在显得不是那么重要了。

有限状态机是由寄存器组和组合逻辑构成的硬件时序电路;
其状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态;
究竟转向哪一状态不但取决于各个输入值,还取决于当前状态。
状态机可用于产生在时钟跳变沿时刻开关的复杂的控制逻辑,是数字逻辑的控制核心。


2. FSM的种类和不同点

Mealy状态机:
Verilog语法_3(同步有限状态机)_第1张图片

带流水线输出的Mealy状态机:
Verilog语法_3(同步有限状态机)_第2张图片


有限状态机框图如下:
Verilog语法_3(同步有限状态机)_第3张图片
Verilog语法_3(同步有限状态机)_第4张图片


3. 设计举例

Verilog语法_3(同步有限状态机)_第5张图片

根据上图代码实现:

//ex_fsm.v
module ex_fsm(
                input wire   sclk,
                input wire   rst_n,
                output reg   k1,//输出的时候可以作为寄存器,它相当于把输出寄存器的
                output reg   k2,//Q端直接连接到输出口了,就把中间那根线给省略了
                input  wire  A//状态
);
parameter    IDLE   =  4'b0001;//4'h1十六进制,状态少的时候最好显示的写出状态表达式
parameter    START  =  4'b0010;
parameter    STOP   =  4'b0100;
parameter    CLEAR  =  4'b1000;

//reg  [1:0] state;
//2'b00 2'b01 2'b10 2'b11,二进制编码的时候用的寄存器数量少,但是用的组合逻辑资源较多
//if(state == 2'b11)比较器是2比特的

reg [3:0]  state;
//4'b0001 4'b0010 4'b0100 4'b1000 独热码占用寄存器数量多,但是组合逻辑资源消耗较少
//if(state == 4'b0001)---->if(state[0]==1'b1)综合后把4比特的比较器优化成1比特的比较器,所以占用的组合逻辑资源较少
//对于二进制编码(多个比特表示一个状态),比特线有可能不一样长,导致延迟,出现中间状态,本来应该是111,可能中间状态是110等,(两边交错不稳定,使得数据存在不稳定区)因此在跑高速的时候可能出现数据采样窗变小,使得建立时间、保持时间的余量减少
//而独热码就不会出现这个问题,因为它用一个比特表示一个状态,从出发到结束就是一根线,不会出现中间状态,可以跑高速。

//两段式描述状态机
//第一段描述状态机,(状态机是时序逻辑)
always @(posedge sclk or negedge rst_n)//只对状态进行处理,不会写入其他变量赋值
                if(rst_n == 1'b0)
                        state<=IDLE;//非阻塞赋值
                else 
                        case(state)
                                    IDLE:if(A==1'b1)    
                                                    state <=START;//时序电路,不加else自动保持原状态,因此可以不写
                                             //else
                                                    //state <=state;
                                    START:if(A==1'b0)
                                                    state <= STOP;//复位的时候回到IDLE,最上边的if那有相关代码
                                    STOP:if(A==1'b1)
                                                    state <= CLEAR;
                                  CLEAR:if(A==1'b0)
                                          state <= IDLE;
                                  default:state <= IDLE;
                        endcase

//控制变量输出
always @(posedge sclk or negedge rst_n)
                if(rst_n == 1'b0)
                                k1 <= 1'b0;
              else if(state == IDLE && A == 1'b1)
                            k1 <= 1'b0;
              else if(state == CLEAR && A == 1'b0)
                            k1 <= 1'b1;

always @(posedge sclk or negedge rst_n)
                if(rst_n == 1'b0)
                                k2 <= 1'b0;
                else if(state ==STOP && A == 1'b1)
                                k2 <= 1'b1;
                else if(state ==CLEAR && A == 1'b0)
                                k2 <= 1'b0;


endmodule
//tb_ex3_fsm.v
`timescale 1ns/1ns
module tb_ex3_fsm;
reg sclk,rst_n;
reg in_A;
wire k1,k2;
initial begin
                sclk <= 0;
                rst_n <= 0;
                #100;
                rst_n <=1;
end

initial begin
                #200;
                in_data();              
end


always #10 sclk <=~sclk;

ex_fsm ex_fsm_inst(
                .sclk         (sclk),
                .rst_n        (rst_n),
                .k1           (k1),//k1我上边没声明,但是综合的时候自动声明一个wire变量,不推荐
                .k2           (k2),//k1,k2是输出,芯片画PCB时,输出的管脚都用线连
                .A            (in_A)//状态
);

task in_data();
            integer i;
      begin
            for(i=0;i<1024;i=i+1)
            begin
                    @(posedge sclk);
                    if(i<50)
                            in_A<=0;
                    else if(i<200)
                            in_A<=1;
                    else if(i<700)
                            in_A<=0;
                    else if(i<800)
                            in_A<=1;
                    else if(i<900)
                            in_A<=0;                
            end
      end
endtask
endmodule

在Quartus II里面进行仿真设置后,点击EDA Netlist Writer后
在ex3/quartus_prj 里面多了一个Simulation文件夹,文件夹下有modelsim文件夹
该文件夹下有:
ex_fsm.sft
ex_fsm.vo//标准网标
ex_fsm_7_1200mv_125c_slow.vo//”125”指的是125度,分析建立时间,因为只有在信号传输地太慢了
ex_fsm_7_1200mv_125c_slow.sdo//,路径延时太大了的时候,才会建立时间的违例
ex_fsm_min_1200mv_-40c_fast.vo//用于建立时间的检查,数据传输的太快,使得数据太快的到达
ex_fsm_min_1200mv_-40c_v_fast.sdo//当上升沿之后,数据很快的结束了,没有办法保持住,因此用它来检查保持时间
ex_fsm_modelsim.xrf
ex_fsm_v.sdo//标准延时文件

//ex_fsm.vo里面调用了ex_fsm_v.sdo文件(initial $sdf_annotate(“ex_fsm_sdo”);)
//将ex_fsm_v.sdo放到ex_3/sim下(.sdo文件一定放到根目录,要不然找不到,就没有延时信息)
//将ex_fsm.vo放到ex_3/design
//仿真的时候,ex_fsm.vo里面调用了Altera FPGA里面的东西。因此需要加进来一些库文件。
//库文件在哪里找:打开Quartus II安装目录下:QuartusII13.1/quartus/eda/sim_lib下把alter_mf.v拷贝到ex_3/sim目录下的新建的文件夹altera_lib下。
打开modelsim,在Project标签页下把ex_fsm.v移除,加入ex_3/design/ex_fsm.vo文件
再加一个库文件ex_3/sim/altera_lib/altera_mf.v
共三个文件:altera_mf.v,ex_fsm.vo,tb_ex_fsm.v
修改编译顺序:compile—>compile order—>altera_mf.v(调到第一个)
出现错误是因为刚才把ex_3/sim/work(库) 删了
因此新建一个库,在最下方输入命令:
vilb work

在Library 标签页下,找到tb_ex_fsm—>右键Simulate without Optimization启动
有错误,需要加其它组件(cycloneive_io_obuf … not found…)
QuartusII13.1/quartus/eda/sim_libcycloneive_atoms.v加到ex_3/sim/altera_lib下,
然后在modelsim的Project标签页下,加入cycloneive_atoms.v
编译
在Library标签页下,右键tb_ex_fsm启动仿真
出现错误:“dffeas …not found…”
然后在QuartusII13.1/quartus/eda/sim_libaltera_primitives.v(原语)按同样方式加入到ex_3/sim/altera_lib下,然后在modelsim的Project标签页下,加入altera_primitives.v
编译,成功。
发现寄存的信号和时钟不同不了,事件都有延时了。(后仿里面的东西)

练习:检测10010这个序列作为练习,画出状态迁移图。


来源:
https://ke.qq.com/user/index/index.html#cid=66019&term_id=100056181

你可能感兴趣的:(FPGA)