序列检测器是时序数字电路中非常常见的设计之一。它的主要功能是将一个指定的序列从数字码流中识别出来。这里给出一个“1101”序列检测器的Verilog实现和Testbench代码。
★设计目标:“1101”序列检测器
★EDA:Quartus 15.0
★仿真软件:Modelsim 10.1c
本序列检测器共有4个bit位,每个bit占用一个状态,再加上开始和结束状态,故使用格雷码定义6个状态:
// 序列检测器 状态编码(格雷码)
localparam SEQ_IDLE = 3'b000;
localparam SEQ_STATE1 = 3'b001;
localparam SEQ_STATE2 = 3'b011;
localparam SEQ_STATE3 = 3'b010;
localparam SEQ_STATE4 = 3'b110;
localparam SEQ_STOP = 3'b111;
采用一段式状态机,状态转移图如下:
SEQ_IDLE:检测bit流中是否出现 “1” ,出现则跳转到下一状态。
SEQ_STATE1:检测bit流中是否出现 “1” ,出现则跳转到下一状态,若出现 "0" 则跳转回 SEQ_IDLE 重新等待第一个 “1” bit位。
SEQ_STATE2:检测bit流中是否出现 “1” ,出现则跳转到下一状态,若出现 "0" 则跳转回 SEQ_IDLE 重新等待第一个 “1” bit位。
SEQ_STATE3:检测bit流中是否出现 “0” ,出现则跳转到下一状态,若出现 "1" 则跳转回 SEQ_IDLE 重新等待第一个 “1” bit位。
SEQ_STATE4:检测bit流中是否出现 “1” ,出现则跳转到下一状态,若出现 "0" 则跳转回 SEQ_IDLE 重新等待第一个 “1” bit位, 同时拉高输出标志位 。
SEQ_STOP:拉低输出标志位,同时跳转回 SEQ_IDLE 开始下一轮检测。
“1101”序列检测器完整Verilog代码如下:
module seq_detector(
// 输入端口input clk100M, // 输入时钟:100MHzinput 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_STATE4 = 3'b110;
localparam SEQ_STOP = 3'b111;reg[2:0] seq_state; // 状态寄存器// 序列检测器 一段式状态机
always@(posedge clk100M or negedge rst_n)beginif(!rst_n)begindata_out <= 1'b0;seq_state <= SEQ_IDLE;endelse begincase(seq_state)// IDLESEQ_IDLE: begindata_out <= 1'b0;if(data_in)seq_state <= SEQ_STATE1;elseseq_state <= SEQ_IDLE;end// 检测bit1SEQ_STATE1: beginif(data_in)seq_state <= SEQ_STATE2;elseseq_state <= SEQ_IDLE;end// 检测bit2SEQ_STATE2: beginif(~data_in)seq_state <= SEQ_STATE3;elseseq_state <= SEQ_IDLE;end// 检测bit3SEQ_STATE3: beginif(data_in)seq_state <= SEQ_STATE4;elseseq_state <= SEQ_IDLE;end// 检测bit4SEQ_STATE4: beginif(data_in)beginseq_state <= SEQ_STOP;data_out <= 1'b1;endelseseq_state <= SEQ_IDLE;end// STOPSEQ_STOP: beginseq_state <= SEQ_IDLE;data_out <= 1'b0;endendcaseend
endendmodule
Testbench代码如下:
`timescale 1ns/1ps
module seq_detector_tb;reg clk100M;
reg rst_n;
reg[15:0] data;
wire data_in;
wire data_out;// 信号初始化
initial beginclk100M = 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拉高一个时钟周期。