序列检测器

功能描述:

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

用FSM实现

module seqdet
(
   input wire x,
   input wire clk,
   input wire rst,
   output wire z
);

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;

assign z = (state == D && x==0)?1'b1:1'b0;//状态为D时又收到输入0,表明10010已经收到,输出为1

always @ (posedge clk,negedge rst)
   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              

测试文件:

`timescale 1ns/1ns
module seqdet_tb;
localparam T =20;
reg clk,rst;
reg [23:0] data;
wire z,x;

assign x = 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 @ (posedge clk)
   #2 data = {data[22:0],data[23]};
   
seqdet U1
(
   .x(x),
   .z(z),
   .clk(clk),
   .rst(rst)
);

endmodule

用移位寄存器实现检测

module seqdet
(
   input wire x,
   input wire clk,
   input wire rst,
   output wire z,
   output reg [4:0] q
);

//reg [4:0] q;

assign z = (q == 5'b10010) ? 1'b1:1'b0;

always @ (posedge clk,negedge rst)
   if(!rst)
      q <= 5'd0;
   else
      q <= {q[3:0],x};

endmodule  

RTL级视图:

测试文件:

`timescale 1ns/1ns
module seqdet_tb;
localparam T =20;
reg clk,rst;
reg [23:0] data;
wire z,x;
wire [4:0] q;

assign x = 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 @ (posedge clk)
   #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.

代码修改如下:

module seqdet
(
   input wire x,
   input wire clk,
   input wire rst,
   output wire z,
   output reg [4:0] q
);

wire [4:0] q_next;

assign q_next ={q[3:0],x};
assign z = (q_next== 5'b10010) ? 1'b1:1'b0;

always @ (posedge clk,negedge rst)
   if(!rst)
      q <= 5'd0;
   else
      q <= q_next;

endmodule  

状态机修改:

module seqdet
(
   input wire x,
   input wire clk,
   input wire rst_n,
   output wire z
);
//用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 @ (posedge clk,negedge rst_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;
assign z = (ns==E);

endmodule  

posted on 2011-04-18 15:51  齐威王  阅读(12911)  评论(0编辑  收藏  举报

导航