Финал же у всех закончившихся микроопераций один - они «возвращаются» в ICU с полученными результатами, и ICU, по мере готовности линий, потихоньку производит их отставку. На все про все в идеальных условиях у нас ушло 10-17 тактов, причем за каждый такт мы исполняли по три mOP’а (это обычно 1,5-3 инструкции x86).
Устройство процессоров Intel архитектуры NetBurst
Архитектура NetBurst сегодня лежит в основе всех процессоров Pentium 4, Xeon и Celeron. Эффективная длина конвейера в зависимости от варианта составляет 20 или 31 стадию. Количество одновременно исполняемых инструкций за такт в устоявшемся режиме - до четырех; тактовые частоты серийно выпускаемых процессоров - от 2,53 до 3,8 ГГц - это по всем показателям лучше данных по K8. Лучше, но, к сожалению, только сугубо теоретически и на специально подготовленном коде.
NetBurst тщательно оптимизировалась для работы на высоких частотах, и назвать эту архитектуру классической можно только с большой натяжкой. Для начала упомянем хотя бы тот же Trace Cache (TC), заменяющий в NetBurst классический Гарвардский I-cache (L1 code). Идея состоит в том, что в NetBurst декодер вынесен за пределы собственно конвейера - процессор конвертирует x86-инструкции в свое внутреннее представление не на лету, как AMD K8, а заблаговременно, еще на стадии копирования кода в кэш-память первого уровня. Устроено это все так своеобразно (например, в процессе декодирования декодер убирает безусловные переходы, занимается предсказанием условных переходов и может едва ли не «разворачивать» циклы!), что внутреннему устройству Trace Cache и декодеру инструкций для него вообще можно посвятить отдельную статью (чего мы делать сейчас не будем; скажем только, что декодер для TC работает очень медленно). Точная длина соответствующего участка конвейера неизвестна, но составляет, по разным оценкам, от 10-15 до 30 тактов - то есть этот «скрытый» участок конвейера имеет длину едва ли не большую, чем «видимый». Таким образом, введение TC позволяет практически вдвое уменьшить эффективную длину конвейера (страшно даже представить NetBurst без Trace Cache)[С K8, кстати, та же самая история - декодированием и подготовкой инструкций занята примерно половина конвейера. Есть предположения, что в следующем поколении процессоров AMD - архитектуре K9 - появится и Trace Cache. Скажем, в K8 подобное нововведение уменьшило бы видимую длину конвейера до 6-7 стадий в целочисленных вычислениях и до 12 стадий в вычислениях с плавающей точкой!]! Емкость TC для всех NetBurst составляет 12 тысяч микроопераций; в терминах классического x86 это соответствует примерно 8-16 Кбайт кэша L1-data; причем работает TC и обслуживающая его логика на половинной частоте ядра и наполняется декодером с темпом не более одной новой инструкции за такт. Поэтому если процессор некстати вылетит на незакэшированный участок кода (а кэш маленький, и подобная ситуация вполне возможна), то от теоретически возможных четырех инструкций за такт в лучшем случае останется лишь одна. Подобные «резкие потери темпа» вообще свойственны архитектуре NetBurst; к счастью, такие ситуации возникают редко.
Дальнейшее повествование я буду вести, указывая время исполнения инструкции для ядра Northwood (20-стадийный конвейер). Для более нового Prescott в целом справедливо все то же самое, просто время исполнения отдельных стадий слегка возросло.
Первые четыре такта работы конвейера - извлечение специальным блоком выборки инструкций из TC и второй этап предсказания условных переходов. В первый раз декодер TC уже пытался предсказать переход, так что второй этап предсказания фактически сводится к «угадыванию» того, правильно ли декодер угадал переход еще «в тот раз» или нет. Заодно для некоторых записей TC («закладок»["Закладки" позволяют увеличить эффективный объем Trace Cache, поскольку вместо нескольких mОР’ов мы храним в нем одну «закладку»]) происходит их «развертывание» в несколько микроопераций. В силу того что TC работает на половинной частоте ядра, происходит выборка довольно медленно и каждый ее этап занимает по два такта конвейера. Затем полученные микрооперации (до шести штук за такт) складываются в традиционную очередь выборки (Fetch Queue), где буферизуются, сглаживая неравномерность декодирования и обеспечивая «на выходе» устоявшийся темп декодирования в три микроинструкции за такт. Задержка, вносимая буферизацией, - 1 такт; еще 1 такт расходуется на то, чтобы подготовить внутренние ресурсы процессора для выбранной из Fetch Queue тройки mOP’ов. Затем еще два такта уходит на то, чтобы подготовить для каждого mOP’а персональные физические регистры для вычислений (в рамках техники переименования регистров). И, наконец, на последнем, девятом по счету такте полностью готовые к исполнению mOP’ы начинают «распихиваться» по очередям инструкций, стоящих на выполнение.