September 21, 2016
作者:dengshuai_super
出处:http://blog.csdn.net/dengshuai_super/article/details/52571372
声明:转载请注明作者及出处。
在FPGA里面做有限状态机的原因:因为FPGA都是并行处理的,想要做一些有前后顺序的事件处理的时候,我们就引入这种状态的机制。因此状态机在FPGA里面应用这么广。
在软件里面也是有状态机的思想,但是软件它是一个顺序执行的方法,所以状态机的存在显得不是那么重要了。
有限状态机是由寄存器组和组合逻辑构成的硬件时序电路;
其状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态;
究竟转向哪一状态不但取决于各个输入值,还取决于当前状态。
状态机可用于产生在时钟跳变沿时刻开关的复杂的控制逻辑,是数字逻辑的控制核心。
根据上图代码实现:
//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_lib把cycloneive_atoms.v加到ex_3/sim/altera_lib下,
然后在modelsim的Project标签页下,加入cycloneive_atoms.v
编译
在Library标签页下,右键tb_ex_fsm启动仿真
出现错误:“dffeas …not found…”
然后在QuartusII13.1/quartus/eda/sim_lib把altera_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