功能描述:
序列检测器就是将一个指定序列从数字码流中识别出来。本例中将设计一个“10010”序列的检测器。设X为数字码流的输入,Z为检测出标记输出,高电平表示发现指定的序列10010.考虑码流为110010010000100101....则,如表有:

用FSM实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 |
moduleseqdet
(
inputwirex,
inputwireclk,
inputwirerst,
outputwirez
);
reg[2:0] state;
localparam IDLE = 3'd0,
A = 3'd1,
B = 3'd2,
C = 3'd3,
D = 3'd4,
E = 3'd5,
F = 3'd6,
G = 3'd7;
assignz = (state == D && x==0)?1'b1:1'b0;//状态为D时又收到输入0,表明10010已经收到,输出为1
always@ (posedgeclk,negedgerst)
if(!rst)
begin
state <= IDLE;
end
else
casex(state)
IDLE:
if(x==1)
state <= A; //状态A记住第一位正确高电平1来过
else
state <= IDLE;
A:
if(x==0)
state <= B; //状态B记住第二位正确低电平0来过
else
state <= A;
B:
if(x==0)
state <= C; //状态C记住第三位正确低电平0来过
else
state <= F; //输入高电平,不符合要求,F记住只有1位对过
C:
if(x==1)
state <= D; //状态D记住第四位正确高电平1来过
else
state <= G; //输入低电平,不符合要求,G记住没有1为曾经对过
D:
if(x==0)
state <= E; //状态E记住第五位正确低电平0来过
else
state <= A;
E:
if(x==0)
state <= C; //用状态记住100正确来过
else
state <= A;
F:
if(x==1)
state <= A;
else
state <= B;
G:
if(x==1)
state <= F;
else
state <= B;
default:
state <=IDLE;
endcase
endmodule |
测试文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 |
`timescale1ns/1ns
moduleseqdet_tb;
localparamT =20;
regclk,rst;
reg[23:0] data;
wirez,x;
assignx = 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@ (posedgeclk)
#2 data = {data[22:0],data[23]};
seqdet U1
(
.x(x),
.z(z),
.clk(clk),
.rst(rst)
);
endmodule |

用移位寄存器实现检测
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 |
moduleseqdet
(
inputwirex,
inputwireclk,
inputwirerst,
outputwirez,
outputreg[4:0] q
);
//reg [4:0] q;
assignz = (q == 5'b10010) ? 1'b1:1'b0;
always@ (posedgeclk,negedgerst)
if(!rst)
q <= 5'd0;
else
q <= {q[3:0],x};
endmodule |
RTL级视图:

测试文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 |
`timescale1ns/1ns
moduleseqdet_tb;
localparamT =20;
regclk,rst;
reg[23:0] data;
wirez,x;
wire[4:0] q;
assignx = 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@ (posedgeclk)
#2 data = {data[22:0],data[23]};
seqdet U1
(
.x(x),
.z(z),
.clk(clk),
.q(q),
.rst(rst)
);
endmodule |
仿真结果:

NOTE:
由于移位寄存器的赋值是在always块中,故而相对实际延迟了一个clk.
由上面的方针结果可知,输出z相对x晚了一个时钟周期,因为由于移位寄存器的赋值是在always块中,故而相对实际延迟了一个clk.
代码修改如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 |
moduleseqdet
(
inputwirex,
inputwireclk,
inputwirerst,
outputwirez,
outputreg[4:0] q
);
wire[4:0] q_next;
assignq_next ={q[3:0],x};
assignz = (q_next== 5'b10010) ? 1'b1:1'b0;
always@ (posedgeclk,negedgerst)
if(!rst)
q <= 5'd0;
else
q <= q_next;
endmodule |

状态机修改:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 |
moduleseqdet
(
inputwirex,
inputwireclk,
inputwirerst_n,
outputwirez
);
//用verilog设计一个 10010 序列的检测器
reg[4:0] cs,ns;
localparam[4:0] IDLE =5'd0,
A =5'd1,
B =5'd2,
C =5'd3,
D =5'd4,
E =5'd5;
//状态转移
always@ (posedgeclk,negedgerst_n)
if(!rst_n)
cs <= IDLE;
else
cs <= ns;
//组合逻辑,产生下一状态译码逻辑
always@ (*)
begin
ns = 5'bx;
case(cs)
IDLE:
begin
if(x==1)
ns = A;
else
ns = IDLE;
end
A:
begin
if(x==0)
ns = B;
else
ns = A;
end
B:
begin
if(x==0)
ns = C;
else
ns = A;
end
C:
begin
if(x==1)
ns = D;
else
ns = IDLE;
end
D:
begin
if(x==0)
ns = E;
else
ns = A;
end
E:
begin
if(x==0)
ns = C;
else
ns = A;
end
default:
ns = IDLE;
endcase
end
//状态寄存输出
/*
always @ (posedge clk,negedge rst_n)
begin
if(!rst_n)
z <= 1'b0;
else
begin
case(ns)
IDLE,A,B,C,D: z <= 1'b0;
E : z <= 1'b1;
default: z <= 1'b0;
endcase
end
end
*/
//状态为D时又收到输入0,表明10010已经收到,输出为1
//assign z = (cs == D && x==0)?1'b1:1'b0;
assignz = (ns==E);
endmodule | |
|