FPGA是并行执行的,如果需要处理前后顺序的事件怎么办?就需要引入我们的状态机了。

共同点,状态的跳转只和输入有关。Moore型状态机,最后的输出只和当前的状态有关与输入无关。Mealy型 最后的输出不仅和当前状态有关还和输入相关。

可乐机系统,每次售价3元,每次只能投一枚硬币






使用mealy型状态机讲解


小知识:
1 在低速系统中,状态机的个数小于4个,我们使用二进制码
2 状态介于4到24个,就使用独热码
3 状态大于24个,使用格雷码
4 在高速系统中,无论多少个状态都建议使用独热码
module simple_fsm
(
input wire sys_clk,
input wire sys_rst_n,
input wire pi_money,
output wire po_cola;
);
// 独热码(比较好的) 二进制码 格雷码
parameter IDLE = 3'b001;
parameter ONE = 3'b010;
parameter TWO = 3'b100;
reg [2:0] state;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= IDLE;
else case(state)
IDLE:if(pi_money == 1'b1)
state <= ONE;
else
state <= IDLE;
ONE: if(pi_money == 1'b1)
state <= TWO;
else
state <= ONE;
TWO: if(pi_money == 1'b1)
state <= IDLE;
else
state <= TWO;
default: state <= IDLE;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
po_cola <= 1'b0;
else if((state == TWO) && (pi_money == 1'b1))
po_cola <= 1'b1;
else
po_cola <= 1'b0;
endmodule
一段式:
二段式:
三段式:
tb文件代码:
`timescale 1ns/1ns
module tb_simple_fsm();
reg sys_clk;
reg sys_rst_n;
reg pi_money;
wire po_cola;
initial begin
sys_clk = 1'b0;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
// 如何对内部的状态变量进行检测
wire [2:0] state = simple_fsm_inst.state;
// 产生投币信号 使用随机数的方法
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
pi_money <= 1'b0;
else
pi_money <= {$random} % 2;
// 系统函数方便验证
initial begin
$timeformat(-9, 0, "ns", 6);
$monitor("@time %t: pi_money = %b, state= %b, po_cola = %b", $time, pi_money, state, po_cola);
end
// 实例化
simple_fsm simple_fsm_inst
(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.pi_money(pi_money),
.po_cola(po_cola);
);
endmodule


如果投币不足2.5元,不出可乐。如果超过2.5元需要找零



输入输出编码:



module complex_fsm
(
input wire sys_clk,
input wire sys_rst_n,
input wire pi_money_half,
input wire pi_money_one,
output wire po_cola,
output wire po_money
);
parameter IDLE = 5'b00001,
HALF = 5'b00010,
ONE = 5'b00100,
ONE_HALF = 5'b01000,
TWO = 5'b10000;
// pi_money 并没有延迟一个周期,所以assign来赋值
wire [1:0] pi_money;
reg [4:0] state;
assign pi_money = {pi_money_one, pi_money_half};
// 第一段 状态机的跳转
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
stats <= IDLE;
else case(state)
IDLE: if(pi_money == 2'b01)
state <= HALF;
else if(pi_money == 2'b10)
state <= ONE;
else
state <= IDLE;
HALF: if(pi_money == 2'b01)
state <= ONE;
else if(pi_money == 2'b10)
state <= ONE_HALF;
else
state <= HALF;
ONE: if(pi_monet == 2'b01)
state <= ONE_HALF;
else if(pi_money == 2'b10)
state <= TWO;
else
state <= ONE;
ONE_HALF: if(pi_money == 2'b01)
state <= TWO;
else if(pi_money == 2'b10)
state <= IDLE;
else
state <= ONE_HELF;
TWO: if((pi_money == 2'b01) && (pi_money == 2'b10))
state <= IDLE;
else
state <= TWO;
default: state <= IDLE;
endcase
// 第二段数据的输出
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
po_cola<= 1'b0;
else if((state == ONE_HALF && pi_money == 2'b10)
|| (state == TWO && pi_money == 2'b01)
|| (state == TWO && pi_money == 2'b10))
po_cola <= 1'b1;
else
po_cola <= 1'b0;
// 第三段找零的输出
always@(posedge sys_clk or negedge sys_rst_n)
if(!sys_rst_n)
po_money<= 1'b0;
else if(state == TWO && pi_money == 2'b10)
po_money <= 1'b1;
else
po_money <= 1'b0;
endmodule
tb文件
`timescale 1ns/1ns
module tb_complex_fsm();
reg sys_clk;
reg sys_rst_n;
reg pi_money_half;
reg pi_money_one;
reg random_data;
wire po_cola;
wire po_money;
initial begin
sys_clk = 1'b0;
sys_rst_n <= 1'b0;
#20
sys_rst_n <= 1'b1;
end
always #10 sys_clk = ~sys_clk;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_clk == 1'b0) begin
random_data <= 1'b0;
end
else
random_data <= {$random} % 2;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_clk == 1'b0) begin
pi_money_half<= 1'b0;
end
else
pi_money_half<= random_data;
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_clk == 1'b0) begin
pi_money_one<= 1'b0;
end
else
pi_money_one<= ~random_data;
// 如何对内部的状态变量进行检测
wire [2:0] pi_money= complex_fsm_inst.pi_money;
// 系统函数方便验证
initial begin
$timeformat(-9, 0, "ns", 6);
$monitor("@time %t: pi_money = %b, state= %b, po_cola = %b", $time, pi_money, state, po_cola);
end
// 实例化
complex_fsm complex_fsm_inst
(
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.pi_money_half(pi_money_half),
.pi_money_one(pi_money_one),
.po_cola(po_cola),
.po_money(po_money)
);
endmodule

