题意整理
题目要求检测a的序列,a为单bit输入,每个时刻可能具有不同的值,且并不是每一个数据都是有效的,需要根据data_valid信号进行判断。在状态转化过程中,当data_valid为0,表示该时刻是输入数据无效,应保持在当前状态。当data_valid为1,再根据输入数据是否匹配进行下一个状态的值。
题解主体
对于序列检测题目,常规的解法有两种:状态机法和序列缓存对比法。
状态机法的过程类似于题意理解中提到的过程:在初始状态中,在data_valid有效时逐一判断当前时刻的数值。先判断第一位是否符合,若符合则进入下一个状态,判断第二位是否符合;若第一位不符合则保持在初始状态,直到第一位匹配。如前两位匹配,则判断第三位是否符合,若第一位匹配,最新输入的数值和目标序列的第二位不匹配,则根据最新一位是否匹配第一位,进入第一位匹配状态或者初始状态。依次类推。
序列缓存对比法,则是将四个data_valid有效的数据data缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。如果数组和目标序列相等,则说明出现目标序列。拉高match信号。
s1_d0表示第一位0匹配,s2_d01表示前两位01匹配,s3_d011表示前三位011匹配,s4_d0110表示四位数值0110全部匹配。X表示不论data的值为0或1,都完成该状态跳变。依据状态转移图编写verilog代码:
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
pstate<=idle;
else
pstate<=nstate;
end
always @(pstate or data)
begin
case(pstate)
idle:
if(data_valid && !data)
nstate=s1_d0; //第一位匹配
else
nstate=idle;
s1_d0:
if (data_valid)
beginif (data) nstate = s2_d01; //数据有效且为1,即前两位//01匹配,下一状态为s2_d01else nstate = s1_d0; //数据有效但为0,即只有第一//位0匹配,下一状态为s1_d0end
else nstate = s1_d0; //数据无效,保持在s1_d0
s2_d01:
if (data_valid)
beginif (data) nstate = s3_d011; //数据有效且为1,即前三位//011匹配,下一状态为s3_d011else nstate = s1_d0; //数据有效但为0,即只有第一//位0匹配,下一状态为s1_d0endelse nstate = s2_d01; //数据无效,保持在s2_d01
s3_d011:
if (data_valid)
beginif (!data) nstate = s4_d0110; //数据有效且为0,即前四位//0110匹配,下一状态为s4_d0110else nstate = idle; //数据有效但为1,即不匹//配,下一状态为idleendelse nstate = s3_d011; //数据无效,保持在s3_d011
s4_d0110:
if (data_valid)
beginif (!data) nstate = s1_d0; //数据有效且为0,即匹配目标//序列的第一位0,下一状态为s1_d0else nstate = idle; //数据有效但为1,不匹配目标序列,下一状态为idleendelse 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
参考答案
`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