FPGA之序列检测的状态机实现

一、序列检测的原理

比如在FPGA和外设进行通讯时,一般会在发送数据之前,提前发送一段序列如1010110,当检测到发送的数据和正确序列一致时,我们就通过FPGA给外部设备发送一个flag标志信号。

二、实现方式-三段式状态机

首先要绘制状态转移图,确定状态个数及状态之间的跳转。状态转移图如下

FPGA之序列检测的状态机实现_第1张图片 序列检测状态转移图

三、代码

1、序列检测verilog源代码

//====================================================================
//						correct continuous number sequence 1010110
//====================================================================

module check_flow(

	input		wire					clk,
	input		wire					rst_n,

	input		wire					flow,
	
	output	reg					flag
);

	localparam		S0	=	7'b000_0001;
	localparam		S1	=	7'b000_0010;
	localparam		S2	=	7'b000_0100;
	localparam		S3	=	7'b000_1000;
	localparam		S4	=	7'b001_0000;
	localparam		S5	=	7'b010_0000;
	localparam		S6	=	7'b100_0000;
	
	reg	[6:0]		c_state;
	reg	[6:0]		n_state;
	
	always @ (posedge clk, negedge rst_n)
		begin
			if (!rst_n)
				c_state <= S0;
			else
				c_state <= n_state;
		end

	always @ (*)
		begin
			if (!rst_n)
				n_state <= S0;
			else
				case (c_state)
					
					S0			:	if (flow)
										n_state <= S1;
									else
										n_state <= S0;
										
					S1			:	if (flow)
										n_state <= S1;
									else
										n_state <= S2;
										
					S2			:	if (flow)
										n_state <= S3;
									else
										n_state <= S0;
										
					S3			:	if (flow)
										n_state <= S3;
									else
										n_state <= S4;
										
					S4			:	if (flow)
										n_state <= S5;
									else
										n_state <= S0;
										
					S5			:	if (flow)
										n_state <= S6;
									else
										n_state <= S4;
										
					S6			:	if (flow)
										n_state <= S1;
									else
										n_state <= S2;
										
					default	:	n_state <= S0;				
				endcase			
		end
		
		always @ (posedge clk, negedge rst_n)
			begin
				if (!rst_n)
					flag <= 1'b0;
				else
					if (c_state == S6 && flow == 0)
						flag <= 1'b1;
					else
						flag <= 1'b0;
			end

endmodule 

2、测试tb文件

`timescale 1ns/1ps 

module check_flow_tb;

	reg					clk;
	reg					rst_n;
	
	reg					flow;
	
	wire					flag;
	
	wire	[6:0]			tb_state;
	reg	[15:0]		ascii_state;
	
	assign tb_state = check_flow_inst.c_state;
	
	check_flow check_flow_inst(

		.clk					(clk	),
		.rst_n				(rst_n),
                         
		.flow					(flow	),
		                   
		.flag					(flag	)
	);

	initial clk = 1;
	always # 10 clk = ~ clk;
	
	initial 
		begin
			rst_n = 0;
			# 201
			rst_n = 1;
			# 20000
			$stop;
		end
	
	initial 
		begin
			forever
				begin
					flow = {$random} % 2;
					@ (posedge clk);
					# 2;
				end
		end

	always @ (*)
		case (tb_state)
			7'b000_0001	:	ascii_state = "S0";
			7'b000_0010	:	ascii_state = "S1";
			7'b000_0100	:	ascii_state = "S2";
			7'b000_1000	:	ascii_state = "S3";
			7'b001_0000	:	ascii_state = "S4";
			7'b010_0000	:	ascii_state = "S5";
			7'b100_0000	:	ascii_state = "S6";
			default		:	ascii_state = "NO";
		endcase		

//=================================================
//		check flow 1010110

	reg	[6:0]		temp;
	reg				tb_flag;
	
	always @ (posedge clk)
		begin
			temp <= {temp[5:0],flow};
		end

	always @ (posedge clk)
		begin
			if (temp == 7'b1010110)
				tb_flag <= 1;
			else
				tb_flag <= 0;
		end
				
endmodule 

测试文件特别关注flow的生成和如何在tb里检测生成正确序列,就是最后单独写的两个always 语句。

三、Modelsim仿真波形

FPGA之序列检测的状态机实现_第2张图片序列检测仿真波形

四、总结

难点在于状态之间的跳转,重点学习测试文件tb的编写

你可能感兴趣的:(FPGA入门基础)