28 / 37 · 概念
状态机:分离状态、转移与输出
从规格表编写 FSM,比较 Moore、Mealy 输出、非法状态与请求策略。
课时内容可免费阅读,选课后可保存学习进度。
状态只概括过去输入中必要的信息
当输出不能只由当前输入决定时,就需要定义存储状态。无需保存全部输入历史,只需区分那些会影响未来行为的差异。
考虑管理任务启动与完成的控制器。IDLE 表示等待请求,BUSY 表示处理中,DONE 表示持续一个周期的完成状态。
| 当前状态 | 条件 | 下一状态 | busy | done |
|---|---|---|---|---|
| IDLE | start=0 | IDLE | 0 | 0 |
| IDLE | start=1 | BUSY | 0 | 0 |
| BUSY | work_done=0 | BUSY | 1 | 0 |
| BUSY | work_done=1 | DONE | 1 | 0 |
| DONE | 无条件 | IDLE | 0 | 1 |
busy 和 done 是当前状态的输出。例如在 BUSY 中观察到完成的边沿之后,状态变为 DONE,done 才变成 1。这属于 Moore 输出。
每列记录一个上升沿上升沿 时钟从 0 变为 1 的瞬间。它不同于表示整个 CLK=1 区间的电平。了解更多的观察结果。输入取自边沿前,名称带 after 的状态取自更新后。列的排列表示采样顺序,并非描绘物理传播延迟传播延迟 从输入变化到输出稳定为正确值所需的时间。逻辑表达式等价与时间特性是两回事。了解更多。初始状态为 IDLE。接受 work_done 的边沿之后,状态变为 DONE,done 为 1。DONE 的下一状态始终为 IDLE,与 start 无关。
查看波形数据
| 信号 | 波形 | 总线值 |
|---|---|---|
| edge | 2345 | E0 → E1 → E2 → E3 |
| start | 10.1 | |
| work_done | 0.10 | |
| state after | 2.34 | BUSY → DONE → IDLE |
| busy after | 1.0. | |
| done after | 0.10 |
将转移与存储分开的 RTL
typedef enum logic [1:0] {IDLE, BUSY, DONE} state_t;
state_t state, next_state;
always_comb begin
next_state = state;
case (state)
IDLE: if (start) next_state = BUSY;
BUSY: if (work_done) next_state = DONE;
DONE: next_state = IDLE;
default: next_state = IDLE;
endcase
end
always_ff @(posedge clk)
if (rst) state <= IDLE;
else state <= next_state;
assign busy = (state == BUSY);
assign done = (state == DONE);这是用于说明控制结构的 SystemVerilog 示例。所连接处理器的 work_done 生成与输入同步仍需另行实现。
规格中容易遗漏的问题
上述电路在 BUSY 或 DONE 时忽略 start。若要求在完成的同时接受新请求,必须先修改转移表。Mealy 输出同时使用状态与当前输入,能够更快响应,但也必须审查组合输出路径的时序与毛刺。状态采用二进制还是独热独热码 多个位中恰好只有一个为 1 的表示。若也允许全部为 0,则应称为 one-hot-or-zero。了解更多编码,与 Moore/Mealy 分类是两个不同决定。
自己试试
在 DONE 状态,start=1 持续一个周期。该 FSM 会立即开始新任务吗?若要允许连续任务,需要改变什么?
阅读解释
上述转移表规定 DONE→IDLE,因此不会接受该请求。需要改为 DONE 中若 start 有效则进入 BUSY,或设计保存请求的协议。同时应按新规格验证 done 的持续时间与请求接受时刻。