Теперь мы можем перейти к знакомству с внутренним миром АЛУ. Как и в первой части статьи я не буду рассматривать какую то определенную микросхему или какой то определенный тип АЛУ. При этом предполагается, что читатели знакомы с основами цифровой логики.
Оптимизации логический выражений, которые реализуются на аппаратном уровне, внимание уделяться не будет. Точно так же не будет уделяться внимание синхронизации и гонкам из-за разных времен путей прохождения сигналов. Иллюстрации в статье будут функциональными схемами, а не принципиальными, так как вряд ли кто то будет сегодня собирать АЛУ из дискретных элементов. В основном будет рассматриваться построение статического АЛУ, причем невысокой разрядности. Вопросы разрядности мы уже обсуждали в первой части статьи.
В работе АЛУ нет никакой мистики. Но некоторую сложность представляет многообразие и разнородность выполняемых функций. Поэтому АЛУ часто строятся как набор отдельных функциональных блоков. При этом, построение этих блоков и их объединение в единое целое могут быть разными. Во с этого и начнем.
Но сначала необходимо сделать еще одно важное уточнение. Набор выполняемых АЛУ операций не тождественен набору команд процессора! Операции АЛУ это лишь базовый набор элементов, из которого и строятся все выполняемые процессором операции. И этот базовый набор не обязательно должен быть большим.
Статья не является учебником. Это не копия каких либо книг или учебников. Это не компиляция других источников и статей. Как и другие статьи канала, это мой личный опыт.
Первую часть статьи можно прочитать здесь - Элементы ЭВМ. АЛУ - арифметико-логическое устройство. Часть 1
Объединить разнородное в единое целое
Самым простым и очевидным, но далеко не всегда самым эффективным и целесообразным, решением является просто использовать столько разных блоков, сколько операций должно выполнять АЛУ. А код операции будет выбирать, выходной сигнал какого именно блока будет поступать на выход АЛУ.
Такой принцип построения АЛУ действительно применяется на практике. Такие АЛУ одни из самых быстрых, но их схемотехника может быть избыточной. При этом они исключают наличие "недокументированных" функций, что можно рассматривать и как достоинство, и как недостаток. Чуть позже мы еще вернемся к этому вопросу.
Большое количество выполняемых операций требует и большого количества функциональных блоков, которые работают параллельно, даже в том случае, если функционал блоков частично перекрывается. Поскольку по входам все блоки включены параллельно, это может создавать излишнюю нагрузку на предшествующие узлы процессора с которых и поступают входные сигналы a и b. Для исключения этого на входах операндов АЛУ устанавливаются буферные усилители, я показал их а иллюстрации.
Однако, можно уменьшить схемотехническую избыточность АЛУ за счет объединения функционала отдельных блоков. При этом для управления многофункциональными блоками потребуются дополнительные сигналы, что усложняет управление АЛУ. Но зато это повышает гибкость и уменьшает схемотехническую избыточность.
На первый взгляд, различия невелики. Однако, это не так. Во первых, теперь каждый блок может выполнять несколько различных функций, что управляется дополнительными сигналами с1 и с2. Более того, блоки могут быть взаимосвязанным (на иллюстрации не показано). Однако, это не исключает необходимости коммутатора выходных сигналов блоков, который управляется сигналом sw.
Такие АЛУ немного медленнее, так как путь сигналов операндов от входов до выхода более длинный (мы это скоро увидим). Но они и более гибкие в применении. И именно такие АЛУ мы и будем далее рассматривать в статье.
Однако, сначала пару слов о "предельном случае"
ПЗУ в роли АЛУ
Давайте представим, что и сигналы операндов, и сигналы выбора операции, являются полностью равноправными и образуют некое "множество входных данных". В таком представлении нет ничего искусственного и неестественного. Достаточно просто абстрагироваться от функционального значения отдельных сигналов.
Теперь мы можем представить АЛУ как функциональный модуль, который ставит в соответствие множеству входных сигналов заранее определенное множество выходных сигналов. Такое функциональное преобразование можно записать в табличной форме. Ничего не напоминает?
Да, именно так, мы можем представить АЛУ как ПЗУ. Сигналы входных операндов, входящий перенос, код операции, в совокупности будут являться адресом ячейки ПЗУ, а ее содержимое будет сигналами результата операции и исходящим переносом.
И такие АЛУ действительно иногда используются. Особенно в случаях, когда требуется выполнение нетривиальных операций при высоком быстродействии. Например, специализированное АЛУ выполняющее операции преобразования между системами координат для навигационного процессора.
Несмотря на все преимущества подобных АЛУ, они используются нечасто. С ростом разрядности обрабатываемых операндов, даже небольшим, резко возрастает требуемый объем ПЗУ, что приводит к увеличению занимаемого им на кристалле места. И размер АЛУ получается слишком большим, а стоимость высокой. Такие АЛУ в статье рассматриваться далее не будут.
Многофункциональный логический блок
Давайте начнем с самого простого - одноразрядного многофункционального логического блока. Предположим, что нам требуется выполнение четырех логических операций:
- НЕ
- И
- ИЛИ
- ИСКЛЮЧАЮЩЕЕ ИЛИ
Давайте вспомним формулы де-Моргана
которые устанавливают зависимость между операциями И и ИЛИ для прямой и инверсной логики. Это позволяет нам использовать всего один логический элемент, например, И, для выполнения как операции И, так и операции ИЛИ. Просто для ИЛИ нам потребуется инверсия входных сигналов и выходного сигнала.
Точно так же можно использовать элемент ИЛИ для выполнения операции И если инвертировать входные и выходной сигналы.
Таким образом, наша задача сводится к управлению инверсией сигналов. И сделать это можно, например, с помощью инвертора и мультиплексора
Здесь сигнал передается на выход без инверсии если управляющий сигнал p/n равен "0" и с инверсией если p/n равно "1". На иллюстрации слева показана принципиальная схема с использованием элементарных логических элементов, а справа функциональная схема. Элементы DD2-DD5 и образуют тот самый мультиплексор.
Можно использовать и другой вариант, с использованием элемента исключающее ИЛИ
В данном случае сигнал, точно так же, как в предыдущем варианте, передается без инверсии если p/n равно "0" и с инверсией если p/n равно "1". На иллюстрации слева показан один из распространенных вариантов реализации функции ИСКЛЮЧАЮЩЕЕ ИЛИ на элементах 2И-НЕ, а справа функциональная схема.
Время задержки прохождения сигнала в обоих вариантах примерно одинакового. На практике используются оба варианта, хотя построение элемента ИСКЛЮЧАЮЩЕЕ ИЛИ может быть и иным.
Теперь мы можем нарисовать схему блока выполняющего операции И и ИЛИ, причем тип операции будет задаваться внешними сигналами
Здесь у нас есть три дополнительных управляющих сигнала (s0, s1, s2), что может показаться излишним. Однако, это дает нам дополнительную гибкость и функциональность. Давайте посмотрим, какие операции может выполнять этот наш многофункциональных элемент
Как вы помните, мы планировали свести в одном элементе две функции, И и ИЛИ, но результат получился более интересным. В частности, получилась и функция ЗАПРЕТ, о которой я уже упоминал в статьях
Феррит-диодные ячейки. Старая импульсная логика. История цифровой техники.
и
Феррит-транзисторная динамическая логика. История цифровой схемотехники
Эти дополнительные операции могут оказаться полезными. Если же они не нужны, а на первом месте стоит простота управления, то мы можем объединить сигналы в s0-s2 в один сигнал. И у нас останется только две возможные функции, И и ИЛИ, как мы изначально и планировали.
Этот блок, без каких либо изменений, позволяет выполнять и операцию НЕ, причем для любого операнда. Например, для инверсии операнда a нам нужно задать s0="1" s1="0" s2="0" и зафиксировать b="1". Фиксация операнда b="1" может быть выполнена внешней, по отношению к АЛУ, схемой, например, декодером команд или блоком микропрограммного управления процессора. То есть, теми же узлами процессора, которые формируют и сигналы s0-s2.
Но можно добавить еще один управляющий сигнал и дополнительный мультиплексор, который позволит выбирать в качестве операнда или выход схемы передача/инверсия, или предопределенные "0" или "1". Все зависит от функциональных требований к АЛУ. Я не буду отдельно иллюстрировать эти варианты.
Однако, наши начальные требования к функционалу блока все еще выполнены не полностью. Нет реализации операции ИСКЛЮЧАЮЩЕЕ ИЛИ. Давайте добавим недостающее.
Недостающую операцию нам пришлось добавить в виде отдельного элемента ИСКЛЮЧАЮЩЕЕ ИЛИ и мультиплексора. Обратите внимание, что при выполнении операции ИСКЛЮЧАЮЩЕЕ ИЛИ сигнал s2 не имеет значения.
Это лишь один из вариантов построения логического блока, причем даже не столько вариант, сколько набросок варианта. Он вполне работоспособен, но далеко не оптимален. И многие важные при построении реальных АЛУ вопросы оставлены "за кадром". Да и в управляющих сигналах порядок надо навести.
Многоразрядное АЛУ будет содержать несколько таких многофункциональных логических блоков. Их информационные входы и выходы будут раздельными, а управляющие сигналы общими.
Арифметические операции. Сумматоры. Полноценное одноразрядное АЛУ
Из всех арифметических операций АЛУ зачастую поддерживают только сложение и вычитание. Причем выполняет обе операции сумматор. Давайте, но кратко, поговорим о сумматорах. Я не сомневаюсь, что вы все про них знаете, но отдельные моменты, с точки зрения АЛУ, уточнить будет полезно.
В первой части статьи я говорил, что операция ИСКЛЮЧАЮЩЕЕ ИЛИ является и арифметической. Это действительно так. Если не считать переносов между разрядами двоичных чисел. Полусумматор вычисляет сумму двух чисел без учета входящего переноса и формирует сигнал исходящего переноса, который возникает как результат операции. Полный сумматор вычисляет сумму двух чисел с учетом входящего переноса и формирует сигнал исходящего переноса. Полусумматоры нам не интересны.
Без сомнения вы все знаете эту схему. Ci это входящий перенос от предыдущего разряда (младшего). Co это исходящий перенос для следующего разряда (старшего). Сигнал исходящего переноса имеет самую большую задержку формирования и определяет быстродействие сумматора. Для многоразрядных сумматоров переносы вычисляются последовательно, разряд за разрядом. Это сильно снижает быстродействие. Проблему позволяют решить схемы ускоренного переноса. Однако, я сегодня не буду касаться этого вопроса.
В данном случае, мы же строим АЛУ, нам важен лишь один элемент схемы сумматора - элемент ИСКЛЮЧАЮЩЕЕ ИЛИ (левый верхний) на который поступают сигналы a и b. Дело в том, что такой элемент у нас уже есть в логическом блоке. Почему бы его не использовать? Давайте попробуем
Позвольте, а откуда же взялась операция вычитания? Все очень просто, у нас уже есть элементы обеспечивающие инверсию сигналов входных операндов. Например, если мы установим s1="1", то сигнал b будет инвертироваться, а результирующая операция будет a-b. Вот так вот все просто!
На самом деле, здесь еще будет полезной возможность инверсии входящего переноса. Точно так же, как мы это реализовали для сигналов a и b. Я не буду показывать это на иллюстрации. Оставлю это читателям в качестве упражнения.
Увеличение количества управляющих сигналов полезно, так как увеличивает количество выполняемых операций. Включая арифметические. Я показал два сигнала управления выходным мультиплексором, s3 и s4. Теперь у нас нужно выбирать один из трех сигналов с внутренних блоков АЛУ для передачи на выход.
Не все комбинации управляющих сигналов действующие и не все имеют смысл. Но, как я говорил в начале данной статьи, вопросы оптимизации логических функций сегодня не будут рассматриваться.
Сдвигатели даных
А как же сдвиги? Это ведь важная операция. Важная, но ее не обязательно реализовывать внутри АЛУ, так как сдвиги имеют более широкое использование внутри процессоров. Тем не менее, сдвигатели могут устанавливаться на входах и внутри АЛУ. До рассмотренных ранее элементов АЛУ. Мы не будем их подробно рассматривать сегодня, но упрощенную функциональную схему сдвигателя на один разряд вправо и влево я приведу
В данном случае я не стал показывать управляющие сигналы мультиплексоров, что бы не загромождать картинку. Думаю, принцип работы сдвигателей понятен. Сдвиг не обязательно должен быть на один разряд. Можно использовать многоразрядные мультиплексоры и реализовать сдвиг на любое число разрядов, причем число разрядов можно задавать и управляющими сигналами.
Если вместо фиксированных значений "0" выводы мультиплексоров подключить к сигналам входящего переноса, то можно каскадировать сдвигатели точно так же, как сумматоры и АЛУ. Можно реализовать и циклические сдвиги, в том числе, с участием переносов. Но этот вопрос выходит за рамки сегодняшней статьи.
Сдвигатели данных могут включаться не только на входах АЛУ, но и на выходе. Это позволяет строить сложные схемы управления данными и выполнения операций уже на уровне процессора.
Умножение и деление
Очень кратко. Умножение и деление сложные операции, которые зачастую выполняются итерационно на уровне микропрограмм. Однако, в некоторых процессорах могут использоваться и аппаратные блоки умножения/деления.
Умножение реализовать проще. Достаточно последовательного включения сумматоров и сдвигателей данных, что бы получить аппаратный эквивалент всем известного умножения столбиком. Причем нужно понимать, что произведение двух двоичных чисел разрядностью N имеет разрядность 2N. Почему это так, я описывал в статье
Простые типы данных. Машинное представление простых типов. Операции с простыми типами.
Умножители не столько сложны, сколько громоздки. Их структура регулярна, но количество элементов велико. И время выполнения операции умножения, даже аппаратно реализованной, велико.
Деление сложнее умножения, так как к схемам сдвига и вычитания необходимо добавлять схемы сравнения (цифровые компараторы), которые не только формируют разряды частного и остатка, но и влияют на ход процесса деления.
Кроме уже упомянутой особенности, два выходных значения, частное и остаток, нельзя не сказать, что делимое имеет удвоенную разрядность по сравнению с частным и остатком. Причины так же описаны в статье по приведенной ссылке. А что бы сложность деления стала более понятной, можете почитать статью
Машинное деление целых двоичных чисел
В которой я рассказываю об алгоритмах деления на примере архитектуры микроконтроллеров PIC.
Заключение
Сегодня мы, чрезвычайно кратко и упрощенно, познакомились с некоторыми принципами лежащими в основе построения и работы центрального элемента любого процессора - АЛУ, арифметическо-логического устройства. Заглянули в его внутренний мир, который оказался не столь страшен, как казалось со стороны. Во всяком случае, для рассмотренных нами примеров.
Будут и другие статьи посвященные устройству и работе узлов процессоров и ЭВМ в целом. В дополнение к уже ведущемуся циклу статей "Микроконтроллеры для начинающих". Правда пока сложно сказать, насколько этот новый цикл окажется для вас интересным. А от интереса будет зависеть и тематика новых статей, и их количество.
Как всегда, можете задавать вопросы в комментариях. И можете предлагать интересующие вас темы статей. Или вопросы требующие более глубокого и подробного рассмотрения.