Как железо принимает решения (Жизнь без if/else)
В программировании нет ничего естественнее, чем ветвление. Ты пишешь if (condition) { do_a(); } else { do_b(); } и не задумываешься о том, как это работает. Компьютер просто проверяет условие и идет строго по одной ветке кода. Вторая ветка в этот момент спит — она даже не запускается, экономя ресурсы процессора.
В аппаратной разработке на структурном Verilog оператора if не существует.
Электрический ток не читает код и не умеет думать. Он течет по всем физически доступным медным дорожкам одновременно. Если у чипа есть два возможных пути развития событий (например, сложить числа или вычесть их), кремний сделает и то, и другое одновременно.
Как же тогда процессор выбирает правильный ответ и отбрасывает ненужный?
Знакомьтесь: Мультиплексор (Mux)
Чтобы направить ток в нужное русло, инженеры придумали мультиплексоры. Мультиплексор (или просто Mux) — это аппаратный «стрелочник». Это физический переключатель, который имеет несколько входов с данными, один выход и специальный управляющий пин.
Давайте посмотрим на простейший Мультиплексор 2-в-1. У него есть:
- Два информационных входа:
aиb. - Один управляющий вход:
sel(от слова select — выбор). - Один выход:
out.
Логика работы железная (в прямом смысле):
- Если на пин
selподается 0 (нет напряжения), переключатель соединяет выход с проводомa. - Если на пин
selподается 1 (есть напряжение), переключатель «переводит рельсы» и пропускает на выход сигналb.
Анатомия переключателя: собираем Mux из базовых вентилей
Как заставить глупые логические вентили работать как умный переключатель? Нам понадобятся два «охранника» (вентили and) и один «сборщик» (вентиль or).
Вспомним, как работает вентиль and (Логическое И). Он выдает единицу на выход только если на оба его входа приходят единицы. Если хотя бы на одном входе висит строгий 0, вентиль and блокируется — он будет выдавать 0, независимо от того, что происходит на втором проводе. Это идеальный шлагбаум!
Вот как строится схема мультиплексора:
- Создаем инвертированный переключатель. Нам нужно, чтобы первый охранник открывался при
sel = 0. Для этого мы пропускаем проводselчерез вентильnot. - Ставим первого охранника для сигнала
A. Берем вентильand. На один его вход заводим наши данныеa, а на второй — инвертированныйsel. Теперь сигналaсможет пройти сквозь этот вентиль только когда изначальноselбыл равен нулю. - Ставим второго охранника для сигнала
B. Берем второй вентильand. На него подаем данныеbи прямой (не инвертированный) проводsel. Сигналbпройдет дальше только когдаselравен единице. - Собираем всё вместе. Поскольку
selне может быть одновременно и нулем, и единицей, только один из охранников пропустит свой сигнал. Чтобы вывести победивший сигнал наружу, мы просто направляем выходы обоих вентилейandв финальный вентильor(Логическое ИЛИ).
Секрет инженеров: В программировании мы пишем
if/else, чтобы сэкономить вычисления. В схемотехнике мы считаем абсолютно всё параллельно, тратя на это транзисторы, а затем просто ставим Mux, чтобы он «заглушил» ненужные результаты и пропустил дальше только один верный ответ. Это основа невероятной скорости современных процессоров.
На уровне 3.1 тебе предстоит впервые перенести эту логику в текстовый код. Вспомни всё, что ты узнал о внутренних проводах (wire) — тебе понадобится создать их для выходов вентилей-охранников, чтобы соединить их со сборщиком. Удачи!