Визуальная электроника

Блоки "Always"

Как предполагает само название, блок “always” выполняется всегда, в то время как блок “initial” выполняется лишь один раз (в начале симуляции). Вторым различием является тот факт, что блок “always” должен содержать список чувствительности или задержку, связанную с ним.

Список чувствительности говорит блоку “always”, когда выполнять блок кода, как показано на рисунке ниже. Символ @ после зарезервированного слова “always” отображает тот факт, что блок будет применен в случае условия вставки скобок после символа @. Важное примечание касательно блока “always”: он не может работать с типом данных wire, но работает с типами данных reg и integer.

Verilog Code:
  1. always @ (a or b or sel)
  2. begin
  3. y = 0;
  4. if (sel == 0) begin
  5. y = a;
  6. end else begin
  7. y = b;
  8. 8 end
  9. 9 end

Пример выше представляет собой мультиплексор 2:1 со входными параметрами a и b; sel – сигнал выбора, а у – выход мультиплексора. При любой комбинационной логике, выходной параметр меняется тогда, когда меняется входной параметр. Эта теория при применении к блокам “always” означает тот факт, что код внутри блоков “always” должен выполняться каждый раз, когда меняются переменные на входе (либо управляющие переменные на выходе). Эти переменные включены в список чувствительности под названием a, b и sel. Существует два типа списка чувствительности: чувствительный к уровню (для комбинационных цепей) и чувствительный к фронту (для триггеров). Код ниже представляет собой все тот же мультиплексор 2:1, но выходной параметр у уже выступает в качестве выхода триггера.

Verilog Code:
  1. always @ (posedge clk )
  2. if (reset == 0) begin
  3. y <= 0;
  4. end else if (sel == 0) begin
  5. y <= a;
  6. end else begin
  7. y <= b;
  8. end

При нормальных условиях мы должны возвращать триггеры в исходное положение, следовательно, каждый раз, когда счетчик делает переход от 0 на 1 (posedge), мы проверяем инициацию сброса (синхронный сброс). Затем, продолжаем работу с обычной логикой. Если посмотреть внимательнее, то можно увидеть, что в случае комбинационной логики мы имеем "=" для присвоения, а для последовательного блока мы имеем оператор "<=".

Таким образом, "=" представляет собой блокирующее присваивание, а "<=" – неблокирующее присваивание. "=" выполняет код последовательно внутри цикла begin / end, в то время как неблокирующее "<=" выполняет код параллельно. Мы можем иметь блок “always” без списка чувствительности, но в этом случае нам потребуется задержка, как показано в коде ниже.

Verilog Code:
  1. always begin
  2. #5 clk = ~clk;
  3. end

#5 перед предложением задерживает его выполнение на 5 единиц времени.

Присваивание состояния

Присваивание состояния используется для моделирования только комбинационной логики, и выполняется непрерывно. Таким образом, присваивание состояния называется “непрерывным присваиванием состояния”, так как отсутствует список чувствительности.

Verilog Code:
  1. assign out = (enable) ? data : 1'bz;

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

Verilog Code:
  1. assign out = data;

Настоящий пример представляет собой простой буферный элемент.

Задачи и функции

При повторении аналогичных старых операций вновь и вновь, язык Verilog, как и любой другой язык программирования, предоставляет средства для вызова повторенного кода, это и называется “Задачи и Функции”. Хотелось бы иметь что-то похожее для веб-страниц, просто для вывода содержимого этого языка программирования вновь и вновь. Приведенный ниже код используется для проверки на четность.

Verilog Code:
  1. function parity;
  2. input [31:0] data;
  3. integer i;
  4. begin
  5. parity = 0;
  6. for (i= 0; i < 32; i = i + 1) begin
  7. parity = parity ^ data[i];
  8. end
  9. end
  10. endfunction

Функции и задачи имеют один и тот же синтаксис; единственным различием является тот факт, что задачи могут иметь задержки, в то время как функции не могут иметь каких-либо задержек. Это означает, что функция может использоваться для моделирования комбинационной логики. Вторым различием является возврат значения функциями, чего не могут сделать задачи.