Автор: Бибило П.Н.  

Теги: программирование  

ISBN: 5-93455-056-X

Год: 2007

Текст
                    П.Н. Бибило

ОСНОВЫ ЯЗЫКА
VHDL

“Солон-Р”
Москва 2007
П.Н. Бибило


Основы языка VHDL Эффективная работа в современных САПР, разработанных ведущими зарубежными фирмами в области микроэлектроники (XILINX, Altera, Cadence, Synopsys, Mentor Graphics и др.), требует знания языка VHDL – исходного языка описания проектов. Книга доктора технических наук, профессора Бибило П.Н. предназначена для первоначального ознакомления с языком VHDL, являющимся международным стандартом в области автоматизации проектирования микроэлектронных систем на современной элементной базе сверхбольших интегральных схем (СБИС) – как на заказных СБИС, так и на программируемых логических интегральных схемах (ПЛИС). Рецензенты: доктор технических наук А.А. Петровский, доктор технических наук А.А. Прихожий, кандидат технических наук Д.И. Черемисинов Приглашаем к сотрудничеству Авторов по тематике САПР: E-mail: Solon.Pub@relcom.ru тел.: (095) 254-44-10 (095) 252-36-96 ISBN 5-93455-056-X ©  “CОЛОН-P”, 2007 П.Н.Бибило, 2007
3 Оглавление Оглавление Оглавление Предисловие ............................................. 5 Глава 1. Основные элементы языка VHDL............... 7 1.1. Структурное и поведенческое описание цифровой системы .......................................... 7 1.2. Лексические элементы и типы данных.............. 19 1.3. Декларации ..................................... 33 1.4. Интерфейс и архитектура объекта ................. 35 1.5. Предопределенные атрибуты ..................... 38 1.6. Имена .......................................... 41 1.7. Операторы ...................................... 42 1.8. Понятие сигнала в языке VHDL ................... 49 1.9. Дельта-задержка ................................. 53 Упражнения .................................. 57 Глава 2. Последовательные и параллельные операторы .. 62 2.1. Последовательные операторы ..................... 62 2.2. Параллельные операторы......................... 78 Упражнения .................................. 99 Глава 3. Организация проекта ......................... 107 3.1. Подпрограммы ................................. 107 3.2. Функции ....................................... 108 3.3. Процедуры ..................................... 109 3.4. Разрешающие функции. Пакет std_logic_1164 ...... 111 3.5. Архитектура.................................... 117 3.6. Декларация интерфейса объекта.................. 118 3.7. Карта портов и карта настройки ................. 120
4 Оглавление 3.8. Конфигурация .................................. 121 3.9. Блоки проекта и VHDL-библиотеки .............. 124 Упражнения ................................. 126 Глава 4. Примеры проектирования на VHDL ........... 128 4.1. Стили описания поведения ....................... 128 4.2. Формы описания сигналов ....................... 131 4.3. Описание автоматов ............................ 135 4.4. Отладка VHDL-описаний........................ 155 4.5. Синтезируемое подмножество языка VHDL ....... 158 Упражнения ................................. 169 Литература .............................................. 171 Приложения ............................................ 172 1. Форма задания синтаксических конструкций языка VHDL .................................... 172 2. Синтаксис языка VHDL’93 ........................ 173 3. Пакет STANDARD ............................... 197 4. Пакет STD_LOGIC_1164 .......................... 199
Предисловие 5 Предисловие Предисловие Язык VHDL (Very high speed integrated circuits Hardware Description Language) является фактически международным стандартом в области автоматизации проектирования цифровых систем, это входной язык многих современных систем автоматизированного проектирования (САПР) как заказных, так и программируемых логических интегральных схем (ПЛИС) - Programmable Logic Devices (PLD) - и программируемых пользователями вентильных матриц - Field-Programmable Gate Arrays (FPGA). VHDL предназначен, в первую очередь, для спецификации точного описания проектируемых систем и их моделирования на начальных этапах проектирования - алгоритмическом и логическом. С помощью VHDL можно моделировать электронные схемы с учетом реальных временных задержек. В последнее время весьма успешно разрабатываются и системы синтеза схем по спецификациям на этом языке. Например, используя САПР Xilinx Foundation Series 2.1i, можно провести моделирование исходного описания схемы на языке VHDL, а затем синтезировать схему и получить файл настройки (конфигурации) микросхемы типа FPGA фирмы Xilinx. Использование САПР MAX+PLUSII позволяет решать аналогичные задачи для программируемых микросхем, выпускаемых фирмой Altera. Для заказных СБИС могут быть использованы САПР фирмы Mentor Graphics: система моделирования ModelSim позволяет провести моделирование описаний, представленных на языке VHDL, система синтеза Leonardo Spectrum Level 3 позволяет получать по описаниям на языке VHDL схемы в заданных базисах логических элементов. Такие крупнейшие фирмы – производители программного обеспечения САПР в области микроэлектроники, как Cadence, Synopsys и многие другие используют язык VHDL в качестве языка исходного описания проектов. VHDL - это мощный язык, он позволяет описывать поведение, т.е. алгоритмы функционирования цифровых систем, а также проводить иерархическое функционально-структурное описание систем, имеет средства для описания параллельных асинхронных процессов, регулярных (систолических) структур и в то же время имеет все признаки языка программирования высокого уровня - позволяет создавать свои типы
6 Предисловие данных, имеет широкий набор арифметических и логических операций и т.д. Язык VHDL был разработан в США по инициативе министерства обороны этой страны. В 1987 г. VHDL был принят в качестве стандарта ANSI/IEEE Std 1076-1987. Данный стандарт часто называют VHDL’87. Затем язык был усовершенствован, новый стандарт ANSI/IEEE Std 10761993 (стандарт VHDL’93) появился в 1993 г. Книга [7] целиком посвящена новому стандарту языка и его отличиям от стандарта VHDL’87. В 1999 г. утвержден стандарт Std 1076.1-1999 (или более распространенное наименование VHDL-AMS), который включает расширения, дающие возможность описания моделей аналоговых и смешанных (цифро-аналоговых) схем. Язык VHDL развивается, ему посвящаются международные конференции, выходят научные журналы, в которых изучаются проблемы использования VHDL. Он стал языком разработки международных проектов, в том числе осуществляемых с помощью всемирной компьютерной сети Internet. Знакомство с этим языком необходимо для эффективной работы по созданию самой разнообразной электронной аппаратуры на современной элементной базе сверхбольших интегральных схем. Данная книга предназначена для первоначального ознакомления с языком VHDL. Приводимые в ней определения синтаксических конструкций языка базируются на стандарте VHDL’87. В приложении дается синтаксис стандарта VHDL’93. Основной упор в книге делается на применение языка VHDL на этапах алгоритмического и логического проектирования цифровых систем, она оказалась незаменимой при начальном изучении языка VHDL студентами Белгосуниверситета (специализация “Математическая электроника”). При написании книги за основу был взят материал лекционного курса, читаемого автором в этом вузе на протяжении ряда лет. В конце каждой главы даются вопросы, задачи и упражнения для самостоятельной работы. Книга будет полезна как для студентов и аспирантов соответствующих специальностей, так и для специалистов, занимающихся разработкой электронной аппаратуры с помощью средств САПР. Автор выражает благодарность О.В.Клачко за помощь в подготовке рукописи к изданию.
Структурное и поведенческое описание цифровой системы 7 Глава 1 Основные элементы языка VHDL Глава 1. Основные элементы языка VHDL 1.1. Структурное и поведенческое описание цифровой системы Структурное и поведенческое описание цифровой системы Цифровая система может быть описана на уровне поведения функций, реализуемых системой, и на структурном уровне. Структурное описание - это описание системы в виде совокупности компонент (подсхем, элементов) и связей между компонентами. Поведенческое описание - это описание системы при помощи некоторых процедур на уровне зависимостей выходов от входов. Иначе говоря, поведенческое описание задает алгоритм, реализуемый системой. Цифровая система может быть сложной, как, например, СБИС, (микропроцессор) или весьма простой, как логический элемент (вентиль). Естественно, некоторые компоненты системы в структурном описании могут состоять из нескольких частей - компонент более низкого уровня иерархии описания. Представляя отношение вхождения подсхем в схемы в виде графа, можно получить дерево (граф) иерархии описания всей системы. Например, пусть цифровая система S (рис. 1.1) реализует следующий алгоритм. На входные полюсы системы S подаются два двухразрядных числа a=(a2,a1), b=(b2,b1), где a2, b2 - старшие разряды чисел a, b соответственно и x - управляющий сигнал [3]. Если x=1, система S должна перемножить числа a, b и выдать четырехразрядное число d=(d4,d3,d2,d1), где d= a×b. Если x=0, то числа a, b должны быть сложены, при этом в разряде d4 всегда должен быть нуль, в разряде d3 - перенос c2, в разряде d2 - старший разряд суммы s2, в разряде d1 - младший разряд суммы s1. Предполагается, что
8 Глава 1. Основные элементы языка VHDL (a2,a1) + (b2,b1)= (с2,s2,s1). Мы описали алгоритм, который должна реализовать система S, на русском языке. Однако для автоматизированного (компьютерного) проектирования требуется формальная спецификация. a1 a2 d4 b2 d3 S b1 d2 d1 Интерфейс x Рис.1.1. Система S и ее интерфейс Формальные спецификации должны быть записаны на соответствующем формальном языке. Позже будет показано, что алгоритм, реализуемый системой S, может быть очень коротко описан на языке VHDL. Если же рассматривать структурный уровень описания системы S, то можно легко увидеть, что в систему S входит двухразрядный сумматор и двухразрядный умножитель. Двухразрядный сумматор - это устройство для сложения двухразрядных чисел, двухразрядный умножитель - устройство для перемножения двух чисел, каждое из которых имеет только два
9 Структурное и поведенческое описание цифровой системы разряда. В систему S должно входить также простейшее устройство управления и схема дизъюнктивного объединения выходных сигналов. Структура системы S изображена на рис. 1.2, где adder_2 двухразрядный сумматор, mult_2 - двухразрядный умножитель, yy устройство управления, dd схема дизъюнктивного формирования d4 d3 1 dd t4 t3 t2 d2 d1 1 1 c2 t1 mult_2 b2 b1 s2 s1 adder_2 f2 f1 f4 f3 f6 f5 yy x a2 a1 Рис. 1.2. Структура цифровой системы S выходных сигналов. Схему dd образуют три дизъюнктора. Устройство управления yy является весьма простым и функционирует следующим образом: если x=0, то (a2,a1)=(f4,f3), (b2,b1)=(f6,f5),
10 Глава 1. Основные элементы языка VHDL (f2,f1)=(0,0), т.е. числа a, b подаются на вход сумматора adder_2. Если же x=1, то (f4,f3)=(0,0), (f6,f5)=(0,0), (a2,a1)=(f2,f1), т.е. числа a, b подаются на вход умножителя mult_2. Пусть описание системы S имеет имя VLSI_1. Тогда иерархия структурного описания системы S будет иметь вид (рис.1.3) VLSI_1 adder_2 mult_2 yy dd Рис. 1.3. Дерево иерархии структурного описания системы S Рассмотрим двухразрядный умножитель mult_2. На вход данной схемы (рис. 1.4) поступают сигналы r1, r0, s1, s0. Сигналы r1, r0 интерпретируются как двухразрядное целое число r=(r1,r0), сигналы s1, s0 - как двухразрядное целое число s=(s1,s0). Выходные сигналы в t3, t2, t1, t0 представляют собой разряды числа t=(t3, t2, t1, t0) - произведения чисел s, r: (t3, t2, t1, t0) = (r1,r0)×(s1,s0). В схему входят элементы двух типов - add1 и and2. Элемент and2 представляет собой логический элемент И двухвходовый конъюнктор. Заметим, что на языке VHDL знак & употребляется не для обозначения логической операции "И" (конъюнкции), а для операции конкатенации векторов. Оператором логической конъюнкции служит оператор and, поэтому описание функции элемента and2 на языке VHDL выглядит следующим образом: y <= x1 and x2;
11 Структурное и поведенческое описание цифровой системы где x1, x2 - имена входных сигналов, у - имя выходного сигнала, <= - оператор назначения сигнала (будет рассмотрен позже). t3 t2 add1 t1 t0 circ2 add1 circ1 p3 p2 p4 and2 and2 el_4 el_3 pl s1 r1 r0 and2 el_2 and2 el_1 s0 r1 r0 Рис. 1.4. Двухразрядный умножитель mult_2 Элемент add1 представляет собой одноразрядный полусумматор, функционирование которого описывается таблицей истинности (табл. 1.1). b1 0 0 1 1 Таблица 1.1 b2 c s1 0 0 0 1 0 1 0 0 1 1 1 0
12 Глава 1. Основные элементы языка VHDL В данном случае b1, b2 интерпретируются как одноразрядные числа, s1 - сумма, c - перенос в следующий разряд. В привычной математической записи булевы функции c, s1 могут быть представлены следующим образом: s1 = b1 ⊕ b2 = (b1 ∧ b2 )∨( b1 ∧b2 ), c=b1∧b2. В языке VHDL функционирование записывается следующим образом: элемента add1 s1<=((b1 and (not b2)) or (not b1) and b2)); c<=b1 and b2; где or - оператор логической дизъюнкции; and - оператор логической конъюнкции; not - оператор отрицания. Итак, в дерево проекта схемы умножителя, которую назовем mult_2, входят элемент and2 и подсхема add1. Если использовать логические элементы or2 (двухвходовый дизъюнктор) и inv (инвертор) и and2 (двухвходовый конъюнктор) для реализации подсхемы add1, то дерево проекта будет трехуровневым. Элементы and2, or2, inv являются листьями проекта. Листья проекта не имеют составных частей и называются примитивами проекта. Примитив описывается только на поведенческом уровне. Объектами проекта для двухразрядного умножителя являются mult_2, add1, and2. Обозначение корня дерева (mult_2) является именем проекта. Каждый объект проекта имеет два различных типа описаний: - описание объекта "в целом" (entity); - описание архитектуры объекта (architecture). Упрощенно можно сказать, что описание объекта "в целом" состоит из имени объекта и описания портов (входов, выходов) объекта. Описание объекта "в целом" в языке VHDL носит название "интерфейс" объекта. Чтобы отличать один объект проекта от другого, термин entity будет пониматься иногда и как объект проекта. Для сигналов, подаваемых, снимаемых с портов указывается вид (режим, направление) сигнала: входной (in), выходной (out) и его тип.
Структурное и поведенческое описание цифровой системы 13 Описание объекта проекта and2 имеет вид. entity and2 is port (x1,x2: in BIT; y: out BIT); end and2; -- декларация имени объекта проекта -- декларация входных портов -- декларация выходного порта architecture functional of and2 is -- декларация архитектуры begin y <= x1 and x2; -- описание функции объекта end functional; В тексте данной программы имеются комментарии. Комментарий начинается двумя смежными дефисами и продолжается до конца строки. В данном примере BIT - это тип сигнала. Архитектурное тело может определять поведение объекта проекта непосредственно (быть примитивом), либо представлять собой структурную декомпозицию на более простые компоненты. Описание объекта проекта add1 выглядит следующим образом: entity add1 is port (b1,b2 : in BIT; c1,s1 : out BIT); end add1; architecture struct_1 of add1 is begin s1<= ((b1 and (not b2)) or ((not b1) and b2)); c1<= b1 and b2; end struct_1; Описание объекта проекта mult_2 выглядит следующим образом: entity mult_2 is port (s1,s0,r1,r0 : in BIT; t3,t2,t1,t0 : out BIT); end mult_2; architecture structure of mult_2 is component
14 Глава 1. Основные элементы языка VHDL add1 port (b1,b2: in BIT; c1,s1: out BIT); end component; signal p1,p2,p3,p4 : BIT; begin t0 <= r0 and s0; -p2 <= r0 and s1; -p1 <= r1 and s0; -p4 <= r1 and s1; -circ1: add1 port map (p1, p2, p3,t1); circ2: add1 port map (p3,p4,t3,t2); end structure; элемент el_1 элемент el_3 элемент el_2 элемент el_4 В описании архитектуры объявляются (декларируются) две подсхемы (компоненты). После ключевого слова begin приводятся экземпляры описаний. Каждый экземпляр имеет уникальную метку (сirc1, сirc2 – метки). Каждый экземпляр имеет карту портов (port map). Карта портов отражает связь между входами, выходами описаний компонента и экземплярами компонента. Заметим, что в данном описании мы использовали понятие компонента (подсхемы) для add1, в то время как логические элементы И схемы мы описали на функциональном уровне, не используя понятие компонента. Возможность проведения таких смешанных описаний является важной полезной особенностью языка VHDL. Данная гибкость весьма удобна при проектировании на начальных этапах, когда важно получить точное алгоритмическое описание, не вдаваясь в детали структурной организации некоторых частей проекта. Аналогично можно рассмотреть двухразрядный сумматор adder_2 (рис. 1.5), состоящий из двух подсхем add1, add2, где add1 это уже известный нам одноразрядный полусумматор, а add2 одноразрядный сумматор, функционирование которого описывается следующей таблицей истинности (табл. 1.2): Таблица 1.2 c1 0 0 a1 0 0 a2 0 1 c2 0 0 s2 0 1
Структурное и поведенческое описание цифровой системы 0 0 1 1 1 1 1 1 0 0 1 1 0 1 0 1 0 1 0 1 0 1 1 1 15 1 0 1 0 0 1 В дерево проекта для подсхемы adder_2 входят подсхемы add1, add2, а VHDL-описание имеет вид entity adder_2 is port (a1, b1, a2,b2 : in BIT; c2,s2,s1 : out BIT); end adder_2; architecture structure of adder_2 is component add1 port (b1,b2: in BIT; c1,s1: out BIT); end component; component add2 port(c1, a1,a2:in BIT; c2,s2:out BIT); end component; signal c1: BIT; begin circ1: add1 port map (b1,b2, c1,s1); circ2: add2 port map (c1,a1,a2,c2,s2); end structure;
16 Глава 1. Основные элементы языка VHDL c2 s1 s2 adder_2 a) a1 b1 a2 b2 s1 add1 s2 c1 add2 c2 б) b1 b2 a1 a2 Рис. 1.5. Двухразрядный сумматор (a1,b1)+(a2,b2)=(c2,s2,s1): a - условное обозначение; б - схема в виде каскадного соединения одноразрядного полусумматора add1 и одноразрядного сумматора add2 Можно заметить, что в различные подсхемы входит add1, при этом подсхема add1, входящая в сумматор adder_2, является листом проекта и поэтому описана на поведенческом уровне. Подсхема add1, входящая в умножитель mult_2, описана на структурном уровне. Предлагаем читателю самостоятельно описать подсхему add1 в виде объекта проекта, используя примитивы and2, or2, inv. Итак, VHDL-код для структурного описания системы S (см. рис. 1.2) выглядит следующим образом: entity vlsi_1 is port (a2, a1, b2,b1,x:in BIT; d4,d3,d2,d1: out BIT); end vlsi_1; architecture structure of vlsi_1 is component -- декларация компонента adder_2 port (a1,b1,a2,b2: in BIT;
Структурное и поведенческое описание цифровой системы 17 c2,s2,s1: out BIT); end component; component mult_2 port(s1,s0, r1,r0: in BIT; t3,t2,t1,t0: out BIT); end component; component dd port (x1,x2,x3,x4,x5,x6 : in BIT; y1,y2,y3 : out BIT); end component; component yy port( a2,a1,b2,b1,x : in BIT; f6,f5,f4,f3,f2,f1 : out bit); end component; signal f1,f2,f3,f4,f5,f6,t4,t3,t2,t1,c2,s2,s1: BIT; -- декларация внутренних сигналов begin circ1: yy port map ( a2,a1, b2,b1, x, f6,f5,f4,f3,f2,f1); circ2: mult_2 port map ( f2,f1, b2,b1, d4,t3,t2,t1); circ3: adder_2 port map ( f4,f3, f6,f5,c2,s2,s1); circ4: dd port map ( s1,t1,s2,t2,c2,t3, d1,d2,d3); end structure; Дерево проекта для системы S изображено на рис. 1.6. Приведем один из вариантов алгоритмического описания системы S в целом. Следует обратить внимание на то, что входные и выходные сигналы интерпретируются как целые числа, что позволяет сделать алгоритмическое описание весьма компактным. entity vlsi_1 is port (a,b : in integer range 0 to 3; x : in BIT; D : out integer range 0 to 15); end vlsi_1; architecture functional of vlsi_1 is
18 Глава 1. Основные элементы языка VHDL signal e: integer range 0 to 15; begin p0: process(a,b,x) begin if (x='0') then e <= a + b; elsif ( x = '1') then e <= a * b ; end if; end process; D <= e; end functional; VLSI_1 adder_2 add1 add2 mult_2 and2 yy dd add1 Рис.1.6. Дерево проекта цифровой системы S Как видно, оно значительно компактнее структурного описания. Очевидно, что переход от алгоритмического описания к структурному представляет значительный практический интерес. К сожалению, автоматический переход возможен только для подмножества языка VHDL. Такое подмножество языка называется синтезируемым.
Лексические элементы и типы данных 19 Получение функционально-структурной схемы по ее алгоритмическому описанию называется высокоуровневым синтезом в отличие от логического синтеза, когда по функциональноструктурному описанию цифровой системы надо получить логическую схему из заданных базисных логических элементов. Программу, осуществляющую по VHDL-описанию синтез схемы, например схемы FPGA, часто называют компилятором. Однако в системах моделирования VHDL-кодов под компиляцией также понимается преобразование VHDL-кода в промежуточный язык, с которым оперируют непосредственно программы моделирования. Как и для языков программирования, сборку откомпилированных модулей осуществляет программа LINK. Программа, осуществляющая проверку синтаксической корректности, называется VHDL-анализатором. Приведенное VHDL-описание системы S станет понятным позже, когда будут введены типы данных и основные операторы языка VHDL - операторы процессов, назначения сигналов и др. Лексические элементы и типы данных 1.2. Лексические элементы и типы данных Лексические элементы, разделители, операторы. Текст на языке VHDL есть последовательность раздельных лексических элементов, таких как • идентификатор; • разделитель; • ключевое (зарезервированное) слово; • абстрактный литерал; • символьный литерал; • строка литералов; • битовая строка литералов; • комментарий. Смежные лексические элементы разделяются • разделителями; • концами строк; • знаками форматирования. Оператор есть один из следующих специальных символов: & ( ) * + ? - . / : ; < = > |
20 Глава 1. Основные элементы языка VHDL Составной cпециальных символов оператор есть композиция двух смежных => ** := /= >= <= < > Пример. VHDL-предложение A <= B and C; имеет шесть лексических элементов "A", "<=", "B", "and", "C", ";" . Два из шести лексических элементов являются операторами: " <= " (составной оператор назначения сигнала); ";" В качестве разделителей в данном примере используются пробелы, однако нет необходимости иметь разделитель между оператором " ; " и лексическим элементом "C". Комментарий начинается с двух смежных дефисов и продолжается до конца строки. Комментарии не учитываются при моделировании VHDL-описания. Глава 1. Основные элементы языка VHDL Идентификаторы Определение. identifier ::= letter { [ underline ] letter_or_digit } Внимание! Здесь и далее формальная запись синтаксических конструкций языка VHDL основывается на формах Бэкуса-Наура, употребление которых разъясняется в Приложении 1. Далее важная информация, на которую следует обратить особое внимание, будет сопровождаться только восклицательным знаком. Идентификаторы употребляются как пользовательские имена и ключевые слова. Идентификатор должен начинаться с буквы (не цифры). Может употребляться кроме букв и цифр, знак подчеркивания. Два подряд идущих подчеркивания не допускаются. ! В VHDL-коде нет различия между прописными и строчными буквами. AbC7 эквивалентно aBC7, A_3 не эквивалентно A3.
21 Лексические элементы и типы данных Идентификатор не должен оканчиваться подчеркиванием. Пример. Правильные Идентификаторы carry_OUT Dim_Sum Count7SUB_2goX AaBBb Неправильные Идентификаторы 7AB (начинается с цифры) A@B (специальный символ @) SUM_(кончается подчеркиванием) PI_ _A (два подчеркивания подряд) Зарезервированные (ключевые) слова Как и многие другие языки программирования, VHDL имеет ключевые (специальные) слова. Список ключевых слов abs and begin case access architectur e block component after array Alias Assert all attribute body configuratio n elsif for if library nand null others process report subtype units when Buffer Constant bus disconnect downto else End entity exit file Function generate generic guarded In inout is label Linkage loop map mod New next nor not Of on open or Out package port procedure range record register rem return select severity signal then to transport type until use variable wait while with xor В стандарт VHDL’93 добавлены следующие слова: group pure sla impure reject sll inertial rol sra literal ror srl postponed shared unaffected
22 xnor Глава 1. Основные элементы языка VHDL Литералы Классификация литералов языка VHDL приведена на рис. 1.7. Literal Abstract Decimal Character String BitString Based Рис. 1.7. Классификация литералов Десятичный литерал может быть целым, вещественным или вещественным с экспонентой. Определение. decimal_literal ::= integer [ . integer ] [ exponent ] integer ::= digit { [ underline ] digit } exponent ::= E [ + ] integer | E - integer Примеры. Целые литералы: 21, 0, 1Е2, 3e4, 123_000. Вещественные литералы: 11.0, 0.0, 0.468, 3.141_592_6. Вещественные литералы с экспонентой: 1.23E-11, 1.0E+4, 3.024E+23. Знак экспоненты E может быть строчным либо прописным. Подчеркивание в десятичном литерале не является значащим. Экспонента для целого литерала не должна иметь знак минус. Базовый литерал указывает на систему счисления: - от двоичной
23 Лексические элементы и типы данных до шестнадцатеричной: 2# 1111_1100# 16# fc# 016# 0FC# 7# 510# Все эти литералы имеют значение 252 Число 16#6#E1 означает 6*16**1 - это число 96 в десятичной системе счисления: 96 = 6 × 161. Символ * - знак умножения, ** возведение в степень. Число 2E - 3 не является целым, 3e4 - это число 3 × 104. Символьный литерал формируется одним из символов (букв) между апострофами: 'A','a','%', ''' (литерал - апостроф), ' ' (пробел); 'A' отличается от 'a' в случае символьного литерала. Строковый литерал формируется как последовательность букв (возможно пустая) между двумя кавычками, употребляемыми как строковые скобки. Строковый литерал должен располагаться в одной строке. Для формирования "длинных" строковых литералов может быть употреблена операция конкатенации & (напомним, что для оператора логического И употребляется оператор AND). Литерал "строка бит" Определение. bit_string_literal ::= base_specifier " bit_value " base_specifier ::= B | O | X bit_value ::= extended_digit { [ underline ] extended_digit } Литерал "строка бит" формируется как последовательность цифр 0, ... , 9, A, ... ,F (или a, ... , f) между двумя кавычками. Подчеркивание в таком литерале не является значащим. Литерал "строка бит" может быть B - бинарным; O - восьмеричным; X - шестнадцатеричным. Очевидно, вместо прописных букв B, O, X могут употребляться строчные буквы b, o, x.
24 Глава 1. Основные элементы языка VHDL Длина строкового битового литерала есть число бит в последовательности, представляющей литерал. Для примера: все литералы X"F_FF", O"7777", B"1111_1111_1111" имеют длину 12. Примеры. B"1010110" -- длина 7 O"126" -- эквивалентно B"001_010_110", длина 9 X"56" -- эквивалентно B"0101_0110", длина 8 Пакеты Базовым элементом в языке VHDL служит блок. Блок - это ограниченный фрагмент текста, содержащий раздел описания и исполняемый раздел. Само архитектурное тело есть блок. Более подробно оператор "блок" будет рассмотрен далее. Пакет (package) в VHDL - это блок, который может включать множество деклараций: • типов; • подтипов; • констант; • процедур; • функций. Пример функции языка VHDL: функция NOW возвращает текущее время системы моделирования. Тело пакета есть одно из мест, где могут быть определены тела функций, тела процедур и другие VHDL-описания (рис. 1.8). Функции и процедуры иногда называют подпрограммами. Приведем только пример декларации процедуры, более подробно подпрограммы будут рассмотрены далее. Пакет multiplexer показывает, что процедура MX декларируется в пакете и тело процедуры определяется в теле пакета. package multiplexer is procedure MX( signal SEL : in bit; signal x0 : in bit; signal x1 : in bit; signal F : out bit); end multiplexer; package body multiplexer is procedure MX(
25 Лексические элементы и типы данных signal SEL : in bit; signal x0 : in bit; signal x1 : in bit; signal F : out bit) is begin case SEL is when '0' => F <= x0; when others => F <= x1; end case; end MX; end multiplexer; entity architecture package configuration package body Рис. 1.8. В пакете могут размещаться различные VHDL-описания Типы Большинство языков программирования предусматривает различные типы данных, и язык VHDL не является в этом смысле исключением. Однако, поскольку этот язык используется для представления аппаратных проектов в самых разных вариантах, средства типизации данных приобретают здесь особенно важное значение. Например, они дают разработчику возможность представить группу линий (проводников) шины в виде • массива битов; • целого числа.
26 Глава 1. Основные элементы языка VHDL В языке VHDL реализована строгая типизация. Это означает, что смешение различных типов в одной операции является ошибкой. Средства строгого контроля типов играют ответственную роль, поскольку позволяют уточнять намерения разработчика [1]. Тип - поименованное множество значений с некоторыми общими характеристиками. Подтип - подмножество значений данного типа. Например, тип NATURAL есть подтип типа INTEGER. Классификация типов языка VHDL дана на рис. 1.9. Types Scalar Integer Real Composite Physical File Accsess Enumerated Типы определяются обычно в Рис. 1.9. Классификация типов • пакете; • процессе; • архитектурном теле. Тип "целый" Определение. integer_type_definition ::= range_constraint range_constraint ::= range range range ::= simple_expression direction simple_expression direction ::= to | downto Примеры декларации целых типов. type byte_int is range 0 to 255;
27 Лексические элементы и типы данных type signed_word_int is range –32768 to 32767; type bit_index is range 31 downto 0; В табл. 1.3 приведены основные типы данных языка VHDL. Логические типы BOOLEAN (булев) BIT (битовый) BIT_VECTOR (битовый вектор) - Арифметические типы INTEGER (целый) POSITIV (положительный) NATURAL (натуральный) REAL (вещественный) Таблица 1.3 Символьные типы CHARACTER (символьный) STRING (строковый) - В пакете STANDARD (см. приложение 3) декларируются типы BOOLEAN, BIT, CHARACTER, INTEGER, NATURAL, TIME, STRING, BIT_VECTOR. Тип BOOLEAN состоит из значений TRUE (истина), FALSE (ложь). Все операторы IF (если) в языке должны проверять объекты или выражения этого типа. Тип BIT состоит из значений 0,1. Значение TRUE типа BOOLEAN не эквивалентно значению 1 типа BIT, аналогично, значение FALSE не эквивалентно значению 0. Тип СHARACTER, по сути дела, представляет набор символов кода ASCII. Числовые типы имеют диапазон (range), или область значений. Примеры. type INDEX is range 0 to 9; -- тип целый, type VOLTAGE is range 0.0 to 10.0; -- тип вещественный.
28 Глава 1. Основные элементы языка VHDL Физический тип Определение. physical_type_definition ::= range_constraint units base_unit_declaration { secondary_unit_declaration } end units base_unit_declaration ::= identifier ; secondary_unit_declaration ::= identifier = physical_literal ; physical_literal ::= [ abstract_literal ] unit_name Поскольку VHDL - это язык описания аппаратуры, в нем предусмотрены физические типы. Например, тип TIME (время) может быть описан следующим образом: type TIME is range 0 to 1E20 units fs; ps = 1000fs; ns = 1000ps; us = 1000ns; ms = 1000us; s = 1000ms; min = 60s; nr = 60min; end units; В качестве базовой выбрана фемтосекунда (10-15 с). Диапазон (1E20) обеспечивает максимальный период времени 100 000 с (27,7 ч). Естественно, диапазон ограничивается длиной слова инструментальной машины. Перечислимые типы Определение. enumeration_type_definition ::= ( enumeration_literal { , enumeration_literal } )
Лексические элементы и типы данных 29 enumeration_literal ::= identifier | character_literal Примеры перечислимых типов. type logic_level is (unknown, low, undriven, high); type alu_function is (disable, pass, add, subtract, multiply, divide); type octal_digit is ('0', '1', '2', '3', '4', '5', '6', '7'); Определения некоторых перечислимых типов: type severity_level is (note, warning, error, failure); type boolean is (false, true); type bit is ('0', '1'); Составные типы - это тип "массив" (индексируемый тип) и тип "запись" (структурный тип). Массивы Определение . array_type_definition ::= unconstrained_array_definition | constrained_array_definition unconstrained_array_definition ::= array ( index_subtype_definition { , index_subtype_definition }) of element_subtype_indication constrained_array_definition ::= array index_constraint of element_subtype_indication index_subtype_definition ::= type_mark range <> index_constraint ::= ( discrete_range { , discrete_range }) discrete_range ::= discrete_subtype_indication | range Примеры декларации типа "массив". type word is array (31 downto 0) of bit; type memory is array (address) of word;
30 Глава 1. Основные элементы языка VHDL type transform is array (1 to 4, 1 to 4) of real; type register_bank is array (byte range 0 to 132) of integer; Тип BIT_VECTOR определяет массив битов, например BIT_VECTOR (0 to 7). Тип BIT_VECTOR есть тип массива, который неявно описывается следующим образом: type BIT_VECTOR is array (NATURAL range <>) of BIT; BIT - базовый тип элементов массива, выражение "NATURAL range" (диапазон натуральный) - это стандартный способ указать, что длина массива будет задаваться диапазоном натуральных чисел. Пользователь должен задавать конкретный диапазон при применении такого типа, например, BIT_VECTOR (0 to 3) - возрастающий диапазон, BIT_VECTOR (7 downto 0) - убывающий диапазон. Примеры массивов, определяемых пользователем (рис. 1.10). 3 2 1 0 15 0 1 0 1 1022 1023 4094 4095 14 1k × 4 ... ... ... 2 signal Mem4k16: array(0 to 4095) of bit_vector(15 downto 0); Пример. Рис. 1.10. Примеры пользователем массивов, определяемых signal DataBus: bit_vector (7 downto 0); 0 6 0 5 1 4 0 3 0 4k ×16 signal Mem1k4: array(0 to 1023) of bit_vector(3 downto 0); 1 7 1 1 2 DataBus = "10010101" 0 1 1 0 номер разряда
Лексические элементы и типы данных DataBus(7)=’1’ DataBus(6)=’0’ DataBus(5)=’0’ DataBus(4)=’1’ DataBus(3)=’0’ DataBus(2)=’1’ DataBus(1)=’0’ DataBus(0)=’1’ Записи Определение. record_type_definition ::= record element_declaration { element_declaration } end record element_declaration ::= identifier_list : element_subtype_definition ; identifier_list ::= identifier { , identifier } element_subtype_definition ::= subtype_indication Тип "запись" - это составной тип, состоящий из ряда полей. Примеры декларации типа "запись". type instruction is record op_code : processor_op; address_mode : mode; operand1, operand2: integer range 0 to 15; end record; type Instr_T is record Mnemonic: String; Code: Bit_vector (3 downto 0); ExeCycles: Integer; end record; 31
32 Глава 1. Основные элементы языка VHDL signal Instr1, Instr2, Instr3: Instr_T; Примеры сигналов типа Instr_T Instr1.Mnemonic: "add reg1, reg2" Instr1. Code: "0010" Instr1. ExeCycles: 2 Instr2.Mnemonic: "or reg1, reg2" Instr2. Code: "0001" Instr2. ExeCycles: 1 Instr3.Mnemonic: "null reg1, reg2" Instr3. Code: "1110" Instr3. ExeCycles: 8 Например, тип DATE (дата) можно описать как тип "запись" следующим образом: type DATE is record DAY: INTEGER range 1 to 31; MONTH: MONT_NAME; YEAR:INTEGER range 0 to 3000; end record; Здесь MONTH_NAME (имя месяца) - это перечислимый тип, содержащий имена месяцев. VHDL предусматривает (см. рис. 1.9) определенные типы файлов (FILE) и типы доступа (ACCSESS). В данной книге они не рассматриваются.
Декларации 33 Глава 1. Основные элементы языка VHDL 1.3. Декларации Декларации Имеются три класса объектов языка VHDL: • константы; • сигналы; • переменные. С помощью объектов языка VHDL описываются объекты проекта, т.е. различные подсистемы проектируемой (моделируемой) цифровой системы. Поэтому, естественно, следует отличать объекты проекта от объектов языка VHDL Декларация константы. Определение. constant_declaration ::= constant identifier_list : subtype_indication [ := expression ] ; В VHDL константы подобны константам в других языках программирования. Примеры декларации констант. constant PERIOD: time:=100ns; constant PI: real:= 3.14159; constant WIDTH: integer:=32; constant DEFAULT: bit_vector(0 to 3):= "0101"; Если символы ":=" следуют после выражения, то выражение принимает значение объекта. Если символов ":=" нет в декларации константы, то константа называется задержанной. Такие константы могут быть в разделе деклараций пакета. Соответствующая полная декларация появляется в теле пакета. Декларация переменной Определение. variable_declaration ::= variable identifier_list : subtype_indication [ := expression ];
34 Глава 1. Основные элементы языка VHDL Переменная в VHDL подобна идентификатору, употребляемому в других языках программирования высокого уровня. Значение переменной может быть инициализировано и изменено немедленно после выполнения предложения, присваивающего переменной новое значение. Примеры декларации переменных. variable ROM, COLUMN: integer range 0 to 31; variable COUNT : positive :=100; variable MEMORY : TWO_DIMENSION (0 to 15, 0 to 31); Декларация сигнала Определение. signal_declaration ::= signal identifier_list : subtype_indication [ signal_kind ] [ := expression ] ; signal_kind ::= register | bus Концепция сигнала в VHDL является одной из самых важных. Сигналы подобны (соответствуют) физическим линиям (проводникам), которые соединяют элементы схемы. Сигналы и переменные будут рассмотрены далее. Примеры декларации сигналов. signal CLK, RESETn: bit; signal COUNTER: integer range 0 to 31; signal RAM : TWO_DIMENSIONAL (0 to 15, 0 to 31); signal INSTRUCTION: bit_vector (15 downto 0); Декларация компонента Определение. component component_name generic (generic_list); port (port_list); end component; Список портов, начинающийся с ключевого слова port, определяет имя, направление (режим - mode) и тип каждого порта.
Интерфейс и архитектура объекта 35 Тип порта - это тип сигнала, ассоциированного с данным портом. Направление порта может быть: in - входной порт, out - выходной, inout - двунаправленный. Компоненты декларируются в архитектурном теле прежде оператора begin. Для примера можно рассмотреть декларацию компонента add1 в архитектурном теле mult_2. Ключевое слово generic служит для передачи параметров, чаще всего таких, как разрядность, число полюсов и других настраиваемых параметров. Примеры настраиваемых параметров будут даны позже. Компонент является частью проекта. Его реализация осуществляется соответствующим entity и одним либо несколькими архитектурными телами. ! В entity и декларируемом компоненте должны совпадать спецификации. 1.4. Интерфейс и архитектура объекта Интерфейс и архитектура объекта Понятие entity определяется как "интерфейс объекта проекта". В entity описывается интерфейс между объектом проекта и окружением, в котором употребляется объект. "Внутренность" объекта в entity не описывается и может быть уподоблена "черному ящику". Термин "архитектура" безотносительно к языку VHDL может быть определен как распределение функций, реализуемых системой, по отдельным ее уровням и точное определение границ между этими уровнями. К термину "архитектура" близок термин "структура", понимаемый как совокупность элементов системы и связей между ними. Архитектура - это структура системы на функциональном уровне ее описания. Архитектурное тело (architecture) определяет тело объекта, т.е. раскрывает внутренность "черного ящика". В архитектурном теле описываются функции (поведение) либо структура объекта проекта. В приведенном ниже примере архитектурные тела RTL1, RTL2, RTL3 задают поведение схемы, представленной на рис. 1.11. Архитектурные тела, в данном примере это RTL1, RTL2, могут быть различными, задавая одно и то же поведение.
36 Глава 1. Основные элементы языка VHDL x1 w & x2 1 f x3 architecture entity Рис. 1.11. Комбинационная логическая схема Пример. entity ANDOR is port (x1, x2, x3 : f : end ANDOR; in bit; out bit); architecture RTL1 of ANDOR is begin f <= (x1 and x2) or x3; end RTL1; architecture RTL2 of ANDOR is signal w : bit; begin w <= x1 and x2; p1 : process (w, x3) begin f <= w or x3; end process p1; end RTL2;
Интерфейс и архитектура объекта 37 В entity (в разделе деклараций) наряду с декларацией портов могут быть декларированы параметры. Для декларации таких параметров употребляется ключевое слово generic (настраиваемый). С помощью generic могут передаваться такие параметры, как ширина (разрядность) шины, число входных либо выходных полюсов, задержки элементов и т.д. Пример декларации объекта с настраиваемым (изменяемым) параметром N. entity Cate is generic (N: Natural:=4); port (Inputs: in bit_vector ( 1 to N); Result: out bit); end Cate; Изменяя параметр N, можно получать объект Cate с различным числом входов. При этом вносить другие изменения в VHDL-код нет необходимости. Пример "минимальной" декларации объекта entity TestBench is end TestBench; В гл.4. будет показано, что минимальная декларация объекта проекта используется при отладке VHDL-описания. Пример использования generic для описания объекта Processor с переменной шириной шины (рис.1.12). entity Processor is generic (BusWidth: Integer:=3); port (DataBus: inout bit_vector (BusWidth -1 downto 0); . . . ); end Processor
38 Глава 1. Основные элементы языка VHDL 2 1 0 DataBus a) BusWidth=3 3 2 1 0 DataBus б) Processor Processor BusWidth=4 Рис. 1.12. Объект Processor с переменной шириной шины: а - ширина шины равна 3; б - ширина шины равна 4 1.5. Предопределенные атрибуты Предопределенные атрибуты Атрибуты - это значения, связанные с поименованным элементом - объектом языка VHDL. В VHDL имеются предопределенные (predefined) атрибуты и определенные пользователем атрибуты. Определенные пользователем атрибуты в данной книге рассматриваться не будут. Для построения моделей и моделирования важную роль играют атрибуты сигналов. Например, предопределенный атрибут event ассоциируется с каким-либо сигналом (например, с сигналом CLK). Атрибут записывается CLK'event. Этот атрибут имеет тип BOOLEAN cо значением TRUE, когда значение CLK изменилось. Атрибут S'last_value (прошлое значение S) - предыдущее значение, которое сигнал имел непосредственно перед последним изменением S. Относится к тому же самому типу, что и S. Может использоваться для того, чтобы проверить, не изменился ли данный сигнал, например оператор if(S/=S'last_value) позволяет контролировать изменение сигнала S. Атрибут S'stable(T) имеет тип BOOLEAN. Атрибут имеет истинное значение, если сигнал S стабилен в течение последних T
39 Предопределенные атрибуты единиц времени. Если Т=0, атрибут записывается S'stable. Пример. В табл. 1.4 показано, как изменяются значения атрибутов ex'transaction, ex'event, ex'last_value при изменении сигнала ex ex <= '0' after 2 s, '1' after 5 s, '0' after 6 s, '1' after 8 s; Таблица 1.4 Атрибут t=0 false false 0 0 Ex'transaction Ex'event Ex'last_value Сигнал ex t=1 false false 0 0 t=2 true false 0 0 t=3 false false 0 0 Время t=4 t=5 false true false true 0 0 0 1 t=6 true true 1 0 t=7 false false 0 0 t=8 True True 0 1 Временная диаграмма изменения сигнала ex показана на рис. 1.13. Время 0 1 2 3 4 5 6 7 8 9 10 Ex 1 0 Рис. 1.13. Изменение сигнала Ex Полезный набор атрибутов относится к массивам, типам, подтипам, например, атрибуты TS'left, TS'right, TS'low, TS'high возвращают левую, правую, нижнюю и верхнюю границу соответственно (табл.1.5). Пример. Пусть тип type A_BYTE есть массив бит убывающего диапазона (7 downto 0). Тогда A_BYTE'left = A_BYTE'high= 7;
40 Глава 1. Основные элементы языка VHDL A_BYTE'low = A_BYTE'right= 0; В случае type table is array (1 to 8) of bit; variable array_1 : table := ''00001111''; значением атрибута array_1'left является 1 - левая граница возрастающего диапазона. Атрибут TS'base возвращает базовый тип TS. Атрибуты A'left(N), A'right(N), A'high(N), A'low(N) (табл.1.5) ассоциируются с массивом объектов или конструируемым массивом подтипов. Атрибуты возвращают значение N-го объекта в массиве. Параметр N является необязательным и по умолчанию равен 1. Таблица 1.5 Атрибуты Атрибут T'left T'right T'low T'high T'pos(X) Результат Левая граница T Правая граница T Нижняя граница T Верхняя граница T T'val(N) Значение позиции N в T T'leftof(X) Значение левой от X позиции в T T'rightof(X) Значение правой от X позиции в T T'pred(X) Значение нижней соседней с X позиции в T T'succ(X Значение верхней соседней с X позиции в T Позиция объекта X в T Пример. signal RAM: TWO_DIMENSIONAL (0 to 10, 0 to 15); Тогда RAM'left(2) = RAM'low(2) = RAM'low = RAM'low(1) = RAM'left = RAM'left(1) = 0;
Имена 41 RAM'high(1)= RAM'right(1)=10; RAM'high(2)= RAM'right(2)=15; Пример. Пусть Type new_values is (low, high, middle); Тогда значением атрибута new_values'pred (high) является 'low'. Пример. Для перечислимого типа new_values покажем VHDLкод, в котором определяются значения атрибутов "крайних" элементов перечислимого типа. entity TestAtr1 is end TestAtr1; architecture example of TestAtr1 is type new_values is (a1, b1, a2, b2, a3, b3, w); signal A : integer; signal B,D,C,E,F: new_values; begin A<= new_values'pos(a1); B <= new_values'val(4); C <= new_values'leftof(a1); D <= new_values'rightof(w); E <= new_values'pred(b2); F <= new_values'succ(w); end example; В результате моделирования: A = 0; B = 'a3'; C = 1; D = 7; E= 'a2'; F = 7. Обратите внимание на типы. 1.6. Имена Имена Имена употребляются для обозначения декларируемых объектов. Простые имена являются идентификаторами, такими как COUNTER, CLK. Индексированные имена употребляются для обозначения массива элементов, например, RAM(1,3) и INSTRUCTION(5). Интервал имен INSTRUCTION(7 downto 0).
42 Глава 1. Основные элементы языка VHDL Выборка имен используется для выбора полей записи или считывания, а также для выбора элемента библиотеки. Пример. DATE1.MONTH обозначает имя элемента, содержащегося в поле MONTH записи DATE. PACK.VDD может относиться к глобальному сигналу VDD в пакете PACK. WORK.DESIGN может обозначать объект проекта DESIGN в библиотеке WORK. Имена атрибутов могут употребляться для обозначения предопределенных атрибутов или определенных пользователем атрибутов. 1.7. Операторы Операторы Набор операторов (операций) в VHDL обеспечивает возможность работы с предусмотренными типами данных. Список операций приведен в табл. 1.6. Строки табл. 1.7 располагаются в порядке старшинства (от низшего к высшему) операторов. Операторы, находящиеся в одной строке, обладают одинаковым старшинством (приоритетом). Таким образом, операции нижней строки табл. 1.7 обладают наибольшим приоритетом и выполняются первыми, в частности, логический оператор not выполняется прежде других логических операторов. Исходя из контекста VHDL-кода следует отличать оператор <= (назначение сигнала) и оператор <= (меньше либо равно). Следует также отличать унарные операции присвоения знака +, - от соответствующих бинарных операций сложения и вычитания. Замечание. Для устранения неоднозначностей трактовки старшинства операций используются скобки. Например, выражение "A nand B nand C" неверно (синтаксическая ошибка). Данное выражение не представляет трехвходовый элемент И-НЕ (трехвходовую NAND-ячейку). Правильная запись "not (A and B and C) ". Запись "A nand (B nand C)" не есть то же самое, что "(A nand B) nand C".
43 Операторы Таблица 1.6 Операции языка VHDL Обозначение Название not логическое НЕ and логическое И or логическое ИЛИ nand логическое И-НЕ nor логическое ИЛИ-НЕ xor исключающее ИЛИ xnor эквивалентность (VHDL'93) = равно /= не равно < меньше <= меньше либо равно > больше >= больше либо равно + сложение, присвоение знака + - вычитание, присвоение знака - & конкатенация * умножение / деление mod модуль rem остаток ** возведение в степень abs абсолютное значение
44 Глава 1. Основные элементы языка VHDL Класс операций Логические Сравнения Сложения и конкатенации Присвоение знака Умножения Смешанные Классификация операций Операции and or nand nor xor = + /= - + - * ** / abs < & <= mod not rem > Таблица 1.7 Xnor (VHDL’93) >= Примеры арифметических операторов. Сложение (+) RealX2+2.0 1us+3ns Вычитание (-) 8.33-5 BusWidth-1 -- если RealX2 есть сигнал типа -- вещественный, то число 2 должно -- быть записано как вещественное -- 1003ns ---- неправильно, оба числа должны быть одного типа допустимо, если BusWidth типа integer ----- допустимо, если SomeVal типа Integer или Time результат типа Integer либо Real в зависимости от типа Mult --- тип CLK - Integer результат - вещественное число 2.5 Умножение (*) 4*SomeVal Mult*5ns Деление (/) CLK/2 5.0/2.0
45 Операторы 10ns/2ns -- результат 5 типа Integer, но не Time ---- результат 2 результат -2 результат 2 Модуль (mod) 6 mod 4 6 mod (-4) (-6) mod 4 Остаток деления (rem) 6 rem 4 6 rem (-4) (-6) rem 4 ---- результат 2 результат 2 результат -2 Экспонента (**) с*0.5 -A**2 -B**3 -- неправильно в VHDL эквивалентно A*A эквивалентно B*B*B Абсолютное значение (abs) abs1 -результат 1 abs(-1) -результат 1 abs(5*(-2)) -результат 10 Следует быть внимательным при переходе от битовых векторов к числам: bit_vector (0 to 7); 1 0 0 1 1 2 1 3 1 4 1 5 0 6 0 7 bit_vector (7 downto 0); 1 7 0 6 1 5 1 4 1 3 1 2 0 1 0 0 -- возрастающий -- диапазон число 61 (десятичное) -- убывающий -- диапазон число 188 (десятичное) Логические операторы выполняются для следующих типов данных: • boolean;
46 Глава 1. Основные элементы языка VHDL • bit, bit_vector; • std_logic, std_logic_vector; • std_ulogic, std_ulogic_vector. Логические операторы and, or, nand, nor, xor имеют одинаковое старшинство и выполняются слева направо в выражениях. Оператор not имеет более высокое старшинство и выполняется прежде других операторов. В сложных логических выражениях порядок выполнения операторов регулируется скобками. Рекомендуем читателю применять скобки в затруднительных случаях. Например, для выражения Z <= A and not B or C; будет только отрицание B, в выражении Z <= A and not (B or C); будет отрицание подвыражения B or C, находящегося в скобках. Операторы сдвига Данные операторы поясним на примере семиразрядного битового вектора MyBus. signal MyBus: bit_vector(7 downto 0) := "01101001"; Логический сдвиг влево (Shift Left Logical) оператор sll < 0 1 1 0 1 0 0 1 < 0 начало 1 1 0 1 0 0 1 0 < 0 шаг1 1 0 1 0 0 1 0 0 < 0 шаг2 Логический сдвиг вправо (Shift Right Logical)
47 Операторы Оператор srl 0 > 0 1 1 > 0 1 0 0 > 0 0 1 1 0 1 0 0 шаг1 0 > 0 0 0 1 1 0 1 0 шаг2 0 1 начало Арифметический сдвиг влево (Shift Left Arithmetic) оператор sla 0 1 < 1 0 1 0 0 1 начало 1 1 0 1 0 0 1 1 шаг 1 1 0 1 0 0 1 1 1 шаг 2 Арифметический сдвиг вправо (Shift Right Arithmetic) оператор sra > 0 1 1 0 1 0 0 1 начало 0 0 1 1 0 1 0 0 шаг1 0 0 0 1 1 0 1 0 шаг2 Вращение логическое влево (Rotate Left Logical)
48 Глава 1. Основные элементы языка VHDL Оператор rol 0 1 1 0 1 0 0 1 начало 1 1 0 1 0 0 1 0 шаг 1 1 0 1 0 0 1 0 1 шаг 2 Вращение логическое вправо (Rotate Right Logical) оператор ror 0 1 1 0 1 0 0 1 начало 1 0 1 1 0 1 0 0 шаг 1 0 1 0 1 1 0 1 0 шаг 2 Оператор конкатенации Оператор конкатенации обозначается через &. Пример.
Понятие сигнала в языке VHDL 49 BitOne:bit 1 Data2: bit_vector (0 to 7) 0 0 1 0 1 0 1 0 Data2 (3 to 5) Data1: bit_vector (0 to 7) 1 0 1 1 0 0 1 0 Data1 (0 to 3) AggVec:bit_vector(0 to 7) 1 0 1 1 0 1 0 1 AggVec<=(Data1(0 to 3)&Data (3 to 5)&BitOne); Рис. 1.14. Конкатенация векторов 1.8. Понятие сигнала в языке VHDL Понятие сигнала в языке VHDL Логические сигналы в логических схемах передаются и обрабатываются параллельно. На схеме показаны три логических блока [1]. Если предположить, что входной набор 1 и входной набор 2 активизируются одновременно, то логические блоки 1, 2 будут активизироваться также одновременно. Логический блок 3 будет активизирован, а через блоки 1, 2 могут проходить измененные значения сигналов входного набора 1 и входного набора 2. Таким образом поток сигналов может проходить через все блоки одновременно.
50 Глава 1. Основные элементы языка VHDL x1 x2 Логический блок 1 x3 z1 Логический блок 3 z2 x2 x4 Логический блок 2 Рис. 1.15. Логическому блоку схемы соответствует процесс языка VHDL Язык описания аппаратуры должен иметь средства для отображения такой одновременности. В языке VHDL это требование реализуется при помощи механизма процессов. Каждый процесс представляет некоторый логический блок моделируемой схемы, причем все процессы выполняются параллельно (во времени). Три параллельных процесса могут быть описаны следующим образом. BLOCK1: process(X1,X2,X3) -- X1,X2,X3 список -- чувствительности блока 1 begin -- операторы процесса BLOCK1 end process BLOCK1; BLOCK2: process(X2,X4) -- операторы процесса BLOCK2 end process BLOCK2; BLOCK3: process(Z1,Z2) -- операторы процесса BLOCK3 end process BLOCK3;
51 Понятие сигнала в языке VHDL В языке VHDL процесс активизируется, когда происходит изменение какого-либо сигнала в списке сигналов запуска этого процесса. Список сигналов запуска - то же самое, что и список чувствительности (sensitivity list). В общем случае список сигналов запуска содержит входной набор сигналов соответствующего логического блока. Рассмотрим схему (рис. 1.16). 1 A B Y C D & Рис. 1.16. Сигнал Y, имеющий два источника Сигнал У ведет к двум источникам. Каждый источник сигнала есть драйвер. В каждом процессе сигнал должен иметь только один источник, иначе требуется специальная функция, которая будет определять значения сигнала, определяемого из нескольких драйверов. Подробнее эта проблема будет рассмотрена далее. Каждый процесс может быть в одном из трех состояний: • выполняющийся; • активный; • приостановленный. Выполняющийся - когда система моделирования выполняет процесс. Активный - когда процесс является ожидающим, чтобы система моделирования его выполнила. Приостановленный - когда он не является выполняющимся или активным. Большинство ЭВМ, на которых работают системы моделирования, являются однопроцессорными. Параллелизм программно имитируется. Поэтому только один процесс из нескольких параллельных процессов является "выполняющимся" по существу. Реализация параллельных процессов происходит следующим образом.
52 Глава 1. Основные элементы языка VHDL Параллельные процессы, которые надо "одновременно" выполнять, выстраиваются в очередь. Система моделирования выбирает процесс из очереди активных процессов и выполняет процесс, тем самым исполняет предложения языка VHDL, относящиеся к данному процессу. Другие активные процессы выбираются поочередно. Заметим, что выполненный процесс является приостановленным. Когда очередь активных процессов пуста, считается, что все параллельные процессы выполнились "одновременно", и может начаться следующий цикл моделирования. Приостановленный процесс может стать активным, когда изменился хотя бы один из драйверов сигналов из списка чувствительности этого процесса. Рассмотрим простую двухуровневую логическую схему (см. рис. 1.11) и ее описание в языке VHDL в виде параллельных процессов. entity ANDOR is port( x1, x2, x3 : f: end ANDOR; in bit; out bit); architecture example of ANDOR is signal w : bit; begin p0 : w <= x1 and x2 after 10 ns; p1 : process (w, x3) begin f <= w or x3 after 20 ns; end process p1; end example; Во время фазы инициализации каждый сигнал из множества {x1,x2,x3} имеет значение 0. Процесс p0 вычислит w и приостановится. Затем вычисляется значение f через 30ns, так как 10ns выполняется процесс p0 и 20ns - процесс p1. Цикл моделирования начинается, когда один из сигналов изменится. Временная диаграмма изображена на рис. 1.17. Заметим, что если сигнал x1 при декларации не имеет начального значения, то по умолчанию он принимает значение левой границы (x1'left) декларируемого типа. Например,
53 Дельта-задержка signal I : integer range 0 to 3; -- при инициализации значение 0; signal X : std_logic; 10 20 x1 -- при инициализации значение 'U'. 50 80 100 110 1 0 1 0 1 x3 0 x2 w 1 0 f 1 0 Рис. 1.17. Моделирование схемы ANDOR 1.9. Дельта-задержка Дельта-задержка Изменим архитектурное тело example для entity ANDOR, удалив ключевые слова after и конкретные временные задержки тем самым логические операции and, or будут срабатывать "мгновенно". architecture DELTA of ANDOR is signal w:bit; begin p0: w<= x1 and x2; -- нет слова after p1: process(w, x3) begin f<=w or x3; - - нет слова after end process p1; end DELTA;
54 Глава 1. Основные элементы языка VHDL Рассмотрим временную диаграмму (рис. 1.18). 50 x1 80 100 1 0 1 0 1 x3 0 x2 w 1 0 f 1 0 Рис. 1.18. Временная диаграмма (architecture DELTA) В 80ns входной сигнал x2 изменился, что послужило причиной изменения сигнала w и причиной изменения сигнала f. Эта ситуация очерчена лупой на временной диаграмме (рис.1.18). Все это случилось точно в то же время. Рассмотрим более подробно, что же произошло в момент времени 80 ns. В 80ns входной сигнал x2 изменяется. Начинается цикл моделирования. Активизируется процесс p0, выполняется, приостанавливается. Сигнал w изменяется в 0. Резонно сказать, что сигнал w изменился после сигнала x2. Мы будем ссылаться на это время как на время дельта, или дельта-задержку (рис.1.19).
55 Дельта-задержка 80ns x1 1 0 x2 1 0 x3 1 0 w 1 0 f 1 0 Дельта Рис. 1.19. Временная диаграмма, иллюстрирующая понятие "дельта-задержка" Изменение сигнала w служит причиной для процесса p1, который активизируется, выполняется, приостанавливается. Сигнал f изменяется после изменения сигнала w. Появляется другая дельта-задержка. Понятие дельта-задержки есть основное понятие моделирования в языке VHDL. В одно и то же время (физическое) много сигналов могут изменяться и много процессов могут быть активными. После того как все процессы пришли в состояние "приостановленный", система моделирования увеличивает время моделирования. Итак, ответом на вопрос "Что представляет собой дельта-задержка, или просто дельта?" является следующее: ! Дельта есть один цикл прогона VHDL-модели. VHDL-модель, имитирующая поведение цифровой системы, состоит из множества процессов. Во время прогона модели в данном цикле запускаются все процессы, входные параметры которых изменились с момента выполнения последнего цикла. После того как все процессы выполнены, данный цикл моделирования считается завершенным. Следующий цикл начнется после того, как в очередной раз произойдет изменение какого-то входного сигнала для какого-то процесса. Этот период может
56 Глава 1. Основные элементы языка VHDL составлять наносекунды времени моделирования или может просто означать, что мы перешли на следующий цикл моделирования, т.е. сделали временной шаг дельта. Шаг величиной дельта образуется, например, при выполнении операторов назначения сигналов (в рассмотренном примере это сигналы w, f), не имеющих фразы after. С точки зрения логической схемы дельта - это задержка на одном уровне-каскаде логики, когда не задана конкретная задержка логического элемента. Параллельные выполнения операторов (назначение сигналов) указываются при помощи символов <=. Символы := означают процедурное выполнение и называются операторами присваивания значения переменной. Требует ответа еще один важный вопрос: "Где в описаниях на языке VHDL могут быть использованы операторы присваивания значений переменным и операторы назначения сигналов?" Ответ: "Операторы присваивания значений переменным разрешается использовать внутри процессов и в подпрограммах (функциях или процедурах)". Оператор назначения сигналов может встречаться в любом месте выполняемого раздела архитектурного тела. ! Однако можно определять только по одному драйверу на сигнал в процессе. Природа оператора назначения сигнала, оператора присваивания переменной и блоков процессов дает разработчику VHDL-моделей ряд возможностей выбора [1]. В начале проектирования разработчик может использовать блок процесса, алгоритм которого реализуется при помощи операторов присваивания значений переменным, а последний оператор блока есть оператор назначения сигнала, вычисляющий выходной сигнал блока. Такой подход применяется на этапе алгоритмического проектирования, не ориентируясь на какую-то конкретную схему. Другой подход заключается в том, чтобы использовать операторы назначения сигналов. Этот подход называется иногда реализацией "потока данных" (data flow), он ориентирован на конкретную схему и более целесообразен на этапе логического проектирования.
57 Упражнения УПРАЖНЕНИЯ Упражнения 1. Что такое язык VHDL? 2. Для чего предназначен язык VHDL? Выберите правильный ответ. a) только для проектирования заказных СБИС; b) только для проектирования программируемых пользователями вентильных матриц; c) для спецификации аппаратурной части проектируемой цифровой системы; d) для спецификации системы перед разбиением ее на аппаратную и программную части; e) для всех случаев a - d. 3. Что такое VHDL-описание, VHDL-код? 4. Что такое проект, лист проекта, примитив проекта? 5. Что такое иерархия проекта? 6. Что такое высокоуровневый синтез? 7. Что такое логический синтез? 8. Что такое структура схемы, функция схемы, поведение схемы? 9. Что такое IEEE? 10. Что такое VHDL-компилятор, VHDL-анализатор, система моделирования VHDL-кода? 11. Опишите технологию проектирования цифровых систем с использованием VHDL. 12. Можно ли на языке VHDL написать программу нахождения факториала натурального числа? 13. Что такое "синтезируемое подмножество" языка VHDL? 14. Правильно ли утверждение: "VHDL имеет много возможностей для моделирования аналоговых схем" ? 15. Когда были приняты стандарты языка VHDL? 16. Используя примитивы or2, and2, inv, составьте VHDL-код объекта add1. 17. Какие из следующих операторов являются неправильными и почему?
58 Глава 1. Основные элементы языка VHDL А_А, А_, 9U, A%B, P8_3, e4, wait, in, OU_T 18. Какие из следующих литералов являются неправильными и почему? 12_ _000, 1E-0, 2#1101#, 5#44#, #3#, 16# F#E3 19. Какие из следующих литералов c плавающей точкой являются неправильными и почему? 1_ 0.00, 100_.0, 1.1Е-2, 2Н#10.11#, 16 #F #E2, 1_0.0. 20. Какие из следующих литералов типа "строка бит" являются неправильными и почему? 2''110'', В ''1101'', О''047'', Н''ABcd'', 10''99'', ''0101'' 21. Укажите правильные и неправильные идентификаторы a) Decoder_1 b) _Decoder_1 c) 2FFT d) sig_N e) Not_Ack f) Not-Ask g) Sig_#N h) FFT 22. Найдите ошибки в следующем VHDL-коде: entity EXP is end EXP; architecture RTL of EXP is signal A, B, C, D, E, F : bit; signal X, Y, Z, S, T, R : bit; begin R <= A and B and C; S <= B or C or D; T <= A and B or D; Y <= C nor E nor F; X <= A and not B and not C; Z <= F nand E nand B; end RTL; Исправьте их, проверьте результат с помощью VHDLанализатора. 23. Правильно ли утверждение: "Комментарий в языке VHDL начинается и оканчивается двумя дефисами "?
Упражнения 59 24. Для каждого из утверждений ответьте, является оно правильным или ложным: a) все элементы массива должны быть одного и того же типа; b) значение true типа boolean эквивалентно значению 0 типа bit; c) константы могут употребляться в выражениях. 25. Как специфицируются скалярные типы? Выберите правиль-ный ответ: a) употребляя только понятие диапазона значений; b) употребляя только понятие перечисления элементов; c) употребляя а) и b) одновременно. 26. Какой тип данных, возвращаемых операторами сравнения? 27. Правильно ли, что в языке VHDL разрешено умножение вещественного числа на целое? А если один из операндов имеет тип time? 28. Какой из трех операторов отличается от двух других? a) Z <= not X and not Y; b) Z <= not (X and Y); c) Z <= not X and Y; 29. Правильно ли утверждение: "Константе может быть присвоено новое значение, если оно эквивалентно предыдущему значению"? 30. Правильно ли утверждение: "Когда константа декларируется, то достаточно специфицировать ее значение, потому что тип константы косвенным образом определяется через ее значение"? 31. Правильно ли, что логические операторы могут употребляться только для типа bit ? 32. Как определяются арифметические операции для типа bit? Правильно ли, что операторы всегда определяются для отдельных (конкретных) типов данных языка VHDL ? 33. Можно ли в языке VHDL узнать (проверить) предыдущее значение сигнала, предыдущее значение переменной ? Если "да", то как это делается ? 34. Задан фрагмент VHDL-кода. Variable TIME1, TIME2 : time; a) TIME1 := TIME2 * 2,5; b) TIME1:= TIME2/4;
60 Глава 1. Основные элементы языка VHDL c) TIME1:= 3.6 ns + TIME2; d) TIME1:= TIME2 * 6.62 ns; Укажите правильные и неправильные строки. 35. Что такое сигнал в языке VHDL? Чему соответствует сигнал в логической схеме? 36. Чем сигнал отличается от переменной? Как записывается оператор присвоения значения переменной? 37. Что такое параллельный процесс? 38. В каких состояниях бывают параллельные процессы? 39. Что такое дельта-задержка? 40. В каких разделах VHDL-кода может встретиться: - оператор назначения сигнала; - оператор присвоения значения переменной? 41. В какой части VHDL-кода необходимо указывать тип сигнала, который декларируется? Выберите правильный ответ: a) когда сигнал декларируется; b) когда сигнал употребляется первый раз в коде; c) в пакете; d) нет необходимости декларировать тип сигнала. 42. Когда (с точки зрения взаимодействия процессов) сигнал корректируется, т.е. получает то новое значение, которое приобретет в результате операции назначения сигнала, находящейся внутри процесса? 43. Промоделируйте "вручную" параллельные процессы A<=X∗Y; B<=A+Z; используя понятие дельта-задержки. Запишите VHDL-код и промоделируйте его с помощью системы моделирования. 44. Рассмотрите рис. 1.20. Назовите внешние и внутренние сигналы системы A. Ответьте, где декларируются внешние сигналы системы A, где декларируются внутренние сигналы системы A. Укажите интерфейсы для системы А и для подсистем B, C, D. 45. Рассмотрите систему, состоящую из телевизора и переносного кнопочного пульта, с помощью которого осуществляется управление телевизором. Укажите entity и architecture для данной системы.
61 Упражнения A TL1 TL2 TL7 TL4 B TL9 TL5 D C TL6 TL8 TL3 Рис. 1.20. Структура цифровой системы A 46. Рассмотрите персональный компьютер, как систему, состоящую из системного блока, монитора и клавиатуры. Укажите entity и architecture для данной системы.
62 Глава 2. Последовательные и параллельные операторы Глава 2 Последовательные и параллельные операторы Глава 2. Последовательные и параллельные операторы 2.1. Последовательные операторы Последовательные операторы В VHDL последовательные операторы подобны операторам языков высокого уровня. На рис. 2.1 приведена общая структура VHDL-описания, из которой следует, что последовательные операторы (sequential statement) могут появляться внутри операторов процесса или внутри тел подпрограмм (функций, процедур). На данном рисунке указаны основные параллельные и последовательные операторы. Перечислим последовательные операторы: 1) оператор variable assignment (присвоения значения переменной); 2) оператор signal assignment (назначения сигнала, т.е. присвое-ния значения сигналу); 3) оператор if (если); 4) оператор case (случай); 5) оператор loop (цикл); 6) оператор next (следующий); 7) оператор exit (выход); 8) оператор null (нуль, пустой); 9) оператор procedure call (вызова процедуры); 10) оператор return (возврат); 11) оператор assertion (сообщение); 12) оператор wait (ожидать). Оператор присваивания значения переменной Определение. variable_assignment_statement::=target:=expression;
63 Последовательные операторы Данный оператор заменяет текущее значение переменной новым значением, которое определяется выражением. Переменная и выражение должны быть того же базового типа. Package (optional) Entity (I/O) Architecture Concurrent statements Signal declaration Component instantiation statement Conditional signal assignment statement Selected signal assignment statement Generate statement Process statement Sequential statement Variable declaration Signal assignment Variable assignment Procedure call If, case, loop, next, exit, return Wait statement Рис. 2.1. Структура VHDL-описания Еще раз напомним, что присваивание значения переменным не есть то же самое, что сигналам. Присваивание значений сигналам мы обсудим в следующем разделе. В VHDL локальные переменные могут быть только декларированы в области операторов процессов и подпрограмм (функций или процедур).
64 Глава 2. Последовательные и параллельные операторы В следующем VHDL-коде приведены примеры присваивания значений переменным. Слева указаны номера строк, не относящиеся к тексту на языке VHDL. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 entity VAR is end VAR; architecture functional of VAR is signal A, B, J : bit_vector(1 downto 0); signal E, F, G : bit; begin p0 : process (A, B, E, F, G, J) variable C, D, H, Y : bit_vector(1 downto 0); variable W, Q : bit_vector(3 downto 0); variable Z : bit_vector(0 to 7); variable X : bit; variable DATA : bit_vector(31 downto 0); begin C := "11"; X := E and F; Y := H nand J; Z(0 to 3) := C & D; -- конкатенация Z(4 to 7) := (not A) & (A nor B); -- конкатенация D := ('0', '0'); -- агрегат W := (2 downto 1 => G, 3 => '1', others => '0'); -- агрегат DATA := (others => '1'); -- агрегат end process; end functional; В строке 15 переменная C получает константное значение. Выражения в строке 16, 17 используют логические операторы. В строке 18 в выражении употребляется оператор & конкатенации, чтобы присвоить значения первым четырем битам переменной Z. В строке 19 употреблена комбинация логических операторов и конкатенация. Строка 20 показывает агрегат, в котором употребляется позиционное отображение. В строке 21 употребляется позиционное отображение и ключевое слово others.
Последовательные операторы 65 В строке 22 всем компонентам битового вектора - переменной DATA - присваивается значение нуль. Заметим, что локальные переменные "видны" только внутри процессов или подпрограмм, которые декларированы. VHDL‘93 определяет другой класс переменных, называемых shared (совместно используемые, общие), которые могут совместно использоваться (видны) с процессами и подпрограммами. Понятие "видимости" будет рассмотрено далее. Агрегаты и конкатенация могут использоваться не только при присвоении значений переменным, но и при назначении сигналов для таких типов данных, как массивы. Рассмотрим пример агрегата. Variable z_bus : bit_vector (3 downto 0 ); Variable A,B,C,D : bit; z_bus := (A,B,C,D); -- агрегат Запись (A,B,C,D) называется агрегатом. Агрегат заключается в круглые скобки, входящие в агрегат элементы разделяются запятой. Присваивание значений сигналам (назначение сигналов) Определение. signal_assignment_statement::= target <=[transport] waveform_element {, waveform_element}; waveform_element::= value_expression[after time_expression] | null [after time_expression] Ключевое слово transport определяет транспортную задержку. В языке VHDL в операторах назначения сигналов используются два вида задержек: • инерционная задержка; • транспортная задержка; Пример. X<=Y after 3 ns; -- инерционная задержка, X<= transport Y after 3ns; -- транспортная задержка. В случае инерционной задержки передача сигнала будет иметь место, если и только если входной сигнал будет сохранять
66 Глава 2. Последовательные и параллельные операторы соответствующий уровень в течение заданного отрезка времени. В языке VHDL этот заданный отрезок времени и есть задержка, указываемая во фразе after. Таким образом, в первом примере изменение значения Y подействует на значение X только в случае, если новый уровень Y будет сохраняться в течение 3ns и более. Во втором примере (транспортная задержка) все изменения Y будут передаваться в X независимо от того, сколько времени будет сохраняться новое значение Y. ! Если не используется ключевое слово transport, то подразумевается инерционная задержка. Как отмечено в [1], механизм инерционной задержки позволяет отфильтровывать входные сигналы, которые меняются слишком быстро. Данный механизм по существу имитирует работу реальной схемы. Логический сигнал представляется на схемном уровне напряжением узла. Ввиду наличия электрических емкостей напряжения узлов не могут изменяться мгновенно, необходимо, чтобы определенное качество энергии подавалось в течение определенного отрезка времени, - только в этом случае напряжение узла изменится настолько, чтобы вызвать переключение схемы, управляемой этим напряжением. Поэтому при моделировании реальных логических схем используется инерционная задержка. Транспортная задержка чаще используется на этапе алгоритмического проектирования. Укажем различия между локальными переменными и сигналами. 1. Локальные переменные декларируются и видны только внутри процесса или подпрограммы. Сигналы не могут быть декларированы внутри процесса или подпрограммы. 2. Новое значение локальной переменной немедленно корректируется, когда выполняется оператор присваивания. Понятие времени не ассоциируется с понятием переменной. Оператор назначения сигнала корректирует сначала драйвер сигнала. Когда процесс станет приостановленным, сигнал корректируется. Поэтому использование сигналов ведет к двухпроходному моделированию. С точки зрения системы моделирования переменные применять "дешевле". 3. Только сигналы могут употребляться для связывания параллельных операторов. ! Порты, декларируемые в entity, являются сигналами. Аргументы подпрограмм могут быть сигналами или переменными.
67 Последовательные операторы 4. В VHDL-описаниях логических (цифровых) схем сигнал употребляется для описания соединений элементов. Локальные переменные обычно употребляются как временные значения в алгоритме описания функции. Пример. ( Различие между локальной переменной и сигналом). Данный VHDL-код Y<= A+(B*C+D*E*F+G); Z<= A-(B*C+D*E*F+G); эквивалентен следующему VHDL-коду V:=(B*C+D*E*F+G); Y<= A+V; Y<= A- Y; однако не эквивалентен приведенному ниже VHDL-коду V<=(B*C+D*E*F+G); Y<= A+V; Z<= A - Y; Замечание. Запись x <= y <= z понимается не как "конвейерное" назначение сигналов. Правильное понимание: сигналу x присваивается значение, равное значению выражения y<=z (у меньше либо равно z). Назначение сигналов в случае массивов, например битовых векторов, является позиционным. Пример. Signal z_bus : bit_vector (3 downto 0); Signal c_bus : bit_vector (1 to 4); z_bus <= c_bus; эквивалентно z_bus(3) <=c_bus(1); z_bus(2) <=c_bus(2); z_bus(1) <=c_bus(3); z_bus(0) <=c_bus(4); При назначении сигналов должно указываться то направление диапазона (возрастающий диапазон - to, убывающий диапазон - downto), которое было при декларации массива. Для предыдущего примера
68 Глава 2. Последовательные и параллельные операторы z_bus (3 downto 2) <= ''00''; -- правильно c_bus (2 to 4) <= z_bus (3 downto 1); -- правильно z_bus (0 to 1) <= ''11''; -неправильно, так как z_bus декларирован -- с убывающим диапазоном Сигналы и переменные одного и того же типа могут быть присвоены один другому. Пример использования агрегатов при назначении сигналов. Signal z_bus : bit_vector (3 downto 0 ); Signal A,B,C,D : bit; z_bus <= (3 => '1', 1 downto 0 => '1', 2 => B); -- агрегат Оператор if (если) Определение. if_statement::=if condition then sequence of sequential statements {elsif condition then sequence of sequential statements} [else sequence of sequential statements] end if; Оператор if языка VHDL подобен операторам if в других языках программирования. Выражение условия (condition) должно иметь тип BOOLEAN. В одном if операторе может быть одна (ни одной) либо более частей elsif. Ключевое слово elsif следует отличать от слов else if. Часть else может быть только одна (или ни одной). Должен быть разделитель между ключевыми словами в заключительной фразе end if; Следующая модель 5-битового счетчика употребляет if операторы [9]. entity IFSTMT is port ( RSTn, CLK, EN, PL : in bit; DATA : in integer range 0 to 31; COUNT : out integer range 0 to 31);
Последовательные операторы 69 end IFSTMT; architecture RTL of IFSTMT is signal COUNT_VALUE : integer range 0 to 31; begin p0 : process (RSTn, CLK) begin if (RSTn = '0') then COUNT_VALUE <= 0; elsif (CLK'event and CLK = '1') then if (PL = '1') then COUNT_VALUE <= DATA; elsif (EN = '1') then if (COUNT_VALUE = 31) then COUNT_VALUE <= 0; else COUNT_VALUE <= COUNT_VALUE + 1; end if; end if; end if; end process; COUNT <= COUNT_VALUE; end RTL; Как показано в разделе деклараций, 5-битовый счетчик имеет порты RSTn, CLK, EN, PL, DATA. Выходной порт COUNT получает значение счетчика, RSTn - асинхронная установка (в нуль), CLK входной сигнал синхронизации, PL - параллельное считывание, DATA - порт данных. Оператор case (случай) Определение. case_statement ::= case expression is when choice => sequence of sequential statements [when choice => sequence of sequential statements] end case; Оператор case выбирает одну из альтернатив, избранная альтернатива (случай) определяется значением выражения. Выражение (expression) должно быть дискретного типа или типа
70 Глава 2. Последовательные и параллельные операторы одноразмерного массива символов, значения которых могут быть представлены как строки или строка битов. Выбор (choice) должен быть такого же типа, как выражение. Все возможные выборы (случаи) должны быть покрыты. Выбор "others" (другие) должен быть покрыт значением, не покрываемым предыдущими альтернативами. Оператор case является подходящим для моделирования конечных автоматов и программ микропроцессора. Используя оператор case, приведем пример [9] VHDL-кода для вычисления числа дней в каждом месяце. package PACK is type month_type is (JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC); end PACK; use work.PACK.all; entity CASESTMT is port ( MONTH : in month_type; LEAP : in boolean; DAYS : out integer); end CASESTMT; architecture RTL of CASESTMT is begin p0 : process (LEAP, MONTH) begin case MONTH is when FEB => if LEAP then DAYS <= 29; else DAYS <= 28; end if; when APR | JUN | SEP | NOV => DAYS <= 30; when JUL to AUG => DAYS <= 31; when others => DAYS <= 31;
Последовательные операторы 71 end case; end process; end RTL; Оператор loop (оператор цикла) Определение. loop_statement::= [loop_label:][while condition | for identifier in discrete_range] loop sequence of sequential statements end loop [loop_label]; Когда в записи цикла используется ключевое слово while, то сначала вычисляется условие (condition). Если условие есть TRUE, выполняется последовательность последовательных операторов, иначе оператор цикла завершается. Когда в записи цикла используется ключевое слово for, то идентификатор (identifier) определяет цикловой параметр с базовым дискретным типом. Параметр цикла употребляется как константа внутри действия оператора цикла и он не может быть целью оператора присваивания. ! Общая ошибка: употребление параметра цикла снаружи оператора цикла. Пример. loop1: for i in 0 to 9 loop exit loop1 when A(i)>20; next when A(i)>10; sum:=sum +A(i); end loop loop1; if i=20 then -- ошибка! Параметр цикла снаружи цикла. Оператор NEXT Определение. next _statement::=next [loop_label][when condition];
72 Глава 2. Последовательные и параллельные операторы Пример дан выше. Оператор завершения итераций цикла. next употребляется для Оператор EXIT Определение. exit_statement::=extit[loop_label][when condition]; Оператор EXIT употребляется, чтобы завершить выполнение и закрыть оператор цикла. Если условие (condition) есть TRUE, то осуществляется выход из цикла. Оператор null Определение. null_statement::=null; Оператор null не представляет действий. Он употребляется, чтобы точно специфицировать, что нет действий. Типичное применение - в операторе case, чтобы определить действия во всех случаях. Оператор вызова процедуры Оператор вызова процедуры состоит из имени процедуры с аргументами (если они есть) в скобках. Приведем пример определения и вызова функции и процедуры. entity CALL_PRO is end CALL_PRO; architecture RTL of CALL_PRO is function bit_bool (inp_bit : in bit) return boolean is begin if (inp_bit = '1') then return true; else return false; end if; end bit_bool; procedure left_one (
Последовательные операторы 73 signal DATA : in bit_vector (1 to 8); signal l_bit : out integer) is variable temp : integer; begin temp := 0; for i in 1 to 8 loop if (DATA(i) = '1') then temp := i; end if; if (temp /= 0) then exit; end if; end loop; l_bit <= temp; end left_one; signal DIN : bit_vector (1 to 8); signal bit_1 : bit; signal bool_1 : boolean; signal DOUT : integer; begin p0: process (bit_1,DIN) begin bool_1 <= bit_bool(bit_1); -- вызов функции LEFT_ONE(DIN, DOUT); -- вызов процедуры end process; p1: process begin bit_1 <= '1' after 20 ns, '0' after 40 ns; DIN <= "01010000" after 20 ns, "00000000" after 40 ns, "00001100" after 60 ns, "00000001" after 80 ns; wait for 100 ns; end process; end RTL; Функция bit_bool преобразует тип BIT в тип BOOLEAN. Предлагаем читателю провести моделирование, проанализировать временную диаграмму и определить функциональное назначение процедуры left_one.
74 Глава 2. Последовательные и параллельные операторы Оператор return Определение. return_statement::=return[expression]; Употребляется, чтобы завершить выполнение самой внутренней функции или процедуры. Он используется только внутри тела функции или процедуры. Оператор return не требуется в теле процедуры, поэтому в архитектурном теле RTL (entity RETURNSTMT) соответствующая строка может быть удалена. Оператор return может быть употреблен с другими последовательными операторами, такими как if, case для управления возвратом функции или процедуры. Оператор сообщений (assertion) Определение. assertion_statement::=assert condition [report expression ] [severity expression ]; Операторы сообщений проверяют, является ли условие истинным (TRUE), и сообщают об ошибке, если условие является ложным. По умолчанию сообщенное выражение есть "Assertion violation" (нарушение). Выражение с ключевым словом severity (severity - степень серьезности) имеет перечислимый тип: NOTE, WARNING, ERROR, FAILURE. Примеры. assert (CLK'event and CLK='0') report "D hold error" severity WARNING; assert (CLK'last_event > HOLD) report "D hold error" severity ERROR; В данных примерах атрибут CLK'last_event имеет тип TIME и возвращает время, пройденное с момента последнего изменения сигнала CLK, HOLD имеет тип TIME. Условие CLK'last_event>HOLD может быть либо истинным, либо ложным.
Последовательные операторы 75 Оператор wait (ждать) Оператор wait является причиной временного прекращения оператора процесса или процедуры. Определение. wait _statement::= wait [sensitivity_clause] [condition_clause]; [timeout_clause]; sensitivity_clause::= on sensitivity_list condition_clause::= until boolean_expression timeout_clause ::= for time_expression Sensitivity_list - список чувствительности (список сигналов запуска). В цифровых системах логические процессы часто приостанавливаются в своем выполнении, ожидая истечения некоторого периода времени или наступления некоторого события. После истечения указанного периода времени или наступления ожидаемого события выполнение процесса возобновляется. Эта ситуация иллюстрируется следующим образом process ----------------------------------------------wait ------------------------------------------end process; -- начало выполнения процесса -- оператор ожидания -- возобновление выполнения процесса -- конец выполнения процесса Общий вид оператора ожидания wait on sensitivity_list until condition clause for timeout;
76 Глава 2. Последовательные и параллельные операторы Оператор wait приостанавливает процесс до момента, пока не изменится некоторый сигнал в списке чувствительности процесса (sensitivity_list), в это время будет произведено вычисление условия (condition). Фраза условия есть выражение типа BOOLEAN. Если получается истинное значение, выполнение процесса возобновляется. Фраза тайм-аута (timeout) устанавливает максимальное время ожидания, после которого процесс возобновит свое выполнение. Пример. WAIT on A, B until (C=0) for 50 ns; Этот оператор приостановит процесс до момента изменения A или B, после чего будет проверено выражение C=0 и, если результатом проверки будет истина, процесс возобновится. Но независимо от этих условий возобновление процесса произойдет через 50ns. Допустимо записывать одно или более условий в операторе ожидания, например, Условие 1. Условие 2. Условие 3. WAIT on A, B; WAIT until (C=0); WAIT for 50 ns; В условии 1 процесс будет возобновляться, когда изменится A или B. В условии 2 нет списка сигналов запуска, поэтому процесс возобновится, когда C изменит свое значение из 1 в 0. В условии 3 процесс возобновится через 50ns независимо от любых других условий. ! Для оператора процесса мы можем иметь либо список чувствительности после ключевого слова процесс, либо оператор wait, но не оба вместе. Может быть более одного оператора wait внутри оператора процесса. Примеры оператора wait. 1. Оператор wait типа for wait for 10ns; wait for CLK_Period/2;
77 Последовательные операторы 2. Оператор wait типа until wait until CLK='1'; wait until CE and (not RST); wait until IntData>16; 3. Оператор wait типа on wait on CLK; wait on Enable, Data; wait until Enable ='1'; эквивалентн о loop wait on Enable; exit when Enable = '1'; end loop; 4. Комбинированный оператор wait (комбинация двух или трех предыдущих) wait on Data until CLK='1'; wait until CLK='1' for 10ns;
78 Глава 2. Последовательные и параллельные операторы 2.2. Параллельные операторы Глава 2. Последовательные и параллельные операторы Параллельные операторы Параллельные операторы (табл. 2.1) в VHDL определяют параллельное (во времени) поведение схем. ! Порядок выполнения параллельных операторов не связан с порядком их появления внутри архитектурного тела. Параллельные операторы активизируются сигналами, которые употребляются для связи параллельных операторов. Последовательные операторы выполняются в порядке их появления в VHDL-коде. Таблица 2.1. Параллельные операторы Оператор процесса process statement Оператор assert statement параллельного сообщения Оператор procedure call statement параллельного вызова процедуры Условное назначение conditional signal сигнала assignment statement Выборочное selected signal назначение сигнала assignment statement Оператор component instantiation конкретизации statement (создания экземпляра) компонента Оператор генерации generate statement Оператор блока block statement Параллельный оператор процесса (process statement) Определение. process_statement::= [process_label] process [sensitivity_list] process_declaration_part begin sequence of sequential statements
79 Параллельные операторы end process [process_label]; Оператор процесса есть параллельный оператор, который определяет независимое последовательное поведение некоторой части проекта, описанное упорядоченной совокупностью последовательных операторов. Метка процесса необязательна, однако если она есть в конце (после слов end process), то она должна быть и вначале перед словом process. В декларативной части процесса могут быть: • тела подпрограмм; • декларации подтипов; • декларация констант; • декларация файлов; • декларация альтернативных точек входа в подпрограмму; • декларация атрибутов; • спецификации атрибутов. Процесс может иметь список сигналов запуска и один (или более) операторов ожидания, но не оба вместе. ! Сигналы не могут быть декларированы внутри процессов. Структура процесса имеет вид имя_процесса: process(список чувствительности) декларации begin последовательные операторы end process имя_процесса; ! Ожидание (wait) в начале процесса не эквивалентно ожиданию в списке чувствительности процесса. process(signal_1) statement_1; statement_2; ... statement_n; end process; эквивалентно process statement_1; statement_2; ... statement_n; wait on signal_1; end process;
80 Глава 2. Последовательные и параллельные операторы process(signal_1) statement_1; statement_2; ... statement_n; end process; не эквивалентно process wait on signal_1; statement_1; statement_2; ... statement_n; end process; Оператор параллельного сообщения (assert statement) Синтаксис оператора параллельного сообщения такой же, как и у оператора последовательного сообщения. "Параллельность" заключается в том, что оператор assert может присутствовать в параллельных процессах. Оператор параллельного вызова процедуры (procedure call statement) Определение. concurrent_procedure_call::= [label] procedure_call_statement Оператор параллельного вызова процедуры представляет процесс, содержащий оператор последовательного вызова процедуры. Его выполнение эквивалентно оператору процесса. Пример. 1 entity call_parallel is 2 port ( 3 data_inp : in bit_vector(5 downto 0); 4 data_out : out bit_vector(1 downto 0)); 5 end call_parallel; 6 architecture RTL of call_parallel is 7 procedure N_XOR ( 8 signal x1, x2, x3 : in bit; 9 signal f : out bit) is 10 begin 11 f <= x1 xor x2 xor x3; 12 end N_XOR; 13 begin
Параллельные операторы 81 14 N_XOR (x1 => data_inp(5), x2 => data_inp(4), x3 => data_inp(3), 15 f => data_out(1)); 16 p0 : N_XOR (data_inp(2), data_inp(1), data_inp(0), data_out(0)); 17 end RTL; В строках 14, 16 осуществляется параллельный вызов процедур. В строке 16 параметры передаются позиционным сопоставлением, в строке 14 передача параметров осуществляется сопоставлением имен: вместо параметра x1 передается data_inp(5), вместо x2 передается data_inp(4) и т.д. ! Каждый формальный параметр процедуры должен быть типа константы или сигнала. Декларация процедур и тела процедур будут обсуждены далее. Параллельный оператор условного назначения сигнала (conditional signal assignment statement) Oператор параллельного назначения сигнала эквивалентен оператору процесса, назначающему значения сигналам. Определение. concurrent_signal_assignment_statement::= [label:] conditional_signal_assignment  [label:] selected_signal_assignment conditional_signal_assignment::=[guarded][transport] {waveform when condition else] waveform; Могут быть употреблены опции guarded (охраняемый) transport (транспортный). Пример, показывающий эквивалентность параллельного оператора условного назначения сигнала (архитектурное тело first) и оператора процесса (архитектурное тело second). entity example_condition is port ( x1, x2, x3, x4 : in bit;
82 Глава 2. Последовательные и параллельные операторы condition : in bit_vector(1 downto 0); F : out bit); end example_condition; architecture first of example_condition is begin F <= x1 when condition = "00" else x2 when condition = "01" else x3 when condition = "10" else x4; end first; architecture second of example_condition is begin process (x1, x2, x3, x4, condition ) begin if (condition = "00") then F <= x1; elsif (condition = "01") then F <= x2; elsif (condition = "10") then F <= x3; else F <= x4; end if; end process; end second; Параллельный оператор выборочного назначения сигнала (selected signal assignment statement) Определение. selected_signal_assignment::= with expression select [label:] selected_signal_assignment target<=[guarded][transport] {waveform when choices, } waveform choices; Данный оператор эквивалентен оператору процесса. Пример, показывающий эквивалентность параллельного оператора выборочного назначения сигнала (архитектурное тело first) и оператора процесса (архитектурное тело second).
Параллельные операторы 83 entity example_selection is port ( x1, x2, x3, x4 : in bit; selection : in bit_vector(1 downto 0); F : out bit); end example_selection; architecture first of example_selection is begin with selection select F <= x1 when "00", x2 when "01", x3 when "10", x4 when others; end first; architecture second of example_selection is begin process (x1, x2, x3, x4, selection) begin case selection is when "00" => F <= x1; when "01" => F <= x2; when "10" => F <= x3; when others => F <= x4; end case; end process; end second; Параллельный оператор конкретизации компонента (component instantiation statement ) Определение. component_instantiation_statement::= instantiation_label: component_name [generic_map_aspect] [port_map_aspect]; Этот оператор употребляется для структурной организации проекта. Часть схемы (подсхема) описывается как компонент (component), имеющий имя (name). Одна и та же подсхема может
84 Глава 2. Последовательные и параллельные операторы входить в схему несколько раз, однако при этом она имеет различные связи. Чтобы описать эти связи, употребляется оператор создания экземпляра компонента (оператор конкретизации компонента), т.е. имеется в виду конкретизация связей данной подсхемы. Соответствие портов при создании экземпляров компонентов может быть осуществлено • позиционным сопоставлением; • ключевым соответствием, с использованием оператора "=>". Пример ключевого соответствия портов при создании экземпляров компонентов. p1: A port map (x1 => x1, y1=>w) ; p2: B port map (x2 => w, y2=>z) ; p3: C port map (y3=>v, x3 => z) ; Сделаем пояснения. При создании экземпляра компонента A портам x1, y1 компонента A ставятся в соответствие сигналы x1, w. При создании экземпляра компонента B портам x2, y2 компонента B ставятся в соответствие сигналы w, z (рис. 2.2). При ключевом соответствии порядок перечисления портов не играет роли, поэтому при ключевом соответствии портов можно сначала указать выходной порт, как это сделано при создании экземпляра компонента C. x1 x1 A y1 w x2 B y2 z x3 C v y3 Рис. 2.2. Конкретизация (создание экземпляров) Рассмотрим 8-разрядный сдвиговый регистр (рис. 2.3), в состав которого входит восемь подсхем - D-триггеров (элементов памяти) [9]. D-триггер имеет имя DFF. 1 2 3 4 entity DFF is port ( RSTn, CLK, D : in bit; Q : out bit);
Параллельные операторы 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 85 end DFF; architecture RTL of DFF is begin process (RSTn, CLK) begin if (RSTn = '0') then Q <= '0'; elsif (CLK'event and CLK = '1') then Q <= D; end if; end process; end RTL; --------------------------------------------entity SHIFT is port ( RSTn, CLK, SI : in bit; SO : out bit); end SHIFT; architecture RTL1 of SHIFT is component DFF port ( RSTn, CLK, D : in bit; Q : out bit); end component; signal T : bit_vector(6 downto 0); begin bit7 : DFF port map (RSTn => RSTn, CLK => CLK, D => SI, Q => T(6)); bit6 : DFF port map (RSTn, CLK, T(6), T(5)); bit5 : DFF port map (RSTn, CLK, T(5), T(4)); bit4 : DFF port map (CLK => CLK, RSTn => RSTn, D => T(4), Q => T(3)); bit3 : DFF port map (RSTn, CLK, T(3), T(2)); bit2 : DFF port map (RSTn, CLK, T(2), T(1)); bit1 : DFF port map (RSTn, CLK, T(1), T(0)); bit0 : DFF
86 46 47 Глава 2. Последовательные и параллельные операторы port map (RSTn, CLK, T(0), SO); end RTL1; Схема SHIFT задает сдвиговый регистр - каскадное соединение D-триггеров (элементов памяти). D-триггер описан в строках 1-16. Сдвиговый 8-битовый региcтр специфицирован в строках 1822. Строки 24-28 декларируют компонент DFF. Строка 29 декларирует 7-битовый сигнал T, употребляемый для связи между соседними триггерами. Компонент DFF конкретизирован (упомянут) восемь раз, чтобы получить сдвиговый регистр. ! Каждый оператор создания экземпляра компонента должен иметь метку. Метки играют роль имен элементов схемы. Карта портов дается в скобках после ключевых слов port map. Назначение портов компонентов является как позиционным (см. метки bit0, bit1, bit2, bit3, bit5, bit6), так и ключевым (см. метки bit6, bit7). ! Для выходных неиспользуемых портов компонентов нужно употребить ключевое слово open. Следующий фрагмент VHDL-кода показывает, что при создании экземпляра компонента add1 на вход b1 можно подать константу 0 и выход c1 не использовать. P1: add1 port map (b1 => '0', b2 =>x, s1 => s1, c1 => open); Рассмотрим еще один пример - 7-разрядный сумматор, являющийся каскадным соединением одного полусумматора add1 и шести одноразрядных сумматоров add2. Схема данного сумматора изображена на рис. 2.4,а. entity adder_N_comp is port (a,b : in bit_vector (0 to 6); s : out bit_vector (0 to 6); c : out bit); end adder_N_comp;
Rst Clk SI D T(6) D T(5) D D T(3) D Рис. 2.3. Сдвиговый регистр T(4) T(2) D T(1) D T(0) D SО
88 Глава 2. Последовательные и параллельные операторы architecture structural of adder_N_comp is component add1 port (b1,b2: in BIT; c1,s1: out BIT); end component; component add2 port(c1, a1,a2:in BIT; c2,s2:out BIT); end component; signal c_in : bit_vector (0 to 5); s(6) ; begin p0: add1 port map (b1 => a(0), b2 => b(0), c1 => c_in(0), s1 => s(0) ); p1: add2 port map (c1 => c_in(0), a1 => a(1), a2 => b(1), c2 => c_in(1), s2 => s(1) ); p2: add2 port map (c1 => c_in(1), a1 => a(2), a2 => b(2), c2 => c_in(2), s2 => s(2) ); p3: add2 port map (c1 => c_in(2), a1 => a(3), a2 => b(3), c2 => c_in(3), s2 => s(3) ); p4: add2 port map (c1 => c_in(3), a1 => a(4), a2 => b(4), c2 => c_in(4), s2 => s(4) ); p5: add2 port map (c1 => c_in(4), a1 => a(5), a2 => b(5), c2 => c_in(5), s2 => s(5) ); p6: add2 port map (c1 => c_in(5), a1 => a(6), a2 => b(6), c2 => c, s2 => end structural;
б) a) c_in(0) s(2) c_in(1) a(1) b(1) a(2) b(2) adder_2p s(1) s(4) adder_2p adder_2p s(3) add2 s(4) c_in(2) add2 s(5) adder_2p a(5) b(5) a(6) b(6) adder_2p s(6) add2 s(6) c a(6) b(6) c_in(5) a(5) b(5) s(5) c_in(4) a(4) b(4) c_in(3) a(3) b(3) add2 s(3) a(3) b(3) a(4) b(4) c_in(2) a(2) b(2) add2 s(2) c Рис. 2.4. 7-разрядный сумматор: а - в виде каскадного соединения одноразрядного полусумматора add1 и одноразрядных сумматоров add2; б - в виде каскадного соединения одноразрядного полусумматора add1 и двухразрядных сумматоров adder_2p a(0) b(0) add1 s(0) adder_2p a(1) b(1) a(0) b(0) c_in(1) add2 c_in(0) s(1) add1 s(0)
90 Глава 2. Последовательные и параллельные операторы Примеры, приведенные для пояснения оператора создания экземпляров компонентов, понадобятся нам в дальнейшем. Схемы сдвигового регистра и сумматора являются регулярными и могут быть описаны более компактно с помощью оператора генерации, рассматриваемого далее. Параллельный оператор генерации (generate statement) Определение. generate_statement::= generate_label: for generate_parameter_specification generate if condition generate concurrent statements end generate [generate_label]; Параметр генерации (generate_parameter_specification) константа дискретного типа в определенном диапазоне. Параметром генерации не может быть декларированная переменная или сигнал. Структура регистра регулярна. Мы можем создать N экземпляров компонента DFF (D-триггера) и сделать N-битный сдвиговый регистр. Когда число N большое, значительно возрастает длина VHDL-кода. Оператор генерации представляет собой механизм для проектирования (описания) регулярных (систолических) структур. Следующий пример [9] показывает применение оператора генерации к описанию 8-битового сдвигового регистра. architecture RTL2 of SHIFT is component DFF port ( RSTn, CLK, D : in bit; Q : out bit); end component; signal T : bit_vector(6 downto 0); begin g0 : for i in 7 downto 0 generate g1 : if (i = 7) generate bit7 : DFF
Параллельные операторы T(6)); 91 port map (RSTn => RSTn, CLK => CLK, D => SI, Q => end generate; g2 : if (i > 0) and (i < 7) generate bitm : DFF port map (RSTn, CLK, T(i), T(i-1)); end generate; g3 : if (i = 0) generate bit0 : DFF port map (RSTn, CLK, T(0), SO); end generate; end generate; end RTL2; Проанализировав данное описание, можно заметить, что некоторое "неудобство", связанное с установлением связей схемы в целом с полюсами элементов, возникает при описании входного (метка bit7) и выходного триггера (метка bit0). Избежать этого неудобства можно, если увеличить размерность сигнала T . T(i)); architecture RTL3 of SHIFT is component DFF port ( RSTn, CLK, D : in bit; Q : out bit); end component; signal T : bit_vector(8 downto 0); -- декларация сигнала T begin T(8) <= SI; SO <= T(0); g0 : for i in 7 downto 0 generate allbit : DFF port map (RSTn => RSTn, CLK => CLK, D => T(i+1), Q => end generate; end RTL3; Имеются два способа употребления оператора генерации. Способ 1 - (способ for), синтаксис такой же, как у последовательного оператора for loop.
92 Глава 2. Последовательные и параллельные операторы Способ 2 - (способ if) употребление подобно по синтаксису последовательному оператору if. В архитектуре RTL2 способ if употреблен внутри способа for. Укажем различия параллельного оператора генерации от последовательных операторов for, if. 1. Оператор генерации есть параллельный оператор, а if, for loop есть последовательные операторы. 2. Оператор генерации не имеет фраз else, elsif. 3. Необходима метка для оператора генерации. 4. Только параллельные операторы могут появляться внутри оператора генерации. Только последовательные операторы могут появляться внутри последовательного for loop оператора и последовательного if оператора. Архитектура DFF может быть декларирована в пакете и употреблена в архитектурах RTL1, RTL2, RTL3. Затем эта компонента может быть удалена из этих архитектур. ! В архитектуре RTL3 параметр i не нуждается в декларации. Все три архитектуры RTL1, RTL2, RTL3 описывают то же самое поведение. В следующем примере VHDL-кода оператор generate употребляется для спецификации N-разрядного сумматора adder_N (рис.2.5). s(0) add1 s(1) c-in(0) a(0) b(0) add2 c-in(2) ... a(1) b(1) s(N-2) s(N-1) add2 add2 a(N-2) b(N-2) a(N-1) b(N-1) Рис. 2.5. N-разрядный сумматор entity adder_N is generic (N : natural := 4); port (a,b : in bit_vector (0 to N-1); s : out bit_vector (0 to N-1); c : out bit); end adder_N; c
Параллельные операторы 93 architecture functional of adder_N is component add1 port (b1,b2: in BIT; c1,s1: out BIT); end component; component add2 port(c1, a1,a2:in BIT; c2,s2:out BIT); end component; signal c_in : bit_vector (0 to N-1); begin adder: for i in 0 to N-1 generate first_bit: if (i=0) generate first_cell: add1 port map (b1 => a(0), b2 => b(0), c1 => c_in(0), s1 => s(0) ); end generate first_bit; middle_bit: if (i>0) and (i < N-1) generate middle_cell: add2 port map (c1 => c_in(i-1), a1 => a(i), a2 => b(i), c2 => c_in(i), s2 => s(i) ); end generate middle_bit; end_bit: if (i=N-1) generate end_cell: add2 port map (c1 => c_in(i-1), a1 => a(i), a2 => b(i), c2 => c, s2 => s(i) ); end generate end_bit; end generate adder; end functional; Изменяя число N в строке с ключевым словом generic, можно получать описание сумматора требуемой разрядности. В представленном ниже архитектурном теле func_1 для N-разрядного сумматора используется только подсхема одноразрядного сумматора add2, при этом на вход переноса c1 подсхемы add2 (в
94 Глава 2. Последовательные и параллельные операторы разряде с номером 0) подается нулевой сигнал, описание становится более компактным. architecture func_1 of adder_N is component add2 port(c1, a1,a2:in BIT; c2,s2:out BIT); end component; signal c_in : bit_vector (0 to N); begin c_in(0)<='0'; adder: for i in 0 to N-1 generate add2 port map (c1 => c_in(i), a1 => a(i), a2 => b(i), c2 => c_in(i+1), s2 => s(i) ); end generate adder; c <= c_in(N); end func_1; Параллельный оператор блока (block statement) Определение. block_statement::=block_label block[(guard_expression)] block_header block_declaration_part begin concurrent statements end block[block_label]; Оператор блока определяет часть проекта (часть VHDLописания цифровой системы, схемы). Напомним, что блок - это ограниченный фрагмент VHDL-кода, содержащий раздел описания и исполняемый раздел. Блоки могут быть иерархически вложены и поддерживать тем самым декомпозицию проекта. ! Метка необходима в операторе блока. В разделе деклараций блока размещаются
Параллельные операторы • • • • • • • • • • 95 декларации подпрограмм; тела подпрограмм; типы, подтипы; константы; сигналы; альтернативные точки входа в подпрограмму; декларации атрибутов; декларации констант; спецификации атрибутов; конфигурации. Параллельные операторы размещаются в теле блока. Необязательные охранные выражения будут обсуждены позднее. Оператор блока обсудим на примере 7-разрядного сумматора, составленного из одного полусумматора и трех полных двухразрядных сумматоров. Полный двухразрядный сумматор adder_2p есть каскадное соединение двух полных одноразрядных сумматоров add2. Структурное описание схемы adder_2p приведено ниже, в данном описании a1, b1 - младшие разряды двухразрядных складываемых чисел a = (a2, a1), b = (b2, b1); a2, b2 - старшие разряды; c0 - перенос из предыдущего разряда. Таким образом схема adder_2p реализует операцию сложения (c0) + (a2, a1) + (b2, b1) = (c2, s2,s1) одноразрядного числа c0 с двухразрядными числами a, b. entity adder_2p is port (a1, b1, a2,b2,c0 : in BIT; c2,s2,s1 : out BIT); end adder_2p; architecture structural of adder_2p is component add2 port(c1, a1,a2:in BIT; c2,s2:out BIT); end component; signal c1:BIT; begin circ1: add2
96 Глава 2. Последовательные и параллельные операторы port map (c1 => c0, a1 => b1,a2 =>b2,c2 =>c1,s2=>s1); circ2: add2 port map (c1 => c1, a1 => a1,a2 =>a2,c2 =>c2,s2=>s2); end structural; В приводимом ниже описании две схемы adder_2p, предназначенные для сложения разрядов 1 - 4, описываются в виде блока. Подсхемы, входящие в блок, отмечены на рис. 2.4,б штриховой линией. entity adder_N_block is port (a,b : in bit_vector (0 to 6); s : out bit_vector (0 to 6); c : out bit); end adder_N_block; architecture structural of adder_N_block is component add1 port (b1,b2: in BIT; c1,s1: out BIT); end component; component adder_2p port(a1,b1,a2,b2,c0:in BIT; c2,s2,s1:out BIT); end component; signal c_in : bit_vector (0 to 2); begin p0: add1 port map (b1 => a(0), b2 => b(0), c1 => c_in(0), s1 => s(0) ); block0:block begin stage1: adder_2p port map (c0 => c_in(0), a1 => a(1), b1 => b(1), a2 => a(2), b2 => b(2), c2 => c_in(1), s2 => s(2), s1 => s(1) ); stage2: adder_2p port map (c0 => c_in(1), a1 => a(3), b1 => b(3), a2 => a(4), b2 => b(4), c2 => c_in(2), s2 => s(4), s1 => s(3) );
97 Параллельные операторы end block; stage3: adder_2p port map (c0 => c_in(2), a1 => a(5), b1 => b(5), a2 => a(6), b2 => b(6), c2 => c, s2 => s(6), s1 => s(5) ); end structural; В данном примере отсутствуют охранные заголовок блока, раздел деклараций блока. Блоки могут быть вложены. выражения, architecture XX of SYSTEM is ----- раздел описаний внешнего блока ------begin -- выполнимые операторы внешнего блока ------A: block ----- раздел описаний внутреннего блока A ---begin -- выполнимые операторы внутреннего блока A ------end block A; B: block ----- раздел описаний внутреннего блока B ---begin -- выполнимые операторы внутреннего блока B ------end block B; end XX; В данном примере блоки A, B вложены в блок XX. Обсудим теперь охранные выражения блоков. Рассмотрим архитектурное тело add1_e одноразрядного сумматора в виде охраняемого блока.
98 Глава 2. Последовательные и параллельные операторы entity add1_e is port (b1,b2,enable : in BIT; c1,s1 : out BIT); end add1_e; architecture struct_3 of add1_e is begin p0: block (enable = '1') begin s1<= guarded (b1 xor b2); c1<= guarded (b1 and b2); end block p0; end struct_3; Охранным выражением блока является выражение enable = 1. Если это выражение принимает значение true (истина), то охраняемые конструкции (назначения сигналов) выполняются, т.е. одноразрядный сумматор складывает числа, если же значение выражения является false (ложь), то охраняемые назначения сигналов не выполняются, т.е. сумматор не складывает числа b1, b2. Охрана назначения сигналов осуществляется указанием ключевого слова guarded. В качестве другого примера охраняемого блока приведем пример [1] описания D-триггера с асинхронным сбросом в виде блока с охранным выражением (clk = '1' or clr = '1'). D_LATCH : block (clk = '1' or clr = '1') begin Q <= guarded '0' when clr = '1'; else D when clk = '1'; else Q; end block D_LATCH; В данном примере clk - вход синхронизации, clr - асинхронный сброс, D - вход данных, Q - выход триггера. Когда охранное выражение имеет значение ложь, то сигнал Q в левой части сохраняет свое прежнее значение. Легко видеть, что сигнал асинхронного сброса имеет приоритет по отношению к сигналу clk.
99 Упражнения Упражнения УПРАЖНЕНИЯ 1. Перечислите последовательные операторы языка VHDL . 2. Какой порядок выполнения последовательных операторов? 3. Правильно ли утверждение: "Булево условие в цикле типа while проверяется в начале каждой итерации"? 4. Правильно ли утверждение: "Счетчик в цикле типа for есть переменная, которую нужно декларировать в начале процесса, в котором цикл употребляется"? 5. Какой будет дельта-задержка после выполнения операторов в случаях a) X:=A+B+C+D; b) Y:=A+B+C; c) Z:=A+B; d) W:=A; 6. Где в VHDL-коде может быть декларирована локальная переменная? 7. Где в VHDL-коде может быть декларирован сигнал? 8. Перечислите различия между локальными переменными и сигналами в языке VHDL . 9. Какие из последовательных операторов могут быть помечены? Являются ли метки обязательными? 10. Может ли процесс иметь список сигналов запуска и оператор wait внутри оператора процесса? 11. Может ли процесс иметь - несколько списков сигналов запуска; - несколько операторов wait внутри оператора процесса; - несколько списков сигналов запуска и несколько операторов wait внутри оператора процесса. 12. Правильно ли, что знак оператора назначения сигнала может быть ориентирован как в левую сторону (<=), так и в правую сторону (=>) по желанию проектировщика, пользующегося языком VHDL? 13. Объясните, как Вы понимаете запись на языке VHDL x <= y <= z Является ли она корректной? Почему? 14. Какая часть VHDL-кода содержит последовательные операторы. Выберите правильный ответ:
100 Глава 2. Последовательные и параллельные операторы a) процесс (перед ключевым словом begin); b) архитектурное тело; c) процесс (после ключевого слова begin); d) пакет. 15. Пусть имеется фрагмент VHDL-кода. signal a_bus : bit_vector( 3 downto 0); signal z_bus : bit_vector( 3 downto 0); signal a_bit, b_bit, c_bit, d_bit : bit; 1) BYTE <= (OTHERS => '1'); 2) z_bus <= a_bit & b_bit; 3) a_bus <= ('1', b_bit, '0', d_bit); 4) a_bus (0 to 1) <= (OTHERS => '0'); Какие строки корректны. Выберите правильный ответ. Обоснуйте ответ. a) только 2 и 4; b) только 3 и 4; c) только 1 и 2; d) только 1 и 3. 16. Пусть имеется фрагмент VHDL-кода. Type my_state is (RESET, IDLE, RW_CYCLE, INT_CYCLE); signal STATE : my_state; signal TWO_BIT : bit_vector (0 to 1); 1) STATE <= RESET; 2) STATE <= ''00''; 3) STATE <= TWO_BIT; Какие строки корректны. 17. В какой части VHDL-кода можно употреблять операторы if, case, for ... loop. Выберите правильный ответ: a) architecture; b) entity; c) package; d) process. 18. В данном фрагменте VHDL-кода осуществляется инициализация массива z_bus четырьмя способами: Signal z_bus : bit_vector (3 downto 0);
101 Упражнения a) z_bus <= ''0000'' ; b) z_bus <= (1 => '0' , others => '0' ); c) z_bus <= (others => '0' ); d) z_bus <= ('0' ,'0','0', '0' ); Укажите способ, который наиболее просто осуществляет инициализацию массива независимо от его длины. 19. Что такое транспортная и инерционная задержка сигнала? Какой тип задержки (транспортная, инерционная) принят по умолчанию в языке VHDL? 20. В каком случае модель инерционной задержки сигнала и модель транспортной задержки сигнала дают тот же результат? 21. Перечислите параллельные операторы языка VHDL. 22. Какая часть VHDL-кода содержит параллельные операторы назначения сигнала. Выберите правильный ответ: a) entity; b) process; c) package; d) architecture. 23. Какой параллельный оператор требуется внутри параллельных операторов? 24. В следующем VHDL-коде [9] имеются четыре параллельных вызова процедуры. 4), entity PROCALL_EX is end PROCALL_EX; architecture RTL of PROCALL_EX is procedure ANDOR ( signal A, B, C, D : in bit_vector(1 downto 0); signal Y : out bit_vector(1 downto 0)) is begin Y <= (A and B) or (C and D); end ANDOR; signal DIN, DOUT : bit_vector(7 downto 0); signal X, Y, Z : bit_vector(1 downto 0); begin call0 : ANDOR (A => DIN(7) & DIN(6), B => DIN(5 downto C => DIN(3 downto 2), D => DIN(1 downto 0), Y => DOUT(1 downto 0));
102 4), Глава 2. Последовательные и параллельные операторы call1 : ANDOR (A => DIN(7 downto 6), B => DIN(5 downto C => DIN(3 downto 2), D => DIN(1 downto 0), Y => DOUT(3 downto 2)); call2 : ANDOR (A => DIN(7 downto 6) and DIN(5 downto 4), B => DIN(5 downto 4), C => DIN(3 downto 2), D => DIN(1 downto 0), Y => DOUT(5 downto 4)); call3 : ANDOR (A => X nand Y, B => Z, C => DIN(3 downto 2), D => DIN(1 downto 0), Y => DOUT(7 downto 6)); end RTL; Является ли каждый вызов корректным или нет, почему? 25. Может ли локальная переменная употребляться как фактический параметр оператора параллельного вызова процедуры? Составьте соответствующий VHDL-код, проверьте его с помощью VHDL-анализатора. 26. Каким параллельным операторам требуются метки? 27. Для каких параллельных операторов метки необязательны? 28. Что такое компонент в языке VHDL? Чему соответствует компонент в логической схеме? Какие средства языка VHDL употребляются для соединения компонент? 29. Могут ли декларироваться компоненты внутри раздела декларации процесса? 30. Требуется ли декларировать сигналы внутри процесса? 31. Допустимо ли декларировать любые объекты внутри процесса? 32. Правильно ли, что все операторы внутри процесса выполняются один за другим? 33. Правильно ли, что все процессы внутри архитектурного тела выполняются один за другим? 34. Должен ли каждый процесс иметь имя (метку)? Рекомендуется ли именовать процессы? Если "да", то почему? 35. Правильно ли, что имя процесса специфицируется после ключевого слова process? 36. Правильно ли, что как сигналы, так и переменные могут употребляться для хранения временных данных внутри процесса?
103 Упражнения 37. Перепишите следующий VHDL-код оператор выборочного назначения сигнала. [9], используя entity IFCASE is port ( HEX : in bit_vector(3 downto 0); LED : out bit_vector(6 downto 0)); end IFCASE; architecture RTL of IFCASE is begin p0 : process (HEX) begin case HEX is when "0000" => LED <= "1111110"; when "0001" => LED <= "1100000"; when "0010" => LED <= "1011011"; when "0011" => LED <= "1110011"; when "0100" => LED <= "1100101"; when "0101" => LED <= "0110111"; when "0110" => LED <= "0111111"; when "0111" => LED <= "1100010"; when "1000" => LED <= "1111111"; when "1001" => LED <= "1110111"; when "1010" => LED <= "0111001"; when "1011" => LED <= "0111101"; when "1100" => LED <= "0011001"; when "1101" => LED <= "1111001"; when "1110" => LED <= "1011111"; when others => LED <= "0001111"; end case; end process; end RTL; Проведите моделирование, сравните результаты. 38. Правильно ли, что оператор выборочного назначения сигнала и оператор условного назначения сигнала представляют то же действие, только записанное по-разному? 39. Правильно ли утверждение "Условное назначение сигнала может употребляться как в архитектурном теле (как параллельный оператор), так и в процессе (как последовательный оператор)"?
104 Глава 2. Последовательные и параллельные операторы 40. Для чего служит оператор generate? Структуру каких схем удобно описывать с его помощью? 41. Допустимо ли при конкретизации компонентов использовать оба направления (=>, <=) в зависимости от того, является порт входным либо выходным? 42. Разработайте логическую схему и, употребляя оператор generate, запишите VHDL-код структурного описания мультиплексора с двумя, тремя, четырьмя и n управляющими входами. 43. Разработайте функциональное описание схемы для перемножения двух матриц A, B размерностью 4×4, элементами которых являются целые числа. Используйте двухразмерные массивы для входных и выходных данных. Примените операторы generic, generate, запишите VHDL-код для общего случая, когда матрицы имеют размерность N×N. Разработайте структурные описания для случаев N=2, N=3, используя умножители и сумматоры и полагая, что элементами aij, bij матриц A,B являются целые числа, не большие числа 3. Примените битовое представление входных и выходных данных. Приведите моделирование, убедитесь в корректности VHDL-кода. Введите соответствующие типы данных и разработайте поведенческое VHDL-описание схемы для умножения матрицы A на вектор c. Разработайте структурное описание, используя битовое представление входных данных для случая, когда элементы матрицы A и компоненты вектора c являются целыми числами, не большими 7, а матрица A имеет размерность N× N, вектор с имеет размерность N, N=2,3,4. Используйте функции преобразования типов integer, bit_vector.
105 Упражнения 44. На рис. 2.6 изображена схема 4-разрядного умножителя. Введите имена сигналам, соединяющим элементы схемы: одноразрядные полусумматоры add1, одноразрядные сумматоры add2, двухвходовые конъюнкторы. t7 t6 t5 t4 t3 add2 add2 add2 add1 & & s3 & s2 add2 & s1 add2 & s0 add2 & s3 add1 add1 & s2 & s1 add2 & s0 add2 & s3 r3 t2 add1 & s2 r2 t1 & s1 r1 s0 t0 & & s3 & s2 & s1 s0 r0 Рис. 2.6. Четырехразрядный умножитель Опишите схему, используя операторы создания экземпляров компонентов. Составьте более компактное описание, используя другие операторы языка VHDL. Проведите моделирование, сравните результаты. Введите задержки элементам: add1 - 10ns, add2 -15 ns, элементам И - 5 ns. Проведите моделирование. Определите задержку схемы..
106 Глава 2. Последовательные и параллельные операторы 45. На рис. 2.7 дана схема D-триггера. Введите задержки элементам и составьте структурное описание. Модифицируйте функциональное описание, введя задержку в оператор назначения сигнала, проведите моделирование в обоих случаях. Сравните результаты. T D C Q Q a) D & DD1 C A & Y1 DD3 & & DD2 DD4 Y2 Q Q б) Рис. 2.7. D-триггер (защелка): a - условное обозначение; б - схема D-триггера на элементах И-НЕ 46. Опишите функционирование RS-триггера использованием конструкции "охраняемый блок". с
Подпрограммы 107 Глава 3 Организация проекта Г л а в а 3 . Организация проекта 3.1. Подпрограммы Подпрограммы Декларация подпрограммы Определение. subprogram_declaration::= procedure identifier [(formal_parameter_list)]| function designator [(formal_parameter_list)] return type_mark; Подпрограммы имеют две формы - функции и процедуры. Вызов процедуры есть оператор, в то время как вызов функции возвращает значение в выражении. Указателем функции (операторным символом) может быть идентификатор или строковый литерал. Заметим, что строковый литерал не может быть именем процедуры. Список формальных параметров (formal_parameter_list) - список интерфейса (interface_list), который состоит из одной или более деклараций интерфейса (interface_declaration). interface_list ::= interface_declaration {; interface_declaration} interface_declaration ::= interface_constant_declaration | interface_signal_declaration | interface_variable_declaration interface_constant_declaration ::= [ constant ] identifier_list : [ in ] subtype_indication [:=static_expression ]
108 Глава 3. Организация проекта interface_signal_declaration ::= [signal] identifier_list : [ mode ] subtype_indication [ bus ] [ :=static_expression ] interface_variable_declaration ::= [variable] identifier_list : [ mode ] subtype_indication [ := static_expression ] mode ::= in | out | inout | buffer | linkage Подпрограммы могут быть декларированы в пакете, интерфейсе объекта (entity), архитектурном теле (architecture), процессе, процедуре или функции. Тело подпрограммы Определение. subprogram_body::= subprogram_declarations is subprogram_declarative_part begin sequential statements end [procedure identifier or function designator]; Примеры подпрограмм уже приводились и будут даны далее. 3.2. Функции Функции Функция имеет только входные параметры. Следующий пример показывает функцию BOOL_TO_SL, преобразующую тип BOOLEAN в тип STD_ULOGIC. Пример. function BOOL_TO_SL(X : boolean) return std_ulogic is begin if X then return '1'; else return '0'; end if; end BOOL_TO_SL;
Процедуры 109 Функция может содержать последовательные операторы, исключая операторы ожидания и назначения сигналов. В теле функции могут декларироваться локальные переменные. Например, в теле функции PARITY декларируется локальная переменная TMP. Пример. function PARITY (X : std_ulogic_vector) return std_ulogic is variable TMP : std_ulogic := '0'; begin for J in X'range loop TMP := TMP xor X(J); end loop; return TMP; end PARITY; теле. Пример использования функции PARITY в архитектурном architecture FUNCTIONS of PAR is begin -- вызов функции PARITY_BYTE <= PARITY(DATA_BYTE); PARITY_WORD <= PARITY(DATA_WORD); end FUNCTIONS; 3.3. Процедуры Процедуры Процедура может иметь входные (in), выходные (out) и вход/выходные (inout) параметры. Это могут быть сигналы, переменные или константы. По умолчанию входные параметры константы, выходные и вход/выходные - переменные. Процедуры могут вызываться последовательно или параллельно. При параллельном вызове происходит выполнение процедуры, когда какой-нибудь входной вход/выходной параметр изменился. Следующий пример процедуры PARITY показывает отличия процедуры от функции: функция имеет только входные параметры, режим (mode) которых не специфицируется, в процедуре могут содержаться операторы назначения сигналов. Пример.
110 Глава 3. Организация проекта procedure PARITY (signal X : in std_ulogic_vector; signal Y : out std_ulogic) is variable TMP : std_ulogic := '0'; begin for J in X'range loop TMP := TMP xor X(J); end loop; Y <= TMP; -- в процедуре могут быть операторы -- назначения сигналов end PARITY; Следующий пример показывает процедуру DISPLAY_MUX и ее вызов в архитектурном теле SUBPROG. procedure DISPLAY_MUX (ALARM_TIME, CURRENT_TIME : in digit; SHOW_A : in std_ulogic; signal DISPLAY_TIME : out digit) is begin if (SHOW_A = '1') then DISPLAY_TIME <= ALARM_TIME; else DISPLAY_TIME <= CURRENT_TIME; end if; end DISPLAY_MUX; architecture SUBPROG of DISP_MUX is ... begin -- вызов процедуры DISPLAY_MUX (ALARM_TIME, CURRENT_TIME, SHOW_A, DISPLAY_TIME); end SUBPROG; Если подпрограмма определена в подпрограммы должен быть в теле пакета. пакете, то текст 3.4. Разрешающие функции. Пакет std_logic_1164 Разрешающие функции. Пакет std_logic_1164 Когда сигнал имеет один драйвер (иногда драйвер называют контейнером), то значение сигнала легко определить, потому что,
Разрешающие функции. Пакет std_logic_1164 111 когда процесс приостанавливается, значение сигнала из драйвера передается сигналу. Однако во многих практических ситуациях один и тот же сигнал может назначаться в различных (нескольких) процессах. Например, шина данных в персональном компьютере может получать данные из процессора, памяти (ОЗУ), жесткого диска и других устройств. Сигнал от многих источников называется в языке VHDL разрешаемым (resolved), т.е. требующим решения проблемы разрешения - определения значения результирующего сигнала по значениям сигналов из различных источников. Сигнал, не требующий решения проблемы разрешения, называется неразрешаемым (unresolved) - это сигнал из одного источника. Функция разрешения - это функция определения значения сигнала по его значениям из различных источников. Далее будем рассматривать два источника и для этого случая изучать функции разрешения в электронных схемах. Для моделирования процессов прохождения сигналов в реальных электронных схемах используется многозначная логика. Тип bit обобщается на случай девяти значений сигнала 'U' 'X' '0' '1' 'Z' 'W' 'L' 'H' '-' ---------- не инициализировано; неизвестное значение (сильный источник сигнала); логический 0 (сильный источник сигнала); логическая 1 (сильный источник сигнала); высокий импеданс (цепь не подключена к источнику); неизвестное значение (слабый источник сигнала); логический 0 (слабый источник сигнала); логическая 1 (слабый источник сигнала); неопределенное значение (don't care). На практике чаще всего используется шестизначный алфавит {U, X, 0,1,Z,-}. Заметим, что неизвестное значение 'X' не эквивалентно неопределенному значению '-'. Неопределенное значение эффективно используется при логическом синтезе схемы и логической оптимизации. Читатель, знакомый, например, с методами минимизации не полностью определенных булевых функций, может вспомнить о том, что некоторые неопределенные значения '-' функции заменяются при минимизации определенными (0,1) с целью получения лучшего результата. Расширение типа bit на случай девяти значений сигнала привело к понятию типа std_logic.
112 Глава 3. Организация проекта Основное назначение типа std_logic - это дать "легальную" возможность разработчику делать многократные присваивания одному и тому же сигналу. Пример. Signal FlagC : std_logic := 'Z'; ALU: process begin if Carry then FlagC <= '1'; end if; end process ALU; COMM: process begin FlagC <= '0'; end process COMM; В данном примере для сигнала FlagC требуется разрешающая функция, так как операторы назначения данного сигнала имеются в двух процессах (рис. 3.1). Тип std_logic будем называть разрешаемым. Тип std_logic является подтипом типа std_ulogic. Тип std_ulogic является не разрешаемым перечислимым типом с множеством значений {'U', 'X', '0','1','Z','W', 'L','H','-'}. Для сигналов этого типа запрещено использовать много источников сигнала, поэтому нет необходимости указывать разрешающую функцию. Буква u в названии типа std_ulogic сигнализирует о термине (unresolved). Итак, типы std_logic, std_ulogic - это перечислимые типы. Их определение содержится в пакете std_logic_1164 (см. приложение 4).
113 Разрешающие функции. Пакет std_logic_1164 process ALU FlagC<='1'; process Comm FlagC<='0'; Драйвер сигнала FlagС Функция разрешения F Сигнал FlagC Драйвер сигнала FlagС Рис. 3.1. Функция разрешения F для сигналов с многими драйверами В пакете std_logic_1164 содержатся определения типов, подтипов, функций на случай многозначной логики: • тип std_ulogic - неразрешаемый логический тип с девятизначным алфавитом; • тип std_logic_vector; • подтип std_logic типа std_ulogic; • "перегружаемые" логические функции and, nand, or, xor, not для операндов std_ulogic и др. Заметим, что для преобразования типа bit в тип std_logic (и наоборот) требуются соответствующие функции. Табл. 3.1, по существу, есть табличное задание разрешающей функции F для сигнала из двух источников. Рис. 3.2 иллюстрирует смысл таблицы, т.е. получение значения сигнала с помощью функции разрешения F. Фактически типы std_logic, std_ulogic стали промышленным стандартом и доступны во всех системах моделирования с языком VHDL, поставляющихся вместе с пакетом std_logic_1164. Чтобы использовать пакет std_logic_1164, необходимо указать следующее: Library IEEE; use IEEE. std_logic_1164.all; Опишем схему (рис.3.3), используя для сигналов тип std_logic.
114 Глава 3. Организация проекта Чтобы описать являющийся а) б) в) монтажное X 'U' 'X' 'X' 'X' 'X' 'X' 'X' 'X' 'X' 0 'U' 'X' '0' 'X' '0' '0' '0' '0' 'X' Драйвер 1 a) введем тип resolved_bit, Таблица 3.1 U 'U' 'U' 'U' 'U' 'U' 'U' 'U' 'U' 'U' U X 0 1 Z W L H - ИЛИ, 1 'U' 'X' 'X' '1' '1' '1' '1' '1' 'X' Z 'U' 'X' '0' '1' 'Z' 'W' 'L' 'H' 'X' W 'U' 'X' '0' '1' 'W' 'W' 'W' 'W' 'X' L 'U' 'X' '0' '1' 'L' 'W' 'L' 'W' 'X' 'U' (столбец) (столбец) F Драйвер 2 H 'U' 'X' '0' '1' 'H' 'W' 'W' 'H' 'X' 'U' 'X' 'X' 'X' 'X' 'X' 'X' 'X' 'X' 'U' '1' (строка) Драйвер 1 'Z' 'U' (столбец) (столбец) F б) Драйвер 2 'W' 'W' (строка) Драйвер 1 в) 'L' 'U' (столбец) (столбец) F Драйвер 2 'W' 'H' (строка) Рис. 3.2. Иллюстрация табличного задания функции разрешения F для сигналов типа std_logic с двумя драйверами
115 Разрешающие функции. Пакет std_logic_1164 подтипом типа std_logic, и определим в пакете wire, находящемся в рабочей библиотеке work, разрешающую функцию res_func для сигнала типа resolved_bit. Разрешающая функция определяет значение сигнала по значениям сигналов из нескольких источников. В данном примере разрешающая функция назначит сигналу out_wire значение '1', если хотя бы один из выходных сигналов логических элементов И первого уровня схемы (рис. 3.3) будет иметь значение '1', в противном случае сигнал out_wire примет значение '0'. В VHDL-коде используются следующие имена: схема, изображенная на рис. 3.3, имеет имя circuit_wire, двухвходовый элемент И - имя cc. x1 & x2 x3 & x4 x5 out_wire & x2 & x6 Рис. 3.3. Схема circuit_wire library IEEE; use IEEE.std_logic_1164.all; library work; use work.wire.all; entity circuit_wire is port (x1,x2,x3,x4,x5,x6 : in std_logic; out_circ : out std_logic); end circuit_wire; out_circ
116 Глава 3. Организация проекта architecture structure of circuit_wire is component cc port (x1,x2 : in std_logic; y : out std_logic); end component; signal out_wire : resolved_bit; begin p1: cc port map (x1 => x1, x2 => x2, y => out_wire); p2: cc port map (x1 => x3, x2 => x4, y => out_wire ); p3: cc port map (x1 => x5, x2 => x6, y => out_wire ); p4: cc port map (x1 => out_wire, x2 => x2, y => out_circ); end structure; library IEEE; use IEEE.std_logic_1164.all; entity cc is -- описание логического элемента И port (x1,x2: in std_logic; y: out std_logic); end cc; architecture functional of cc is begin y <= x1 and x2; end functional; Ниже приведен пакет wire и тело (body) этого пакета. library IEEE; use IEEE.std_logic_1164.all; package wire is function RES_FUNC(DATA: in std_logic_vector) return std_logic; subtype RESOLVED_BIT is RES_FUNC std_logic; end; package body wire is -- описание разрешающей функции function RES_FUNC(DATA: in std_logic_vector) return std_logic is begin for I in DATA'range loop
Архитектура 117 if DATA(I) = '1' then return '1'; end if; end loop; return '0'; end; end; В тексте функции RES_FUNC используется атрибут DATA'range - диапазон сигнала DATA. Аналогичным образом можно ввести разрешающую функцию для монтажного И. 3.5. Архитектура Архитектура Ранее в общем виде была представлена архитектура объекта проекта и интерфейс объекта проекта. Приведем определение архитектуры. Определение. architecture_body::=architecture identifier of entity_name is architecture_declaration_part begin [concurrent statements] end [architecture_simple_name] В разделе деклараций архитектуры могут быть • декларации подпрограмм; • тела подпрограмм; • спецификации конфигурации; • декларации типов, подтипов, констант, сигналов, файлов, альтернативных точек входа, компонентов и др. ! В разделе деклараций архитектуры не могут быть декларированы локальные переменные. ! Только параллельные операторы размещаются в теле архитектуры между ключевыми словами begin, end. Последовательные операторы могут быть внутри оператора процесса или подпрограммы. Допустимо, чтобы параллельных операторов не было внутри архитектурного тела.
118 Глава 3. Организация проекта 3.6. Декларация интерфейса объекта Декларация интерфейса объекта Определение. entity_declaration::= entity identifier is [generic (generic_list);] [port (port_list);] entity_declaration port [begin entity_statement_port] end [entity_simple_name]; Необязательный раздел операторов entity может иметь только параллельные вызовы процедур, параллельные операторы сообщения, операторы процесса. Все они должны быть пассивными, так чтобы не было присваивания значений сигналам. Список портов (port_list) и список настройки (generic_list) такие же, как и в подпрограммах. Если специфицировать объект другого класса, а не сигнал после ключевого слова port, то это является ошибкой. Ошибкой будет также, если специфицировать не константу после ключевого слова generic. В entity ключевое слово port является необязательным. Список после ключевого слова generic (общий, настраиваемый) есть хороший способ проведения (передачи) параметров в интерфейс объекта проекта, таких как параметры временной задержки, ширина шины (число проводников) и т.д. Употребляя настройку (слово generic), можно специфицировать регулярную структуру переменной длины. Приведем пример [9] entity для сдвигового регистра переменной длины N, определив сперва модификацию D-триггера c предустановкой (очисткой). library IEEE; use IEEE.std_logic_1164.all; entity DFF is -- D-триггер generic ( PRESET_CLRn : in integer); port ( RSTn, CLK, D : in std_logic;
Декларация интерфейса объекта 119 Q : out std_logic); end DFF; architecture RTL of DFF is begin process (RSTn, CLK) begin if (RSTn = '0') then if (PRESET_CLRn = 0) then Q <= '0'; else Q <= '1'; end if; elsif (CLK'event and CLK = '1') then Q <= D; end if; end process; end RTL; Тогда архитектурное тело сдвигового регистра переменной длины N будет иметь вид library IEEE; use IEEE.std_logic_1164.all; entity SHIFTN is -- сдвиговый регистр длины N generic ( PRESET_CLRn : in integer; N : in integer); port ( RSTn, CLK, SI : in std_logic; SO : out std_logic); signal T : std_logic_vector(N downto 0); begin assert (N > 3) and (N < 33) report "N outside of range 3 to 32"; end SHIFTN; architecture RTL1 of SHIFTN is component DFF generic ( PRESET_CLRn : in integer); port ( RSTn, CLK, D : in std_logic;
120 T(i)); Глава 3. Организация проекта Q : out std_logic); end component; begin T(N) <= SI; SO <= T(0); g0 : for i in N-1 downto 0 generate allbit : DFF generic map (PRESET_CLRn => PRESET_CLRn) port map (RSTn => RSTn, CLK => CLK, D => T(i+1), Q => end generate; end RTL1; Обращаем внимание на то, что спецификация компонента DFF в архитектурном теле RTL1 совпадает с его определением в entity DFF. 3.7. Карта портов и карта настройки Карта портов и карта настройки Соединение VHDL-описаний осуществляется с помощью карт (map). Для иерархического проекта порты низкоуровневых компонент (уровня i-1) могут быть отображены в порты высокоуровневого объекта (уровня i) сигналами с учетом следующих ограничений. Сигнал порта, имеющий режим (mode) in, может быть соединен с портом, имеющим режим in, inout, buffer (рис. 3.4). На рис. 3.4 изображены только некоторые возможные соединения портов компонента с портами той подсхемы, в которую компонент входит. Сигнал порта режима out может быть соединен с портом, имеющим режим out или inout, buffer. Сигнал порта режима inout, buffer может быть отображен (соединен) с портом, имеющим режим вида inout, buffer соответственно. Сигнал порта режима linkage может быть соединен с сигналом порта любого режима. С точки зрения проектирования аппаратуры вид связи linkage не является естественным, данный тип связи более подходит для алгоритмических описаний.
121 Конфигурация out запрещен in in разрешен in Компонент (уровень i-1) out out разрешен разрешен out inout Объект проекта уровня i Рис. 3.4. Связи портов компонента с портами объектаinout употребляется чаще всего для двунаправленных Режим контактов, которые находятся снаружи кристалла СБИС. Для внутренних сигналов режим не указывается. 3.8. Конфигурация Конфигурация Один и тот же объект проекта (entity) может иметь много архитектурных тел. Как при моделировании выбрать то или другое архитектурное тело? Формальное определение (синтаксис) понятия конфигурации довольно сложное. Начнем с простейших случаев Пусть мы определили компоненту goose. entity goose is port (a, b: in bit; c : out bit); end goose; architecture struct_1 of goose is begin c <= a xor b; end struct_1;
122 Глава 3. Организация проекта Мы можем употребить данную компоненту стандартным образом, употребляя имя goose. entity flock is port (a, b: bit; c: out bit); end flock; architecture three_geese of flock is signal w, r: bit; component goose -- декларация компонента port (a, b: bit; c: out bit); end component; begin one: goose port map (a, b, w); -создание экземпляра компонента two: goose port map (a, w, r); three: goose port map (a, r, c); end three_geese; Архитектурное тело содержит три экземпляра компонента goose. По умолчанию предполагается, что это тот же самый компонент goose, который был определен ранее и который содержится в рабочей библиотеке (Work - имя рабочей библиотеки). Пусть у нас имеется другое архитектурное тело для компонента goose. architecture struct_2 of goose is begin c <= ((a and (not b)) or ((not a) and b)) ; end struct_2; Мы можем не действовать "по умолчанию", а "явно" определить употребление того или другого архитектурного тела для конкретного компонента на основе конфигурации. configuration bird of flock is -- bird - имя конфигурации for three_geese for one: goose use entity work.goose(struct_2); end for; for two: goose
Конфигурация 123 use entity work.goose(struct_1); end for; for three: goose use entity work.goose(struct_1); end for; end for; end bird; Мы указали, что для компонента goose, имеющего имя (метку) one, необходимо использовать (use) из рабочей библиотеки архитектурное тело struct_2, аналогично - для компонентов с метками two, three необходимо использовать архитектурное тело struct_1. Рассмотрим немного более сложный пример конфигурации на примере схемы vlsi_1 (см. рис. 1.2). Представим, что в схемах сумматора adder_2 и умножителя mult_2 мы хотим использовать различные архитектурные тела для одноразрядного полусумматора add1. Итак, в умножителе будем использовать для подсхемы add1 архитектурное тело struct_2, а в сумматоре - архитектурное тело struct_1. Архитектурное тело struct_2 отличается от архитектурного тела struct_1 только назначением сигнала: вместо s1<=((b1 and (not b2)) or (not b1) and b2)); можно использовать s1<= (b1 xor b2); Конфигурация example выглядит следующим образом: configuration example of vlsi_1 is for struct_1 -- имя архитектурного тела схемы vlsi_1 for circ2: mult_2 use entity work.mult_2(structure); for structure for all: add1 use entity work.add1(struct_2); end for; end for;
124 Глава 3. Организация проекта end for; for circ3: adder_2 use entity work.adder_2(structure); for structure for all: add1 use entity work.add1(struct_1); end for; for all: add2 use entity work.add2(struct_1); -- вместо struct_1 end for; -- можно указать end for; -- другую архитектуру end for; end for; end example; В данной конфигурации предполагается, что подсхемы сумматора и умножителя находятся в рабочей библиотеке work. Использование библиотек в языке VHDL рассматривается в следующем разделе. При записи конфигурации могут быть использованы другие конфигурации для подсхем, входящих в схему, таким образом описание конфигурации может быть организовано иерархически, наподобие иерархической организации описания проектируемой цифровой системы. Большое число примеров конфигураций для сдвигового регистра можно найти в [9]. 3.9. Блоки проекта и VHDL-библиотеки Блоки проекта и VHDL-библиотеки Файл проекта может содержать один или более блоков проекта. Имеются первичные и вторичные блоки проекта. Первичные блоки проекта: • декларация объекта в целом (интерфейса entity); • декларация конфигурации; • декларация пакета. Первичный блок может быть связан с многими вторичными блоками проекта, которые включают: • архитектурное тело; • тело пакета.
125 Блоки проекта и VHDL-библиотеки ! Каждый первичный блок в данной библиотеке должен иметь уникальное простое имя. Каждое архитектурное тело, связанное с entity, должно быть уникальным. Блоки проекта (первичные и вторичные) размещаются в библиотеках (рис.3.5). Рабочая библиотека может быть только одна. Библиотека ресурсов VHDL-код (файлы) ... VHDL-анализатор Библиотека ресурсов Рабочая библиотека В рабочей библиотеке размещаются файлы (блоки), анализируемые VHDL-анализатором. Рис. 3.5. VHDL-библиотеки и VHDLВ библиотеках анализатор ресурсов размещаются блоки, на которые ссылаются анализируемые блоки. Ресурсной библиотеки может не быть во время анализа. Ссылка на библиотеку осуществляется указанием ключевого слова library. Например, ссылка на библиотеку STD, содержащую пакет STANDARD, и на библиотеку WORK, содержащую пакет FXP, осуществляется следующим образом: library STD, WORK; use STD.STANDARD.all use WORK.FXP.all VHDL-анализатор читает файлы исходного VHDL-кода, читает ссылки на ресурсные библиотеки и генерирует базу данных моделирования в рабочей библиотеке. Область видимости библиотеки - от начальной ссылки до конца декларативной области, связанной с блоком проекта, где ссылка появилась.
126 Глава 3. Организация проекта Видимость сигналов: сигнал, декларированный в пакете, является видимым во всех объектах проекта, которые употребляют ссылку (use) на данный пакет. Сигнал, декларированный в entity как порт, является видимым во всех архитектурных телах, связанных с данным entity. Сигнал, декларированный в разделе деклараций архитектурного тела, видим только внутри данного архитектурного тела. Упражнения УПРАЖНЕНИЯ 1. В какой части VHDL-кода должны быть декларированы локальные сигналы архитектурного тела? Выберите правильный ответ: a) в списке портов архитектурного тела; b) в конфигурации; c) в архитектурном теле после ключевого слова begin; d) в архитектурном теле перед ключевым словом begin. 2. Как должны быть подобны компонент (component) и соответствующий интерфейс (entity)? Выберите правильный ответ: a) entity и component должны иметь одно и то же имя, но порты могут различаться; b) имена entity и component могут различаться, но имена портов должны быть одинаковы; c) entity и component должны иметь одинаковые имена и должны иметь одинаковые имена портов. 3. Правильно ли, что компоненты, декларируемые в архитектурном теле, должны специфицироваться полностью, т.е. вместе с их интерфейсом и выполняемыми функциями? 4. Как много архитектурных тел может быть связано с одним entity? Выберите правильный ответ: a) одно или более; b) более одного; c) только одно; d) ни одного. 5. Правильно ли утверждение: "Каждый порт должен быть специфицирован с его режимом (mode)"? 6. Правильно ли утверждение: "Режим порта специфицирует направление потока данных через порт"? 7. Являются ли порты сигналами?
127 Упражнения 8. Правильно ли утверждение: "Описание каждого порта с комментарием в конце строки является необходимым согласно стандарту языка VHDL"? 9. Разрешается ли специфицировать начальное значение порта? 10. Может ли настраиваемый параметр (generic) динамически изменяться во время моделирования? 11. Правильно ли утверждение: "Все процессы в архитектурном теле являются активными, когда архитектура активна "? 12. Могут ли употребляться переменные для передачи информации между процессами? 13. Напишите VHDL-код для схемы 4-разрядного сумматора, представляющей каскадное соединение одноразрядных сумматоров. Напишите VHDL-код для одноразрядного сумматора add2 в виде а) логической схемы элементов И, ИЛИ, НЕ; б) логических функций. Запишите различные конфигурации, используя различные архитектурные тела для одноразрядных сумматоров add1, add2. 14. Рассмотрите предыдущую задачу для случая 4-разрядного умножителя (см. рис. 2.6). Запишите различные конфигурации. 15. Разработайте логическую схему для вычисления функции f = ( p + q) + w × d , где p = ( p2 , p1 ) , q = (q 2 , q1 ) , w = ( w 2 , w1 ) , d = ( d2 , d1 ) - двухразрядные числа. Опишите ее на языке VHDL. Запишите различные конфигурации, употребляя различные архитектурные тела для сумматоров и умножителя. 16. Что из перечисленного ниже не является блоком проекта. Выберите правильный ответ: a) architecture; b) entity; c) process; d) package.
128 Глава 4. Примеры проектирования на VHDL Глава 4 Примеры проектирования на VHDL Г л а в а 4 . Примеры проектирования на VHDL 4.1. Стили описания поведения Стили описания поведения Рассмотрим различные стили описания одного и того же поведения на примере дешифратора DC(2), который имеет два входных полюса и четыре выходных ( рис. 4.1) . x(0) y(0) y(1) y(2) y(3) DС x(1) Рис. 4.1. Дешифратор На рис. 4.1 слева и справа указаны имена входных и выходных полюсов, употребляемых в VHDL-описании. Функции дешифратора имеют следующий вид: y0=x0 ∧ y1=x0 ∧ y2= x0 ∧ y3= x0 ∧ x1; x1; x1; x1; Интерфейс дешифратора entity Decoder is port (X: in Bit_vector (0 to 1); Y: in Bit_vector (0 to 3)); end Decoder;
Стили описания поведения 129 Представим различные стили описания функционирования дешифратора: "чисто" структурное описание, описание в виде потока данных, процедурное описание. Заметим, что при спецификации цифровых систем допустим смешанный стиль, что весьма удобно при проектировании. Структурное описание архитектурного тела в виде схемы в базисе инверторов (Inverter) и двухвходовых элементов И (AND_Gate) имеет вид architecture structure of Decoder is signal S: bit_vector (0 to 1); component AND_Gate port (A, B: in Bit; D: out Bit); end component; component Inverter port (A: in Bit; B: out Bit); end component; Inv1: Inverter port map (A=>x(0), B=>s(0)); Inv2: Inverter port map (A=>x(1), B=>s(1)); A1:AND_Gate port map (A=>s(0), B=>s(1), D=>y(0)); A2:AND_Gate port map (A=>s(0), B=>x(1), D=>y(1)); A3:AND_Gate port map (A=>x(0), B=>s(1), D=>y(2)); A4:AND_Gate port map (A=>x(0), B=>x(1), D=>y(3)); end structure; Описание поведения дешифратора в виде потока данных (data flow). architecture Data_flow of Decoder is begin y(0) <= (not x(0) and (not x(1)); y(1) <= (not x(0) and x(1)); y(2) <= x(0) and (not x(1)); y(3) <= x(0) and x(1)); end Data_flow; Процедурное описание дешифратора выглядит следующим образом: architecture Procedural of Decoder is
130 Глава 4. Примеры проектирования на VHDL signal s: bit_vector (0 to 3); begin process (x, s) case x is when "00"=> s<= "1000"; when "01"=> s<= "0100"; when "10"=> s<= "0010"; when "11"=> s<= "0001"; end case; y<=s; end process; end Procedural; Смешанное описание, использующее элементы структурного описания и элементы описания "поток данных", приведено ниже. architecture Mixed of Decoder is component Inverter port (A: in Bit; B: out Bit); end component; signal S: bit_vector (o to 1); begin Inv1: Inverter port map (A=>x(0), B=>s(0)); Inv2: Inverter port map (A=>x(1), B=>s(1)); p: process (s, x) begin y(0) <= s(0) and s(1); y(1) <= s(0) and x(1); y(2) <= x(0) and s(1); y(3) <= x(0) and x(1)); end process; end Mixed; В данном примере структурное описание и описание типа "поток данных" весьма схожи, так как происходит замена логических элементов (компонентов) логическими выражениями. Однако для более сложных схем такая замена может быть совершенно не очевидной. 4.2. Формы описания сигналов Формы описания сигналов
131 Формы описания сигналов Битовое представление сигналов может быть громоздким. На начальных этапах проектирования могут быть использованы другие типы данных [1]. Устройство управления COUT Component UU C Операционное устройство OUIN Component OU Рис. 4.2. Сигнал С может быть описан как bit_vector и как перечислимый тип Пусть устройство управления (UU) посылает четырехбитовый код в операционное устройство (OU). Четырехбитовый код определяет операцию, подлежащую выполнению. На рис. 4.2 выходной порт устройства управления имеет имя COUT, входной порт операционного устройства – имя OUIN. Можно описать сигнал C на битовом уровне signal C: BIT_VECTOR(0 to 3); или же как перечислимый тип type CONTROL is (AND, OR, XOR, ADD, SUB, ..., TCOMP); signal C: CONTROL; Таким образом, если использовать перечислимый тип, то управляющую информацию можно представлять в мнемоническом виде, т.е. именовать команды UU. При этом в архитектурном теле устройства управления можно было бы использовать операторы назначения сигнала, такие как COUT <= ADD; а в архитектурном теле операционного устройства if (OUIN = ADD) then ... При таком подходе разработчик модели освобождается от необходимости беспокоиться о низкоуровневых деталях [1]. Другой вариант описания сигнала C выглядит следующим образом: subtype CONTROL is INTEGER range 0 to 15; signal C: CONTROL;
132 Глава 4. Примеры проектирования на VHDL Подтип CONTROL ограничивает диапазон значений, которые могут быть присвоены сигналу C, тем самым обеспечивается некоторый контроль ошибок. В некоторых случаях может понадобиться как битовый уровень, так и более высокий уровень - типа INTEGER. Для преобразования типов нужны функции. Ниже описаны две функции. Функция BIN4_TO_INT преобразует битовые векторы в целые числа путем суммирования соответствующих степеней двойки. Функция INT_TO_BIN4 выполняет обратную операцию. Функция INT_TO_BIN4 приведена ниже в пакете vv_vls. Предоставляем читателю самостоятельно написать VHDL-код функции BIN4_TO_INT, для образца можно воспользоваться VHDL-кодом функции BIN2_TO_INT, находящемся в теле пакета vv_vls. С использованием функций BIN2_TO_IN, INT_TO_BIN4 легко описывается (на алгоритмическом уровне) поведение схем mult_2, adder_2, входящих в схему VLSI_1 (см. гл. 1). Определим функции BIN2_TO_INT, INT_TO_BIN4 в пакете vv_vls. package vv_vls is function bin2_to_int (signal w2,w1: bit) return integer; function int_to_bin4 (signal INPUT : integer) return bit_vector; end vv_vls; package body vv_vls is function bin2_to_int (signal w2,w1: bit) return integer is variable sum : integer :=0; begin if w1 ='1' then sum :=1; else sum :=0; end if; if w2 ='1' then -- функция преобразования битового -- вектора в число
Формы описания сигналов sum := sum+2; else sum := sum; end if; return sum; end bin2_to_int; function int_to_bin4 -- функция преобразования числа (signal INPUT : integer) -- в битовый вектор return bit_vector is variable fout: bit_vector(0 to 3); variable temp_a: integer:=0; variable temp_b: integer:=0; begin temp_a:=INPUT; for i in 3 downto 0 loop temp_b:=temp_a/(2**i); temp_a:=temp_a rem (2**i); if (temp_b=1) then fout(i):='1'; else fout(i):='0'; end if; end loop; return fout; end int_to_bin4; end vv_vls; architecture functional of mult_2 is -- функциональное описание use std.vv_vls.all; -- умножителя signal ss, rr : integer range 0 to 3; signal tt : integer range 0 to 9; signal tt_sig : bit_vector (0 to 3); begin ss <= bin2_to_int(s1,s0); rr <= bin2_to_int(r1,r0); tt <= ss*rr; -- функция умножителя tt_sig <= int_to_bin4(tt); t0 <= tt_sig(0); -- формирование выходных сигналов 133
134 Глава 4. Примеры проектирования на VHDL t1 <= tt_sig(1); t2 <= tt_sig(2); t3 <= tt_sig(3); end functional; entity adder_2 is port (a1,b1,a2,b2 : in BIT; c2,s2,s1 : out BIT); end adder_2; architecture functional of adder_2 is -- функциональное описание -- сумматора use std.vv_vls.all; signal aa, bb : integer range 0 to 3; signal cc : integer range 0 to 7; signal cc_sig : bit_vector (0 to 3); begin aa <= bin2_to_int (a1,b1); bb <= bin2_to_int (a2,b2); cc <= aa+bb; -- функция сумматора cc_sig <= int_to_bin4(cc); s1 <= cc_sig(0); -- формирование выходных сигналов s2 <= cc_sig(1); c2 <= cc_sig(2); end functional; Предлагаем читателю провести моделирование схемы VLSI_1, используя архитектурные тела functional (алгоритмические описания) для объектов проекта mult_2, adder_2 вместо архитектурных тел structure, представленных в гл. 1. Вернемся к схеме VLSI (разд. 1.1). Чтобы заменить алгоритмическое описание структурным, необходимо использовать функцию преобразования типа INTEGER в тип BIT_VECTOR. Предоставляем читателю сделать это самостоятельно.
135 Описание автоматов 4.3. Описание автоматов Описание автоматов Схема с обратной связью Рассмотрим схему, изображенную на рис. 4.3. В нее входит элемент памяти (D-триггер) и комбинационный элемент И. Данная схема описывается в виде двух процессов, причем для описания функционирования D-триггера вводится функция rising_edge. & a B D C clk Q C R reset Рис. 4.3. Схема с обратной связью (architecture circ_feedback) architecture circ_feedback of some_entity is signal b: bit; function rising_edge (signal s : bit ) return boolean is begin return s = '1' and s'event; end; begin process (clk, reset) begin if reset = '1' then c <= '0'; elsif rising_edge(clk) c <= b; end if; end process; process (a, c) -- комбинационный процесс
136 Глава 4. Примеры проектирования на VHDL begin b <= a and c; end process; end circ_feedback ; Глава 4. Примеры проектирования на VHDL Конечный автомат Широкое распространение в практике проектирования дискретных устройств получила модель конечного (абстрактного) автомата. Конечный автомат K определяется как набор K = (A, Z, W, δ , λ , a1 ), где A = { a1 ,..., aQ } - множество (алфавит) состояний (имеются в виду внутренние состояния автомата); Z = { z1 ,..., zN } - множество входных сигналов (входной алфавит); W = { w1 ,..., wM } - множество выходных сигналов (выходной алфавит); δ - функция переходов, определяющая состояние автомата в момент времени t+1 в зависимости от состояния автомата и входного сигнала в момент времени t, иначе говоря, as = δ (am , z), (4.1) где am - состояние автомата в момент времени t; z - входной сигнал в момент времени t; as - состояние автомата в момент времени t+1; λ - функция выходов. Если функция λ по состоянию автомата am и входному сигналу zn определяет значение выходного сигнала wm wm = λ (aq , zn ), (4.2) то конечный автомат называется автоматом Мили , если же wm = λ (aq), (4.3) то конечный автомат называется автоматом Мура; a1 - начальное состояние автомата в момент времени t =0, a1 ∈A. Функционирование автомата происходит следующим образом: в дискретные моменты времени t = 0, 1, 2, 3,... на вход устройства поступает входной сигнал - один из элементов множества Z, а на
137 Описание автоматов выходе появляется выходной сигнал - один из элементов множества W, в этот же момент времени t автомат из состояния am переходит в состояние as, в котором он будет находиться в момент времени t+1. Разработаны различные формы задания конечных автоматов. Например, в табл. 4.1 задан конечный автомат с четырьмя внутренними состояниями [2]. Таблица 4.1 Входные сигналы z1 z2 a1 a2/w1 a4/w5 Состояния a2 a3 a2/w1 a1/w2 a3/w3 a4/w4 a4 a1/w4 a3/w5 Алфавит состояний A = {a1, a2, a3, a4}, q = 1,...,4. Входной алфавит Z образуют сигналы z1, z2, т.е. Z = {z1 , z2 }, n = 1,2. Выходной алфавит W образуют сигналы w1, ..., w5, т.е. W = {w1, w2 ,w3 ,w4,w5}, m = 1,...,5. На пересечении строки zn и столбца aq в таблице находится состояние as , в которое должен перейти автомат из состояния aq под воздействием сигнала zn. После косой черты в этой же графе таблицы указывается выходной сигнал, выдаваемый автоматом в состоянии aq при поступлении на его вход сигнала zn . Иначе говоря, табл. 4.1 является таблицей задания функций δ , λ и называется совмещенной таблицей переходов и выходов. Следующий VHDL-код реализует поведение конечного автомата, заданного в табл. 4.1. Поведение автомата представляется в виде совокупности двух взаимодействующих процессов (рис. 4.4). Процесс NS определяет выходной сигнал w и внутренний сигнал NEXT_state, который является входным для процесса REG. Заметим, однако, что в списке чувствительности процесса REG имеется только сигнал clk, который соответствует моментам времени срабатывания автомата. Для входных сигналов автомата в пакете vv_vls определяется перечислимый тип fsm_in_type is (z1, z2);
138 Глава 4. Примеры проектирования на VHDL state z state w Процесс NS NEXT_state clk Процесс REG Рис. 4.4. Описание функционирования конечного автомата в виде совокупности двух процессов (entity FSM_A) для выходных сигналов в том же пакете определяется перечислимый тип fsm_out_type is (w1 , w2 ,w3 ,w4 ,w5); Для задания состояний автомата в архитектурном теле определяется перечислимый тип t_state. Предполагается, что начальное состояние автомата равно a1. Начальное состояние явно не указывается, так как при инициализации будет взят элемент нижней границы перечислимого типа - это и будет элемент a1. use work.vv_vls.all; entity FSM_A is port (z : in fsm_in_type; clk : in bit; w : out fsm_out_type); end FSM_A; architecture rtl_a of fsm_a is type T_state is (a1,a2,a3,a4); signal NEXT_state : T_state; signal state : T_state; begin NS : process (state, z)
Описание автоматов begin NEXT_state <= state; case state is when a1 => if (z=z1) then NEXT_state <= a2; w <= w1; elsif (z=z2) then NEXT_state <= a4; w <= w5; end if; when a2 => if (z=z1) then NEXT_state <= a2; w <= w1; elsif (z=z2) then NEXT_state <= a3; w <= w3; end if; when a3 => if (z=z1) then NEXT_state <= a1; w <= w2; elsif (z=z2) then NEXT_state <= a4; w <= w4; end if; when a4 => if (z=z1) then NEXT_state <= a1; w <= w4; elsif (z=z2) then NEXT_state <= a3; w <= w5; end if; end case; end process; REG : process(clk) begin if clk = '1' then state <= NEXT_state; end if; end process; end rtl_a; Сделав следующие назначения сигналов z, clk z <= z1, z2 after 50 ns, z1 after 100 ns, z2 after 150 ns, z1 after 200 ns, z2 after 250 ns; clk <= '1', 139
140 Глава 4. Примеры проектирования на VHDL '0' after 25 ns, '1' after 50 ns, '0' after 75 ns, '1' after 100 ns, '0' after 125 ns, '1' after 150 ns, '0' after 175 ns, '1' after 200 ns, '0' after 225 ns, '1' after 250 ns; "снаружи" объекта FSM_A, получим соответствующую временную диаграмму (рис. 4.5) функционирования автомата. Многократное изменение синхросигнала clk можно более компактно описать в виде процесса generator. Переменная number задает число тактов. В данном случае число тактов равно 5. generator : process variable number : integer := 5; begin for i in 1 to number loop clk <= transport '1'; wait for 25 ns; clk <= transport '0'; wait for 25 ns; end loop; end process; При схемной реализации автомата обычно поступают следующим образом. Выделяют комбинационную часть автомата и память. Как же детализировать описание поведения автомата на случай элементов памяти того или иного типа? В случае нашего примера будем реализовывать элементы памяти на D-триггерах. Заметим, что в архитектурном теле rtl_a для entity FSM_A не указывается, как будут функционировать элементы памяти. Так как поведение D-триггера нам известно, можем использовать соответствующий VHDL-код для описания процесса REG. Описание поведения конечного автомата в виде совокупности двух взаимодействующих процессов - процесса NS и детализированного процесса REG - показано на рис. 4.6.
1 100 w2 a1 a3 z1 125 150 w5 a4 a1 z2 175 200 w4 a1 a4 z2 225 250 Рис. 4.5. Временная диаграмма функционирования конечного автомата w3 w1 w 0 a3 a2 Next_state clk a2 a1 State 75 z2 50 z1 z1 25 z 0 w5 a4 a1 z2 Время
142 Глава 4. Примеры проектирования на VHDL use work.vv_vls.all; entity FSM is port (z : in fsm_in_type; clk, rst : in bit; w : out fsm_out_type); end FSM; architecture rtl of fsm is type T_state is (a1,a2,a3,a4); signal NEXT_state, state : T_state; begin NS : process (state, z) -- комбинационный процесс ... -- описание процесса NS дано в архитектурном теле -- rtl_a для entity FSM_A end process NS; REG: process (clk, rst) -- процесс REG для D-триггера begin if (rst = '1') then state <= a1; elsif clk'event and clk = '1' then state <= NEXT_state; end if; end process REG; end rtl; z Процесс NS w NEXT_state Процесс REG clk rst Рис. 4.6. Структура конечного автомата (entity FSM) state
Описание автоматов 143 Дальнейшая детализация поведения автомата связана с кодированием значений перечислимых типов булевыми векторами, описанием функций комбинационной части схемы и формированием регистра триггеров. В качестве упражнения можно составить VHDLкод для структурной схемы автомата, для этого можно использовать приведенную в [2] структуру: булевы функции для комбинационной части и регистр D-триггеров. Далее рассмотрим различные способы структурной организации автоматов Мура и Мили и приведем общие планы описания их на языке VHDL, не конкретизируя функции комбинационных частей и регистров элементов памяти. Автомат Мура Рассмотрим схему moore1, изображенную на рис. 4.7. Не будем конкретизировать типы сигналов a, d. Может быть дано следующее описание поведения схемы moore1: entity system is port (clock: boolean; a: some_type;.d: out some_type); end system; architecture moore1 of system is signal b, c: some_type; begin process (a, c) begin b <= F1(a, c); end process; process (c) begin d <= F2(c); end process; process begin wait until clock; c <= b; end process; end moore1;
144 Глава 4. Примеры проектирования на VHDL b F1 c Регистр d F2 a clock Рис. 4.7. Схема moore1 Для схемы moore1 более компактное описание представлено архитектурным телом moore1_1. architecture moore1_1 of system is signal c: some_type; begin process (c) -- процесс для комбинационной логики begin d <= F2(c); end process; process -- процесс для последовательностной логики begin wait until clock; c <= F1(a, c); end process; end moore1_1; В литературе автоматом Мура называют также схему с памятью, у которой выходные функции равны состояниям элементов памяти. Например, для схемы moore2 (рис. 4.8 ) описание поведения имеет вид architecture moore2 of system is begin process begin wait until clock; d <= F(a,d); end process; end moore2;
145 Описание автоматов Выходной регистр d F a clock Рис. 4.8. Схема moore2 Автомат Мили Схема mealy, реализующая некоторый автомат Мили, изображена на рис. 4.9, а ниже представлено описание ее поведения. architecture mealy of system is signal c: some_type; begin process (a, c) -- процесс для комбинационной логики begin d <= F2(a, c); end process; process -- процесс для последовательностной логики begin wait until clock; c <= F1(a, c); end process; end mealy; F1 b Регистр a clock Рис. 4.9. Схема mealy c F2 d
146 Глава 4. Примеры проектирования на VHDL Параллельный автомат Все шире в практике проектирования цифровых систем используются языки и формальные модели, позволяющие описывать параллелизм и асинхронность логического управления. Одной из таких моделей является модель параллельного автомата. Отличительной особенностью параллельного автомата является то, что он может одновременно находиться в нескольких состояниях, называемых частичными [4]. В работе [4] для описания функционирования параллельного автомата используется язык ПРАЛУ. Язык ПРАЛУ [4] предназначен для описания параллельных алгоритмов логического управления. Его характерными особенностями являются логическая стройность, простота, компактность получаемых описаний, использование двоичных (булевых) переменных для входных и выходных переменных устройства управления, алгоритм функционирования которого задан на языке ПРАЛУ. Полное описание языка ПРАЛУ содержится в [4]. Дадим некоторые сведения по языку ПРАЛУ, касающиеся параллельных автоматов. Будем считать исходным ПРАЛУ-описание, состоящее из элементарных цепочек. Согласно [4] элементарной называется цепочка вида µi : -ki′ →ki" →νi , (4.4) где операция -ki′ или →ki" или обе вместе в ней могут отсутствовать. В общем случае элементарная цепочка состоит из четырех частей: µi - множество начальных меток цепочки; -ki′ - операция ожидания события ki′ ; →ki" - операция действия; νi - множество заключительных меток цепочки. Двоеточие служит разделителем, а стрелка перед νi играет роль операции внесения элементов в текущее множество запуска цепочек. Множество M, называемое множеством запуска цепочек, получается в результате объединения множеств начальных и заключительных меток всех цепочек. Поясним сначала, что представляют собой операции ожидания и действия, а затем объясним, каким образом выполняется алгоритм в целом, т.е. как выполняются цепочки, как они взаимодействуют друг с другом и какова роль в этом множества M.
147 Описание автоматов В записи (4.4) ki′, ki" представляют собой элементарные конъюнкции булевых переменных. Конъюнкции ki′ образуются из литералов булевых переменных множества X, конъюнкции ki" образуются из литералов переменных множества Y. Если конъюнкция ki′, ( ki" ) отсутствует в (4.4), то предполагается, что она тождественно равна 1. Множество X представляет собой множество входных переменных устройства управления (УУ), множество Y - выходных переменных (рис. 4.10). Предполагается, что алгоритм, представленный ПРАЛУ-описанием, реализует поведение (функции) УУ. z1 Устройство управления (ПРАЛУ-алгоритм) X Y Объект управления z_end Рис.4.10. ПРАЛУ-описание реализует функции устройства управления Операция -ki′ представляет собой операцию ожидания события ki′. Выполнение этой операции сводится к ожиданию события, когда переменные, входящие в конъюнкцию ki′, примут значения, обращающие ki′ в единицу. Операция действия →ki" означает присвоение таких значений переменным конъюнкции ki" , при которых ki" обращается в единицу. Цепочка (4.4) срабатывает, если в текущем множестве запуска содержится множество µi и если выполнилась операция ожидания -ki′ . Срабатывание цепочки заключается в немедленном удалении множества µi из текущего множества запуска, после чего выполняется операция действия →ki" , а затем немедленно добавляются элементы множества νi в текущее множество запуска. В начале работы алгоритма в текущее множество запуска включается метка 1, алгоритм заканчивает работу, если множество запуска содержит заключительную метку. В процессе работы алгоритма некоторые цепочки могут выполняться одновременно (параллельно), поэтому такой формализм
148 Глава 4. Примеры проектирования на VHDL позволяет описывать параллельные алгоритмы логического управления. В [4] показано, что множество элементарных цепочек представляет собой параллельный автомат. При этом множество таких цепочек должно удовлетворять определенным требованиям, например, цепочки i, j, имеющие одинаковые множества начальных меток, должны иметь ортогональные конъюнкции в операциях ожидания. Другие требования к корректности исходных ПРАЛУ-описаний изложены в [4]. Будем предполагать, что исходное ПРАЛУ-описание является корректным. Рассмотрим вопрос о преобразовании ПРАЛУ-описаний в VHDLкоды. Естественно, сначала нужно, если потребуется, изменить идентификаторы языка ПРАЛУ в соответствии с требованиями языка VHDL. После этого преобразование ПРАЛУ-описаний в VHDL-коды может быть полностью автоматизировано. Покажем, как это может быть сделано. Рассмотрим ПРАЛУ-описание [4], в котором X = {a, b, c, d}, Y = ={u, v, w}. В элементарных конъюнкциях ki′ , ki" отрицательный литерал x i булевой переменной xi будем записывать в виде xi′. Номер цепочки 1 (начало) 1: -u →ab →9 2 9: -u′ →2.3 3 2: -v′w →b′c →10 4 10: -w′ →b →11 5 11: →c′ →2 6 2: -v →a′c →4.5 7 3: -uw →d →6 8 4: -u′v′ →a →12 9 12: -u →a′ →4 10 4: -u →ab′ →7 11 5: -v′w →c′ →8
149 Описание автоматов 12 6.7.8: →a′d →13 13 13: -w′ →. (конец) В данном примере идентификаторы u, v, w, a, b, c, d ПРАЛУописания являются однобуквенными и проблем с их изменением не возникает. Отдельное ПРАЛУ-описание переводится в объект проекта языка VHDL. Именем entity будет имя ПРАЛУ-описания. Обозначим через behavior имя архитектурного тела для формируемого объекта проекта. Формирование интерфейса объекта осуществляется следующим образом. 1. Имя ПРАЛУ-описания становится именем объекта проекта в языке VHDL. Пусть в нашем примере example будет именем ПРАЛУописания. 2. По спискам входных (INP) и выходных (OUT) переменных формируется раздел port VHDL-кода, при этом переменные языка ПРАЛУ специфицируются на языке VHDL как битовые сигналы (bit). В список входных переменных добавляется битовый сигнал z1, в список выходных переменных - битовый сигнал z_end. Назначение сигналов z1, z_end поясним позже. В нашем примере интерфейс объекта проекта будет иметь вид entity example is port ( u,v,w,z1 : in bit; a,b,c,d, z_end : out bit); end example; Для ПРАЛУ-описания формирование архитектурного тела объекта проекта осуществляется в виде совокупности процессов языка VHDL. Каждой элементарной цепочке ПРАЛУ-описания взаимно однозначно соответствует процесс языка VHDL. В архитектурном теле декларируются внутренние сигналы типа bit. Каждый такой сигнал взаимно однозначно соответствует элементу множества запуска M, за исключением первого и последнего элемента множества M. Будем считать, что элемент 1 из множества M является входным сигналом z1, разрешающим работу алгоритма в целом. Единичное значение выходного сигнала z_end будет сигнализировать о том, что алгоритм закончил свою работу (см. рис. 4.10). Сигналы z1,
150 Глава 4. Примеры проектирования на VHDL z_end могут быть использованы для записи VHDL-кодов тех ПРАЛУописаний, которые устроены иерархически (рис.4.11). ПРАЛУ-алгоритм Головной блок z1_1 z_end_1 Подчиненный блок 1 z1_n .. .. .. z_1 z_end_n Подчиненный блок n z_end Объект управления Рис. 4.11. Взаимодействие головного и подчиненных блоков иерархического ПРАЛУ-алгоритма осуществляется с помощью сигналов z1, z_end В примере элементу 1 множества M будет соответствовать сигнал z1, заключительной метке (точке) будет соответствовать сигнал z_end. Таким образом, меткам 2, 3, ..., 11, 12, 13 будут соответствовать внутренние сигналы z2, z3,..., z11, z12, z13 архитектурного тела. Покажем теперь, каким образом элементарная цепочка переводится в процесс языка VHDL. Пронумеруем цепочки, как это показано в примере. Номера цепочек не следует путать с номерами начальных меток. Номер j цепочки будет соответствовать процессу pj в архитектурном теле.
151 Описание автоматов Все процессы, соответствующие цепочкам, будут ожидающими, т.е. не будут иметь списков сигналов запуска. Срабатывание цепочки на языке VHDL записывается с помощью оператора wait (ждать). Рассмотрим, например, цепочку 3 2: -v′w →b′c →10 , которой будет соответствовать процесс p3. Фрагмент VHDL-кода приведен ниже. Заметим, что комментарии на языке VHDL начинаются с двух смежных знаков дефиса и продолжаются до конца строки. p3 : process -- процесс, соответствующий цепочке 3 begin wait until ( (v='0') and (w = '1') and (z2 = '1')); -- оператор ожидания z2 <= transport '0'; -- изымание метки 2 из текущего множества запуска b<= transport '0'; c<= transport '1'; -- операция действия z10 <= transport '1'; -- занесение заключительной метки 10 в -- текущее множество запуска end process p3; Процесс p3 является ожидающим, операторы назначения сигналов, записанные после оператора wait, будут выполняться, если будет истинным булево выражение (v='0') and (w = '1') and (z2 = '1'), записанное после ключевого слова until. Оно будет истинным (примет значение true), если битовые переменные y, w, z2 примут значение 0,1,1 соответственно. В процессе p3 в операторе назначения сигнала использовано ключевое слово transport, т.е. используется транспортная задержка. Транспортная задержка предполагает, что все изменения сигналов будут передаваться независимо от того, сколько времени будет сохраняться новое значение сигнала. Заметим, что записанные после оператора wait операторы назначения сигналов, представляющие собой изымание меток из текущего множества запуска, операцию действия и внесение заключительных меток в текущее множество запуска, будут выполняться параллельно. Поэтому, чтобы определить временной
152 Глава 4. Примеры проектирования на VHDL интервал их выполнения, в практических ситуациях можно вносить конкретные временные задержки. Пусть требуется, чтобы перед операцией действия была задержка 20 ns, а сигналы, устанавливающие значение 0 для переменной b и значение 1 для переменной c, были стабильными в течение 10 ns, а сигналы z2, z10 были стабильны 5 ns. В этом случае процесс p3 будет иметь вид p3 : process begin wait until ( (v='0') and (w = '1') and (z2 = '1')); z2 <= transport '0'after 5 ns; wait for 20 ns; -- ожидание перед операцией действия b<= transport '0' after 10 ns; c<= transport '1' after 10 ns; z10 <= transport '1' after 5 ns; end process p3; Ниже представлен VHDL-код архитектурного тела behavior объекта проекта для примера ПРАЛУ-описания, составленного из 13 элементарных цепочек. architecture behavior of example is -- декларация внутренних сигналов signal z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13 : bit; begin p1 : process begin wait until ((u='1') and (z1 = '1')); a<= transport '1'; b<= transport '1' ; z9 <= transport '1' ; end process p1; p2 : process begin wait until ((u='0') and (z9 = '1')); z9 <= transport '0' ; z2 <= transport '1'; z3 <= transport '1'; end process p2; p3 : process
Описание автоматов begin wait until ( (v='0') and (w = '1') and (z2 = '1')); z2 <= transport '0' ; b<= transport '0'; c<= transport '1'; z10 <= transport '1'; end process p3; p4 : process begin wait until((w = '0') and (z10 = '1')); z10 <= transport '0'; b <= transport '1'; z11 <= transport '1'; end process p4; p5 : process begin wait until (z11 = '1'); z11 <= transport '0'; c<= transport '0'; z2 <= transport '1' ; end process p5; p6 : process begin wait until ((v='1') and (z2 = '1')); z2 <= transport '0'; a <= transport '0'; c <= transport '1' ; z4 <= transport '1'; z5 <= transport '1'; end process p6; p7 : process begin wait until ((u='1') and (w = '1') and (z3 = '1')); z3 <= transport '0'; d <= transport '1'; z6 <= transport '1'; end process p7; p8 : process begin wait until ((u='0') and (v = '0') and (z4 = '1')); z4 <= transport '0'; 153
154 Глава 4. Примеры проектирования на VHDL a <= transport '1'; z12 <= transport '1'; end process p8; p9 : process begin wait until ((u='1') and (z12 = '1')); z12 <= transport '0'; a <= transport '0'; z4 <= transport '1'; end process p9; p10 : process begin wait until ((u='1') and (z4 = '1')); z4 <= transport '0'; a <= transport '1'; b<= transport '0'; z7 <= transport '1'; end process p10; p11 : process begin wait until ((v='0') and (w = '1') and (z5 = '1')); z5 <= transport '0'; c <= transport '0'; z8 <= transport '1'; end process p11; p12 : process begin wait until ((z6='1') and (z7 = '1') and (z8 = '1')); z6 <= transport '0'; z7 <= transport '0'; z8 <= transport '0'; a <= transport '0'; d <= transport '1'; z13 <= transport '1'; end process p12; p13 : process begin wait until ((w='0') and (z13 = '1')); z13 <= transport '0'; z_end <= '1'; end process p13; end behavior;
Отладка VHDL-описаний 155 Очевидно, что преобразование ПРАЛУ-описания в VHDL-код может быть автоматизировано. При автоматизированном проектировании совместное использование языков ПРАЛУ и VHDL может быть организовано следующим образом. Так как в существующих системах моделирования VHDL-кодов проводится только проверка правильности синтаксических конструкций языка VHDL, то в качестве исходного описания параллельного алгоритма целесообразно взять ПРАЛУописание, семантическая корректность которого может быть проверена с помощью хорошо развитых формальных методов верификации, когда параллельный алгоритм проверяется на живость, безопасность, наличие тупиковых состояний и т.д. [4]. После семантической отладки алгоритма осуществляется автоматическое преобразование ПРАЛУописания в VHDL-код, который может быть аппаратно реализован в виде СБИС типа FPGA. 4.4. Отладка VHDL-описаний Отладка VHDL-описаний Отладка VHDL-кодов происходит путем подачи входных сигналов в объект проекта, после чего происходит сравнение полученных реакций с ожидаемыми. Этот процесс, по существу, аналогичен отладке программ. С точки зрения "отладки" аппаратуры этот процесс напоминает тестирование схемы на предмет установления правильности ее функционирования. Пример тестирования VHDL-кода схемы VLSI_1. entity test_vlsi_1 is end test_vlsi_1; architecture test of test_vlsi_1 is component vlsi_1 port (a2,a1,b2,b1,x : in BIT; d4,d3,d2,d1 : out BIT); end component; signal a2, a1, b2, b1, x, d4, d3,d2,d1 : BIT; begin p:component vlsi_1 port map (a2 => a2, a1=>a1, b2=>b2,b1=>b1,x=>x, d4=>d4, d3=>d3,d2=>d2,d1=>d1); b2 <= '1'; b1 <= '1'; a2 <= '1'; a1 <= '0', '1' after 50 ns;
156 Глава 4. Примеры проектирования на VHDL x <= '0', '1' after 30 ns, '0' after 70 ns ; end test; Временная диаграмма показана на рис. 4.12. В табл. 4.2 дано функционирование схемы во времени. 0 30ns 50ns 70ns 100ns Время a2 1 0 a1 1 0 b2 1 0 b1 1 0 x 1 0 d4 1 0 d3 1 0 d2 1 0 d1 1 0 Рис. 4.12. Временная диаграмма
157 Отладка VHDL-описаний Таблица 4.2 Сигналы a=(a2, a1) b=(b2,b1) x=(x) d=(d4,d3,d2,d1) t=[0ns, 30ns] 2 3 0 (сложение) 5 Время t=[30ns, 50ns] t=[50ns, 70ns] 2 3 3 3 1(умножение) 1(умножение) 6 9 t=[70ns,100ns] 3 3 0 (сложение) 6 В данном примере объект проекта test_vlsi_1 представляет собой "оболочку" (рис. 4.13) объекта проекта vlsi_1 с единственной целью организовать подачу входных сигналов в объект vlsi_1, так как внутри архитектурного тела объекта vlsi_1 нельзя назначить входные сигналы. Входные сигналы для entity должны быть назначены "снаружи"! a2 a1 d4 b2 b1 d3 S d2 d1 x entity VLSI 1 entity test_VLSI_1 Рис. 4.13. При тестирование объекта VLSI_1 entity test_VLSI_1 не имеет портов
158 Глава 4. Примеры проектирования на VHDL 4.5. Синтезируемое подмножество языка VHDL Глава 4. Примеры проектирования на VHDL Синтезируемое подмножество языка VHDL После того как проектировщик убедился в корректности VHDLмодели цифровой системы, возникает проблема программной либо схемной реализации данной модели. Схемные реализации, как правило, являются более быстродействующими, поэтому важной задачей является задача синтеза схемы, функции которой реализуют поведение VHDL-модели. На практике, однако, переход к соответствующей логической схеме осуществляется не для всего языка VHDL, а только для некоторого подмножества этого языка, называемого синтезируемым подмножеством. Для VHDL-модели цифровой системы, описанной на синтезируемом подмножестве языка VHDL, можно получить схему. Обычно это интегральная схема типа ПЛИС либо схема программируемой пользователем вентильной матрицы [5]. Общий метод получения такой схемы является компилятивным операторы языка VHDL заменяются компилятами. Компилят - это подсхема, реализующая вполне определенный оператор языка, например оператор сложения. При синтезе схемы типы данных bit отражаются при синтезе в проводники (полюса) схем, типы данных bit_vector - в шины (жгуты проводников). Перечислимые типы данных при синтезе кодируются булевыми векторами. Кодирование обычно ведется с использованием минимального числа кодирующих переменных. Например, для перечислимого типа type my_state is (RESET, IDLE, RW_CYCLE, INT_CYCLE); может быть проведено кодирование RESET = ''00'', IDLE = ''01'', RW_CYCLE = ''10'', INT_CYCLE = ''11''. Очевидно, в кодах 00, 01, 10, 11 используются только две кодирующие булевы переменные. Переменные языка VHDL, мгновенно передающие свои значения, исчезают при схемной реализации. В приведенном ниже примере проследите за переменной W в VHDL-коде и в соответствующей схеме (рис. 4.14). Пример схемной "реализации" переменных языка VHDL.
Синтезируемое подмножество языка VHDL 159 Library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; entity xor_var is port (A,B,C : in std_logic; X,Y : out std_logic); end xor_var; architecture example of xor_var is begin P : process (A,B,C) variable W: std_logic; begin W := A; X < = C xor W; W := B; Y <= C xor D; end process; end example; C A C B ⊕ X ⊕ Y Рис. 4.14. Исчезновение переменных при схемной реализации Для логических операторов and, or, nand, nor, xor, xnor, not, имеющих тип bit, boolean, arrays, bit_vector, компиляция в схему осуществляется прямым преобразованием логических выражений в соответствующие логические вентили (элементы). Пример схемной реализации логических выражений.
160 Глава 4. Примеры проектирования на VHDL entity logical_ops_1 is port (a, b, c, d: in bit; m: out bit); end logical_ops_1; architecture example of logical_ops_1 is signal e: bit; begin m <= (a and b) or e; -- оператор назначения сигнала e <= c xor d; end example; Схема, реализующая поведение объекта logical_ops_1, приведена на рис. 4.15. a b c d & 1 m ⊕ Рис. 4.15. Схемная реализация логического выражения для типа bit Пример схемной реализации логических выражений типа bit_vector. entity logical_ops_2 is port (a, b: in bit_vector (0 to 3); m: out bit_vector (0 to 3)); end logical_ops_2 architecture example of logical_ops_2 is begin m <= a and b; end example; Соответствующая схема приведена на рис. 4.16.
Синтезируемое подмножество языка VHDL a(0) b(0) a(1) b(1) a(2) b(2) a(3) b(3) & m(0) & m(1) & m(2) & m(3) 161 Рис. 4.16. Схемная реализация логического выражения для типа bit_vector Схемная реализация операторов отношения Операторами отношения являются следующие операторы = (равно); /= (не равно) > (больше); < (меньше); >= (больше или равно); <= (меньше или равно). Операторы = , /= определяются в языке VHDL для всех типов. Операторы (>=, <=, >, < ) определяются для числовых типов, перечислимых типов и некоторых массивов. Результирующий тип для всех операторов boolean. Следующие два примера показывают схемную реализацию для операторов a=b, a>=b. entity relational_ops_1 is port (a, b: in bit_vector (0 to 3); m: out boolean); end relational_ops_1; architecture example of relational_ops_1 is begin
162 Глава 4. Примеры проектирования на VHDL m <= a = b; end example; Схема, реализующая оператор равенства для типа bit_vector, приведена на рис. 4.17. a(0) b(0) a(1) b(1) ⊕ ⊕ 1 m a(2) b(2) a(3) b(3) ⊕ ⊕ Рис. 4.17. Схемная реализация оператора a=b для типа bit_vector (0 to 3) entity relational_ops_2 is port (a, b: in integer range 0 to 3; m: out boolean); end relational_ops_2; architecture example of relational_ops_2 is begin m <= a >= b; end example; Схема, реализующая оператор >= для типа integer, показана на рис. 4.18.
163 Синтезируемое подмножество языка VHDL b0 1 a0 & 1 b1 a1 & ⊕ & 1 b2 a2 & ⊕ & 1 b3 a3 & ⊕ m & Рис. 4.18. Схемная реализация оператора отношения а>=b для целых чисел a =(a3,a2,a1,a0), b =(b3,b2,b1,b0)
164 Глава 4. Примеры проектирования на VHDL Схемная реализация арифметических операторов Арифметические операторы + (сложение); - (вычитание); * (умножение); / (деление); mod (модуль); rem (остаток ); abs (абсолютное значение); ** (возведение в степень) определяются для числовых типов. Операторы ( +, - ) являются достаточно "дорогостоящими" (дающими сложные схемы). Операторы (*, / , mod, rem) являются очень дорогостоящими. Обычно при синтезе делается специальная оптимизация, если справа от оператора находится константа или число, не большее 2. Реализация оператора (abs) не является сложной. Оператор (**) поддерживается только для констант. Примеры схем, реализующих операторы сложения и умножения, уже рассматривались в данной книге. Схемная реализация операторов управления Схемным "аналогом" оператора if является, по существу, мультиплексор (рис. 4.19) с одним управляющим входом, где b, c выступают в качестве настроечных входов, вход a - в качестве управляющего. Функционирование мультиплексора описывается следующей формулой: m = a& c ∨ a& b . entity control_if is port (a, b, c: boolean; m: out boolean); end control_if; architecture example of control_if is begin process (a, b, c) variable n: boolean; begin if a then n := b;
165 Синтезируемое подмножество языка VHDL else n := c; end if; m <= n; end process; end example; Схема, реализующая оператор if, изображена на рис. 4.19: если a=1, то m=b, если a=0, то m=c. Предлагаем читателю сравнить функцию, реализуемую процедурой MX, содержащейся в пакете multiplexer (разд.1.2), с функцией объекта проекта control_if. Однако не всегда очевидна та логическая схема, которая соответствует оператору языка VHDL. В качестве примера укажем на тот факт, что в компиляторах, осуществляющих схемную реализацию VHDL-кода, оператор if, у которого после ключевого слова else не производится никаких действий, интерпретируется как D-триггер (задержка). Поэтому получение нужных логических схем по VHDLкодам с помощью САПР требует тщательного изучения библиотеки компилятов. a 1 & с 1 a b m & Рис. 4.19. Схемная реализация оператора управления if (entity control_if) Схемная реализация оператора case entity control_case is port (sel: in bit_vector (0 to 1); a,b,c,d : in bit; m: out bit); end control_case; architecture example of control_case is begin
166 Глава 4. Примеры проектирования на VHDL process (sel,a,b,c,d) begin case sel is when "00" => m <= c; when "01" => m <= a; when "10" => m <= d; when others => m <= b; end case; end process; end example; Схема, реализующая оператор case, изображена на рис. 4.20. sel (1) sel (0) a 1 & & b & & & c & 1 & d & Рис.4.20. Схемная реализация оператора case (entity control_case) m
Синтезируемое подмножество языка VHDL 167 Схемная реализация подпрограмм и циклов Операторы generate, loop, for loop, while loop, function, procedure также могут быть схемно реализованы. Для каждого вызова подпрограммы и для каждой итерации цикла создается соответствующая схема. entity control_loop is port (a: bit_vector (0 to 3); m: out bit_vector (0 to 3)); end control_loop; architecture example of control_loop is begin process (a) variable b: bit; begin b := '1'; for i in 0 to 3 loop b:= a(3-i) and b; m( i ) <= b; b := b + 1; end loop; end process; end example; entity subprograms is port (a: bit_vector (0 to 2); m: out bit_vector (0 to 2)); end subprograms; architecture example of subprograms is function simple (w, x, y: bit) return bit is begin return (w and x) or y; end; begin process (a) begin m(0) <= simple(a(0), a(1), a(2)); m(1) <= simple(a(2), a(0), a(1)); m(2) <= simple(a(1), a(2), a(0)); end process; end example
168 Глава 4. Примеры проектирования на VHDL Например, для цикла (entity loop_stmt) и для подпрограммы (entity subprograms) соответствующие схемы приведены ниже (рис. 4.21, 4.22). a (0) & a (1) m (3) & a (2) m (2) & m (1) a (3) m (0) Рис. 4.21. Схемная реализация оператора loop (entity control_loop) a (0) 1 & m (2) a (1) 1 & m (1) a (2) 1 & m (0) Рис. 4.22. Схемная реализация оператора "подпрограмма" (entity subprograms) В заключение можно сказать, что мир VHDL большой и достаточно сложный, так как сложны те электронные схемы и системы,
169 Упражнения инструментом описания, моделирования, верификации и синтеза которых он является. За чертой остались еще такие аспекты языка VHDL, как типы файлов и типы доступа, инородные подпрограммы, группы, разделяемые переменные и другие вопросы. Автор надеется, что провести их изучение можно будет, базируясь на материалах, представленных в данной книге. Упражнения УПРАЖНЕНИЯ 1. Правильны ли утверждения a) структурное VHDL-описание может быть иерархичным; b) поведенческое VHDL-описание может быть иерархичным; c) смешанное (структурно-поведенческое) VHDL-описание не может быть иерархичным. 2. Правильно ли, что структурное описание состоит из компонент и сигналов? 3. Правильно ли, что все компоненты должны быть специфицированы на поведенческом уровне? 4. Какие компоненты проекта не имеют структурного описания? 5. Какое устройство реализует поведение, представленное VHDLкодом? entity EX is port (A : in std_ulogic_vector(0 to 15); SEL : in integer range 0 to 15; Z : out std_ulogic); end EX; architecture RTL of EX is begin WHAT: process (A, SEL) begin for I in 0 to 15 loop if SEL = I then Z <= A(I); end if; end loop; end process WHAT;
170 Глава 4. Примеры проектирования на VHDL end RTL; Выберите правильный ответ. a) дешифратор; в) счетчик; с) мультиплексор. Укажите разрядность устройства. 6. Опишите поведение конечного автомата, используя двухразмерные массивы для задания совмещенной таблицы переходов и выходов. 7. Используя информацию о структурной схеме, приведенную в [2, с. 20-21], составьте VHDL-код и проведите моделирование конечного автомата, поведение которого задано в архитектурном теле rtl_a (entity FSM_A). 8. Составьте VHDL-код для генерации синхроимпульсов (см. рис. 4.5) в виде процесса с использованием оператора wait. 9. Как должен быть написан VHDL-код, чтобы с помощью существующих средств САПР можно было автоматически получить схему? Выберите правильный ответ. a) код должен быть написан на поведенческом уровне; b) код должен быть написан на уровне регистровых передач; c) код должен быть написан на уровне логических вентилей; d) средства САПР могут синтезировать схему для любого уровня VHDL-описания. 10. В данной книге даны различные архитектурные тела для Dтриггера. Рассмотрите особенности их функционального и структурного описания. Проведите моделирование.
171 Литература Литература Литература 1. Армстронг Дж.Р. Моделирование цифровых систем на языке VHDL/Пер с англ. - М.: Мир, 1992. - 175 с. 2. Баранов С.И., Скляров В.А. Цифровые устройства на программируемых БИС с матричной структурой. - М.: Радио и связь, 1986. - 279 с. 3. Бибило П.Н. Кремниевая компиляция заказных СБИС. Минск: Ин-т техн. кибернетики АН Беларуси, 1996. - 268 с. 4. Закревский А.Д. Параллельные алгоритмы логического управления. - Минск: Ин-т техн. кибернетики НАН Беларуси, 1999. 202 с. 5. Соловьев В.В., Васильев А.Г. Программируемые логические интегральные схемы и их применение. - Минск: Беларуская навука, 1998. - 270 с. 6. VHDL для моделирования, синтеза и формальной верификации аппаратуры/Пер с англ. - М: Радио и связь, 1995. - 360с. 7. VHDL’92. Новые свойства языка описания аппаратуры VHDL/Пер с англ. - М.: Радио и связь, 1995. -256 с. 8. Asheden P.J. The VHDL Cookbook. University of Adelaide, South Australia. -1990. 9. Chang K.C. Digital design and modeling with VHDL and synthesis. IEEE Computer Society Press. 1997.
172 Приложения Приложения Приложения 1. Форма задания синтаксических конструкций языка VHDL Форма задания синтаксических конструкций языка VHDL Для задания синтаксических конструкций языка VHDL используются так называемые формы Бэкуса-Науэра, служащие для описания грамматик формальных языков. Для определения синтаксической конструкции используется выражение <синтаксическая конструкция>::=<определение> Используемые фигурные скобки служат для обозначения повторения выражения, заключенного в них. Выражение может повторяться k раз (k=0,1,2, ...). При k=0 выражение отсутствует. Вертикальная черта служит для обозначения альтернативных случаев. Например, letter_or_digit ::= letterdigit, т.е. синтаксическая конструкция символ_или_число определяется как символ (letter) или цифра (digit). В случае, например, choices::=choice{choise}, когда в фигурных скобках стоит то же выражение (с символом «вертикальная черта»), это означает повторение того же выражения. В данном примере повторяется выражение «choice». Квадратные скобки служат для обозначения необязательного выражения или необязательного слова. Например, запись return_statement::=return[expression]; эквивалентна записи return_statement::=return;return[expression]; Если элемент синтаксической конструкции начинается с курсива, то выделяемая курсивом часть конструкции несет смысловую нагрузку (семантическую информацию). Выделяемое курсивом слово может не приниматься во внимание. Например, элементы type_name и subtype_name могут рассматриваться просто как name (имя). В случае type_name подчеркивается, что это имя типа, в случае subtype_name, что это имя подтипа.
Синтаксис языка VHDL’93 Синтаксис языка VHDL’93 173 2. Синтаксис языка VHDL’93 Синтаксические конструкции, приводимые в данном приложении, можно найти по следующему адресу сети Internet: http://tech-www.informatik.uni-hamburg.de/vhdl/tools/vhdl-93.bnf abstract_literal ::= decimal_literal | based_literal access_type_definition ::= access subtype_indication actual_designator ::= expression | signal_name | variable_name | file_name | open actual_parameter_part ::= parameter_association_list actual_part ::= actual_designator | function_name ( actual_designator ) | type_mark ( actual_designator ) adding_operator ::= + | - | & aggregate ::= ( element_association { , element_association } ) alias_declaration ::= alias alias_designator [ : subtype_indication ] is name [ signature ] ; alias_designator ::= identifier | character_literal | operator_symbol allocator ::= new subtype_indication | new qualified_expression architecture_body ::= architecture identifier of entity_name is
174 Приложения architecture_declarative_part begin architecture_statement_part end [ architecture ] [ architecture_simple_name ] ; architecture_declarative_part ::= { block_declarative_item } architecture_statement_part ::= { concurrent_statement } array_type_definition ::= unconstrained_array_definition | constrained_array_definition assertion ::= assert condition [ report expression ] [ severity expression ] assertion_statement ::= [ label : ] assertion ; association_element ::= [ formal_part => ] actual_part association_list ::= association_element { , association_element } attribute_declaration ::= attribute identifier : type_mark ; attribute_designator ::= attribute_simple_name attribute_name ::= prefix [ signature ] ' attribute_designator [ ( expression ) ] attribute_specification ::= attribute attribute_designator of entity_specification is expression ; base ::= integer
Синтаксис языка VHDL’93 base_specifier ::= B | O | X base_unit_declaration ::= identifier ; based_integer ::= extended_digit { [ underline ] extended_digit } based_literal ::= base # based_integer [ . based_integer ] # [ exponent ] basic_character ::= basic_graphic_character | format_effector basic_graphic_character ::= upper_case_letter | digit | special_character| space_character basic_identifier ::= letter { [ underline ] letter_or_digit } binding_indication ::= [ use entity_aspect ] [ generic_map_aspect ] [ port_map_aspect ] bit_string_literal ::= base_specifier " bit_value " bit_value ::= extended_digit { [ underline ] extended_digit } block_configuration ::= for block_specification { use_clause } { configuration_item } end for ; block_declarative_item ::= subprogram_declaration | subprogram_body | type_declaration | subtype_declaration 175
176 Приложения | constant_declaration | signal_declaration | shared_variable_declaration | file_declaration | alias_declaration | component_declaration | attribute_declaration | attribute_specification | configuration_specification | disconnection_specification | use_clause | group_template_declaration | group_declaration block_declarative_part ::= { block_declarative_item } block_header ::= [ generic_clause [ generic_map_aspect ; ] ] [ port_clause [ port_map_aspect ; ] ] block_specification ::= architecture_name | block_statement_label | generate_statement_label [ ( index_specification ) ] block_statement ::= block_label : block [ ( guard_expression ) ] [ is ] block_header block_declarative_part begin block_statement_part end block [ block_label ] ; block_statement_part ::= { concurrent_statement } case_statement ::=
Синтаксис языка VHDL’93 [ case_label : ] case expression is case_statement_alternative { case_statement_alternative } end case [ case_label ] ; case_statement_alternative ::= when choices => sequence_of_statements character_literal ::= ' graphic_character ' choice ::= simple_expression | discrete_range | element_simple_name | others choices ::= choice { | choice } component_configuration ::= for component_specification [ binding_indication ; ] [ block_configuration ] end for ; component_declaration ::= component identifier [ is ] [ local_generic_clause ] [ local_port_clause ] end component [ component_simple_name ] ; component_instantiation_statement ::= instantiation_label : instantiated_unit [ generic_map_aspect ] [ port_map_aspect ] ; component_specification ::= 177
178 Приложения instantiation_list : component_name composite_type_definition ::= array_type_definition | record_type_definition concurrent_assertion_statement ::= [ label : ] [ postponed ] assertion ; concurrent_procedure_call_statement ::= [ label : ] [ postponed ] procedure_call ; concurrent_signal_assignment_statement ::= [ label : ] [ postponed ] conditional_signal_assignment | [ label : ] [ postponed ] selected_signal_assignment concurrent_statement ::= block_statement | process_statement | concurrent_procedure_call_statement | concurrent_assertion_statement | concurrent_signal_assignment_statement | component_instantiation_statement | generate_statement condition ::= boolean_expression condition_clause ::= until condition conditional_signal_assignment ::= target <= options conditional_waveforms ; conditional_waveforms ::= { waveform when condition else } waveform [ when condition ] configuration_declaration ::= configuration identifier of entity_name is configuration_declarative_part block_configuration
Синтаксис языка VHDL’93 end [ configuration ] [ configuration_simple_name ] ; configuration_declarative_item ::= use_clause | attribute_specification | group_declaration configuration_declarative_part ::= { configuration_declarative_item } configuration_item ::= block_configuration | component_configuration configuration_specification ::= for component_specification binding_indication ; constant_declaration ::= constant identifier_list : subtype_indication [ := expression ] ; constrained_array_definition ::= array index_constraint of element_subtype_indication constraint ::= range_constraint | index_constraint context_clause ::= { context_item } context_item ::= library_clause | use_clause decimal_literal ::= integer [ . integer ] [ exponent ] declaration ::= type_declaration | subtype_declaration | object_declaration 179
180 Приложения | interface_declaration | alias_declaration | attribute_declaration | component_declaration | group_template_declaration | group_declaration | entity_declaration | configuration_declaration | subprogram_declaration | package_declaration delay_mechanism ::= transport | [ reject time_expression ] inertial design_file ::= design_unit { design_unit } design_unit ::= context_clause library_unit designator ::= identifier | operator_symbol direction ::= to | downto disconnection_specification ::= disconnect guarded_signal_specification after time_expression ; discrete_range ::= discrete_subtype_indication | range element_association ::= [ choices => ] expression element_declaration ::= identifier_list : element_subtype_definition ; element_subtype_definition ::= subtype_indication entity_aspect ::= entity entity_name [ ( architecture_identifier) ] | configuration configuration_name | open entity_class ::=
Синтаксис языка VHDL’93 entity | architecture | configuration | procedure | function | package | type | subtype | constant | signal | variable | component | label | literal | units | group | file entity_class_entry ::= entity_class [ <> ] entity_class_entry_list ::= entity_class_entry { , entity_class_entry } entity_declaration ::= entity identifier is entity_header entity_declarative_part [ begin entity_statement_part ] end [ entity ] [ entity_simple_name ] ; entity_declarative_item ::= subprogram_declaration | subprogram_body | type_declaration | subtype_declaration | constant_declaration | signal_declaration | shared_variable_declaration | file_declaration | alias_declaration | attribute_declaration | attribute_specification | disconnection_specification | use_clause | group_template_declaration | group_declaration entity_declarative_part ::= { entity_declarative_item } 181
182 Приложения entity_designator ::= entity_tag [ signature ] entity_header ::= [ formal_generic_clause ] [ formal_port_clause ] entity_name_list ::= entity_designator { , entity_designator } | others | all entity_specification ::= entity_name_list : entity_class entity_statement ::= concurrent_assertion_statement | passive_concurrent_procedure_call_statement | passive_process_statement entity_statement_part ::= { entity_statement } entity_tag ::= simple_name | character_literal | operator_symbol enumeration_literal ::= identifier | character_literal enumeration_type_definition ::= ( enumeration_literal { , enumeration_literal } ) exit_statement ::= [ label : ] exit [ loop_label ] [ when condition ] ; exponent ::= E [ + ] integer | E - integer expression ::= relation { and relation } | relation { or relation } | relation { xor relation } | relation [ nand relation ]
Синтаксис языка VHDL’93 | relation [ nor relation ] | relation { xnor relation } extended_digit ::= digit | letter extended_identifier ::= \ graphic_character { graphic_character } \ factor ::= primary [ ** primary ] | abs primary | not primary file_declaration ::= file identifier_list : subtype_indication file_open_information ] ; file_logical_name ::= string_expression file_open_information ::= [ open file_open_kind_expression ] is file_logical_name file_type_definition ::= file of type_mark floating_type_definition := range_constraint formal_designator ::= generic_name | port_name | parameter_name formal_parameter_list ::= parameter_interface_list formal_part ::= formal_designator | function_name ( formal_designator ) | type_mark ( formal_designator ) full_type_declaration ::= type identifier is type_definition ; 183
184 Приложения function_call ::= function_name [ ( actual_parameter_part ) ] generate_statement ::= generate_label : generation_scheme generate [ { block_declarative_item } begin ] { concurrent_statement } end generate [ generate_label ] ; generation_scheme ::= for generate_parameter_specification | if condition generic_clause ::= generic ( generic_list ) ; generic_list ::= generic_interface_list generic_map_aspect ::= generic map ( generic_association_list ) graphic_character ::= basic_graphic_character | lower_case_letter | other_special_character group_constituent ::= name | character_literal group_constituent_list ::= group_constituent { , group_constituent } group_template_declaration ::= group identifier is ( entity_class_entry_list ) ; group_declaration ::= group identifier : group_template_name ( group_constituent_list ) ; guarded_signal_specification ::= guarded_signal_list : type_mark
185 Синтаксис языка VHDL’93 identifier ::= basic_identifier | extended_identifier identifier_list ::= identifier { , identifier } if_statement ::= [ if_label : ] if condition then sequence_of_statements { elsif condition then sequence_of_statements } [ else sequence_of_statements ] end if [ if_label ] ; incomplete_type_declaration ::= type identifier ; index_constraint ::= ( discrete_range { , discrete_range } ) index_specification ::= discrete_range | static_expression index_subtype_definition ::= type_mark range <> indexed_name ::= prefix ( expression { , expression } ) instantiated_unit ::= [ component ] component_name | entity entity_name [ ( architecture_identifier ) ] | configuration configuration_name instantiation_list ::= instantiation_label { , instantiation_label } | others | all integer ::= digit { [ underline ] digit }
186 Приложения integer_type_definition ::= range_constraint interface_constant_declaration ::= [ constant ] identifier_list : [ in ] subtype_indication [ := static_expression ] interface_declaration ::= interface_constant_declaration | interface_signal_declaration | interface_variable_declaration | interface_file_declaration interface_element ::= interface_declaration interface_file_declaration ::= file identifier_list : subtype_indication interface_list ::= interface_element { ; interface_element } interface_signal_declaration ::= [signal] identifier_list : [ mode ] subtype_indication [ bus ] [ := static_expression ] interface_variable_declaration ::= [variable] identifier_list : [ mode ] subtype_indication [ := static_expression ] iteration_scheme ::= while condition | for loop_parameter_specification label ::= identifier letter ::= upper_case_letter | lower_case_letter letter_or_digit ::= letter | digit library_clause ::= library logical_name_list ;
Синтаксис языка VHDL’93 library_unit ::= primary_unit | secondary_unit literal ::= numeric_literal | enumeration_literal | string_literal | bit_string_literal | null logical_name ::= identifier logical_name_list ::= logical_name { , logical_name } logical_operator ::= and | or | nand | nor | xor | xnor loop_statement ::= [ loop_label : ] [ iteration_scheme ] loop sequence_of_statements end loop [ loop_label ] ; miscellaneous_operator ::= ** | abs | not mode ::= in | out | inout | buffer | linkage multiplying_operator ::= * | / | mod | rem name ::= simple_name | operator_symbol | selected_name | indexed_name | slice_name | attribute_name next_statement ::= [ label : ] next [ loop_label ] [ when condition ] ; 187
188 null_statement ::= [ label : ] null ; numeric_literal ::= abstract_literal | physical_literal object_declaration ::= constant_declaration | signal_declaration | variable_declaration | file_declaration operator_symbol ::= string_literal options ::= [ guarded ] [ delay_mechanism ] package_body ::= package body package_simple_name is package_body_declarative_part end [ package body ] [ package_simple_name ] ; package_body_declarative_item ::= subprogram_declaration | subprogram_body | type_declaration | subtype_declaration | constant_declaration | shared_variable_declaration | file_declaration | alias_declaration | use_clause | group_template_declaration | group_declaration package_body_declarative_part ::= { package_body_declarative_item } package_declaration ::= package identifier is Приложения
Синтаксис языка VHDL’93 package_declarative_part end [ package ] [ package_simple_name ] ; package_declarative_item ::= subprogram_declaration | type_declaration | subtype_declaration | constant_declaration | signal_declaration | shared_variable_declaration | file_declaration | alias_declaration | component_declaration | attribute_declaration | attribute_specification | disconnection_specification | use_clause | group_template_declaration | group_declaration package_declarative_part ::= { package_declarative_item } parameter_specification ::= identifier in discrete_range physical_literal ::= [ abstract_literal ] unit_name physical_type_definition ::= range_constraint units base_unit_declaration { secondary_unit_declaration } end units [ physical_type_simple_name ] port_clause ::= port ( port_list ) ; port_list ::= port_interface_list 189
190 Приложения port_map_aspect ::= port map ( port_association_list ) prefix ::= name | function_call primary ::= name | literal | aggregate | function_call | qualified_expression | type_conversion | allocator | ( expression ) primary_unit ::= entity_declaration | configuration_declaration | package_declaration procedure_call ::= procedure_name [ ( actual_parameter_part ) ] procedure_call_statement ::= [ label : ] procedure_call ; process_declarative_item ::= subprogram_declaration | subprogram_body | type_declaration | subtype_declaration | constant_declaration | variable_declaration | file_declaration | alias_declaration | attribute_declaration | attribute_specification | use_clause
191 Синтаксис языка VHDL’93 | group_template_declaration | group_declaration process_declarative_part ::= { process_declarative_item } process_statement ::= [ process_label : ] [ postponed ] process [ ( sensitivity_list ) ] [ is ] process_declarative_part begin process_statement_part end [ postponed ] process [ process_label ] ; process_statement_part ::= { sequential_statement } qualified_expression ::= type_mark ' ( expression ) | type_mark ' aggregate range ::= range_attribute_name | simple_expression direction simple_expression range_constraint ::= range range record_type_definition ::= record element_declaration { element_declaration } end record [ record_type_simple_name ] relation ::= shift_expression [ relational_operator shift_expression ] relational_operator ::= = | report_statement ::= [ label : ] /= | < | <= | > | >=
192 Приложения report expression [ severity expression ] ; return_statement ::= [ label : ] return [ expression ] ; scalar_type_definition ::= enumeration_type_definition | integer_type_definition | floating_type_definition | physical_type_definition secondary_unit ::= architecture_body | package_body secondary_unit_declaration ::= identifier = physical_literal ; selected_name ::= prefix . suffix selected_signal_assignment ::= with expression select target <= options selected_waveforms ; selected_waveforms ::= { waveform when choices , } waveform when choices sensitivity_clause ::= on sensitivity_list sensitivity_list ::= signal_name { , signal_name } sequence_of_statements ::= { sequential_statement } sequential_statement ::= wait_statement | assertion_statement | report_statement | signal_assignment_statement | variable_assignment_statement | procedure_call_statement
Синтаксис языка VHDL’93 | if_statement | case_statement | loop_statement | next_statement | exit_statement | return_statement | null_statement shift_expression ::= simple_expression [ shift_operator simple_expression ] shift_operator ::= sll | srl | sla | sra | rol | ror sign ::= + | signal_assignment_statement ::= [ label : ] target <= [ delay_mechanism ] waveform ; signal_declaration ::= signal identifier_list : subtype_indication [ signal_kind ] [ := expression ] ; signal_kind ::= register | bus signal_list ::= signal_name { , signal_name } | others | all signature ::= [ [ type_mark { , type_mark } ] [ return type_mark ] ] simple_expression ::= [ sign ] term { adding_operator term } simple_name ::= identifier slice_name ::= prefix ( discrete_range ) string_literal ::= " { graphic_character } " 193
194 Приложения subprogram_body ::= subprogram_specification is subprogram_declarative_part begin subprogram_statement_part end [ subprogram_kind ] [ designator ] ; subprogram_declaration ::= subprogram_specification ; subprogram_declarative_item ::= subprogram_declaration | subprogram_body | type_declaration | subtype_declaration | constant_declaration | variable_declaration | file_declaration | alias_declaration | attribute_declaration | attribute_specification | use_clause | group_template_declaration | group_declaration subprogram_declarative_part ::= { subprogram_declarative_item } subprogram_kind ::= procedure | function subprogram_specification ::= procedure designator [ ( formal_parameter_list ) ] | [ pure | impure ] function designator [ ( formal_parameter_list ) ] return type_mark subprogram_statement_part ::= { sequential_statement } subtype_declaration ::= subtype identifier is subtype_indication ;
Синтаксис языка VHDL’93 195 subtype_indication ::= [ resolution_function_name ] type_mark [ constraint ] suffix ::= simple_name | character_literal | operator_symbol | all target ::= name | aggregate term ::= factor { multiplying_operator factor } timeout_clause ::= for time_expression type_conversion ::= type_mark ( expression ) type_declaration ::= full_type_declaration | incomplete_type_declaration type_definition ::= scalar_type_definition | composite_type_definition | access_type_definition | file_type_definition type_mark ::= type_name | subtype_name unconstrained_array_definition ::= array ( index_subtype_definition { , index_subtype_definition } ) of element_subtype_indication use_clause ::= use selected_name { , selected_name } ;
196 Приложения variable_assignment_statement ::= [ label : ] target := expression ; variable_declaration ::= [ shared ] variable identifier_list : subtype_indication [ := expression ]; wait_statement ::= [ label : ] wait [ sensitivity_clause ] [ condition_clause ] [ timeout_clause ] ; waveform ::= waveform_element { , waveform_element } | unaffected waveform_element ::= value_expression [ after time_expression ] | null [ after time_expression ] Пакет STANDARD 3. Пакет STANDARD package STANDARD is type BOOLEAN is (FALSE, TRUE); type BIT is ('0', '1'); type CHARACTER is ( NUL, SOH, STX, ETX, EOT, ENQ, ACK, BEL, BS, HT, LF, VT, FF, CR, SO, SI, DLE, DC1, DC2, DC3, DC4, NAK, SYN, ETB, CAN, EM, SUB, ESC, FSP, GSP, RSP, USP, ' ', '!', '"', '#', '$', '%', '&', ''', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
Пакет STANDARD 197 'X', 'Y', 'Z', '[', '\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', DEL); type SEVERITY_LEVEL is (NOTE, WARNING, ERROR, FAILURE); type INTEGER is range -214748 to +214748; type TIME is range -9 to +9 units fs; -- femtosecond ps = 1000 fs; -- picosecond ns = 1000 ps; -- nanosecond us = 1000 ns; -- microsecond ms = 1000 us; -- millisecond sec = 1000 ms; -- second min = 60 sec; -- minute hr = 60 min; -- hour end units; function NOW return TIME; subtype NATURAL is INTEGER range 0 to INTEGER'HIGH; subtype POSITIVE is INTEGER range 1 to INTEGER'HIGH; type STRING is array ( POSITIVE range <> ) of CHARACTER; type BIT_VECTOR is array ( NATURAL range <> ) of BIT; end STANDARD;
198 Пакет STD_LOGIC_1164 Приложения 4. Пакет STD_LOGIC_1164 package PACK1164 is type std_ulogic is ( 'U', -- Uninitialized 'X', -- Forcing Unknown '0', -- Forcing 0 '1', -- Forcing 1 'Z', -- High Impedance 'W', -- Weak Unknown 'L', -- Weak 0 'H', -- Weak 1 '-'); -- Don't care type std_ulogic_vector is array ( NATURAL RANGE <> ) of std_ulogic; function resolved ( s : std_ulogic_vector ) RETURN std_ulogic; subtype UX01 is resolved std_ulogic RANGE 'U' TO '1'; subtype std_logic is resolved std_ulogic; type std_logic_vector is array ( NATURAL RANGE <>) of std_logic; function "and" ( l : std_ulogic; r : std_ulogic ) RETURN UX01; function "and" ( l, r : std_logic_vector ) RETURN std_logic_vector; function "and" ( l, r : std_ulogic_vector ) RETURN std_ulogic_vector; end PACK1164; package body PACK1164 is type stdlogic_1d is array (std_ulogic) of std_ulogic; type stdlogic_table is array (std_ulogic, std_ulogic) of std_ulogic; constant resolution_table : stdlogic_table := ( ---- --------------------------------------------------------| U X 0 1 Z W L H | | --------------------------------------------------------( 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U' ), -- | U | ( 'U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' ), -- | X | ( 'U', 'X', '0', 'X', '0', '0', '0', '0', 'X' ), -- | 0 | ( 'U', 'X', 'X', '1', '1', '1', '1', '1', 'X' ), -- | 1 | ( 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', 'X' ), -- | Z | ( 'U', 'X', '0', '1', 'W', 'W', 'W', 'W', 'X' ), -- | W | ( 'U', 'X', '0', '1', 'L', 'W', 'L', 'W', 'X' ), -- | L | ( 'U', 'X', '0', '1', 'H', 'W', 'W', 'H', 'X' ), -- | H | ( 'U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' ) -- | - | ); function resolved ( s : std_ulogic_vector ) RETURN std_ulogic IS variable result : std_ulogic := 'Z'; -- weakest state default
199 Пакет STD_LOGIC_1164 begin if (s'LENGTH = 1) then RETURN s(s'LOW); else for i in s'RANGE loop result := resolution_table(result, s(i)); end loop; end if; RETURN result; end resolved; constant and_table : stdlogic_table := ( ---- ---------------------------------------------------| U X 0 1 Z W L H ---------------------------------------------------( 'U', 'U', '0', 'U', 'U', 'U', '0', 'U', 'U' ), -( 'U', 'X', '0', 'X', 'X', 'X', '0', 'X', 'X' ), -( '0', '0', '0', '0', '0', '0', '0', '0', '0' ), -( 'U', 'X', '0', '1', 'X', 'X', '0', '1', 'X' ), -( 'U', 'X', '0', 'X', 'X', 'X', '0', 'X', 'X' ), -( 'U', 'X', '0', 'X', 'X', 'X', '0', 'X', 'X' ), -( '0', '0', '0', '0', '0', '0', '0', '0', '0' ), -( 'U', 'X', '0', '1', 'X', 'X', '0', '1', 'X' ), -( 'U', 'X', '0', 'X', 'X', 'X', '0', 'X', 'X' ) -- | | | | | | | | | | | U X 0 1 Z W L H - | | | | | | | | | ); function "and" ( l : std_ulogic; r : std_ulogic ) RETURN UX01 is begin RETURN (and_table(l, r)); end "and"; function "and" (l,r : std_logic_vector ) RETURN std_logic_vector is alias lv : std_logic_vector ( 1 TO l'LENGTH ) is l; alias rv : std_logic_vector ( 1 TO r'LENGTH ) is r; variable result : std_logic_vector ( 1 TO l'LENGTH ); begin if ( l'LENGTH /= r'LENGTH ) then assert FALSE report "arguments of 'and' operator are not of the same length" severity FAILURE; else for i in result'RANGE loop result(i) := and_table (lv(i), rv(i)); end loop;
200 end if; RETURN result; end "and"; -----------------------------------------------------------------function "and" ( l,r : std_ulogic_vector ) RETURN std_ulogic_vector is alias lv : std_ulogic_vector ( 1 TO l'LENGTH ) is l; alias rv : std_ulogic_vector ( 1 TO r'LENGTH ) is r; variable result : std_ulogic_vector ( 1 TO l'LENGTH ); begin if ( l'LENGTH /= r'LENGTH ) then assert FALSE report "arguments of 'and' operator are not of the same length" severity FAILURE; else for i in result'RANGE loop result(i) := and_table (lv(i), rv(i)); end loop; end if; RETURN result; end "and"; end PACK1164; Приложения