19 / 20 · Übung
Abschlussprojekt: ein Verifikationsmodell für gekachelte N×N-Arrays
Kombinieren Sie beliebiges N und K mit Auffüllung und Pausen und vergleichen Sie mit einer unabhängigen Referenz.
Lektionen sind frei lesbar. Schreibe dich ein, um deinen Fortschritt zu speichern.
Das vollständige Modell zusammensetzen
Das Abschlussprojekt übernimmt A der Form M×K und B der Form K×P auf einem N×N-Gitter. Jede räumliche Kachel beginnt leer, aufgefüllte Operanden sind gültige Nullen und Schreibzugriffe werden nach Koordinaten maskiert. Nur ein Auftrag belegt eine Kachel und globale Pausen halten die logische Zeit an. Ausgabequantisierung bleibt ein separater Test nach der breiten Summe.
Speichern Sie dies als capstone-lab.mjs und führen Sie node capstone-lab.mjs aus. Es sind keine Pakete erforderlich. Die Eingaben sind kleine Ganzzahltestfälle im exakten Bereich von JavaScript Number; größere Bereiche benötigen BigInt und ausdrückliche Breitenprüfungen. Dies prüft ein Node-Arithmetik-/Ablaufmodell unabhängig von RTL- oder DDS-Ausführung.
import assert from 'node:assert/strict';
function golden(A,B){return A.map(r=>B[0].map((_,j)=>
r.reduce((s,a,k)=>s+a*B[k][j],0)));}
function solve(A,B,N,pauses=new Set()){
const M=A.length,K=A[0].length,P=B[0].length;
assert.ok(N>=1&&Number.isInteger(N)&&K>=1);assert.equal(B.length,K);
assert.ok(A.every(r=>r.length===K)&&B.every(r=>r.length===P));
const C=Array.from({length:M},()=>Array(P).fill(null));
let advances=0,physical=0;
for(let r0=0;r0<M;r0+=N)for(let c0=0;c0<P;c0+=N){
const job=r0*P+c0;
let g=Array.from({length:N},()=>Array.from({length:N},()=>
({a:null,b:null,acc:0,count:0})));
const token=(value,k)=>({value,k,job});let t=0,p=0;
while(t<K+2*N-2){
if(pauses.has(p)){p++;continue;}
const next=g.map(r=>r.map(pe=>({...pe})));
for(let i=0;i<N;i++)for(let j=0;j<N;j++){
const ka=t-i,kb=t-j;
const a=j?g[i][j-1].a:(ka>=0&&ka<K?
token(r0+i<M?A[r0+i][ka]:0,ka):null);
const b=i?g[i-1][j].b:(kb>=0&&kb<K?
token(c0+j<P?B[kb][c0+j]:0,kb):null);
const pe=next[i][j];pe.a=a;pe.b=b;
if(a&&b){assert.equal(a.job,b.job);assert.equal(a.k,b.k);
assert.equal(a.k,pe.count);pe.acc+=a.value*b.value;pe.count++;}}
g=next;t++;p++;
}
for(let i=0;i<N;i++)for(let j=0;j<N;j++){
assert.equal(g[i][j].count,K);
if(r0+i<M&&c0+j<P){assert.equal(C[r0+i][c0+j],null);
C[r0+i][c0+j]=g[i][j].acc;}}
advances+=t;physical+=p;
}
return {C,advances,physical};
}
const A=[[1,2,3],[4,5,6],[7,8,9]],B=[[1,0,2],[0,1,0],[2,0,1]];
for(const N of [1,2,3])assert.deepEqual(
solve(A,B,N,new Set([1,2])).C,golden(A,B));
const run=solve(A,B,2,new Set([1,2]));
assert.deepEqual(run.C,[[7,2,5],[16,5,14],[25,8,23]]);
assert.equal(run.advances,20);assert.equal(run.physical,28);
assert.deepEqual(solve([[2,-1],[0,3]],[[4,5],[-2,1]],2).C,
[[10,9],[-6,3]]);
assert.deepEqual(solve([[-128]],[[-128]],1).C,[[16384]]);
console.log('Capstone lab passed');Die Sollfunktion kennt nur Matrixarithmetik. Der Löser verschiebt unabhängig markierte Tokens, prüft geordnete Terme und maskiert Schreibzugriffe. Bei N=2 benötigen vier Kacheln zwanzig advance-Flanken. Pausen an physischer Flanke eins und zwei jeder Kachel fügen acht Pausen hinzu, insgesamt achtundzwanzig physische Flanken. Initialisierung, Speicherladen und serialisierte Ausgabeübertragung sind ausgeschlossen.
Reichen Sie das Protokoll, die Spur verarbeiteter k-Werte einer Kachel, die Analyse vorzeichenbehafteter Breiten und den Entwurf einer valid/ready-Ergebnishülle ein. Erhalten Sie die Flankenregeln bei der Übertragung auf RTL. Beginnen Sie mit N=1,K=1 und 2×2, bevor Sie skalieren. Ergänzen Sie Quantisierung, erhaltene Teilsummen oder Doppelpufferung einzeln mit neuen ausdrücklichen Prüfungen.
Die drei Gittergrößen prüfen unterschiedliche Abbildungen: N=1 wiederholt Skalarprodukte ohne Versatz, N=2 prüft vier aufgefüllte Kacheln und N=3 nutzt eine vollständige Kachel. Alle müssen dieselbe mathematische Matrix erzeugen. Die Initialisierung von C mit null unterscheidet eine gültige Null von einer nicht ausgegebenen Ausgabe und erkennt doppelte Schreibzugriffe. Die aus der Kachel abgeleitete job-Nummer ist hier eindeutig; echtes RTL muss Tag-Breite und Wiederverwendungsregeln definieren. Versuchen Sie als Erweiterung M=2,K=3,P=1 mit von Hand berechneten Erwartungswerten. Das interne Gitter bleibt quadratisch, während die Ausgabematrix rechteckig ist. Prüfen Sie, dass jede Kachel das vollständige K verarbeitet und Schreibzugriffe außerhalb des Bereichs unterdrückt.
Selbst ausprobieren
Bestimmen Sie für das 3×3-Beispiel mit N=3 und Pausen an physischer Flanke eins und zwei die Anzahl der advance- und physischen Flanken. Was gilt, wenn die Messung eine vorhergehende Löschflanke enthält?
Erklärung lesen
Es gibt sieben advance-Flanken und neun physische Flanken im Rechenintervall einschließlich zweier Pausen. Mit einer vorhergehenden Löschflanke sind es zehn; Laden und Ausgabeübertragung bleiben ausgeschlossen.