【FPGA学习笔记】VL28 输入序列不连续的序列检测
题目描述:
请编写一个序列检测模块,输入信号端口为data,表示数据有效的指示信号端口为data_valid。当data_valid信号为高时,表示此刻的输入信号data有效,参与序列检测;当data_valid为低时,data无效,抛弃该时刻的输入。当输入序列的有效信号满足0110时,拉高序列匹配信号match。
模块的接口信号图如下:
clk:系统时钟信号
rst_n:异步复位信号,低电平有效
data:单比特信号,待检测的数据
data_valid:输入信号有效标志,当该信号为1时,表示输入信号有效
输出描述:
match:当输入信号data满足目标序列,该信号为1,其余时刻该信号为0。
对于序列检测题目,常规的解法有两种:状态机法和序列缓存对比法。
状态机法的过程类似于题意理解中提到的过程:在初始状态中,在data_valid有效时逐一判断当前时刻的数值。先判断第一位是否符合,若符合则进入下一个状态,判断第二位是否符合;若第一位不符合则保持在初始状态,直到第一位匹配。如前两位匹配,则判断第三位是否符合,若第一位匹配,最新输入的数值和目标序列的第二位不匹配,则根据最新一位是否匹配第一位,进入第一位匹配状态或者初始状态。依次类推。
序列缓存对比法,则是将四个data_valid有效的数据data缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。如果数组和目标序列相等,则说明出现目标序列。拉高match信号。
状态机:
首先画出状态转移图。
s1_d0表示第一位0匹配,s2_d01表示前两位01匹配,s3_d011表示前三位011匹配,s4_d0110表示四位数值0110全部匹配。X表示不论data的值为0或1,都完成该状态跳变。依据状态转移图编写verilog代码:
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
|
`timescale 1ns/1ns module sequence_detect( input clk, input rst_n, input data, input data_valid, output reg match ); reg [ 3 : 0 ] pstate,nstate; parameter idle= 4 'd0, s1_d0= 4 'd1, s2_d01= 4 'd2, s3_d011= 4 'd3, s4_d0110= 4 'd4; always @(posedge clk or negedge rst_n) begin if (!rst_n) pstate<=idle; else pstate<=nstate; end always @(pstate or data or data_valid) begin case (pstate) idle: if (data_valid && !data) nstate=s1_d0; //第一位匹配 else nstate=idle; s1_d0: if (data_valid) begin if (data) nstate = s2_d01; //数据有效且为1,即前两位01匹配,下一状态为s2_d01 else nstate = s1_d0; //数据有效但为0,即只有第一位0匹配,下一状态为s1_d0 end else nstate = s1_d0; //数据无效,保持在s1_d0 s2_d01: if (data_valid) begin if (data) nstate = s3_d011; //数据有效且为1,即前三位011匹配,下一状态为s3_d011 else nstate = s1_d0; //数据有效但为0,即只有第一位0匹配,下一状态为s1_d0 end else nstate = s2_d01; //数据无效,保持在s2_d01 s3_d011: if (data_valid) begin if (!data) nstate = s4_d0110; //数据有效且为0,即前四位0110匹配,下一状态为s4_d0110 else nstate = idle; //数据有效但为1,即不匹配,下一状态为idle end else nstate = s3_d011; //数据无效,保持在s3_d011 s4_d0110: if (data_valid) begin if (!data) nstate = s1_d0; //数据有效且为0,即匹配目标序列的第一位0,下一状态为s1_d0 else nstate = idle; //数据有效但为1,不匹配目标序列,下一状态为idle end else nstate = idle; //数据无效,下一状态为idle default : nstate=idle; endcase end always @(pstate or rst_n) begin if (!rst_n== 1 ) match= 1 'b0; else if (pstate==s4_d0110) //进入状态s4_d0110表示四位数据都匹配,把匹配指示信号match拉高 match= 1 'b1; else match= 1 'b0; end 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
|
`timescale 1ns/1ns module sequence_detect( input clk, input rst_n, input data, input data_valid, output reg match ); reg [ 3 : 0 ] data_r; always@(posedge clk or negedge rst_n) begin if (~rst_n) data_r <= 4 'b0; else data_r <= data_valid? {data_r[ 2 : 0 ], data}: data_r; end always@(posedge clk or negedge rst_n) begin if (~rst_n) match <= 0 ; else match <= data_r[ 2 : 0 ]== 3 'b011 && data== 0 ; // && ~match; end //注释为延迟一拍的结果// always@(posedge clk or negedge rst_n) begin // if(~rst_n) // match <= 0; // else // match <= data_r==4'b0110; // end endmodule |