12. Повышение эффективности процессора

### 12.1. Конвейерная архитектура процессора

Конвейер инструкций – это техника для увеличения пропускной способности процессора (количества инструкций, выполняемых в единицу времени). Несколько инструкций перекрываются во времени. При этом используется врожденный параллелизм, существующий среди действий, составляющих инструкцию. Инструкция разбивается на последовательность этапов. Различные этапы выполняются одновременно и параллельно (различными схемами). Техника увеличивает пропускную способность благодаря параллельному выполнению нескольких операций. Однако время выполнения (время запаздывания, latency) одной инструкции остается прежним или даже увеличивается, т.к. всё равно нужно выполнить все этапы. Непредсказуемость времени выполнения одной инструкции из-за остановок конвейера осложняет его использование в системах реального времени. Техника не требует особых усилий со стороны пользователей. Это выглядит очень привлекательно: техника предлагает увеличение производительности при сохранении существующего кода. В настоящее время конвейеризация – это ключевая техника в задачах построения быстродействующих процессоров.

Время, требуемое для продвижения инструкции по одному этапу конвейера, называется процессорным циклом. На рис. 12.1 показано разбиение инструкции на несколько этапов. При этом каждый этап требует меньше аппаратуры и выполняется за меньшее время. Из-за того, что все этапы работают одновременно, время процессорного цикла определяется задержкой самого медленного этапа. Важной задачей при разработке конвейера является балансировка длины каждого этапа.

Рис. 12.1

Рассмотрим простейший конвейер RISC-процессора. В нем выполнение инструкции разбивается на 5 этапов:

1. IF (Instruction Fetch) – выборка инструкции по адресу, указываемому счетчиком команд, приращение счетчика команд.

2. ID (Instruction Decode) – декодирование инструкции, выборка операндов, вычисление адреса перехода.

3. Ex (Execute) – выполнение инструкции.

4. Mem (Memory Access) – доступ к памяти в случае инструкций загрузки или сохранения.

5. WB (Write-Back) – запись результата в регистровый файл.

На рис. 12.2 иллюстрируются модули и этапы такого конвейера.

Рис. 12.2

Работу конвейера отражает временная диаграмма (таблице 1).

Таблица 1

| Номер такта
Номер инструкции | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
i | IF | ID | Ex | MEM | WB |  |  |  |
i + 1 |  | IF | ID | Ex | MEM | WB |  |  |
i + 2 |  |  | IF | ID | Ex | MEM | WB |  |
i + 3 |  |  |  | IF | ID | Ex | MEM | WB |
i + 4 |  |  |  |  | IF | ID | Ex | MEM | WB

Конвейеризация увеличивает пропускную способность процессора – количество инструкций, завершенных в единицу времени), однако не сокращает время выполнения отдельной инструкции. Более того, обычно она даже немного увеличивает время выполнения каждой инструкции из-за издержек управления конвейером. Повышение пропускной способности означает, что программа выполняется быстрее и имеет меньшее время выполнения, несмотря на то, что каждая отдельная инструкция выполняется дольше.

Тот факт, что время выполнения каждой инструкции не уменьшается, накладывает ограничения на длину конвейера. Кроме ограничений, связанных с задержкой конвейера, ограничения также возникают из-за несбалансированности этапов конвейера и издержек конвейеризации. Дисбаланс между этапами конвейера снижает производительность, т.к. продолжительность такта синхронизации не может быть меньше продолжительности самой долгой стадии. Издержки конвейеризации возникают из-за задержек установки значения на регистрах и перекоса сигнала синхронизации.

Дана неконвейеризированная машина с 5 этапами, имеющими продолжительность 40, 40, 50, 40, 40 нс. Пусть накладные расходы на конвейеризацию составляют 5 нс. Тогда среднее время выполнения инструкции на неконвейеризированной машине будет 210 нс. В случае конвейеризации продолжительность такта синхронизации будет равно длительности самого медленного этапа и накладных расходов, т.е. 55 нс. Это же время соответствует среднему времени выполнения инструкции на конвейере. Тогда ускорение, достигаемое при конвейеризации равно 210 / 55 = 3,81.

Наибольшая эффективность конвейера достигается, когда его загрузка близка к максимальной. Однако при выполнении программы могут возникать ситуации, препятствующие выполнению следующей инструкции в следующем такте. Они называются конфликтами. Конфликты сокращают производительность конвейера в сравнении с идеальным ускорением.

Важным вопросом является выбор количества этапов конвейера. Классический цикл выполнения инструкции включает 3 стадии: Fetch, Decode, Execute. Классика RISC процессоров содержит 5 стадий: Fetch, Decode, Execute, Memory Access, Register Write Back. AVR, PIC микроконтроллеры в конвейере имеют 2 стадии: Fetch, Decode-Execute. В процессорах общего назначения распространены также 7, 10 этапов. Pentium 4: 20. Pentium 4 Prescott: 31.

Количество этапов оказывает существенное влияние на производительность. Преимуществом «глубоких» (Deep) конвейеров является простота схем, реализующих отдельные стадии (часто стадия занимает 12-25 вентилей), и малая длина путей прохождения сигналов, что позволяет добиться более высокой тактовой частоты. Кроме того, чем «глубже» конвейер, тем выше пропускная способность. Недостатки: увеличивается цена конфликта; возрастает число тактов на инструкцию; усложняется оборудование пересылки значений.

12.2 Конвейерные конфликты

Конфликт – это любая причина, вызывающая приостановку конвейера. В ходе приостановки, инструкции, предшествовавшие конфликтной продолжают выполнение, а последующие – нет, образуя «пузырь».

Выделяют три класса конфликтов:

1. Структурные конфликты – конфликты, возникающие когда несколько инструкций пытаются использовать один и тот же ресурс одновременно.

2. Конфликты по данным – данным – конфликты, возникающие, если инструкция зависит от данных, используемых более ранними инструкциями в конвейере.

3. Конфликты по управлению.

12.2.1 Структурные конфликты

Совмещенное выполнение инструкций в конвейерном процессоре требует конвейеризации функциональных модулей и дублирования ресурсов для обеспечения выполнения всех возможных комбинаций инструкций в конвейере. Если какие-либо комбинации инструкций не могут быть выполнены из-за конфликта по ресурсам, то имеет место структурный конфликт.

Наиболее распространенные структурные конфликты возникают, если некоторые функциональные модули не полностью конвейеризированы. В этом случае последовательность инструкций, использующая данный модуль не может выполняться со скоростью одна инструкция за такт. Другой источник структурных конфликтов имеет место, если какой-либо ресурс не был дублирован достаточное количество раз для обеспечения возможности выполнения всех комбинаций инструкций в конвейере. Например, регистровый файл процессора может иметь только один порт записи, однако при определенных обстоятельствах конвейер может попытаться осуществить две операции записи за такт. В результате возникнет структурный конфликт.

Когда последовательность инструкций встречает структурный конфликт, конвейер приостанавливает выполнение одной из инструкций до тех пор, пока требуемый модуль не будет освобожден.

При прочих равных процессор без структурных конфликтов будет иметь более низкий CPI. Почему же проектировщики допускают возможность возникновения структурных конфликтов? Основная причина заключается в сокращении стоимости модуля, т.к. конвейеризация всех функциональных модулей или их дублирование может быть слишком затратным. Например, полностью конвейеризированный модуль умножения с плавающей точкой требует большого количества вентилей. Если структурный конфликт встречается редко, то попытки его предотвращения могу не окупить себя.

Возможны и другие решения. Например, планирование, в ходе которого инструкции, которые могут вызвать конфликт, переставляются. Это может осуществляться как аппаратно, так и программно. Аппаратное решение усложняет процессорную логику. Программное решение требует более сложных компиляторов. Ещё одним решением может быть динамическая реконфигурация, когда при повышении использования какого-либо модуля в ходе решения задачи процессор обнаруживает такую ситуацию и его часть динамически перестраивается, вводя в пользование дубликаты недостающих ресурсов, например, АЛУ с плавающей точкой.

12.2.2 Конфликты по данным

Конфликты по данным возникают, когда конвейер изменяет порядок запросов чтения/записи операндов таким образом, что он отличается от порядка, видимого при последовательном выполнении инструкции на неконвейеризированном процессоре.

Выделяют следующие разновидности конфликтов по данным:

1. Read after write (RAW) – чтение после записи;

2. Write after read (WAR) – запись после чтения;

3. Write after write (WAW) – запись после записи.

RAW-конфликт – ситуация, возникающая при попытке чтения значения, которое ещё не было записано в ходе предыдущей инструкции. Пример и временная диаграмма (рис. 12.3) показаны ниже. Как видно, инструкция sub обращается к результату инструкции add раньше момента, когда он записывается в регистровый файл.

Add R2, R3, R4

Sub R5, R2, R6

Рис. 12.3

WAR-конфликт – это конфликт, в котором инструкция пытается записать значение в регистр, который читается предыдущей инструкцией конвейера на более поздней стадии (рис. 12.4).

Sw R1, 0(R2)

Add R2, R3, R4

Рис. 12.4

WAW-конфликт представляет собой нарушение порядка чтения (рис. 12.5). Он возникает, когда инструкция пытается записать регистр, записываемый предыдущей инструкцией (например, при записи в течение нескольких тактов процессора, при неравномерной длине инструкций).

Lw R1, 0(R2)

Add R1, R2, R3

Рис. 12.6

Для преодоления конфликтов по данным используется несколько подходов: пересылка данных (forwarding), приостановка конвейера, переупорядочение инструкций.

Суть техники пересылки данных заключается в том, что в процессоре вводятся дополнительные пути. Эти пути передают значения с выхода АЛУ или других модулей на их вход на следующем такте. Если обнаруживается конфликт, то операнд следующей инструкции подается на вход ожидающего модуля по цепи обхода, а не из регистрового файла. Следует отметить, что некоторые конфликты по данным нельзя устранить подобным способом:

Ld R1, 0(R2)

Dsub R4, R1, R5

And R6, R1, R7

Or R8, R1, R9

Инструкция загрузки данных Ld получает данные из памяти только на четвертом такте. Следующие за ней инструкции требуют значения этого же регистра раньше. В таком случае потребуется приостановка конвейера.

Другим подходом борьбы с конфликтами по данным является планирование компилятором. Суть подхода заключается в том, что компилятор расставляет инструкции таким образом, чтобы избежать конфликтов, не нарушая корректности программы.

Рассмотрим пример. Исходный код:

a = b + c;

d = e – f;

a, b, c, d ,e, и f в памяти.

Медленный код:

LW Rb,b

LW Rc,c

ADD Ra,Rb,Rc

SW a,Ra

LW Re,e

LW Rf,f

SUB Rd,Re,Rf

SW d,Rd

Более быстрый код:

LW Rb,b

LW Rc,c

LW Re,e

ADD Ra,Rb,Rc

LW Rf,f

SW a,Ra

SUB Rd,Re,Rf

SW d,Rd

Переименование регистров (register renaming) - техника оптимизации, направленная на предотвращение конфликтов WAR и WAW (RAW – остаются в силе). Ее идея заключается в том, чтобы рассматривать регистры, как имена, а не позиции (рис. 12.7). Как следствие, появляется возможность иметь больше позиций, чем имен и возможность динамического отображения имени на позицию. Пример показан на рисунке.

Рис. 12.7

Таблица отображения содержит соответствие (имя-позиция). При записи выделяется новая позиция и заносится в таблицу. При чтении находится позиция наиболее поздней записи путем поиска по имени в таблице. Существует необходимость освобождения позиций.

12.2.3 Преодоление конфликтов по данным с использованием динамического планирования

Серьезнейшим ограничением простых подходов конвейеризации является то, что они используют выдачу и выполнение инструкций строго по порядку: инструкции выдаются в порядке, предписанном программой, и если инструкция вызывает простой конвейера, то никакие следующие за ней инструкции не могут продолжать выполнение. Таким образом, если существует зависимость между двумя расположенными рядом инструкциями в конвейере, то возникнет простой. Если используется несколько функциональных модулей, то они могут работать вхолостую. Например:

DIV F0, F2, F4

ADD F10, F0, F8

SUB F12, F8, F14.

Инструкция SUB не может быть выполнена из-за зависимости инструкции ADD от результата инструкции DIV и возникшего вследствие этого простоя; в то же время сама инструкция SUB не зависит ни от одной из этих инструкций. Таким образом возникает ограничение производительности, которое можно преодолеть, сняв требование на выполнение инструкций в порядке, заданном программой.

В классическом пятиступенчатом конвейере конфликты по данным и структурные конфликты проверяются на стадии декодирования: если инструкция может быть выполнена без конфликтов, происходит выдача со стадии декодирования.

Для того, чтобы разрешить выполнение инструкции SUB из предыдущего примера, необходимо разделить процесс выдачи на две части: проверку структурных конфликтов и ожидание отсутствия конфликтов по данным. Следовательно, используется выдача по порядку, однако выполнение инструкции начинается как только все ее операнды доступны. Такой сценарий называется выполнение не по порядку, что подразумевает и завершение не по порядку.

Выполнение не по порядку может приводить к новым WAR и WAW конфликтам. Для их разрешения используется в частности переименование регистров.

Завершение не по порядку создает сложности в обработке исключений. Динамическое планирование с завершением не по порядку должно сохранить поведение в случае исключений, т.е. исключения должны возникнуть в точности тогда, когда они возникли бы при выполнении в порядке, заданном программой.

12.2.4 Конфликты по управлению

Конфликты по управлению могут приводить даже к более высоким потерям производительности, чем конфликты по данным. Когда выполняется инструкция ветвления, она может изменить значение счетчика команд на что-то другое нежели текущее значение плюс 4. Если инструкция ветвления изменяет значение PC на значение целевого адреса, то переход называется выполняемым, иначе – невыполняемым.

Простейшим подходом работы с ветвлениями является приостановка конвейера до определения нового значения счетчика команд. Один такт задержки для каждой инструкции ветвления приведет к потерям производительности в 10 – 30% в зависимости от частоты переходов. Поэтому огромное значение имеет разработка техник предотвращения подобных потерь.

Существует много методов работы с простоями конвейера, вызванными задержками инструкций ветвления. Далее рассматриваются четыре простых схемы времени компиляции. В этих схемах действия, выполняемые над инструкцией ветвления, являются статическими, т.е. они фиксированы для каждой ветви на всем промежутке выполнения. Программное обеспечение может попытаться минимизировать издержки ветвлений, используя знания об устройстве аппаратуры и поведении ветвей.

Метод выжидания. Простейшая схема обработки ветвлений заключается в замораживании инструкций в конвейере, путем блокирования инструкций после инструкции ветвления до тех пор, пока не будет определено направление. Привлекательность решения заключается в его простоте, как с аппаратной, так и с программной точки зрения.

Метод возврата. Более производительная и лишь немного более сложная схема заключается в рассмотрении каждого перехода как невыполняемого, разрешая аппаратному обеспечению продолжать выполнение, как если бы переход не был выбран. Здесь важно не изменить состояние процессора до тех пор, пока направление ветвления не станет известно наверняка. В простейшей реализации выборка продолжается как будто выбрана обычная инструкция. Однако если оказывается, что переход выполняемый, то выбранная инструкция преобразуется в пустую операцию nop, а выборка повторяется, но уже по новому адресу.

Следующая схема представляет собой противоположность метода возврата. В ней каждый переход рассматривается как выполняемый. Как только инструкция декодирована, выполняется вычисление направления ветвления и по рассчитанному адресу осуществляется выборка очередной инструкции.

Задержанный переход. Эта схема широко использовалась в ранних RISC процессорах. В архитектуру вводится правило: k инструкций после инструкции ветвления выполняются обязательно. Эти инструкции называются слотами задержки. Задача компилятора заключается в выборе допустимых и полезных инструкций для слотов задержки. Три случая рассматриваются в таблице 2 и на рис. 12.8.

Таблица 2

Рассматриваемый случай | Требования | Когда увеличивается производительность
(a) | Команда условного перехода не зависит от переставляемой команды. | Всегда
(b) | Выполнение переставляемой команды должно оставаться корректным, даже если переход не выполняется. Может потребоваться копирование команды, т.к. она достижима и по другому пути. | Когда переход выполняется. Может увеличить размер программы в случае копирования команды.
(c) | Выполнение переставляемой команды должно быть корректным, даже если переход выполняется | Когда переход не выполняется.

Рис. 12.8

12.2.5 Предсказание ветвлений

Конфликты, вызванные ветвлениями, наносят большой урон производительности. Исследования показывают, что в программах больше условных, чем безусловных переходов. При этом больше переходов вперед (75%), чем назад. 67% переходов выбираются. Среди переходов вперед выбираются 60%. Среди переходов назад выбираются около 80% (из-за циклов).

Предсказание ветвлений может осуществляться статически или динамически. Статическое предсказание – прогноз устанавливается до выполнения. Динамическое предсказание – адаптируется в процессе выполнения. Предсказание может выполняться компилятором или аппаратурой.

Статическое предсказание выполняется на этапе компиляции. У каждой инструкции ветвления указывается дополнительный бит (1 – ветвь будет выбрана, 0 – не будет). Требуется поддержка со стороны архитектуры команд. Простейшая схема заключается в том, что переход всегда помечается как выбираемый. Более точная схема предсказывает ветвления с использованием профиля, созданного на основе предыдущих запусков. Достоинства статического прогнозирования: нет ограничения по аппаратуре; низкая цена. Недостатки: предсказание не изменяется в ходе выполнения; плохая производительность.

Динамическое предсказание ветвлений базируется на том, что каждая ветвь имеет свои особенности – «индивидуальность». Кроме того, наблюдается строгая «предрасположенность» ветвей к выбору того или иного перехода (например, циклы). Достоинства: точность изменяется динамически. Недостатки: затраты по площади кристалла, энергопотреблению; ограниченная производительность.

Простейшей динамической схемой прогнозирования ветвлений является таблица истории переходов или буфер предсказания переходов. Таблица истории представляет собой небольшую память, индексируемую младшей частью адреса инструкции перехода. Память содержит бит, который указывает была ли ветвь недавно выбрана. При промахе значение по заданному адресу в таблице изменяется. Доступ к таблице осуществляется на этапе выборки инструкции (IF).

Простейшая однобитная схема предсказания характеризуется плохой производительностью: в случае, когда ветвь в большинстве случаев выбирается, а затем один раз не выбирается, предсказатель выдаст неправильное значение дважды, т.к. при неправильном предсказании значение его бита изменилось. Для преодоления недостатка используются двухбитовые схемы предсказаний (рис. 12.9). В них предсказание должно оказаться неправильным дважды, прежде чем будет изменено. Примеры предсказателей показаны на рисунке. Исследования n-битовых предсказателей показали, что 2-битовые предсказатели работают практически также хорошо, как и предсказатели с большим количеством бит. Поэтому большинство систем используют 2-битовые реализации.

Какой точности можно добиться от буфера предсказания переходов с 2 битовым предсказателем? Результаты исследований на тестовом наборе SPEC89 показывают, что буфер с 4096 предсказателями дает точное предсказание 82 – 99% случаев.

Рис. 12.9

2-битовые предсказатели полагаются на недавнее поведение только данной ветви для предсказания ее поведения в будущем. Точность предсказания может быть повышена, если использовать недавнее поведение и других ветвей, а не только той, которую нужно предсказать. Предсказатели, использующие поведение других ветвей, называются коррелирующими предсказателями (двухуровневыми предсказателями). В общем случае (m, n)-предсказатель использует историю переходов последних m ветвей для выбора из 2m предсказателей, каждый из которых имеет n-бит. Такой подход привлекателен тем, что при небольших аппаратных издержках можно получить более высокую точность предсказания, чем в случае обычного 2-битового предсказателя.

Следующим шагом оптимизации является использование соревнующихся предсказателей, состоящих из нескольких предсказателей, обычно один основан на глобальной информации, а другой на локальной, и механизма выбора между ними. Такие предсказатели стали стандартом для процессоров Pentium 4, Power5. Наиболее сложная версия была разработана для процессора Alpha 21264 и будет рассмотрена позже.

Буферы адресов переходов

Для сокращения задержек, связанных с обработкой инструкций ветвления, полезно знать, является ли еще не декодированная инструкция ветвлением и, если является, то каким будет следующее значение счетчика команд. Если выбранная инструкция – это инструкция ветвления и направление перехода известно, то издержки сокращаются до нуля. Кэш предсказания ветвлений, хранящий предсказанный адрес следующей после перехода инструкции, называется буфером адресов переходов или кэшем адресов переходов (Branch-Target Buffer, BTB). Пример показан на рис. 12.10.

Рис. 12.10

Буфер адресов переходов работает следующим образом. Значение адреса очередной выбранной инструкции сопоставляется с адресами ветвей в кэше (BTB). Если есть совпадение, то выбранная инструкция представляет собой выполняемый переход, а в кэше по заданной позиции хранится целевой адрес. Выборка следующей инструкции начинается по этому адресу незамедлительно. Также в реализациях иногда присутствует дополнительное поле предсказателя.

В одной из вариаций буфера адресов переходов вместо целевого адреса сохраняются одна или несколько целевых инструкций. В таком решении есть несколько преимуществ. Во-первых, это позволяет увеличить время доступа к буферу адресов переходов, а значит скрыть возможную задержку при обращении к большим буферам. Во-вторых, появляется возможность организовать сворачивание ветвей. В таком случае не потребуется даже выборка следующей инструкции, т. е. после выборки инструкции ветвления на стадию декодирования будет передана уже следующая инструкция, а время выполнения собственно инструкции ветвления составит 0 тактов.

Стэк адресов возврата

При предсказании ветвлений особую сложность представляет предсказание косвенных переходов, т.е. переходов, чей целевой адрес изменяется в процессе выполнения. Программы на высокоуровневых языках программирования генерируют такие переходы для косвенных вызовов процедур, выражений case, однако наибольшее количество подобных косвенных переходов составляют инструкции возврата из процедур. Например, для тестовых наборов SPEC95 количество возвратов из процедур составляет 15% от общего количество ветвлений. Для объектно-ориентированных языков процент ещё выше.

Возвраты из процедур можно предсказывать с помощью буферов адресов переходов, однако точность таких предсказаний будет достаточно низкой, если процедура вызывается из нескольких мест и вызовы из одного места не совмещены во времени. Например, для SPEC95 агрессивный предсказатель ветвлений достигает точности меньше 60% для возвратов из процедур. Для преодоления подобной проблемы в некоторых проектах используется небольшой буфер недавних адресов возврата: при вызове процедуры возврата в специальный стек заносится адрес возврата, а при возврате из процедуры этот адрес выталкивается из стека. Если кэш имеет достаточный размер (достаточен для максимальной глубины вложенности), то он будет отлично предсказывать возвраты. Приемлемого качества предсказания можно добиться при размере стека в 16 записей.

12.3 Суперскалярная архитектура

В 80-х годах в области проектирования микропроцессоров получила распространение конвейерная организация [Shen]. В 90-х доминирующей темой стало проектирование суперскалярных процессоров. Суперскалярные машины выходят за пределы одного конвейера инструкций. Они используют несколько функциональных модулей для достижения большего параллелизма при обработке инструкций и более высокой пропускной способности. Подобно конвейерной организации идея использования нескольких функциональных модулей была предложена в начале 60-х при проектировании мейнфреймов. Например, CDC 6600 использовал как конвейеризацию, так и несколько функциональных модулей. Следующим основополагающим атрибутом суперскалярных процессоров является возможность выполнения инструкций в порядке, отличающемся от указанного в исходной программе. Последовательное упорядочение инструкций в обычных программах подразумевает некоторые ненужные приоритеты между инструкциями. Способность выполнения инструкций не по порядку, указанному в программе, ослабляет эту навязанную последовательность и увеличивает уровень параллелизма в обработке инструкций без модификации исходной программы. Такая динамическая форма выполнения также была предложена в 60-х. Классический пример – алгоритм Томасуло, реализованный в модуле обработки чисел с плавающей точкой в IBM 360/91. Несмотря на то, что фундамент суперскалярных процессоров был заложен более 40 лет назад, с тех пор было предложено много новых и гораздо более агрессивных техник. По сути, такой подход – это основная причина современного доминирования Intel с момента выпуска конвейеризированного 486 процессора, являющегося совместимым по коду с предыдущими поколениями (неконвейеризированных) процессоров Intel. Несмотря на то, что конвейеризация показала себя чрезвычайно эффективным подходом, скалярные конвейеры имеют ряд недостатков и ограничений. Способом их преодоления явились суперскалярные конвейеры, которые способны достичь уровней производительности, существенно превосходящих уровни скалярных конвейеров.

12.3.1 Суперскалярная конвейерная организация

Конвейеризация – это техника повышения пропускной способности процессора. В связи с тем, что техника реализуется ниже уровня DSI (Dynamic/Static Interface), она не требует специальных усилий со стороны пользователя. Поэтому ускорение может быть достигнуто для существующих последовательных программ без каких-либо модификаций кода. Этот подход, предлагающий повышение производительности с поддержанием совместимости кода, чрезвычайно привлекателен.

12.3.2 Ограничения скалярных конвейеров

Скалярные конвейеры характеризуются одним конвейером инструкций длиной k этапов. Все инструкции вне зависимости от их типов проходят через один и тот же набор (все) этапов конвейера. Максимум одна инструкция находится на каждом этапе в любой момент времени. Инструкции продвигаются по конвейеру по одному шагу за раз. За исключением этапов, в которых произошел, конвейерный простой (stall), каждая инструкция пребывает на каждом этапе в течении ровно одного такта и переходит на следующий этап в следующем такте. Такие жесткие скалярные конвейеры характеризуются тремя фундаментальными ограничениями:

1. Максимальная пропускная способность скалярного конвейера ограничена одной инструкцией за такт.

2. Унификация всех типов инструкций для единого конвейера может приводить к неэффективному проектному решению.

3. Простой в конвейере приводит к появлению нежелательных конвейерных пузырей.

1. Пропускная способность

Производительность может быть измерена как время, необходимое для выполнения программы. Время выполнения программы – это произведение числа инструкций, CPI и времени такта.

Более высокая степень конвейеризации увеличивает пропускную способность скалярного конвейера по сравнению с неконвейеризированными или слабо конвейеризированными реализациями. Однако это справедливо до определенной точки. Кроме того, глубокий конвейер накладывает более высокие издержки в виде пустых циклов при работе с зависимостями между инструкциями. Дополнительные издержки по CPI могут свести на нет выигрыш, достигаемый за счет уменьшения продолжительности такта.

Независимо от продолжительности цикла скалярный конвейер может запускать максимум одну инструкцию на каждом машинном такте. По сути IPC (instruction per cycle) для скалярного конвейера изначально ограничено единицей. Для получения более высокой производительности, особенно в ситуации, когда глубокая конвейеризация более не эффективна, необходима возможность запуска для обработки более чем одной инструкции на каждом процессорном такте. Это требует повышения ширины конвейера. Такие конвейеры называются параллельными.

2. Неэффективное объединение в единый конвейер

Инструкции различаются по выполняемым действиям, поэтому объединение их в единый конвейер может приводить к неэффективным реализациям. Более того, некоторые типы инструкций унифицировать в единый конвейер достаточно сложно. Такие инструкции включают инструкции с плавающей точкой и некоторые целочисленные инструкции (умножение/деление), требующие несколько тактов. Инструкции, имеющие большую и, возможно, нефиксированную продолжительность трудно объединить вместе с простыми инструкциями, требующими одного такта задержки. Вместе с ростом разрыва между скоростями памяти и процессора растет продолжительность инструкций памяти.

Следовательно, вынужденное объединение всех типов инструкций в единый конвейер становится либо невозможным, либо чрезвычайно неэффективным для будущих высокопроизводительных процессоров. Для параллельных конвейеров существуют серьезные причины не объединять всю исполняющую аппаратуру в один конвейер, а реализовать несколько разных исполняющих устройств или суб-конвейеров в исполняющей части. Такие параллельные конвейеры называются диверсифицированными конвейерами.

3. Потеря производительности из-за жесткой организации

Скалярные конвейеры имеют жесткую организацию в том смысле, что инструкции продвигаются по этапам строго пошагово. Инструкции попадают в конвейер согласно порядку в программе. Если в конвейере нет простоев, все инструкции на всех этапах продвигаются синхронно и порядок программы сохраняется. Если произошел простой из-за зависимости на данной инструкции, тогда она остается на текущем этапе, все инструкции, начатые до нее могут продолжать выполнение. Из-за жесткой организации, все инструкции, начатые после нее, также простаивают. Все i этапов простаивают. Т.е. простой охватывает все предыдущие стадии.

Если разрешен обход инструкции, вызвавшей простой, то такая организация называется внеочередным выполнением. Параллельные конвейеры, поддерживающие внеочередное выполнение, носят название динамических конвейеров.

12.3.3 От скалярных к суперскалярным конвейерам

Суперскалярные конвейеры являются прямыми потомками скалярных конвейеров и используют ряд расширений для смягчения трех ограничений их предков. Суперскалярные конвейеры – это параллельные конвейеры, т.е. они могут запускать несколько инструкций в течении одного такта. Кроме того, суперскалярные конвейеры являются диверсифицированными, используя несколько различных функциональных устройств на этапе выполнения. Наконец, суперскалярные конвейеры могут реализовываться в форме динамических конвейеров, для достижения максимальной производительности без переупорядочивания инструкций компилятором.

Параллельные конвейеры

Степень параллелизма машины может быть измерена максимальным числом инструкций, находящимся в обработке одновременно. Скалярный конвейер с k этапами может содержать одновременно k инструкций и потенциально достичь ускорения в k раз по сравнению с неконвейеризированной машиной (рис. 12.11а). С другой стороны то же ускорение может быть достигнуто использованием k копий неконвейеризированной машины для обработки k инструкций параллельно. Две этих формы параллелизма иллюстрируются на рисунке (рис. 12.11б-в) и могут быть обозначены как временной и пространственный параллелизм. Временной и пространственный параллелизм в одинаковой степени позволяют достичь примерно одинакового ускорения. Очевидно, что временной параллелизм с использованием конвейеризации требует меньше аппаратуры по сравнению с пространственным, требующим полного дублирования обрабатывающего устройства. Параллельные конвейеры используют как временной, так и пространственный параллелизм (рис. 12.11г).

Рис. 12.11 – Параллелизм машин.

Ускорение скалярного конвейера измеряется относительно неконвейеризированного варианта и в первую очередь зависит от глубины конвейера. Для параллельных конвейеров, или суперскалярных конвейеров, ускорение измеряется относительно скалярного конвейера и определяется в первую очередь шириной параллельного конвейера. Параллельный конвейер ширины s может одновременно обрабатывать до s инструкций на каждом из конвейерных этапов, что ведет к потенциальному ускорению в s раз в сравнении со скалярным конвейером.

На рис. 12.12 конвейеры i486 и Pentium. В Pentium параллельный конвейер ширины 2.

Рис. 12.12 – а) Пятиступенчатый конвейер i486; б) параллельный конвейер Pentium.

Диверсифицированный конвейер

Выборка и начальное декодирование инструкций представляют собой часть вычислений, общую для обработки любых инструкций независимо от их типа. Большинство инструкций также требуют считывания регистров для получения операндов и запись регистров для сохранения результатов. Однако, собственно исполнение инструкций может существенно различаться в зависимости от их типа. Следовательно, аппаратные ресурсы, необходимые для поддержки выполнения различных типов инструкций могут варьироваться в широких пределах. В случае скалярного конвейера все разнообразные требования для выполнения всех типов инструкций должны быть объединены в единый конвейер. Результирующий конвейер может оказаться совершенно неэффективным. Каждый тип инструкции будет требовать только подмножества этапов, однако должен будет пройти все этапы выполнения. Время выполнения каждой инструкции будет равно количеству шагов выполнения. Это может приводить к ненужным простоям инструкции или к необходимости введения дополнительных путей пересылки.

Неэффективность из-за объединения в один конвейер решается в случае параллельных конвейеров путем введения множества различных функциональных модулей на шагах выполнения. Вместо реализации s одинаковых конвейеров в параллельном конвейере ширины s, стадия выполнения параллельного конвейера может быть диверсифицирована (рис.). В этом случае реализуются 4 исполняющих конвейера или 4 функциональных модуля с различными задержками. На этапе RD осуществляется диспетчеризация инструкций по 4 конвейерам в зависимости от типа инструкции.

Рис. 12.13. – Диверсифицированный конвейер ширины s = 4.

Достоинства. Каждый конвейер может специализироваться на конкретном типе инструкций, обеспечивая эффективную аппаратную реализацию. Каждый тип инструкций накладывает только необходимую задержку и использует все этапы конвейера. Это определенно более эффективный подход, чем создание s копий универсального модуля выполнения, каждая из которых может выполнять любую инструкцию. Если все зависимости между инструкциями разрешаются до диспетчеризации, тогда как только инструкции выданы на отдельные исполняющие конвейеры никаких простоев не может возникнуть из-за инструкций в других конвейерах. Благодаря этому можно организовать распределенное и независимое управление каждым исполняющим конвейером.

Проектирование диверсифицированных параллельных конвейеров требует особого внимания. Одно из соображений – количество и выбор функциональных модулей. В идеале количество функциональных модулей должно совпадать с достижимым уровнем параллелизма команд программы и набор функциональных модулей должен совпадать с динамическим набором типов инструкций программы. Большинство суперскалярных процессоров первого поколения просто интегрировали второй исполняющий конвейер для обработки инструкций с плавающей точкой (первый конвейер использовался только для целочисленных инструкций). Суперскалярные процессоры развивались от моделей, выдающих по 2 инструкции за один такт, к моделям, выдающим 4 и обычно содержащим 4 исполнительных устройства, реализующих целочисленные операции, операции с плавающей точкой, операции с памятью, ветвления. Некоторые разработки содержат несколько целочисленных модулей, некоторые из которых предназначены для длительных инструкций типа умножения или деления, а другие используются для выполнения специальных операций из области обработки сигналов.

Аналогично конвейеризации, использование нескольких диверсифицированных функциональных модулей в проектировании высокопроизводительных процессоров – не новинка. CDC 6600 использовал как конвейеризацию, так и несколько функциональных модулей. В нем было 10 функциональных модулей.

Динамические конвейеры

В любой конвейерной организации требуются буферы между этапами. В жестком скалярном конвейере буфер на одну запись размещается между любыми двумя этапами i, j (рис. 12.14 а). Буфер включает всю необходимую управляющую информацию и биты данных для инструкции. Такими буферами достаточно просто управлять. На каждом такте текущее содержимое буфера используется как вход для следующего этапа j; в конце такта буфер сохраняет значение из предыдущего этапа. В случае простоя содержимое буфер не передается дальше. Все инструкции входят и покидают буфер в фиксированном порядке, определяемом кодом.

Рис. 12.14 - Буферизация между этапами конвейера: а) в скалярном конвейере; б) в параллельном конвейере; в) буфер переупорядочивания.

В параллельном конвейере между соседними этапами нужны буферы на несколько записей (рис. 12.14 б). Буферы на несколько записей могут рассматриваться как простое расширение буфера на одну запись. Несколько инструкций могут быть записаны в каждый такой буфер на каждом машинном такте. В следующем такте они будут переданы на следующий этап конвейера. Если все инструкции в буфере должны передаваться на следующий шаг одновременно, тогда управление таким буфером осуществляется аналогично буферу на одну запись. Буфер целиком либо передает свое содержимое на следующий этап, либо простаивает на каждом машинном такте. Однако такое функционирование параллельного конвейера может приводить к ненужным простоям некоторых инструкций в буфере на несколько записей. Для более эффективного функционирования параллельного конвейера требуются более сложные механизмы.

Каждая запись простого многовходового буфера аппаратно соединяется с одним портом записи и одним портом чтения, при этом нет никакого взаимодействия между разными записями. Усовершенствованием такого простого буфера является добавление соединения между записями, что способствует движению данных между записями. Например, записи могут быть объединены в линейную цепь наподобие сдвигового регистра и функционировать как очередь. Другое улучшение подразумевает использование механизма для независимого обращения к каждой записи. При этом требуется возможность явной адресации каждой отдельной записи в буфере и независимого контроля чтения/записи. Если каждый входной/выходной порт буфера может осуществлять доступ к любой записи буфера, тогда буфер будет напоминать небольшую многопортовую память RAM. При такой организации инструкция может оставаться в записи буфера в течение множества тактов и может модифицироваться пока находится в нем. Дальнейшее усовершенствование заключается в использовании ассоциативного доступа к записям буфера. Вместо использования стандартных адресов для индексации содержимое записи может использоваться как ассоциативный тег этой записи. Тогда буфер превращается в небольшую кэш-память.

Суперскалярные конвейеры отличаются от жестких скалярных конвейеров одним ключевым аспектом, а именно, использованием сложных буферов на множество записей для буферизации инструкций на лету. С целью минимизации ненужных простоев параллельного конвейера последующим инструкциям разрешается обходить простаивающие предыдущие. Такой обход может изменить порядок выполнения инструкций по сравнению с исходным порядком в коде. При исполнении инструкций не по порядку существует возможность достижения предела скорости выполнения инструкций потока данных, т.е. инструкции исполняются так быстро, как быстро доступны их операнды. Параллельный конвейер, поддерживающий исполнение не по порядку называется динамическим. Динамический конвейер осуществляет выполнение не по порядку благодаря использованию сложных многовходовых буферов, позволяющих инструкциям входить и выходить в разном порядке. Такие буферы называют буферами переупорядочивания (рис. 12.14 в).

Рис. 12.15 иллюстрирует параллельный диверсифицированный конвейер ширины 4 – динамический конвейер. Исполняющая часть конвейера состоит из 4 конвейеризированных функциональных модулей, обрамленных двумя буферами переупорядочивания. В первый, называемый буфером диспетчеризации, загружаются декодированные инструкции в соответствии с порядком программы, а затем буфер диспетчеризирует инструкции по функциональным модулям, возможно, в порядке, отличном от порядка программы. Таким образом, инструкции могут покидать буфер диспетчеризации в порядке, отличающемся от порядка, в котором они туда попали. Этот конвейер также использует набор различных функциональных модулей с разными задержками. С потенциальной выдачей не по порядку и разным временем выполнения на функциональных модулях инструкции, очевидно, завершают выполнение также не по порядку. Чтобы гарантировать точные прерывания, инструкции должны быть завершены, т.е. должны обновить состояние процессора, в порядке, предписанном программой. В случае инструкций, закончивших выполнение не по порядку, для гарантии выполнения по порядку, требуется другой буфер переупорядочивания. Этот буфер носит название буфер завершения, он хранит инструкции, которые закончили выполнение не по порядку и выдает инструкции по порядку на стадию записи результатов (write-back). Такой динамический конвейер использует исполнение не по порядку для достижения наименьшего времени выполнения и предполагает возможность организации точных прерываний, выдавая выполненные инструкции и обновляя состояние машины в соответствии с порядком программы. Многовходовые буферы и их логика управления вносят дополнительную сложность в аппаратуру.

Рис. 12.15 – Динамический конвейер ширины 4

12.3.4 Вопросы разработки суперскалярного конвейера

Далее рассматриваются критические вопросы, связанные с проектированием суперскалярных конвейеров. Акцент делается на организацию или структуру суперскалярных конвейеров. В качестве примера будет использоваться конвейер, показанный на рис. 12.16.

Рис. 12.16 – Пример суперскалярного конвейера

Выборка (Fetch). В отличие от скалярного конвейера суперскалярный, будучи параллельным, способен выбирать более одной инструкции из кэша команд за один такт. В случае суперскалярного конвейера ширины s, стадия Fetch должна иметь возможность читать s инструкций из кэша в течении каждого такта.

Основной задачей стадии выборки является максимизация полосы выборки. Пропускная способность, достигаемая на данной стадии, влияет на пропускную способность конвейера целиком, т.к. пропускная способность последующих стадий зависит и не может превышать производительность данной стадии. Две проблемы достижения максимальной пропускной способности в s инструкций за такт: 1) выравнивание инструкций в строке кэша; 2) присутствие инструкций перехода.

Декодирование (Decode) включает идентификацию отдельных инструкций, определение их типов, определение зависимостей между инструкциями и между группами инструкций. Сложность декодирования 5определяется двумя факторами: архитектурой команд и шириной параллельного конвейера. Для типичного набора инструкций RISC c фиксированной длиной и простым форматом задача достаточно проста.

В случае RISC и параллельного конвейера, когда несколько инструкций декодируются одновременно, этап декодирования должен идентифицировать зависимости между инструкциями и определять независимые инструкции, которые можно выдавать параллельно. Для повышения эффективности выборки декодирование должно рано обнаруживать инструкции ветвления, чтобы дать знать стадии выборки. Эти две задачи могут сделать аппаратную реализацию этапа декодирования достаточно сложной.

В случае CISC процессоров и параллельных конвейеров, задача декодирования может быть еще более сложной и обычно требует нескольких этапов конвейера. Для такой организации даже определение типа инструкции перестает быть тривиальной задачей. В Pentium используется 2 такта, в Pentium Pro 5 тактов на выборку и декодирование. Использование инструкций переменной длины вносит нежелательную последовательность в декодирование: предшествующая инструкция должна быть декодирована до того, как будет определено начало следующей. Следовательно, одновременное декодирование нескольких инструкций затруднено.

На аппаратуру декодирования в случае CISC накладывается дополнительное бремя. Декодер должен транслировать инструкции архитектуры команд во внутренний низкоуровневый формат, который может исполняться аппаратурой напрямую. Эти операции похожи на инструкции RISC, поэтому их иногда называют ROPs (RISC operations).

Для многих суперскалярных CISC процессоров аппаратура декодирования может быть чрезвычайно сложной и требовать разбиения на несколько этапов конвейера. Для сокращения сложности используется предекодирование. Предекодирование переносит часть задачи декодирования на сторону входа, т. е. на вход кэша инструкций. Когда происходит промах кэша и новая строка кэша считывается из памяти, то инструкции в строке частично декодируются аппаратными модулями, расположенными между памятью и кэшем. Инструкции и дополнительная декодированная информация сохраняются в кэше. Благодаря этому, часть декодирования осуществляется только единожды, при перемещении инструкции из памяти в кэш, а не при каждом обращении к кэшу.

AMD K5 – это пример суперскалярного CISC конвейера, который использует агрессивное предекодирование инструкций х86 во время их загрузки из памяти перед тем, как они будут помещены в кэш инструкций (рис. ). За одну транзакцию выбирается 8 байт инструкций. Эти байты предекодируются и 5 дополнительных бит генерируются для каждого байта исходных инструкций. Эти биты содержат информацию содержат информацию о положении начала и конце инструкции х86, числе ROP, необходимом для трансляции этой инструкции, расположении опкодов и префиксов. Дополнительные биты сохраняются в кэше инструкций вместе с исходными байтами команд. При каждом обращении к кэшу выбираются 16 байт инструкций вместе с 80 предекодированными битами. Биты предекодирования существенно упрощают декодирования и позволяют одновременно декодировать несколько инструкций х86 на 4 декодерах.

С предекодированием две формы издержек связаны: время промаха кэша немного увеличивается в связи выполнением логики декодирования. Другая проблема заключается в увеличении размера кэша (в примере на 50%).

Рис. 12.17 – Предекодирование в AMD K5

Диспетчеризация (Dispatching)

В скалярном процессоре все инструкции независимо от их типов проходят через один и тот же конвейер. В суперскалярных процессорах разные типы инструкций выполняются на разных функциональных устройствах. Как только тип инструкции определен на стадии декодирования, она должна быть направлена в соответствующий аппаратный модуль для выполнения. Эту задачу выполняет этап диспетчеризации.

Несмотря на то, что суперскалярные конвейеры являются параллельными, как задача выборки, так и задача декодирования обычно выполняются централизовано, т.е. все инструкции управляются одним контроллером.

С другой стороны, в диверсифицированном конвейере все функциональные модули могут работать независимо, распределенно, выполняя собственные типы инструкций после того, как были разрешены все зависимости. Следовательно при переходе от декодирования к выполнению происходит изменение централизованной обработки на распределенную. Это изменение проводится на этапе диспетчеризации.

Другой механизм, требуемый между декодированием и выполнением – это временная буферизация инструкций. Перед выполнением инструкции должны получить операнды. В ходе декодирования регистровые операнды читаются из регистрового файла. В суперскалярном конвейере возможна ситуация, когда некоторые из этих операндов еще не готовы из-за предыдущих инструкций, изменяющих значения этих регистров и не завершивших свою работу. Когда происходит подобная ситуация, очевидным решением является приостановка стадии декодирования до тех пор, пока все регистры не будут готовы. Это решение серьезно бьет по производительности декодирования и потому нежелательно. Более предпочтительным решением может быть выборка тех регистровых операндов, которые уже доступны, а затем движение дальше с помещением в отдельный буфер ожидающих инструкций. Когда все регистровые операнды готовы, эти инструкции могут покинуть буфер и выдаваться на функциональные устройства для выполнения. Временные буферы для инструкций принято называть станциями резервирования. Их использование разделяет декодирование и выполнение и предоставляет буфер для устранения провиса между декодированием и выполнением, что позволяет устранить ненужный простой на стадии декодирования и ненужное «голодание» на стадии выполнения.

В зависимости от размещения выделяют два типа станций резервирования. Если используется единый буфер на стороне источника диспетчеризирования, то это централизованная станция резервирования (рис. 12.18 а). С другой стороны, если несколько буферов размещены на стороне назначения диспетчеризирования, тогда имеют место распределенные станции резервирования (рис. 12.18 б).

В Pentium Pro используется централизованная станция резервирования. В Power PC 620 распределенные.

Существуют гибридные или компромиссные решения. MIPS R10000 реализует такой подход. В кластеризованных станциях резервирования инструкции распределяются между несколькими станциями резервирования, а каждая станция резервирования разделяется между более чем одним функциональным модулем. Обычно кластеризация осуществляется в зависимости от типа данных или инструкций.

Рис. 12.18 – Станции резервирования: а) централизованная; б) распределенные.

Станции резервирования подразумевают некоторые компромиссы. Централизованная станция резервирования позволяет всем типам инструкций использовать одну и ту же станцию резервирования и, вероятно, обеспечивает наилучшее использование записей станции. Однако она существенно усложняет аппаратную реализацию. Она требует централизованного управления и многопортового буфера. Распределенные станции могут быть однопортовыми (простыми). Однако использование записей станций будет уже не таким эффективным.

Этап выполнения

Стадия выполнения – это сердце суперскалярной машины. Современные тенденции склоняются к более параллельным и более диверсифицированным конвейерам. Это проявляется в увеличении количества функциональных модулей и их большей специализации. Путем специализации для выполнения конкретных типов инструкций, эти функциональные модули делаются более производительными. Ранние скалярные конвейеры содержали один функциональный модуль. Все типы инструкций (за исключением инструкций с плавающей точкой, выполняемых сопроцессором) выполнялись одним и тем же функциональным модулем. Большинство суперскалярных процессоров первого поколения представляли собой параллельные машины с двумя диверсифицированными функциональными модулями, один из которых выполнял целочисленные инструкции, а другой – инструкции с плавающей точкой.

Современные суперскалярные процессоры обычно используют несколько целочисленных устройств и некоторые содержат несколько устройств для работы с числами с плавающей точкой. Это два наиболее фундаментальных типа функциональных устройств. Некоторые из этих устройств становятся достаточно сложными и способны выполнять более одной операции, включающей более двух операндов на каждом такте.

В дополнение к выполнению инструкций целочисленного АЛУ целочисленный модуль может использоваться для генерации адресов памяти и выполнения инструкций ветвления или инструкций записи/чтения памяти. Однако в большинстве современных проектных решений используются отдельные модули для ветвлений и для операций чтения/записи. Модуль ветвления отвечает за обновление значения счетчика команд PC, тогда как модуль чтения/записи напрямую соединяется с кэшем данных.

Как же выглядит наилучший набор функциональных модулей для суперскалярного процессора? Очевидно, что ответ зависит от области применения. Если воспользоваться статистикой, типичные программы содержат 40% инструкций АЛУ, 20% ветвлений, 40% инструкций загрузки сохранения, тогда получается правило 4-2-4. На каждые 4 АЛУ должно быть предусмотрено 2 устройства ветвления и 4 устройства чтения/записи. Многие из современных суперскалярных процессоров содержат 4 или более АЛУ (как целочисленных, так и с плавающей точкой). Большинство из них содержат только одно устройство ветвления, однако способное предсказывать более одной условной инструкции. Также используется одно устройство чтения/записи. Некоторые способны обрабатывать две инструкции чтения/записи с некоторыми ограничениями. Очевидно, что присутствует разбалансировка по количеству устройств чтения/записи. Причина состоит в том, что реализация нескольких устройств чтения/записи, работающих параллельно с кэшем данных – это сложная задача. Она требует многопортового кэша, который реализуется с помощью сложных схем и существенно снижает скорость работы с памятью.

Количество параллелизма ресурсов в процессе выполнения определяется комбинацией пространственного и временного параллелизмов. Наличие нескольких функциональных модулей образует пространственный параллелизм. С другой стороны, параллелизм может быть получен с использованием конвейеризации некоторых функциональных модулей – это временной параллелизм. Например, вместо реализации двухпортовых кэшей используется конвейеризированный двухшаговый доступ к кэшу. Пространственный параллелизм требует больше аппаратуры, повышает сложность. Временной параллелизм увеличивает задержку и цену простоя конвейера.

Вместе с большим количеством функциональных модулей приходит и дополнительная аппаратная сложность. Результаты с выходов функционального модуля должны передаваться на входы функциональных модулей. Требуется множество шин, логика для их контроля и арбитража. Межсоединение вносит дополнительную задержку. Для поддержки пересылки станции резервирования отслеживают шины на наличие совпадений тегов и сохраняют операнды, когда осуществляется их широковещание по шине. Сложность этапа выполнение растет практически квадратично общему количеству функциональных модулей.

Этап завершения и изъятие

Инструкция считается завершенной, когда она заканчивает выполнение и обновляет состояние машины. Инструкция заканчивает выполнение, когда покидает функциональный модуль и входит в буфер завершения. Когда инструкция заканчивает выполнение, ее результат может находиться только в неархитектурных регистрах. Когда инструкция завершается, ее результат записывается в архитектурные регистры. В случае инструкций, работающих с памятью, имеется промежуток времени между тем как они завершаются и записью в память. Итак, завершение – это обновление состояния архитектурных регистров, а изъятие – обновление памяти.

Для поддержки точных прерываний стадия завершения инструкции должна происходить согласно порядку программы для обновления архитектурного состояния в порядке программы. Для поддержки используется буфер переупорядочивания. Как только инструкция заканчивает выполнение, она попадает в буфер переупорядочивания. Выходит она оттуда уже в нужном порядке.