Altifigence Academy

22 / 24 · Travaux pratiques

TP final : FIFO et calculateur en flux à deux étages

Reliez une FIFO d’entrée de profondeur deux, deux étages élastiques et un tableau de suivi.

Combiner stockage, calcul et livraison

Le projet final a une FIFO d’entrée de deux éléments et deux étages élastiques de calcul. Le premier stocke la somme a+b sur neuf bits ; le second stocke 3×sum modulo 256. Les étiquettes suivent chaque valeur. La capacité totale est quatre transactions. La contre-pression se propage depuis la sortie tandis que les emplacements vides peuvent encore se remplir. Supposez une horloge unique, une FIFO enregistrée, un retrait/insertion simultané et aucun passage direct de sortie.

Enregistrez manuellement capstone-model.mjs et exécutez node capstone-model.mjs. Calculez toutes les disponibilités et valeurs suivantes des étages à partir de l’état précédent avant de mettre à jour FIFO et registres. Le tableau JavaScript est une file fonctionnelle, et non du HDL synthétisable.

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');
Étiquettea, bRésultat largey
2250, 1078012
3255, 2551530250
517, 2407713

La première entrée pénètre la FIFO au front 0, s1 au front 1 et s2 au front 2. Les blocages du récepteur aux fronts 2, 3, 4 retardent sa livraison au front 5. La latence sans blocage est trois fronts ; cette transaction en prend cinq. D’autres stockages vides se remplissent tandis que s2 conserve sa valeur.

La file de référence calcule les valeurs attendues uniquement à l’acceptation. Comparez étiquettes et résultats à la livraison et vérifiez l’occupation à chaque front. Après le front 25, vidangez tout. L’exécution Node vérifie huit résultats ordonnés ; les fichiers SystemVerilog ci-dessous testent indépendamment les registres réels de FIFO et de pipeline.

Construire et simuler le RTL

Téléchargez dp_stream_calculator.sv et tb_dp_stream_calculator.sv dans un même dossier. L’interface a, b, tag non signée sur huit bits accepte sur in-valid/in-ready et livre y avec son étiquette sur out-valid/out-ready. Les sommes sur neuf bits et les valeurs mises à l’échelle sur onze bits ne sont réduites qu’en sortie. Reset vide le stockage et supprime les transferts.

Exécutez avec Icarus Verilog installé :

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 vérification de l’auteur a compilé et simulé ces fichiers avec succès :

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

Le banc de test vérifie arithmétique, étiquettes, ordre, blocages, remplacement à plein, rebouclage des pointeurs, annulation de quatre éléments par reset et vidange. Modifiez la durée du blocage et comparez la latence aux trois cycles sans blocage. Cela vérifie la simulation RTL Icarus, et non la synthèse, la temporisation physique ou l’exécution DDS.

Essayez vous-même

Avec un récepteur toujours prêt, à quel front tag0 est-il transféré ? Si la profondeur FIFO devient un, que deviennent la latence sans blocage et la capacité totale ?

Lire l’explication

Tag0 est transféré au front 3 après acceptation à 0, s1 à 1 et s2 à 2. Conserver la FIFO enregistrée maintient une latence de trois fronts ; la capacité descend à 1+1+1=3 transactions. Modifiez la limite de profondeur d’input-ready et revérifiez le modèle.

Lesson files

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

Votre choix s’applique à ce navigateur. Modifiez-le à tout moment en bas de page.