Как железо принимает решения (Жизнь без if/else)

В программировании нет ничего естественнее, чем ветвление. Ты пишешь if (condition) { do_a(); } else { do_b(); } и не задумываешься о том, как это работает. Компьютер просто проверяет условие и идет строго по одной ветке кода. Вторая ветка в этот момент спит — она даже не запускается, экономя ресурсы процессора.

В аппаратной разработке на структурном Verilog оператора if не существует.

Электрический ток не читает код и не умеет думать. Он течет по всем физически доступным медным дорожкам одновременно. Если у чипа есть два возможных пути развития событий (например, сложить числа или вычесть их), кремний сделает и то, и другое одновременно.

Как же тогда процессор выбирает правильный ответ и отбрасывает ненужный?

Знакомьтесь: Мультиплексор (Mux)

Чтобы направить ток в нужное русло, инженеры придумали мультиплексоры. Мультиплексор (или просто Mux) — это аппаратный «стрелочник». Это физический переключатель, который имеет несколько входов с данными, один выход и специальный управляющий пин.

Давайте посмотрим на простейший Мультиплексор 2-в-1. У него есть:

Логика работы железная (в прямом смысле):

Анатомия переключателя: собираем Mux из базовых вентилей

Как заставить глупые логические вентили работать как умный переключатель? Нам понадобятся два «охранника» (вентили and) и один «сборщик» (вентиль or).

Вспомним, как работает вентиль and (Логическое И). Он выдает единицу на выход только если на оба его входа приходят единицы. Если хотя бы на одном входе висит строгий 0, вентиль and блокируется — он будет выдавать 0, независимо от того, что происходит на втором проводе. Это идеальный шлагбаум!

Вот как строится схема мультиплексора:

  1. Создаем инвертированный переключатель. Нам нужно, чтобы первый охранник открывался при sel = 0. Для этого мы пропускаем провод sel через вентиль not.
  2. Ставим первого охранника для сигнала A. Берем вентиль and. На один его вход заводим наши данные a, а на второй — инвертированный sel. Теперь сигнал a сможет пройти сквозь этот вентиль только когда изначально sel был равен нулю.
  3. Ставим второго охранника для сигнала B. Берем второй вентиль and. На него подаем данные b и прямой (не инвертированный) провод sel. Сигнал b пройдет дальше только когда sel равен единице.
  4. Собираем всё вместе. Поскольку sel не может быть одновременно и нулем, и единицей, только один из охранников пропустит свой сигнал. Чтобы вывести победивший сигнал наружу, мы просто направляем выходы обоих вентилей and в финальный вентиль or (Логическое ИЛИ).

Секрет инженеров: В программировании мы пишем if/else, чтобы сэкономить вычисления. В схемотехнике мы считаем абсолютно всё параллельно, тратя на это транзисторы, а затем просто ставим Mux, чтобы он «заглушил» ненужные результаты и пропустил дальше только один верный ответ. Это основа невероятной скорости современных процессоров.

На уровне 3.1 тебе предстоит впервые перенести эту логику в текстовый код. Вспомни всё, что ты узнал о внутренних проводах (wire) — тебе понадобится создать их для выходов вентилей-охранников, чтобы соединить их со сборщиком. Удачи!