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 邊緣傳輸一次。不完整工作期間重設,會清除累加器、位置與結果 valid 狀態,因此恢復時重新開始工作。
四步驟 2×2 排程加入兩次全域暫停,得到四個 advance 邊緣與六個實體邊緣。結果與已消費 k 清單必須符合無停頓執行。邏輯完成公式不變。
這是同步控制參考。實體重設同步與跨時脈域需要另外設計。被重設中止的工作絕不能回報成功完成;重新開始前清除上游緩衝器。模型成功不代表 RTL、已安裝應用程式或硬體驗收通過。
自己試試看
valid=1、ready=0 保持三個邊緣,再將 ready 設為成立。哪些訊號必須保持?發生多少傳輸?若等待時重設到達呢?
查看解說
保持 data、job 與 valid。等待期間傳輸零筆;ready 邊緣傳輸一筆。重設捨棄待處理有效狀態,不能將該工作當成成功交付。任何取消通知需要另外的狀態契約。