状态机
状态机(State Machine)
有限状态机(FSM):在有限个状态之间按一定规律转换的时序电路。
模型:
梅利型和摩尔型区别:输出是否只与状态有关(是否需要输入信号)
编程方法:四段论
根据前面的模型可以知道,要想完成状态机的编程需要完成以下几步:
-
状态空间的定义
-
状态的跳转(判断当前状态是啥,是一个时序结构)
-
下一个状态(根据当前状态,结合一些其他的判断来判断下一个状态是什么)
-
状态的动作
实例
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2021/08/14 10:48:49
// Design Name:
// Module Name: flow_check
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module flow_check(
input clk,
input rst_n,
input idata,
output reg flag
);
parameter S0 = 7'B000_0001;
parameter S1 = 7'B000_0010;
parameter S2 = 7'B000_0100;
parameter S3 = 7'B000_1000;
parameter S4 = 7'B001_0000;
parameter S5 = 7'B010_0000;
parameter S6 = 7'B100_0000;
reg [6:0] c_state;
reg [6:0] n_state;
always @(negedge rst_n or posedge clk) begin
if (!rst_n)
c_state<=S0;
else
c_state<=n_state;
end
always @(*) begin //组合结构
case(c_state)
S0:begin
if(idata)
n_state=S1;
else
n_state=S0;
end
S1:begin
if(idata)
n_state=S1;
else
n_state=S2;
end
S2:begin
if(idata)
n_state=S3;
else
n_state=S0;
end
S3:begin
if(idata)
n_state=S1;
else
n_state=S4;
end
S4:begin
if(idata)
n_state=S5;
else
n_state=S0;
end
S5:begin
if(idata)
n_state=S6;
else
n_state=S4;
end
S6:begin
if(idata)
n_state=S1;
else
n_state=S2;
end
default:n_state=S0;
endcase
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
flag <= 1'b0;
else
if(c_state == S6 && idata == 1'b0)
flag <= 1'b1;
else
flag <= 1'b0;
end
endmodule
测试代码
`timescale 1ns/1ps
module flow_check_tb;
reg clk;
reg rst_n;
reg idata;
wire flag;
reg [15:0] ascii_state;
wire [6:0] tb_state;
assign tb_state = flow_check_inst.c_state;
always @(*) begin
case(tb_state)
7'b000_0000 : ascii_state = "S0";
7'b000_0010 : ascii_state = "S1";
7'b000_0100 : ascii_state = "S2";
7'b000_1000 : ascii_state = "S3";
7'b001_0000 : ascii_state = "S4";
7'b010_0000 : ascii_state = "S5";
7'b100_0000 : ascii_state = "S6";
default : ascii_state = "NO";
endcase
end
parameter PERIOD = 20;
flow_check flow_check_inst(
.clk (clk),
.rst_n (rst_n),
.idata (idata),
.flag (flag)
);
//clock generate moudle
initial begin
clk = 1'b0;
forever #(PERIOD/2)
clk = ~clk;
end
//将复位信号封装在Task中
task task_reset;
begin
rst_n = 0;
repeat(2) @(negedge clk);
rst_n = 1;
end
endtask
task task_sysinit;
begin
idata = 1'b0;
end
endtask
initial begin
task_sysinit;
task_reset;
repeat (10) begin
@(posedge clk);
#2;
idata = {$random} % 2;
end
@(posedge clk);
#2;
idata = 1'b1;
@(posedge clk);
#2;
idata = 1'b0;
@(posedge clk);
#2;
idata = 1'b1;
@(posedge clk);
#2;
idata = 1'b0;
@(posedge clk);
#2;
idata = 1'b1;
@(posedge clk);
#2;
idata = 1'b1;
@(posedge clk);
#2;
idata = 1'b0;
@(posedge clk);
#2;
idata = 1'b1;
@(posedge clk);
#2;
idata = 1'b0;
@(posedge clk);
#2;
idata = 1'b1;
@(posedge clk);
#2;
idata = 1'b1;
@(posedge clk);
#2;
idata = 1'b0;
repeat (10) begin
@(posedge clk);
#2;
idata = {$random} % 2;
end
#200;
$stop;
end
endmodule