有限状态机(finite-state machine, FSM)
想想红绿灯。在任何一刻,它都恰好处于某一种状态——绿灯、黄灯或红灯——而且它清楚地知道接下来会怎样:绿灯让位给黄灯,黄灯转为红灯,红灯再回到绿灯。它绝不会停在半绿的状态,也绝不会从绿灯直接跳到红灯。这就是有限状态机的全部精髓:一段逻辑,它总是恰好处于一组数量不多、固定的具名状态之一,并在某件事情发生时——按下一个按钮、定时器到时、一个时钟跳动——沿着定义明确的转移在这些状态之间移动。
有限状态机是控制逻辑的标准范式——也就是数字电路中决定下一步该做什么、而非埋头计算数字的那部分。你用三样东西来描述它:状态的集合、在状态间移动的规则(通常取决于当前状态加上当前输入),以及每个状态产生的输出。在硬件中,"我现在处于哪个状态"这份记忆存放在由触发器构成的寄存器里,每个时钟边沿更新一次;而一块组合逻辑则根据当前状态和输入计算出下一个状态和输出。正是这种划分——保存状态的时序元件馈送组合判决逻辑——让有限状态机成为构建控制器、协议处理器和序列发生器的一种干净、可复用的方式。
有限状态机有两种经典的形式,区别在于输出从何而来。在摩尔(Moore)型机器中,输出只取决于当前状态——读出状态,你就知道输出——这使它们稳定、易于推理,但它们要晚一个时钟才作出反应。在米利(Mealy)型机器中,输出取决于当前状态以及当前输入,因此它们能在同一周期内响应,往往用更少的状态,代价是输出可能产生毛刺,或在周期中途随输入抖动而变化。一个好记的方法:摩尔型的输出标在状态上;米利型的输出标在转移上。
// Three-state controller, binary-encoded.
// next-state logic is combinational; the state register is clocked.
localparam IDLE = 2'd0, RUN = 2'd1, DONE = 2'd2;
reg [1:0] state, next;
always @(posedge clk or negedge rst_n) // sequential: hold the state
if (!rst_n) state <= IDLE; // reset to a known state
else state <= next;
always @(*) begin // combinational: choose next
next = state; // default: stay put
case (state)
IDLE: next = start ? RUN : IDLE;
RUN : next = done ? DONE : RUN;
DONE: next = IDLE;
default: next = IDLE; // recover from illegal states
endcase
end一个最简的三状态控制器——一个带时钟的寄存器保存状态,一块组合逻辑挑选下一个状态。复位和 `default` 分支让它始终停留在已知且合法的状态上。
"有限"是承重的关键词:这种机器拥有可数、固定数量的状态,而正是这一点让你能把它画成气泡加箭头的状态图,并对它做穷举式检查——每一个状态和转移都能被枚举出来、被推敲清楚。一旦加入无界的存储(一个能无限往上加的计数器、一个栈),你就离开了有限状态机的范畴,进入了一种更强大的计算模型。