序列检测
序列检测主要功能是:将一个指定的序列从数字码流中识别出来,当然也可以实现对指定序列的计数。
序列检测的工具是状态机。
输出只和状态有关,而与输入无关,称为Moore状态机;
输出不仅和状态有关而且和输入有关系,称为Mealy状态机
在进行序列检测之前,需要我们画出状态转换表或者状态转换图。
本次假设我们需要检测 110010
我们画出以下状态表
S0为空闲状态
x为下个输入
这样我们就可以利用状态机写出代码
可看到,我们在最后有个S6的下一个状态没写,S6的下个状态写什么可以实现不一样的功能。
1、S6的所有下个状态(不论输入的是什么)都为S6,则实现的是序列检测,检测到序列就保持当前状态。
2、当在S6的状态下,如果输入0后转到S0,输入1的时候转到S1,那么就可以实现序列多次检测,也就是检测序列的个数。
1、序列检测
Verilog代码
module check_bit(
input clk,
input rst_n,
input din, // 数据输入
output reg [5:0] current_state,
output Y // 是否检测到序列
);
localparam IDLE = 6'b000000;
localparam S1 = 6'b000001;
localparam S11 = 6'b000010;
localparam S110 = 6'b000100;
localparam S1100 = 6'b001000;
localparam S11001 = 6'b010000;
localparam S110010 = 6'b100000;
reg [5:0] next_state;
assign Y = (current_state == S110010);
/******状态转移******/
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
current_state <= IDLE;
else
current_state <= next_state;
end
/******序列检测******/
always@(*) begin
if(!rst_n)
next_state <= IDLE;
else
case(current_state)
IDLE : next_state <= din? S1:IDLE;
S1 : next_state <= din? S11:IDLE;
S11 : next_state <= din? S11:S110;
S110 : next_state <= din? S1:S1100;
S1100 : next_state <= din? S11001:IDLE;
S11001 : next_state <= din? S11:S110010;
S110010 : next_state <= S110010;
//S110010 : next_state <= din?S1:IDLE;
default : next_state <= IDLE;
endcase
end
endmodule
testbench文件
`timescale 1ns/1ns
`define clk_period 20
module check_bit_tb();
reg clk;
reg rst_n;
wire din;
reg [23:0] data;
wire Y;
wire [5:0] state;
assign din = data[23];
check_bit check_bit(
.clk (clk),
.rst_n (rst_n),
.din (din),
.Y (Y),
.current_state (state)
);
initial clk = 1;
always #(`clk_period/2) clk = ~clk;
always @(posedge clk)
data={data[22:0],data[23]};//移位输出码流
initial begin
rst_n = 0;
#20;
rst_n = 1;
#20;
data=20'b1010_1001_1100_1001_0100;//码流数据
#(`clk_period*500)$STOP;//运行500个时钟周期后停止仿真
end
endmodule
由图中可以看到,检测到110010后,Y输出1
2、序列计数
如果需要对序列进行计数,只需要在代码的case中改变S110010的状态转移,变为注释的那一行,并使用计数器计数就行了。
源代码
module check_bit(
input clk,
input rst_n,
input din, // 数据输入
output reg [5:0] current_state,
output reg [7:0] Y_cnt = 0, // 序列计数
output Y // 是否检测到序列
);
localparam IDLE = 6'b000000;
localparam S1 = 6'b000001;
localparam S11 = 6'b000010;
localparam S110 = 6'b000100;
localparam S1100 = 6'b001000;
localparam S11001 = 6'b010000;
localparam S110010 = 6'b100000;
//reg [5:0] current_state;
reg [5:0] next_state;
assign Y = (current_state == S110010);
/******序列计数******/
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
Y_cnt <= 8'd0;
else if(current_state == S110010)
Y_cnt <= Y_cnt + 1'b1;
else
Y_cnt <= Y_cnt;
end
/******状态转移******/
always@(posedge clk or negedge rst_n) begin
if(!rst_n)
current_state <= IDLE;
else
current_state <= next_state;
end
/******序列检测******/
always@(*) begin
if(!rst_n)
next_state <= IDLE;
else
case(current_state)
IDLE : next_state <= din? S1:IDLE;
S1 : next_state <= din? S11:IDLE;
S11 : next_state <= din? S11:S110;
S110 : next_state <= din? S1:S1100;
S1100 : next_state <= din? S11001:IDLE;
S11001 : next_state <= din? S11:S110010;
S110010 : next_state <= din? S1:IDLE;
//S110010 : next_state <= IDLE;
default : next_state <= IDLE;
endcase
end
endmodule
testbench文件
`timescale 1ns/1ns
`define clk_period 20
module check_bit_tb();
reg clk;
reg rst_n;
wire din;
reg [39:0 ]data;
wire Y;
wire [5:0] state;
wire [7:0] Y_cnt;
assign din = data[39];
check_bit check_bit(
.clk (clk),
.rst_n (rst_n),
.din (din),
.Y (Y),
.Y_cnt (Y_cnt),
.current_state (state)
);
initial clk = 1;
always #(`clk_period/2) clk = ~clk;
always @(posedge clk)
//#2 data={data[22:0],data[23]};//移位输出码流
data={data[38:0],data[39]};//移位输出码流
initial begin
rst_n = 0;
#2;
rst_n = 1;
#3;
data=40'b1100_1001_1100_1001_0100_1100_1011_0010_1100_1011;//码流数据
#(`clk_period*40) data = 40'dz;//运行500个时钟周期后停止输入数据
end
endmodule
在tb文件中,输入序列为1100_1001_1100_1001_0100_1100_1011_0010_1100_1011
共有5个序列
在下图中,仿真计数得到的序列也为5个