SS I www.finestreet.ru
компоненты ПЛИС
Алексей РАБОВОЛЮК
Обзор маршрута проектирования ПЛИС FPGA Advantage
компании Mentor Graphics
Данная статья является продолжением описания маршрута проектирования FPGA Advantage, начатого в «КиТ» № 07'2005. В ней речь пойдёт о создании в пакете HDL Designer блок-диаграммы.
Блок-диаграмма (Block Diagram) — это набор взаимосвязанных между собой блоков проекта. Как правило, блоки являются иерархическими. Внутри блока может содержаться любой элемент: другая блок-диаграмма, конечный автомат, таблица истинности, просто текст на языке VHDL или Verilog и т. д. (рис. 1). Внешний вид блока может быть произвольным: по умолчанию это прямоугольник, но его можно изменить как самостоятельно, так и выбрав одну из имеющихся заготовок. Между собой блоки соединяются сигналами и шинами. Сигнал на схеме соответствует сигналу на языке VHDL, а шина соответствует массиву. Внешние по отношению к блок-диаграмме данные передаются через объект, определяемый как порт (Port). Как и в VHDL, порты могут быть входными, выходными и двунаправленными.
Функционально блок-диаграмма может нести различную смысловую нагрузку. Самый
очевидный вариант — это сборка частей проекта в единое целое. Блок-диаграмма может включать некоторые элементы документирования. Например, непосредственно на блок-диаграмме можно размещать так называемые графические комментарии. Фактически это разновидность блоков, которые не несут функциональной нагрузки с точки зрения моделирования. Комментарии, как и любые другие блоки, могут принимать произвольный внешний вид. Одна из полезных функций комментариев заключается в следующем: щелкнув по комментарию правой клавишей мыши, можно при помощи пункта Include In HDL вставить выбранный комментарий в сгенерированный HDL-текст. Например, если выбрать последовательность Include In HDL > Before Object, то текст выбранного комментария будет вставлен перед тем объектом, на который пользователь укажет после выбора данного пункта.
Другое назначение блок-диаграммы — это разработка первоначальной концепции проекта. Если пользователю приходилось когда-нибудь рисовать на листе бумаги предполагаемую структурную схему проекта, он может реализовать этот процесс непосредственно в HDL Designer (рис. 2). Это делается путем помещения в блок-диаграмму пустого блока с отсутствующим («плавающим») интерфейсом. На блок-диаграмме он будет окрашен в синий цвет (более детально типы блоков будут рассмотрены в последующих разделах). Поместив несколько таких блоков, присвоив им логические имена и соединив их соответствующими сигналами и шинами, можно получить начальный вариант структурной схемы проекта. HDL Designer вообще, и концепция блок-диаграммы в частности, позволяют в полной мере использовать метод проектирования «сверху вниз». Далее можно шаг за шагом детализировать проект. Например, если стоит задача спроектировать калькулятор, один из блоков которого выполняет четыре арифметические действия: сложение, вычитание, умножение и деление, то можно добавить в блок-диаграмму пустой блок и создать для него архитектуру, где с помощью языковых конструкций VHDL или Verilog выходному сигналу присваивается значение суммы, разности, произведения или частного от деления входных значений, в зависимости от кода операции. Такой блок уже можно моделировать, подавая на него входные воздействия, для генерации которых необходимо создать виртуальный объект, именуемый «тестер».
Выше мы коснулись еще одного назначения блок-диаграммы — функциональной верификации проекта. Существует множество подходов к верификации. Самый простой — это интерактивное моделирование с ручным заданием входных сигналов и наблюдением соответствующих откликов на выходе объекта моделирования. Идеология проектирования в среде HDL Designer подразумевает создание двух дополнительных объектов: Tester (тестер) и TestBench (тестбенч). Тестер — это
Подключенные библиотеки Список сигналов
Рис. 1
ПЛИС
компоненты I 89
блок, генерирующий тестовые последовательности для проекта, тестбенч — это блок-диаграмма, содержащая два объекта (блока): тестер и объект моделирования. HDL Designer позволяет автоматически создавать тестбенч (с пустым тестером). Для этого в обозревателе объектов (Design Explorer) необходимо выделить какой-нибудь объект и выбрать последовательность File > New > Test Bench... . При этом появляется окно Create Test Bench, в котором необходимо указать библиотеку для размещения тестбенча и тестера и нажать Ok. В результате будет создана блок-диаграмма с именем <имя_выбранного_объекта>_Ш. На созданной блок-диаграмме будут располагаться тестер и объект, соединенные соответствующими сигналами. Далее остается только создать архитектуру для тестера (как правило, это делается с помощью блок-схемы алгоритма Flow Chart, которая более подробно будет рассмотрена в последующих разделах) и тестбенч можно использовать для моделирования. Участие блок-диаграммы в верификации не ограничивается только созданием тестбенча. Интеграция с системой ModelSim позволяет во время моделирования разместить на сигналах блок-диаграммы так называемые индикаторы, показывающие значение сигнала на текущий момент моделирования или на любой другой момент, выбранный пользователем.
Рассмотрим подробнее структуру блок-диаграммы. На блок-диаграмме могут размещаться несколько типов блоков: графический комментарий (Text), встроенный блок (Embedded Block — окрашен в желтый цвет),
компонент (Component — окрашен в зеленый цвет), просто блок (Block — окрашен в синий цвет), компонент ModuleWare и IP-блок. Далее под словом «блок» будем понимать именно синий блок на блок-диаграмме. Остановимся на каждом из вышеуказанных блоков подробнее.
Графический комментарий — это графическая иллюстрация к проекту, которая, как правило, содержит текст. Этот текст, как уже отмечалось выше, может быть включен в сгенерированный HDL-код.
Встроенный блок — это блок, содержимое которого непосредственно вставляется в сгенерированный текст, то есть он не является иерархическим. Такой блок может содержать любое представление (конечный автомат, таблица истинности и т. д.), кроме блок-диаграммы. Например, если в качестве представления этого блока был выбран VHDL Text, содержащий предложения параллельного присваивания, то эти предложения в явном виде будут включены в архитектуру объекта между «BEGIN» и «END ARCHITECTURE».
Компонент — это вхождение объекта в блок-диаграмму. Фактически это копия символа вставляемого объекта. В принципе, это создает некоторые сложности. Например, если вставить объект в блок-диаграмму, а затем изменить интерфейс (список сигналов) символа исходного объекта, вхождение объекта на блок-диаграмме (то есть копия символа объекта) не изменяется. Если при этом попытаться откомпилировать проект, содержащий такие расхождения, то компиляция закончится ошибкой. Для того чтобы привести в соот-
ветствие различающиеся реальный объект и его вхождение в блок-диаграмму, в меню существует список Update, который раскрывается щелчком правой кнопкой мыши по интересующему компоненту. Например, для переноса изменений в интерфейсе объекта на компонент необходимо выбрать последовательность Update > Interface. Таким образом, пользователь имеет возможность произвольно изменять внешний вид компонента вне зависимости от исходного объекта. Главное требование — это совпадение списка сигналов.
Блок — это практически компонент, который создается на блок-диаграмме с нуля. Для этого необходимо поместить на блок-диаграмму пустой синий прямоугольник, подведя к нему сигнал и присвоив ему соответствующее имя. В результате в обозревателе объектов (Design Explorer) появится новый объект, помеченный не зеленым, а синим цветом, что означает невозможность его повторного использования в блок-диаграмме. Для блока, также как и для компонента, в сгенерированном VHDL-коде будет сформирован свой объект ENTITY и ARCHITECTURE, свое вхождение ENTITY в архитектуру блок-диаграммы при помощи предложения COMPONENT и т. д. То есть, добавляя блок, пользователь создает полноценный объект с двумя ограничениями: его нельзя повторно использовать и его интерфейс формируется в интерактивном режиме: при подведении сигнала автоматически создается порт. Именно блок позволяет реализовать идеологию проектирования «сверху вниз», когда интерфейсы еще четко не определены, и требуются эксперименты с разными вариантами.
Есть еще одно важное отличие блока от компонента. При работе с компонентом можно создать так называемые параметры настройки (в VHDL это называется GENERIC) в символе исходного объекта, а во вхождении объекта (то есть в компоненте) можно только присваивать новые значения уже существующим параметрам. При работе с блоком пользователь имеет возможность создавать новые параметры настройки непосредственно на блоке.
После того как интерфейс точно определен, блок можно конвертировать в компонент. Для этого надо щелкнуть правой кнопкой мыши по блоку и выбрать пункт Convert to Component. (Внимание! Обратное преобразование невозможно!)
Компонент ModuleWare — это объект из поставляемой вместе с HDL Designer библиотеки ModuleWare. Его можно сравнить со встроенным блоком. Точнее, это блок, генерирующийся непосредственно при выборе из библиотеки. У каждого объекта из ModuleWare есть свой набор параметров. Например, если добавить в блок-диаграмму объект ModuleWare > Logic > N Input AND, щелкнуть правой кнопкой мыши по добавленному объекту и выбрать ModuleWare > Parameters, то откроется окно, в котором сре-
90
компоненты
ПЛИС
Блок
Компонент
IP блок
Сигнал
Связка сигналов
_/^к°енный\\ Фрей» \шина\ порт
Рис. З
ди прочего будет пункт «Dynamic Number Ports», в котором пользователь может выбрать число входных портов добавленного объекта. При изменении количества портов, изображение блока на блок-диаграмме меняется. Таким образом, можно гибко настраивать все объекты из ModuleWare. Например, если используется элемент памяти, то можно задать ее объем. Рассмотрим, во что превратится выбранный элемент N Input AND после генерации VHDL-кода. Предположим, пользователь задал число входов равное четырем. Тогда после генерации кода получится следующее:
где dout, din0, dinl, din2, din3 — это имена подведенных к объекту сигналов.
Рассмотрим пример посложнее: Memory > ROM. Это «генератор» памяти типа ROM. В настройках этого компонента есть пункт «ROM Data File», в котором нужно указать файл с образом памяти, на основе которого будет создан VHDL-код. Например, можно использовать файл со следующим содержимым:
Описание этого файла приведено в документации по HDL Designer: Help > Bookcase > ModuleWare Reference Guide > Chapter 9 Memory Parts.
После генерации VHDL-кода, элемент ROM будет представлен следующим описанием:
Последний пример показывает, что библиотека ModuleWare включает достаточно сложные элементы.
IP-блоки (IntellectualProperty) — это блоки, разработанные другими компаниями или поставляемые в составе библиотеки InventraIP компании Mentor Graphics, которые исполь-
зуются в качестве готовых решений. Как правило, в комплект поставки IP-блока входит VHDL- или Verilog-описание интерфейса, а описание архитектуры поставляется в двоичном виде. После нажатия на кнопку добавления IP-блока необходимо указать HDL-файл и выбрать в нем нужный объект. Одним из преимуществ проектирования с помощью IP-блоков является то, что они могут быть использованы в неограниченном количестве проектов. Однако необходимым свойством IP-блока является возможность настройки на конкретный проект. В случае с VHDL-описанием параметры IP-блока задаются при помощи «параметров настройки» (GENERIC) в описании интерфейса (ENTITY) объекта. Изменить значения этих параметров можно щелкнув правой кнопкой мыши по добавленному IP-блоку и выбрав последовательность Object Properties > ExternalIPs > Parameters.
Порты — это средство обеспечения интерфейса с внешними объектами. Интерфейс, то есть список портов блок-диаграммы и соответствующего ей символа должны соответствовать друг другу. В последних версиях среды HDL Designer (на момент написания данной статьи доступна версия 2005.1b) при изменении интерфейса (добавление или удаление порта) и последующем сохранении (как блок-диаграммы, так и символа) происходит синхронизация интерфейсов. В более старых версиях или в случаях, когда синхронизация не произошла автоматически, ее можно сделать вручную, щелкнув правой кнопкой мыши по пустому месту на блок-диаграмме и выбрав Update Interface. В появившемся окне будут показаны расхождения в списках портов символа и блок-диаграммы и возможные варианты действий.
Сигналы (и шины) доступны как в графической форме, в виде линий на блок-диаграмме, так и в табличном виде, во вложенном окне Structure Navigator, которое включается через меню View > Diagram Browser. Формат графического представления сигналов, например, толщину линии, цвет и т. д., можно настраивать.
Если в распоряжении пользователя имеются сконфигурированные данные для лабораторных работ, о которых говорилось в первой статье, можно самостоятельно создать блок-диаграмму (рис. 4). Для этого необходимо выбрать меню File > New > File > Graphical View > Block Diagram и нажать Next. Далее следует указать библиотеку, в которой будет располагать-
ся новая блок-диаграмма, ее имя и имя архитектуры. Имя архитектуры — это имя ENTITY в сгенерированном VHDL-коде. Например, можно указать имя BCDRegister (двоично-десятичный регистр, состоящий из двух готовых двоично-десятичных счетчиков — разрядов регистра), библиотеку XYZLib и имя архитектуры struct.bd. Далее нажать Next и, ничего не вводя в список портов, нажать Finish. При этом открывается пустая блок-диаграмма, а в обозревателе объектов появляется новый объект BCDRegister. В этом обозревателе у объекта BCDRegister нет символа, поскольку он еще не был создан. Объекту соответствует только представление (в виде новой блок-диаграммы). Если данный объект является объектом верхнего уровня, то символ можно и не создавать, поскольку вся информация для генерации ENTITY есть на самой блок-диаграмме: список портов и имя объекта. Однако реальный объект верхнего уровня, как правило, является составной частью тестбенча, поэтому символ позднее придется создать.
Создав новую блок-диаграмму, можно приступить к размещению на ней компонентов. Для этого необходимо нажать на кнопку добавления компонентов (рис. 2) ив появившемся окне добавить к списку библиотек библиотеку XYZLib, нажав кнопку Add Library; пометив в появившемся списке библиотеку XYZLib и раскрыв ее, перетащить объект BCDCounter на блок-диаграмму. На блок-диаграмме появится компонент BCDCounter. Аналогично можно добавить еще один компонент BCDCounter. Кроме списка портов на компонентах присутствует информация о том, из какой библиотеки был выбран компонент (в данном случае это XYZLib), имя объекта (BCDCounter) и имя компонента (имя вхождения). После генерации VHDL-кода имя компонента превращается в метку перед вхождением компонента. Например, если присвоить одному из компонентов имя Ones (единицы), а другому Tens (десятки) и подвести к портам сигналы с теми же именами, что и порты, то после генерации получается следующий код:
-- Instance port mappings.
Ones : BCDCounter PORT MAP ( clear => clear, clk => clk, cnten => cnten, load => load, load_in => load_in, carry_out => carry_out,
q => q
dout <= dinO AND dinl AND din2 AND din3;
:l00000002el5a0e300008le502d7a0e300a0a0e345
:00000001FF
-- ModuleWare code(v1.5) for instance 'I0' of 'rom' mw_I0addr_int <= (TO_INTEGER(unsigned(d))); i0rom_table_proc : PROCESS ( mw_I0addr_int )
BEGIN
CASE mw_I0addr_int IS
WHEN 0 => mw_I0rom_table(0) <= «11100011»;
WHEN 1 => mw_I0rom_table(1) <= «10100000»;
WHEN 2 => mw_I0rom_table(2) <= «10100000»;
WHEN 3 => mw_I0rom_table(3) <= «00000000»;
WHEN 4 => mw_I0rom_table(4) <= «11100011»;
WHEN 5 => mw_I0rom_table(5) <= «10100000»;
WHEN 6 => mw_I0rom_table(6) <= «11010111»;
WHEN 7 => mw_I0rom_table(7) <= «00000010»;
WHEN 8 => mw_I0rom_table(8) <= «11100101»;
WHEN 9 => mw_I0rom_table(9) <= «10000001»;
WHEN 10 => mw_I0rom_table(10) <= «00000000»; WHEN 11 => mw_I0rom_table(11) <= «00000000»; WHEN 12 => mw_I0rom_table(12) <= «11100011»; WHEN 13 => mw_I0rom_table(13) <= «10100000»; WHEN 14 => mw_I0rom_table(14) <= «00010101»; WHEN 15 => mw_I0rom_table(15) <= «00101110»; WHEN OTHERS => mw_I0rom_table(mw_I0addr_int) <= (OTHERS => 'X') ;
END CASE;
END PROCESS ;
i0rom_read_proc : PROCESS ( clk )
BEGIN
IF (clk'EVENT AND clk='1') THEN
q <= mw_I0rom_table(mw_I0addr_int);
END IF;
END PROCESS ;
Tens : BCDCounter PORT MAP ( clear => clearl, clk => clkl, cnten => cntenl, load => loadl, load_in => load_in1, carry_out => carry_out1,
q => q1
Далее можно добавить на диаграмму блок (синий), указать имя объекта как BCDRegControl, а имя компонента оставить по умолчанию. Следует иметь ввиду, что при работе с блоком можно редактировать не только имя вхождения объекта, но и имя самого объекта (то есть имя ENTITY). Это объясняется тем, что, как отмечалось выше, блок может быть использован только в одном месте, несмотря на то, что при генерации из него получается полноценный объект, со своим ENTITY и со своей ARCHITECTURE. Полученную блок-диаграмму (рис. 4) необходимо сохранить.
При добавлении сигналов следует обратить внимание на то, что если «новый» сигнал подводится к порту на компоненте, то сигнал автоматически принимает то же имя и тип, что и порт.
Нерассмотренным остался еще один объект на блок-диаграмме — это штамп. В качестве штампа может быть использован любой графический комментарий. Это можно сделать путем выделения нужного комментария и использования меню File > Save Title Block. Сложная структура штампа достигается груп-
reset
std___logic
clk
stdjogic
stdjogic data in
unsigned(7:0)
ripple_in
stdjogic
cairy_out_ones
stdjogic
q_ones
unsigned(3:0)
XYZLib
BCDRegControl
12
stdjogic load in tens
unsigned(3:0)
cntenjen^
stdjogic load in tens
stdjogic
clk tensf
stdjogic
clear q
loadjn XYZLib
cnten BCDRegControl Ones
load carry_out
>clk
data_out unsigned (7:0^^ ripole out
stdjogic 1
o—
stdjogic ^ ad in tens
unsigned(3:0)
cnten tens.
stdjogic load in tens
stdjogic
clk tens r
stdjogic
clear
q
loadjn
XYZLib
cnten BCDRegControl
Tens
load
carry_out
>clk
carry_out_tens
stdjogic
q_tens
usigned(3:0)
Ccompany name>
Title: BCDRegister Block Diagram
Path: XYZLib/BCDRegister/struct
Edited: by gerhardb on 11 Jun 2001
Project: <enter project name here>
The BcD Register implements a cascadable two digit BCD Counter with reset and load functionality
Рис. 4
пировкой нескольких комментариев с помощью меню Group > Group.
В следующей статье речь пойдет о конечных автоматах (State Machines). ■