Процессоры Intel Pentium III, Pentium M и Core Duo
В процессорах семейства P6 инструкции считываются из I-кэша выровненными блоками по 16 байтов за такт. Выборка производится с опережением – у процессора есть два буфера, в которые помещаются два последних считанных блока. На вход подсистемы декодирования в каждом такте передаётся порция байтов, начинающаяся с того места, где была прекращена обработка в предыдущем такте. Длина этой порции ограничена также 16 байтами. Порция байтов поступает на вход определителя длины инструкций (ILD), который производит её разметку – нахождение границ и положения кода операции в каждой x86-инструкции.
Определитель длины инструкций должен быть обязательно реализован неконвейерным образом, с временем работы 1 такт – так как в следующем такте надо будет размечать новую порцию, начинающуюся после последней инструкции, размеченной в данном такте. Определитель содержит 16 одинаковых устройств, построенных на основе программируемых логических матриц (PLA). На вход каждого такого устройства подаётся фрагмент кода длиной 4 байта, начинающийся с одного из 16 байтов в обрабатываемой порции. Устройство (PLA) представляет собой примитивный декодер, который предполагает, что данный фрагмент является началом x86-инструкции (без префиксов), и пытается определить её длину. Кроме того, это устройство анализирует первый байт в фрагменте и определяет, не может ли он являться префиксом.
Результаты работы всех таких устройств собираются воедино с помощью цепочки схем быстрого переноса. По существу, эти схемы последовательно выстраивают список инструкций на основе данных о длинах и признаках наличия префиксов, начиная с первой инструкции в обрабатываемой порции байтов. По результатам этого выстраивания в специальных массивах делаются пометки о позициях кода операции и последнего байта в каждой инструкции. Эта информация используется в последующем такте для извлечения инструкций из буфера и передачи их на вход трёх каналов декодера.
В некоторых случаях определитель длины инструкций не может произвести разметку за один такт. Например, если встречается префикс, меняющий длину непосредственного операнда или смещения адреса в инструкции с 16 бит на 32 бита, либо наоборот, определитель переходит в «медленный» режим, размечая по 4 байта за такт. Однако такие случаи не часты и по существу представляют собой нарушение правил программирования. Кроме того, разметка замедляется, если в какой-то инструкции встречается два или более префиксов – в этом случае обработка каждого дополнительного префикса занимает один такт. На практике эта ситуация также очень редка.
После разметки три выделенные x86-инструкции передаются в основной декодер – точнее, в три параллельно работающих канала декодирования. Эти три канала не являются полностью симметричными – только первый из них может обработать любую инструкцию, а оставшиеся два имеют ограничения: инструкция должна иметь длину до 8 байтов и порождать только один МОП. У первого канала декодирования таких ограничений нет – он может породить до 4 МОПов в одном такте, параллельно с работой двух других каналов. Для обработки самых сложных инструкций (более 4 МОПов) требуются дополнительные такты, и в этом случае обработка ведётся последовательно.
Таким образом, схему работы декодера в процессоре P-III можно обозначить как «4-1-1 / >4»: он может обрабатывать в одном такте, либо три инструкции, порождающие до 6 МОПов (4+1+1), либо одну, порождающую более 4 МОПов. Порождаемые МОПы накапливаются в небольшой очереди перед отправкой (группами по три) в последующие тракты процессора. Схема «4-1-1» накладывает определённые ограничения на оптимальное размещение x86-инструкций в коде: сложные инструкции (в частности, инструкции типа Load-Op) должны чередоваться с простыми, а не следовать подряд друг за другом. Впрочем, даже при плотном размещении нескольких сложных инструкций всё равно в каждом такте будет порождаться как минимум 2 МОПа, а очередь МОПов после декодера позволит сглаживать возникающие неравномерности.
В процессоре P-III при декодировании инструкций загрузки из памяти с последующим исполнением (Load-Op) порождаются отдельные МОПы для загрузки и для выполнения. Аналогично, для инструкций выгрузки в память также порождаются два отдельных МОПа: для вычисления адреса, и для осуществления записи. В обоих случаях два МОПа обслуживаются в последующих трактах процессора по отдельности и занимают его ресурсы. Из-за частой встречаемости инструкций, содержащих загрузку из памяти и выгрузку в память, среднее число МОПов на одну x86-инструкцию может находиться в диапазоне от 1.3 до 1.5.
Начиная с процессора P-M, в декодере реализован механизм «слияния микроопераций» (micro-ops fusion), когда порождается единый МОП, содержащий два элементарных действия. Разделение на эти элементарные действия происходит при запуске МОПа на исполнение. Механизм слияния микроопераций похож на аналогичный механизм в процессорах AMD K7/K8. Этот механизм экономит ресурсы буферов и увеличивает эффективную пропускную способность трактов процессора. Благодаря такому механизму среднее число МОПов на одну x86-инструкцию значительно снижается и становится близким к единице. Кроме того, инструкции Load-Op могут теперь обрабатываться во всех трёх каналах декодера, что, практически, сводит на нет недостатки несимметричной схемы «4-1-1».
Правда, в декодере процессоров P-III и P-M имеется ещё одно ограничение, касающееся инструкций SSE. Эти инструкции могут обрабатываться только в первом канале декодера — причём данное ограничение относится не только к упакованным инструкциям SSE, расщепляемым на два МОПа, но и к скалярным инструкциям тоже. Кроме того, на инструкции SSE с загрузкой из памяти (Load-Op) не распространяется механизм слияния микроопераций. Таким образом, скалярная инструкция SSE типа Load-Op в процессоре P-M преобразуется в два МОПа, а упакованная – в четыре. Данные ограничения связаны, скорее всего, со сложностью реорганизации декодера для поддержки операций SSE.
В процессоре P-M2 (Core Duo) декодер x86-инструкций был радикально переделан. Теперь он поддерживает слияние микроопераций для инструкций Load-Op всех типов (включая различные SSE, за исключением инструкций упаковки/распаковки), а также обработку инструкций SSE (как скалярных, так и упакованных) во всех трёх каналах декодера. В результате число МОПов, порождаемых для скалярных инструкций SSE типа Load-Op, снизилось с двух до одного, а для упакованных – с четырёх до двух. Предельная пропускная способность декодера выросла в три раза – с одной инструкции SSE за такт до трёх.
Схему декодера процессора P-M2 можно обозначить как «4-2-2 / >2». По своей гибкости эта схема превосходит схему декодера процессора AMD K8 «2-2-2 / >2» благодаря обработке сложных инструкций в первом канале декодера одновременно с работой двух других каналов. Правда, декодер процессора K8 может порождать два МОПа также для некоторых других типов инструкций (не только SSE), но большинство таких инструкций в процессоре P-M2 являются простыми, с преобразованием в один МОП.
Таким образом, последний представитель семейства P6/P6+ – процессор P-M2 (Core Duo) – имеет гибкий трёхканальный декодер, эффективно работающий с подавляющим большинством x86-инструкций. Он в целом не уступает декодерам, реализованным с применением предекодирования перед помещением инструкций в I-кэш, и лишён некоторых их недостатков. Применённая в декодере схема потребовала введения сложного определителя длины инструкций и удлинения конвейера на один такт.
Несмотря на то, что МОПы выходят из декодера группами по три, в последующих трактах они обрабатываются и отслеживаются по отдельности. В частности, в буфере переупорядочения они размещаются плотно, без потери на фрагментацию, как это свойственно микроархитектурам, в которых МОПы собираются в фиксированные группы с привязкой позиции в группе к конкретным очередям и устройствам.
Одновременно с помещением новой группы МОПов в буфер переупорядочения и в очередь планировщика производится переименование (переназначение) регистров результатов для этих МОПов. Каждой позиции буфера переупорядочения приписан один внутренний (физический) регистр длиной 80 разрядов, который ставится в соответствие исходному (архитектурному) регистру. Обратное копирование содержимого физического регистра в соответствующий архитектурный будет произведено в момент отставки операции. Для хранения одного 128-битного регистра XMM используются два внутренних регистра.