В 1978 году Intel представила процессор 8086 — революционный чип, приведший к созданию современной архитектуры x86. Однако в отличие от современных 64-битных процессоров, 8086 был 16-битным. Его арифметически-логическое устройство (АЛУ, ALU) работает с 16-битными значениями, выполняя арифметические операции (например, сложение и вычитание), а также логические операции, включающие побитовые AND, OR и XOR. АЛУ процессора 8086 — сложная часть чипа, выполняющая 28 операций1.
В этом посте я расскажу об управляющих АЛУ схемах, генерирующих сигналы управления конкретных операций. Этот процесс сложнее, чем можно было бы ожидать. Во-первых, команда машинного кода приводит к исполнению множества команд микрокода. Использование АЛУ — это двухэтапный процесс: одна команда микрокода (микрокоманда) конфигурирует АЛУ под нужную операцию, а вторая микрокоманда получает результаты из АЛУ. Кроме того, на основании микрокоманды и команды машинного кода схема управления отправляет в АЛУ сигналы управления, переконфигурируя его под нужную операцию. Таким образом, эта схема становится источником «клея» между микрокомандами и АЛУ.
На фотографии ниже показан процессор 8086 под микроскопом. Я разметил основные функциональные блоки. Архитектурно чип разделён на блок интерфейса шины (Bus Interface Unit, BIU) в верхней части и блок исполнения (Execution Unit, EU) внизу. BIU занимается действиями с шиной и памятью, а также упреждающей выборкой команд, а EU исполняет команды. В правом нижнем углу находится ROM микрокода, хранящее микрокоманды. АЛУ (ALU) находится в левом нижнем углу; биты 7-0 расположены сверху, биты 15-8 — снизу, а между ними расположена схема флагов состояний. Темой этой статьи станет схема управления АЛУ, выделенная внизу красным цветом.
Микрокод
Процессор 8086 реализует большинство машинных команд в микрокоде с микрокомандами для каждого этапа машинной команды. (Я уже подробно писал о микрокоде 8086.) Для микрокода 8086 использует интересную архитектуру: каждая микрокоманда выполняет две несвязанные друг с другом операции. Первая операция копирует данные между источником и получателем. Вторая операция может быть и переходом, и вызовом подпрограммы, и чтением/записью в память, и операцией АЛУ. Операция АЛУ имеет пятибитное поле для указания конкретной операции и двухбитное поле для указания временного регистра, содержащего ввод. Как мы увидим ниже, эти два поля играют важную роль в схеме АЛУ.
Во многих случаях микрокоманда 8086 не определяет операцию АЛУ, подробности подставляются из опкода машинной команды. Например, машинные команды ADD, SUB, ADC, SBB, AND, OR, XOR и CMP имеют одинаковый микрокод, а оборудование выбирает операцию АЛУ из опкода команды. Аналогично, команды инкремента и декремента используют один микрокод, как и команды десятичной коррекции DAA и DAS, а также команды ASCII-коррекции AAA и AAS. Внутри микрокоманды все эти операции выполняются «псевдооперацией» АЛУ под названием XI. Если микрокод определяет операцию АЛУ XI, то оборудование заменяет её операцией АЛУ, определённой в команде. Ещё одна важная особенность микрокода заключается в том, что необходимо выполнить одну микрокоманду АЛУ для конфигурирования операции АЛУ, но результат будет недоступен до последующей микрокоманды, перемещающей результат в получатель. Из-за этого оборудование должно запоминать команду АЛУ.
Приведём конкретный пример: ниже показан микрокод, реализующий типичную арифметическую команду наподобие ADD AL, BL или XOR [BX+DI], CX. Этот микрокод состоит из трёх микрокоманд. Левая половина каждой микрокоманды определяет копирование данных, сначала копируя два аргумента во временные регистры АЛУ, а затем сохраняя результат АЛУ (называемый Σ). Правая половина каждой микрокоманды выполняет вторую задачу. Сначала АЛУ конфигурируется на выполнение операции XI с использованием временного регистра A. Напомню, что XI обозначает операцию АЛУ, подставляемую из машинной команды; именно так один и тот же микрокод обрабатывает восемь разных типов машинных команд. Во второй микрокоманде следующая машинная команда запускается, только если не требуется запись обратно в память (WB). Последняя микрокоманда — это RNI (Run Next Instruction), запускающая новую машинную команду. Также она обозначает, что флаги состояния процессора (F) необходимо обновить, обозначив таким образом, что результат АЛУ равен нулю, положителен, переполнен и так далее2.
M → tmpa XI tmpa Загрузка первого аргумента, конфигурирование АЛУ.
R → tmpb WB,NXT Загрузка второго аргумента, запуск следующей команды, если нет обратной записи в память
Σ → M RNI F Сохранение результата АЛУ, Run Next Instruction, обновление флагов состояния
Схема АЛУ
АЛУ — сердце процессора, выполняющее арифметические и логические операции. Микропроцессоры 1970-х обычно поддерживали сложение и вычитание, логические AND, OR и XOR, а также различные операции побитового сдвига. (Хоть у 8086 были команды умножения и деления, они реализованы в микрокоде, а не в АЛУ.) Так как АЛУ и объёмен, и критически важен для производительности, архитекторы чипа стремились оптимизировать его архитектуру. Вследствие этого модели микропроцессоров имеют совершенно различающиеся архитектуры АЛУ. Например, в микропроцессоре 6502 есть отдельные схемы для сложения и каждой логической операции; соответствующий вывод выбирает мультиплексор. Intel 8085 использует оптимизированный набор вентилей, выполняющих нужную операцию на основании сигналов управления (подробности), а 4-битный АЛУ Z80 использует разные наборы вентилей (подробности).
В 8086 выбран другой подход: две таблицы поиска используются (наряду с другими вентилями) для генерации сигналов переноса и вывода каждого бита АЛУ. Настроив таблицы поиска соответствующим образом, можно сконфигурировать АЛУ на выполнение нужной операции. (Это похоже на то, как FPGA реализует произвольные функции при помощи таблиц поиска.) На диаграмме ниже показана схема для одного бита АЛУ. Я не буду объяснять эту схему подробно, потому что говорил о ней в предыдущей статье3. Важная для нас часть этой схемы — шесть сигналов управления слева. Два мультиплексора (трапеции) реализуют таблицы поиска, используя два входных бита аргумента для выбора выводов из сигналов управления с целью управления генерацией переноса и распространением переноса. Таким образом, передавая в АЛУ соответствующие сигналы управления, 8086 может переконфигурировать АЛУ для выполнения нужной операции. Например, при одном наборе сигналов управления эта схема будет выполнять сложение. Другие наборы сигналов управления заставят схему вычитать или вычислять логическую операцию, например, AND или XOR. В 8086 есть 16 копий этой схемы, поэтому он может работать с 16-битными значениями.
8086 — сложный процессор, и его команды имеют множество особых случаев, поэтому управлять АЛУ сложнее, чем описано выше. Например, операция сравнения аналогична вычитанию, только числовой результат сравнения отбрасывается, обновляются только флаги состояния. Команды сложения и сложения с переносом требуют разные значения переноса в бите 0, а вычитание требует инвертирования флага переноса, потому что он обрабатывается как заём. АЛУ 8086 поддерживает операции инкремента и декремента, а также инкремента и декремента на 2, которые требуют сигнала инкремента в бите 1 вместо бита 0. Особой обработки требуют все операции побитового сдвига. Например, циклический сдвиг может использовать бит переноса или исключать его, а арифметический сдвиг вправо требует дублирования старшего бита. Поэтому наряду с шестью сигналами управления таблицы поиска (LUT) АЛУ также получает различные сигналы управления для подстройки своего поведения под определённые команды. В следующем разделе я объясню, как генерируются эти сигналы.
Схема управления АЛУ на кристалле
На диаграмме ниже показаны компоненты логики управления АЛУ на кристалле. Информация от микрокоманды поступает справа и хранится в защёлках. Программируемые логические матрицы (PLA, Programmable Logic Array) декодируют команду и генерируют сигналы управления. Эти сигналы движутся влево, где они управляют АЛУ.

Как говорилось выше, если микрокод определяет операцию XI, то поле операции заменяется значением на основании опкода машинной команды. Эта подстановка выполняется мультиплексором XI перед тем, как значение сохраняется в защёлке операции. Из-за сложности набора команд 8086 операция XI не так проста, как можно было ожидать. Этот мультиплексор получает три бита команды от специального регистра X, ещё одни бит команды от регистра команд и последний бит от декодирующей схемы, называющейся Group Decode ROM4.
Напомню, что одна микрокоманда определяет операцию АЛУ, а последующая микрокоманда выполняет доступ к результату. Следовательно, схема управления АЛУ должна запоминать заданную операцию, чтобы можно было использовать её в дальнейшем. В частности, схема управления должна отслеживать операцию АЛУ для выполнения и указанный временный регистр. Для отслеживания указанного временного регистра использует три триггера, по одному триггеру на каждый регистр. Микрокоманда содержит двухбитное поле, определяющее временный регистр. Схема управления декодирует это поле и активирует соответствующий триггер. Выводы из этих триггеров поступают в АЛУ и включают соответствующий временный регистр. В начале каждой машинной команды5 триггеры сбрасываются, поэтому по умолчанию выбирается временный регистр A.
Схема управления использует пять триггеров для хранения пятибитного поля операции из микрокоманды. В начале каждой машинной команды триггеры сбрасываются, поэтому по умолчанию выбирается операция 0 (ADD, сложение). Из-за этого операция сложения потенциально может выполниться без микрокоманды конфигурирования АЛУ, что укорачивает микрокод на одну микрокоманду, а значит, укорачивая время команды на один такт.
Пятибитный вывод из триггеров операции поступает на программируемую логическую матрицу (Programmable Logic Array)7 операций, декодирующую операцию в 27 сигналов управления6. Многие из этих сигналов поступают в АЛУ, где они управляют поведением АЛУ в особых случаях. Примерно пятнадцать из этих сигналов поступают в PLA таблиц поиска (LUT), которая генерирует шесть сигналов таблиц поиска для АЛУ. В левой части PLA LUT специальные высокотоковые схемы возбуждения усиливают сигналы управления перед их передачей в АЛУ. Подробные сведения об этих схемах приведены в примечаниях8.
Заключение
Когда я изучаю схему процессора 8086, то вижу различия между чипами RISC и CISC. В процессоре RISC (Reduced Instruction Set Computer), например, в ARM, декодирование команд происходит просто, и схема процессора тоже проста. Но в 8086, процессоре CISC (Complex Instruction Set Computer), повсюду есть пограничные случаи и усложнения. Например, машинная команда 8086 иногда определяет операцию АЛУ в первом байте, а иногда во втором, иногда в где-то в другом месте, поэтому необходимы защёлка регистра X, мультиплексор XI и Group Decode ROM. В АЛУ 8086 существуют запутанные операции, включающие в себя четыре типа коррекций BCD и семь типов сдвигов, что усложняет АЛУ. Разумеется, длительный успех архитектуры x86 доказывает, что у такой сложности есть и преимущества.
Примечания и ссылки
-
Список реализованных АЛУ операций:
00
ADD
Сложение
01
OR
Логическое ИЛИ
02
ADC
Сложение с учётом переноса
03
SBB
Вычитание с заёмом
04
AND
Логическое И
05
SUBT
Вычитание
06
XOR
Логическое XOR
07
CMP
Сравнение
08
ROL
Циклический сдвиг влево
09
ROR
Циклический сдвиг вправо
0a
LRCY
Циклический сдвиг влево через перенос
0b
RRCY
Циклический сдвиг вправо через перенос
0c
SHL
Сдвиг влево
0d
SHR
Сдвиг вправо
0e
SETMO
Присвоение минус единицы (под вопросом)
0f
SAR
Арифметический сдвиг вправо
10
PASS
Передача аргумента без изменения
11
XI
Команда определяет операцию АЛУ
14
DAA
Десятичная коррекция после сложения
15
DAS
Десятичная коррекция после вычитания
16
AAA
ASCII-коррекция после сложения
17
AAS
ASCII-коррекция после вычитания
18
INC
Инкремент
19
DEC
Декремент
1a
COM1
Обратный код
1b
NEG
Смена знака
1c
INC2
Инкремент на 2
1d
DEC2
Декремент на 2
Также см. код Эндрю Дженнера. ↩
-
Вы можете задаться вопросом, как этот микрокод обрабатывает сложные режимы адресации 8086, например,
[BX+DI]. Хитрость в том, что режимы адресации реализуют подпрограммы микрокода. Подробности см. в моей статье о микрокоде адресации 8086. ↩ -
В АЛУ 8086 есть отдельная схема для реализации сдвига вправо. Проблема в том, что данные в АЛУ обычно движутся справа налево, а перенос движется от младших битов к старшим. Сдвиг вправо происходит противоположно этому движению, поэтому требует особого пути. (Сдвиг влево выполнить просто, достаточно прибавить число к самому себе.)
Для операций коррекции (DAA, DAS, AAA, AAS) тоже используется совершенно отдельная схема. Эти операции генерируют коэффициенты коррекции для арифметики BCD (binary-coded decimal) на основании значения и флагов. Схема для этих операций расположена рядом со схемой для флагов, отдельно от остальной части схемы АЛУ. ↩
-
8086 хранит биты 5-3 машинной команды в регистре X. В случае операции XI биты регистра X становятся битами 2-0 определения операции АЛУ, бит 3 берётся из бита 6 команды, а бит 4 для некоторых команд берётся из Group Decode ROM. Смысл в том, что набор команд спроектирован так, что биты команды соответствуют битам определителя операции АЛУ, но их сопоставление сложнее, чем можно было бы подумать. Восемь базовых арифметических/логических операций (ADD, SUB, OR и так далее) имеют прямолинейное сопоставление, которое видно из таблицы опкодов 8086, но сопоставление для других команд не столь очевидно. Более того, иногда операция определяется в первом байте машинной команды, но иногда она определяется во втором байте, поэтому регистр X должен хранить соответствующие биты. ↩
-
Триггеры сбрасываются по сигналу 8086, называемому «Second Clock». При запуске новой машинной команды по первому байту команды генерируется сигнал «First Clock», а по второму байту команды генерируется сигнал «Second Clock». (Стоит отметить, что эти сигналы необязательно находятся в идущих друг за другом тактах, потому что если очередь команд пуста, может потребоваться извлечение из памяти.) Почему триггеры сбрасываются по Second Clock, а не по First Clock? В 8086 есть конвейер, поэтому предыдущая микрокоманда может всё ещё завершать своё выполнение во время First Clock следующей команды. К моменту Second Clock уже можно безопасно сбрасывать состояние АЛУ. ↩
-
27 выводов из PLA инициируются следующими микрооперациями АЛУ:
Вывод 0: RRCY (циклический сдвиг вправо через перенос)
Вывод 1: ROR (циклический сдвиг вправо)
Вывод 2: Корректировки BCD: DAA (десятичная коррекция после сложения), DAS (десятичная коррекция после вычитания), AAA (ASCII-коррекция после сложения), AAS (ASCII-коррекция после вычитания)
Вывод 3: SAR (арифметический сдвиг вправо)
Вывод 4: Сдвиг влево: ROL (циклический сдвиг влево), RCL (циклический сдвиг влево через перенос), SHL (сдвиг влево), SETMO (присвоение минус единицы)
Вывод 5: Сдвиг вправо: ROR (циклический сдвиг вправо), RCR (циклический сдвиг вправо через перенос), SHR (сдвиг вправо), or SAR (арифметический сдвиг вправо)
Вывод 6: INC2 (инкремент на 2)
Вывод 7: ROL (циклический сдвиг влево)
Вывод 8: RCL (циклический сдвиг влево через перенос)
Вывод 9: ADC (сложение с переносом)
Вывод 10: DEC2 (декремент на 2)
Вывод 11: INC (инкремент)
Вывод 12: NEG (смена знака)
Вывод 13: Операция АЛУ 12 (не используется?)
Вывод 14: SUB (вычитание), CMP (сравнение), DAS (десятичная коррекция после вычитания), AAS (ASCII-коррекция после вычитания)
Вывод 15: SBB (вычитание с заёмом)
Вывод 16: ROL (циклический сдвиг влево), RCL (циклический сдвиг влево через перенос)
Вывод 17: ADD, ADC (сложение с переносом)
Вывод 18: DEC, DEC2 (декремент на 1 или на 2)
Вывод 19: PASS (передача без изменений) или INC (инкремент)
Вывод 20: COM1 (обратный код) или NEG (смена знака)
Вывод 21: XOR
Вывод 22: OR
Вывод 23: AND
Вывод 24: SHL (сдвиг влево)
Вывод 25: DAA or AAA (десятичная/ASCII-коррекция после сложения)
Вывод 26: CMP (сравнение) ↩ -
Программируемая логическая матрица — это способ реализации логических вентилей в виде структурированной сетки. PLA часто применяются в микропроцессорах, потому что они позволяют реализовывать логику компактным образом. Обычно PLA состоит из двух слоёв: слоя «OR» и слоя «AND». Вместе эти слои создают выводы «суммы произведений», состоящих из подвергнутых OR множества членов. PLA АЛУ немного необычна тем, что многие выводы берутся непосредственно из слоя OR, и только примерно пятнадцать выводов из первого слоя подаются на второй слой. ↩
-
Сигналы управления проходят через показанную ниже схему возбуждения. Работа этой схемы долгие годы озадачивала меня, потому что казалось, что транзистор с его затвором на +5 В всегда имеет это напряжение. Но однажды я изучал книгу DRAM Circuit Design и обнаружил ту же самую схему, называвшуюся «Bootstrap Wordline Driver». Задача этой схемы — поднять напряжение вывода выше, чем у обычной схемы N-МОП. Проблема схем N-МОП заключается в том, что транзисторы N-МОП не очень хорошо справляются с подтягиванием сигнала вверх: из-за свойств транзистора выходное напряжение меньше напряжения затвора на пороговое напряжение VTH (полувольт или более).

Bootstrap Wordline Driver использует ёмкость, чтобы вытянуть из схемы больше напряжения. В частности, предположим, что входное напряжение равно +5 В при высоком уровне тактового импульса. Точка A будет равна примерно 4,5 В, теряя половину вольта из-за порогового напряжения. Теперь предположим, что тактовый импульс имеют низкий уровень, поэтому инвертированный тактовый импульс делает сигнал транзистора высоким. Из-за ёмкости во втором транзисторе, когда исток и сток переходят на высокий уровень, затвор подтягивается выше его предыдущего напряжения, вероятно, набирая ещё пару вольт. Высокое напряжение на затворе создаёт вывод полного напряжения, позволяя избежать снижения из-за VTH. Но почему транзистор с затвором на +5 В? Этот транзистор используется примерно как диод, препятствуя движению повышенного напряжения обратно через ввод и рассеянию.
Bootstrap-схема используется для сигналов управления таблицы поиска АЛУ по двум причинам. Во-первых, эти сигналы управляют проходными транзисторами. Проходной транзистор испытывает падение напряжения из-за порогового напряжения, поэтому сигнал управления должен иметь максимально высокое напряжение. Во-вторых, каждый сигнал соединён с 16 транзисторами (по одному на каждый бит). Это большое количество транзисторов для управления от одного сигнала, потому что у каждого транзистора есть ёмкость затвора. Повышение напряжения помогает преодолеть задержку R-C (резистор-конденсатор), повышая производительность.
Bootstrap-схемы в левой части PLA LUT На диаграмме выше показаны шесть bootstrap-схем на кристалле. Слева находятся транзисторы, заземляющие сигналы при высоком уровне тактовых импульсов. По всему изображению распределены транзисторы +5 В; два из них помечены. Шесть больших транзисторов обеспечивают сигнал вывода, управляемый тактовыми импульсами. Стоит отметить, что эти транзисторы гораздо крупнее других транзисторов, потому что они должны обеспечивать высокотоковый вывод, а остальные транзисторы в основном поддерживающие.
(Bootstrap-схемы имеют давнюю историю; Федерико Фаджин спроектировал такую схему для Intel 8008; по его утверждению, она «была необходимой для создания процессора».) ↩
Автор: interpres
