序列检测器是时序数字电路中非常常见的设计之一。它的主要功能是将一个指定的序列从数字码流中识别出来。这里给出一个“1101”序列检测器的Verilog实现和Testbench代码。
★设计目标:“1101”序列检测器
★EDA:Quartus 15.0
★仿真软件:Modelsim 10.1c
本序列检测器共有4个bit位,每个bit占用一个状态,再加上结束状态,故使用格雷码定义5个状态:
// 序列检测器 状态编码(格雷码)
localparam SEQ_IDLE = 3'b000;
localparam SEQ_STATE1 = 3'b001;
localparam SEQ_STATE2 = 3'b011;
localparam SEQ_STATE3 = 3'b010;
localparam SEQ_STOP = 3'b110;
采用一段式状态机,状态转移图如下:
SEQ_IDLE:检测bit流中是否出现 “1” ,出现则跳转到下一状态。
SEQ_STATE1:检测bit流中是否出现 “1” ,出现则跳转到下一状态,若出现 "0" 则跳转回 SEQ_IDLE 重新等待第一个 “1” bit位。
SEQ_STATE2:检测bit流中是否出现 “0” ,出现则跳转到下一状态,若出现 "1" 则跳转回 SEQ_IDLE 重新等待第一个 “1” bit位。
SEQ_STATE3:检测bit流中是否出现 “1” ,出现则跳转到下一状态,若出现 "0" 则跳转回 SEQ_IDLE 重新等待第一个 “1” bit位,并同时拉高输出标志位。
SEQ_STOP:拉低输出标志位,同时跳转回 SEQ_IDLE 开始下一轮检测。
“1101”序列检测器完整Verilog代码如下:
module seq_detector(
// 输入端口
input clk100M, // 输入时钟:100MHz
input rst_n, // 异步复位:低电平复位
input data_in, // 输入串行数据
// 输出端口
output reg data_out // 输出标志
);
// 序列检测器 状态编码(格雷码)
localparam SEQ_IDLE = 3'b000;
localparam SEQ_STATE1 = 3'b001;
localparam SEQ_STATE2 = 3'b011;
localparam SEQ_STATE3 = 3'b010;
localparam SEQ_STOP = 3'b110;
reg[2:0] seq_state; // 状态寄存器
// 序列检测器 一段式状态机
always@(posedge clk100M or negedge rst_n)begin
if(!rst_n)begin
data_out <= 1'b0;
seq_state <= SEQ_IDLE;
end
else begin
case(seq_state)
// IDLE 检测bit1
SEQ_IDLE: begin
data_out <= 1'b0;
if(data_in)
seq_state <= SEQ_STATE1;
else
seq_state <= SEQ_IDLE;
end
// 检测bit2
SEQ_STATE1: begin
if(data_in)
seq_state <= SEQ_STATE2;
else
seq_state <= SEQ_IDLE;
end
// 检测bit3
SEQ_STATE2: begin
if(~data_in)
seq_state <= SEQ_STATE3;
else
seq_state <= SEQ_IDLE;
end
// 检测bit4
SEQ_STATE3: begin
if(data_in)begin
seq_state <= SEQ_STOP;
data_out <= 1'b1;
end
else
seq_state <= SEQ_IDLE;
end
// STOP
SEQ_STOP: begin
seq_state <= SEQ_IDLE;
data_out <= 1'b0;
end
endcase
end
end
endmodule
Testbench代码如下:
`timescale 1ns/1ps
module seq_detector_tb;
reg clk100M;
reg rst_n;
reg[15:0] data;
wire data_in;
wire data_out;
// 信号初始化
initial begin
clk100M = 0;
rst_n = 1;
#10 rst_n = 0;
#10 rst_n = 1;
// 生成序列
data = 15'b1101_0010_1101_1001;
end
// 生成100MHz时钟
always
#5 clk100M = ~clk100M;
// 序列在下降沿移位,在相邻的上升沿采样
always@(negedge clk100M)
data = { data[14:0] , data[15] };
// 串行输出
assign data_in = data[15];
// RTL例化
seq_detector seq_detector_inst(
.clk100M(clk100M),
.rst_n(rst_n),
.data_in(data_in),
.data_out(data_out)
);
endmodule
testbench中使用16位环形移位寄存器将既定的4组4bit序列从MSB开始,依次一位一位地从 data 移出到 data_in 上并循环输出,若检测到序列 “1101“ 则将data_out拉高一个时钟周期。