Verilog手撕代码(4)序列检测


序列检测有两种写法,分别为状态机和移位寄存器,且序列检测也有很多类型,如连续和非连续检测、重叠和非重叠检测、含有无关项检测

连续和不连续序列检测

连续序列检测

检测输入信号a是否满足01110001序列,当信号满足该序列,给出指示信号match

状态机写法

verilog代码:

module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
);

	parameter IDLE = 9'b0_0000_0001,
					s0 = 9'b0_0000_0010,
					s1 = 9'b0_0000_0100,
					s2 = 9'b0_0000_1000,
					s3 = 9'b0_0001_0000,
					s4 = 9'b0_0010_0000,
					s5 = 9'b0_0100_0000,
					s6 = 9'b0_1000_0000,
					s7 = 9'b1_0000_0000;
	reg [8:0]c_state;
	reg [8:0]n_state;
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			c_state <= n_state;
		else
			c_state <= n_state;
	end
	
	always@(*)begin
		case(c_state)
			IDLE:n_state = (a == 1'b0)?s0:IDLE;
			  s0:n_state = (a == 1'b1)?s1:s0;
			  s1:n_state = (a == 1'b1)?s2:s0;
			  s2:n_state = (a == 1'b1)?s3:s0;
			  s3:n_state = (a == 1'b0)?s4:IDLE;
			  s4:n_state = (a == 1'b0)?s5:s1;
			  s5:n_state = (a == 1'b0)?s6:s1;
			  s6:n_state = (a == 1'b1)?s7:s0;
			  s7:n_state = (a == 1'b1)?s2:s0;
			  default:n_state = IDLE;
		endcase
	end
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			match <= 1'b0;
		else	
			match <= (n_state == s7)?1'b1:1'b0;
	end	
endmodule

这里采用的是moore型的三段式状态机写法

仿真时,令输a = 01110001110010,由于这里看做是连续且可重叠的检测,因此,仿真结果应该会检测到联两次

关于重叠和非重叠序列检测,将在下面进行讨论

Testbench;

`timescale 1ns/1ns
module sequence_detect_tb();
	reg clk;
	reg rst_n;
	reg a;
	wire match;
	
	
	sequence_detect u0(
		.clk(clk),
		.rst_n(rst_n),
		.a(a),
		.match(match)
	);
	
	always #10 clk = ~clk;
	
	initial begin
		clk = 0;
		rst_n = 0;
		a = 0;
		#10
		rst_n = 1;
		#40 a = 1;
		#20 a = 1;
		#20 a = 1;
		#20 a = 0;	
		#20 a = 0;
		#20 a = 0;
		#20 a = 1;
		#20 a = 1;
		#20 a = 1;
		#20 a = 0;
		#20 a = 0;
		#20 a = 0;
		#20 a = 1;
		#20 a = 0;
		#200
		$stop;		
		
	end
	//状态机查看器
	reg [31:0]state_cur;
	reg [31:0]state_next;
	
	always@(*)begin
		case(u0.c_state)
			9'b0_0000_0001 : state_cur = "IDLE";
			9'b0_0000_0010 : state_cur = "s0";
			9'b0_0000_0100 : state_cur = "s1";
			9'b0_0000_1000 : state_cur = "s2";
			9'b0_0001_0000 : state_cur = "s3";
			9'b0_0010_0000 : state_cur = "s4";
			9'b0_0100_0000 : state_cur = "s5";
			9'b0_1000_0000 : state_cur = "s6";
			9'b1_0000_0000 : state_cur = "s7";
			default:state_cur = "IDLE";
		endcase
	end
	
	always@(*)begin
		case(u0.n_state)
			9'b0_0000_0001 : state_next = "IDLE";
			9'b0_0000_0010 : state_next = "s0";
			9'b0_0000_0100 : state_next = "s1";
			9'b0_0000_1000 : state_next = "s2";
			9'b0_0001_0000 : state_next = "s3";
			9'b0_0010_0000 : state_next = "s4";
			9'b0_0100_0000 : state_next = "s5";
			9'b0_1000_0000 : state_next = "s6";
			9'b1_0000_0000 : state_next = "s7";
			default:state_cur = "IDLE";
		endcase
	end
endmodule

仿真结果:
在这里插入图片描述
结果match拉高两次,在状态机的第三段的输出是基于n_state(次态)的时序逻辑判断的,因此在检测到01110001后的下一个时钟周期match拉高。

移位寄存器写法

verilog代码:

module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
);
	reg [7:0]a_reg;
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			a_reg <= 8'b0;
		else
			a_reg <= {a_reg[6:0],a};
	end
	
	always@(posedge clk or negedge rst_n)begin
		if(!rst_n)
			match <= 1'b0;
		else
			match <= (a_reg == 8'b0111_0001)?1'b1:1'b0;
	end	
endmodule

Testbench:

`timescale 1ns/1ns
module sequence_detect_tb();
	reg clk;
	reg rst_n;
	reg a;
	wire match;
	
	
	sequence_detect u0(
		.clk(clk),
		.rst_n(rst_n),
		.a(a),
		.match(match)
	);
	
	always #10 clk = ~clk;
	
	initial begin
		clk = 0;
		rst_n = 0;
		a = 0;
		#10
		rst_n = 1;
		#40 a = 1;
		#20 a = 1;
		#20 a = 1;
		#20 a = 0;	
		#20 a = 0;
		#20 a = 0;
		#20 a = 1;
		#20 a = 1;
		#20 a = 1;
		#20 a = 0;
		#20 a = 0;
		#20 a = 0;
		#20 a = 1;
		#20 a = 0;
		#200
		$stop;		
		
	end
endmodule

仿真结果:

在这里插入图片描述
移位寄存器写法与状态机写法仿真结果一致

不连续序列检测

输入信号端口为data,表示数据有效的指示信号端口为data_valid。当data_valid信号为高时,表示此刻的输入信号data有效,参与序列检测;当data_valid为低时,data无效,抛弃该时刻的输入。当输入序列的有效信号满足0110时,拉高序列匹配信号match。

状态机写法

verilog代码:

module sequence_detect_1(
	input clk,
	input rst_n,
	input data,
	input data_valid,
	output  reg match
	);

reg [1:0]c_state,n_state;
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		c_state <= 2'b00;
	else if(data_valid)
		c_state <= n_state;
	else
		c_state <= c_state; 
end
always@(*)begin
	case(c_state)
		2'b00:
		begin
			if(data_valid)
				n_state  = (data == 1'b0)?2'b01:2'b00;
			else 
				n_state = 2'b00;
		end
		2'b01:
		begin
			if(data_valid)
				n_state  = (data == 1'b1)?2'b10:2'b01;
			else 
				n_state = 2'b01;
		end
		2'b10:
		begin
			if(data_valid)
				n_state  = (data == 1'b1)?2'b11:2'b10;
			else 
				n_state = 2'b10;
		end
		2'b11:
		begin
			if(data_valid)
				n_state  = (data == 1'b0)?2'b00:2'b11;
			else 
				n_state = 2'b11;
		end
		default:n_state = 2'b00;
	endcase
end

always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		match <= 1'b0;
	else if((data_valid)&&(c_state == 2'b11))
		match <=1'b1;
	else
		match <= 1'b0;
end
endmodule

quartus综合出的状态转移图:
在这里插入图片描述
Testbench:

`timescale 1ns/1ns
module sequence_detect_1_tb();
	reg clk;
	reg rst_n;
	reg data;
	reg data_valid;
	wire match;
	
	
	sequence_detect_1 u0(
		.clk(clk),
		.rst_n(rst_n),
		.data(data),
		.data_valid(data_valid),
		.match(match)
	);
		
	always #10 clk = ~clk;
	
	initial begin
		clk= 0;
		rst_n = 0;
		data = 0;
		data_valid = 0;
		#20
		rst_n = 1;
		data = 0;
		data_valid = 1;		
		#20
		data = 1;
		#40
		data = 0;
		#20
		data_valid = 0;
		#20
		data = 1;
		#40
		data_valid = 1;
		data = 0;
		#20
		data_valid = 0;
		#20
		data_valid = 1;
		#20
		data = 1;
		#40
		data = 0;
		
		#200
		$stop;
	end	
endmodule

仿真结果:
在这里插入图片描述
因为只有data_valid拉高时,data数据才有效,所以当data为0110且data_valid同时拉高时,match才拉高。

移位寄存器写法
module sequence_detect_1(
	input clk,
	input rst_n,
	input data,
	input data_valid,
	output  reg match
	);
  reg[3:0]data_r;
  always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		data_r <= 4'b0;
	else if(data_valid)
		data_r <= {data_r[2:0],data};
	else 
		data_r <= data_r;
  end
  always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		match <= 1'b0;
	else if(({data_r[2:0],data} == 4'b0110)&&(data_valid == 1'b1))
		match <= 1'b1;
	else
		match <= 1'b0;
  end 
endmodule

Testbench:

`timescale 1ns/1ns
module sequence_detect_1_tb();
	reg clk;
	reg rst_n;
	reg data;
	reg data_valid;
	wire match;
	
	
	sequence_detect_1 u0(
		.clk(clk),
		.rst_n(rst_n),
		.data(data),
		.data_valid(data_valid),
		.match(match)
	);
		
	always #10 clk = ~clk;
	
	initial begin
		clk= 0;
		rst_n = 0;
		data = 0;
		data_valid = 0;
		#20
		rst_n = 1;
		data = 0;
		data_valid = 1;		
		#20
		data = 1;
		#40
		data = 0;
		#20
		data_valid = 0;
		#20
		data = 1;
		#40
		data_valid = 1;
		data = 0;
		#20
		data_valid = 0;
		#20
		data_valid = 1;
		#20
		data = 1;
		#40
		data = 0;
		
		#200
		$stop;
	end	
endmodule

仿真结果:
在这里插入图片描述
移位寄存器写法与状态机写法仿真结果一致

重叠和非重叠序列检测

重叠序列检测

设计一个状态机,用来检测序列 1011,要求:

1、进行重叠检测 即10110111 会被检测通过2次

2、寄存器输出,在序列检测完成下一拍输出检测有效

注意rst为低电平复位

状态机写法
module sequence_test1(
	input wire clk  ,
	input wire rst  ,
	input wire data ,
	output reg flag
);
localparam s0 = 5'b0_0001,
		   s1 = 5'b0_0010,
		   s2 = 5'b0_0100,
		   s3 = 5'b0_1000,
		   s4 = 5'b1_0000;
		  
reg[4:0]c_state,n_state;
always@(posedge clk or negedge rst)begin
	if(!rst)
		c_state <= s0;
	else
		c_state <= n_state;
end
always@(*)begin
	case(c_state)
		s0:n_state = data?s1:s0;
		s1:n_state = data?s1:s2;
		s2:n_state = data?s3:s0;
		s3:n_state = data?s4:s2;
		s4:n_state = data?s1:s2;
		default:n_state = s0;
	endcase
end
always@(posedge clk or negedge rst)begin
	if(!rst)
		flag <= 1'b0;
	else 
		flag <= (c_state == s4)?1'b1:1'b0;
end
endmodule

状态状态转移图;
在这里插入图片描述
Testbench:

`timescale 1ns/1ns
module sequence_test1_tb();
	reg clk;
	reg rst_n;
	reg data;
	wire flag;

	sequence_test1 u0(
		.clk(clk),
		.rst_n(rst_n),
		.data(data),
		.flag(flag)
	
	);
	
	always #10 clk = ~clk;
	
	initial begin
		clk = 0;
		rst_n = 0;
		data = 0;
		#10 rst_n =1;
		#20 data = 1;
		#20 data = 0;
		#20 data = 1;
		#20 data = 1;
		#20 data = 0;
		#20 data = 1;
		#20 data = 1;
		#20 data = 1;
		#20 data = 1;
		#200
		$stop;		
	end
endmodule

仿真结果;
在这里插入图片描述
10110111中进行1011的重叠检测会检测出两次!

非重叠序列检测

设计一个状态机,用来检测序列 10111,要求:

1、进行非重叠检测 即101110111 只会被检测通过一次

2、寄存器输出且同步输出结果

注意rst为低电平复位

verilog代码:

`timescale 1ns/1ns

module sequence_test2(
	input wire clk  ,
	input wire rst  ,
	input wire data ,
	output reg flag
);
//*************code***********//

localparam s0 = 6'b00_0001,
		   s1 = 6'b00_0010,
		   s2 = 6'b00_0100,
		   s3 = 6'b00_1000,
		   s4 = 6'b01_0000,
		   s5 = 6'b10_0000;
reg [5:0]c_state,n_state;
always@(posedge clk or negedge rst)begin
	if(!rst)
		c_state <= s0;
	else 
		c_state <= n_state;
end
always@(*)begin
	case(c_state)
		s0:n_state = data?s1:s0;
		s1:n_state = data?s1:s2;
		s2:n_state = data?s3:s0;
		s3:n_state = data?s4:s2;
		s4:n_state = data?s5:s2;
		s5:n_state = data?s1:s0;
		default:n_state = s0;
	endcase
end

always@(posedge clk or negedge rst)begin
	if(!rst)
		flag <= 1'b0;
	else if(n_state == s5)
		flag <= 1'b1;
	else
		flag <= 1'b0;
end

/*
reg [4:0]data_r;
always@(posedge clk or negedge rst)begin
	if(!rst)
		data_r <= 5'b0;
	else if(!flag)	
		data_r <= {data_r[3:0],data};
	else
		data_r <= 5'b0;
end
always@(posedge clk or negedge rst)begin
	if(!rst)
		flag <= 1'b0;
	else	
		flag <= {data_r[3:0],data} == 5'b10111;
end
*/
//*************code***********//
endmodule

注释部分为移位寄存器写法!

状态转移图:
在这里插入图片描述
Testbench:

`timescale 1ns/1ns
module sequence_test2_tb();
	reg clk;
	reg rst_n;
	reg data;
	wire flag;

	sequence_test2 u0(
		.clk(clk),
		.rst_n(rst_n),
		.data(data),
		.flag(flag)
	
	);
	
	always #10 clk = ~clk;
	
	initial begin
		clk = 0;
		rst_n = 0;
		data = 0;
		#10 rst_n =1;
		#20 data = 1;
		#20 data = 0;
		#20 data = 1;
		#20 data = 1;
		#20 data = 0;
		#20 data = 1;
		#20 data = 1;
		#20 data = 1;
		#20 data = 1;
		#200
		$stop;		
	end
endmodule

状态机写法仿真结果:
在这里插入图片描述
移位寄存器写法仿真结果:
在这里插入图片描述
可以看到两种写法达到的效果一样

更多关于序列的重叠和非重叠检测:序列检测_1011(重叠&不重叠检测)Verilog实现

含有无关项的序列检测

请编写一个序列检测模块,检测输入信号a是否满足011XXX110序列(长度为9位数据,前三位是011,后三位是110,中间三位不做要求),当信号满足该序列,给出指示信号match。

verilog代码:

module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
	);

  
  reg[8:0]a_reg;
  always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		a_reg <= 8'd0;
	else
		a_reg <= {a_reg[7:0],a};
  end
  always@(posedge clk or negedge rst_n)begin
	if(!rst_n)
		match <= 1'b0;
	else if((a_reg[8:6] == 3'b011)&&(a_reg[2:0] == 3'b110))
		match <= 1'b1;
	else 
		match <= 1'b0;
  end
endmodule
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值