Verilog进阶挑战
输入序列不连续的序列检测
一、题目描述
请编写一个序列检测模块,输入信号端口为data,表示数据有效的指示信号端口为data_valid。当data_valid信号为高时,表示此刻的输入信号data有效,参与序列检测;当data_valid为低时,data无效,抛弃该时刻的输入。当输入序列的有效信号满足0110时,拉高序列匹配信号match。
模块的接口信号图如下:
输入描述:
clk:系统时钟信号
rst_n:异步复位信号,低电平有效
data:单比特信号,待检测的数据
data_valid:输入信号有效标志,当该信号为1时,表示输入信号有效
输出描述:
match:当输入信号data满足目标序列,该信号为1,其余时刻该信号为0
二、解析与代码
`timescale 1ns/1ns
module sequence_detect(
input clk,
input rst_n,
input data,
input data_valid,
output reg match
);
reg [3:0]data_reg=0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
data_reg <= 0;
else if(data_valid)
data_reg <= {data_reg[2:0],data};
else
data_reg <= data_reg;
end
//计数器 避免那个0110的开头是数据无效时的
reg [2:0] cnt=0;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt <= 0;
else if(data_valid==1)
cnt <= cnt +1;
else
cnt <= 0;
end
//match更新
//错的原因:原本是always@(posedge clk or negedge rst_n)时序逻辑,data_reg比实际data慢一拍
always@(*)begin
if(!rst_n)
match <= 0;
else if(data_reg==4'b0110 && cnt>=3'd4)
match <= 1;
else
match <= 0;
end
endmodule
状态机的写法:
状态空间定义:S0:0000; S1:0001; … S15:1111
状态转移图:
module sequence_detect(
input clk,
input rst_n,
input data,
input data_valid,
output reg match=0
);
//三段式状态机方法
reg [3:0]current_state,next_state;
//状态更新
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
current_state <= 4'b0000;
else if(data_valid)
current_state <= next_state;
else
current_state <= current_state;
end
//状态转移
//状态定义
parameter S0 = 4'b0000;
parameter S1 = 4'b0001;
parameter S2 = 4'b0010;
parameter S3 = 4'b0011;
parameter S4 = 4'b0100;
parameter S5 = 4'b0101;
parameter S6 = 4'b0110;
parameter S7 = 4'b0111;
parameter S8 = 4'b1000;
parameter S9 = 4'b1001;
parameter S10 = 4'b1010;
parameter S11 = 4'b1011;
parameter S12 = 4'b1100;
parameter S13 = 4'b1101;
parameter S14 = 4'b1110;
parameter S15 = 4'b1111;
always@(*)begin
if(data_valid)
case(current_state)
S0:begin
if(data) next_state <= S1;
else next_state <= S0;
end
S1:begin
if(data) next_state <= S3;
else next_state <= S2;
end
S2:begin
if(data) next_state <= S3;
else next_state <= S4;
end
S3:begin
if(data) next_state <= S7;
else next_state <= S6;
end
S4:begin
if(data) next_state <= S5;
else next_state <= S8;
end
S5:begin
if(data) next_state <= S11;
else next_state <= S10;
end
S6:begin
if(data) next_state <= S13;
else next_state <= S12;
end
S7:begin
if(data) next_state <= S15;
else next_state <= S14;
end
S8:begin
if(data) next_state <= S9;
else next_state <= S0;
end
S9:begin
if(data) next_state <= S3;
else next_state <= S2;
end
S10:begin
if(data) next_state <= S11;
else next_state <= S5;
end
S11:begin
if(data) next_state <= S7;
else next_state <= S6;
end
S12:begin
if(data) next_state <= S9;
else next_state <= S8;
end
S13:begin
if(data) next_state <= S11;
else next_state <= S10;
end
S14:begin
if(data) next_state <= S15;
else next_state <= S12;
end
S15:begin
if(data) next_state <= S15;
else next_state <= S14;
end
endcase
else
next_state <= S0;
end
//输出
always@(*)begin
match <= (next_state==S6)?1:0;
end