Перейти к содержанию

Лабораторная 5.2 — Отображение FIR-фильтра в RTL

Цель

Понять, как fixed-point FIR-фильтр из модели переносится в синтезируемую RTL-архитектуру с регистрами задержки, умножителями, аккумулятором, округлением и насыщением.

Что выполняется

В работе студент:

  1. изучает 4-tap IQ FIR на Verilog;
  2. генерирует эталонные векторы Python-скриптом;
  3. запускает self-checking testbench;
  4. проверяет совпадение RTL с fixed-point эталоном;
  5. анализирует задержку, разрядность и насыщение.

Результат

После выполнения работы должны быть получены:

  • RTL-модуль FIR-фильтра;
  • входные и ожидаемые test vectors;
  • VCD waveform;
  • PASS/FAIL лог симуляции;
  • таблица разрядностей datapath.

Что приложить к отчёту

  • структуру FIR datapath;
  • коэффициенты фильтра;
  • product width и accumulator width;
  • правило округления и насыщения;
  • результат симуляции;
  • вывод о готовности блока к Vivado/FPGA flow.

Подробная техническая часть

Исполняемый HDL-пакет

Файл Назначение
blocks/block_05_fpga_hdl_flow/rtl/fir_iq_4tap.v исполняемый учебный RTL-блок 4-коэффициентного IQ FIR
blocks/block_05_fpga_hdl_flow/tb/tb_fir_iq_4tap.v самопроверяющийся Verilog-testbench
blocks/block_05_fpga_hdl_flow/python/generate_fir_iq_4tap_vectors.py генератор детерминированных эталонных векторов
blocks/block_05_fpga_hdl_flow/tb/fir_iq_4tap_input_vectors.txt сгенерированные входные векторы
blocks/block_05_fpga_hdl_flow/tb/fir_iq_4tap_expected_vectors.txt сгенерированные ожидаемые выходные векторы

Запуск из корня репозитория:

python blocks/block_05_fpga_hdl_flow/python/generate_fir_iq_4tap_vectors.py

iverilog -g2012 \
  -o blocks/block_05_fpga_hdl_flow/tb/tb_fir_iq_4tap.out \
  blocks/block_05_fpga_hdl_flow/rtl/fir_iq_4tap.v \
  blocks/block_05_fpga_hdl_flow/tb/tb_fir_iq_4tap.v

vvp blocks/block_05_fpga_hdl_flow/tb/tb_fir_iq_4tap.out

Ожидаемый результат:

PASS: fir_iq_4tap test completed without errors

Workflow GitHub Actions .github/workflows/block5_hdl.yml автоматически генерирует векторы и запускает эту симуляцию.

Инженерный вопрос

Как модель FIR в Q1.15 становится тактируемым RTL-трактом данных с явными умножителями, ростом разрядности аккумулятора, округлением и насыщением?

Входные данные из Блока 4

Параметр Пример Следствие для RTL
Формат входа Q1.15 знаковые 16-битные входные порты
Формат коэффициентов Q1.15 знаковое 16-битное ROM коэффициентов
Число коэффициентов 4 в исполняемой работе, 129 в полном проекте длина сдвигового регистра и число умножителей
Формат произведения Q2.30 32-битные произведения
Защитные биты ceil(log2(N)) аккумулятор должен быть шире произведения
Формат выхода Q1.15 округление/насыщение перед выходом

Тракт данных FIR

flowchart LR
    IN[Входной отсчёт] --> SR[Сдвиговый регистр]
    SR --> MUL[Умножители на коэффициенты]
    COEF[ROM коэффициентов] --> MUL
    MUL --> SUM[Сумматорное дерево / аккумулятор]
    SUM --> ROUND[Округление до Q1.15]
    ROUND --> SAT[Насыщение]
    SAT --> OUT[Выходной отсчёт]

Уравнение FIR в прямой форме

y[n] = sum_{k=0}^{N-1} h[k] * x[n-k]

Для комплексного IQ один и тот же FIR с вещественными коэффициентами применяется независимо к I и Q:

y_i[n] = sum h[k] * x_i[n-k]
y_q[n] = sum h[k] * x_q[n-k]

Исполняемый пример на 4 коэффициента

Исполняемая работа использует такой набор коэффициентов Q1.15:

h = [0.125, 0.375, 0.375, 0.125]
h_q15 = [4096, 12288, 12288, 4096]

Он намеренно достаточно мал, чтобы разобраться в нём в просмотрщике waveform, но при этом демонстрирует полный шаблон fixed-point FIR:

  • сдвиговый регистр;
  • умножение на коэффициенты;
  • рост разрядности аккумулятора;
  • округление обратно до Q1.15;
  • насыщение;
  • выравнивание сигнала valid на выходе;
  • сравнение с эталонными векторами.

Варианты архитектуры

Архитектура Использование DSP Пропускная способность Задержка Когда применять
Полностью параллельная высокое один отсчёт за такт малая/средняя потоковая обработка на высокой скорости
Мультиплексированный по времени MAC низкое один отсчёт за много тактов высокая низкая скорость или ограниченные ресурсы
Симметричный FIR среднее один отсчёт за такт средняя линейная фаза, симметричные коэффициенты
Полифазный FIR среднее/высокое эффективное изменение частоты средняя дециматор/интерполятор

Размер аккумулятора

Для знакового входа Q1.15 и коэффициентов Q1.15:

ширина произведения = 16 + 16 = 32 бита
дробных бит произведения = 15 + 15 = 30 бит
защитные биты = ceil(log2(Ntaps))
ширина аккумулятора >= 32 + guard_bits

Для исполняемой 4-коэффициентной работы:

guard_bits = 2
ширина аккумулятора >= 34 бита

Для практического FIR на 129 коэффициентов:

guard_bits = 8
ширина аккумулятора >= 40 бит

Каркас RTL

module fir_iq_stream #(
    parameter integer W = 16,
    parameter integer NTAPS = 129,
    parameter integer ACC_W = 40
)(
    input  wire                 clk,
    input  wire                 rst,
    input  wire                 in_valid,
    input  wire signed [W-1:0]  in_i,
    input  wire signed [W-1:0]  in_q,
    output reg                  out_valid,
    output reg  signed [W-1:0]  out_i,
    output reg  signed [W-1:0]  out_q
);

// Учебный каркас: настоящее ROM коэффициентов, сдвиговый регистр,
// массив умножителей, сумматорное дерево, округление и насыщение
// добавляются шаг за шагом в лабораторных по реализации.

endmodule

Стратегия testbench

Используйте эталонные векторы из Python/MATLAB Lab 4.1 или из локального генератора векторов FIR.

Рекомендуемые тесты:

  1. единичный импульс на входе -> выход совпадает с последовательностью коэффициентов;
  2. постоянный вход -> выход приближается к коэффициенту усиления по постоянному току;
  3. двухтональный вход -> подавление помехи совпадает с эталоном;
  4. случайный вектор IQ -> отсчёт-за-отсчётом сравнение после компенсации задержки;
  5. вектор стресса насыщения -> выход детерминированно ограничивается.

Документирование задержки

Задержку необходимо указывать явно:

Этап Задержка, такты
Входной регистр 1
Обновление сдвигового регистра 0/1
Конвейер умножителя 1–3
Сумматорное дерево зависит от глубины дерева
Округление/насыщение 1
Выходной регистр 1

Шаблон отчёта Vivado по ресурсам

Ресурс Оценка После синтеза Комментарий
LUT управление + сумматоры
FF регистры + конвейер valid
DSP умножители
BRAM хранение коэффициентов, если используется
Задержка такты
Fmax МГц

Справочный результат для этого RTL: out-of-context синтез в Vivado 2021.1 для кристалла курса xc7z020clg400-2 с тактом 100 МГц (python tools/generate_block5_vivado_reports.py, исходные отчёты в reports/fpga/vivado_ooc_raw):

Ресурс После синтеза Комментарий
LUT 117 сумматоры, округление и насыщение
FF 129 сдвиговый регистр, выходы, valid
DSP48E1 4 умножения на константы, отображённые в DSP-срезы
BRAM 0 коэффициенты: константы
Задержка 1 такт от in_valid до out_valid
Тайминг на 100 МГц WNS -0,125 нс не укладывается с небольшим запасом: 20 уровней логики, оценка около 98,8 МГц (только синтез)
Тайминг после размещения и трассировки WNS -0,247 нс по-прежнему не укладывается, тот же путь из 20 уровней; пути от портов проверяются (отчёт)

Чего ожидать

PASS: fir_iq_4tap test completed without errors

Сравнение побитовое: Python-генератор вычисляет тот же фильтр h = [0.125, 0.375, 0.375, 0.125] в целых числах с округлением half-up и насыщением, и каждый выходной отсчёт должен совпасть точно. Коэффициент передачи на постоянном токе равен 1.0, поэтому постоянный вход после заполнения четырёх отводов выходит без изменений.

Раннер курса генерирует векторы, компилирует, запускает симуляцию и считает ошибкой любую строку FAIL или ненулевой код выхода симулятора:

python tools/run_block5_hdl_smoke.py --test tb_fir_iq_4tap

Упражнения

Каждое упражнение ниже: намеренная мутация RTL в одну строку. Внесите её, запустите testbench, прочитайте сообщения и верните файл (git checkout -- <file>). Приведённые выводы получены на Icarus Verilog 12.0.

  1. Замените округление усечением: round_q15 = value >>> SHIFT;. Testbench сообщает 6 ошибок, каждая ровно на 1 LSB меньше, например out=(4095,0) expected=(4096,0) и out=(12287,4095) expected=(12288,4096). Усечение это смещение -0.5 LSB; сравнение с плавающей точкой и допуском 1e-3 его бы не заметило, побитовый testbench замечает.
  2. Измените H1 с 16'sd12288 на 16'sd12289 (один LSB коэффициента). Testbench сообщает только 4 ошибки, например out=(12289,4096) expected=(12288,4096). Остальные выходы не изменились: добавка x * 2^-15 не пересекла границу округления. Что это говорит о количестве векторов, нужных для проверки коэффициентов?
  3. Сумма коэффициентов ровно 1.0. Вычислите худшую ширину аккумулятора для 16-битных входов и обоснуйте (или уменьшите) ACC_W = 40.
  4. Критический путь на 100 МГц находится не там, где кажется. Поставьте регистр после умножителей (задержка 2) и синтезируйте снова: WNS остаётся -0,125 нс. Отчёт тайминга показывает почему: путь теперь начинается на регистрах произведений и по-прежнему проходит через 40-битную сумму, сумматор округления и сравнение насыщения за один такт (20 уровней, 15 из них CARRY4). Зарегистрируйте и сумму, а округление и насыщение выполните в третьем такте: WNS становится +5,35 нс при 12 уровнях логики (70 LUT, 67 FF, 6 DSP48E1). Оба варианта проверены побитно против этого RTL на 2000 случайных отсчётах, просто на 1 и 2 такта позже. Какое изменение вы бы оставили в реальном проекте и чем за него платите по задержке?
Ответы (сверены с RTL и стендом)
  1. Наблюдаемый вывод приведён в упражнении: побитовый стенд видит смещение в 1 МЗР, которое любое сравнение с допуском приняло бы.
  2. Изменение коэффициента на один МЗР проявляется только там, где произведения близки к границе округления, здесь в 4 выходах. Проверке коэффициентов нужно много векторов по всему диапазону входа, включая значения, при которых произведения попадают около половины МЗР; горстка «удобных» входов может вовсе не заметить неверный коэффициент.
  3. Все четыре коэффициента положительны и в сумме дают 2^15 (1,0 в Q1.15), поэтому |Σ x·h| ≤ 2^15 · 2^15 = 2^30: 31 бит модуля плюс знак, 32 бита. ACC_W = 40 оставляет этому фильтру 8 неиспользуемых защитных бит; 32 достаточно. Для произвольного 4-отводного фильтра с Σ|h| до 4 · 2^15 понадобилось бы 34 бита.
  4. Оставить третью ступень: округление и насыщение в отдельном такте сокращают путь с 20 до 12 уровней логики, а WNS с −0,125 до +5,35 нс ценой 2 лишних тактов латентности и нескольких триггеров. Фильтру в потоке два такта почти никогда не мешают; контуру обратной связи вокруг него (ФАПЧ, АРУ) помешали бы, и там искали бы другое разбиение.

Чек-лист отчёта (расширенный)

  • Указан формат FIR и число коэффициентов.
  • Вычислены ширины произведения и аккумулятора.
  • Выбрана архитектура: параллельная, мультиплексированная по времени, симметричная или полифазная.
  • Нарисована схема тракта данных.
  • Определены потоковые порты.
  • Определена задержка.
  • Определены тестовые векторы.
  • Определён допуск ошибки pass/fail.
  • Добавлена таблица оценки ресурсов.

Шаблон инженерного вывода

Отображение FIR в RTL использует ____ коэффициентов с входом и коэффициентами Q1.15.
Ширина произведения — ____ бит, ширина аккумулятора — ____ бит.
Выбранная архитектура — ____, потому что ______.
Ожидаемая задержка — ____ тактов, а главная цена в ресурсах FPGA — ______.