Домой / Группы / Что такое плис и зачем они нужны. Сделай шаг к плис

Что такое плис и зачем они нужны. Сделай шаг к плис

Написать эту статью заставили меня товарищи, которые очень хорошо (гораздо лучше меня) разбираются в контроллерах и применяют их везде, где ни попадя. Тем не менее, есть огромная куча приложений, когда применение ПЛИС не только оправдано, но и приводит к значительному упрощению системы и улучшению ее параметров. Сразу оговорюсь: в этой и, возможно, последующих статьях я рассматриваю ПЛИС только фирмы Xilinx не потому, что они мне заплатили, и даже не потому, что они лучше всех, просто исторически сложилось, что работаю я практически только с ними.

Итак, начнем с небольшого количества теории. ПЛИС делятся на две основных группы: CPLD (Complex Programmed Logic Device) и FPGA (Field Programmed Gate Array). CPLD - это обычно ПЛИС класса "эконом", т.е. имеют невысокую цену и довольно скудное количество ресурсов, особенно это заметно на триггерах. FPGA обычно подороже, содержат побольше ресурсов (простой логики - триггеров...) и, самое важное, в последнее время дополнительные "непростые" блоки, как, например, умножители, блоковую память, интерфейсные причиндалы (Ethernet, PCI-express...) и даже процессорные ядра PowerPC. Отдельно можно упомянуть серию Zinq от Xilinx - туда вообще ядра ARM запихали. Главным же отличием FPGA от CPLD является потребность в загрузке конфигурации при включении питания и, соответственно, внешней ПЗУ с конфигурацией. Даже семейство SPARTAN-3AN имеет на борту встроенную ПЗУ-шку, из которой и грузится.

Теперь самое главное: чем ПЛИС отличается от контроллера и когда их применять. Тут всё довольно просто: ПЛИС (берем те, что без наворотов) - это, по сути, мешок логики на одном кристалле, которую можно произвольно соединять: те самые триггеры, AND, OR и тому подобные примитивы, как, например, в серии К155 или 74НС. Контроллер же - это готовый процессор (пусть со скудным количеством команд), встроенная память, шины данных и команд, периферия и т.д. В общем-то говоря, из большой ПЛИС можно сделать маленький контроллер, но эта затея, по крайней мере, глупая. Итак, контроллер заточен под выполнение длинных цепочек команд, их циклического повторения, переключения с одной цепочки на другую и т.д., а ПЛИС заточена под выполнение простых логических операций и, что немаловажно, большого количества сразу (и даже на разных тактовых частотах).

Перейдем от теории к практике. Для начала нам хватит какой-нибудь микросхемы CPLD. Ресурсов мало, но для освоения самое оно. Я возьму XC95288XL в корпусе TQ144 (опять же просто оказалась в наличии), вообще рекомендую взять что-нибудь посвежее, например, из серии CoolRunner 2 . Чтобы получить готовое изделие (пусть даже минимально мигающее светодиодом), нам необходимо: спаять аппаратную часть (тут, я надеюсь, проблем не возникнет, а нюансы я упомяну), "написать" прошивку (в нашем случае, скорее, нарисовать) и зашить прошивку в микросхему. В общем, нам понадобятся софт, генерящий прошивку, и программатор. Софт (Xilinx ISE Webpack) качаем с официального сайта (правда, попросят зарегистрироваться), лицензия Webpack - свободная. Программатор можно сделать по схеме на рис.1 (под LPT-порт) или приобрести заводской USB-шный (в китайских интернет-магазинах встречал по цене порядка 50$, но сам не покупал). Более .

Рис. 1

После того, как мы припаяли ПЛИС на макетную плату, спаяли или купили программатор, скачали и установили пакет ISE Webpack (у меня версия 13.2), запускаем Project Navigator и создаем новый проект. Чтобы создать проект, выбираем File -> New Project, указываем имя проекта и куда его сохранить, также указываем тип исходника TOP-LEVEL (рис.2). Дело в том, что для ПЛИС не обязательно рисовать схему из триггеров и их соединений, можно, например, писать на языках высокого уровня (VHDL, Verilog) и совсем не обязательно в пределах одного проекта использовать что-то одно. Мы же пока используем только Schematic на всех уровнях.


Рис. 2
(рисунок кликабелен для увеличения, откроется в новом окне)

В следующем окошке (рис. 3) выбираем нашу микросхему (остальное поначалу не трогаем); в окне, появившемся после нажатия на кнопку "Next", любуемся на параметры созданного проекта, жмем "Финиш" - и готово: проект создан.


Рис. 3

Теперь надо, собственно, нарисовать схему: правым кликом на окошко с проектом и new sourсe (рис 4.), нарекаем этот исходник именем (это имя нашей схемы, их в проекте может быть много), выбираем опять-таки Schematic, жмем "Next", любуемся на параметры вновь создаваемого файла, жмем "Финиш" и получаем чистую схему.


Рис. 4
(рисунок кликабелен для увеличения, откроется в новом окне)

Начинается самое интересное: на панельке слева (не с самого краю) жмем кнопочку "add symbol" (рис. 5).


Рис. 5
(рисунок кликабелен для увеличения, откроется в новом окне)

И получаем еще левее список символов текущей библиотеки. Как добавлять, создавать, править библиотеки, разберемся потом (по мере необходимости). Сейчас нам важно выбрать необходимый символ. Так в верхнем окошке мы видим некий классификатор - фильтр, которым пользоваться не обязательно (ну зачем же пролистывать всякие триггеры и логические элементы, когда нам нужен счетчик).

Для примера рассмотрим следующую задачу: нужно максимально точно определить время задержки между передними фронтами 2-х импульсов, появляющихся на разных проводах, и слить это значение в контроллер по интерфейсу SPI. Всякое сходство задачи с темой "Повышение рабочей частоты МК" на одном из робототехнических форумов умышленное. Итак, на входе устройства 2 провода для импульсов и 3 провода для SPI контроллера. Добавляем еще вход тактирования (пока мы не знаем на какой частоте, можем только предположить, что не менее 70 МГц). Начинаем рисовать прошивку: нам нужны триггеры-защелки, которые будут "ловить" импульсы, счетчик времени, регистр сдвига (создавать их не надо, они есть библиотечные). Что такое триггеры и счетчики, описывать не буду, надеюсь, читатели "в теме" и проблем не возникнет, в противном случае придется писать еще несколько статей. Получили вот такую схему (рис. 6), как вы видите, необязательно тянуть провод от выхода символа до входа, достаточно просто обозвать цепь. Для обозначения внешних входов и выходов используем кнопку "Add I/O Marker".


Рис. 6
(рисунок кликабелен для увеличения, откроется в новом окне)

Когда схема готова, переходим на вкладку Design, и даблкликаем на Implement Design - начинаются всякие процессы (для начала не важно какие именно - главное, что всё вместе - это процесс перегонки исходника в прошивку). Когда всё отработает, смотрим на эрроры с варнингами: всё, что важно, исправляем, остальное оставляем. Например, не нужны нам выходы СЕО и ТС счетчика и остальные 15 бит параллельного выхода регистра сдвига тоже не нужны, а варнингами ругается. Если ругается эррорами на то, что мы так и хотим, значит, мы хотим чего-то не того. Если нас (и синтезатор) всё устраивает - любуемся дальше на репорты: сколько каких ресурсов израсходовано, какие тактовые частоты доступны... Если опять всё хорошо, то самое время просимулировать схему и убедиться, что она, собственно, работает согласно поставленной задаче. Симуляцию после проверки таймингов я предлагаю проводить по причине того, что иногда для получения нужной тактовой частоты приходится всю схему перетрясти, что, естественно, может сказаться на результате...

Итак, симуляция: на вкладке Design (в левой панельке) выбираем simulation (рис. 7).


Рис. 7
(рисунок кликабелен для увеличения, откроется в новом окне)

Внизу, в процессах, вместо процессов синтеза и разводки появился процесс Simulate Behavioral Model, даблкликаем на него - запускается симулятор, в котором мы видим наши сигналы (не только входные-выходные, но и промежуточные) (рис 8).


Рис. 8
(рисунок кликабелен для увеличения, откроется в новом окне)

Наводим на кнопочки курсор мышки, читаем комментарии к кнопочкам. Устанавливаем время шага симуляции (рис. 9) и начальные значения входных сигналов, сразу же настраиваем тактовые сигналы (не будем же мы каждые 5 нс симулировать и клок переключать).


Рис. 9
(рисунок кликабелен для увеличения, откроется в новом окне)

Шагая по времени путем манипуляций с входами и (при необходимости) с шагом симуляции, получаем временную диаграмму (рис. 10).


Рис. 10
(рисунок кликабелен для увеличения, откроется в новом окне)

Убеждаемся, что всё работает так, как задумано (или отлаживаем схему дальше), и переходим к следующему шагу - распределению выходов и входов по ножкам микросхемы. Для этого добавляем еще один файл-исходник (рис. 11), а именно Implementation Constraints File.


Рис. 11
(рисунок кликабелен для увеличения, откроется в новом окне)

Прописываем "распиновку микросхемы" (рис. 12), здесь же прописываем требования к тактовым частотам. И вот мы дошли до нюанса, связанного с тактовыми сигналами. Дело в том, что сигналы тактирования должны приходить на так называемые глобальные линии - линии, которые проходят через всю микросхему, остальные линии имеют локальный характер и от блока к блоку проходят через коммутационную логику. У микросхемы XC95288XL в корпусе TQ144 таких линий 3, и подключаются они к ногам 30, 32, 38. Остальные сигналы можно подключить к любым ножкам ввода-вывода (I/O).


Рис. 12
(рисунок кликабелен для увеличения, откроется в новом окне)

Снова даблкликаем Implement Design, ждем, читаем замечания на тему варнингов с эррорами и переходим на отчеты по распиновке (рис. 13) и таймингам (рис. 14); убеждаемся в том, что всё нас устраивает, и имеем счастье в виде файла %project_name%.jed.


Рис. 13
(рисунок кликабелен для увеличения, откроется в новом окне)


Рис. 14
(рисунок кликабелен для увеличения, откроется в новом окне)

Файл прошивки готов. Допустим, устройство тоже. Подключаем к ЭВМ JTAG кабель и даблкликаем на Configure Target Device. Запустится утилитка прошивки (Impact.exe), собственно, при изготовлении нескольких устройств для прошивки серии можно ограничиться запуском только ее одной. Создаём новый проект (это проект для программки-прошивалки), разрешаем ей автоматически найти программатор и подключенную микросхему, показываем файл прошивки и жмем Program. Ждем несколько десятков секунд, видим надпись о том, что всё хорошо, - устройство готово.

ВВЕДЕНИЕ

Обычно, когда кто-то видит функционирующую плату, всегда задают одни и те же вопросы: - Это Ардуино? - А как это работает без Ардуино?

Это не микроконтроллер, это даже не процессор, это ПЛИС. ПЛИС - это программируемая логическая интегральная схема , такая микросхема состоит из множества одинаковых блоков или макроячеек, каждый производитель по своему их называет, так у Xilinx это Slices (ломтики) у Altera - LogicElements (логические элементы). Эти блоки относительно простые, они могут выполнять роль нескольких логических элементов, быть маленькой таблицей поиска (LUT), содержать готовый сумматор, умножитель, блок цифровой обработки сигналов (DSP), в общем все что задумает производитель. Пользователь может по своему желанию расположить и настроить эти блоки как ему захочется, реализовав таким образом достаточно сложные цифровые схемы. На ПЛИС можно реализовать хоть микроконтроллер, реализовав например ту же Ардуино или процессор вашей собственной архитектуры, например не регистровый а стековый процессор, даже свою собственную ПЛИС можно реализовать на ПЛИС!

Из доступных бюджетных ПЛИС можно выделить двух основных производителей Altera и Xilinx, с их продукции можно начать свой путь освоения данных технологий. На мой взгляд лучше выбрать чипы компании Altera, так как их среда проектирования стабильно обновляется, а выбрав один популярный чип Xilinx XC3S500E вам придется довольствоваться устаревшей средой ISE 14.7 (хотя и там есть свои плюсы).

В иностранной литературе можно встретить сокращения для ПЛИС: FPGA и CPLD. CPLD (Complex Programmable Logic Device) - чипы с небольшим числом макроячеек, специализированных блоков и малым энергопотреблением. Большой проект не получится синтезировать для такого типа чипов, но и для них находят применение на практике, так у редкого микроконтроллера найдется, скажем 300 ножек. Такие чипы часто применяют в качестве интерфейсных систем, предобработчиков, расширителей ввода-вывода. FPGA (Field-Programmable Gate Array) - программируемая пользователем вентильная матрица (ППВМ), значительно более мощные чипы по сравнению с CPLD, но потребляющие больше энергии и стоящие значительно дороже. Для уменьшения затрат площади кристалла FPGA чипы могут содержать уже готовые функции, такие как блоки цифровой обработки сигналов (DSP блоки), встроенные процессоры, встроенная память. FPGA широко применяются для проверки и верификации проектов, в так называемой докремниевой проверке пригодности, тем самым уменьшая затраты и время перед выходом продукта. FPGA чипы могут быть переконфигурированы практически в любой момент времени, сейчас ведутся разработки, например в Intel, по совмещению архитектур обычного процессора и чипа FPGA. У Xilinx уже есть такие решения - Zynq, но о них мы пока не будет вести речь.

Разговор пойдет о более простых вещах, тем более ко мне в руки попал набор разработчика: Cyclone IV 4 FPGA Core Board и Altera USB Blaster Downloader PLD Development kit за 35$, приобретенный на AliExpress .

1 Демоплата Cyclone IV 4 FPGA Core Board, краткая характеристика

Рис. 1 - Демоплата Cyclone IV 4 FPGA Core Board

На плате (Рис. 1) установлен чип EP4CE6E22C8N, его характеристики:

Вид ресурса Краткое описание Количество
Logic elements (Les) Число логических блоков - ячеек, основная характеристика, по которым мы можем сравнивать «мощность» чипов, любая синтезированная логика будет затрачивать данные блоки 6,272
Embedded memory (Kbits) Встроенной памяти, пока для нас не важная характеристика 270
Embedded 18x18 multipliers Встроенных аппаратных умножителей, очень важный параметр в цифровой обработке сигналов, вся мощь ПЛИС раскрывается, когда несколько умножителей работают параллельно 15
General-purpose PLLs Узлов фазовой автоподстройки частоты, пока не важная характеристика, упрощает синхронизацию устройств, работающих на разных частотах 2
Global Clock Networks Количество частотных доменов, пока не важная характеристика 10
User I/O Banks Число раздельных пользовательских банков ввода-вывода, пока не важная характеристика 8
Maximum user I/O Число пользовательских пинов ввода-вывода, мы можем подключить любые устройства, как например к Ардуино 91

На плате установлено:

  1. Флэш память – при подаче питания ПЛИС будет сконфигурирована в реализацию во флеш памяти. Вы можете синтезировать свой проект и записать в эту флэш
  2. Кварц 25 Мгц – генератор опорной тактовой частоты, именно на этой частоте будут работать все наши проекты, наша ПЛИС может поддерживать до 10 таких каналов.
  3. Светодиоды – 10, кнопки – 2.
  4. Пины ввода-вывода 61 + 2 земля, 1 не соединен. Можно подключить разнообразные устройства. ЦАП-АЦП, акселерометры и гироскопы, символьный и графические дисплеи, как и у Ардуино.
  5. Питание через USB, или внешнее 5В.

В комплекте также идет программатор JTAG, Altera USB Blaster.

2. Среда Quartus II и наш первый проект

Для работы с данной ПЛИС нам нужно скачать официальную среду разработки - Quartus II Web Edition , она бесплатная. Заходим на официальный сайт http://dl.altera.com/15.0/?edition=web , на момент написания версия 15.0 самая новая, если вышла новее, скачиваем ее.

Выбираем:


Рис. 2 - выбираем необходимые продукты Altera

И жмем кнопку скачать (Download Selected Files). После чего нам предложат зарегистрироваться, регистрируемся, скачиваем и устанавливаем.

Создадим свой первый проект.

Запускаем Quartus, выбираем главное меню File -> New Project Wizard, появляется окно введения, жмем next. Далее нужно указать каталог для проекта и его имя, третье поля – имя верхнего модуля, попозже увидите, что это. Выбираем папку, куда хотим сохранить проект и придумываем имя, у меня test1.


Рис. 3 - окно мастра нового проекта

Жмем next, у нас спрашивают, пустой проект (empty project) или шаблон (Project template). Оставляем пустой, next. Дальше нас просят добавить существующие файлы, у нас ничего нет, поскольку мы только начинаем свой путь, жмем next.

Далее нам необходимо выбрать наш чип, это можно сделать в любое время. Выбираем как на рисунке, Family – Cyclone IV E, specific device selected in “Available devices” и выбираем наш чип EP4CE6E22C8N, он в самом начале. Если у вас другой, найдите свой, это важно . Жмем next.


Рис. 4 -

Появится окно - выбора средств проектирования, отладки, пока это пропускаем, нажимаем next и затем finish.


Рис. 5 - Окно « Assinments-Deice »

В окне выбираем пункт «Unused pins». Эта настройка определяет, что будет с неподключенными пинами. Это может быть важно, в своем проекте вы вряд ли используете все пины, а не подключенные могут быть на деле соединены с землей или питанием (ну мало ли, кто разводил плату). Если вы подадите единичку на заземленный пин, то он сгорит, поэтому нужно внимательно следить за этим.

По умолчанию неиспользуемые пины «As input tri-stated with weak pull-up» (пины для ввода, находятся в третьем состоянии с высоким импедансом, со слабой подтяжкой по питанию), можно оставить или выбрать «As input tri-stated». Про подтягивающий резистор можете прочитать на википедии https://ru.wikipedia.org/wiki/Подтягивающий_резистор . В цифровой технике может быть три состояния, логическая единица – это напряжение питания или высокий уровень, логический ноль – это когда вывод подключен к земле или низкий уровень и высокоимпедансное состояние. Высокоимпедансное состояние - это когда пин имеет очень высокое сопротивление и практически не влияет на провод, к которому подключен, такое состояние нужно, например, при организации шин, когда множество устройств подключены к одному проводу и не активные устройства не мешают работе.


Рис. 6 - Окно « Device and Pin Options » , Unused Pins

Подключаем это все в «Assignment Editor»


Рис. 7 - Вызов « Assignment Editor » из меню или панели

В появившемся окне делаем как у меня, ну или если совсем правильно, то согласно схеме вашей платы.


Рис. 8 - Assinement Editor

В колонке «To» вписываем имя входа или выхода. В колонке «Assignment Name» выбираем «Location». В колонке «Value» номер контакта микросхемы, согласно схемы платы (у меня номера пинов написаны прямо на плате).

Также нужно указать, что делать с кнопками, которые одной ногой подключены к земле, а другой ко входу чипа. При нажатии на ноге будет низкий уровень, а вот без нажатия, непонятно, нога чипа будет просто висеть в воздухе, что очень плохо. Нужно подтянуть к питанию вход чипа либо резистором на плате, либо боле элегантным способом в «Assignments Editor». В колонке «Assignment Name» выбираем «Weak Pull Up resistor» для группы key* (группа обозначается через звездочку).


Рис. 9 - Assignment Editor

Далее нужно создать описание модуля верхнего уровня, который будет работать непосредственно с ножками чипа, все остальные модули будут работать только с ним. В главном меню жмем New, и выбираем "Design Files-> Block Diagram/Schematic File".


Рис. 10 - Диалог новых файлов

В открывшемся окне выбираем инструмент «Pin Tool» и располагаем вход и выход (пины ввода и вывода) на диаграмме. Переименовываем вход как key, выход как led и соединяем их проводником. Сохраняем и нажимаем "Start Compilation".


Рис. 11 - Окно графического описания, выделены Pin Tool и Start Compilation

После компиляции у нас возникли предупреждения, пока игнорируем их, они касаются неподключенных пинов, отсутствия тактового сигнала и описания для «Timing Analyzer».

Подключаем демоплату и программатор, выбираем инструмент «Programmer». В окне должно значиться «USB-Blaster », если нет то нажимаем «Hardware Setup» и пытаемся разобраться почему нет, скорее всего не установлены драйвера, смотрим в устройства Windows, ищем неопределенные устройства, может с кабелем проблема. Если все хорошо нажимаем «Auto Detect» и выбираем наш чип.


Рис. 12 - Окно Programmer

Нажимаем двойным щелчком мыши в поле «File» и выбираем файл для записи на ПЛИС (находиться в папке output_files нашего проекта), ставим галочку в поле «Program / Configure», и нажимаем кнопку «Start».


Рис. 13 - Окно Programmer, наш чип уже сконфигурирован

Поздравляю с первой конфигурацией ПЛИС! Диод D1 должен светиться, при нажатии key1 должен гаснуть (так как кнопка замыкает ножку с землей), далее мы с этим что-нибудь сделаем)


Поле, засеянное Массивами Программируемых Калиток

Начинаем курс лекций о том, что такое программируемая логика и как начать ее использовать на благо себя и ближнего своего…

ПЛИС - так ЭТО называется по-русски. П рограммируемая Л огическая И нтегральная С хема.
По-буржуйски это звучит несколько иначе - FPGA - F ield of P rogrammable G ate A rrays. Дословно это переводится как "Поле, засеянное массивами программируемых калиток."
Если быть чуть серьезнее, можно назвать это "Матрица программируемых вентилей"

Что такое вентиль?
Совершенно верно, это в подвале такая хреновина на водопроводной трубе, которую если завинтишь, то весь дом останется без воды. Короче говоря, это то, что может закрываться и открываться.

Так вот, пусть для вас это будет откровением, но каждая микросхема состоит из вентилей. Правда, они не совсем похожи на то, что у вас и у меня в подвале. Но делают они то же самое - открываются и закрываются.

Вентиль - это элементарная составляющая любой цифровой микросхемы.

Даже самый навороченный супермегапроцессор состоит из вентилей. Их в нем много, очень много, просто целое море. Естественно, что в каждой микросхеме вентили соединены определенным образом. Собственно, от того, как они соединены, и зависит функциональность микросхемы.

В обычных микросхемах схема соединения вентилей задается при изготовлении, и в последствии ее изменить уже нельзя.
ПЛИС позволяет нам задавать эту схему самим, и изменять ее как нам заблагорассудится уже при "жизни" микросхемы. Достаточно лишь нарисовать схему на компютере и при помощи программатора прошить ее в микросхему ПЛИС.

Это в-общем.

На самом деле, все гораздо сложнее:) Смотрим на рисунок


Это есть одна макроячейка - Macrocell по-ихнему.
Каждая микросхема ПЛИС состоит из таких вот макроце… макроячеек. Как видно из схемы макроячейки, она состоит из блока Look-Up Table (LUT ) - "Просмотровой таблицы", а также, триггера с синхронными и асинхронными входами и некоторой логики по входам триггера. Программируется, собственно, только LUT. Как видите, у нее 4 входа и один выход. Этот выход может быть подан как непосредственно на выход макроячейки (Q0), так на синхронный вход данных триггера (D).

LUT - это ни что иное как ПЗУ на 16 1-битных ячеек. При подаче на входы LUT (D0…D3) некой комбинации цифровых сигналов, она воспринимает их как адрес и выдает на выход содержимое ячейки по этому адресу.

Вообще, любая схема из логических элементов, у которой 4 входа (или меньше) и один выход, может быть описана таблицей истинности в 16 строк. Например, возьмем вот такую несложную схему, и напишем для нее таблицу истинности:

Таблица истинности описывает логический уровень выхода схемы (Q) для всех возможных комбинаций сигналов на входах (D0…D3). Точно так же в LUT каждой комбинации входных сигналов (читай - каждому адресу ПЗУ) сопоставлен свой выходной сигнал. То есть, в LUT прошивается таблица истинности той схемы, которую мы хотим видеть на его месте. Вот так все просто!

Если схема содержит более 4 входов или более 1 выхода - используются LUT нескольких макроячеек.

clear="all">

Но самое главное - это триггер. Ведь, как вы знаете (а может, еще не знаете), все регистры, счетчики и многие другие элементы цифровой техники состоят именно из триггеров. Так вот, количество макроячеек в микросхеме ПЛИС определяет количество триггеров. И наоборот:) Так что, выбирая микросхему для какого-либо проекта, надо предварительньно прикинуть, сколько триггеров будет в схеме, и брать с запасом…

На рисунке чуть ниже изображена структурная схема микросхем серии EPM7000 фирмы Altera Эта картинка дернута из даташита https://www.altera.com/literature/ds/m7000.pdf Она относится к микросхемам EPM7032, EPM7064, EPM7096. Дык вот, последние две цифры в названии обозначают именно количество макроячеек в микросхеме.


Как видно из схемы, макроячейки объединяются в "блоки логических массивов" (LAB - Logic Array Block).
Эти блоки соединяются между собой через "программируемый массив внутренних соединений" - programmable interconnect array (PIA).
Кроме того, LAB"ы подключаются к выводам микросхемы через блоки управления ввода/вывода (I/O Control Block).

При прошивке, в каждый из блоков "зашивается" своя информация:
- В Макроячейках программируются LUT"ы,
- в PIA зашивается информация о внутренних межблочных соединениях,
- в блоки управления ввода/вывода (I/O Control Block) зашивается информация о подключениях к ногам микросхемы.

По-серьезному, "прошивка" ПЛИС называется "загрузка конфигурации".

А как вы думаете, чем мы будем загружать конфигурацию???
Ну конечно же, старым добрым Байт Бластером! :) Байт бластер - это штука универсальная:) О том, как его сделать, подробнейшим образом я рассказывал вот

В ПЛИС для конфигурации используется оперативная память CRAM (Configuration RAM). Эта память распределена по всему кристаллу, значения, записанные в нее, управляют внутренним коммутационным полем, определяя структуру синтезируемого цифрового устройства. Как правило, в ПЛИС архитектуры FPGA эта память энергозависимая и при подаче питания на устройство требуется загрузить в нее значения из какого-либо внешнего (по отношению к кристаллу ПЛИС) носителя, часто для этих целей используется микросхема ПЗУ (Постоянное Запоминающее Устройство), либо , а в случае стенда LESO2, загрузка осуществляется из компьютера.

Одной из важнейших характеристик ПЛИС является ее логическая емкость. Емкость определяет насколько сложные цифровые устройства можно синтезировать. Другими словами, логическая емкость показывает сколько всего поместится в кристалле. Если вам уже доводилось компилировать в Quartus II проект для ПЛИС, то должны были обратить внимание на итоговый отчет, где указывается какие ресурсы и в каком количестве использованы в проекте, а также указывается процентное соотношение от максимального. Основной ресурс ПЛИС – это логические элементы (Logic Elements). В ПЛИС EP4CE6E22C8, а именно такая использована в учебном стенде, таких элементов 6272. Это много или мало? Для того, чтобы ответить на это вопрос, следует рассмотреть, что же из себя представляет этот логический элемент.

Базовый логический элемент

Из булевой алгебры известно, что используя некий элементный базис, например элемент И-НЕ или ИЛИ-НЕ, можно реализовать любую логическую функцию. Однако использование лишь одного типа элемента не всегда оправдано технически, при синтезе сложных устройств большое количество элементов увеличит время прохождения сигнала и тем самым снизит быстродействие. Поэтому в ПЛИС структуры FPGA в качестве простейшего логического элемента используют более сложную структуру, представляющей собой соединение программируемого комбинационного устройства и D-триггера . На рисунке 1 показана упрощенная структура такого элемента.

Рисунок 1 – Обобщенная структура логического элемента (LE) ПЛИС

Ячейка имеет три логических входа DATAA, DATAB и DATAC, вход тактовых импульсов CLK и один выход LEOUT. В случае если от ячейки требуется работа в качестве только комбинационного устройства, то выходной мультиплексор коммутирует выход элемента LUT на выход всей ячейки, если выход должен быть регистровым, то сигнал с LUT защелкивается по сигналу синхронизации в D-триггер, выход которого через мультиплексор соединяется с LEOUT. Управляющий вход мультиплексора (на рисунке не показан) подключен к соответствующему биту конфигурационной памяти CRAM.

Если ни у кого не вызывает вопросов как работает триггер и мультиплексор , то с элементом, обозначенным на схеме как LUT , все несколько сложнее. Аббревиатура LUT расшифровывается как Look-Up Table или просто Lookup Table, что дословно можно перевести как "справочная таблица" или "таблица поиска". LUT – это больше, чем таблица, LUT – это скорее метод реализации функции, в котором непосредственное вычисление заменяется поиском по таблице готовых решений. Применительно к ПЛИС это позволяет реализовать любую логическую функцию в виде памяти SRAM, где адрес – это аргумент, а содержимое ячейки – значение. Таким образом, для того, чтобы описать логическую функцию трех переменных (в приведенном примере именно три переменные: DATAA, DATAB и DATAC) достаточно памяти на 8 ячеек. Требуемая таблица истинности хранится в виде маски (LUT-mask) в соответствущей ячейке CRAM. С помощью мультиплексоров выбирается нужное значение. Мультиплексорами управляют сигналы входных портов для построения k-входовой LUT (k-LUT), которая реализует любую логическую функцию из k переменных, требуется 2 k бит SRAM и 2 k-1 мультиплексоров. На рисунке ниже показана трехвходовая LUT.

Рисунок 2 – Устройство LUT

При таком подходе можно достаточно точно спрогнозировать время прохождения сигнала и оно не будет зависеть от реализуемой логической функции. Эта важная особенность делает возможным временной анализ схемы.

Хорошо! Используя логический элемент, показанный на рисунке 1, можно получить любую логическую функцию трех переменных и ее регистровый вариант. А как быть, если нам понадобится реализовать какой-либо триггер, отличный от D-триггера? Для реализации некоторых типов достаточно имеющегося комбинационного устройства (LUT) на входе D-триггера, но для реализации всех известных триггеров нам все же придется внести некоторые изменения в базовую схему. Во-первых, необходимо ввести обратную связь: для этого с выхода D-триггера подадим сигнал на один из входов LUT. Для того, чтобы достигнутый ранее функционал не пострадал, мы не имеем право занимать уже имеющиеся входа, заменим LUT на 4-х входовый. Во-вторых, увеличим функциональность самого D-триггера, добавим дополнительные линии управления: вход разрешения ENA (от английского "Enable" – "Включить") и вход асинхронного сброса ACLR (от английского "Asynchronous Clear" – "Асинхронная Очистка"). В результате получим схему пригодную для синтеза любых триггеров:

Рисунок 3 – Структура логического элемента (LE) с обратной связью

Существует особый широко распространенный класс логических функций, который подразумевает наличие двух выводов. Речь идет о сумматорах. На вход полного двоичного сумматора поступает два операнда и флаг переноса из младшего разряда, а на выходе сумма и перенос в следующий двоичный разряд. Так как арифметические задачи типичны для ПЛИС, для работы с переносом в базовом логическом элементе предусмотрен специальный канал.

Рисунок 4 – Структура логического элемента (LE) с каналом переноса

Фактически для переноса требуется ввести дополнительную LUT, как показано на рисунке 4, но для простоты восприятия комбинацию LUT будем рассматривать как один целый модуль.

Используя канал переноса, легко объединить ячейки для получения многоразрядного сумматора. На рисунке 5 показана схема 4-разрядного сумматора с последовательным переносом, построенная на четырех базовых логических элементах.

Рисунок 5 – Четырехразрядный сумматор

При разработке базовой логической ячейки решались две задачи: во-первых, синтезируемые устройства должны обладать максимальным быстродействием, во-вторых, использование ресурсов должно быть как можно более полным. В предыдущем примере, если требуется работа сумматора исключительно как комбинационной схемы, выходные мультиплексоры сигнал возьмут с выходов LUT, а вся цепочка триггеров окажется неиспользованной. В противоположность этому, при синтезе последовательного или параллельного регистра, все LUT будут по сути выполнять функцию проводника: соединять вход LE с входом D-триггера. Небольшое дополнение к схеме, даст возможность при необходимости использовать комбинационное устройство и триггер элемента раздельно для синтеза независимых модулей. Мультиплексор на входе триггера позволит выбирать источник сигнала: либо с входа DATAC, либо с выхода LUT. Кроме того, появляется возможность организовать дополнительный канал соединения триггеров соседних LE для увеличения быстродействия при построении последовательных регистров. На рисунке 6 показана схема получившегося логического элемента. Вход REGIN и выход REGOUT образуют выделенный канал для соединения триггеров, вход SLOAD (от английского "Synchronous Loading" – "Синхронная загрузка") управляет выбором источника сигнала для входа триггера.

Рисунок 6 – Структура логического элемента (LE) с возможностью разделения LUT и триггера

Базовый логический ПЛИС Cyclone IV

Рассмотренный элемент LE в том или ином виде присутствует в различных семействах ПЛИС, в нем может быть увеличено количество входов и сложность LUT, добавлены дополнительные соединения внутри LE и порты для интеграции в глобальную коммутационную сеть ПЛИС. Так, например, в топовом семействе Stratix IV в один элемент входит две шестивходовые LUT, два выделенных полных сумматора и четыре триггера! Однако, с практической точки зрения, для эффективной работы со стендом LESO2 нам целесообразно рассмотреть более подробно реализацию LE в семействах Cyclone, в частности в Cyclone IV.

На рисунке 7 показана схема логического элемента ПЛИС Cyclone IV.

Рисунок 7 – Логический элемента (LE) Cyclone IV

Также, как и в базовом логическом элементе, каждый триггер имеет вход данных, вход тактовых импульсов CLK, вход разрешения ENA и вход асинхронного сброса (очистки) ACLR. Добавился сигнал синхронной очистки SCLR (от английского "Synchronous Clear" – "Асинхронная Очистка"): если на этом входе появится логическая единица, то следующим тактовым импульсом в триггер будет записал логический ноль. Все это позволяет настроить программируемый триггер каждой LE на работу в режиме D, T, JK или RS триггера.

Комбинационное устройство по сравнению с базовой схемой получило некоторое усложнение. На входе C LUT мультиплексор выбирает источник сигнала, благодаря чему LUT может реализовывать логическую функцию четырех переменных, кроме того, в качестве переменной может быть использован флаг переноса или выход собственного триггера.

В Cyclone IV LUT может работать в двух режимах: нормальном и арифметическом. при компиляции автоматически выберет оптимальный режим для реализации требуемой функции. Нормальный режим предназначен для реализации основной логики и различных комбинационных функций. В этом режиме четыре входа LE (DATAA, DATAB, DATAC, DATAD) поступают на четыре входа LUT. Компилятор автоматически выбирает вход переноса CIN, вход DATAC или выход триггера (цепь обратной связи) в качестве одного из входов LUT. Арифметический режим подходит для синтеза сумматоров, счетчиков, аккумуляторов и компараторов (цепей сравнения). В этом режиме LUT представляет собой полный одноразрядный сумматор, включающий обработчик логики флага переполнения. Компилятор сам создает цепи переноса во время синтеза многоразрадных арифметических устройств.

Можно обратить внимание, что на рисунке логического элемента Cyclone IV отсутствует выходной мультиплексор, на самом деле он есть и не один. Но для того, чтобы понять логику их работы, нужно рассмотреть LE в контексте общей архитектуры ПЛИС.

Логические элементы LE объединяются в логические блоки LAB (Logic array blocks). В Cyclone IV каждый LAB содержит:

  • 16 логических ячеек;
  • сигналы управления LAB;
  • цепи флага переноса LE;
  • цепи каскадного объединения регистров;
  • цепи локальных соединений.

Цепи локальных соединений передают сигналы между ячейками LE в одном LAB. Цепи объединения регистров соединяют выход регистра одного LE с входами регистров прилегающих ячеек LE. Компилятор Quartus II размещает связанную логику в LAB или в соседних LAB, позволяя использовать локальные цепи связи и связи регистров для увеличения производительности и эффективности размещения.

На цепи локальных соединений поступают сигналы со строк и столбцов глобального коммуникационного поля и с выходов ячеек LE, принадлежащих этому же блоку LAB. Соседние логические блоки, блок генератора с фазовой автоподстройкой частоты (PLL), ячейки памяти M9K RAM, встроенные умножители, расположенные с правой или левой стороны через специальные соединители, могут быть напрямую подключены к цепям локальных соединений LAB. Таким образом, любая ячейка LE может иметь соединение с шестнадшатью LE из своего блока (включая саму себя) и тридцатью двумя LE из LAB, расположенных слева или справа. Всего до 48-ми соединений! Такие непосредственные прямые соединения минимизируют использование глобальных маршрутов, обеспечивают большую гибкость при синтезе схемы и увеличивают общее быстродействие.

На рисунке 8 показана интеграция блока LAB в глобальную коммуникационную сеть ПЛИС.

Рисунок 8 – Структура соединений LAB в коммутационном поле ПЛИС

Каждый LE имеет три выхода, которые обеспечивают соединение с коммутационным полем ПЛИС. Эти выходы поступают на строки и столбцы глобальных соединительных трасс и на маршруты локальных соединений. Как и в базовом логическом элементе, LUT или триггер могут независимо управлять этими выходами.

Для того, чтобы можно было управлять всеми ячейками LE в пределах одного LAB одновременно, в логический блок встроена специальная логика и выделены особые линии – каналы управления. По таким каналам распространяются широковещательные (в пределах одного LAB) сигналы управления. Архитектура позволяет одновременно использовать до восьми управляющих сигналов:

  • два тактовых сигнала (labclk1 и labclk2);
  • два сигнала разрешения (labclkena1 и labclkena2);
  • два сигнала асинхронного сброса (labclr1 и labclr2);
  • сигнал синхронного сброса/очистки (synclr);
  • сигнал синхронной загрузки (syncload).

Сигналы синхронной загрузки и сброса удобно использовать для синтеза различных счетчиков и регистров. Эти сигналы оказывают воздействие на все триггеры LE в пределах одного LAB.

На рисунке 9 показано подключение управляющих сигналов LAB и цепей локальных соединений к логической ячейке. Выводы LE соответствуют рисунку 7.

Рисунок 9 – Структура взаимодействия LE с сигналами управления

Каждый LAB имеет два тактовых сигнала и два сигнала разрешения. На уровне логического элемента выбирается какой сигнал будет подан на триггер, но тактовый сигнал связан с сигналом разрешения. Поэтому, хотя для любого LE в конкретной LAB можно выбрать какой тактовый сигнал использовать: labclk1 или labclk2, вместе с ним должен использоваться соответствующий сигнал разрешения. Например, если используется labclk1, вместе с ним будет использоваться только labcken1. Если LAB использует оба фронта (нарастающий и падающий) тактового сигнала, то будут задействованы оба канала тактирования, при этом логика выбора усложнится.

Chip Planer

После компиляции в окне Flow Summary можно посмотреть, какие ресурсы были использованы. После небольшого экскурса в архитектуру ПЛИС становился понятно, что значит Total logic elements и почему Total combinational function вынесено отдельной графой. Безусловно информация полезная, но для того, чтобы держать руку на пульсе этого явно недостаточно.

Рисунок 10 – Отчет компиляции

Для визуального контроля используемых ресурсов в Quartus II применяется утилита Chip Planer . Она показывает расположение и использование элементарных блоков в общей архитектуре целевой ПЛИС. Запустить Chip Planer можно из среды Quartus: меню Tools -> Chip Planer. На карте кристалла (рисунок 11) показаны все ресурсы ПЛИС: LE, объединенные в LAB, аппаратные умножители (DSP block), ячейки памяти, буферы ввода вывода, генераторы PLL. Цветом показана степень использования: светлым – неиспользуемые блоки, темным – максимально загруженные. Если увеличить масштаб (соответствующий инструмент на панел или ctrl+колесико мышки), то доступна детализация на уровне LE, здесь синим показан LUT, темно красным – триггер.

Большую детализацию можно получить если на панели Layers Settings сменить Basic на Detailed. В этом режиме при приближении видны локальные и глобальные цепи соединений, глобальные линии управления и управляющие сигналы LAB.

Рисунок 11 – Карта ресурсов ПЛИС

Если в LE выделить LUT или триггер, то на панели Node Properties можно увидеть схему LE и описание свойств и режимов работы. Двойной клик мыши по LUT или триггеру запустит в новом окне инструмент Resource Property Editor, в котором можно исследовать соединения внутри логического элемента. Синим выделены используемые цепи.

Рисунок 12 – Логический элемент в Resource Property Editor

Вместо заключения

Это далеко не полное описание архитектуры ПЛИС, за кадром остались такие важнейшие элементы как DSP блоки (умножители), блоки оперативной памяти, генератор PLL, буферы ввода-вывода, в последующих статьях цикла я постараюсь уделить им должное внимание. Однако следующий материал будет посвящен применению знаний о структуре логического элемента LE и об их объединении при проектировании простейших цифровых устройств.

Недавно я все-таки сделал свой первый шаг к ПЛИС и призвал вас за собой . Мое фанатическое увлечение ПЛИС и идея о том, что ПЛИС является лучшей платформой для создания любых устройств приобрела религиозный характер. Моя секта ПЛИСоводов проповедует полный отказ от микроконтроллеров, а особо экстремистская ветвь проповедует отказ не только от софт процессоров , но и вообще от последовательных вычислений!

Как всегда, постижению истин помогло решение реальных задач. В сегодняшней проповеди я хотел бы рассказать об испытаниях, которые выпадают на долю молодого ПЛИСовода. Преодолевая испытания мы постигаем истину. Но остаются вопросы, на которые я не нашел ответов. Поэтому я бы очень хотел, чтобы братья-хабровчане - ПЛИСоводы с опытом, поучаствовали в обсуждении, протянули руку помощи своим младшим собратьям.

Эта статья для новичков. В ней я опишу типичные проблемы, вопросы, заблуждения, ошибки, которые могут появиться в самом начале обучения (потому что они появились у меня). Однако, контекст статьи ограничен тем, что разработка ведется на ПЛИС от Altera в среде Quartus на языке Verilog .

Трудно жить ничего не делая, но мы не боимся трудностей!

Одна из причин, по которой многие не начинают изучать Verilog вот прямо сейчас - это отсутствие реальной ПЛИС. Кто-то не может заказать, потому что дорого, а кто-то потому, что не знает, что именно взять (вопрос выбора рассмотрен в предыдущей статье). Кому-то ПЛИС пока еще едет по почте.

Но в своих разработках я пришел к тому, что наличие реальной ПЛИС мне требуется уже на финальном этапе разработки, когда нужно протестировать проект «в железе». Речь о том, что бóльшую часть времени я провожу в отладке своего кода с помощью симуляторов.

Поэтому мой совет: отсутствие ПЛИС - это не повод бездействовать. Пишите и отлаживайте модули для ПЛИС в симуляторах!

Симулятор для Verilog

Итак, чем же развлечь себя скучными длинными рабочими днями (если они таковыми являются)? Конечно же освоеним ПЛИС! Но как же затащить на работу целую среду разработки от Altera, если она весит 3 ежемесячных рабочих лимита интернета? Можно принести на флешке! Но если предметом изучения является Verilog, то можно ограничиться блокнотом, компилятором IcarusVerilog, а результат смотреть в GTK Wave.

Попробовать прямо сейчас

Для начала работы в среде Windows, достаточно скачать по ссылке http://bleyer.org/icarus/ файл установки iverilog-20130827_setup.exe (development snapshot)

Установка трудностей не вызывает. Теперь немного забежим вперед: создадим папку для проекта и в ней пару файлов с пока что не понятным содержимым:

Файл-модуль с кодом для тестирования модулей - bench.v

`timescale 1ns / 100 ps module testbench(); reg clk; initial begin $display("start"); $dumpfile("test.vcd"); $dumpvars(0,testbench); clk <= 0; repeat (100) begin #10; clk <= 1; #10; clk <= 0; end $display("finish"); end


В файле bench.v описан тестовый модуль testbench, в нем создан тестовый источник сигнала clk (меандр). Другие модули будут создаваться в отдельных файлах, либо логику можно протестировать сначала в этом модуле, а потом вынести в отдельный модуль. Потом в модуль testbench будут добавляться экземпляры этих модулей, где мы будем подавать на их входы тестовые сигналы и получать из них результаты. Из модулей мы можем строить иерархию, думаю это понятно всем.

BAT Файл, который скомпилирует и просимулирует главный модуль, добавив другие модули из текущей папки - makev.bat

iverilog -o test -I./ -y./ bench.v vvp test pause


После запуска этого файла мы увидим на экране текст, заданный в $display (это отладочный вывод), значение же сигналов и регистров схемы будут находиться в файле test.vcd. Кликаем по файлу и выбираем программу для просмотра - GTKWave (в моем случае D:\iverilog\gtkwave\bin\gtkwave.exe). Еще пару кликов и мы увидим наш clk.



Практически, каждый свой новый модуль я создаю в блокноте и отлаживаю IcarusVerilog. Следующим этапом после такой отладки идет проверка модулей в Quartus. Хотя в Quartus тоже есть свой симулятор, но я его использую реже. Причина в простоте обновления кода и просмотра результата в IcarusVerilog: сохранил изменения в файле, запустил BAT, нажал кнопку «обновить» в GTKWave - все! В ModelSim для этого требуется чуть больше движений, но он тоже не плох, особенно на данных сложных структур.

После симуляции наступает пора запуска Quartus. Но загружать прошивку в ПЛИС пока еще рано. Нужно убедиться, что божественная вычислительная машина правильно поняла, какую схему мы хотим получить, изложив свои мысли в виде Verilog"а.

Разница между симуляцией и работой в реальном железе

Первое время я, подобно слепому котенку, бился головой об косяки. Казалось бы правильный код, не работает совсем, либо работает не так, как предполагаешь. Либо вот только что работал, а теперь внезапно перестал!

Пытливый котенок, начинает искать взаимосвязь между своими действиями и результатом («голубиное суеверием»).

Самая большая драма
Ниже будет список странностей, но сначала самая большая драма, с которой я столкнулся: не все конструкции Verilog могут быть синтезированы в железе . Это связано с тем, что на Verilog описывается не только аппаратная логика, которая объединяется в модули и работает в железе. На том же Verilog описываются тестовые модули, которые объединяют тестируемые модули, подают на их входы тестовые сигналы и в целом существуют только для проверки на компьютере. Изменение значений сигналов во времени задается конструкциями, содержащим знак "#" в тексте Verilog. Такой знак означает задержку во времени. В примере выше именно так генерируется сигнал CLK. И я грешным делом думал, что таким же образом внутри настоящей ПЛИС можно генерировать, к примеру, последовательность бит для отправки сообщения по RS232. Ведь на вход ПЛИС подан сигнал от генератора 50 МГц! Может быть она как-то на него ориентируется. Как оказалось, я не единственный, кто надеялся на чудо: , , , , . Реальность как всегда оказывается более суровой: ПЛИС это набор логики и временная задержка в ней может появиться при использовании счетчика, значение которого увеличивается тактами от генератора до заданной величины, либо как-то иначе (но всегда аппаратно).
Список найденных странностей
Удивительные вещи, однако, прочтение книг проливает свет на эту бесовщину. Более того, обретается благодать.
Если обозначить reg, то не факт, что он будет создан
Как я пришел к проблеме? Допустим есть один модуль, на вход которого я должен подавать значение (по типу параметра). В перспективе, этот параметр должен будет изменяться во времени в зависимости от каких-то внешних событий. Поэтому значение должно хранится в регистре (reg). Но реализация приема внешних событий пока не реализована, поэтому я регистр не меняю, а просто задаю ему изначальное значение, которое в дальнейшем не меняется.

//задаю 8 битный регистр reg val; //инициирую его значением initial val <= 8"d0240; //wire к которому подключим выход из модуля wire out_data; //неведомый модуль, называется bbox //экземпляр этого модуля называется bb_01 //будем считать, что в модуле есть входной порт in_data и выходной out_data //во входной порт подаем значение с регистра val, а выход подключаем к wire - out_data bbox bb_01(.in_data(val), .out_data(out_data));
Казалось бы в чем подвох? В императивных ЯП мы часто задаем переменные в качестве констант и потом ни разу их не меняем и все работает. Что же мы видим в железе?


Во-первых, мы не видим регистра. Во-вторых, на вход модуля подано 8"hFF вместо наших 8"d0240! И этого уже достаточно для того, чтобы схема заработала не так, как мы планировали. То, что регистра нет - это нормально. В Verilog можно описывать логику разными способами, в то же время, синтезатор всегда оптимизирует аппаратную реализацию. Даже если написать блок always и в нем работать с регистрами, но при этом выходное значение всегда будет определяться входными, то применение регистра тут окажется лишним и синтезатор его не поставит. И наоборот, если при каких то значениях входных данных выходное значение не меняется, то тут никак не обойтись без регистра-защелки и синтезатор его создаст. (Книга 1 стр. 88-89). Что из этого следует? Если мы начнем менять значение регистра, например, в зависимости от нажатии кнопок, то геристр уже будет создан и все будет работать так, как нужно. Если же окажется, что кнопки ничего не меняют, то синтезатор его опять же выкинет и опять все поломается. Что же делать с константой? Нужно подать ее напрямую на вход модуля:

Bbox bb_01(.in_data(8"d0240), .out_data(out_data));
Теперь на входе модуля мы имеем правильное значение:

Остается загадкой, почему при сокращении регистра, его значение в initial не подставляется на вход модуля.

Размерность wire лучше задавать самому.
При разработке в среде Quartus, допускается не задавать линии wire заранее. В этом случае они будут созданы автоматически, но об этом будет выдано предупреждение (warning). Проблема заключается в том, что разрядность wire будет 1-бит, а если порты будут иметь разрядность больше 1 бита, то значение не будет передано.

Bbox bb_01(.in_data(8"d0240), .out_data(int_data)); other_bbox bb_02(.in_data(int_data), .out_data(out_data));
Предупреждение
Warning (10236): Verilog HDL Implicit Net warning at test.v(15): created implicit net for "int_data"
Результат:

Как видим, один бит подключен, а остальные 7 бит получаются не подключены (NC). Чтобы такой проблемы не было - нужно создать wire самостоятельно. Не зря компилятор IcarusVerilog выдает не warning, а ошибку, если wire не задан заранее.

Wire int_data; bbox bb_01(.in_data(8"d0240), .out_data(int_data)); other_bbox bb_02(.in_data(int_data), .out_data(out_data));

Компьютер не будет лазать по модулям, смотреть, какая разрядность портов. К тому же, разрядность может оказаться разной, а на вход модуля или с выхода берутся не все биты, а какие-то определенные.

Нельзя использовать выход логической функции, в качестве тактового сигнала
Иногда в проекте требуется снизить тактовую частоту, либо ввести временную задержку в N тактов. Новичёк может применить счетчик и дополнительную схему определения достижения счетчиком определенного значения (схема сравнения). Однако, если напрямую использовать выход со схемы сравнения в качестве тактового, то могут возникнуть проблемы. Это связано с тем, что логической схеме требуется некоторое время для установки стабильного значения на выходе. Эта задержка смещает фронт сигнала, проходящего через разные части логической схемы относительно тактового, в итоге получаются гонки, метастабильность, асинхронщина. Даже довелось однажды услышать реплику об этом в качестве критики ПЛИС: «с ПЛИС постоянные проблемы - гонки сигналов».

Если прочитать хотя бы парочку статей:
Метастабильность триггера и межтактовая синхронизация
Пару слов о конвейерах в FPGA

То становится ясно, каким образом разрабатываются устройства на ПЛИС: вся задача делится на аппаратные блоки, а данные между ними движутся по конвеерам, синхронно защелкиваясь в регистрах по тактовому сигналу. Таким образом, зная общую тактовую частоту, синтезатор рассчитывает максимальную частоту работы всех комбинаторных схем, определяет, укладывается ли их скорость к период такта и делает вывод - будет или не будет работать схема в ПЛИС. Все это происходит на этапе синтеза. Если схемы укладываются в параметры, то можно прошивать ПЛИС.

Таким образом, для разработчиков устройств на базе ПЛИС созданы все необходимые методологии, и если их придерживаться, то проблем не будет.

А что, если я хочу пойти против системы?
Порядок разработки и поведение синтезатора схем подводит нас к выводу о том, что же такое ПЛИС на аппаратном уровне. Это синхронные схемы. Поэтому, среди целей синтезатора - уложиться во временные интервалы. Для этого он, к примеру, упрощает логические выражения, выбрасывает из синтеза части схем, которые не используются другими схемами и не привязаны к физическим выводам ПЛИС. Асинхронные решения и аналоговые трюки не приветствуются, потому что их работа может быть непредсказуемой и зависеть от чего угодно (напряжение, температура, техпроцесс, партия, поколение ПЛИС), а поэтому не дает гарантированного, повторяемого, переносимого результата. А всем же нужен стабильный результат и общие подходы к проектированию!

Но что же делать, если вы не согласны с мнением синтезатора о том, что нужно выкидывать неизменяемые регистры, сокращать логические схемы? Как быть, если хотите делать схемы с асинхронной логикой? Нужна тонкая настройка? А может быть вы сами хотите собрать схему на низкоуровневых компонентах ПЛИС? Легко! Спасибо разработчикам Altera за такую возможность и подробную документацию!

Как это сделать? Можно попробовать графический редактор схем. Вы, возможно, слышали о том, что Quartus позволяет рисовать схемы? Можно самому выбрать стандартные блоки и соединить их. Но это не решение! Даже нарисованная схема будет оптимизирована синтезатором, если на это будет возможность.

В итоге мы приходим к старой истине: если ничего не помогает - прочитайте инструкцию . А именно «Altera Handbook» часть под названием «Quartus II Synthesis Options» .

Начнем с того, что описывая архитектуру на Verilog определенным образом, можно получить определенный результат. Вот примеры кода для получения синхронного и асинхронного RS триггера:

//модуль синхронного RS триггера module rs(clk, r, s, q); input wire clk, r,s; output reg q; always @(posedge clk) begin if (r) begin q <= 0; end else if (s) begin q <= 1; end end endmodule
В этом случае получится синхронный триггер.

Если не брать во внимание тактовый сигнал и переключаться в зависимости от любых изменений r и s, то в результате получится элемент с асинхронной установной значений - защелка (latch).

//пример модуль асинхронного RS триггера module ModuleTester(clk, r, s, q); input wire clk, r,s; output reg q; always @(r or s) begin if (r) begin q <= 0; end else if (s) begin q <= 1; end end endmodule

Module ModuleTester(clk, r, s, q); input wire clk, r,s; output reg q; DLATCH lt(.q(q), .clrn(~r), .prn(~s)); endmodule

В итоге, весь «обвес» на входе защелки, который синтезатор посчитал нужным, исчезнет и мы получим именно то, что хотели:

Список существующих примитивов можно посмотреть на сайте Altera.

А теперь небольшой пример про асинхронность и сокращение. Задумал я, к примеру, сделать генератор по тому же принципу, как это было принято делать раньше, но только на ПЛИС:

Но для увеличения периода я возьму 4 элемента, но только один из них будет с инверсией:

Module ModuleTester(q); output wire q; wire a,b,c,d; assign a = b; assign b = c; assign c = d; assign d = ~a; assign q = a; endmodule

Но получается сокращение (1 элемент, вместо четырех). Что логично. Но мы то задумывали линию задержки.

Но если поставить синтезатору условие, что линии a,b,c,d не сокращать, то получится то, что мы задумали. Для подсказки синтезатору применяются директивы . Один из способов указания - это текст в комментарии:

Module ModuleTester(q); output wire q; wire a,b,c,d /* synthesis keep */; // ^^^--- это директива для синтезатора assign a = b; assign b = c; assign c = d; assign d = ~a; assign q = a; endmodule
А вот и результат - цепочка из четырех элементов:

И это далеко не все! Оставлю на радость самостоятельного изучения: работу с case и директиву для реализации его в качестве RAM/ROM или логической схемой; работу со встроенными блоками памяти (RAM/ROM); выбор реализации умножения - аппаратным умножителем или логической схемой.