5 / 24 · 概念
在时钟沿分析寄存器传送
区分旧状态与下一状态,并追踪使能信号如何保持已存储的值。
课时内容可免费阅读,选课后可保存学习进度。
所有寄存器读取的都是旧状态
首先找出必须跨周期保存的信息。累加器、已采集的操作数、循环计数和输出有效标志都属于状态。当前累加器与操作数之和属于组合逻辑值。仅仅写入变量并不能说明如何存储它;必须规定哪个事件采集它的值。
这个累加器仅在 en 有效的上升沿将 x 加入其中。en 为低时,累加器保持原值。九位中间结果使加法位宽明确;选择其低八位就定义了模 256 行为。always_ff 中的非阻塞赋值根据当前时钟沿读取的数值安排下一状态。当涉及多个寄存器时,若把该代码块理解成即时执行的软件赋值,就会产生错误。
logic [7:0] acc;
logic [8:0] next_sum;
assign next_sum = {1'b0, acc} + {1'b0, x};
always_ff @(posedge clk) begin
if (rst) acc <= 8'd0;
else if (en) acc <= next_sum[7:0];
end复位是同步的,且优先级高于使能。en 为低时省略时序赋值,表示寄存器保持原值。组合逻辑路径上省略赋值,却可能推导出非预期的锁存器。对于组合的下一状态逻辑,应先给出默认值,再根据具体条件覆盖它们。
| 时钟沿 | rst | en | x | 旧 acc | 新 acc |
|---|---|---|---|---|---|
| 0 | 1 | 1 | 9 | 未知 | 0 |
| 1 | 0 | 1 | 7 | 0 | 7 |
| 2 | 0 | 0 | 100 | 7 | 7 |
| 3 | 0 | 1 | 250 | 7 | 1 |
在时钟沿 2,输入端出现的 100 并未被接收。在时钟沿 3,7+250=257 缩窄后变为 1。当后续把 en 改为 valid AND ready 时,区分“呈现”与“接收”仍然至关重要。
对于 a<=x; b<=a;,旧 a=5 且 x=9 时,会得到新 a=9、b=5。如果希望 b 接收 9,就应把它的输入连接到 x。先填完旧状态一列,再同时计算所有下一状态的值;这样可以发现数据与控制之间相差一个周期的问题。
自己试试
初始 a=4、b=0。输入 x 先为 8,再为 12,每个时钟沿都执行 a<=x; b<=a。第二个时钟沿后 a 和 b 分别是多少?
阅读解释
第一个时钟沿后,a=8、b=4。第二个时钟沿后,a=12、b=8。b 的每次更新都使用旧 a,因此 x=12 不会在一个时钟沿内穿过两个寄存器。