状态机

必考,不用想了。一般都是手写代码/代码填空。看好一二三段状态机。

关于两段式和三段式的例子,可以看看另外一篇文章:两段式状态机与三段式状态机

概述

什么是有限状态机?

  • 有限状态机是由寄存器组和组合逻辑构成的硬件时序电路;
  • 其状态(即由寄存器组的1和0的组合状态所构成的有限个状态)只能在同一时钟跳变沿的情况下才能从一个状态转向另一个状态;
  • 究竟转向哪一状态不但取决于各个输入值,还取决于当前状态。
  • 状态机可产生在时钟跳变沿时刻进行开关的复杂的控制逻辑,是数字逻辑的控制核心。

有限状态机三要素:

  • 状态(当前状态,下一个状态);
  • 输入信号(事件);
  • 输出控制信号(相应操作)。

Mealy

状态是否改变、怎样改变还将取决于产生下一状态的组合逻辑F的输出,F是当前状态和输入信号的函数。

我们把这种时序逻辑的输出不但取决于状态还取决于输入的状态机称为Mealy状态机

Mealy状态机示意图

Moore

有些时序逻辑电路的输出只取决于当前状态,即输出信号=G (当前状态),这样的电路就称为Moore状态机。

Moore状态机示意图

如何描述下面的状态机?

状态转移图

一段式

顾名思义,全模块只有一个always在该模块中既描述状态转移,又描述状态的输入和输出

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
70
module fsm (
Clock,
Reset,
A,
K2,
K1,
state
);

input Clock, Reset, A;
output reg K2, K1;
output reg [1:0] state;

parameter
Idle = 2'b00,
Start = 2'b01,
Stop = 2'b10,
Clear = 2'b11;

always @(posedge Clock)
if (!Reset) begin
state <= Idle;
K2 <= 0;
K1 <= 0;
end
else
case (state)
Idle:
if (A) begin
state <= Start;
K1 <= 0;
end
else begin
state <= Idle;
K2 <= 0;
K1 <= 0;
end

Start:
if (!A) state <= Stop;
else state <= Start;

Stop:
if (A) begin
state <= Clear;
K2 <= 1;
end
else begin
state <= Stop;
K2 <= 0;
K1 <= 0;
end

Clear:
if (!A) begin
state <= Idle;
K2 <= 0;
K1 <= 1;
end
else begin
state <= Clear;
K2 <= 0;
K1 <= 0;
end

default: state <= 2'bxx;
endcase

endmodule

两段式

何谓两段式?这两段是什么?

  • 同步时序描述状态转移
  • 组合逻辑判断状态转移条件、描述状态转移规律及其输出

所以,从一段式改成两段式,我们只要:

  • 将次态单独拆分出来:
1
2
3
4
always @(posedge Clock) begin
if (!Reset) state <= Idle;
else state <= nextstate;
end
  • 用组合逻辑描述输出:改写一下状态跳转和逻辑输出部分;
  • 无了。

三段式

三段式在两段式的基础上,将状态输出单独分离出来,使程序结构更加直观。

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
module fsm (
Clock,
Reset,
A,
K2,
K1
);
input Clock, Reset, A;
output reg K2, K1;

reg [1:0] state,nextstate;

parameter
Idle = 2'b00,
Start = 2'b01,
Stop = 2'b10,
Clear = 2'b11;

//每一个时钟沿产生一次可能的状态变化
always @(posedge Clock)
if (!Reset) state <= Idle;
else state <= nextstate;

//------ 产生下一状态的组合逻辑 ----
always @(state or A)
case (state)
Idle:
if (A) nextstate = Start;
else nextstate = Idle;

Start:
if (!A) nextstate = Stop;
else nextstate = Start;

Stop:
if (A) nextstate = Clear;
else nextstate = Stop;

Clear:
if (!A) nextstate = Idle;
else nextstate = Clear;

default: nextstate = 2'bxx;
endcase

//-- 产生输出K1的组合逻辑 --------------
always @(state or Reset or A)
if (!Reset) K1 = 0;
else if (state == Clear && !A)
//从Clear转向Idle
K1 = 1;
else K1 = 0;
//产生输出K2的组合逻辑
always @(state or Reset or A)
if (!Reset) K2 = 0;
else if (state == Stop && A) //转向Clear
K2 = 1;
else K2 = 0;
endmodule

一个非常棒的例子

Verilog状态机常见三种写法

设计思路

  • 逻辑抽象。得出状态转换图,把给出的一个实际逻辑关系表示为时序逻辑函数
  • 状态化简。将等价状态尽可能地合并,以得到最简的状态转换图
  • 状态分配。采用合适的编码方式,来优化电路结构

关于不同的编码方式,可以看看另外一篇文章:
Verilog中状态机的不同编码方式

后记

2025.04.13竞赛里用到了状态机,本来想再看看笔记的,结果点进CSDN发现以前免费看的文章现在要VIP才能看了。你妈福的,吃相太难看了。