6 / 20 · 實作
實作:有號 MAC 處理單元
以獨立模型檢查有效運算元、停頓與清除。
單元可免費閱讀,註冊課程即可儲存學習進度。
執行單一 PE 契約
將程式儲存為 pe-lab.mjs,並使用 Node.js 執行 node pe-lab.mjs。它不使用外部套件,並會印出 PE lab passed。這驗證的是算術與控制模型;不會編譯 SystemVerilog,也不表示已在 DDS 中執行。一般的兩項工作可視為 W=8、K=2、AW=17,而模型則使用寬位元整數作為參考。
PE 接收獨立的 A 與 B valid 旗標。只有兩者都為真時,才進行累加。轉送則依各運算元自身的 valid 旗標處理。後續課程會加入標籤,以確保兩個有效運算元屬於同一個歸約項。
import assert from 'node:assert/strict';
const pe = {acc:0,a:0,b:0,av:false,bv:false};
function edge({a=0,b=0,av=false,bv=false,
advance=true,clear=false,reset=false}={}) {
if (reset || clear) {
Object.assign(pe,{acc:0,a:0,b:0,av:false,bv:false});
} else if (advance) {
if (av && bv) pe.acc += a*b;
Object.assign(pe,{a,b,av,bv});
}
return {...pe};
}
edge({clear:true});
assert.equal(edge({a:-2,b:3,av:true,bv:true}).acc,-6);
const held={...pe};
assert.deepEqual(edge({a:99,b:99,av:true,bv:true,advance:false}),held);
assert.equal(edge({a:4,b:-5,av:true,bv:true}).acc,-26);
assert.equal(edge({a:8,b:8,av:true,bv:false}).acc,-26);
assert.equal(pe.av,true); assert.equal(pe.bv,false);
edge({clear:true,a:100,b:100,av:true,bv:true});
assert.equal(pe.acc,0); assert.equal(pe.av,false);
assert.equal(edge({a:-128,b:-128,av:true,bv:true}).acc,16384);
edge({reset:true,advance:false});
assert.deepEqual(pe,{acc:0,a:0,b:0,av:false,bv:false});
console.log('PE lab passed');預測並挑戰結果
第一組產生 −6。暫停會忽略呈現的 99 值,並保持所有狀態。下一組有效配對貢獻 −20,累積到 −26。未配對的 A 權杖會轉送,但不執行 MAC。clear 優先於同時出現的有效配對;之後最小值×最小值產生 16384。即使 advance 為假,reset 仍會清除有效狀態。
使用明確的有號 product 與 addend 訊號,將相同優先順序轉成 always_ff。模擬陣列時,讀取舊狀態,並寫入獨立的下一狀態。直接原地更新 PE 物件,可能意外讓權杖在一個邊緣穿越多個 PE。
將累加條件從 AND 改成 OR。未配對權杖的斷言應失敗。也可嘗試只讓累加器受 advance 控制,卻允許轉送持續移動。解釋各斷言保護哪項契約;僅看到通過訊息,並不是完整的學習成果。
分別記錄呈現與已消費的運算元:暫停時的九十九值在介面上可見,卻從未被消費。包裝層必須保留下一個排程項,直到 advance 恢復。傳回狀態副本可保留較早觀察。將檢查轉為波形測試平台時,除了累加器,也檢視轉送 valid 旗標。
實際 RTL:有號 MAC PE
將附件 signed_mac_pe.sv、systolic_2x2.sv、tb_systolic_2x2.sv 一起儲存。前兩檔為可合成 RTL;測試平台只用於模擬。PE 在累加前,將完整 2W 位元乘積符號延伸至 AW。W=8,K=4 檢查使用 AW=18,涵蓋 65536、−65024 與 64516。有序 k 標籤透過 protocol_error 拒絕不符項。
優先順序為 reset、clear、advance。Clear 在第一個資料邊緣前完成。各上升緣後觀察更新的累加器;鄰近單元在下一個 advance 邊緣消費暫存器轉送。暫停保持各值、valid 旗標、標籤與 count。兩次 clear 之間執行一項工作,沒有輸出量化或 DDS 整合。
安裝 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預期 RTL PASS:;失敗以 $fatal 結束。將 addend 改成零延伸,重現負矩陣失敗。解釋第一個不符 PE 的累加器,還原符號延伸並重新執行。分別保留 Node 與 HDL 紀錄。
自己試試看
在 (−2,3) 與 (4,−5) 之間插入有效配對 (0,7)。總和是多少?有效的零與無效權杖有何不同?
查看解說
總和為 −26。有效的零仍會消費真實的 k 項,並推進項目計數與標籤。無效權杖不會消費任何項。對三項工作,應相應更新 K、位元寬度分析與完成控制。