一、状态机
1.定义
状态机简写为FSM(Finite State Machine),也称为同步有限状态机,我们一般简称为状态机分类:Moore型状态机、Mealy型状态机
同步:是指再时钟的作用下进行的
有限:是指表示状态的个数有限
Moore型状态机、Mealy型状态机 的区别:
相同点:状态的跳转都只和输入有关
不同点:在输出的时侯,若最后的输出都只和当前状态有关而与输入无关为Moore型状态机,若最后的输出与输入有关为Mealy型状态机。
2.编码方式
(1)独热码
每个状态只有一个为高电平,其余的都为低电平,所以三个状态就需要使用三个位宽的变量。在综合的时候,会被综合为一个比较器,这个比较器只有一个比特位是不同的。综合器会对其进行一个优化,原来三个比特位的比较器变成一个比特位的比较器。这样大大节省组合逻辑的资源,但是状态变量的位宽会占用的比较多,占用了大量的寄存器。而在FPGA中组合逻辑资源比较少而寄存器资源比较多,所以采用独热码比较好。
(2)二进制
二进制码与独热码正好相反,占用寄存器资源比较少,但是占用组合逻辑资源比较多。
(3)格雷码
每两个相邻的状态只有一个比特位是不同的。
比较
①在低速系统中,状态机中状态机的个数小于4,用二进制,4~24个用独热码,超过24个用格雷码。
②在高速系统中,使用独热码
3.状态机代码的写法
(1)一段式
一段式状态机表示,在一段状态机中使用时序逻辑,及描述状态的转移也描述数据的输出。但是在描述一些大型的状态机是比较困难的,会使得整个系统显得比较臃肿,不够清晰也不利于代码的修改。
(2)二段式
二段式表示分两段状态机,在第一段状态机中使用时序逻辑描述状态的转移,在第二段状态机中使用组合逻辑描述数据的输出。结构和理想的理论模型是完全吻合,既不会有附加的结构存在也比较精简。但是在第二段是使用组合逻辑描述的,在有些情况是无法准确描述的,比如说输出时需要类似计数的累加情况,那么这种情况会在输出时产生自迭代,这是在组合逻辑当中时严格禁止的。i并且第二段主要描述输出,输出用组合逻辑会使得输出产生很多的毛刺
(3)三段式(新二段式)
三段式状态机分三段,第一段状态机中采用时序逻辑描述状态转移,在第二段状态机中使用组合逻辑判断转移条件描述转移规律,在第三段状态机中使用组合逻辑或者时序逻辑描述数据输出。(可以将前两端状态机进行整合,而第三段保持不变,就是新二段式)
二、实现
1.波形
2.程序
module simple_fsm
(
input wire sys_clk,
input wire sys_rst_n,
input wire pi_money,
output reg po_cola
);
reg [2:0] state;
parameter IDEL = 3'b001;
parameter ONE = 3'b010;
parameter TWO = 3'b100;
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
state <= IDEL;
else
case (state)
IDEL: if(pi_money == 1'b0)
state <= IDEL;
else
state <= ONE;
ONE: if(pi_money == 1'b0)
state <= ONE;
else
state <= TWO;
TWO: if(pi_money == 1'b0)
state <= TWO;
else
state <= IDEL;
default: state <= IDEL;
endcase
always@(posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
po_cola <= 1'b0;
else if ((pi_money == 1'b1)&&(state == TWO))
po_cola <= 1'b1;
else
po_cola <= 1'b0;
endmodule
测试程序
`timescale 1ns/1ns
module tb_simple ();
reg sys_clk;
reg sys_rst_n;
reg pi_money;
wire po_cola;
wire [2:0] state = simple_fsm_inst.state;
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_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
对状态变量进行监测
定义一个wire型变量state,将实例化中的state状态赋值给定义的wire型变量state,这样就能够在仿真代码中间读取模块内部的一个变量进行检测。