Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Industrial programming >> Verilog

Понимание блоков always в Verilog: синтаксис и списки чувствительности

always блок — один из процедурных блоков в Verilog. Операторы внутри always выполняются последовательно.

Синтаксис

always @ (event) [statement]
always @ (event) begin [multiple statements] end

always блок выполняется при определённом событии. Событие задаётся списком чувствительности.

Что такое список чувствительности?

Список чувствительности — выражение, определяющее, когда должен выполняться always блок. Указывается после оператора @ в скобках ( ). Может содержать один или группу сигналов, изменение которых запускает блок.

В коде ниже все операторы внутри always выполняются при каждом изменении значений сигналов a или b.

// Выполнять always блок при изменении "a" или "b"
always @ (a or b) begin [statements] end

Для чего нужен always блок?

always блок может реализовывать комбинационные или последовательные элементы. Последовательный элемент (триггер) активируется при подаче такта и сброса. Комбинационный блок — при изменении одного из входов. Эти аппаратные блоки работают параллельно, независимо друг от друга. Связи между ними определяют поток данных. Для моделирования этого поведения always блок делается непрерывным процессом, который срабатывает и выполняет действие, когда сигнал в списке чувствительности становится активным.

В примере ниже все операторы внутри always выполняются на каждом положительном фронте сигнала clk.

// Выполнять always блок на положительном фронте "clk"
always @ (posedge clk) begin [statements] end

Что если нет списка чувствительности?

always блок повторяется непрерывно на протяжении всей симуляции. Список чувствительности привносит чувство времени: когда любой сигнал в списке меняется, блок срабатывает. Если внутри always нет операторов управления временем, симуляция зависнет из-за нулевой задержки бесконечного цикла!

Пример

Пример ниже — always блок, пытающийся инвертировать значение clk. Оператор выполняется каждые 0 единиц времени. Поэтому он выполняется вечно из-за отсутствия задержки.

// always блок стартует в момент 0
// Но когда он должен повторяться?
// Нет управления временем — останется и повторяется в 0 времени. Цикл — симуляция зависнет!
always clk = ~clk;

Даже если список чувствительности пуст, должна быть какая-то задержка. Время симуляции продвигается оператором задержки внутри always как показано ниже. Теперь инверсия такта происходит каждые 10 единиц времени.

always #10 clk = ~clk;

Примечание: Явные задержки не синтезируются в логические гейты!

Поэтому реальный Verilog-код дизайна всегда требует список чувствительности.

Пример проектирования последовательного элемента

Код ниже определяет модуль tff, принимающий вход данных, такт и активный-низкий сброс. Выход инвертируется, когда d равен 1 на положительном фронте такта. always блок срабатывает либо на положительном фронте clk, либо на отрицательном фронте rstn.

Что происходит на положительном фронте такта?

  1. Первый if проверяет значение активного-низкого сброса rstn.
    1. Если rstn ноль — выход q сбрасывается в 0.
    2. Если rstn единица — сброс не применён, следует стандартное поведение.
  2. Если предыдущий шаг ложен:
    1. Проверяется значение d, если 1 — инвертируется q.
    2. Если d = 0 — сохраняется значение q.
module tff (input d, clk, rstn, output reg q);
always @ (posedge clk or negedge rstn) begin
    if (!rstn) q <= 0;
    else if (d) q <= ~q;
    else q <= q;
end
endmodule

Что происходит на отрицательном фронте сброса?

  1. Первый if проверяет rstn. На отрицательном фронте его значение 0.
    1. Если rstn = 0 — сброс применён, выход сбрасывается в 0.
    2. Случай rstn = 1 не рассматривается, так как текущее событие — отрицательный фронт rstn.

Пример проектирования комбинационного элемента

always блок также можно использовать для комбинационных блоков. Например, цифровая схема из трёх гейтов, выдающая выход на сигнале o.

Код ниже — module с четырьмя входами и одним выходом o. always блок срабатывает при изменении любого сигнала в списке чувствительности. Выходной сигнал объявлен как reg в списке портов, потому что используется в процедурном блоке. Все сигналы в процедурном блоке должны быть reg.

module combo ( input a, b, c, d, output reg o);
always @ (a or b or c or d) begin
    o <= ~((a & b) | (c^d));
end
endmodule

Сигнал o становится 1, когда выражение справа истинно, 0 — когда ложно.

Нажмите для слайд-шоу с примером симуляции!

Verilog

  1. Освоение Verilog: полное руководство по проектированию цифровых схем
  2. Освоение конкатенации в Verilog: практическое руководство
  3. Основы Verilog: краткий обзор
  4. Понимание назначений в Verilog: типы, синтаксис и лучшие практики
  5. Блокирующие и неблокирующие назначения в Verilog: ключевые различия
  6. Мастерство функций в Verilog для эффективного RTL дизайна
  7. Понимание задач (Tasks) в Verilog: отличия от функций, синтаксис и применение
  8. Генератор тактового сигнала в Verilog: проектирование и реализация
  9. Мастерство математических функций Verilog для эффективного аппаратного дизайна
  10. Мастерство $timeformat в Verilog: точность и контроль отображения времени