Описание комбинационных схем в Verilog: условные операторы и блоки always
В статье объясняется, как моделировать комбинационную логику в Verilog, охватывая условный оператор для реализации таблиц истинности и мощный блок «always» для лаконичного описания.
В этом руководстве мы пройдемся по ключевым техникам описания комбинационных схем в Verilog. Сначала вспомним синтаксис непрерывного присваивания с ключевым словом assign, затем представим условный оператор (?:) как лаконичный способ выражения логики мультиплексора. Наконец, покажем, как блок always может дать еще более ясное процедурное описание.
Ранее мы рассматривали ключевое слово assign для непрерывных присваиваний. Эти операторы остаются активными и позволяют получить описание схемы на уровне гейтов. Например, следующий код моделирует элемент AND:
assign out1 = a & b;
Условный оператор Verilog позволяет одному присваиванию менять свое значение в зависимости от условия. Синтаксис:
assign [имя_сигнала] = [условное_выражение] ? [значение_если_истина] : [значение_если_ложь];
conditional_expression вычисляется первым. Если он истинно, value_if_true присваивается signal_name; иначе используется value_if_false. Например:
assign out1 = (sel) ? (a & b) : (a | b);
Когда sel истинно, AND от a и b управляет out1; иначе выбирается OR от a и b. Эта единственная строка реализует 2-к-1 мультиплексор.
Поскольку условный оператор ведет себя как оператор if в традиционном программировании, он позволяет более абстрактное представление комбинационной логики. Вкладывая оператор, можно строить сложные структуры, как показано в Примере 1.
Пример 1: Вложенные условные операторы
Ниже приведен 4-к-2 приоритетный кодер, реализованный с вложенными условными операторами. Таблица истинности показана на Рисунке 1.

Код Verilog:
module Prio_4_to_2 ( input wire [3:0] x, output wire [1:0] y, output wire v ); assign y = x[3] ? 2'b11 : x[2] ? 2'b10 : x[1] ? 2'b01 : 2'b00; assign v = ( x[3] | x[2] | x[1] | x[0] ) ? 1'b1 : 1'b0; endmodule
Строки 7–10 демонстрируют вложенный условный оператор. Каждое условие вычисляется последовательно, давая приоритет более ранним термам — идеально для приоритетной логики. Финальный assign для v использует побитовое OR, чтобы указать, высоко ли какой-либо вход.
Результаты симуляции в Xilinx ISE подтверждают поведение (Рисунок 2).

Рисунок 2. Симуляция Xilinx ISE приоритетного кодера.
Важно отметить, что условное выражение вычисляется по порядку, пока не найдено истинное условие; тогда соответствующее значение присваивается. Следовательно, эта конструкция лучше подходит для приоритетных сетей (Рисунок 3), чем для сбалансированных мультиплексоров (Рисунок 4).

Рисунок 3. Приоритетная сеть.

Рисунок 4. n-к-1 мультиплексор без приоритета входов.
В предыдущей статье мы обсуждали параллельные присваивания в VHDL; концепции аналогично переносятся на Verilog.
Процедурные операторы Verilog
Хотя assign и условные операторы достаточны для многих проектов, блок always предлагает более выразительный процедурный подход. Внутри блока always операторы выполняются последовательно и могут включать высокоуровневые конструкции вроде if и case, отражая естественный ход человеческого мышления.
Пример 2 демонстрирует базовый блок always для реализации простого элемента AND.
Пример 2: Операторы блока «Always»
Упрощенный синтаксис блока always:
always @(sensitivity_list) begin sequential_statements; end
sensitivity_list определяет, когда блок должен пересчитываться. Для чисто комбинационной схемы все входные сигналы должны присутствовать в этом списке.
Рассмотрим схему на Рисунке 5, где выход меняется при переключении a или b.

Рисунок 5. Circuit_1
Следующий блок always реализует операцию AND с блокирующим присваиванием:
always @(a, b) begin out1 = a & b; end
Блокирующие присваивания (=) обновляют левую часть немедленно, в то время как неблокирующие (<=) откладывают обновление до конца блока. Для комбинационной логики безопаснее использовать блокирующие присваивания, чтобы избежать нежелательных гонок.
Поскольку процедурный блок не может управлять wire, выход должен быть объявлен как reg, который может или не может выводить элемент хранения. Полный модуль показан ниже:
module Circuit_1 ( input wire a, input wire b, output reg out1 ); always @(a, b) begin out1 = a & b; end endmodule
Подводя итог, статья покрыла условный оператор для компактной логики таблиц истинности, вложенные операторы для приоритетного кодирования и процедурный блок always для более ясных комбинационных описаний. Будущие посты изучат использование always для последовательной логики.
Встроенный
- Основы Verilog: проектирование вашего первого И-шлюза
- Основы цепей постоянного тока: понимание прямого тока и базовых электрических концепций
- Понимание цепей переменного тока: Руководство для начинающих
- Проектирование четырехразрядного 7-сегментного дисплея с одним двоичным энкодером
- Управляющие цепи: основы, применение и лучшие практики
- Операторы C# — исчерпывающее руководство по операторам в C#
- Тернарный оператор в C#: краткое руководство по условным выражениям
- Освоение Verilog: полное руководство по проектированию цифровых схем
- Освоение конкатенации в Verilog: практическое руководство
- Условная компиляция в Verilog: `ifdef, `ifndef, `elsif