Введение
Мечта каждого разработчика не знакомого с Verilog, разобраться в нем за один день, по крайней мере так, чтобы начать применять его на практике. Следующие несколько страниц - моя попытка сделать эту мечту реальностью. Будет представлена теория и примеры, дополненные некоторыми упражнениями. Эта обучающий курс предназначен для разработчиков с опытом проектирования цифровых систем. Несмотря на то, что Verilog выполняет различные кодовые блоки одновременно, в противоположность последовательному выполнению команд большинством языков программирования, все же есть много одинаковых принципов. Также будут полезны познания в разработке цифровых схем.
До появления Verilog, разработка цифровых схем велась исключительно с помощью схематического проектирования. Каждый проект, независимо от сложности, был разработан через схемотехнику. Такие проекты было трудно проверить это приводило к долгим, утомительным циклам проектирования/проверки...
Когда появился Verilog, у нас внезапно поменялось представление о проектировании логических схем. Цикл проектирования Verilog больше походит на традиционное программирование, и этот цикл статей поможет Вам разобраться с основными этапами проектирования. Вот эти этапы:
- Технические требования (спецификация)
- Проектирование высокого уровня
- Проектирование низкого (микро) уровня
- Кодирование RTL (УМП)
- Проверка
- Синтез.
Сначала идут технические требования - каковы ограничения и требования, которые мы накладываем на нашу разработку? Что мы пытаемся спроектировать? В этой обучающей статье мы будем строить арбитра, управляющего двумя агентами: устройство, которое выбирает среди двух агентов, конкурирующих за право быть ведущим. Вот некоторые спецификации, которые мы могли бы описать.
- Арбитр управляющий двумя агентами.
- Активный высокий асинхронный сброс.
- Фиксированный приоритет, агентом 0 имеет приоритет над агентом 1.
- Преимущество удерживается до конца запроса.
Как только мы описали спецификацию, мы можем создать блок-схему, которая является абстракцией потока данных через систему (что входит или выходит из черных ящиков?). Так как примером, который мы взяли, является простым, мы можем создать блок-схему как показано ниже. Мы не говорим о том, что содержится в "волшебных" черных ящиках.
Блок-схема арбитра
Если бы мы проектировали эту систему без Verilog, то стандартная процедура продиктовала бы нам , что нужно использовать машину состояний. Следовательно, мы сделали бы таблицу истинности с изменениями состояния для каждого перехода. После этого мы использовали бы карты Карно, и с их помощью могли получить оптимизированную схему. Этот метод работает просто великолепно для маленьких проектов, но с большими проектами этот подход становится сложным и провоцирует ошибки. Это тот случай, когда альтернативным подходом является использование Verilog.
Проектирование низкого уровня
Чтобы увидеть, как с помощью Verilog спроектировать нашего арбитра, давайте вернемся к нашей машине состояний- теперь мы займемся разработкой низкого уровня. Мы рассмотрим как на черный ящик с предыдущей диаграммы, влияют наши входы.
Каждый из кругов представляет состояние, в котором может находится машина. Каждое состояние соответствует выходу. Стрелки между состояниями - изменения состояния, события, которые вызывает переход из одного состояния в другое. Например, крайняя левая оранжевая стрела означает, что, если машина находится в состоянии GNT0 (при котором сигнал GNT0 равен логической единице) и получает на вход req_0 сигнал логического нуля, машина переходит в состояние ожидания и производит соответствующий сигнал. Эта машина состояний описывает всю логику системы, которую мы будем описывать. Следующим шагом станет описание нашей машины состояний на Verilog.
Модули
Мы должны будем немного прерваться, и рассказать о модулях Verilog. Если Вы смотрите на блок схему арбитра на первом рисунке, то увидим, что модуль имеет имя ("арбитр") и порты ввода/вывода (req_0, req_1, gnt_0, и gnt_1).
Так как Verilog - HDL (язык описания аппаратных средств - используемый для концептуального проектирования интегральных схем), то он должен иметь такое средство как модули. В Verilog мы называем наш "черный ящик" модулем. Module - зарезервированное слово в рамках языка, используется, для описания объектов с входами, выходами и внутренней логикой работы; модули - грубые эквиваленты функций с возвращаемым результатом на других языках программирования.
Код модуля "арбитр"
Если Вы посмотрите на блок арбитра, то увидите, что есть стрелки, (приходящие для входов и уходящие для выходов). В Verilog, после того, как мы объявили имя модуля и названия портов, мы можем определить направление каждого порта. (примечание: В Verilog 2001 мы можем определить порты и направления порта в объявлении модуля), пример показан ниже.
Verilog Code:
module arbiter ( // Два слэша создают строку комментария. clock , // clock reset , // Active high, syn reset req_0 , // Request 0 req_1 , // Request 1 gnt_0 , // Grant 0 gnt_1 // Grant 1 ); //-------------Входящие порты----------------------------- // Примечание : все команды заканчиваются точкой с запятой input clock ; input reset ; input req_0 ; input req_1 ; //-------------Выходящие порты---------------------------- output gnt_0 ; output gnt_1 ;
Здесь у нас представлено только два типа портов, входящие и выходящие. В реальной жизни у нас также могут быть двунаправленные порты. Verilog позволяет нам определять двунаправленные порты директивой "inout".
Пример двунаправленных портов -
inout read_enable; //двунаправленный порт
Как Вы определяете векторные сигналы (сигналы, составленные из последовательностей больше одного бита)? Verilog обеспечивает простой способ определить такие сигналы.
Пример определения вектора -
inout [7:0] address; //двунаправленный 8 битный порт "address"
Примечание: выражение [7:0], использует прямой порядок бит - самый младший бит находится справа, самый старший находится слева. Если бы мы написали [0:7], мы использовали бы обратный порядок бит и они увеличивались слева направо. Порядок бит - чисто произвольный способ решить, в каком порядке выстроятся ваши данные, в разных системах используется разный порядок слов, таким образом важно выбрать правильный порядок бит для совместимости с существующими системами. Как аналогия, представьте разные языки: (английский), в котором буквы написаны слева направо (прямой порядок) в других (арабский язык), написание букв справа налево (обратный порядок). Знание того, как надо читать буквы, крайне важно для понимания слов, но направление букв было выбрано произвольно, много лет назад.
Итог
Мы изучили, как объявить блок/модуль в Verilog.
Мы изучили, как объявить порт и его направление.
Мы изучили, как объявлять векторные/скалярные порты.
Типы данных
Какое отношение имеют типы данных к аппаратным средствам? Фактически никакое. Люди просто хотели следовать традициям языков программирования. Но в нашем случае типы данных имеют другой смысл.
Verilog имеет два вида драйверов.
(Драйверы? Что это такое ?)
Драйвер это тип данных, который может управлять нагрузкой. В принципе, в физическом цепи, драйвером будет нечто, что может проводить электроны.
Драйвер, который может сохранять значение (пример: триггер).
Драйвер, который не может сохранять значение, но соединяет две точки на схеме (пример: провод).
Первый тип драйвера называют reg в Verilog (сокращение от "регистр"). Второй тип данных называют wire (просто "провод"). Вы можете обратиться к описанию языка, чтобы получить более подробную информацию.
Есть много других типов данных - например, регистры могут быть знаковые, без знаковые, с плавающей запятой... как новичок, не вдавайтесь в подробности прямо сейчас.
Примеры:
wire and_gate_output;//"and_gate_output" - провод "and_gate_output"
reg d_flip_flop_output;//"d_flip_flop_output" - регистр "d_flip_flop_output"
reg [7:0] address_bus;//"address_bus" - 8 битный регистр с прямым порядком бит
Резюме
- Тип данных wire используется для соединения двух точек.
- Тип данных reg используется для хранения данных.
- Существуют другие типы данных. Вы познакомитесь с ними позже.
Операторы
Операторы Verilog, к счастью, имеют тот же самый смысл, что и в других языках программирования. Они берут два значения и выполняют действия между ними, что приводит к третьему результату - например: - сложение, сравнение, логические операторы. Чтобы облегчить нашу жизнь, почти все операторы (по крайней мере, те что в списке ниже) являются точно такими же, как и их коллеги в языке программирования C.
Тип оператора |
Обозначение |
Действие |
Арифметические |
* |
Умножение |
|
/ |
Деление |
|
+ |
Сложение |
|
- |
Вычитание |
|
% |
Модуль |
|
+ |
Унарное сложение |
|
- |
Унарное вычитание |
Логические |
! |
Логическое отрицание |
|
&& |
Логическое И |
|
|| |
Логическое ИЛИ |
Отношения |
> |
Больше |
|
< |
Меньше |
|
>= |
Больше или равно |
|
<= |
Меньше или равно |
Равенство |
== |
Равно |
|
!= |
Не равно |
Редукция |
~ |
Побитовое отрицание |
|
~& |
Побитовое НЕ-И |
|
| |
Побитовое ИЛИ |
|
~| |
Побитовое НЕ-ИЛИ |
|
^ |
исключающее ИЛИ |
|
^~ |
инверсное исключающее ИЛИ |
|
~^ |
инверсное исключающее ИЛИ |
Сдвиг |
>> |
Сдвиг вправо |
|
<< |
Сдвиг влево |
Конкатенация |
{ } |
Конкатенация |
Условный оператор |
? |
Условный оператор |
Примеры -
a = b + c; //Ну тут вcе понятно
a = 1 << 5; //Сдвинуть '1' на 5 положений влево и сохранить в a.
a = !b; // Инвертировать b и сохранить в a
a = ~b; //Многократное присваивание может вызвать ошибку.
Резюме
Операторы Verilog очень похожи на такие же в языке C.