本专题共六道题,基本把牛客网序列检测的题型都覆盖到了。
序列检测主要分为两类:
1)连续序列的检测;
2)定长序列或不连续序列的检测。
连续序列的检测:
连续序列的检测首先要定义两个reg类型变量cs(current state)和ns(next state),再定义n个parameter(n = 待检测序列的位数 + 1);step one:定义复位状态(cs <= IDLE;)和正常状态(cs <= ns;);step two:case块通过cs状态决定ns状态;step three:输出match。
VL25 输入序列连续的序列检测
请编写一个序列检测模块,检测输入信号a是否满足01110001序列,当信号满足该序列,给出指示信号match。模块的接口信号图如下:
请使用Verilog HDL实现以上功能,并编写testbench验证模块的功能。
输入描述:
clk:系统时钟信号
rst_n:异步复位信号,低电平有效
a:单比特信号,待检测的数据
输出描述:
match:当输入信号a满足目标序列,该信号为1,其余时刻该信号为0
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input a,
output reg match
);
reg [8:0] cs;
reg [8:0] ns;
parameter IDLE = 9'b000000001;
parameter S0 = 9'b000000010;
parameter S1 = 9'b000000100;
parameter S2 = 9'b000001000;
parameter S3 = 9'b000010000;
parameter S4 = 9'b000100000;
parameter S5 = 9'b001000000;
parameter S6 = 9'b010000000;
parameter S7 = 9'b100000000;
//one step
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
cs <= IDLE;
end
else begin
cs <= ns;
end
end
//two step
always @ (*) begin
case( cs )
IDLE : ns = (a == 1'b0) ? S0 : IDLE;
S0 : ns = (a == 1'b1) ? S1 : S0;
S1 : ns = (a == 1'b1) ? S2 : S0;
S2 : ns = (a == 1'b1) ? S3 : S0;
S3 : ns = (a == 1'b0) ? S4 : IDLE;
S4 : ns = (a == 1'b0) ? S5 : S1;
S5 : ns = (a == 1'b0) ? S6 : S1;
S6 : ns = (a == 1'b1) ? S7 : S0;
S7 : ns = (a == 1'b1) ? IDLE : S0;
default : ns = IDLE;
endcase
end
wire match_tmp;
assign match_tmp = (cs == S7);
//three step
always @ (posedge clk or negedge rst_n) begin
if(~rst_n) begin
match <= 1'b0;
end
else begin
match <= match_tmp;
end
end
endmodule
注:step two部分是否需要变量match_tmp由波形图决定,变量match_tmp作用是拿到输出信号延迟一个clk上升沿给match(见波形图)。
注意assign match_tmp = (cs == S7);这里满足cs == S7是在序列的最后一个数字的下一周期,此时match_tmp为1,但match的赋值要等待上升沿来临,所以下一个周期match拉高,如波形所示。
VL26 含有无关项的序列检测
请编写一个序列检测模块,检测输入信号a是否满足011XXX110序列(长度为9位数据,前三位是011,后三位是110,中间三位不做要求),当信号满足该序列,给出指示信号match。程序的接口信号图如下:
程序的功能时序图如下:
请使用Verilog HDL实现以上功能,并编写testbench验证模块的功能。 要求代码简洁,功能完整。
输入描述:
clk:系统时钟信号
rst_n:异步复位信号,低电平有效
a:单比特信号,待检测的数据
输出描述:
match:当输入信号a满足目标序列,该信号为1,其余时刻该信号为0
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input a,
output reg match
);
parameter IDLE = 10'b0000000001;
parameter S0 = 10'b0000000010;
parameter S1 = 10'b0000000100;
parameter S2 = 10'b0000001000;
parameter S3 = 10'b0000010000;
parameter S4 = 10'b0000100000;
parameter S5 = 10'b0001000000;
parameter S6 = 10'b0010000000;
parameter S7 = 10'b0100000000;
parameter S8 = 10'b1000000000;
reg [9:0] cs, ns;
// one step
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
cs <= IDLE;
end
else begin
cs <= ns;
end
end
// two step
always @ (*)
begin
case(cs)
IDLE : ns = (a == 1'b0) ? S0 : IDLE;
S0 : ns = (a == 1'b1) ? S1 : S0;
S1 : ns = (a == 1'b1) ? S2 : S0;
S2 : ns = (a == 1'b1 | a == 1'b0) ? S3 : S0;
S3 : ns = (a == 1'b1 | a == 1'b0) ? S4 : S0;
S4 : ns = (a == 1'b1 | a == 1'b0) ? S5 : S0;
S5 : ns = (a == 1'b1) ? S6 : S0;
S6 : ns = (a == 1'b1) ? S7 : S0;
S7 : ns = (a == 1'b0) ? S8 : S0;
S8 : ns = (a == 1'b0) ? IDLE : S0;
default : ns = IDLE;
endcase
end
wire match_tmp;
assign match_tmp = (cs == S8);
// three step
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
match <= 1'b0;
end
else begin
match <= match_tmp;
end
end
endmodule
本题与上题区别仅在于中间三位数为0或1都可使状态继续向下转移,所以代码层面仅在step two有所 改动。
VL35 状态机-非重叠的序列检测
设计一个状态机,用来检测序列 10111,要求:
1、进行非重叠检测 即101110111 只会被检测通过一次
2、寄存器输出且同步输出结果
注意rst为低电平复位
信号示意图:
波形示意图:
输入描述:
输入信号 clk rst data
类型 wire
输出描述:
输出信号 flag
类型 reg
`timescale 1ns/1ns
module sequence_test1(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
parameter IDLE = 6'b000001;
parameter S0 = 6'b000010;
parameter S1 = 6'b000100;
parameter S2 = 6'b001000;
parameter S3 = 6'b010001;
parameter S4 = 6'b100000;
reg [5:0] cs;
reg [5:0] ns;
//step one
always @ (posedge clk or negedge rst) begin
if(~rst) begin
cs <= IDLE;
end
else begin
cs <= ns;
end
end
//step two
always @ (*) begin
case(cs)
IDLE : ns = (data == 1'b1) ? S0 : IDLE;
S0 : ns = (data == 1'b0) ? S1 : S0;
S1 : ns = (data == 1'b1) ? S2 : IDLE;
S2 : ns = (data == 1'b1) ? S3 : S1;
S3 : ns = (data == 1'b1) ? S4 : S1;
S4 : ns = (data == 1'b1) ? S0 : IDLE;
default : ns = IDLE;
endcase
end
//step three
always @ (posedge clk or negedge rst) begin
if(~rst) begin
flag <= 1'b0;
end
else begin
if(ns == S4) begin
flag <= 1'b1;
end
else begin
flag <= 1'b0;
end
end
end
endmodule
本题是非重叠的序列检测:检测序列 10111,101110111 只会被检测通过一次。重点在于case块中最后一句ns的状态决定,满足10111后要从头开始,而不是接着前一序列的最后一个数1继续。
注:此题序列满足要求后下一周期match立即拉高,所以不需要match_tmp变量,if(ns == S4)条件在序列的最后一个数字所在周期满足,match等待上升沿来临后恰好在下一周期拉高。
VL36 重叠序列检测
设计一个状态机,用来检测序列 1011,要求:
1、进行重叠检测 即10110111 会被检测通过2次
2、寄存器输出,在序列检测完成下一拍输出检测有效
注意rst为低电平复位
信号示意图:
波形示意图:
输入描述:
输入信号 clk rst data
类型 wire
输出描述:
输出信号 flag
类型 reg
`timescale 1ns/1ns
module sequence_test2(
input wire clk ,
input wire rst ,
input wire data ,
output reg flag
);
reg [4:0] cs;
reg [4:0] ns;
parameter IDLE = 5'b00001;
parameter S0 = 5'b00010;
parameter S1 = 5'b00100;
parameter S2 = 5'b01000;
parameter S3 = 5'b10000;
always @ (posedge clk or negedge rst) begin
if(~rst) begin
cs <= IDLE;
end
else begin
cs <= ns;
end
end
always @ (*) begin
case(cs)
IDLE : ns =(data == 1'b1) ? S0 : IDLE;
S0 : ns =(data == 1'b0) ? S1 : S0;
S1 : ns =(data == 1'b1) ? S2 : IDLE;
S2 : ns =(data == 1'b1) ? S3 : S1;
S3 : ns =(data == 1'b1) ? IDLE : S1;
default : ns = IDLE;
endcase
end
wire flag_tmp;
assign flag_tmp = (cs==S3);
always @ (posedge clk or negedge rst) begin
if(~rst) begin
flag <= 1'b0;
end
else begin
flag <= flag_tmp;
end
end
endmodule
本题为重叠检测:即检测序列 1011,10110111会被检测通过2次。case块中满足1011后下一个数若为0则直接跳到S1。