Лабораторная 5.2 — Отображение FIR-фильтра в RTL¶
Цель¶
Понять, как fixed-point FIR-фильтр из модели переносится в синтезируемую RTL-архитектуру с регистрами задержки, умножителями, аккумулятором, округлением и насыщением.
Что выполняется¶
В работе студент:
- изучает 4-tap IQ FIR на Verilog;
- генерирует эталонные векторы Python-скриптом;
- запускает self-checking testbench;
- проверяет совпадение RTL с fixed-point эталоном;
- анализирует задержку, разрядность и насыщение.
Результат¶
После выполнения работы должны быть получены:
- 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.
Рекомендуемые тесты:
- единичный импульс на входе -> выход совпадает с последовательностью коэффициентов;
- постоянный вход -> выход приближается к коэффициенту усиления по постоянному току;
- двухтональный вход -> подавление помехи совпадает с эталоном;
- случайный вектор IQ -> отсчёт-за-отсчётом сравнение после компенсации задержки;
- вектор стресса насыщения -> выход детерминированно ограничивается.
Документирование задержки¶
Задержку необходимо указывать явно:
| Этап | Задержка, такты |
|---|---|
| Входной регистр | 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.
- Замените округление усечением:
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 замечает. - Измените
H1с16'sd12288на16'sd12289(один LSB коэффициента). Testbench сообщает только 4 ошибки, напримерout=(12289,4096) expected=(12288,4096). Остальные выходы не изменились: добавкаx * 2^-15не пересекла границу округления. Что это говорит о количестве векторов, нужных для проверки коэффициентов? - Сумма коэффициентов ровно 1.0. Вычислите худшую ширину аккумулятора для 16-битных входов и обоснуйте (или уменьшите)
ACC_W = 40. - Критический путь на 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 МЗР, которое любое сравнение с допуском приняло бы.
- Изменение коэффициента на один МЗР проявляется только там, где произведения близки к границе округления, здесь в 4 выходах. Проверке коэффициентов нужно много векторов по всему диапазону входа, включая значения, при которых произведения попадают около половины МЗР; горстка «удобных» входов может вовсе не заметить неверный коэффициент.
- Все четыре коэффициента положительны и в сумме дают
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 бита. - Оставить третью ступень: округление и насыщение в отдельном такте сокращают путь с 20 до 12 уровней логики, а WNS с −0,125 до +5,35 нс ценой 2 лишних тактов латентности и нескольких триггеров. Фильтру в потоке два такта почти никогда не мешают; контуру обратной связи вокруг него (ФАПЧ, АРУ) помешали бы, и там искали бы другое разбиение.
Чек-лист отчёта (расширенный)¶
- Указан формат FIR и число коэффициентов.
- Вычислены ширины произведения и аккумулятора.
- Выбрана архитектура: параллельная, мультиплексированная по времени, симметричная или полифазная.
- Нарисована схема тракта данных.
- Определены потоковые порты.
- Определена задержка.
- Определены тестовые векторы.
- Определён допуск ошибки pass/fail.
- Добавлена таблица оценки ресурсов.
Шаблон инженерного вывода¶
Отображение FIR в RTL использует ____ коэффициентов с входом и коэффициентами Q1.15.
Ширина произведения — ____ бит, ширина аккумулятора — ____ бит.
Выбранная архитектура — ____, потому что ______.
Ожидаемая задержка — ____ тактов, а главная цена в ресурсах FPGA — ______.