22 / 24 · Esercitazione
Laboratorio finale: FIFO e calcolatrice in streaming a due stadi
Collega una FIFO di ingresso con profondità due, due stadi elastici e uno scoreboard.
Le lezioni sono gratuite. Iscriviti per salvare i progressi.
Combina memorizzazione, calcolo e consegna
Il progetto finale ha una FIFO di ingresso a due elementi e due stadi elastici di calcolo. Il primo stadio memorizza la somma a nove bit a+b; il secondo memorizza 3×sum modulo 256. I tag seguono ogni valore. La capacità totale è di quattro transazioni. La contropressione si propaga dall'uscita mentre le posizioni vuote possono ancora riempirsi. Presumi un solo clock, una FIFO registrata, rimozione/inserimento simultanei e nessun passaggio diretto in uscita.
Salva manualmente capstone-model.mjs ed esegui node capstone-model.mjs. Calcola tutti i segnali ready e i valori successivi degli stadi dallo stato precedente prima di aggiornare FIFO e registri. L'array JavaScript è una coda funzionale, non HDL sintetizzabile.
import assert from 'node:assert/strict';
const input = [[0,0],[1,2],[250,10],[255,255],
[128,128],[17,240],[90,90],[4,8]];
const q = [], expected = [], seen = [];
let s1 = null, s2 = null, issued = 0, delivered = 0;
for (let edge = 0; edge < 50; edge++) {
const ready = edge >= 25 || ![2,3,4].includes(edge % 7);
const old1 = s1, old2 = s2;
const r2 = old2 === null || ready;
const r1 = old1 === null || r2;
const pop = q.length > 0 && r1;
const inReady = q.length < 2 || pop;
if (old2 !== null && ready) {
assert.deepEqual(old2, expected.shift());
seen.push(old2.y);
delivered++;
}
const n2 = r2 ? (old1 === null ? null :
{ tag: old1.tag, y: old1.sum * 3 % 256 }) : old2;
const n1 = r1 ? (pop ?
{ tag: q[0].tag, sum: q[0].a + q[0].b } : null) : old1;
if (pop) q.shift();
if (issued < input.length && inReady) {
const [a,b] = input[issued];
q.push({ tag: issued, a, b });
expected.push({ tag: issued, y: (3*a + 3*b) % 256 });
issued++;
}
s1 = n1; s2 = n2;
if (old2 !== null && !ready) assert.deepEqual(s2, old2);
assert.ok(q.length <= 2);
assert.equal(issued - delivered,
q.length + Number(s1 !== null) + Number(s2 !== null));
}
assert.equal(issued, input.length);
assert.equal(delivered, input.length);
assert.deepEqual(seen, [0,9,12,250,0,3,28,36]);
assert.equal(expected.length + q.length, 0);
assert.equal(s1, null); assert.equal(s2, null);
console.log('CAPSTONE PASS: 8 ordered outputs, drained');| Tag | a,b | Risultato esteso | y |
|---|---|---|---|
| 2 | 250,10 | 780 | 12 |
| 3 | 255,255 | 1530 | 250 |
| 5 | 17,240 | 771 | 3 |
Il primo ingresso entra nella FIFO al fronte 0, in s1 al fronte 1 e in s2 al fronte 2. Gli stalli della destinazione ai fronti 2,3,4 ritardano la consegna al fronte 5. La latenza senza stalli è di tre fronti; questa transazione ne richiede cinque. Altro spazio vuoto si riempie mentre s2 mantiene il proprio contenuto.
La coda di riferimento calcola i valori attesi soltanto all'accettazione. Confronta tag e risultati alla consegna e verifica l'occupazione a ogni fronte. Dopo il fronte 25, completa tutto il lavoro. L'esecuzione Node verifica otto risultati ordinati; i file SystemVerilog seguenti esercitano indipendentemente registri FIFO e pipeline effettivi.
Costruisci e simula l'RTL
Scarica dp_stream_calculator.sv e tb_dp_stream_calculator.sv in una cartella. L'interfaccia a,b,tag senza segno a otto bit accetta su in-valid/in-ready e consegna y con il proprio tag su out-valid/out-ready. Le somme a nove bit e i valori scalati a undici bit vengono ridotti soltanto all'uscita. Reset svuota la memoria e sopprime i trasferimenti.
Esegui con Icarus Verilog installato:
iverilog -g2012 -Wall -s tb_dp_stream_calculator -o dp-test.vvp dp_stream_calculator.sv tb_dp_stream_calculator.sv
vvp dp-test.vvpLa verifica dell'autore ha compilato e simulato questi file con successo:
RTL PASS: accepted=527 delivered=523 canceled=4 stalls=517 full_replace=64 wraps=262 reset_with_work=1 zero=3Il testbench verifica aritmetica, tag, ordine, stalli, sostituzione a pieno, ritorno dei puntatori all'inizio, annullamento di quattro elementi al reset e completamento del transito. Cambia la durata degli stalli e confronta la latenza con tre cicli senza stalli. Questo verifica la simulazione RTL con Icarus, non sintesi, temporizzazione fisica o esecuzione DDS.
Prova tu
Con una destinazione sempre pronta, a quale fronte viene trasferito tag0? Se la profondità FIFO diventa uno, che cosa accade alla latenza senza stalli e alla capacità totale?
Leggi la spiegazione
Tag0 viene trasferito al fronte 3 dopo l'accettazione a 0, s1 a 1 e s2 a 2. Mantenere la FIFO registrata conserva la latenza di tre fronti; la capacità diminuisce a 1+1+1=3 transazioni. Cambia il limite di profondità di input-ready e verifica di nuovo il modello.