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.
As aulas podem ser lidas gratuitamente. Inscreva-se para salvar o progresso.
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.
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');| Etiqueta | a,b | Resultado amplo | y |
|---|---|---|---|
| 2 | 250,10 | 780 | 12 |
| 3 | 255,255 | 1530 | 250 |
| 5 | 17,240 | 771 | 3 |
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:
iverilog -g2012 -Wall -s tb_dp_stream_calculator -o dp-test.vvp dp_stream_calculator.sv tb_dp_stream_calculator.sv
vvp dp-test.vvpA verificação do autor compilou e simulou estes arquivos com sucesso:
RTL PASS: accepted=527 delivered=523 canceled=4 stalls=517 full_replace=64 wraps=262 reset_with_work=1 zero=3O 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.