
Революционный Intel 80386 (1985 год) стал первым 32-битным процессором с архитектурой x86. Как и большинство процессоров, он содержит огромное число регистров, которые являются ключевой составляющей, обеспечивая сверхбыструю обработку данных в сравнении с основной памятью. К ним относятся регистры общего назначения, регистры индекса и селекторы сегментов, а также специальные регистры для управления памятью и разработки операционной системы. В этой статье я буду говорить о кремниевом кристалле i386 и объясню, как в нём организованы основные регистры.
Компоновка регистров в i386 оказалась на удивление сложной. Для 30 из них, которые я успел изучить, в этом процессоре используется шесть разных схем, каждая из которых оптимизирована под конкретные характеристики регистра. В некоторых ячейки совмещены для удваивания пространства хранения. Другие поддерживают доступ к данным по 8, 16 или 32 бита за раз. Регистровый файл является преимущественно трёхпортовым, то есть позволяет одновременно считывать два регистра, параллельно производя запись в третий. Наконец, меня удивило, что биты в регистрах хранятся не по порядку: младшие 16 бит каждого регистра чередуются, а старшие располагаются линейно.
На фото выше под увеличением металл-микроскопа показан блестящий кристалл i386 размером с ноготь. На снимке я обозначил основные функциональные блоки. Нас в этой статье будет интересовать Data Unit (модуль данных) в нижнем левом углу микросхемы. Он содержит 32-битный модуль АЛУ, а также блок основных регистров (в красной рамке). Его схема, называемая «тракт данных», является сердцем процессора.
Тракт данных имеет стандартную структуру: каждый регистр АЛУ представляет горизонтальную полосу, и все вместе они формируют горизонтальные группы, которые можно видеть на снимке. Эта часть преимущественно состоит из 32 одинаковых тщательно оптимизированных схем — по одной для каждого бита процессора. Все схемы имеют одинаковую ширину — 60 мкм — что позволяет собирать эти функциональные блоки вместе, подобно микроскопическим кирпичикам LEGO. Связывают их вертикальные металлические линии шины, пролегающие вдоль тракта группами по 32 штуки. Через них данные перемещаются между блоками вверх/вниз. При этом управляющие линии пролегают горизонтально, позволяя выполнять операции в АЛУ, а также чтение/запись регистров. Нестандартная часть схемы справа от Data Unit генерирует сигналы для этих управляющих линий, активируя нужные для каждой инструкции.
Тракт данных строго структурирован для достижения максимальной производительности при минимальной занимаемой на кристалле площади. Далее я расскажу, как в этой структуре реализованы регистры.
▍ Регистры i386
Регистры процессора — это одна из его самых видимых частей. Конкретно данная модель содержит 16 штук для прикладного программирования — очень немного по нынешним стандартам, но весьма немало по тем временам. На диаграмме ниже показано восемь 32-битных регистров общего назначения. Сверху идут EAX, EBX, ECX и EDX. Несмотря на то, что это 32-битные регистры, они также могут рассматриваться как 16- или 8-битные для обратной совместимости с более ранними процессорами. Например, к нижней половине EAX можно обращаться как к 16-битному регистру AX, а к нижнему байту EAX — как к 8-битному регистру AL. Более того, к битам с 15 по 8 можно обращаться как к 8-битному регистру AH. Иными словами, обращаться к EAX, как и к трём другим регистрам, можно четырьмя разными способами. Ниже вы увидите, что эта особенность усложняет реализацию общего набора.

Регистры общего назначения в i386. Выдержка из 80386 Programmer's Reference Manual, стр. 2-8
В нижней части иллюстрации показано, что 32-битные регистры EBP, ESI, EDI и ESP также могут работать как 16-битные BP, SI, DI и SP. В отличие от предыдущих, в качестве 8-битных они уже выступать не могут. В i386 также есть шесть 16-битных сегментных регистров, определяющих начало сегментов памяти. Эти 16 прикладных регистров завершаются флагами состояния и указателем инструкций (EIP). Они рассматриваются как 32-битные регистры, но реализованы сложнее. В i386 также есть множество регистров для программирования операционной системы, но здесь я о них говорить не буду, так как они находятся в другой части микросхемы.1 Ну и, наконец, в этом процессоре есть куча временных регистров, которые невидимы для программиста и используются микрокодом для выполнения сложных инструкций.
▍ Ячейки 6T и 8T в статической RAM
Регистры i386 реализованы с использованием ячеек статической RAM, то есть схемы, которая может содержать один бит информации. Эти ячейки выстроены в сетку, формируя несколько регистров. Статическую RAM можно противопоставить динамической, которая используется в качестве основной памяти ПК. В динамической RAM каждый бит содержится в крохотном конденсаторе, а в статической используется более быстрая, но также более масштабная и сложная схема. Поскольку основная память хранит гигабайты данных, в ней динамическая RAM используется для обеспечения плотно упакованного и дешёвого хранилища. В случае регистров же ситуация иная — здесь область хранения мала, зато обеспечивается высокая скорость. То есть регистры используют статическую RAM, о которой я расскажу ниже.
Суть реализации этой памяти заключается в замыкании двух логических инверторов в петлю. Принцип работы инвертора же состоит в том, что при получении на входе 0 он выдаёт 1 и наоборот. Благодаря этому, петля инвертирования остаётся стабильной — один инвертор установлен, другой — нет. В зависимости от того, какой из инверторов установлен, схема хранит 0 или 1, как показано ниже. Таким образом пара логических элементов образует один бит памяти.

Однако для того, чтобы иметь практическую пользу, петля инвертирования должна хранить в себе бит, а также предоставлять способ его считывать. Для записи нового значения в схему передаются два сигнала, меняющих инверторы на нужные значения. Один получает новое значение бита, а второй — инвертированное. Такое обновление бита напоминает метод брут-форса, но вполне работает. Хитрость в том, что инверторы в ячейке малы и слабы, а входные сигналы имеют более высокий ток и могут перегружать их.2 Эти сигналы передаются им по битовым шинам, которые также можно использовать для чтения хранящегося в ячейке значения.

Для управления доступом к регистру битовые шины подключаются к инверторам через проходной транзистор, который выступает в качестве выключателя, управляющего доступом к петле инвертора.3 Когда транзисторы открыты, сигналы по шинам записи могут проходить к инверторам. Если же они закрыты, инверторы оказываются изолированы от шин записи.
Проходные транзисторы открываются управляющим сигналом, передаваемым через «шину слов» (word line), регулирующую доступ к слову в хранилище регистра. Так как каждый инвертор состоит из двух транзисторов, вышепоказанная схема включает их шесть, почему и называется ячейкой 6T.
Ячейка 6Т использует одни и те же битовые шины для чтения и записи, поэтому писать в регистр и считывать из него одновременно нельзя. Добавление ещё двух транзисторов ведёт к получению схемы 8Т, которая уже позволяет одновременно считывать из одного регистра и записывать в другой. (В техническом смысле регистровый файл является двухпортовым). В показанной ниже схеме 8Т два дополнительных транзистора (G и H) используются для чтения.
Транзистор G буферизует значение ячейки. Он открывается, когда сигнал на выходе инвертора имеет высокий уровень, подтягивая битовую шину чтения к низкому.4 Переходный транзистор H блокирует сигнал, пока из регистра происходит считывание. Управляется он шиной слов, используемой для чтения. Обратите внимание, что есть две битовых шины для записи (как раньше) и одна для чтения.

Схема хранилища ячейки. Каждый транзистор обозначен буквой
Для создания регистра (или памяти) из ячеек выстраивается сетка. Каждый ряд в этой сетке соответствует регистру, а каждый столбец — позиции бита. Горизонтальные линии — это шины слов, указывающие на нужное слово, а вертикальные — это битовые шины, передающие биты в/из регистров. Для записи вертикальные битовые шины могут передавать 32 бита (вместе с их инвертированной формой) в регистр, а для чтения — получать 32 бита из него. Что мы в итоге имеем? Каждый ряд — это регистр, данные передаются вертикально, а управляющие сигналы — горизонтально.

Ячейки статической памяти (8Т), организованные в сетку
▍ Шесть схем регистров в i386
На фото кристалла i386 ниже крупным планом показан блок регистров. Здесь мы видим сетку из ячеек хранилища, но обратите внимание, что от ряда к ряду паттерн меняется. Всего в этом блоке присутствует 30 регистров: 22 из них содержат по 32 бита, а нижние — по 16. Изучая кристалл, я выяснил, что в нём есть шесть разных групп регистров, которые я произвольно обозначил от (а) до (f). Далее я эти группы опишу.

Основной блок регистров i386 в нижней части тракта данных. Числа показывают, сколько битов регистра доступно для обращения
Начну с самой простой внизу: восемь 16-битных регистров, которые я отнёс к типу (f). Слева видно, как «обрывается» регистровый файл, поскольку объём этих регистров вдвое меньше объёма других (16 бит против 32). Эти регистры реализованы с использованием описанной выше схемы 8Т, что делает их двухпортовыми: из одного можно читать, в другой писать. Как уже говорилось, через каждый бит проходят три вертикальных шины: одна для чтения и две (с противоположной полярностью) для записи. Каждый регистр имеет две управляющие шины (шины слов): одна позволяет выбирать регистр для чтения, а другая — регистр для записи.
На фото ниже показано, как четыре ячейки типа (f) реализованы на микросхеме. На этом изображении для демонстрации внутреннего слоя кремния были удалены два металлических слоя кристалла вместе с большей частью поликремниевой разводки. Тёмными контурами обозначены области легированного кремния, а полосы вдоль этой области — это затворы транзисторов. Я отметил каждый транзистор буквой в соответствии со схемой выше. Заметьте, что схема нижней части представляет зеркальную копию верхней, что экономит много пространства. Левая и правая стороны отзеркалены с примерной точностью. Такая нестандартная форма позволяет отделить шины слов для чтения/записи, чтобы можно было управлять левой и правой половинами без коллизий.

В регистровом файле и тракте данных i386 для каждого бита выделена ширина 60 мкм. Тем не менее показанная выше схема регистра необычна: хоть её ширина и составляет 60 мкм, в ней представлены две смежные ячейки регистра. Это означает, что здесь в 60 мкм втиснуто два бита, а не один. Таким образом эта плотная схема реализует по два регистра на ряд (с чередующимися битами), обеспечивая вдвое бо́льшую плотность по сравнению со схемами других регистров.
Если вам интересно, как представленные выше транзисторы соединены, на схеме ниже показано, что их физическое расположение соответствует двум из 8Т-ячеек памяти, о которых говорилось ранее. Поскольку в i386 два накладывающихся металлических слоя, разобрать детали на фото кристалла очень сложно. Желающие могут найти эти фото в моей предыдущей статье.

Схема из двух статических ячеек в i386, обозначенных как «R» и «L» (право и лево). Эта схема примерно совпадает с фактическим размещением деталей
Над регистрами типа (f) находятся 10 регистров типа (e), занимающие пять рядов ячеек. Эти регистры реализованы также по схеме 8Т, но при этом являются 32-битными, а не 16-ти. Поэтому, в отличие от предыдущих своих собратьев, такой регистр занимает всю ширину тракта данных. Как и ранее, в схеме двойной плотности реализуется по два регистра на ряд. Кремниевая структура здесь идентична (только имеет ширину 32 бита, а не 16), поэтому её фото включать не стану.
Над этими регистрами находятся четыре (d) других, которые уже более сложны. Это трёхпортовые регистры, то есть в процессе записи в один регистр из двух других можно выполнять чтение. (Это пригождается для операций с АЛУ, так как позволяет одновременно сложить два значения и вернуть результат). С целью поддержки чтения второго регистра для каждого бита добавляется ещё по одной вертикальной шине. В каждой ячейке есть по два дополнительных транзистора для подключения к этой новой битовой шине. Управляет этим дополнительным трактом чтения ещё одна шина слов. Поскольку каждая ячейка имеет два дополнительных транзистора, всего получается 10 транзисторов, а схема называется 10Т.

Четыре ячейки типа (d). Зелёные области с полосками — это остатки оксидных слоёв, которые были не до конца удалены — не обращайте внимания
На иллюстрации выше показаны четыре ячейки памяти типа (d). В отличие от предыдущих ячеек с двойной плотностью, каждая из этих занимает по 60 мкм. Ячейки зеркально отражаются по горизонтали и вертикали, что слегка увеличивает плотность, так как позволяет им совместно использовать шины питания. Я обозначил транзисторы буквами от А до H, как и ранее, а также отметил два дополнительных — I и J — для второй шины чтения. Схема здесь та же, что и прежде, только появилось два транзистора. Кремниевая же структура отличается сильно.
У каждого из (d) регистров есть пять управляющих линий. Две из них отвечают за выбор регистра для чтения, подключая его к одной из двух вертикальных шин. Три шины записи позволяют независимо записывать разные части регистра: старшие 16 бит, следующие 8 бит и нижние 8 бит. Это необходимо архитектуре х86, где к 32-битному регистру вроде EAX можно обращаться как к 16-битному AX, 8-битному AH или 8-битному AL. Обратите внимание, что для чтения определённой части регистра не требуется отдельных управляющих линий: регистр предоставляет все 32 бита, и отвечающая за чтение схема может игнорировать ненужные из них.
Идём выше. Три регистра (с) также построены из 10Т. Однако эти регистры не поддерживают частичную запись, поэтому записывать нужно сразу все 32 бита. В результате им требуется всего три управляющих линии (две для чтения и одна для записи). За счёт меньшего числа управляющих линий ячейки занимают меньше вертикального пространства, поэтому схема получается чуть компактнее в сравнении с предыдущими ячейками типа (d). На иллюстрации ниже показано четыре ряда типа (с) над двумя рядами типа (d). И хотя в этих ячейках также используются десять транзисторов, они чуть смещены.

Четыре ряда типа (с) над двумя ячейками типа (d)
Далее идут четыре регистра (b), которые поддерживают 16-битовую и 32-битовую запись (но не 8-битовую). Таким образом, эти регистры имеют четыре управляющих линии (две для чтения и две для записи). Из-за дополнительной управляющей линии их ячейки занимают чуть больше вертикального пространства, чем ячейки (с), но само расположение почти идентично.
Наконец, регистр (a) вверху имеет особенность: он может получать копию значения в нижележащем регистре. Это значение копируется напрямую между регистрами без использования шин чтения или записи. У этого регистра 3 управляющих линии: одна для чтения, другая для записи и третья для копирования.

На иллюстрации выше показана ячейка типа (а) над ячейкой типа (b). В основе ячейки (a) лежит стандартная схема 8Т, но с шестью дополнительными транзисторами для копирования значения из ячейки ниже. В частности, два инвертора буферизуют вывод ячейки (b), каждый со своей стороны. Эти инверторы реализуются с помощью транзисторов от l1 до l4.5 Два транзистора, S1 и S2, выступают в качестве проходных переключателей между этими инверторами и ячейкой памяти. При активации управляющей линией переключатели позволяют инверторам переписывать ячейку памяти содержимым ячейки ниже. Заметьте, что ячейка (a) из-за дополнительных транзисторов занимает значительно больше вертикального пространства.
▍ Размышления на тему расположения регистров
Я так и не определил, как именно соотносятся регистры i386 с этими 30 реальными регистрами, но могу порассуждать на эту тему. Во-первых, у i386 есть четыре регистра, к которым можно обращаться как к 8-, 16- или 32-битным: EAX, EBX, ECX и EDX. Значит, они должны соответствовать регистрам (d), которые поддерживают эти паттерны доступа.
Четыре регистра индекса (ESP, EBP, ESI и EDI) могут использоваться как 32- или 16-битные, соотносясь с четырьмя регистрами (b) с теми же свойствами. Содержимое какого из этих регистров можно скопировать в регистр типа (a)? Возможно, указатель стека (ESP) копируется при обработке прерываний.
Регистровый файл содержит восемь 16-битовых регистров типа (f). В i386 есть шесть 16-битовых сегментных регистров, значит, из восьми имеющихся шесть являются сегментными, а два — дополнительными. Инструкция LOADALL даёт кое-какие подсказки, указывая на то, что два дополнительных 16-битных регистра — это LDT (Local Descriptor Table, локальная таблица дескрипторов) и TR (Task Register, регистр задач). Кроме того, LOADALL обрабатывает 10 временных регистров, соответствующих 10 регистрам типа (e) в нижней части регистрового файла. Три 32-битных регистра типа (с) могут являться управляющим регистром CR0 и отладочными регистрами DR6 и DR7.

Шесть 16-битных сегментных регистров в i386
В этой статья я рассматриваю лишь основной регистровый файл в тракте данных. Думаю, что по микросхеме i386 разбросаны и другие регистры для различных целей. К примеру, Segment Descriptor Cache содержит множество регистров, которые аналогичны типу (e) и, возможно, содержат записи кэша. Флаги статуса процессора и указатель инструкций (EIP) могут не реализовываться в виде отдельных регистров.6
Справа от регистрового файла в сложном блоке схемы 7-битные значения используются для выбора регистров. Два значения отвечают за выбор регистров (или констант) для чтения, а третье — для записи. Сейчас я анализирую схему, которая поможет понять, как присваиваются физические регистры.
▍ Сеть перетасовки
У этой схемы регистров есть ещё одна сложность. Как я говорил, младшие 16 бит основных регистров можно рассматривать как 8-битные регистры7 — например, 8-битные регистры AH и AL из младших 16 бит регистра EAX. Я уже объяснял, что в регистрах используются несколько управляющих линий записи, чтобы эти разные части обновлялись по отдельности. Но есть здесь проблема и с самой схемой.
Для демонстрации этой проблемы предположим, что вы выполняете 8-битную операцию с АЛУ в регистре AH, который представляет биты 15-8 регистра EAX. Для того, чтобы использовать эти биты в операции АЛУ их нужно сдвинуть вниз на позиции 7-0, а затем при сохранении данных в AH — обратно. С другой стороны, если мы выполняем операцию АЛУ над AL (биты 7-9 в EAX), нужные биты уже находятся в правильных позициях, и сдвигать их не требуется.
Для обеспечения возможности сдвига, необходимого при выполнении 8-битных операций с регистрами, регистровый файл i386 физически чередует биты из двух младших байтов (но не старших). В результате в регистровом файле бит 0 из AL оказывается рядом с битом 0 из AH и так далее. Это позволяет мультиплексорам при необходимости легко выбирать биты из AH или AL. Иными словами, каждый бит из AH и AL находится практически в правильной позиции, поэтому 8-битный сдвиг не требуется. (Если бы биты располагались по порядку, каждому мультиплексору пришлось бы подключаться к битам, разделённым восемью разрядами, что затруднило бы разводку).8

Показанная сеть перетасовки чередует младшие 16 бит
На фото выше показана сеть перетасовки. С каждым битом связаны три линии шины: две для чтения и одна для записи. Все они перемешиваются. Слева линии для 16 бит проходят по порядку. А вот справа два байта чередуются. Эта сеть перетасовки расположена между АЛУ и регистровым файлом, чтобы слова данных при сохранении в этом файле перемешивались и затем при чтении упорядочивались.9
На фото линии слева непрямые. Дело в том, что схема вверху уже, чем схема внизу. Практически все функциональные блоки в тракте данных выстраиваются при использовании одинакового размера для каждого бита (60 мкм). Это упрощает общую схему, так как функциональные блоки можно накладывать поверх друг друга, проводя через них вертикальную шину. Тем не менее схема над регистрами (устройство быстрого сдвига) где-то на 10% уже (54,5 мкм), поэтому дорожка должна сузиться и затем снова расшириться.10 Здесь у нас возникает компромисс. Такая схема требует больше пространства в отличие от его экономии в случае заужения устройства быстрого сдвига. Похоже, что в Intel этот компромисс сочли оправданным. (Наверное, потому что сеть перетасовки требует дополнительной разводки для чередования битов, и это решение позволило избежать использования лишнего места для втискивания этой разводки).
▍ Заключение
Если вы откроете учебник по проектированию процессоров, то найдёте в нём описание создания регистров из ячеек статической памяти. Тем не менее i386 показывает, что в реальном процессоре всё гораздо сложнее. Разрабатывая 386-ю серию процессоров, в Intel для реализации регистров вместо использования одной схемы использовали шесть разных.
Причём схема регистров i386 также раскрывает проблему обратной совместимости. Архитектура x86 поддерживает доступ к 8-битным регистрам для совместимости с другими процессорами из 1971 года. Эта совместимость требует дополнительной схемы, в частности сети перетасовки и чередующихся регистров. Глядя на схему процессоров x86, не могу не отметить преимущества архитектуры RISC, которая избегает многих особенностей таких процессоров.
Если вам интересно побольше узнать о том, как реализуются ячейки памяти i386, то я уже писал более низкоуровневую статью. Я планирую продолжить писать на тему этих процессоров, так что следите за обновлениями на Bluesky (@righto.com) или в RSS.
▍ Сноски и ссылки
1. В i386 множество регистров, которые важны только для программистов ОС (подробнее читайте в главе 4 руководства 386 Programmer's Reference Manual). К ним относятся регистр глобальной таблицы дескрипторов (Global Descriptor Table Register, GDTR), регистр локальной таблицы дескрипторов (Local Descriptor Table Register, LDTR), регистр таблицы векторов прерываний (Interrupt Descriptor Table Register, IDTR) и регистр задач (Task Register, TR). Есть четыре управляющих регистра (Control Registers, CR0-CR3). Из них CR0 управляет использованием сопроцессора, страничной организацией памяти и ещё некоторыми вещами. Шесть отладочных регистров (Debug Registers) для установки аппаратных точек останова обозначаются как DR0-DR3, DR6 и DR7. Два тестовых регистра (Test Registers) для тестирования TLB называются TR6 и TR7. Я подозреваю, что в i386 эти регистры находятся в блоке сегментации (Segment Unit) и блоке страничной организации памяти (Paging Unit), а не являются частью тракта данных. ↩
2. Как правило, схема драйвера записи генерирует на одной из битовых шин сильный сигнал низкого уровня, переключая выход соответствующего инвертора на высокий уровень. Это переключение одного инвертора приводит другой инвертор в нужное состояние. Для реализации такого поведения в инверторах устанавливаются более слабые подтягивающие транзисторы, чем обычно. ↩
3. Проходной транзистор либо пропускает сигнал, либо блокирует его. В CMOS это обычно реализуется с помощью проходного ключа, состоящего из параллельно подключённых NMOS и PMOS-транзисторов. Ячейка использует только NMOS-транзистор, который передаёт сигнал высокого уровня намного хуже, чем сигнал низкого. Поскольку на каждой стороне инверторов есть по одному проходному NMOS-транзистору, один из них будет передавать низкий сигнал, переключающий состояние. ↩
4. Битовая шина обычно предварительно заряжена на высокий уровень для чтения, после чего ячейка подтягивает её на низкий уровень к 0. Это более компактное решение в сравнении с добавлением в каждую ячейку схемы для подтягивания шины на высокий уровень. ↩
5. Обратите внимание, что для возможности записи данных из ячейки (b) в ячейку (a) нужна буферизация. Если подключить ячейки напрямую, ячейка (а) может так же легко переписать (b), как (b) переписать (a). Установка между ними инверторов препятствует влиянию ячейки (a) на (b). ↩
6. В архитектуре 8086 флаги состояния процессора не сохраняются в физическом регистре, а состоят из разбросанных по микросхеме триггеров (подробнее). И в i386 флаги наверняка реализованы аналогичным образом.
В 8086 счётчика команда (указателя инструкций) как такового не существует. Вместо этого схема упреждающей выборки команд содержит регистр, где хранится адрес текущей предвыборки. Если необходим адрес счётчика команд (к примеру, для передачи адреса возврата или выполнения относительного перехода), значение счётчика команд извлекается из адреса предвыборки. Если i386 устроен аналогично, для счётчика команд в регистровом файле не будет присутствовать физического регистра. ↩
7. По историческим причинам архитектура x86 совмещает два 8-битных регистра для формирования 16-битного. Система Datapoint 2200 (1971 год) на основе TTL содержала 8-битные регистры A, B, C, D, E, H и L, из которых H и L формировали 16-битовый регистр индексирования для доступа к памяти. В Intel создали микропроцессорную версию архитектуры Datapoint 2200, назвав её 8008. В процессоре Intel 8008 были расширены пары регистров, поэтому BC и DE также могли использоваться в качестве 16-битных. В Intel 8086 разработчики сохранили тот же дизайн, но изменили имена 16-битных регистров на AX, BX, CX и DX, назвав их 8-битные части AH, AL и так далее. Получается, что необычная структура регистрового файла в i386 объясняется совместимостью с программируемым терминалом из 1971 года. ↩
8. Для поддержки 8-битных и 16-битных операций в Intel 8086 использовалась аналогичная схема чередования, где чередовались две 8-битные половины. Хотя, поскольку этот процессор был 16-битным, чередование в нём было проще, нежели в 32-битном i386. В частности, ему не нужно было обрабатывать старшие 16 бит. ↩
9. Постоянная ROM в i386 расположена под сетью перетасовки. По этой причине для получения правильных результатов константы сохраняются с чередованием битов. (Из-за этого содержимое ROM было для меня совершенно непонятным, пока я не разобрался в паттерне чередования. Но это уже тема для отдельной статьи). ↩
10. Основная часть тракта данных (АЛУ и прочее) имеет ту же ширину ячейки 60 мкм, что и регистровый файл. Однако в целом тракт данных чуть шире этого файла. Почему? Дело в том, что для обработки 8- и 16-битных операций в нём между битами 7-8 и 15-16 присутствует небольшая схема. В результате эта логическая структура регистров на фото АЛУ ниже видна как светлые полосы. (Эти полосы также заметны на фото кристалла в начале статьи). ↩

Часть схемы АЛУ, представленная под структурой регистра EAX
Telegram-канал со скидками, розыгрышами призов и новостями IT ?

Комментарии (44)
firehacker
01.06.2025 11:27Так в чем абсурдность, про которую говорится в заголовке?
LinkToOS
01.06.2025 11:27Да, без сравнения с "простыми" схемами регистров, абсурдность сложности не очевидна.
Тем более в то время вряд ли были продвинутые оптимизаторы топологий.
Dmitri-D
01.06.2025 11:27Автор нашел кликбейтное название для того, что послужило успеху процессора -- все что запускалось на 8088 и на 80286 могло запускаться на 80386, т.е. обратная совместимость была обеспечена на аппаратном уровне. Это сложно недооценить - наработки софта уже были большими - игры, текстовые процессоры, утилиты и т.п.. Если бы переход на 80386 потребовал бы всё это перекомпилировать -- вот ровно из-за того что регистры вдруг перестали быть 16- и 8- разрядными, то переход на платформу был бы гораздо медленнее и гораздо сложнее. И вообще не факт что Интел вышел бы победителем из конкуренции с Моторолой. Примерно такая же ситуация с Microsoft. Если бы Microsoft требовала переписывать софт заново для каждой новой ОС, как это требовала MacOS не раз, из-за отсутствия обратной совместимости, то тоже не факт, что обрела бы такую долю рынка.
По поводу регистров... Ну не только они. Есть инструкции, которые почти никто не использует, напр. AAM - кто помнит на-вскидку что она делает? А она однобайтовая и занимает место в трансляторе инструкций.
Плюс есть реальный режим работы. Так называется режим, где адресация прямая и не защищена. Процессор стартует в этом режиме. Ну тоже довольно сильное переусложнение ради обратной совместимости.ermouth
01.06.2025 11:27Если бы Microsoft требовала переписывать софт заново для каждой новой ОС, как это требовала MacOS не раз
Зато Эпл наработал Розетту, которая натурально чудо какое-то. Я буквально на днях через копирование по домашней сети установил на M3 авиасимулятор написанный для x86-64 для МакОС 15-летней давности, под операционку на 5 мажорных версий младше. Его в аппсторе уже нет, по-другому никак, так что это была последняя надежда – вдруг хоть как-то заработает.
В результате на М3 фреймрэйт 70 фпс на макс качестве, и это куда лучше чем на 4,5ГГц i7 на том же разрешении.
На Винде при этом я не могу запустить без бубна старый нативный софт даже 10-летней давности иногда. А постарше софт и с бубном не запустишь.
daggert
01.06.2025 11:27Виста была в 2005? Это уже так-то 20 лет. Почти все с нее запускается, за редким исключением. С экспи чуток меньше, а это уже 25 лет почти…
Удачи повторить такое с маком. Особенно софт на с g3 на современном imac.
ermouth
01.06.2025 11:27Удачи повторить такое с маком
Слуште, у меня на маке под параллелсом как раз есть XP – полностью, замечу, интегрированная в Маковский UI – которую я бережно храню, чтобы запускать то, что у меня на Win7 не стартует. На нативном IBM-овском ноуте.
Под тем же параллелсом я под уж не помню какой виндой стартовал Ксемул для запуска кое-чего написанного под Мак G4. Не G3 конечно, но…
Так что удача тут особо не при чём, это как-бы штатная схема )
ermouth
01.06.2025 11:27Вот так выглядит стартующая XP на маке под ретиной, в 2025 )
daggert
01.06.2025 11:27Экспи запустить не проблема. Именно благодаря тому что шикарная обратная совместимость и стабильное апи платформы 86. А вот внутри маков - запуск старого софта это боль, изза кучи миграций и полной неподдержкой легаси через 3-4 года.
unreal_undead2
01.06.2025 11:27И вообще не факт что Интел вышел бы победителем из конкуренции с Моторолой
Если бы 68k побыстрее довели до массового производства в то время, когда IBM выбирала процессор для PC, всё могло пойти совсем по другому. Но история не терпит сослагательного наклонения.
checkpoint
01.06.2025 11:27Статьи Кена Шерриффа безусловно заслуживают уважения, спасибо за перевод. Но хотелось бы сделать пару замечаний.
1. В переводе есть неточость которая противоречит схеме и тому что написано у Кена. Речь идет о 8Т ячейке, цитата:
Переходный транзистор H блокирует сигнал, пока из регистра происходит считывание.
В оригинале:
Transistor H is a pass transistor that blocks this signal until a read is performed on this register;
Перевод по смыслу получился строго противоположный (слово until переведено неверно). Это станет очевидным если посмотреть на схему 8T ячейки. Транзитор H в ней ничего не блокирует, он не выполняет функцию арбитража, как может следовать из перевода. Этот транзистор коммутирует ячейку к соответствующей линии шины данных, и всё. На мой вгляд, правильный перевод мог бы звучать так:
Переходный транзистор H блокирует распростарнение сигнала от ячейки до тех пор, пока не будет выполнена операция чтения.
Для представленой ячейке 8T операция чтения может выполняться одновременно с операцией записи, при этом считываться будет записываемый в ячейку сигнал (посмотрите на схему и проследите распространение сигнала), никакой блокировки тут нет.
2. Тут уже небольшая претензия к Кену. В описании всё той же ячейки T8 автор пишет, что как только подается сигнал чтения (на транзистор H), то налиниях Read bitline появляются данные из текущей ячеки. Причем ранее он говорит о том, что сама ячейка резделена тразитором G который он почему-то называет буферным. Транзистор G не является буферным, это обычный "open drain", он подтягивает к "земле" линию шины данных (Read bitline) если на выходе ячейки находится лог "1". Если линия скоммутирована (сигнал Read wordline подан), то эта лог "1" на выходе превратиться в лог "0" на линии данных (Read bitline), так как линия данных будет тоже подтянута к "земле". Но встает вопрос, а как тогда на линии данных должна появится лог "1" если на выходе ячейки присутствует лог "0" ? Ведь в этом случае транзистор G будет закрыт и ячейка будет отключена от линии данных!? Ответ прост - линии данных всегда подтянуты к положительному потенциалу через резистор подтяжки в несколько десятко в кОм, т.е. по-умолчанию на них всега присутствуют логические единицы, а лог "0" появляется только когда отпирается транзистор G (т.е. на выходе ячейки - лог "1").
Кен ничего не говорит о "потдяжках", видимо полагая, что читатель находится в курсе таких подробностей. В статье есть сноска на небольшое замечание про подтяжку шины данных без особого разъяснения.Кстати, "подтяжки" на кристаллах обычно реализованы в виде таких же транзисторов. Если затвор планарного N-канального полевого транзистора соединить с истоком, то он будет всегда заперт и в таком состоянии его сопротивление составляет десятки-сотни кОм, что и требуется для подтяжек. Конденсаторы, о которых говорит Кен, это тоже транзисторы - емкость создается затвором по отношению к стоку или истоку. А ячейка динамической памяти это один транзистор с высокой паразитной ёмкостью затвора.
3. Об архитектуре x86. Кен справедливо змечает:
Причём схема регистров i386 также раскрывает проблему обратной совместимости. Архитектура x86 поддерживает доступ к 8-битным регистрам для совместимости с другими процессорами из 1971 года. Эта совместимость требует дополнительной схемы, в частности сети перетасовки и чередующихся регистров. Глядя на схему процессоров x86, не могу не отметить преимущества архитектуры RISC, которая избегает многих особенностей таких процессоров.
А также дополнительных линий управления для доступа к дробным частям большого регистра. Если в 32-х битной архитектуре i386 на один регистр требуется пять линий упрвления, то в современной 64-х битной их, очевидно, стало еще больше. То есть всё это "легаси" это не просто "дополнительный микрокод" как многие наивно полагают, оно поедает драгоценное пространство на площади кристалла и серьезно усложняет схемотехнику. И все это добро Интел продолжает тянуть на своих полечах в светлое будущее.
8street
01.06.2025 11:27И все это добро Интел продолжает тянуть на своих полечах
По-моему, АМД тоже. Да и вообще, все x86 должны.
dartraiden
01.06.2025 11:27Была надежда, что хотя бы от части легаси начнут избавляться в x86S. Не срослось.
LinkToOS
01.06.2025 11:27То есть всё это "легаси" это не просто "дополнительный микрокод" как многие наивно полагают, оно поедает драгоценное пространство на площади кристалла и серьезно усложняет схемотехнику.
А можно в цифрах - какой процент от площади кристалла это "усложнение" занимает? Как это влияет на максимальную частоту процессора? На сколько увеличивается время разработки новых процессоров из-за "усложненной" схемотехники?
eandr_67
Возможно, с точки зрения своей архитектуры Intel 80386 и был революционным - в проектировании микросхем я не разбираюсь. Но с точки зрения системы команд он был абсолютно зауряден: универсальные регистры и плоская 32-битная адресация - то, что в других процессорных архитектурах появилось намного раньше, чем в x86, и с позиции программиста 80386 - не "революция", а погоня за ушедшими вперёд конкурентами.
ermouth
Пример можно таких конкурентов? С массовым 32-битным процессором в 1986?
eandr_67
Например, Motorola 68k (надеюсь, построенный на нём Apple Macintosh вы считаете массовым компьютером?). Первое поколение (1979 год) имело 32-битную адресацию и 32-битную систему команд, реализуемую 16-битным ALU. Второе поколение (1984 год) - 32-адресация и 32-битное ALU.
ermouth
68К – 32-битный только в названии и ширине регистров. 16 бит АЛУ и шина данных, 24 битная шина адреса. Можно сколько угодно говорить про 32 бита, но 16Мб памяти максимум – это не про 32 бита.
Это «конкурент» для 286, а не 386.
Про второе поколение – 020 – так он был анонсирован в 1984, как и 386, но к производителям техники начал поступать только к осени 1985 в ограниченных количествах и со сниженной частотой. Эпл вообще не использовала 020 до марта 1987.
vadimr
Во время 386 - 16 мегабайт было выше крыши, а нормально 2 или 4. Я никогда в жизни не видел 386 машину более чем с 16 мегабайтами.
Был процессор 386SX, который не любили не из-за узкой шины, а из-за отсутствия плавающей арифметики.
У первого Мака, вроде, было 128 килобайт памяти при 32-разрядном процессоре.
ermouth
386DX также не имел плавающей арифметики на чипе. Разница по наличию/отсутствию сопроцессора на чипе между sx/dx – это про 486.
vadimr
Точно.
vanxant
Зато его можно было воткнуть в материнку от 286. Тогда, правда, ещё почти не было материнок с "кроватками", процы были припаяны.
В любом случае, 386SX сыграл ту же роль, что и 8088 в своё время. В 1981 было мало и дорого 16-битной периферии, в 1985-ом 32-битной (речь больше про то, что в 90-ых стали называть чипсет, а сегодня вообще почти целиком на кристалле процессора. Всякие драйверы (контроллеры) динамического ОЗУ, контроллеры прерываний и т.д.)
eandr_67
Именно потому я в своём исходном комментарии и написал:
Я не аппаратчик, а программист. И мне совсем не важно, какая именно физическая шина у процессора - важна именно разрядность регистров. Никто же не причисляет 8088, имеющий 8-битную физическую шину, к 8-битным процессорам.
И разве в 30386 физическая шина адреса была 32 битной? Да и 32-битная физическая шина данных была только у старших моделей.
Но куда важнее даже не разрядность процессоров, а наличие универсальных регистров и плоской адресации. ИМХО, именно отказ от принципов, на которых построена система команд в линейке 8086-80286, и переход к тому, что уже было у конкурентов, позволил создать процессор, для которого можно было написать компиляторы языков высокого уровня, эффективно оптимизирующие машинный код.
Из моего личного опыта: один и тот же C-код, производящий много целочисленных вычислений, на ДВК-3м2 (КМ1801ВМ3, 10 MHz) работал существенно быстрее, чем тот же самый код на IBM-PC/AT (20286, 12 MHz).
ermouth
Это, вообще говоря, совсем не факт.
Более того, у меня есть занятное эмпирическое наблюдение, что безукоризненно «ортогональные» системы не очень-то живучи. Да, система команд PDP-11 прекрасна. Как эсперанто.
Но не очень-то популярна.
Ну, тут надо и на код смотреть, и на компилятор – потому что наск помню 286 сложение регистр-регистр 2 такта, а 1801ВМ3 – 3 такта. В чудеса я не верю.
eandr_67
DEC погубила не система команд, а менеджеры. Именно концепции PDP-11 и VAX-11 стали основой и для 68k, и для 80386. Но в Motorola это сделали на много лет раньше, а Intel понадобилось несколько поколений процессоров, чтобы осознать всю бесперспективность своих оригинальных грабель.
На ДВК был компилятор, портированный в RT-11 из Unix. Он использовал r0 и r1 как базовые регистры для вычислений, регистры r2-r4 для оптимизации процесса вычислений: хранение промежуточных значений, указателей, переменных цикла; r5 использовался для границы стекового фрейма. А т.к. регистры универсальны, то r2-r4 использовались в любых процессорных командах сразу - без промежуточного копирования через другие регистры.
В MS-DOS использовался компилятор либо Borland, либо Microsoft: в разное время я использовал разные версии обеих фирм и какой точно это был компилятор, уже не вспомню.
Задача была не на сложение двух чисел, а на автоматизацию бухгалтерских задач - когда 1C ещё не было. И компилятор для PDP-11 выдавал куда более оптимизированный код. Дело не в скорости выполнения одной команды (я же специально указал, что тактовая частота процессора в ДВК была ниже), а в количестве этих команд. Компилятор для Intel генерировал ассемблерный код существенно большей длины - именно потому, что ему приходилось использовать узкоспециализированные регистры, привязанные к конкретным процессорным командам.
ermouth
А я не про DEC, а про ортогональную систему команд как концепцию. Не особо нужна она оказалась в реальности – и потому не выжила.
Так я вам про это и написал – надо смотреть на компилятор и код.
…потому что компиляция под не-ортогональную систему, особенно оптимизация, куда сложнее чем для ортогональной. В то время эта сложность оптимизации была критической, к началу 90-х перестала быть. Тут то ортогональность и кончилась.
vanxant
вот только если мы говорим про 8080 и его потомков, включая Z80, то там немножко наоборот. Куски сишного кода закатывали в систему команд, чтобы компилятор мог буквально подставить три инструкции на одну сишную команду. LOOP / DJNZ, косвенная адресация через регистр со смещением, ENTER/LEAVE, JECXZ и вот это вот всё
ermouth
А 68К и PDP конечно так делать не пытались, вот только откуда BNE/BEQ в 68К и PDP-11?
А сейчас вообще чёрте-что творят, вот FJCVTZS например совсем не в Интел придумана – и ничего. /s
Вообще, «закатывание» конструктов из высокоуровневых языков в инструкции процессора началось с IBM 704, которую доделывали когда уже был написан драфт Фортрана.
Апофеоза это «закатывание» достигло в iAPX 432, и провал показал, что тут важно не переборщить.
checkpoint
Они до сих пор этого не осознали и упорно, вот уже в течении 30-ти лет, выдают "баг" за "фичу".
unreal_undead2
Весьма популярна была в своё время и в оригинале, и в советских клонах. Умерла когда стало не хватать 16битного адресного пространства.
ermouth
Когда стало не хватать 16 бит появился vax11, тоже ортогональный во все стороны – но 32-битный. Умерло оно не из-за разрядности, а из-за непрактичности. Избыточность ортогональности была хорошо осознана уже в середине 70-х.
unreal_undead2
VAX умер скорее из за сложности
ermouth
Мы не про реализацию саму по себе, а про архитектуру системы команд, которая неизбежно ведёт к невостребованному переусложнению. Работу вы правильную привели, она как раз про это, канон практически.
unreal_undead2
Но ортогональность к дебатам RISC/CISC несколько ортогональна - не вижу, с чего бы она требовала сложного микрокода (против которого выступал Паттерсон).
beeruser
А какая разница? ISA 32-битная, линейная память. Там 32-битные операции, а не 16-битные. Ничто, кроме недостатка транзисторов, не мешало сделать 32-битное АЛУ. И программы бы никак от этого не менялись.
Это очень сильное утверждение для ТОГО времени.
16 мегабайт памяти, когда реальные системы имеют 0,5-1 мегабайта, это овер дофига.
Сейчас в 32-битных микроконтроллерах памяти может быть 16 килобайт ОЗУ и никого это не смущает.
vadimr
S/360 (1964).
Dmitri-D
это процессор на рассыпухе. Там не было микропроцессоров т.е. процессоров на 1 кристалле.
vadimr
В то время ещё не было (сейчас это Telum). Но архитектурно же это ничего не меняет.
krote
Ну конкурентов то не так много было, а точней из серьезных всего один - Motorola 68020, остальные кто сумел сделать 32бита не смогли построить вокруг них экосистему и остались нишевыми решениями (для телекома например). Т.е. сравнивать в основном надо с моторолой. Процессор Моторола не имел встроенного MMU в том же массовом компьютере Amiga, что сказывалось на невозможности нормальной реализации многозадачности и защиты памяти процессов и "подкачки", в то время как у 386 все это уже шло "из коробки".
НО в принципе, эти процессоры вышли практически один за одним, так что они оба можно сказать были революционными. Сама 32-бит архитектура можно сказать намного опередила свое время, ибо даже типичные объемы ОЗУ на то время это 0.5-1Мб а запускали на 386 MSDOS и 16-битные приложения.
Oangai
https://en.wikipedia.org/wiki/NS32000
Компьютеры бывали не только персональные, всё что покрупнее уже во второй половине 70х делалось 32бит на слайсевых процессорах, так что понимание таких архитектур и опыт уже были в наличии.
krote
ну это был слабый проц на фоне того же 386 и Моторолы, даже не имел полноценной 32бит архитектуры - 16бит АЛУ и 24бит адресация + 16 бит интерфейс (32 сделали практически как уже вышел 386), отсутствие MMU (реализовывалось отдельным навесом).
т.е. как то что то кто то уже конечно делал в других процессорах, но 386 выходит единственный на то время вобрал в себя все доступные идеи того времени. Маленькой революцией его определенном можно назвать, с моей точки зрения.
vanxant
На подходе был первый SPARC с весьма оригинальными идеями типа регистровых окон (что смешно, изначально он разрабатывался как сопроцессор для Моторов 680х0, но в процессе Остапа понесло:)
abcdsash
это точно... но хоть перегружаться не надо для выхода из защищенного режима в реальный
checkpoint
Революционность i386 состоит еще и в том, что это был первый микропроцессор полностью выполненный в софте. Т.е. вся аппаратура написана на HDL языке, симулирована и верифицирована, и только после этого был изготовлен "кремний". Интелу пришлось нанять каких-то студентов, чтобы те дописывали софт для симуляции. На эту тему у Кена тоже есть статья и она гораздо более интересная чем эта. Вообще, у этого автора можно переводить всё подряд - одна сплошная годнота. :-)