4 Verilog进阶挑战:序列检测

本文详细介绍了如何使用Verilog进行序列检测,包括4种不同情况的序列检测挑战:连续序列检测、含有无关项的序列检测、不重叠序列检测和输入序列不连续的序列检测。通过状态机法和序列缓存对比法,解析了针对不同序列的检测逻辑,并提供了相应的Verilog代码实现。

VL1 输入序列连续的序列检测

描述

请编写一个序列检测模块,检测输入信号a是否满足01110001序列,当信号满足该序列,给出指示信号match。

模块的接口信号图如下:

模块的时序图如下:

输入描述:

clk:系统时钟信号

rst_n:异步复位信号,低电平有效

a:单比特信号,待检测的数据

输出描述:

match:当输入信号a满足目标序列,该信号为1,其余时刻该信号为0

 

题意整理

       题目要求检测a的序列,a为单bit输入,每个时刻可能具有不同的值,当连续8个时钟周期中a的值依次为01110001,判断a出现目标序列,把匹配信号match拉高。

值得注意的是:当前N位数值匹配则N+1位是否匹配,当出现某一位不匹配时,注意不一定从第一位开始重新判断,例如出现前五位数值为01110,第六位数值出现1,不匹配目标序列,但第五,第六位数值符合第一,第二位数值,可以继续判断下一位是否匹配目标序列的第三位,而不需要从第一位开始。

题解主体

       对于序列检测题目,常规的解法有两种:状态机法和序列缓存对比法

状态机法的过程类似于题意理解中提到的过程:在初始状态中,先判断第一位是否符合,若符合则进入下一个状态,判断第二位是否符合;若第一位不符合则保持在初始状态,直到第一位匹配。如前两位匹配,则判断第三位是否符合,若第一位匹配,最新输入的数值和目标序列的第二位不匹配,则根据最新一位是否匹配第一位,进入第一位匹配状态或者初始状态。依次类推。

序列缓存对比法,则是将八个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。然后将数组和目标序列对比,如果数组和目标序列相等,则说明出现目标序列。

序列缓存对比法在实现上比较简单,本题采用该方法实现。首先声明一个数组,缓存八个时刻的a输入的数值。移位可以通过位截取操作和位拼接操作实现:a_tem[6:0]表示截取a_tem的低7位,{a_tem[6:0],a}表示把a_tem[6:0]和新输入的数值a拼接,a位于低位。

       reg [7:0] a_tem;

       always @(posedge clk or negedge rst_n)

              if (!rst_n)

                     begin

                            a_tem <= 8'b0;

                     end

              else

                     begin

                            a_tem <= {a_tem[6:0],a};

                     end

然后将缓存的数组和目标序列:0111_0001相对比,如果匹配,则把match拉高,其它情况下,macth为0。

       always @(posedge clk or negedge rst_n)

              if (!rst_n)

                     begin

                            match <= 1'b0;

                     end

              else if (a_tem == 8'b0111_0001)

                     begin

                            match <= 1'b1;

                     end

              else

                     begin    

                            match <= 1'b0;

                     end

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output reg match
	);

	reg [7:0] a_tem;
	
	always @(posedge clk or negedge rst_n)
		if (!rst_n)
			begin 
				match <= 1'b0;
			end
		else if (a_tem == 8'b0111_0001)
			begin
				match <= 1'b1;
			end
		else 
			begin	
				match <= 1'b0;
			end
		
	always @(posedge clk or negedge rst_n)
		if (!rst_n)
			begin 
				a_tem <= 8'b0;
			end
		else 
			begin
				a_tem <= {a_tem[6:0],a};
			end
endmodule

 VL2 含有无关项的序列检测

描述

请编写一个序列检测模块,检测输入信号a是否满足011XXX110序列(长度为9位数据,前三位是011,后三位是110,中间三位不做要求),当信号满足该序列,给出指示信号match。

程序的接口信号图如下:

程序的功能时序图如下:

输入描述:

clk:系统时钟信号

rst_n:异步复位信号,低电平有效

a:单比特信号,待检测的数据

输出描述:

match:当输入信号a满足目标序列,该信号为1,其余时刻该信号为0

 

题意整理

       题目要求检测a的序列,a为单bit输入,每个时刻可能具有不同的值,题目要求检测前三位和后三位,不要求检测中间三位,如果把如果把中间的XXX,分别列出:000,001,010,011,100,101,110,111,分别检测,代码过于累赘,考虑分别检测前三位和后三位,分成两个小段的序列检测。当前三位信号和后三位信号同时匹配时,把匹配信号match拉高。

值得注意的是:当前N位数值匹配则N+1位是否匹配,当出现某一位不匹配时,注意不一定从第一位开始重新判断,例如出现前两位数值为01,第三位数值出现0,不匹配目标序列,但第三位数值符合第一位数值,可以继续判断下一位是否匹配目标序列的第二位,而不需要从第一位开始。

题解主体

       对于序列检测题目,常规的解法有两种:状态机法和序列缓存对比法。

状态机法的过程类似于题意理解中提到的过程:在初始状态中,先判断第一位是否符合,若符合则进入下一个状态,判断第二位是否符合;若第一位不符合则保持在初始状态,直到第一位匹配。如前两位匹配,则判断第三位是否符合,若第一位匹配,最新输入的数值和目标序列的第二位不匹配,则根据最新一位是否匹配第一位,进入第一位匹配状态或者初始状态。依次类推。

序列缓存对比法,则是将九个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。然后截取数组的前三位和目标序列011对比,截取数组的后三位和目标序列110对比,如果两段数组都和目标序列相等,则说明出现目标序列。

序列缓存对比法在实现上比较简单,本题采用该方法实现。首先声明一个数组,缓存九个时刻的a输入的数值。移位可以通过位截取操作和位拼接操作实现:a_tem[7:0]表示截取a_tem的低7位,{a_tem[7:0],a}表示把a_tem[7:0]和新输入的数值a拼接,a位于低位。

       reg [8:0] a_tem;

       always @(posedge clk or negedge rst_n)

              if (!rst_n)

                     begin

                            a_tem <= 9'b0;

                     end

              else

                     begin

                            a_tem <= {a_tem[7:0],a};

                     end

然后截取数组的前三位和目标序列011对比,截取数组的后三位和目标序列110对比,分别声明两个变量表示两个子序列对比的结果。

       reg match_f;

       reg match_b;

       always @(posedge clk or negedge rst_n)

              if (!rst_n)

                     begin

                            match_f <= 1'b0;

                     end

              else if (a_tem[9:7] == 3'b011)

                     begin

                            match_f <= 1'b1;

                     end

              else

                     begin    

                            match_f <= 1'b0;

                     end

       always @(posedge clk or negedge rst_n)

              if (!rst_n)

                     begin

                            match_b <= 1'b0;

                     end

              else if (a_tem[2:0] == 3'b110)

                     begin

                            match_b <= 1'b1;

                     end

              else

                     begin    

                            match_b <= 1'b0;

                     end

当两个子序列都匹配时,拉高match信号。

       assign match = match_b && match_f;    

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input a,
	output match
	);

	reg [8:0] a_tem;
	reg match_f;
	reg match_b;
	
	always @(posedge clk or negedge rst_n)
		if (!rst_n)
			begin 
				match_f <= 1'b0;
			end
		else if (a_tem[8:6] == 3'b011)
			begin
				match_f <= 1'b1;
			end
		else 
			begin	
				match_f <= 1'b0;
			end

	always @(posedge clk or negedge rst_n)
		if (!rst_n)
			begin 
				match_b <= 1'b0;
			end
		else if (a_tem[2:0] == 3'b110)
			begin
				match_b <= 1'b1;
			end
		else 
			begin	
				match_b <= 1'b0;
			end
			
	always @(posedge clk or negedge rst_n)
		if (!rst_n)
			begin 
				a_tem <= 9'b0;
			end
		else 
			begin
				a_tem <= {a_tem[7:0],a};
			end
			
	assign match = match_b && match_f;
endmodule

VL3 不重叠序列检测 

描述

请编写一个序列检测模块,检测输入信号(a)是否满足011100序列, 要求以每六个输入为一组,不检测重复序列,例如第一位数据不符合,则不考虑后五位。一直到第七位数据即下一组信号的第一位开始检测。当信号满足该序列,给出指示信号match。当不满足时给出指示信号not_match。

模块的接口信号图如下:

模块的时序图如下:

输入描述:

clk:系统时钟信号

rst_n:异步复位信号,低电平有效

a:单比特信号,待检测的数据

输出描述:

match:当输入信号a满足目标序列,该信号为1,其余时刻该信号为0

not_match:当输入信号a不满足目标序列,该信号为1,其余时刻该信号为0

 

题意整理

       题目要求检测a的序列,a为单bit输入,每个时刻可能具有不同的值, 当连续的六个输入值符合目标序列表示序列匹配,当六个输入值的一个或多个不符合则表示序列不匹配。

值得注意的是:题目要求以六位数据为一组,不同于常见的序列检测,要求检测重复序列,在画状态转移图时要注意,例如第一位不匹配,不应该返回到初始状态去进行第一位的判断,因为此时的输入是第二位数值,题目要求不对该数值做判断,而需要等到六个时钟周期之后,即第七位数据(第二组数值的第一位)再判断是否匹配目标序列的第一位。

题解主体

       对于序列检测题目,常规的解法有两种:状态机法和序列缓存对比法。

状态机法的过程类似于题意理解中提到的过程:在初始状态中,先判断第一位是否符合,若符合则进入下一个状态,判断第二位是否符合;若第一位不符合则保持在初始状态,直到第一位匹配。如前两位匹配,则判断第三位是否符合,若第一位匹配,最新输入的数值和目标序列的第二位不匹配,则根据最新一位是否匹配第一位,进入第一位匹配状态或者初始状态。依次类推。

序列缓存对比法,则是将六个时刻的数据缓存,作为一个数组,每个时刻的输入位于数组的末尾,数组其它元素左移,把最早输入的数据移出。如果数组和目标序列相等,则说明出现目标序列。拉高match信号,如果不等则拉高not_match信号。

题目要求使用状态机实现,首先画出状态转移图。

sf1,sf2等状态表示该段序列不匹配,此时进行到第n位的对比,当到达sf6,表示已经对比完成全部六位数据,存在不匹配位,拉高not_match。当六位全部对比结束,开始新一轮的对比。s1,s2等状态表示前n位数值匹配,当到达s6时,表示全部数值位匹配,拉高match。X表示不论data的值为0或1,都完成该状态跳变。依据状态转移图编写verilog代码:

reg [3:0] pstate,nstate;

parameter idle=4'd0,

                s1=4'd1,

          s2=4'd2,

          s3=4'd3,

          s4=4'd4,

          s5=4'd5,

          s6=4'd6;

                sf1=4'd7,

          sf2=4'd8,

          sf3=4'd9,

          sf4=4'd10,

          sf5=4'd11,

          sf6=4'd12;

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==0)

                nstate=s1;                   //第一位匹配

            else

                nstate=sf1;

        s1:

            nstate=data?s2:sf2;

        s2:

            nstate=data?s3:sf3;

        s3:

            nstate=data?s4:sf4;

        s4:

            nstate=data?sf5:s5;

        s5:

            nstate=data?sf6:s6;

        s6:

            nstate=data?sf1:s1;

        sf1:

            nstate=sf2;

        sf2:

            nstate=sf3;

        sf3:

            nstate=sf4;

        sf4:

            nstate=sf5;

        sf5:

            nstate=sf6;

        sf6:

                     nstate=data?sf1:s1;

        default:

            nstate=idle;

        endcase

end

always @(pstate or data or rst_n)

begin

    if(!rst_n==1)

        match=1'b0;

    else if(pstate==s6)

            match=1'b1;

       else if(pstate==sf6)

            not_match=1'b1;

         else

            match=1'b0;

end

 

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input data,
	output reg match,
	output reg not_match
	);


reg [3:0] pstate,nstate;

parameter idle=4'd0,
		  s1=4'd1,
          s2=4'd2,
          s3=4'd3,
          s4=4'd4,
          s5=4'd5,
          s6=4'd6,
		  sf1=4'd7,
          sf2=4'd8,
          sf3=4'd9,
          sf4=4'd10,
          sf5=4'd11,
          sf6=4'd12;

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==0)
                nstate=s1;			//第一位匹配
            else
                nstate=sf1;
        s1:
            nstate=data?s2:sf2;
        s2:
            nstate=data?s3:sf3;
        s3:
            nstate=data?s4:sf4;
        s4:
            nstate=data?sf5:s5;
        s5:
            nstate=data?sf6:s6;
        s6:
            nstate=data?sf1:s1;
        sf1:
            nstate=sf2;
        sf2:
            nstate=sf3;
        sf3:
            nstate=sf4;
        sf4:
            nstate=sf5;
        sf5:
            nstate=sf6;
        sf6:
			nstate=data?sf1:s1;
        default:
            nstate=idle;
        endcase
end

always @(pstate or data or rst_n)
begin
    if(!rst_n==1) 
		begin
			match=1'b0;
			not_match = 1'b0;
		end
    else if(pstate==s6)
		begin
			match=1'b1;
			not_match = 1'b0;
		end
	else if(pstate==sf6)
		begin
			match=1'b0;
			not_match = 1'b1;
		end
    else
		begin
			match=1'b0;
			not_match = 1'b0;
		end
end

endmodule

寄存器写

`timescale 1ns/1ns
module sequence_detect(
    input clk,
    input rst_n,
    input data,
    output  match,
    output  not_match
    );
    
    reg [5:0] data_reg;
    reg [2:0] cnt;
    
    always@(posedge clk or negedge rst_n) begin
        if(~rst_n) begin
            data_reg <= 6'b0;
            cnt <= 0;
        end
        else begin
            data_reg <= {data_reg[4:0],data};
            if(cnt ==6)
                cnt <= 1;
            else
                cnt <= cnt + 1;
        end
    end
    
    assign match = (cnt==6)? ((data_reg==6'b011100)? 1:0) : 0;
    assign not_match = (cnt==6)? ((data_reg==6'b011100)? 0:1) : 0;
endmodule

VL4 输入序列不连续的序列检测

描述

题目描述:

请编写一个序列检测模块,输入信号端口为data,表示数据有效的指示信号端口为data_valid。当data_valid信号为高时,表示此刻的输入信号data有效,参与序列检测;当data_valid为低时,data无效,抛弃该时刻的输入。当输入序列的有效信号满足0110时,拉高序列匹配信号match。

模块的接口信号图如下:

      

模块的时序图如下:

 

题意整理

       题目要求检测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)

                            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 

`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

方法二

`timescale 1ns/1ns
module sequence_detect(
	input clk,
	input rst_n,
	input data,
	input data_valid,
	output reg match
	);
    //parameter 
    parameter N = 4;
    
    //defination
    reg [N - 1 : 0] SR;
    
    //output
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) SR <= 'd0;
        else if(data_valid) SR <= {SR[2 : 0], data};
    end

    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) match <= 'd0;
        else if(data_valid && SR[2 : 0] == 3'b011 && !data) match <= 1'b1; 
        else match <= 1'b0;
    end
endmodule

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值