为了实现对序列 ‘91520’ 的检测,首先画出其状态转移图,如图所示:
由上图可以看出,如果在状态不符合转换条件,那么状态机要么回到初始态 pass_one,要么回到状态 pass_two,且每一个状态都有特定的方向,其输出仅由当前状态决定,因此这是一个摩尔型状态机,模块图如下:
首先,使用独热码对各个状态进行定义。然后,设置好初始状态。依照状态转移图开始状态转移部分的编写。
当在初始态 pass_one 时,如果检测到有数字 ‘9’ 输入,则跳入 pass_two 状态开始对数字 ‘1’ 的检测,否则保留在 pass_one 状态等待数字 ‘9’ 输入。
当在状态 pass_two 时,如果检测到有数字 ‘1’ 输入,则进入 pass_three 状态开始进行对数字 ‘5’ 的检测。如果检测到有数字 ‘9’ 输入,则仍然停留在 pass_two 状态等待数字 ‘1’ 输入;如果检测到有其他数字输入时,跳回初始态 pass_one 等待新的一轮检测;否则一直在状态 pass_two 等待数字的输入。
当在状态 pass_three 时,如果检测到有数字 ‘5’ 输入,则进入 pass_four 状态开始对数字 ‘l’ 的检测;如果检测到有数字 ‘9’ 输入,则跳转到 pass_two 状态等待数字 ‘1’ 输入;如果检测到有其他数字输入时,跳回初始态 pass_one 等待新的一轮检测;否则一直在状态 pass_three 等待数字的输入。
当在状态 pass_four 时,如果检测到有数字 ‘2’ 输入,则进入 pass_five 状态开始数字 ‘0’ 的检测;如果检测到有数字 ‘9’ 输入,则跳转到 pass_two 状态等待数字 ‘1’ 输入;如果检测到有其他数字输入时,跳回初始态 pass_one 等待新的一轮检测;否则一直在状态 pass_four 等待数字的输入。
当在状态 pass_five 时,如果检测到有数字 ‘0’ 输入,则说明完成一次 “91520” 的检测,回到初始态等待新的一轮检测,同时控制 key_flag 产生一个时钟脉冲;如果检测到有数字 ‘9’ 输入,则跳转到 pass_two 状态等待数字 ‘1’ 输入;否如果检测到有其他数字输入时,跳回初始态等待新的一轮检测;否则一直在状态 pass_five 等待数字的输入。
实现代码如下:
module password(
clk,
rst_n,
data_in,
data_valid,
key_flag
);
input clk;
input rst_n;
input [3:0] data_in;
input data_valid;
output reg key_flag;
parameter pass_one = 5'b0_0001;
parameter pass_two = 5'b0_0010;
parameter pass_three = 5'b0_0100;
parameter pass_four = 5'b0_1000;
parameter pass_five = 5'b1_0000;
reg [4:0]state;
always@(posedge clk or negedge rst_n)
if(!rst_n) begin
state <= pass_one;
key_flag <= 0;
end
else case(state)
pass_one:
begin
key_flag <= 0;
if(data_valid)begin
if(data_in == 9 )
state <= pass_two;
else
state <= pass_one;
end
else
state <= state;
end
pass_two:
begin
if(data_valid)begin
if(data_in == 1)
state <= pass_three;
else if(data_in == 9)
state <= pass_two;
else
state <= pass_one;
end
else
state <= state;
end
pass_three:
begin
if(data_valid)begin
if(data_in == 5)
state <= pass_four;
else if(data_in == 9)
state <= pass_two;
else
state <= pass_one;
end
else
state <= state;
end
pass_four:
begin
if(data_valid)begin
if(data_in == 2)
state <= pass_five;
else if(data_in == 9)
state <= pass_two;
else
state <= pass_one;
end
else
state <= state;
end
pass_five:
begin
if(data_valid)begin
if(data_in == 0)begin
key_flag <= 1;
state <= pass_one;
end
else if(data_in == 9)
state <= pass_two;
else
state <= pass_one;
end
else
state <= state;
end
default:state <= pass_one;
endcase
endmodule
仿真代码如下:
`timescale 1ns/1ns
`define clk_period 20
module password_tb();
reg clk;
reg rst_n;
reg [3:0] data_in;
reg data_valid;
wire key_flag;
password password(
.clk(clk),
.rst_n(rst_n),
.data_in(data_in),
.data_valid(data_valid),
.key_flag(key_flag)
);
initial clk = 1;
always #(`clk_period/2) clk = ~clk;
initial begin
rst_n = 0;
data_valid = 0;
data_in = 0;
#(`clk_period*20);
rst_n = 1;
#(`clk_period*20 + 1);
repeat(3) begin
gen_key("9");
#(`clk_period);
gen_key("1");
#(`clk_period);
gen_key("5");
#(`clk_period);
gen_key("2");
#(`clk_period);
gen_key("0");
#(`clk_period);
gen_key("9");
#(`clk_period);
gen_key("5");
#(`clk_period);
gen_key("3");
#(`clk_period);
gen_key("9");
#(`clk_period);
gen_key("1");
#(`clk_period);
gen_key("5");
#(`clk_period);
gen_key("2");
#(`clk_period);
gen_key("0");
#(`clk_period);
gen_key("1");
#(`clk_period);
gen_key("2");
#(`clk_period);
gen_key("4");
#(`clk_period);
gen_key("9");
#(`clk_period);
gen_key("1");
#(`clk_period);
gen_key("3");
#(`clk_period);
gen_key("1");
#(`clk_period);
gen_key("4");
#(`clk_period);
gen_key("9");
#(`clk_period);
gen_key("9");
#(`clk_period);
gen_key("3");
#(`clk_period);
gen_key("9");
#(`clk_period);
gen_key("1");
#(`clk_period);
gen_key("9");
#(`clk_period);
gen_key("1");
#(`clk_period);
gen_key("5");
#(`clk_period);
gen_key("2");
#(`clk_period);
gen_key("0");
#(`clk_period);
gen_key("4");
#(`clk_period);
end
#(`clk_period*10);
$finish;
end
task gen_key;
input [3:0] key;
begin
data_in = key;
data_valid = 1;
#(`clk_period);
data_valid = 0;
end
endtask
initial begin
$fsdbDumpfile("./password_tb.fsdb");
$fsdbDumpvars(0,"password_tb");
$fsdbDumpSVA();
end
endmodule
通过 Verdi 进行仿真,得到如下波形图:
可以看到,在识别到数字序列 ‘91520’ 时,key_flag 会发出脉冲信号。