15 / 20 · 实验
实验:背压与复位
执行全局暂停、结果保持,以及被中断任务的复位。
课时内容可免费阅读,选课后可保存学习进度。
将逻辑时间作为整体暂停
教学阵列使用全局 advance。只有下一逻辑步骤所需的一整组输入准备好时,边界调度器和所有 PE 才移动。计划为无效的通道不需要真实操作数。只推进一条数据流会破坏输入错位。独立停顿的连接需要额外缓冲和匹配规则,超出了此基础设计。
输出使用独立的 valid/ready 约定。结果准备好后,保持 valid、data 和 job 稳定,直到 valid&&ready 的时钟沿恰好传送一次。只要旧结果仍待交付,简单封装就不开始新任务。如果有足够的结果存储,使用方是否 ready 不必阻止计算。
将以下内容保存为 stall-lab.mjs,运行 node stall-lab.mjs。它为两项 PE 加一个结果寄存器建模,不需要软件包,并输出 Stall/reset lab passed。
import assert from 'node:assert/strict';
let s;
function reset(){s={step:0,acc:0,valid:false,data:0,job:7};}
const pairs=[[-2,3],[4,-5]];
function tick({advance=true,ready=false,rst=false}={}){
if(rst){reset();return null;}
if(s.valid){if(!ready)return null;
const out={data:s.data,job:s.job};s.valid=false;return out;}
if(advance&&s.step<pairs.length){
const [a,b]=pairs[s.step];s.acc+=a*b;s.step++;
if(s.step===pairs.length){s.data=s.acc;s.valid=true;}}
return null;
}
reset();tick();assert.equal(s.acc,-6);
const held={...s};tick({advance:false});assert.deepEqual(s,held);
tick();assert.equal(s.data,-26);assert.equal(s.valid,true);
const blocked={...s};tick({ready:false});tick({ready:false});
assert.deepEqual(s,blocked);
assert.deepEqual(tick({ready:true}),{data:-26,job:7});
assert.equal(tick({ready:true}),null);
reset();tick();tick({rst:true,advance:false});
assert.deepEqual(s,{step:0,acc:0,valid:false,data:0,job:7});
tick();tick();assert.equal(s.data,-26);
console.log('Stall/reset lab passed');理解检查
暂停保持第一个和 −6 及调度位置。第二项产生 −26。两个受阻输出时钟沿保持结果;ready 时钟沿将其传送一次。未完成任务期间复位,会清除累加器、位置和结果有效状态,因此恢复后从头开始任务。
在四步 2×2 调度中加入两次全局暂停,会得到四个推进时钟沿和六个实际时钟沿。结果和已使用 k 列表必须与无停顿运行一致。逻辑完成公式保持不变。
这是同步控制参考。物理复位同步和跨时钟域需要单独设计。被复位中止的任务绝不能报告成功完成;重新开始前应清除上游缓冲。模型成功不代表 RTL、已安装应用或硬件验收通过。
自己试试
保持 valid=1、ready=0 三个时钟沿,然后置位 ready。哪些信号必须保持?发生几次传送?如果等待时发生复位,应怎样处理?
阅读解释
保持 data、job 和 valid。等待期间传送零个结果;ready 时钟沿传送一个。复位丢弃待交付的有效状态,不得将该任务作为成功任务交付。取消通知需要独立的状态约定。