一、概述
我们在使用FPGA进行开发的过程当中,实现一个东西用得最多的实现方法就是状态机的实现方法,用一句话总结就是万物皆可状态机,这和我们在学习Linux时常说的在Linux中万物都是文件差不多,这里就主要就是突出状态机的应用范围很广。
二、相关理论
1、概念
2、状态机编码方式
在进行状态机编码时我们一般采用独热码进行编码,独热码想对于自然二进制编码和格雷码编码来说:组合逻辑较少,不易产生毛刺,使用范围广。缺点就是触发器个数较多,(二进制编码毛刺大,格雷码逻辑组合较多)
3、描述方式
在进行代码编写时我们通常采用三段式的编码方式进行编写。
三、代码编写
这里我们就简单使用状态机描述输入多个二进制数,当检测到1011时输出一个标志位的过程。
1、状态转移图
2、设计文件的编写
cpp
module test (
input clk ,
input rst_n ,
input din ,
output reg dout
);
//参数定义
parameter IDLE =5'b00001,//0
S1 =5'b00010,//检测到1
S2 =5'b00100,//检测到10
S3 =5'b01000,//检测到101
S4 =5'b10000;//检测到1011
//内部信号
reg [5:0] state_c ;//现态
reg [5:0] state_n ;//次态
//时序逻辑电路描述状态转移
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
state_c = IDLE;
else
state_c = state_n;
end
//使用组合逻辑描述状态转移条件
always @(*)begin
case (state_c)
IDLE :begin//0
if(din==1)
state_n = S1;
else
state_n = IDLE;
end
S1 :begin//1
if(din==0)
state_n = S2;
else
state_n = S1;
end
S2 :begin//10
if(din==1)
state_n = S3;
else
state_n = IDLE;
end
S3 :begin//101
if(din==1)
state_n = S4;
else
state_n = S2;
end
S4 :begin//1011
state_n = IDLE;
end
default: state_n = IDLE;
endcase
end
//描述输出结果
always @(posedge clk or negedge rst_n)begin
if(!rst_n)
dout<=0;
else if(state_c ==S4)
dout<=1;
else
dout<=0;
end
endmodule
3、测试文件的编写
cpp
//定义时间尺度
`timescale 1ns/1ns
module test_tb ;
//输入信号定义
reg clk ;
reg rst_n;
reg din ;
wire dout ;
//模块例化
test test_inst(
/*input */ .clk (clk ),
/*input */ .rst_n (rst_n),
/*input */ .din (din ),
/*output reg */ .dout (dout )
);
//时钟
parameter CLK_CLY =20;
initial clk=0;
always #(CLK_CLY/2) clk=~clk;
//复位
initial begin
//初始化
rst_n= 1'b0;
#(CLK_CLY*2);
#5;
rst_n=1'b1;
end
//激励
initial begin
din= 1'b0;
#(CLK_CLY*3);
#5;
repeat (30)begin
din= $random;
#(CLK_CLY*1);
end
$stop;
end
endmodule
四、波形仿真
在波形图中我们可以看到当检测到输入的二进制数与状态转移条件就会发生变化,当检测到1011时,输出会产生一个高电平,代表检测到数据。通过总体观察,波形图中状态之间的转移和我们在前面画的状态转移条件一致没说明我们的状态机设置成功。