10 / 20 · 實作
實作:錯時的 2×2 陣列
模擬一邊緣轉送延遲,並檢查每個中間累加器。
單元可免費閱讀,註冊課程即可儲存學習進度。
讓相同 k 值相遇
在邏輯邊緣 k+i,將 A(i,k) 注入左邊界;在 k+j,將 B(k,j) 注入上邊界。暫存器轉送在水平方向增加 j 個邊緣,垂直方向增加 i 個邊緣。因此兩個運算元在 k+i+j 抵達 PE(i,j)。這種交錯注入稱為輸入錯時。
A=[[1,2],[3,4]]、B=[[5,6],[7,8]],clear 在 E0 前完成。邊界排程如下:
| 邊緣 | 左側列 0 | 左側列 1 | 上方欄 0 | 上方欄 1 |
|---|---|---|---|---|
| E0 | 1(k0) | 無效 | 5(k0) | 無效 |
| E1 | 2(k1) | 3(k0) | 7(k1) | 6(k0) |
| E2 | 無效 | 4(k1) | 無效 | 8(k1) |
| E3 | 無效 | 無效 | 無效 | 無效 |
將下列程式儲存為 schedule-lab.mjs,並執行 node schedule-lab.mjs。不需要套件,會印出 Schedule lab passed。無效權杖為 null;有效權杖包含 value 與 k。此單一工作模型省略 job 標籤,但明確檢查 k。
import assert from 'node:assert/strict';
const A=[[1,2],[3,4]],B=[[5,6],[7,8]],N=2,K=2;
const fresh=()=>({a:null,b:null,acc:0,count:0});
let grid=Array.from({length:N},()=>Array.from({length:N},fresh));
const expected=[[[5,0],[0,0]],[[19,6],[15,0]],
[[19,22],[43,18]],[[19,22],[43,50]]];
const token=(value,k)=>({value,k});
for(let t=0;t<K+2*N-2;t++) {
const next=grid.map(r=>r.map(p=>({...p})));
for(let i=0;i<N;i++) for(let j=0;j<N;j++) {
const ka=t-i,kb=t-j;
const a=j?grid[i][j-1].a:(ka>=0&&ka<K?token(A[i][ka],ka):null);
const b=i?grid[i-1][j].b:(kb>=0&&kb<K?token(B[kb][j],kb):null);
const p=next[i][j];p.a=a;p.b=b;
if(a&&b){assert.equal(a.k,b.k);assert.equal(a.k,p.count);
p.acc+=a.value*b.value;p.count++;}
}
grid=next;
assert.deepEqual(grid.map(r=>r.map(p=>p.acc)),expected[t]);
}
assert.deepEqual(grid.map(r=>r.map(p=>p.count)),[[2,2],[2,2]]);
console.log('Schedule lab passed');各 PE 讀舊狀態、寫下一狀態。原地迭代會錯誤允許一邊緣內多次轉送。
E0 後,只有 C(0,0) 累加器為五。E1 將它完成至十九,並讓鄰近單元分別開始於六與十五。E2 將鄰近結果完成為二十二與四十三,最後一個 PE 則只有十八。E3 加入三十二,產生五十。
將列注入從 t−i 改為 t。標籤斷言應偵測未對齊。完成需要四個 advance 邊緣,且每個 count 都等於二。不含初始化與串列輸出傳輸。此可執行模型驗證指定排程,不宣稱 RTL 或 DDS 已執行。
實際 RTL:暫存器式 2×2 網格
附件 systolic_2x2.sv 連接 signed_mac_pe.sv 的四個實例,限制為 N=K=2。A 向右、B 向下,經帶 valid 與 k 標籤的暫存器連線移動。外部邊界供應端執行錯時;測試平台的 step 工作直接驅動 E0..E3 排程。Clear 在 E0 前完成,且沒有額外乘法器管線。
一起儲存全部三個附件,並執行 Icarus Verilog:
iverilog -g2012 -s tb_systolic_2x2 -o systolic.vvp signed_mac_pe.sv systolic_2x2.sv tb_systolic_2x2.sv
vvp systolic.vvp邊緣後矩陣依序為 [[5,0],[0,0]]、[[19,6],[15,0]]、[[19,22],[43,18]]、[[19,22],[43,50]]。Done 只在 E3 後成立。兩次暫停產生四個 advance 邊緣與六個實體運算邊緣。檢查也涵蓋 [[10,9],[−6,3]]、完整狀態保持與工作中途重設。預期 RTL PASS:。
RTL 修改練習可將一個暫存器運算元連線替換為組合路徑。預測第一個標籤對齊或中間總和失敗,比較紀錄,再還原暫存器。擴展此網格至 N×N,必須一起重新檢視接線、錯時、位元寬度、標籤與完成。
自己試試看
E2 後,PE(1,1) 的累加器與剩餘項各是什麼?為何邊界輸入無效,它仍會在 E3 改變?
查看解說
累加器為 3×6 產生的 18,剩餘 4×8=32。這些運算元在內部轉送暫存器中,於 E3 抵達;無效邊界不會立即清空陣列。