轉自:https://www.cnblogs.com/qiweiwang/archive/2011/04/18/2019952.html
Verilog --序列檢測器(采用移位寄存器實現)
序列檢測器就是將一個指定序列從數字碼流中識別出來。本例中將設計一個“10010”序列的檢測器。設X為數字碼流的輸入,Z為檢測出標記輸出,高電平表示發現指定的序列10010.考慮碼流為110010010000100101
之前序列檢測器看到的都是采用狀態機實現,直到偶然看到
https://www.cnblogs.com/qiweiwang/archive/2011/04/18/2019952.html
這篇博客,才發現原來使用移位寄存器可以如此簡單,原理圖如下:

基本思路就是利用移位寄存器作為檢測窗口,每進來一個數就跟目標序列進行比較,簡單粗暴。
下面貼一下原帖的代碼:
module seqdet
(
input wire x,
input wire clk,
input wire rst,
output wire z,
output reg [4:0] q
);
//reg [4:0] q;
assign z = (q == 5'b10010) ? 1'b1:1'b0;
always @ (posedge clk,negedge rst)
if(!rst)
q <= 5'd0;
else
q <= {q[3:0],x};
endmodule
testbench:
`timescale 1ns/1ns
module seqdet_tb;
localparam T =20;
reg clk,rst;
reg [23:0] data;
wire z,x;
wire [4:0] q;
assign x = data[23];
initial
begin
clk =0;
rst =1;
#2 rst =0;
#30 rst =1;
data =20'b1100_1001_0000_1001_0100;
#(T*1000) $stop;
end
always #T clk = ~clk;
always @ (posedge clk)
#2 data = {data[22:0],data[23]};
seqdet U1
(
.x(x),
.z(z),
.clk(clk),
.q(q),
.rst(rst)
);
endmodule

由於移位寄存器的賦值是在always塊中,故而相對實際延遲了一個clk.由上面的方針結果可知,輸出z相對x晚了一個時鍾周期,因為由於移位寄存器的賦值是在always塊中,故而相對實際延遲了一個clk.
Note:
- 跟用狀態機實現的區別在於,使用移位寄存器需要存儲所有的碼字,因此如果序列長度為N,則該方法需要消耗的寄存器就是N個。而使用狀態機實現時,每個狀態代表部分碼字,如果使用十進制編碼,則只需要使用log2(N)個寄存器即可編碼所有狀態,從寄存器資源的角度來看FSM實現起來代價較小。
- 此外,寄存器版本每來一個碼元都要比較所有碼字,因此需要消耗N個比較器,而FSM的的狀態寄存器每一位在狀態轉移時都需要不同的譯碼邏輯,如果狀態轉移比較簡單,組合邏輯可能會比移位寄存器少,狀態轉移復雜的化就不好說了。
- 當然,移位寄存器的版本編碼更加簡潔明了。