状态机简写为FSM,也称为同步有限状态机,一般简称为状态机。分类:Moore型状态机、Mealy型状态机。 关于状态机的详细知识点参照另一位博主的,讲的很详细:状态机
实战演练一
可乐机每次只能投入一枚一元硬币,每瓶可乐卖3元钱,投入3个硬币就可以让可乐机出可乐,如果投币不够3元想放弃投币,则需要按复位键,否则之前投入的硬币不能退回。
一、画图
模块图:
波形图:
二、代码
module simple_fsm(
input wire sys_clk,
input wire sys_rst_n,
input wire pi_money,
output reg 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;
endcase
//输出信号
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
综合器综合出的状态转移图:
三、仿真
仿真代码:
`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'b1;
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_rst_n == 1'b0)
pi_money <= 1'b0;
else
pi_money <= {$random}%2;
wire [2:0] state=simple_fsm_inst.state;
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
打印信息:
实战演练二
前面实现的可乐机比较简单,只能投一元的硬币,但是生活中还有0.5元的硬币,所以我们在这个实验中将可乐机设置得较为复杂一些,做成既可以投1元的硬币,也可以投0.5元的硬币,然后把可乐定价改为2.5元。此处因增加了可乐机的复杂度吧而引入了新的问题:投币后可乐机不仅需要放出可乐,还有可能出现需要找零钱的情况。
实验目标:可乐定价为2.5元一瓶,可投入0.5元、1元硬币,投币不够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 reg po_cola,
output reg po_money
);
parameter IDLE = 5'b00001;
parameter HALF = 5'b00010;
parameter ONE = 5'b00100;
parameter ONE_HALF = 5'b01000;
parameter TWO = 5'b10000;
wire [1:0] pi_money;
reg [4:0] state;//有几个状态就要有几个位宽的状态变量
assign pi_money ={pi_money_one,pi_mo ney_half};
//状态跳转
always @(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= 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_money == 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_HALF;
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 == 1'b0)
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 == 1'b0)
po_money <= 1'b0;
else if(state == TWO && pi_money == 2'b10)
po_money <= 1'b1;
else
po_money <= 1'b0;
endmodule
状态转移图:
三、仿真
`timescale 1ns/1ns
module tb_complex_fsm();
reg sys_clk;
reg sys_rst_n;
reg pi_money_half;
reg pi_money_one;
wire po_cola;
wire po_money;
reg random_data;
initial
begin
sys_clk = 1'b1;
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_rst_n == 1'b0)
random_data <= 1'b0;
else
random_data <={$random} %2;
always @(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
pi_money_half <= 1'b0;
else
pi_money_half <= random_data;
always @(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
pi_money_one <= 1'b0;
else
pi_money_one <= ~random_data;
wire [4:0] state=complex_fsm_inst.state;
wire [1:0] pi_money=complex_fsm_inst.pi_money;
initial
begin
$timeformat(-9,0,"ns",6);
$monitor("@time %t:pi_money_half=%b,pi_money_one=%b,pi_money=%b,state=%b,po_cola=%b,po_money=%b",$time,pi_money_half,pi_money_one,pi_money,state,po_cola,po_money);
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
仿真波形:
打印结果: