状态机

基础概念

一段式状态机

  • 一个always块描述
  • 状态转换,状态转移,状态输出

两段式状态机

  • 一个always块描述:状态转移 (通用的)
  • 一个always块描述:**状态转移,状态输出 ** (描述状态过程)

三段式状态机

  • 一个always块描述:状态转换
  • 一个always块描述:状态转移
  • 一个always块描述:状态输出

推荐三段式状态机:

  • 代码比较简洁
  • 利于时序约束
  • 无组合逻辑输出
  • 利于综合布局布线
  • 代码可靠性可维护性较高
  • 代码风格规范

Moore状态机

  • 状态的输出之何当前的状态有关

Mealy状态机

  • 状态机的输出不仅与当前的状态有关,还和当前的输入信号有关

状态机设计分析

eg1 一段式状态机

  • 使用Verilog设计电路,完成以下三个功能:(1) 每瓶饮料1.5元 (2) 一次只能投入一个硬币,有0.5 与1.0两种硬币 (3) 具有找零功能
  • IDLE状态:0 机器显示额为0,不会输出饮料,不会找零
  • S1状态:0.5 机器显示额为0.5,不会输出饮料,不会找零
  • S2状态:1 机器显示额为1,不会输出饮料,不会找零
  • S3状态:1.5 机器显示额为1.5,输出饮料,不会找零
  • S4状态:2 机器显示额为2,输出饮料,找零0.5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
module one_section(
input clk, //时序逻辑 时钟
input rst_n, //复位信号
input [1:0] money, //投币信号
output drink, //输出饮料
output coin //找零
);

parameter IDLE = 5'b00001; //初始状态
parameter S1 = 5'b00010; //状态1
parameter S2 = 5'b00100;
parameter S3 = 5'b01000;
parameter S4 = 5'b10000;
//普通编码会有中间状态,产生毛刺
//独热码 不管有多少状态,只有一个状态为1,其他均为0
//状态机状态数量不多(几十个以内),建议使用独热码


reg [4:0] cstate; //当前状态
reg [1:0] r_drink;
reg [1:0] r_coin; //方便后面用assign连接

assign drink = r_drink;
assign coin = r_coin;

//一段式状态机
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cstate <= IDLE;
r_drink <= 1'b0;
r_coin <= 1'b0;
end

else begin
case(cstate)
IDLE:begin //复位状态,饮料机中余额为0
/*
if(money[1]) cstate <= S2;
else if(money[0]) cstate <= S1;
else cstate <= cstate;*/ //太麻烦
cstate <= money[1] ? S2 : (money[0] ? S1 : IDLE);
//状态转换和状态转移
r_drink <= 1'b0;
r_coin <= 1'b0;
end
S1:begin //状态1,饮料机中余额为0.5元
cstate <= money[1] ? S3 : (money[0] ? S2 : S1);
r_drink <= 1'b0;
r_coin <= 1'b0;
end
S2:begin //状态2,饮料机中余额为1元
cstate <= money[1] ? S4 : (money[0] ? S3 : S2);
r_drink <= 1'b0;
r_coin <= 1'b0;
end
S3:begin //状态3,饮料机中余额为1.5元
cstate <= money[1] ? S2 : (money[0] ? S1 : IDLE);
r_drink <= 1'b1;
r_coin <= 1'b0;
end
S4:begin //状态4,饮料机中余额为2元
cstate <= money[1] ? S2 : (money[0] ? S1 : IDLE); //无论投多少币,均回到初始状态
r_drink <= 1'b1; //输出饮料信号
r_coin <= 1'b1; //投2元找1元,投1元不找零
end
endcase
end
end
endmodule

Moore状态机

  • 输出仅为当前状态,状态变化时,输出变化(完全取决于状态
  • 例如:台灯
  • 适用于稳定输出的场景(灯一直亮)
  • 先变状态,后输出

Mealy状态机

  • 输出由当前状态和输入共同决定,输出在输入变化后立即发生
  • 例如:感应式水龙头
  • 适用于快速响应场景
  • 先输出,后变状态

状态图设计要点

  • 离开一个特定状态的弧线上的转移表达式必须是相互排斥的
  • 能复位进入初始状态
  • 有工具支持状态图作为逻辑输入
  • 时钟信号是隐含的

状态表设计要点

  • 穷举方法,列出所有状态和输入的组合
  • 为每个可能的输入组合提供一列表示次态,一列表示输出
  • 状态表的规模随着状态数的增加呈指数增长
  • 状态表的规模随输入数的增加呈指数增长