11 / 24 · 实验
实验:追踪两级流水线与气泡
根据旧状态计算下一状态,并比较输出标签、数值和时钟沿。
课时内容可免费阅读,选课后可保存学习进度。
建立寄存器同时更新的模型
为两级函数 f(a,b)=3(a+b) 建立周期模型。每次迭代代表一个上升沿。首先使用旧 s2 的输出。然后根据旧 s1 计算新的第二级状态,再更新两级。如果在计算 s2 之前就更新 s1,就会错误地让输入在一个时钟沿内跨过两个寄存器。
手动将 pipeline-model.mjs 添加到项目,保存后,在 Node.js 终端中运行 node pipeline-model.mjs。在时钟沿 0 到 3 接收四个输入,再在时钟沿 4 和 5 排空流水线。依据此处始终 ready 的约定,所有输入都被接收。Null 表示空级,而不是数值零。有效的零结果仍然代表一个事务。
import assert from 'node:assert/strict';
const inputs = [[1,2], [250,10], [100,0], [255,255]];
let s1 = null, s2 = null;
const seen = [];
for (let edge = 0; edge < 6; edge++) {
if (s2 !== null) seen.push({ edge, ...s2 });
const next2 = s1 === null ? null : {
tag: s1.tag, y: (s1.sum * 3) % 256
};
const next1 = edge < inputs.length ? {
tag: edge, sum: inputs[edge][0] + inputs[edge][1]
} : null;
s1 = next1;
s2 = next2;
}
assert.deepEqual(seen, [
{ edge: 2, tag: 0, y: 9 },
{ edge: 3, tag: 1, y: 12 },
{ edge: 4, tag: 2, y: 44 },
{ edge: 5, tag: 3, y: 250 }
]);
assert.equal(s1, null);
assert.equal(s2, null);
console.log('PIPELINE PASS: 4 ordered results, latency=2');| 时钟沿 | 已接收的输入 | 已交付的输出 |
|---|---|---|
| 0 | tag0:1+2 | 无 |
| 1 | tag1:250+10 | 无 |
| 2 | tag2:100+0 | tag0:y9 |
| 3 | tag3:255+255 | tag1:y12 |
| 4 | 气泡 | tag2:y44 |
| 5 | 气泡 | tag3:y250 |
第二个事务保留和 260,并把 780 缩窄为 12。最后一个事务把 1530 缩窄为 250。明确比较时钟沿、标签和数值,既能发现时序错误,也能发现算术错误。排空气泡会清除两级,防止旧输出重复出现。
若要研究缺少输入的情况,可在选定的接收时钟沿插入 null,并仅在接收事务时递增标签。输出间隔会跟随气泡,而有效事务仍保持相隔两个时钟沿的延迟。此模型不包含输出背压。下一章会加入弹性行为。通过 Node 检查只验证这个状态模型,不代表 HDL 编译或 DDS 仿真运行已通过。
自己试试
如果时钟沿 1 没有输入,而 B、C、D 分别在时钟沿 2、3、4 被接收,标签 0 到 3 分别在哪个时钟沿交付?
阅读解释
A 在时钟沿 2 传送。B、C、D 在时钟沿 4、5、6 传送。时钟沿 3 是输出气泡。应按接收顺序分配标签 0、1、2、3,而不是使用实际时钟沿编号。
✓ 已学习