[Перевод] Как работает FPGA?
Введение
Давайте начнём с самого начала. Что такое FPGA? FPGA расшифровывается как Field Programmable Gate Array (программируемая пользователем вентильная матрица).
FPGA относятся к классу устройств программируемой логики, иногда называемых программируемым оборудованием. По сути, сама по себе FPGA ничего не делает, но может быть сконфигурирована так, чтобы превратиться практически в любую нужную цифровую цепь. Магия заключается в том, что физически при этом ничего не меняется. Достаточно просто загрузить конфигурацию в FPGA, и она начнёт вести себя так, как нужная вам цепь. Не нужны ни пайка, ни перемычки, ни возня с другими соединениями. FPGA можно переконфигурировать так, чтобы она вела себя, как другая цепь, и делать это множество раз. Конфигурация хранится в ОЗУ, то есть, по сути, устройство можно переконфигурировать бесконечно.
Хотя мы говорили об использовании FPGA для создания цифровых цепей, обычно для разработки их архитектуры не рисуют схемы. Если бы нам пришлось чертить схему, то размер и сложность цепей, которые могут содержать FPGA, стали бы очень громоздкими. Вместо этого мы можем описать поведение нужной нам цепи, а инструменты используют это описание для создания цепи, соответствующей этому поведению.
В каком-то смысле это похоже на программирование, ведь мы просто вводим текст. Однако фундаментальная реализация существенно отличается, так как мы создаём оборудование.
Если создание оборудования при помощи текста кажется вам магией, не волнуйтесь. Концепция его работы на самом деле довольно проста, и в этом туториале мы подробно о ней расскажем.
▍ Рекомендуемое чтение
В этом туториале мы узнаем, что такое FPGA и как она работает. Будем предполагать, что вы разбираетесь в электричестве (напряжение, ток и так далее) и двоичных значениях. Всё остальное легко понять из основ. Статья задумывалась как обзор FPGA и её фундаментальной архитектуры, а не руководство по проектированию собственного устройства.
Если вы незнакомы со следующими концепциями, то прежде чем читать дальше, рекомендую изучить данные туториалы:
Напряжение, ток, сопротивление и закон Ома. Узнайте о законе Ома — одном из самых фундаментальных уравнений во всей электромеханике.
Что такое электричество?. Работу электричества мы можем наблюдать в своих компьютерах, осветительных приборах и молниях, но что же это такое? Это непростой вопрос, и данный туториал прольёт на него немного света!
Аналоговое и цифровое. В этом туториале излагается концепция аналоговых и цифровых сигналов, и их связь с электроникой.
Транзисторы. Краткое введение в биполярные транзисторы. Узнайте, как работают транзисторы и в каких цепях мы их используем.
Цифровые цепи и логические вентили
▍ Цифровые цепи
Недостаток FPGA заключается в том, что они могут создавать только цифровые цепи. В некоторых новых FPGA есть встроенные аналогово-цифровые преобразователи, но даже они сразу же преобразуют аналоговый входной сигнал в цифровой. Но что же такое цифровая цепь?
В электронике цифровыми называются цепи, абстрагирующие непрерывные значения напряжения в дискретные единицы и нули. Для высокоуровневой архитектуры истинные напряжения и пороговые значения не так важны, но внутри FPGA часто бывает так, что 0 В обозначается как 0, а 1,2 В — как 1. Если истинное напряжение, допустим, равно 0,8 В, это достаточно близко к 1,2 В, чтобы считаться 1, а всё остальное работает так же.
Цифровые цепи преобразуют напряжения в крайние значения, что делает их невероятно устойчивыми к шуму и другим воздействиям реального мира. Также концепция цифрового устройства позволяет нам моделировать в цепи сложное поведение без необходимости работы над низкоуровневой архитектурой. Мы можем работать в идеальном мире. Все тонкости спрятаны внутри архитектуры простых строительных блоков, которые мы будем использовать.
Такими строительными блоками являются логические вентили.
▍ Логические вентили
Существует несколько логических вентилей, самые распространённые из которых — это AND (И), OR (ИЛИ), XOR (исключающее ИЛИ) и NOT (НЕТ). Каждый из них получает на входе цифровые сигналы, выполняет свою логическую функцию и подаёт на выход цифровое значение.
Вентиль AND получает два входных значения и выводит 1, только если первое и второе входные значения равны 1. Если хотя бы одно из входных значений равно 0, то на выходе будет 0. Символ вентиля AND выглядит так:
Вентиль OR получает два входных значения и выводит 1, если первое или второе значение равно 1. Выходное значение равно 0, только когда оба входных значения равны 0. Вот символ вентиля OR:
Вентиль XOR схож с вентилем OR, но подаёт на выход 1, только когда или первое, или второе входное значение равно 1, но не когда оба равны 1. Можно ещё сказать, что он выводит 1, когда входные значения различаются. X в XOR расшифровывается как exclusive («исключающее»). Вот символ вентиля:
Вентиль NOT — самый простой. У него только один вход и он просто выводит противоположное значение. То есть 1 превращается в 0, а 0 превращается в 1.
Существуют вариации этих базовых вентилей, называющиеся NAND, NOR и XNOR. Это просто версии стандартных вентилей, но с инвертированными выходами.
Вентиль AND, как и все другие логические вентили, можно изготовить из транзисторов. На изображении ниже показано, как можно реализовать вентиль AND. В этой схеме использованы МОП-транзисторы NMOS и PMOS. Такой тип архитектуры называется CMOS (complementary metal-oxide semiconductor, КМОП, комплементарная структура металл-оксид-полупроводник), она используется в большинстве современных цепей.
Обратите внимание, что показанная выше схема на самом деле является вентилем NAND, за которым идёт вентиль NOT. Так получилось потому, что КМОП-цепи инвертируют выходное значение.
Мультиплексоры
Теперь, когда у нас есть базовые строительные блоки, от транзисторов до логических вентилей, мы можем создать из них что-то более полезное. При помощи одних только логических вентилей можно описать любую цифровую цепь. Однако существует множество часто используемых и обозначаемых собственными символами высокоуровневых функций, например, в двоичной математике (сумматоры, умножители и так далее).
Мы рассмотрим один из фундаментальных строительных блоков FPGA — мультиплексор.
Мультиплексор выбирает единственное входное значение из множества на основании значения входа выбора. Вот его символ:
Символ / на линии sel обозначает, что он имеет ширину 6 битов.
Количество входов может варьироваться, но выход у мультиплексора всегда только один.
Способ кодирования входа выбора тоже варьируется. Обычно он представлен как двоичное число, но в более простых цепях используется унитарное кодирование. Унитарный код — это просто двоичное значение, в котором всегда ровно одна 1. Важно в нём положение этой 1.
Декодер получает двоичное значение и превращает его в унитарный сигнал. Кодировщик превращает унитарное значение в двоичное число. Их можно использовать для того, чтобы мультиплексор принимал двоичные значения.
Взгляните, как можно реализовать мультиплексор с унитарным кодированием всего из нескольких вентилей AND и OR.
Если мы присвоим sel значение 000010, то есть только sel[1] будет равно 1, то для каждого вентиля AND, за исключением того, который имеет вход b, одно из входных значений будет равно 0. Это значит, что каждый из них будет подавать на выход 0, вне зависимости от того, какие входные значения на a, c, d, e и f. Единственный имеющий значение вход — это b. Если b равен 1, то он подвергается AND с 1 и на выходе вентиля AND будет 1. Когда b равен 0, то он подвергается AND с 1 и на выходе вентиля AND будет 0.
Иными словами, на выходе вентиля AND просто будет b.
Результат вентилей AND, когда sel[1] присвоено значение 1
Вентиль OR на этой схеме показан с более чем двумя входами. Это можно реализовать, создав дерево из двух входных вентилей OR, в которых два входа подвергаются OR, после чего выходы тоже подвергаются OR, и так снова и снова, пока мы не получим один выход. Вентиль OR со множественными входами будет иметь на выходе 1, если хотя бы один из входов равен 1.
Однако в этой цепи каждый вход вентиля OR гарантировано будет иметь значение 0, за исключением входа от вентиля AND, выходом которого является b. Это значит, что вентиль OR будет выводить 1, когда b равен 1, и выводить 0, когда b равен 0.
Иными словами, выходом вентиля OR будет просто b.
Результатом вентиля OR будет b
Эту логику можно повторить для любого входа, если вход будет с унитарным кодированием, то вход, соответствующий заданной 1, будет передан на выход.
Можно представить большую матрицу мультиплексоров с программируемыми входными данными sel. Это позволит направлять сигналы так, как нужно в архитектуре. Именно так FPGA передают сигналы туда, где они должны быть; это называется general routing matrix (главной трассировочной матрицей).
Очевидно, подробности маршрутизации тысяч и тысяч сигналов становятся запутанными, но в конечном итоге всё это просто множество мультиплексоров, входы выбора которых подключены к программируемой памяти.
Таблицы поиска
Итак, научившись динамически маршрутизировать сигналы туда, где они должны быть, мы должны найти способ выполнения произвольной логики. Для этого мы снова используем мультиплексоры, а точнее, их потомков, называемых LUT, или look-up table (таблицами поиска).
Представьте, что у нас есть мультиплексор с четырьмя входами и 2-битным двоичным выбором (вместо унитарного). Вместо того, чтобы открывать основные входы миру, подключим их к некой программируемой памяти. Это значит, что мы сможем запрограммировать каждый вход на некое постоянное значение. Объединим всё это в один блок и получим две входные LUT.
Два входа в LUT — это входы выбора мультиплексора. Программируя входы мультиплексора любыми нужными нам значениями, мы можем использовать эту LUT для реализации ЛЮБОЙ двоичной функции »2-к-1».
Например, можно заставить его работать как простой вентиль AND, задав в памяти следующее содержимое.
Это простой пример — обычно LUT больше, чем просто два входа; FPGA на Alchitry Au основана на LUT с пятью входами.
Xilinx объединяет LUT с пятью входами с ещё одним мультиплексором для создания или LUT с шестью входами, или LUT с пятью входами и двух независимых выходов.
Если вы хотите подробнее узнать о том, что такое LUT и как выглядят ресурсы в FPGA, то прочитайте этот документ Xilinx по Artix 7. Учтите, что этот документ очень труден для понимания. Стоит взглянуть на страницу 20. На ней показана упрощённая схема SLICEL. Слайсы находятся на один строительный блок выше LUT. Четыре прямоугольника слева — это LUT, похожие на показанные выше.
Для контекста: в FPGA на Alchitry Au содержится 20800 двойных LUT. Это большое число, но оно и близко несравнимо с самыми крупными FPGA, в которых на момент написания статьи содержится примерно в 260 раз больше таблиц. Как можно понять, даже маршрутизировать все эти сигналы невероятно сложно. К счастью для нас, чтобы работать с FPGA, всё это нам делать не нужно. Инструменты выполняют всю низкоуровневую маршрутизацию и программирование LUT. Нам просто достаточно описать нужные цепи.
Зачем использовать FPGA?
Надеюсь, этот туториал дал вам примерное понимание того, как работают FPGA, но зачем их вообще использовать?
Обычно такой вопрос возникает в контексте выбора между использованием процессора или создания собственной архитектуры на FPGA. Многие люди знают, как писать код, но гораздо меньшее количество понимает, как создавать архитектуры для FPGA. Писать код часто проще при создании сложных поведений и для существенного изменения способа реализации.
Однако FPGA могут быть гораздо более эффективными с точки зрения времени обработки, а также обеспечения хороших таймингов. Чтобы проиллюстрировать это, рассмотрим тривиальный пример со включением светодиода при нажатии на кнопку. Если написать код для этого на чём-то вроде Arduino, то процессор будет выполнять небольшой цикл кода, считывающий состояние контакта, а затем обновляющий состояние другого контакта на основании этого значения.
Если вы оптимизируете этот код, то сможете добиться скорости обновления в миллионы раз в секунду. Кажется, это замечательно, но давайте посмотрим, как это будет выглядеть в случае FPGA. Если мы просто подключаем кнопку к светодиоду при помощи FPGA, то мы просто связываем кнопку и светодиод. Значение от кнопки передаётся через какой-то входной буфер, подаётся через матрицу трассировки, а затем выводится через выходной буфер. Этот процесс непрерывно повторяется всё время. Единственная задержка возникает из-за задержек коммутации транзисторов в чипе, которые невероятно малы.
Давайте расширим нашу конструкцию и добавим в неё микрофон. Мы можем брать сэмплы с микрофона и выполнять их обработку, чтобы определять частоты перехваченного аудио. По собственному опыту знаю, что это довольно сложно делать на маленьком микроконтроллере в реальном времени с приличной частотой сэмплирования. Процессору необходимо жонглировать считыванием сэмплов с микрофона, сохранением их в некий буфер, выполнением математических действий и выводом значений, например, на дисплей из светодиодов. Каждый из этих этапов требует времени, а процессор может выполнять только по одному этапу за раз.
При использовании FPGA можно выделить небольшой фрагмент архитектуры для считывания сэмплов с микрофона. Затем можно передавать сэмплы в буфер, а при его заполнении отправлять их в цепь, которая будет выполнять вычисления. Далее эта цепь может передавать результаты другой цепи, которая будет отображать светодиодами.
Каждый из этих этапов будет работать совершенно независимо друг от другого, потому что они просто существуют в оборудовании. Это не строки кода, конкурирующие за процессорное время.
А теперь представьте, что нам всё ещё нужно, чтобы кнопка была привязана к светодиоду. Раньше мы получали потрясающее время ответа в миллионы доли секунды, которое теперь превратилось в ужасающую пятую часть секунды, потому что мы не можем выделить достаточно процессорного времени, чтобы считывать кнопку так часто. Однако в FPGA кнопка и светодиод просто соединены вместе и реагируют почти мгновенно, как и раньше.
Такая независимость делает FPGA потрясающим кандидатом для управления всем тем, что требует быстрых таймингов. Например, светодиод WS2812B (он же NeoPixel) требует точного тайминга потока импульсов, чтобы записывать в них данные. При использовании микроконтроллера обычно необходимо писать встроенный ассемблер только для того, чтобы тайминг импульсов был достаточно точным. Также нужно отключить прерывания, потому что любые простои будут мешать сигналу.
При работе с FPGA достаточно просто создать последовательность чётко контролируемых импульсов для управления этими светодиодами; при этом не нужно беспокоиться о том, что какой-то другой элемент архитектуры конфликтует с таймингом.
Когда стоит использовать FPGA
Учитывая все плюсы применения FPGA, можно задаться вопросом: «Почему бы их не использовать для всего?». Отличный вопрос!
В описании работы FPGA можно было заметить, что для динамической реализации даже простейшей цепи нужно множество всего дополнительного. И это имеет свою цену, как в долларах, так и в ресурсах на проектирование.
FPGA обычно дороги. Самые крупные легко могут стоить тысячи долларов за чип. Это связано с большим количеством микросхем для их производства, затратами на исследования и разработки для проектирования чипов и инструментов, а также с относительно небольшими тиражами по сравнению, например, с крошечными процессорами, которые используются в телефонах.
Ещё один аспект затрат — это энергопотребление. В LUT используется множество транзисторов по сравнению с количеством, необходимым для непосредственной реализации цепи. Всем этим транзисторам требуется питание. Из-за этого FPGA оказываются плохими кандидатами для работы в устройствах на аккумуляторах. Разумеется, можно спроектировать цепи так, чтобы они были экономичными, но даже когда абсолютно ничего не делает, FPGA на Alchitry Au потребляет чуть больше 100 мА. Если начать использовать чип, то запросто можно получить больше 1000 мА. Для сравнения: чип ATmega32U4, используемый в Arduino Leonardo, на полной мощности потребляет 27 мА при 5 В. Хотя нужно учесть, что Alchitry Au гораздо более функциональный.
Так зачем же вообще использовать FPGA? При создании собственной цифровой цепи у вас есть два основных варианта. Во-первых, её можно создать самостоятельно из дискретной логики. Для этого понадобится существенное количество времени, гораздо больше затрат, а если понадобится что-то поменять, то гибкость окажется гораздо ниже.
Вторая, более реалистичная альтернатива заключается в проектировании цепи непосредственно в кремнии. При этом вы создадите очень быструю и эффективную цепь, но ценой нулевой гибкости и кучи денежных затрат. Огромные предварительные затраты на собственные микросхемы связаны с инструментарием и подготовкой. Однако инкрементные затраты на чип будут меньше, чем за отдельные FPGA. Впрочем, если вы не изготавливаете десятки тысяч чипов, это всё равно будет более затратным. Но даже при больших партиях иногда не имеет смысла замыкать свою архитектуру в кремний. При использовании FPGA можно изменять её в любой момент и без дополнительных затрат.
Благодаря своей гибкости и низкой стоимости по сравнению с альтернативами, FPGA открывает возможности добавления собственных цифровых цепей практически в любую архитектуру. Но нужна ли вам собственная цепь на самом деле?
Важно помнить, что FPGA — это просто один из инструментов. Молоток отлично подходит для забивания гвоздей, но ужасно справляется со вкручиванием шурупов. И забивать гвоздь отвёрткой тоже будет очень неудобно.
Создание собственных цепей может быть сложной задачей, и иногда стоит задаться вопросом, нет ли решения получше. Существует множество очень функциональных процессоров с кучей периферии, способных справляться с большинством ваших задач. Выполнение некоторых задач, например, получение и отправка данных через WiFi, может быть пугающим процессом при работе с FPGA, но легко выполнимым с микроконтроллером за несколько долларов, например, с ESP8266.
Я часто сравниваю FPGA со сборочной линией. Каждый участок сборочной линии не зависит от другого и чрезвычайно эффективно выполняет свою цель. Однако первоначальная подготовка линии может быть сложной работой, а иногда при внесении серьёзных изменений проще начать всё с нуля.
С другой стороны, процессоры похожи на людей. Если дать человеку время и обучить его, то он может выполнить практически любую задачу. Человеку легко выполнять сложные последовательные работы.
Действительно ли вам нужно организовывать целый завод по производству сэндвичей, если вы хотите просто сделать сэндвич на обед?
FPGA потрясающи и часто становятся незаменимыми в подходящих для них задачах, но это всего лишь один из инструментов. Очень мощный и стоящий изучения, но всё-таки ещё один инструмент.
Ресурсы и дальнейшее изучение
Мы изложили основы работы FPGA и их составляющих. На веб-сайте Alchitry есть множество других отличных ресурсов, в том числе туториалы, проекты и форум Alchitry.
Если вы хотите глубже погрузиться в мир FPGA и Lucid, то изучите «Learning FPGAs: Digital Design for Beginners with Mojo and Lucid HDL» Джастина Раевски. Эту книгу можно приобрести на Amazon, это отличный ресурс для понимания и проектирования собственных FPGA.
Telegram-канал с розыгрышами призов, новостями IT и постами о ретроиграх