/*序列检测器,检测序列10010,rst低电平有效*/
module seqdet(x,z,clk,rst);
input x,clk,rst;
output z;
reg[2:0]state;//保存当前状态
wire z;//输出信号
parameter s0=3'd0,s1=3'd1,s2=3'd2,s3=3'd3,s4=3'd4,s5=3'd5,s6=3'd6,s7=3'd7;
assign z=(state==s4&&x==0)?1:0;//状态4时输入0则检测到序列,z输出1
always@(posedge clk or negedge rst)
if(!rst) state<=s0;//复位
else
case(state)//状态之间转换关系
s0:
if(x==1)state<=s1;
else state<=s0;
s1:
if(x==0)state<=s2;
else state<=s1;
s2:
if(x==0)state<=s3;
else state<=s6;
s3:
if(x==1)state<=s4;
else state<=s7;
s4:
if(x==0)state<=s5;
else state<=s1;
s5:
if(x==1)state<=s1;
else state<=s3;
s6:
if(x==1)state<=s1;
else state<=s2;
s7:
if(x==1)state<=s6;
else state<=s7;
default:state<=s0;
endcase
endmodule
//testbench
`timescale 1 ns/ 1 ns
`define halfpriod 20
module seqdet_vlg_tst();
reg clk,rst;
reg [23:0]data;
// wires
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;
#(`halfpriod*1000)$stop;
$display("Running testbench");
end
always #(`halfpriod)clk=~clk;//产生时钟
always@(posedge clk)
#2 data={data[22:0],data[23]};//序列移位
//调用序列检测模块
seqdet i1(
.clk(clk),
.rst(rst),
.x(x),
.z(z));
endmodule
序列检测是数字电路中的经典案例,用verilog实现时并没有什么值得注意的地方,主要是对逻辑状态转换的理解。
两个状态转换图都表示在状态S1收到高电平1时转换到状态S2并输出低电平0
上述代码中实现了对10010的序列检测,testbench模拟了1100_1001_0000_1001_0100的输入,波形图如下