В последнее время небезызвестный китайский сайт предлагает купить радиолюбителям разного рода отладочные платы на ПЛИС, но к сожалению, доступного для неподготовленного ума (ну или такого, которое бы мне понравилось) описания на русском (как же ЭТО работает?) на просторах интернета я не нашел. Со временем, конечно, понимание пришло, но также пришло и желание написать некую вводную статью с красивыми картинками, которые бы наглядно поясняли суть ПЛИС. Начнем.
ПЛИС — Программируемая Логическая Интегральная Схема. ВАЖНО! Существует два типа БИС (Большая Интегральная Схема), которые у нас в СНГ попадают под определение ПЛИС, но тем не менее принцип работы этих БИС отличается, что создает некоторый диссонанс с реальным положением вещей. В то же время на западе у каждой из этих БИС есть вполне свое собственное название, четко ставящее все точки над i, а именно: CPLD-микросхема — это ПЛИС, прошивка (конфигурация) которой ВСЕГДА хранится в самой микросхеме и при выключении питания НИКОГДА не стирается. Кажется вполне себе логичным, что прошивка само-собой должна хранится в микросхеме, и заострять внимание на этом не следует, но перейдем к следующей БИС. FPGA-микросхема — это тоже ПЛИС, но ее конфигурация хранится на внешнем энергонезависимом источнике памяти (например всякого рода flash). Как это работает? Очень просто, при каждом включении, FPGA прошивает саму себя конфигурацией, которую берет из памяти, а при выключении стирается.
Хочется отметить, что процесс написания конфигурации на CPLD и на FPGA ничем не отличается: все пишется на языке описания аппаратуры VHDL или Verilog. Потом происходит синтез и имплементация (компилятор сначала пытается понять, что вы написали, а потом пытается разместить все структуры, регистры и соединения в ПЛИС, на основе написанного), и на последнем этапе генерится .bit — файл, который зашивается программатором по JTAG-интерфейсу в устройство.
Если с CPLD ещё как-то привычнее работать («Ну как в микроконтроллере!» — скажите Вы), то FPGA, со всеми ее непонятными внешними источниками памяти, кажутся каким-то несуразным зверем, поэтому все ниже написанное будет посвящено FPGA (но приемы программирования справедливы и для CPLD), чтобы внести некую ясность в этот вопрос. Все примеры кода будут выполнятся на языке VHDL.
Рассмотрим наименьшую составляющую FPGA, которая называется PLB — Программируемый Логический Блок.
PLB состоит из LUT-таблицы соответствия, мультиплексора и D-триггера. Рассмотрим для начала LUT. По-сути, LUT — это статическое ОЗУ (ОЗУ — Оперативное Запоминающее Устройство. Является энергозависимой памятью, т.е. при отключении питания данные стираются. (Включил. Записал. Выключил. Включил снова, а все записанные данные стерты). Обладает высокими показателями скорости.), в котором хранятся выходные значения X, образованные значениями A,B,C,D.
Предположим нам требуется реализовать на ПЛИС схему представленную на рисунке ниже, с соответствующей таблицей истинности:
Сигналы A, В, С, D подаются на вход LUT, далее исходя из таблицы истинности, которая хранится в LUT, моментально формируется сигнал X. Все очень просто. В коде это выглядит так:
X <= (A nand B) nand (C nand D);
На рисунке ниже красной линией показано, как формируется выходной сигнал на аппаратном уровне:
Но что, если нам нужно синхронизировать сигнал по тактовой частоте? Тогда, в процессе написания конфигурации, нам нужно указать, что выходной сигнал будет устанавливаться либо по фронту (rising_edge(clk)) или по срезу (falling_edge(clk)) тактового сигнала CLK, и компилятор будет брать выходной сигнал не c выхода X, а с выхода Y. На языке VHDL это выглядит так:
process(clk)
begin
if (rising_edge(clk)) then
Y <= (A nand B) nand (C nand D);
end if;
end process;
На аппаратном уровне это происходит так: сигнал с LUT идет на Т-триггер, который устанавливает значение выхода Y по CLK.
Что делать если нужно задержать входной сигнал на один такт? Тогда в конфигурации мы присваиваем сигнал, который нужно задержать, новому сигналу в процессе синхронизированном по CLK:
process(clk)
begin
if (rising_edge(clk)) then
Y <= Е;
end if;
end process;
Аппаратно это происходит так:
Напомню, все выше рассмотренное происходит в рамках ОДНОЙ НАИМЕНЬШЕЙ составляющей FPGA, а именно PLB. Но внутри FPGA десятки тысяч таких PLB (а может и сотни, технологии они такие: не стоят на месте), которые могут соединяться между собой. Для простоты организации связей между ними, в FPGA применяется некий модульный принцип: малое составляет большое: две PLB образуют один SLICE.
Два SLICE образуют один конфигурационный логический блок (CLB), внутри которого SLICE могут образовывать связь. Таким образом, за счет оптимизации адресации внутри FPGA, компилятору проще производить имплементацию нашей конфигурации по кристаллу.
В завершении хотелось бы рассказать почему стоит присмотреться к ПЛИС, и в частности к FPGA-микросхемам. Во-первых это неограниченное поле для творчества: нужен экзотический 13-битный таймер/счетчик? — получи. Требуется 15 UART? — легко. Передать данные со скоростью 6 Гбит/с? — не вопрос. И если преимущества ПЛИС очевидны, то перейдем к тому какая из них предпочтительнее: CPLD или FPGA? Хочется отметить, что собственно тут все зависит от применения. Если проект не большой, но требует специфической периферии, то это CPLD. А если нужна гибкость и очень большие скорости, то это FPGA. Ничто не мешает вам сделать так, чтобы в какой-то момент времени FPGA работала сначала по-одной прошивке, потом по-второй, третьей, пятой, десятой (свойство реконфигурируемости), ведь в отличие от других микросхем, ресурс запись/стирание у FPGA стремиться к бесконечности (когда последний раз вы меняли оперативную память в своем ПК по причине того, что выработали ее ресурс на запись/стирание? Вот и я об этом. Собственно на этом все, спасибо за внимание