цифровая электроника
вычислительная техника
встраиваемые системы

 

Verilog. Базовый курс. Часть IV

Автор: Mike(admin) от 5-02-2014, 09:15

Циклы в Verilog


В предыдущей части мы на простом примере познакомились с принципом модульной конструкции в Verilog и создали RS-триггеры с помощью концепции модуля-экземпляра.


Но что нам делать, если потребуется создать много (например, 50) D-триггеров, которые должны быть соединены между собой в соответствии со схемой делителя частоты? Мы уже знаем, как сделать общий модуль для D-триггера, поэтому нужно сделать 50 экземпляров этого модуля и соединить входы тактового сигнала каждого модуля с выходом предыдущего, также подвести сигнал Сброс (Reset) ко всем модулям и вывод D через инверсию соединить с выходом Q. В общем, нужно сделать всё то, что показано на рисунке:


verilog

Вручную писать столько экземпляров (50 штук по 6 строк в каждом – 300 строк!) – не практично. Поэтому в Verilog для генерации большого числа одинаковых модулей мы можем воспользоваться циклом контроллера счетчика, который является чем-то вроде цикла for. Но, чтобы этот цикл работал правильно, мы должны тщательно продумать структуру делителя частоты.


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


Итак, поскольку каждый триггер (кроме первого) должен иметь вход, зависящий от выхода предыдущего, то мы можем все эти сигналы объединить в одну шину, что равносильно созданию массива в C/C++. Следует также учитывать, что D-вход каждого триггера зависит от выхода этого триггера. Еще не стоит забывать про общий сброс.


Но, во-первых, какой тип шины мы зададим? Поскольку шина просто переносит сигнал от источника к выходу, то это будет wire. Сделаем так:



wire in[49:0] //50-битная шина для входов триггеров
wire out[49:0] //50-битная шина для выходов триггеров

Быть может, вы захотите назвать эти шины Q и D, но не стоит этого делать, ибо нельзя давать имя одной части проекта при уже используемом таком имени другой частью проекта (Q и D являются портами модуля D-триггера).


Мы также можем создать экземпляр для нашего первого триггера:



dff dff0(
.clk(clk),
.rst(rst),
.D(in[0]),
.Q(out[0])
);

Не беспокойтесь об инвертировании сигнала, идущего на D-вход. Мы сделаем это позже. А сейчас сосредоточимся на создании цикла. Хотя он похож на цикл в C/C++, все же у него имеются некоторые отличия. Сначала мы должны создать переменную счетчика. В Verilog такой тип переменной называется «genvar», он используется для объявления переменной, например:



genvar y;

Цикл начинается с ключевого слова «generate» и заканчивается «endgenerate». Следует помнить, что объявление переменных с помощью genvar должно производиться вне тела цикла.



genvar y;
generate

endgenerate

После ключевого слова «generate» начинается область, отвечающая за работу цикла. Самому циклу не нужны никакие фигурные скобки «{}» как в C/C++, но тело цикла должно быть заключено между ключевыми словами «begin» и «end». Также нужно помнить, что Verilog не поддерживает специальные операции вроде инкремента y++, поэтому нужно делать так: y = y + 1. При создании цикла будем иметь ввиду, что мы уже создали первый (точнее нулевой) D-триггер, поэтому диапазон количества новых триггеров будет от 1 до 49 (<50).



genvar y;
generate
for(y = 1; y < 50; y = y + 1 )
begin

end
endgenerate

При создании цикла нам нужно после «begin» указать имя, начинаемого процесса. Это имя нужно для синтезатора цикла и не будет использоваться где-либо еще в нашей программе. При этом после «begin» ставится двоеточие и указывается это имя. Пусть оно будет «dff_generation», тогда получим:



genvar y;
generate
for(y = 1; y < 50; y = y + 1 )
begin : dff_generation

end
endgenerate

Итак, мы дошли до самой сложной части – создания модели экземпляра. Она будет похожа на стандартный экземпляр за исключением того, что в качестве подводимых к модулю сигналов будет использоваться переменная, объявленная как «genvar».



genvar y;
generate
for(y = 1; y < 50; y = y + 1 )
begin : dff_generation
//имя экземпляра не имеет значения в дальнейшем
dff dff_insts (
.clk(out[y-1]), //clk триггера под номером «y» является входом выхода «y-1»
.rst(rst), //общий сброс
.D(in[y]), //D-вход
.Q(out[y]) //выход
);
end
endgenerate

Нам не хватает только одного – инверсии на входе порта «.D». Ее можно применить ко всей шине, а не к отдельным сигналам:



assign in = ~in;

Итак, мы рассмотрели циклы в Verilog и собрали вполне полезную и работоспособную схему.




Часть I


Часть II


Часть III


Часть V


Часть VI




Перевод © digitrode.ru


<Источник>


Теги: Verilog, ПЛИС



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

Комментарии:

Оставить комментарий
Цитата
  • Группа: Гости
  • ICQ:
  • Регистрация: --
  • Статус:
  • Комментариев: 0
  • Публикаций: 0
^
По последнему примеру - а где обратная связь входа D-триггера с его выходом.
Наверное надо было написать в цикле :
assign in[y] = -out[y],

По последнему примеру - а где обратная связь входа D-триггера с его выходом.
Наверное надо было написать в цикле :
assign in[y] = -out[y],