Для чего нужен vhdl
VHDL с нуля.
VHDL с нуля. Выпуск первый — VHDL в картинках.
Статья предназначена для желающих освоить VHDL с нуля, но более опытное пользователи могут читать и вносить свои предложения. О языке буду рассказывать безотносительно какого-либо железа, так как особенности синтеза и реализации в железе написанного кода это отдельная тема, здесь же я хотел бы передать концепцию(идею) проектирования(да именно проектирования, а не программирования) цифровых устройств с использованием языка VHDL. В качестве среды для моделирования буду использовать ModelSim. Так как существует достаточное количество статей по VHDL, например тут, некоторые места не буду подробно рассматривать, а буду ссылаться. По поводу точности определений, для маньяков таких как я, любящих точные определения есть стандарт(тут), но читая его можно сломать мозг и как это не парадоксально, чтобы его читать уже нужно иметь представление о языке, как мне кажется. В данной статье я попытаюсь менее четко формулировать понятия, для того что бы сделать их более понятными, принимаются все предложения по их коррекции.
VHDL(Very high speed integrated circuits Hardware Description Language)- данный язык предназначен для описания проектируемых систем на схемотехническом уровне проектирования и замены классического подхода к схемотехническому проектированию на уровне отдельных элементов. Язык позволяет описывать цифровые ситемы на алгоритмическом уровне. При помощи специального программного обеспечения описание на языке VHDL преобразовывается в схему на уровне простейших элементов цифровой электроники. Описание на языке применятся VHDL как при проектировании
заказных СБИС так и при проектировании цифровых систем на базе специальных устройств ПЛИС(Программируемые логические интегральные схемы).
Теперь перейдем к основным понятиям языка(это моя трактовка):
Как же выглядит структура проекта. заглянем в замечательную книгу П.Н.Бибило Основы языка VHDL.
Что мы видим из рисунка: на одном уровне описывается интерфейс объекта проекта и архитектура объекта проекта, плюс если требуется к каждому интерфейсу можно подключить требующийся пакет. В свою очередь тело архитектуры состоит из параллельных операторов, среди которых может быть оператор процесса, содержащий последовательные операторы. Обратите внимание, что сигналы декларируются на уровне архитектуры, а переменные на уровне отдельных процессов и используются внутри их.
Всего имеется четыре класса типов: скалярный, составной, файловый и ссылочный(в стандарте за 200 год нашел еще пятый — защищенный тип, может потом рассмотрю). Вот они
Зелененьким светофором обозначил типы которые синтезируются, т.е. их смело можно использовать при написании программ для программирования ПЛИС. Пример объявления типов посмотри на основе предопределенных типов в пакете STANDART.
Достану несколько оттуда:
С остальными типами советую ознакомится из пакета. При синтезе используется пакет std_logic_1164. Он хорошо описан в статье, на которую я дал ссылку в начале. Единственное, не рассмотрено использование безразличного состояния, его применение я рассмотрю позже.
Еще один нюанс, необходимо понимать, что все типы при синтезе преобразовываются в типы std_logic(расширенный эквивалент bit) и std_logic_vector(расширенный эквивалент bit_vector).Т.е. все значения перечислимых типов будут закодированы двоичными комбинациями и целый тип так же будет закодирован двоичными комбинациями.
Способы задания значений.
В VHDL для задания числовых значений используются литералы. Вот они
Далее посмотрим декларации, которые нам могут понадобится в самом начале, более сложные будем рассматривать позже при рассмотрении последующих тем.
Операторы используемые в выражениях.
Я думаю здесь все понятно, объясню только оператор конкатенации(&) — он нужен для объединения нескольких битовых строк в одну.
1. Оператор присваивания значений переменной(:=) — A := B and C;
Вводная. ПЛИС в картинках, а также немного о языках VHDL и Verilog.
Лично я в ПЛИС влюблён давно и бескорыстно, ещё с тех пор, как впервые услышал саму идею программируемой логики.
Посему, работаю с ними уже довольно давно, а так же немножко преподаю в университете.
Этой статьёй я хотел помочь начинающим поскорее освоиться и избежать стандартных ошибок. А ещё, хотел показать, что в «низкоуровневом копании» в ПЛИС мало того, что нет ничего страшного, так оно ещё и помогает добиться от микросхемы именно того результата, который нужен, вместо «ой, что это» 🙂
Думаю, мало для кого является секретом тот факт, что ПЛИС это микросхема, состоящая из большого количества относительно несложных логических блоков, соединённых очень большим количеством проводов. На каждом из этих проводов стоит ключ, который позволяет разорвать связь. Правильно задав состояние всех ключей, можно получить практически любую цифровую схему, в том числе и ту, которая требуется для какой-либо практической задачи.
Состояние этих ключей задаётся битами, записанными в так называемую конфигурационную память. Эта память может быть разных типов.
Чипы с энергонезависимой конфигурационной памятью в наше время обычно называются CPLD. Они, как правило дёшевы, имеют довольно простую структуру и относительно небольшое число логических элементов. Это связано с особенностями процесса производства.
А вот чипы с энергозависимой памятью, именуемые FPGA, могут быть самого разного размера и стоимости от 300 рублей за какой-нибудь xc3s50a (самый маленький чип семейства Spartan 3A abhvs Xilinx) до… хм… в общем, смотрите сами 🙂
search.digikey.com/scripts/DkSearch/dksus.dll?vendor=0&keywords=XC6VLX760
Ещё иногда встречаются гибриды — например, семейство Spartan3AN. Буква N означает, что в корпус FPGA Spartan3A вставили дополнительную флешку, с которой он может загружаться.
Но что-то я отвлёкся.
Итак, чтобы сделать из пустой программируемой логической матрицы нужную нам схему, эту схему надо для начала хоть как-то описать. Можно рисовать графическую схему, вручную задавая все связи между элементами. Но это, во-первых, громоздко, а во-вторых, базовые элементы микросхем разных семейств могут сильно отличаться — порой, при переносе схемы на другую микросхему её будет проще переписать заново, чем адаптировать…
Значит надо выбираться на уровень большей абстракции. Можно, опять же графически, соединять абстрактные примитивы типа «регистр», «сумматор», «мультиплексор» и т.п., из которых специальная программа (синтезатор) потом сформирует описание схемы уже из базовых элементов нужного семейства микросхем.
Это более переносимый вариант, но в серьёзных проектах и такие схемы очень быстро становятся огромными и нечитаемыми.
Поэтому, на данный момент, большинство разработчиков пользуется текстовым описанием логических схем.
Языков для этого существует великое множество.
VHDL — очень старый, но развивается, и по-прежнему очень популярен. Довольно громоздкий. Строгий, позволяет избежать многих ошибок.
Verilog — новее, лаконичнее, свободнее. Легче делать ошибки. Тоже очень популярен. Кроме того, на нём гораздо удобнее писать benchmark’и для симуляции (до этого мы ещё когда-нибудь дойдём).
SystemVerilog — расширенный вариант Verilog, ещё только набирает популярность, к тому же не поддерживается ПО Xilinx =( (Но для микросхем Xilinx с него всё же можно синтезировать с помощью сторонних программ, например Synplify). Раскрывает все свои прелести только на действительно больших проектах.
AHDL — только для микросхем фирмы Altera, к тому же довольно старый. Кажется, даже горячие поклонники Альтеры его уже по большей части забросили.
Это те, что часто мелькают на виду. Есть ещё экзотика типа Verilog-AMS для смешанных цифро-аналоговых схем.
Ну и вообще, если покопаться, можно много чего найти, но в данной статье я буду приводить примеры на VHDL и Verilog — сегодняшних стандартах де-факто.
Наверное, пора бы уже начать что-нибудь делать, а не только языком чесать. Для работы нам понадобится программный пакет Xilinx ISE, любую версию которого можно скачать тут
www.xilinx.com/tools/webpack.htm
Бесплатной лицензии WebPack нам хватит выше крыши. Правда, чтобы её получить, придётся зарегистрироваться. Ну или воспользоваться более традиционными отечественными методами установки ПО, если кому лень.
На данный момент только что вышла версия 13.1. Кто боится «свежего глючного», может ставить 12.4 — отличий не найдёт. У меня стоит 13.1, работает без проблем.
Итак, поставили, запускаем PlanAhead (да, именно его, а не Project Navigator, как тут некоторые советуют).
Жмём Create New Project, как-нибудь его обзываем, дальше выбираем тип проекта. Есть куча разных, но нас интересует синтез с нуля с текстовым описанием — выбираем Specify RTL Sources (RTL значит Register Transfer Level. К чему это — тоже станет со временем ясно, надеюсь).
Дальше нам предлагают добавить файлы исходников, жмём Create File.
Выбираем язык — Verilog или VHDL, кому как больше нравится, и задаём имя файла. Лучше всего для каждого модуля делать отдельный файл. В нашем примере модуль будет один, основной, он же корневой. Я такие модули обычно, не мудрствуя лукаво обзываю root.
Existing IP у нас пока не exists. Constraints (ограничения) тоже пока оставляем пустыми — они нам пригодятся несколько позже, тогда и добавим.
Потом выбираем микросхему, под которую собственно собираемся ваять.
Я выберу самую маленькую микросхему семейства Spartan3AN — самый подходящий вариант для начинающих изучать FPGA, не очень старая, позволяет не тратить бешеных денег и не заблудиться во внутренних ресурсах кристалла 🙂
К тому же, она входит в состав одной из самых дешёвых и, кажется, популярных плат SK-M-XC3S50AN(не сочтите за рекламу. Если что, могу убрать).
Итак, задали настройки, посмотрели, что всё так как надо.
У меня получилось вот так
И наконец-то создали проект.
Теперь напишем схему. Для простоты возьмём банальное логическое И.
Для начала подключим библиотеку:
В ней содержатся типы std_logic и std_logic_vector, которые понадобятся нам для описания цифровых схем.
ВНИМАНИЕ! Схемы у нас чисто цифровые, сигналы (напряжения на проводах) могут быть ТОЛЬКО 0 (земля) и 1 (питание). Никаких Integer’ов и прочей дребедени в синтезируемой схеме быть не должно, только биты и группы бит. Всё остальное ТОЛЬКО ДЛЯ СИМУЛЯЦИИ.
Чтобы сымитировать окружение ПЛИС, прогнать какие-то тесты, всё хорошенько проверить, можно писать так называемые benchmark’и — это модули-обёртки для синтезируемых (тех, из которых синтезируется прошивка для ПЛИС) модулей. benchmark’и пишутся обычно на том же языке, что и синтезируемые модули, но в benchmark’ах используются и Integer’ы, и файловый ввод-вывод, и вообще что угодно. Но это только для симуляции.
Некоторые синтезаторы пытаются сочинить что-то из любого текста, который им подсунут, но результаты чаще всего далеки от идеала. И как правило далеки от того, что имел в виду автор.
Так что, только биты, и ничего кроме битов.
Дальше описываем наш модуль, на языке VHDL «сущность» (entity).
Это корневой модуль, он соответствует всей микросхеме в целом. Из него торчат три ноги — два входа и один выход. Это значит, что у нашей микросхемы так же будет задействовано три ноги (не считая служебных типа питания, земли и JTAG’а).
Дальше мы описываем архитектуру нашего модуля. Вообще, в VHDL у каждого модуля может быть несколько архитектур, но это опять же от лукавого (и для симуляции). Здесь архитектура одна, и обзывать мы её можем как хотим (здесь «Behavioral»).
А внутри описания архитектуры мы (внимание!) соединяем провода.
Не пишем программу, не описываем, боже упаси, алгоритм, а соединяем провода. Ну, можем ещё соединять их через какую-нибудь логику. Например через И.
Это значит, что на выход y подаётся 1 тогда и только тогда, когда на обоих входах 1. Иначе 0.
В итоге получается вот такой файлик:
Verilog
Тут как-то всё пока очевидно, даже не знаю что ещё сказать.
А, да комментарии — как в С // или /**/ 🙂
Сборка
Теперь жамкаем слева большую зелёную стрелочку Synthesize (если стрелки не видно, то сначала Ctrl+Q). Комп шустро синтезирует из нашего текстового описания логическую схему. Если есть ошибки, это можно увидеть в правом верхнем углу вкладки Project Summary. Оттуда же по ссылке можно эти ошибки почитать.
Если всё ОК, тыкаем на вторую зелёную стрелку Implement. Это просьба разложить логические элементы по кристаллу и просчитать, какими проводами они будут соединяться.
Ну а теперь полюбуемся, что получилось.
Жмём уже вот эту стрелочку
В появившемся меню выбираем Open Implemented Design и дальше единственный имеющийся.
И вот мы наконец-то увидели наш кристалл, а так же нашу грандиозную схему схему 🙂 (обведена кружком).
По краю видны, что характерно, ноги. Мелкие клеточки внутри — логические блоки. Большие квадраты — DCM’ы (Digital Clock Managers), Большие вытянутые прямоугольники — блоки памяти и умножители.
Но это всё потом, нас интересует наша схема.
Из всей стаи непонятных тараканчиков выделен (задействован) только один — наш единственный логический элемент, а так же три ноги микросхемы — P75, P76 и P78.
Выделив любой элемент и нажав F4 (или Schematic через всплывающее меню) можно увидеть схему.
При помощи двойного клика по любой ноге на схеме можно увидеть все присоединённые к ноге элементы.
Вот, собственно, что у нас получилось:
По краям пины микросхемы, чуть ближе к центру входные и выходной буферы, а в самой середине — единственный наш осмысленный элемент — логическая функция.
LUT — это Look-Up Table, простейший логический элемент в FPGA. На схеме у неё задействовано(и изображено) только два входа, но на вкладке Device (той, что открылась сначала) при подходящем зуме можно увидеть, что у неё 4 входа. Вообще, в разных семействах микросхем у них может быть разное количество входов. В Spartan3 LUT’ы 4х-входовые и могут реализовать любую логическую функцию. То есть это по желанию может быть OR4, или AND4, или NOR4, или какая-нибудь фигня типа (A & B) | (
По сути, LUT это маааленький блок памяти на 16 бит — входы задают адрес, а на выходе получаем однобитные данные. В памяти храница таблица истинности нужной функции.
(Посмотреть, какая именно функция реализована в конкретной LUT через PlanAhead мне, почему-то, так и не удалось, но можно выделить нужный элемент, ткнуть в него правой кнопкой мыши и в меню выбрать Cross-probe to FPGA Editor. Откроется FPGA Editor, в котором можно разглядеть вообще всё что угодно, но он гораздо менее удобный.)
Помимо LUT, которые реализуют произвольную логику, есть ещё более мелкие и специализированные элементы. Например, «логика ускорения переноса» позволяет делать более экономные по ресурсам и быстрые сумматоры/вычитатели/счётчики.
Реализуем, для примера, простенький 16-битный сумматор.
Verilog
Видно, что теперь задействованы дополнительные элементы помимо LUT.
Синхронщина
Всё это, конечно, хорошо, но где же зависимость от времени? Где тактовая частота?
Щас будет.
Пишем счётчик.
Точнее, напишем чрезвычайно полезную в хозяйстве и столь же редкую штуку — мигание светодиодом 🙂
Предположим, что к микросхеме подведён тактовый сигнал 20 MHz (кварц взяли первый попавшийся, от ближайшей AVR’ки), а светодиодом надо мигать полтора раза в секунду. Проблема? Да ни фига 🙂
Вообще, для извращений с тактовыми сигналами и частотами в FPGA есть специальные блоки — DCM (Digital Clock Manager) — они позволяют делить частоты, синхронизовать тактовые сигналы по фазе, даже умножать(!) частоты. Но вот беда, они рассчитаны на быстрые сигналы (от 5 МГц, кажется), а мигать нам надо с частотой 1.5 Гц. Ну ничего, поделим вручную.
Нам надо мигнуть светодиодом полтора раза в секунду, то есть изменить напряжение на управляющей светодиодом ноге 3 раза за секунду (полтора раза зажечь и полтора раза потушить :). Это значит, что изменять напряжение надо каждые 20*10^6 / 3 = 6666667 тактов (16 с хвостом наносекунд погрешности, образовавшиеся при округлении считаем приемлемыми :).
Как отсчитать нужное количество тактов? Счётчиком.
Нам потребуется 23-битный счётчик, он может досчитать аж до 8388607. От 0 до 8388607 — период 8388608. Нам явно много, но ничего, справимся.
Для начала напишем собственно счётчик и посмотрим, во что он синтезируется.
Считать будем, когда вход enable_n притянут к земле.
Ещё, в более-менее сложных цифровых схемах считается хорошим тоном иметь сигнал reset, который полностью возвращает схему в исходное состояние. Это, например, чтобы в любой момент можно было замкнуть пару проводков отвёрткой и начать отладку сначала — очень удобно. Или при сбое питания аккуратно перезагрузить схему, или ещё что…
Verilog
Для работы с синхронными сигналами в FPGA предусмотрено большое количество триггеров. Это самые обычные D-триггеры.
Обратите внимание, что в Verilog мы явно указываем, что биты счётчика это регистры (reg), или иначе — триггеры. А не wire, то есть просто провода.
А в VHDL всё это пишется одинаково — signal. Но умный синтезатор заметит, что напряжение на проводе должно меняться по фронту клока и сам поймёт, что туда надо воткнуть триггер.
Видим, что теперь в схеме почти не задействованы LUT. Задействована только логика переноса и триггеры (справа).
Посмотрим повнимательнее на триггер.
Он самый обычный, у него есть вход для бита данных, выход, один тактовый вход. И ещё входы CE — Clock Enable, и CLR — вход сброса.
В нашем случае на CE подан наш enable_n, а на CLR — reset.
(Ну, на самом деле не совсем обычный. Например, в зависимости от конфигурационного бита, вход сброса может работать синхронно и не синхронно. А ещё Триггер может выступать в роли защёлки(Latch) — работать не по фронту, а по значению сигнала, о это редко пригождается.)
Тактовый вход — только один. В частности это означает, что один регистр может тактироваться только одним тактовым сигналом. А то новички часто порываются менять один и тот же сигнал по двум разным клокам при разных условиях. Не выйдет, чудес не бывает )
О частотах
Очевидно, что наш счётчик не сможет работать на любой частоте, где-то у него есть потолок. Но где?
Любой элемент ПЛИС(LUT, триггер, даже провода-межсоединения), через который проходит сигнал, вносит в сигнал некоторую задержку.
За время от одного фронта тактового сигнала до следующего, сигнал, защёлкнувшийся на триггере Counter_13 должен успеть дойти до триггера Counter_14, чтобы защёлкнуться на нём.
Точнее, все сигналы должны успеть дойти от одного триггера до следующего.
Таким образом, максимальная рабочая частота определяется временем прохождения самого длинного пути в схеме.
Но мы никак не указали, программе-синтезатору, на каких частотах должна работать наша схема. По идее он может разбросать элементы даже несложной схемы по разным углам кристалла, и из-за задержек на межсоединениях работать всё это будет очень медленно (при почти пустом кристалле, как у нас сейчас, такая ситуация маловероятна, но при заполнении в 80-90% — запросто).
Так что, расскажем ему, на всякий случай, что у нас предполагается тактовый сигнал в 20 МГц.
При открытом Implemented Design слева появляется вкладка Timing Constraints.
Находим там Basic period и тыкаем в него два раза (или правой кнопкой > New Timing Constraint).
Задаём в окошке частоту.
Синтезатор сам определил, что тактовый сигнал у нас — clock.
Теперь при синтезе нашу схему не только будут пытаться упихать в заданный тайминг, но и бонусом напишут максимальную частоту, на которой она гарантированно заработает в данном чипе.
(Слева — прикидочная частота, вычисленная после начального синтеза. Её нам показывали и раньше. А справа — уже точная, полученная после раскладки элементов по чипу. Эту нарисовали только после добовления constraint’а.)
Timing Score: 0 — это означает, что вся схема улеглась в заданный тайминг.
А это
Unrouted: 0 — число путей, которые в тайминг уложить не удалось. Ни одного, всё ОК.
Вернёмся к нашим светодиодам
Теперь подгоним нашу схему, чтобы частота мигания соответствовала ТЗ.
Verilog
Обратите внимание, как просела частота. Компаратор 23-х битного числа даже с константой — штука не дешёвая.
Всё, наверное пора заканчивать, и так простыня жуткая получилась.
PS Писал в один присест, так что в конце мозг уже отключался.
Написал не всё, что хотел. Если тема хорошо пойдёт, выдам ещё пару статей.
Для чего нужен vhdl
VHDL (англ. VHSIC (Very high speed integrated circuits) Hardware Description Language ) — язык описания аппаратуры интегральных схем. Язык проектирования VHDL является базовым языком при разработке аппаратуры современных вычислительных систем.
Был разработан в 1983 г. по заказу Министерства обороны США с целью формального описания логических схем для всех этапов разработки электронных систем, начиная модулями микросхем и заканчивая крупными вычислительными системами.
Первоначально язык предназначался для моделирования, но позднее из него было выделено синтезируемое подмножество. Написание модели на синтезируемом подмножестве позволяет автоматический синтез схемы функционально эквивалентной исходной модели. Средствами языка VHDL возможно проектирование на различных уровнях абстракции (поведенческом или алгоритмическом, регистровых передач, структурном), в соответствии с техническим заданием и предпочтениями разработчика. Заложена возможность иерархического проектирования, максимально реализующая себя в экстремально больших проектах с участием большой группы разработчиков. Представляется возможным выделить следующие три составные части языка: алгоритмическую — основанную на языках Ada и Pascal и придающую языку VHDL свойства языков программирования; проблемно ориентированную — в сущности и обращающую VHDL в язык описания аппаратуры; и объектно-ориентированную, интенсивно развиваемую в последнее время.
VHDL создан как средство описания цифровых систем, однако существует подмножество языка — VHDL AMS (Analog Mixed Signal), позволяющее описывать как чисто аналоговые, так и смешанные, цифро-аналоговые схемы.
Содержание
Стандарты
Открытое аппаратное обеспечение, использующее VHDL
На языке VHDL созданы описания открытых микропроцессоров ERC32 (SPARC V7) и LEON (SPARC V8). Исходный код доступен под лицензиями LGPL и GPL соответственно.