10 / 20 · Esercitazione
Laboratorio: array 2×2 con ingressi sfasati
Modella ritardi di inoltro di un fronte e verifica ogni accumulatore intermedio.
Le lezioni sono gratuite. Iscriviti per salvare i progressi.
Fai incontrare valori k uguali
Inserisci A(i,k) al confine sinistro al fronte logico k+i e B(k,j) a quello superiore a k+j. L'inoltro registrato aggiunge j fronti orizzontalmente e i verticalmente. Entrambi gli operandi raggiungono quindi PE(i,j) a k+i+j. Questo inserimento scaglionato è lo sfasamento degli ingressi.
Per A=[[1,2],[3,4]], B=[[5,6],[7,8]], clear termina prima di E0. Le pianificazioni al confine sono:
| Fronte | Sinistra riga 0 | Sinistra riga 1 | Alto colonna 0 | Alto colonna 1 |
|---|---|---|---|---|
| E0 | 1(k0) | non valido | 5(k0) | non valido |
| E1 | 2(k1) | 3(k0) | 7(k1) | 6(k0) |
| E2 | non valido | 4(k1) | non valido | 8(k1) |
| E3 | non valido | non valido | non valido | non valido |
Salva il codice seguente come schedule-lab.mjs ed esegui node schedule-lab.mjs. Non richiede pacchetti e stampa Schedule lab passed. I token non validi sono null; quelli validi trasportano value e k. Questo modello con un solo lavoro omette i tag job ma verifica esplicitamente 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');Ogni PE legge lo stato precedente e scrive quello successivo. Un'iterazione con aggiornamenti diretti consentirebbe erroneamente l'inoltro su più collegamenti in un solo fronte.
Dopo E0 soltanto l'accumulatore di C(0,0) vale cinque. E1 lo completa a diciannove e avvia i vicini a sei e quindici. E2 completa questi ultimi a ventidue e quarantatré, mentre il PE finale ha soltanto diciotto. E3 aggiunge trentadue producendo cinquanta.
Cambia l'inserimento delle righe da t−i a t. Un'asserzione sui tag deve rilevare il disallineamento. Il completamento richiede quattro fronti di avanzamento e ogni count uguale a due. Inizializzazione e trasferimento seriale di uscita sono esclusi. Questo modello eseguibile convalida la pianificazione dichiarata senza attestare l'esecuzione RTL o DDS.
RTL effettivo: la griglia 2×2 registrata
L'allegato systolic_2x2.sv collega quattro istanze da signed_mac_pe.sv, limitate a N=K=2. A si muove verso destra e B verso il basso tramite collegamenti registrati che trasportano valid e tag k. Il fornitore esterno al confine esegue lo sfasamento; il task step del testbench applica direttamente la pianificazione E0..E3. Clear termina prima di E0 e non esiste una pipeline aggiuntiva del moltiplicatore.
Salva insieme tutti e tre gli allegati ed esegui Icarus Verilog:
iverilog -g2012 -s tb_systolic_2x2 -o systolic.vvp signed_mac_pe.sv systolic_2x2.sv tb_systolic_2x2.sv
vvp systolic.vvpLe matrici dopo i fronti sono [[5,0],[0,0]], [[19,6],[15,0]], [[19,22],[43,18]] e [[19,22],[43,50]]. Done si attiva soltanto dopo E3. Due pause danno quattro fronti di avanzamento e sei fronti fisici di calcolo. Le verifiche coprono anche [[10,9],[−6,3]], mantenimento completo dello stato e reset durante il lavoro. Attenditi RTL PASS:.
Come esercizio di modifica RTL, sostituisci un collegamento registrato degli operandi con un percorso combinatorio. Prevedi il primo errore di allineamento dei tag o somma intermedia, confronta il log e ripristina il registro. Estendere questa griglia a N×N richiede di rivedere insieme cablaggio, sfasamento, larghezze, tag e completamento.
Prova tu
Dopo E2, qual è l'accumulatore di PE(1,1) e quale termine rimane? Perché cambia a E3 nonostante gli ingressi al confine non validi?
Leggi la spiegazione
L'accumulatore è 18 da 3×6, con 4×8=32 rimanente. Questi operandi sono nei registri interni di inoltro e arrivano a E3; confini non validi non svuotano istantaneamente l'array.