Altifigence Academy

22 / 24 · Практика

Итоговая лабораторная работа: FIFO и двухступенчатый потоковый вычислитель

Соедините входную FIFO глубины два, две эластичные ступени и таблицу ожидаемых результатов.

Совместите хранение, вычисление и выдачу

Итоговый проект имеет входную FIFO на две записи и две эластичные вычислительные ступени. Первая хранит девятибитную сумму a+b; вторая — 3×sum по модулю 256. Метки сопровождают каждое значение. Общая ёмкость — четыре транзакции. Обратное давление распространяется от выхода, пока пустые места могут заполняться. Предположим один такт, регистровую FIFO, одновременные pop/push и отсутствие сквозного прохода выхода.

Вручную сохраните capstone-model.mjs и выполните node capstone-model.mjs. Вычисляйте всю готовность и значения следующей ступени из старого состояния до обновления FIFO и регистров. Массив JavaScript — функциональная очередь, а не синтезируемый HDL.

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');
Меткаa,bШирокий результатy
2250,1078012
3255,2551530250
517,2407713

Первый вход входит в FIFO на фронте 0, s1 — на фронте 1, s2 — на фронте 2. Остановки приёмника на фронтах 2,3,4 задерживают выдачу до фронта 5. Задержка без остановок — три фронта; эта транзакция занимает пять. Другие пустые места заполняются, пока s2 удерживает данные.

Эталонная очередь вычисляет ожидаемые значения только при приёме. Сравнивайте метки и результаты при выдаче и проверяйте заполненность на каждом фронте. После фронта 25 опустошите всё. Запуск Node проверяет восемь упорядоченных результатов; файлы SystemVerilog ниже независимо проверяют реальные регистры FIFO и конвейера.

Соберите и симулируйте RTL

Загрузите dp_stream_calculator.sv и tb_dp_stream_calculator.sv в одну папку. Беззнаковый восьмибитный интерфейс a,b,tag принимает по in-valid/in-ready и выдаёт y со своей меткой по out-valid/out-ready. Девятибитные суммы и одиннадцатибитные масштабированные значения сужаются только на выходе. Reset освобождает хранилище и подавляет передачи.

Выполните при установленном Icarus Verilog:

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

При авторской проверке эти файлы успешно скомпилированы и симулированы:

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

Тестовый стенд проверяет арифметику, метки, порядок, остановки, замену при заполненности, циклический переход указателей, отмену четырёх элементов сбросом и опустошение. Измените длительность остановки и сравните задержку с тремя тактами без остановок. Это проверяет симуляцию RTL Icarus, а не синтез, физические временные характеристики или выполнение DDS.

Попробуйте сами

При постоянно готовом приёмнике на каком фронте передаётся tag0? Если глубина FIFO становится один, что происходит с задержкой без остановок и общей ёмкостью?

Прочитать объяснение

Tag0 передаётся на фронте 3 после приёма на 0, s1 на 1 и s2 на 2. Сохранение регистровой FIFO сохраняет задержку в три фронта; ёмкость уменьшается до 1+1+1=3 транзакций. Измените ограничение глубины input-ready и снова проверьте модель.

Lesson files

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

Выбор действует в этом браузере. Его можно изменить внизу страницы.