Мультиплексоры, таблицы истинности и базовые вентили

Собираем классические комбинационные блоки — вентили и мультиплексор — и связываем их с таблицами истинности.

Мультиплексор (MUX) — комбинационный «переключатель»: по управляющему сигналу select он пропускает на выход один из нескольких входов.

Комбинационная логика строится из базовых вентилей — И, ИЛИ, НЕ, XOR. Любую булеву функцию можно задать таблицей истинности (что на выходе для каждой комбинации входов) и реализовать вентилями. В этом уроке соберём важнейший комбинационный блок — мультиплексор — и увидим, что одну схему можно описать несколькими способами.

Базовые вентили и их таблицы

Напомним таблицы истинности базовых вентилей (фундамент из курса «Логика и булева алгебра»):

a b | AND  OR  XOR | a | NOT
----+--------------+ --+----
0 0 |  0    0   0  | 0 |  1
0 1 |  0    1   1  | 1 |  0
1 0 |  0    1   1  |
1 1 |  1    1   0  |

В Verilog они выражаются операторами напрямую: assign y = a & b; (И), a | b (ИЛИ), a ^ b (XOR), ~a (НЕ). Синтезатор сам подберёт, как уложить это в LUT.

Мультиплексор: переключатель сигналов

Мультиплексор 2-в-1 пропускает на выход y либо a, либо b — в зависимости от управляющего бита sel. Его таблица проста: при sel=0 выход равен a, при sel=1 — равен b. В Verilog его можно описать тремя эквивалентными способами:

// Способ 1: условный (тернарный) оператор
assign y = sel ? b : a;

// Способ 2: булева формула из вентилей
assign y = (~sel & a) | (sel & b);

// Способ 3: процедурный блок с case (комбинационный always)
always @(*) begin
    case (sel)
        1'b0: y = a;
        1'b1: y = b;
    endcase
end

Все три после синтеза дадут одинаковое железо — мультиплексор. Выбор способа — вопрос читаемости. Тернарный оператор компактен для 2-в-1; case удобнее для мультиплексоров на много входов.

Как работает под капотом

Промоделируем мультиплексор 4-в-1, где 2-битный sel выбирает один из четырёх входов. Это раскрывает идею «адресации» входов управляющим кодом:

# MUX 4-в-1: 2-битный sel выбирает один из входов d0..d3
def mux4(d0, d1, d2, d3, sel):
    inputs = [d0, d1, d2, d3]
    return inputs[sel]            # sel как индекс выбирает нужный вход

d = [0, 1, 0, 1]   # d0=0, d1=1, d2=0, d3=1
print("sel | выбранный вход -> y")
print("----+------------------")
for sel in range(4):
    y = mux4(d[0], d[1], d[2], d[3], sel)
    print(f" {sel:02b} |   d{sel}={d[sel]}        -> {y}")

Вывод:

sel | выбранный вход -> y
----+------------------
 00 |   d0=0        -> 0
 01 |   d1=1        -> 1
 10 |   d2=0        -> 0
 11 |   d3=1        -> 1

Управляющий код sel работает как адрес: его значение прямо указывает, какой вход попадёт на выход. В железе мультиплексор 4-в-1 — это дерево из трёх MUX 2-в-1, и именно из таких переключателей, кстати, частично построена матрица соединений FPGA.

Частые ошибки

  • Неполный case без default. Если в комбинационном always не покрыты все варианты sel, синтезатор может вывести нежелательную защёлку (latch). Добавляйте default или else.
  • Перепутать ветви тернарного оператора. В sel ? b : a при истинном sel выбирается b (первая ветвь), при ложном — a. Легко спутать порядок.
  • Думать, что разные способы дают разное железо. Тернарник, формула и case для одной логики синтезируются в одинаковую схему.

Итог

  • Базовые вентили выражаются операторами Verilog напрямую.
  • Мультиплексор по sel пропускает один из входов; его пишут тернарником, формулой или case.
  • Управляющий код мультиплексора работает как адрес входа.
  • Неполный case без default может породить нежелательную защёлку.
Проверьте себя
1. Что делает мультиплексор (MUX)?
AСкладывает все входы
BПо управляющему сигналу select пропускает на выход один из нескольких входов
CХранит значение между тактами
DДелит частоту тактового сигнала
2. Что выберет выражение assign y = sel ? b : a при sel = 0?
Ab
Ba
CНоль
DНеопределённое значение
3. Чем опасен неполный case без default в комбинационном always-блоке?
AОн ускоряет схему
BСинтезатор может вывести нежелательную защёлку (latch), сохраняющую старое значение
CОн всегда вызывает ошибку компиляции
DОн удваивает потребление LUT