Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
шпоры бис.docx
Скачиваний:
2
Добавлен:
01.07.2025
Размер:
12 Мб
Скачать
☆

3.6.2. Создание и применение пользовательских макрофункций

В файлах, написанных на AHDL можно легко создавать и использовать пользовательские макрофункции, выполняя следующие действия:

  • Создать логику для макрофункции в файле проекта.

  • Определить порты макрофункции в объявлении прототипа функции.

Прототип функции дает краткое описание функции: ее имя, а также входные, выходные и двунаправленные порты. Можно также использовать машинные порты для макрофункций, которые импортируют или экспортируют цифрового автомата.

Объявление прототипов функций может быть размещено в Include-файле, который вызывается в пользовательском файле. Используя команду CreateDefaultIncludeFile, можно автоматически создавать Include-файл с прототипом функции для любого файла проекта.

  • Вставить в файл пример макрофункции с помощью объявления примера в секции VARIABLE или с помощью непосредственной ссылки в тексте.

  • Использовать макрофункцию в файле.

3.6.3. Определение пользовательской макрофункции

Для использования макрофункции ее нужно либо включить в описание прототипа функции в TDF-файле, либо указать в директиве INCLUDE файла TDF имя Include-файла, содержащего прототип этой макрофункции. Как уже упоминалось выше, Include-файлы можно создавать автоматически.

Ниже приводится файл keyboard.tdf, в котором реализован кодировщик для 16-клавишной клавиатуры.

TITLE "Keyboard Encoder";

INCLUDE "74151";

INCLUDE "74154";

INCLUDE "4count";

FUNCTION debounce (clk, key_pressed)

RETURNS (pulse);

SUBDESIGN keyboard

(

clk : INPUT; % 50-KHz clock % col[3..0] : INPUT; % keyboard columns % row[3..0], d[3..0] : OUTPUT; % keyboard rows, key code % strobe : OUTPUT; % key code is valid %

)

VARIABLE

key_pressed : NODE; % VCC when key d[3..0] is pressed % mux : 74151;

decoder : 74154;

counter : 4count;

opencol[3..0] : TRI;

BEGIN

% Drive keyboard rows with a decoder and % % open-collector outputs. %

row[] = opencol[].out;

opencol[].in = GND;

opencol[].oe = decoder.(o0n,o1n,o2n,o3n); decoder.(b,a) = counter.(qd,qc);

% Sense keyboard columns with a multiplexer %

mux.d[3..0] = col[3..0];

mux.(b,a) = counter.(qb,qa);

key_pressed= !mux.y;

% Scan keyboard until a key is pressed. % % Drive key's code onto d[] outputs %

counter.clk = clk;

counter.cin= !key_pressed;

d[] = counter.(qd,qc,qb,qa);

% Generate strobe when key has settled %

strobe = debounce(clk, key_pressed);

END;

В данном примере в директивах INCLUDE указываются файлы прототипов функции для стандартных макрофункций фиромыAltera: 4count, 74151 и 74154.

Отдельно в файле дан прототип функции для макрофункции debounce, в котором описаны входы clk и key_pressed и выходpulse.

Примеры макрофункций 4count, 74151 и 74154 вызываются объявлением примеров в секции VARIABLE. Пример макрофункцииdebounce вызывается непосредственной ссылкой в тексте логической секции

3.6.4. Импорт и экспорт цифровых автоматов (statemachine)

Операции импорта и экспорта цифровых автоматов осуществляются между файлами TDF и другими файлами проекта путем задания входного или выходного порта как входа автомата (MACHINЕ INPUT) и его выхода (MACHINЕ OUTPUT) в секции SUBDESIGN. Прототип функции, который представляет собой файл, содержащий машину состояние, должен указывать, какие входы и выходы принадлежат машине состояний. Это осуществляется снабжением имен сигналов префиксом - ключевым словом Machine.

Замечание. Порты типа MACHINЕ INPUT и MACHINЕ OUTPUT нельзя использовать в файл проекта верхнего уровня.

Можно переименовать автомат, дав ей временное имя  (псевдоним) в объявлении MACHINE в секции VARIABLE. Псевдоним цифрового автомата можно использовать в том файле, где создается цифровой автомат (statemachine), или в том файле, где используется порт MACHINЕ INPUT для импортирования цифрового автомата. Это имя можно потом использовать вместо первоначального имени цифрового автомата.

Ниже приводится файл ss_def.tdf, который определяет и экспортирует цифровой автомат ss с портом ss_out типа MACHINЕ OUTPUT.

SUBDESIGN ss_def

(

clk, reset, count : INPUT;

ss_out : MACHINE OUTPUT;

)

VARIABLE

ss : MACHINE WITH STATES (s1, s2, s3, s4, s5);

BEGIN

ss_out = ss;

CASE ss IS

WHEN s1=>

IF count THEN ss = s2; ELSE ss = s1; END IF;

WHEN s2=>

IF count THEN ss = s3; ELSE ss = s2; END IF;

WHEN s3=>

IF count THEN ss = s4; ELSE ss = s3; END IF;

WHEN s4=>

IF count THEN ss = s5; ELSE ss = s4; END IF;

WHEN s5=>

IF count THEN ss = s1; ELSE ss = s5; END IF;

END CASE;

ss.(clk, reset) = (clk, reset);

END;

Ниже приводится файл ss_use.tdf, который импортирует цифровой автомат с портом ss_in типа MACHINE INPUT.

SUBDESIGN ss_use

(

ss_in : MACHINE INPUT;

out : OUTPUT;

)

BEGIN

out = (ss_in == s2) OR (ss_in == s4);

END;

Ниже приведен файл top1.tdf, в котором используются непосредственные ссылки в тексте для вставки примеров функций ss_def иss_use. В прототипах этих функций содержится ключевое слово MACHINE для указания, какие входы и выходы являются цифровыми автоматами с памятью (state machine).

FUNCTION ss_def (clk, reset, count) RETURNS (MACHINE ss_out);

FUNCTION ss_use (MACHINE ss_in) RETURNS (out);

DESIGN IS "top1" DEVICE IS "AUTO";

SUBDESIGN top1

(

sys_clk, /reset, hold : INPUT;

sync_out : OUTPUT;

)

VARIABLE

ss_ref: MACHINE; % Machine Alias Declaration %

BEGIN

ss_ref = ss_def(sys_clk, !/reset, !hold);

sync_out = ss_use(ss_ref);

END;

Внешний цифровой автомат можно также реализовать в TDF-файле верхнего уровня с объявлением примера в секции VARIABLE.

Ниже приведен файл top2.tdf, который имеет ту же функцию, что и файл top1.tdf, но для вызова макрофункций использует объявление примеров.

FUNCTION ss_def (clk, reset, count) RETURNS (MACHINE ss_out);

FUNCTION ss_use (MACHINE ss_in) RETURNS (out);

DESIGN IS "top2" DEVICE IS "AUTO";

SUBDESIGN top2

(

sys_clk, /reset, hold : INPUT;

sync_out : OUTPUT;

)

VARIABLE

sm_macro :ss_def;

sync :ss_use;

BEGIN

sm_macro.(clk, reset, count) = (sys_clk, !/reset,!hold);

sync.ss_in = sm_macro.ss_out;

sync_out = sync.out;

END;

2.2

Типы данных.

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

Типы данных:

1.                  integer — целый;

2.                  real — действительный;

3.                  bit — представляет один логический бит (значение ‘0’ либо ‘1’);

4.                  boolean — объекты этого типа принимают значения true либо false;

5.                  character — объединяет все символы;

6.                  time — используется для задания задержек;

7.                  severity_level — служит для управления работой компилятора;

8.                  file_open_statusи file_open_kind — обеспечивают возможность контроля процедур между программой и файловой системой компьютера;

9.                  stringи bit_vector — массив символов и битов соответственно.

<>Объекты <>VHDL<>.

Объекты выполняют роль хранения различных значений. Идентификаторы обязательно должны начинаться с буквы. Объекты должны быть объявлены перед использованием, за исключением переменной цикла в операторе for, которая объявляется по умолчанию.

Классы объектов:

-        Constant — константы.

-        Variable — переменные.

-        Signal — сигналы, представляют значения, передаваемые по проводам.

Синтаксисобъявленияобъектов:

Constant {name [, name]}: Type [(index_range [, index_range])]:= initial_value;

Variable {name [, name]}: Type [(index_range [, index_range])] [:= initial_value];

Signal {name [, name]}: Type [(index_range)];

<>Операторы <>VHDL<>.

Операторы в VHDL делятся на два типа:

-       Последовательные.

-       Параллельные.

<>Последовательные операторы включены в операторы процессов. В одной строке можно размещать несколько операторов. Все операторы в <>VHDL <>оканчиваются точкой с запятой.

<>Последовательные операторы включают в себя:

<>-                   <>Оператор присваивания — выполняет присваивание переменной или сигналу результата выражения.

<>\результат\:=\выражение\ — присваивания переменной.

<>\результат\<=\выражение\ — присваивание сигнала [3, <>c<>.52].

<>-                   <>Оператор ожидания события <>wait<>.

<>Синтаксис<>оператора<>:

<>\<>wait <>\::=<>wait [on\<>name signal<>\ {\<>name signal<>\}]

<>-                   <>Оператор <>if<> — оператор цепочки последовательных событий;

<>\<>if <>\::=<>if <>\<>условие <>\ <>then

<>{\<>последовательный оператор<>\}

<>endif

<>-                   <>Оператор <>case<> — <>оператор разрешения выполнения последовательных операторов.

<>\<>case <>\::=<>case <>\ <>повторное выражение <>\ <>is

<>when <>\<>альтернативы<>\ =>{\<>последовательный оператор<>\}

<>{<>when <>\<>альтернативы<>\ =>{\<>последовательный оператор<>\}}

<>end<>case

<>-                   <>Пустой оператор <>null<> — <>не выполняет никаких действий.

<>-                   <>Оператор повторения — выполняет повторение последовательных операторов.

<>\оператор повторения \::=

<>[<<>метка оператора повторения<>>:] [<<>итерационная схема<>>:] <>loop

<><оператор> <>«<><оператор ><>»

<>end<>loop <>[<<>метка оператора повторения<>>] [<>2<>];

<>Параллельные операторы.

<>Параллельные операторы выполняются при любом изменении сигнала. К параллельным операторам относятся [2]:

<>-                   <>Оператор параллельного присваивания<>;

<>-                   <>Параллельный вызов процедуры<>;

<>-                   <>Оператор процесса<>;

<>-                   <>Оператор блока<>;

<>-                   <>Оператор вхождения компонента<>;

<>-                   <>Оператор генерации<>;

<>-                   <>Параллельный оператор проверки<>;

Язык Verilog-HDL(Verilog).

Структура проекта.

Основной единицей языка является модуль. Элементами модуля являются декларации и операторы. Структура проекта выглядит следующим образом:

module<имя модуля> (<порт><>«, <><порт ><>»);

<>«<<>декларация<>> | <<>параллельный оператор<>>»

endmodule

Типы данных.

По сравнению с VHDL,вVerilog используется меньшее количество типов данных. Данные в Verilog могут принимать одно из четырех состояний:

-                   1 — представляет логическую 1 или значение «истинно» (true)

-                   0 — представляет логический 0 или значение «ложно» (false)

-                   z — представляет состояние высокого импеданса

-                   x — представляет неизвестное логическое состояние

Verilog включает две группы типов данных:

-                   Регистры (reg);

-                   Цепи (wire);

Регистры предназначены для сохранения состояний. Цепи осуществляют передачу состояний между моделируемыми объектами.

Типы цепей:

-                   Wire, tri — соединение элементов

-                   Wand/triand, wor/trior — моделирование цепей с разрешающей логикой

-                   Trireg — сохраняет свое состояние(емкость).

-                   Tri1, tri0, supply1,supply0. Цепи Tri1, tri0 — моделирование цепи с резистивной подтяжкой, а supply1,supply0 — моделируют источники питания подключенные к этой цепи.

Операторы Verilog.

Операторы в Verilog, как и в VHDL, делятся на два вида: последовательные и параллельные.

Оператор initialзапускается единожды при начале моделирования и задает начальное состояние устройства. Синтаксис данного оператора выглядит следующим образом:

< операция инициализации >::= initial< оператор >

Оператор always — оператор повторения. Запускается в начале программы так же как и initial,но повторяется каждый раз после завершения вложенного оператора. Синтаксис оператора имеет вид:

< операция постоянного повторения>::= always< оператор >

Операторы принятия решений — выбор одного из путей выполнения алгоритма. К операторам принятия решений относятся:

-                   Оператор условия

< оператор условия>:::=

if(<выражение>)<оператор>

-                   Оператор варианта

<оператор варианта>::=

<определитель оператора варианта>(<ключевое выражение>)

<>«<вариант><>«, <>< вариант >»:<<>оператор>»

<>Endcase

Порты Порты обеспечивают интерфейс, с помощью которого модуль может общаться с внешней средой. Например, входы ввода/вывода сигналов из микросхемы представляют собой ее порты. Среда может взаимодействовать с модулем только через порты модуля. Внутренняя организация модуля недоступна извне. Это обеспечивает проектировщику очень большие возможности, потому что внутренняя организация модуля может быть изменена, но это не затрагивает внешнюю, по отношению к модулю, среду до тех пор, пока интерфейс модуля не будет изменен. Порты модуля определяются следующим образом: после имени модуля в круглых скобках приводится список портов модуля так, как показано здесь: modulename( port_list ); Список портов Определение модуля содержит список портов. Если модуль не обменивается сигналами со средой, то у него нет списка портов. Порт в списке может быть выражен следующим образом: • идентификатор; • единственный бит, выбранный из вектора, объявленного в пределах модуля; • группа битов, выбранных из вектора, объявленного в пределах модуля; • конкатенация любого из вышеупомянутых (конкатенация — процесс объединения нескольких однобитовых или многобитовых операндов в один большой битовый век- тор. Для получения дополнительной информации см. раздел «Оператор конкатенации»). Каждый порт в списке должен быть объявлен как ввод, вывод или двунаправленный порт при помощи ключевых слов input, outputилиinout. Рассмотрим 4-битовый полный сумматор, который установлен в проекте верхнего уровня. Диаграмма для портов ввода/вывода показана на рис. 5. Обратите внимание на то, что проект Top — это проект верхнего уровня. На модуль fulladd4 входные сигналы поступают на порты a, b и c_in, а выходные сигналы, формируемые модулем, выдаются из него через порты sum и c_out. Модуль Top — модуль верхнего уровня в моделировании, и к нему нет необходимости передавать сигналы или получать их извне. Таким образом, этот модуль не имеет списка портов. НазваниямодуляиспискипортовдляобоихобъявлениймодулейвVerilogприведенывпримере 36. modulefulladd4(sum, c_out, a, b, c_in); //ModulewithalistofportsmoduleTop; // Nolistofports, top-levelmoduleinsimulationПример 36. Список портов для модулей Top и fulladd4

Стили описания — функциональное (поведенческое) и структурное Verilog является языком, который позволяет выполнять как функциональное или поведенческое, так и структурное описание. Структурные описания Элементами структурного описания в языке Verilog являются различные логические вентили, специфические библиотечные компоненты и компоненты, определяемые пользователем. Само структурное описание как таковое представляет собой набор компонентов, установленных в проект и связанных проводами. В простейшем случае структурное описание может рассмотриваться как простой netlist, в котором представлены установленные в проекте вентили, порты которых связаны проводами между собой. Однако, в отличие от списка связей (netlist), цепи в структурном описании могут быть также представлены в виде произвольных выражений, которые описывают то, как будет функционировать та или иная цепь. Такое назначение на цепь называют непрерывным назначением. Непрерывные назначения — удобное средство для связи между простыми списками связей (netlist) и функциональными описаниями. Структурное описание Verilog может содержать различные иерархические конструкции и конструкции уровня вентилей, а также определения модулей, установленные компоненты и подключения из netlist. Функциональное описание Функциональные элементы описания в языке Verilog — это, в основном, объявления функций, задачи — tasks и блоки — always. Эти элементы описывают функцию схемы, именно то, как она работает, но не описывают ее физическую сущность или размещение на кристалле. Выбор вентилей и компонентов оставляют полностью на усмотрение того программного инструмента, который будет проводить компиляцию проекта. Разработчик может создать описания с функциональными конструкциями Verilog. Эти конструкции могут появиться в пределах функций или блоков (always). Функции подразумевают только комбинационную логику, а блоки (always) могут подразумевать как комбинационную логику, так и триггеры, регистры или счетчики.

Директивы компилятора 'ifdef', `ifndef, `else, `elsif, `endif и `define

Условная компиляция — 'ifdef', `ifndef, `else, `elsif и `endif Условная компиляция проекта может быть выполнена при использовании директив компилятора 'ifdef', `ifndef, `else, elsif, и `endif. Для описания директив компилятора используется значок «`» апострофа. Директивы условной компиляции `ifdef и `ifndef могут находиться в любом месте проекта, они применяются для того, чтобы по требуемому условию выполнить компиляцию необходимых утверждений, модулей, блоков, объявлений и других директив компилятора. Директива `else является дополнительной, и только эта одна директива используется после `ifdef или `ifndef. Любое число директив `elsif может сопровождать директивы `ifdef или `ifndef. Но они всегда заканчиваются директивой `endif. Приведем пример условной компиляции (примеры 30, 31).

//Следующий фрагмент текста выполнится,

// если TEST определено

'ifdef TEST

moduletest;

... ...

Endmodule

// Этот фрагмент выполнится, по умолчанию,

// если TEST не определено

'else

... ...

Endmodule

'endif

Пример 30. Пример условной компиляции

moduletop;

... — выполняются безусловно

'ifdef A1 — выполняется, если A1 определено

... 'elsif A2 — выполняется, если A2 определено ...

'else — выполняется, по умолчанию ...

'endif 'ifndef A3 — выполняется, если A3 не определено ...

'endif

endmodule

Пример 31. Пример условной компиляции

Директива компилятора `define

Директива компилятора `define используется так же, как и в других языках программирования. Ее применение для описания текстового макроса можно представить следующим образом. Сначала выполняется определение макроса:

`definemy_clock @(posedgeclk);

А в коде программы делается так:

аlways `my_clock;

или

a<= `my_clock b;

Теперь, когда подготовительная часть описания пройдена, переходим к следующему разделу книги. Можно сказать, что мы выучили слова, теперь научимся складывать их во фразы. В своей книге [2, 3] ЖаникБергерон делает вот такие, очень важные для нас выводы: до 70% трудозатрат в проекте приходится на верификацию проекта. В дальнейшем мы еще вернемся к рассмотрению данного вопроса. А сейчас давайте обратимся к тому, как именно производится разработка проекта и какое место в ней занимает язык Verilog.

2.3

2.4

Непрерывное присваивание

То, что в Верилоге именуется «постоянным», или «непрерывным» присваиванием на самом деле всегда развертывается в комбинаторную схему. Непрерывное присваивание может встречаться в операторе assign, либо же прямо в декларации сигнала wire. Левой частью всегда является сигнал, правой — выражение, использующее любые другие сигналы. Значения регистровых переменных тоже являются сигналами. Примеры:

// регистр, содержащий семплированное значение входа strobe regstrobe_sampled; // декларация сигнала strobe_negedge wirestrobe_negedge; // непрерывное присваивание выражения сигналу strobe_negedge assignstrobe_negedge = ~strobe&strobe_sampled; // декларация и присваивание совмещенные в одном операторе wirestrobe_posedge = strobe& ~strobe_sampled;

3.1 автоматы конечные