Altifigence Academy

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.

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.

javascript
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');
Taga,bRisultato estesoy
2250,1078012
3255,2551530250
517,2407713

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:

text
iverilog -g2012 -Wall -s tb_dp_stream_calculator -o dp-test.vvp dp_stream_calculator.sv tb_dp_stream_calculator.sv
vvp dp-test.vvp

La verifica dell'autore ha compilato e simulato questi file con successo:

text
RTL PASS: accepted=527 delivered=523 canceled=4 stalls=517 full_replace=64 wraps=262 reset_with_work=1 zero=3

Il 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.

Lesson files

capstone-model.mjs ↓dp_stream_calculator.sv ↓tb_dp_stream_calculator.sv ↓

La scelta vale per questo browser. Puoi modificarla in qualsiasi momento dal piè di pagina.