Цикл while for verilog

Verilog за день часть 2.
Подождите, что-то знакомое? if, else, repeat, while, for, case – это конструкции Verilog, что выглядит в точности как и C (и, вероятно, любой другой язык, на котором вы привыкли программировать)! Но при функциональности по видимости, близкой, к языку C, Verilog является языком описания аппаратуры, таким образом, описание Verilog должно перевести к синтезу схемы. Это означает, что вы должны быть осторожны при использовании управляющих операторов (в противном случае ваши проекты могут быть не осуществима в оборудовании).
If-else
If-else конструкция, проверяет условие, и решает будет или нет выполнена часть кода. Если условие верно, код выполнится. Иначе выполнится другая часть кода.
Verilog Code:
// begin и end выполняют роль фигурных скобок в C/C++.
if (enable == 1’b1) begin
data = 10; // Десятичное присваивание
address = 16’hDEAD; // Шестнадцатиричное присваивание
wr_enable = 1’b1; // Двоичное присваивание
end else begin
data = 32’b0;
wr_enable = 1’b0;
address = address + 1;
end
Можно использовать любой оператор для проверки состояния, так-же как в языке C. В случае необходимости, можно использовать вложенные if-else выражения; выражение без else так же является нормальным, но такое выражение может вызывать проблемы, при создании комбинаторной логики такое выражение может приводить к созданию защелки (впрочем не всегда).
Case
Case инструкция используется, когда надо проверить одну переменную на множество условий. Это похоже на декодер адреса, где вход – адрес и он должен быть проверен на все возможные адреса, которые могут потребоваться. Вместо того, чтобы использовать многократно вложенный if, где в каждом условии проверяется одно состояние, мы используем case с единственным аргументом: это подобно оператору switch в языке C ++.
Конструкция Case начинается с зарезервированного слова case а заканчивается endcase (Verilog не использует скобки, чтобы разграничить блоки программы). Далее идет список состоящий из совпадающего значение, и через двоеточие выполняемого при совпадении действия. В конце каждого действия- точка с запятой. Также неплохой идеей является использование действия по умолчанию. Так же как автомат конечных состояний, Verilog попадает в неопределенное состояние при неучтенном значении. Введение действия по умолчанию, защищает нас от такой ситуации.
Verilog Code:
case(address)
0 : $display (“Сейчас 11:40 вечера”);
1 : $display (“Я чувствую себя сонным”);
2 : $display (“Побыстрее бы закончить это руководство”);
default : $display (“Я должен его закончить”);
endcase
Пусть address равняется 3, значит я должен закончить это описание.
Примечание: Общей чертой конструкций if-else и Case является то, что если вы не охватываете все случаи (отсутствие else у if-else и default у case) то это приводит к синтезу защелки.
While
Оператора while повторно выполняет код внутри тела цикла, до тех пор пока проверка условия возвращает true. Циклы while обычно не используются для модели в реальной жизни, но они используются для создания тестов. От других блоков операторов, тело цикла отделяется операторами begin и end.
Verilog Code:
while (free_) begin
$display (“продолжить веб-разработку”);
end
Пока переменная free_ имеет значение true, код между begin и end, будет выполнятся. В нашем случае печатать “продолжить веб-разработку”. Давайте посмотрит на этот странный пример, который использует большинство конструкций Verilog. Вы не ослышались. Verilog имеет меньше зарезервированных слов, чем vhdl, и в этом его большое преимущество в реальном написании кода. Это один из плюсов Verilog.
Verilog Code:
module counter (clk,rst,enable,count);
input clk, rst, enable;
output [3:0] count;
reg [3:0] count;
always @ (posedge clk or posedge rst)
if (rst) begin
count <= 0;
end else begin : COUNT
while (enable) begin
count <= count + 1;
disable COUNT;
end
end
endmodule
Приведенный выше пример использует большинство конструкций Verilog. Вы видите новый блок под названием always – это иллюстрация одной из ключевых особенностей Verilog. Большинство языков программного обеспечения, как уже говорилось, выполняют действия последовательно – то есть, одно действие идет за другим. Программы на Verilog, с другой стороны, многие инструкции, часто выполняет параллельно. Все блоки, помеченные always будут выполняться одновременно, когда одно или несколько условий, перечисленные в его описании выполняются.
В приведенном выше примере, блок “always” будет выполнятся, по положительному фронту сигналов rst или clk , то есть, когда сигнал меняется из 0 в 1. В программе Вы можете иметь два или больше блоков always выполняющихся одновременно (не показано здесь, но часто используется).
Мы можем отключить блок кода, используя зарезервированное слово disable. В приведенном выше примере после каждого приращения счетчика блок кода COUNT (здесь не показан) отключается.
For loop
Циклы for на Verilog организуются почти так же, как в C или C++. Разница лишь в том, что операторы ++ и — не поддерживаются в Verilog. Вместо написания i++ как в C, вы должны написать его полный операторный эквивалент, i = i + 1.
Verilog Code:
for (i = 0; i < 16; i = i +1) begin
$display (“Current value of i is %d”, i);
end
Этот код напечатает числа от 0 до 15 по порядку. Будьте осторожны при использовании циклов for для синтеза на уровне регистровых передач (RTL) как минимум убедитесь, что код на самом деле адекватно реализуется в оборудовании… и что ваш цикл не бесконечен.
Repeat
Repeat аналогичен только что рассмотренному циклу for. Вместо явного задания и увеличения переменной , как в объявлении цикла for, мы просто указываем программе, сколько раз запускать код, при этом никакие переменные не увеличиваются (конечно если мы не хотим их увеличивать, как в этом примере).
Verilog Code:
repeat (16) begin
$display (“Current value of i is %d”, i);
i = i + 1;
end
Результат точно такой же, как в предыдущем примере цикла for. Это относительно редкое использование оператора repeat (или цикла for) в реальной аппаратной реализации.
Итог
- While, if-else, case(switch) операторы такие же как и в языке Си.
- If-else и case операторы требуют описания всех вариантов.
- Цикл for такой же, как в C, но не поддерживает операторы ++ и –.
- Repeat такой же, как и цикл for, но без увеличения переменной.
В цифровом синтезе существует два типа элементов, комбинационные и последовательные. Конечно, мы знаем, что это такое. Но остается вопрос: “Как мы можем моделировать это в Verilog?”. Verilog предоставляет два способа моделирования комбинационной логики и только один путь к моделированию последовательной логики.
- Комбинаторные элементы могут быть смоделированы с помощью блоков “as” и “always”.
- Последовательные элементы могут быть смоделированы только с использованием блокаа “always”.
- Существует третий блок операторов, который используется только при написании тестов: Начальное объявление.
Блок начальной инициализации
Начальная инициализация, как следует из названия, выполняется только один раз, при старте моделирования. Это полезно при написании тестов. Если у нас есть несколько блоков начальной инициализации, то все они выполнены в начале моделирования.
Пример
Verilog Code:
initial begin
clk = 0;
reset = 0;
req_0 = 0;
req_1 = 0;
end
В приведенном выше примере, в начале моделирования (т. е. при времени = 0), все переменные внутри блока begin / end установятся в ноль. Важно понимать, что на реально синтезируемую схему блок начальной инициализации влияния не оказывает.
Источник
При описании цифровых устройств дополнительные (к операторам) возможности разработчику предоставляют циклы. В Verilog существуют четыре типа циклов: while, for, repeat и forever. Все циклы можно использовать только внутри блоков always и initial.
Цикл while предназначен для выполнения одного или группы операторов, следующих за ним. Операторы выполняются до тех пор, пока записанное в цикле условие верно. В качестве условия может быть использован любой оператор параграфа 7.4, т.е. такой, результатом выполнения которого является однобитная величина.
Конструкция цикла while имеет следующий вид: while (<условие>) begin
<группа операторов> end
Например: always@ (a,b) while (a < b) begin
y1 = 1′b1; y2 = 1′b0;
end
Цикл for дает возможность инициализировать, проверять и увеличивать переменную явным способом.
Конструкция цикла for имеет следующий вид:
for (<инициализация, начальное назначение переменной>;
<условие продолжения(проверка)>; <оператор, указывающий способ увеличения переменной>) begin
<группа операторов>; end
Операторы выполняются, пока условие продолжения истинно. Увеличение переменной выполняется в конце каждого прохода цикла.
Например: integer [31:0] list; integer index; initial begin
for (index = 0, index < 31; index = index + 1) list [index] = index + index;
end
Цикл repeat – это цикл с заданным числом повторений. Он выполняется конечное число раз.
Конструкция цикла имеет следующий вид: repeat (<условие>) begin
<группа операторов>; end
Здесь условие может быть константой или выражением (значение выражения вычисляется при первом прогоне цикла), но обязательно целым числом.
Например: integer count; reg [127:0] a; initial begin
count = 128; repeat (count)
begin
PDF created with FinePrint pdfFactory Pro trial version https://www.fineprint.com
count = count – 1; a [count] = count/2;
end end
Цикл forever называется вечным циклом. Следующие за ним операторы (или оператор) выполняются непрерывно, пока не поступит команда $finish, т.е. до конца моделирования.
Конструкция цикла forever имеет следующий вид: forever begin
<установка> <группа операторов> end
Например: initial begin
a = 2; b = 4; forever begin
# 5 a = a + b; b = a – 1; end // forever
end // initial
В этом примере указано, что каждые 5 заданных временных единиц надо вычислять a
иb и делать это до тех пор, пока моделирование не будет остановлено командой $finish. Приведем еще один пример:
reg clk; initial begin
clk = 1′b0;
# 100 forever # 5 clk = ~ clk; end
initial # 200 $finish;
Эта запись означает, что в течение 100 единиц заданного модельного времени сигнал clk не меняется и равен 0. Затем в период от 100 до 200 единиц он должен менять свое значение на противоположное каждые 5 временных единиц.
PDF created with FinePrint pdfFactory Pro trial version https://www.fineprint.com
Глава 9. Верификация в Verilog
В языке Verilog предусмотрены различные возможности для организации верификации (проверки, контроля) проекта.
9.1. Формирование начальных значений входных воздействий
Работоспособность проекта (в том числе алгоритмов, устройств) должна быть проконтролирована на соответствие техническому заданию (определенному, например, в виде таблицы истинности). Поэтому в ходе проверки входным портам присваиваются все возможные значения (далее – входные воздействия или сигналы), отображающие реальные варианты работы.
Все входные воздействия формируются в тестовом модуле. Они задаются с помощью
базовых блоков: | ||
initial | always | |
begin | и | begin |
……………. | ……………. | |
end | end |
Блок initial выполняется с начала моделирования, поэтому в нем производится инициализация сигналов, т.е. задание начальных значений. Приведем несколько примеров:
1. initial begin a0 = 0; a1 = 0; d0 = 0;
……………..
d3 = 0; end
2.Те же сигналы в векторной форме: initial begin
a = 2′b00; // допускается a = 0; или a = 2′ d0; d = 4′b0000;
end
3.Те же сигналы с использованием конкатенации: initial
{a0, a1, d0,…, d3} = 6′b000_000;
Итак, установлено значение входных сигналов в момент старта моделирования (t = 0). Далее проект проверяется во времени (временной контроль).
9.2. Временной контроль
Для анализа поведения объекта в процессе работы в языке Verilog предусмотрены три варианта временного контроля: с использованием задержек (delay), событий (event) и списка чувствительности.
PDF created with FinePrint pdfFactory Pro trial version https://www.fineprint.com
Задержка обозначается символом # и означает время либо между сменой входных сигналов, либо между поступлением сигнала на вход элемента или модуля и появлением результата на его выходе.
В первом случае задержка применяется в тестовом модуле для задания поведения входных воздействий во времени и указывается в следующем формате:
# <τ> <одна из трех конструкций операторов, указанных в предыдущем разделе>; Здесь τ может быть числом (целым или действительным), параметром, постоянной
или переменной величиной или, наконец, функцией. Например:
initial begin
#10 a = 1; // выполняется в момент t = 10
#2.5 b = 2; // выполняется в момент t = 12.5
#b/2 c = a; // выполняется в момент t = 13.5
#prm c = 4; // выполняется в момент t = 13.5 + prm
end
Возможны и другие конструкции тех же записей: initial begin
a = # 10 1; b = # 2.5 2;
……………………….
end
Время измеряется в тех единицах, которые определяются в директиве `scale.
В качестве примера задания поведения входных воздействий во времени можно привести описание сигналов в тестовом модуле для сумматора (параграф 4.3):
initial begin
#10 a = 1; // выполняется в момент t = 10
#2 b = 0; // выполняется в момент t = 12
end
Входные воздействия задаются в тестовом модуле, в основном с помощью оператора блокирующего присваивания (=). Однако может применяться и оператор неблокирующего присваивания (<=). Приведенная запись с этим оператором будет иметь другой смысл:
initial begin
#10 a <= 1; // выполняется в момент t = 10
#2 b <= 0; // выполняется в момент t = 2
end
Задержка может применяться при описании встроенных примитивов, а также в конструкции as.
Например:
nor # 2 mynor (out, in1, in2);
as # 5 out = (cntrl = 4′b0111) ? 1 : 0;
Эта форма временного контроля и две следующие применяются во всех модулях, описывающих устройство (базовых, субмодулях, редко – в головном модуле).
При событийном контроле происходит вычисление результата при каждом изменении входных сигналов.
Например, запись
@ (clk) a = b;
означает, что при каждом изменении тактового сигнала clk (это и есть событие) выполняется a = b. Данная запись относится к группе конструкций блока always.
Приведем еще примеры событийного контроля: @ (negedge clk) a = b;
a = @ (negedge clk) b;
PDF created with FinePrint pdfFactory Pro trial version https://www.fineprint.com
Источник
Источник: https://matrix.etseq.urv.es/manuals/matlab/toolbox/commblks/windowedintegrator.html
Не так давно мы познакомились с обыкновенным интегратором, состоящим из регистра аккумулятора и сумматора. Исследования его амплитудно-частотной характеристики показали, что интегратор является фильтром нижних частот (ФНЧ), однако его главное предназначение это накопление постоянной составляющей сигнала. Свойство накопления мы уже использовали при создании управляемого генератора синусоидальных колебаний. Движемся дальше.
Что такое оконный интегратор?
Если ранее рассмотренный интегратор суммирует между собой бесконечное число отсчетов, то
оконный интегратор занимается сложением между собой ограниченного числа подряд идущих отсчетов.
Это самое число отсчетов, попадающих в сумму называется окном интегрирования. Такой интегратор состоит из регистра сдвига, сохраняющего в себе складываемые отсчеты и сумматоров.
Устройство оконного интегратора. Длина окна 4.
Устройство оконного интегратора. Длина окна 4.
Оконный интегратор является очень важным фильтром и польза его в том, что он “сглаживает” сигнал. Понять это довольно не сложно. Как мы ранее выяснили, у последовательности цифровых отсчетов сигнала существует такая характеристика как среднее значение, так и дисперсия. Благодаря тому, что интегратор складывает несколько подряд идущих отсчетов, выходной сигнал на низкой частоте будет явно усиленным, однако в то-же самое время, всякие отклонения отсчетов от некоторого среднего будут сглажены. Дисперсия выходного сигнала уменьшается. Такое происходит только потому, что в расчет берется не каждый отсчет по отдельности, а их совокупность, где аномальные действия одного компенсируются коллективным поведением других.
Реализация на ПЛИС
Рассмотренные ранее синтаксические конструкции языка Verilog позволяют без особого труда собрать в единое целое цепочку регистров для организации окна с движущимися отсчетами, да и сумматоры не вызовут затруднений. Все станет гораздо интереснее если за задачу мы возьмемся с твердым намерением создать абсолютно параметризируемый модуль. Начинаем, входы и выходы:
В данном модуле разрядность отсчетов 16 бит, длина окна интегрирования 4 . Входной отсчет x, результат на выходе y.
Для хранения сдвигающихся внутри отсчетов нам пригодятся регистры (delay), а также шины проводов (sum), которые свяжут между собой сумматоры в цепочку. Как мы понимаем, за не имением сумматора на 4 слагаемых, нам прийдется размещать обычные 2-х входовые сумматоры каскадом.
Цикл for
Поскольку было заявлено о создании параметризированного устройства, прийдется описывать взаимосвязи всех внутренних блоков в общем виде через формулы. Поможет нам в этом синтаксическая конструкция языка Verilog, предоставляющая возможность циклического описания внутреннего устройства модуля.
Цикл for служит для описания повторяющихся фрагментов схемы, когда количество этих элементов известно. В других языках обычно это означает пошаговое выполнение действий в теле цикла. Однако, сейчас будет все совсем не так.
Как и в других языках нам пригодится переменная цикла и декларируется она ключевым словом genvar.
Количество итераций цикла задается как начальным состоянием переменой цикла (i=0), так и конечным ее значением (i<SIZE-1), а также шагом (i=i+1).
Все итерации цикла это описание абсолютно параллельных друг другу операций.
В данном случае мы описали как по переднему фронту тактового сигнала clk следующий регистр delay забирает значение из предыдущего. Тут
необходимо внимательнейшим образом проследить корректность всей конструкции, особенно в крайних состояниях при начальном и конечном состоянии переменной цикла.
Это мы описали сдвиговый регистр, но еще отсутствует та часть, где в нулевой регистр заходит отсчет со входа устройства. Дописываем:
Осталось приложить несколько сумматоров и соединить их каскадно один за другим:
Необходимо отметить, что нулевой сумматор (sum[0]) складывает содержимого нулевого и первого регистров. Далее соединения сумматоров происходят каскадно в цикле. На выход интегратора отправляется последняя сумма в каскаде (sum[SIZE-2]).
Если все сделали корректно, то мы изрядно сэкономили на лишней писанине (особенно при большом значении итераций цикла). В качестве рекомендации – чтоб эта синтаксическая конструкция побыстрее перестала взрывать мозг необходимо с карандашом и листом бумаги разобрать этот пример, нарисовав при этом общую схему устройства.
Что получилось?
После синтеза устройства из его описания получаем вот что:
Схема получившегося оконного интегратора с длиной окна 4
Схема получившегося оконного интегратора с длиной окна 4
Оконный интегратор образуется путем последовательного соединения регистров, в которых сдвигаются отсчеты. На выход этого интегратора отправляется сумма всех отсчетов в окне, которая вычисляется несколько каскадно соединенными сумматорами.
Характеристика фильтра
Рассмотрим амплитудно-частотную характеристику оконного интегратора (АЧХ). Длина окна 4. До проведения лабораторных экспериментов нам поможет только Google. Зависимость амплитуды выходного сигнала фильтра от частоты входного сигнала изображена на рисунке ниже.
Амплитудно частотная характеристика (АЧХ) оконного интегратора
Амплитудно частотная характеристика (АЧХ) оконного интегратора
На первый взгляд АЧХ оконного интегратора резко контрастирует с той, которую мы получили при исследовании простого интегратора. Однако, возникает вопрос – а что будет с характеристикой, если мы будем увеличивать длину окна? Чутье подсказывает, что при увеличении количества складываемых отсчетов мы должны приближаться к характеристикам простого интегратора, где число слагаемых – “бесконечность”. Нужно обязательно это проверить.
Предстоит серия экспериментов и на наше счастье имеется созданный ранее стенд для исследования цифровых устройств. Кроме того, теперь не нужно генерировать входную синусоиду программно. Чуть ранее у нас появился управляемый генератор гармонических колебаний, работающий по алгоритму CORDIC.
Поддержите статью лайком если понравилось и подпишитесь чтобы ничего не пропускать.
Также не обойдите вниманием канал на YouTube. Подписки и лайки будут приятным ответом от аудитории.
Источник