Комбинационная логика: assign и оператор «всё сразу»
Учимся описывать логику без памяти, которая пересчитывается мгновенно при любом изменении входов.
Комбинационная логика — схема, выход которой зависит только от текущих значений входов (без памяти о прошлом); результат пересчитывается «сразу», как только меняется любой вход.
Всю цифровую логику делят на два класса: комбинационную (без памяти) и последовательностную (с памятью, тактируемую). Начнём с комбинационной — она проще и нагляднее всего показывает параллельную природу железа. Комбинационная схема — это чистая функция от входов: подали входы — мгновенно получили выход, никакой истории.
Непрерывное присваивание assign
Главный инструмент комбинационной логики — assign. Он создаёт непрерывную связь: левая часть всегда равна правой. Это не «вычислить один раз», а «провести провод, по которому значение течёт постоянно». Как только меняется любой вход справа, выход слева пересчитывается мгновенно (с точностью до физической задержки вентилей).
assign y = a & b; // y всегда равно a AND b
assign z = (a | b) & ~c; // z пересчитывается при изменении a, b или c
assign w = sel ? x : y; // условный оператор: мультиплексор (см. след. урок)Несколько assign в модуле работают параллельно и независимо — это разные куски железа. Порядок их записи не имеет значения.
Операторы Verilog
Важно различать два семейства операторов:
| Битовые (поразрядно над шинами) | Логические (дают 1 бит: истина/ложь) |
& И, | ИЛИ, ^ XOR, ~ НЕ | && И, || ИЛИ, ! НЕ |
Битовый & применяется к каждой паре битов шин (8'b1100 & 8'b1010 = 8'b1000), а логический && сводит операнды к «истина/ложь» и даёт один бит. Есть ещё операторы сравнения (==, !=, <, >), арифметические (+, -, *) и сдвиги (<< влево, >> вправо). Все они в комбинационном контексте описывают соответствующее железо: сравнение — компаратор, сложение — сумматор, сдвиг — переразводку проводов.
Как работает под капотом: всё происходит «сразу»
Ключевая интуиция: комбинационная схема не «выполняет шаги», она просто есть. Подайте на входы значения — и через крошечную задержку (пока сигнал пробежит по вентилям) на выходе появится результат. Промоделируем комбинационный модуль — побитовые операции над двумя 4-битными шинами — на Python, чтобы увидеть, что выходы зависят только от входов:
# Комбинационный блок: по входам a,b мгновенно считаем три выхода
def comb(a, b):
and_out = a & b # побитовое И
or_out = a | b # побитовое ИЛИ
xor_out = a ^ b # побитовое XOR
return and_out, or_out, xor_out
for a, b in [(0b1100, 0b1010), (0b1111, 0b0001), (0b0000, 0b1111)]:
aa, oo, xx = comb(a, b)
print(f"a={a:04b} b={b:04b} | AND={aa:04b} OR={oo:04b} XOR={xx:04b}")Вывод:
a=1100 b=1010 | AND=1000 OR=1110 XOR=0110 a=1111 b=0001 | AND=0001 OR=1111 XOR=1110 a=0000 b=1111 | AND=0000 OR=1111 XOR=1111
Никакого состояния: подали те же входы — получили тот же выход, всегда. Это и значит «без памяти». В железе три выхода считаются одновременно тремя группами вентилей.
Частые ошибки
- Путать
&и&&. Для поразрядных операций над шинами нужен битовый&; логический&&схлопнет шину в один бит. - Ждать «выполнения» assign по порядку. Все
assignактивны постоянно и параллельно; порядок строк роли не играет. - Создавать комбинационную петлю. Если
assign a = b;иassign b = a;зависят друг от друга без триггера, получится логический цикл — схема «зациклится» и станет нестабильной.
Итог
- Комбинационная логика — функция от входов без памяти; результат «сразу».
assignсоздаёт постоянную связь «выход всегда равен выражению».- Различайте битовые (
&,|,^) и логические (&&,||) операторы. - Избегайте комбинационных петель — они делают схему нестабильной.