Altifigence Academy

22 / 24 · Prática

Laboratório final: FIFO e calculadora em fluxo de dois estágios

Conecte uma FIFO de entrada de profundidade dois, dois estágios elásticos e um scoreboard.

Combine armazenamento, cálculo e entrega

O projeto final tem uma FIFO de entrada de duas posições e dois estágios elásticos de cálculo. O primeiro estágio armazena a soma de nove bits a+b; o segundo armazena 3×sum módulo 256. As etiquetas acompanham cada valor. A capacidade total é de quatro transações. A contrapressão se propaga da saída enquanto posições vazias ainda podem ser preenchidas. Suponha um clock, FIFO registrada, pop/push simultâneos e ausência de passagem direta para a saída.

Salve manualmente capstone-model.mjs e execute node capstone-model.mjs. Calcule todas as prontidões e os valores dos próximos estágios a partir do estado anterior antes de atualizar a FIFO e os registradores. O arranjo JavaScript é uma fila funcional, não HDL sintetizável.

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');
Etiquetaa,bResultado amploy
2250,1078012
3255,2551530250
517,2407713

A primeira entrada entra na FIFO na borda 0, em s1 na borda 1 e em s2 na borda 2. Pausas do destino nas bordas 2,3,4 atrasam sua entrega até a borda 5. A latência sem pausas é de três bordas; essa transação leva cinco. Outros armazenamentos vazios se preenchem enquanto s2 é mantido.

A fila de referência calcula os valores esperados apenas na aceitação. Compare etiquetas e resultados na entrega e verifique a ocupação em cada borda. Após a borda 25, esvazie tudo. A execução em Node verifica oito resultados ordenados; os arquivos SystemVerilog abaixo exercitam independentemente registradores reais de FIFO e pipeline.

Compile e simule o RTL

Baixe dp_stream_calculator.sv e tb_dp_stream_calculator.sv para uma pasta. A interface a,b,tag de oito bits sem sinal aceita por in-valid/in-ready e entrega y com sua etiqueta por out-valid/out-ready. Somas de nove bits e valores escalados de onze bits têm a largura reduzida apenas na saída. Reset esvazia o armazenamento e suprime transferências.

Execute com Icarus Verilog instalado:

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

A verificação do autor compilou e simulou estes arquivos com sucesso:

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

O testbench verifica aritmética, etiquetas, ordem, pausas, substituição com fila cheia, retorno dos ponteiros ao início, cancelamento de quatro itens por reset e esvaziamento. Mude a duração da pausa e compare a latência com três ciclos sem pausas. Isso verifica simulação RTL com Icarus, não síntese, temporização física nem execução no DDS.

Experimente

Com um destino sempre pronto, em qual borda tag0 é transferida? Se a profundidade da FIFO passar a um, o que acontece com a latência sem pausas e a capacidade total?

Ler a explicação

Tag0 é transferida na borda 3 após aceitação em 0, s1 em 1 e s2 em 2. Manter a FIFO registrada preserva a latência de três bordas; a capacidade diminui para 1+1+1=3 transações. Mude o limite de profundidade de input-ready e verifique novamente o modelo.

Lesson files

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

Sua escolha vale neste navegador. Altere-a a qualquer momento no rodapé.