序列检测有两种写法,分别为状态机和移位寄存器,且序列检测也有很多类型,如连续和非连续检测、重叠和非重叠检测、含有无关项检测
连续和不连续序列检测
连续序列检测
检测输入信号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