Как устроена FPGA внутри: LUT, триггеры, матрица соединений
Заглядываем внутрь FPGA и разбираем кирпичики, из которых собирается любая схема.
LUT (Look-Up Table, таблица поиска) — крошечная память, которая по комбинации входов выдаёт заранее записанный бит; так FPGA реализует любую логическую функцию от нескольких входов.
FPGA — это регулярная решётка из одинаковых блоков, соединённых программируемыми проводами. Чтобы описывать схемы осмысленно, нужно понимать, из чего эти блоки состоят. Главных кирпичиков три: LUT (для комбинационной логики), триггер (для памяти на один бит) и программируемая матрица соединений (которая связывает всё это в нужную схему).
LUT — универсальный логический элемент
Самый хитрый кирпичик — LUT. Это не вентиль И или ИЛИ, а маленькая таблица истинности, записанная в память. LUT с N входами хранит 2^N бит: для каждой комбинации входов — один заранее заданный выход. Меняя содержимое таблицы, один и тот же LUT превращается то в И, то в ИЛИ, то в XOR, то в любую функцию от N переменных.
Покажем на Python, как 4-битная таблица задаёт логику. Например, LUT на 2 входа с содержимым [0,1,1,0] — это XOR:
# LUT на 2 входа: 4 ячейки памяти, индекс = (a,b) как 2-битное число
# содержимое [0,1,1,0] задаёт функцию XOR
lut = [0, 1, 1, 0]
print(" a b | out")
print("-----+----")
for a in (0, 1):
for b in (0, 1):
index = a * 2 + b # склеиваем входы в адрес ячейки
out = lut[index] # просто читаем бит из таблицы
print(f" {a} {b} | {out}")Вывод:
a b | out -----+---- 0 0 | 0 0 1 | 1 1 0 | 1 1 1 | 0
Запишите в ту же таблицу [0,0,0,1] — получите И, [0,1,1,1] — ИЛИ. Вот почему LUT называют универсальным: одна структура реализует любую логику. Реальные FPGA используют LUT на 4–6 входов.
Триггер, логический блок и соединения
Рядом с каждым LUT стоит триггер (flip-flop) — элемент, способный «запомнить» один бит до следующего такта. LUT даёт мгновенную логику, триггер добавляет память во времени. Пара «LUT + триггер» — это логическая ячейка; несколько ячеек объединяют в логический блок (его называют CLB у Xilinx или LAB у Intel). Схематично:
входы
|
v
+---------+ +-----------+
| LUT |------->| триггер |---> выход
| (логика)| опц. | (память) |
+---------+ +-----------+
^
|
clockВсе эти тысячи блоков плавают в море программируемых проводов — матрице соединений. В точках пересечения проводов стоят настраиваемые ключи: загружая битстрим, мы замыкаем нужные и размыкаем лишние, прокладывая сигналам путь. Именно соединения занимают большую часть площади FPGA и сильнее всего влияют на задержку.
Как работает под капотом: специализированные блоки
Если бы умножение строили из одних LUT, оно вышло бы громоздким и медленным. Поэтому в FPGA встроены готовые аппаратные блоки:
- DSP-блоки — аппаратные умножители-накопители (умножить и прибавить за такт). Их много, и они ключевые для фильтров и нейросетей.
- Block RAM (BRAM) — блоки встроенной памяти на килобиты, для буферов и таблиц.
- Блоки тактирования (PLL/MMCM) — формируют и умножают тактовые частоты.
- Блоки ввода-вывода (IOB) — связывают внутреннюю схему с ножками микросхемы.
Когда вы пишете в Verilog a * b, синтезатор не выкладывает умножитель из LUT, а подключает аппаратный DSP-блок. Понимание, что таких блоков конечное число, важно: проект может «не влезть» в FPGA не из-за нехватки LUT, а из-за того, что DSP-блоков или BRAM не хватило.
Частые ошибки
- Путать LUT с вентилем. LUT — это память-таблица, а не фиксированный вентиль; его поведение задаётся содержимым.
- Думать, что ресурс один. Кроме LUT есть триггеры, DSP, BRAM, тактовые ресурсы — проект упирается в самый дефицитный из них.
- Игнорировать соединения. Часто схема не работает на нужной частоте не из-за логики, а из-за длинных маршрутов через матрицу соединений.
Итог
- LUT — таблица поиска, реализующая любую логику от нескольких входов.
- Триггер хранит бит; пара LUT+триггер образует логическую ячейку.
- Матрица соединений программируемо связывает блоки и занимает много площади.
- DSP, BRAM, PLL — специализированные блоки; их количество ограничено.