Смекни!
smekni.com

«подклеиванию» (стр. 4 из 7)

Здесь мы подошли к фундаментальной концепции микроархитектуры К7/К8. Мы уже видели, что объединение двух отдельных микроопераций в одну макрооперацию даёт явные преимущества. Точно также дела обстоят и с самими макрооперациями — практически везде они выступают не в виде самостоятельных единиц, а в виде группы. Группу образуют как раз те 3 mOP-а, которые одновременно запускаются на параллельные каналы. Вся дальнейшая работа идет не с одиночными mOP-ами, а с «тройками» mOP-ов («line»). Такая тройка mOP-ов, «line», с точки зрения центрального управляющего блока процессора, ICU (Instruction Control Unit) воспринимается как единое целое: все основные действия выполняются именно над «line», в первую очередь — выделение внутренних ресурсов. Так, под «line» одним приемом выделяется группа из трех позиций в очередях (как мы помним, у каждого канала своя очередь). Здесь mOP-ы на короткое время приобретает независимость — точнее, самостоятельными оказываются ROP-ы, которые выбираются для запуска на ФУ в наилучшей последовательности. Когда окажутся запущенными составляющие всех трех mOP-ов, относящихся к «line», соответствующие позиции в очередях будут одновременно освобождены. Точно также, одновременно будет происходить и «отставка» — освобождение ресурсов после исполнения, сопровождающееся окончательной записью результатов в регистровый файл.

Этот дизайн сама AMD характеризует как «line-oriented», и он является предметом законной гордости корпорации. В нем каждый конвейер представляет собой один «канал» — кстати сказать, слово «канал» не является точной терминологией. Похоже, в этом случае жестко закрепленного термина вовсе не вводится, каждый раз, в зависимости от контекста, применяются термины «position», «issue position», «lane».

Итак, мы имеем три симметричных канала, работающих синхронно и параллельно. Макрооперации проходят конвейер, оставаясь прикрепленными к своим каналам — таким образом практически исключаются поздние стадии переброски и распределения команд по тем портам, к которым подсоединены специфические функциональные устройства, необходимые для исполнения конкретной команды (как правило — это самый «горячий» участок процессора). Далее, «line-oriented» подход позволяет кардинально снизить количество управляющей логики и количество «контролируемых элементов». Использование макроопераций, а не ROP-ов, в качестве элементов «line» позволяет увеличить её эффективную ширину, то есть, в конечном счете — количество команд, обрабатываемых за один такт. Наконец, количество параллельно обрабатываемых элементов в дальнейшем без особых сложностей может быть расширено просто за счет увеличения числа каналов (и, соответственно, количества ФУ). И, последнее: важно отметить, что хотя основные концепции и направлены на построение «широкого» эффективного конвейера, с равным успехом они могут быть применены к конвейерам самой разной длины.

И в этом моменте становится заметным ключевое отличие концепции К7 от концепции Pentium 4: если Pentium 4 спроектирован на достижение максимальной частоты, то К7 (да и К8, вообще говоря) в первую очередь рассчитан на исполнение максимального количества mOP-ов за такт (в конечном итоге, большее количество исполненных mOP-ов означает большее количество исполненных х86-команд, хотя зависимость здесь нелинейная).

Чтобы проиллюстрировать ситуацию, припомним наш конвейер. Представим себе, что мы для увеличения производительности сделали наш конвейер втрое более широким — то есть теперь на нем параллельно собирается три автомобиля. Соответственно, «листики с инструкциями» на конвейере лежат по три, равно как и «детали для сборки». Более того, «детали» теперь на каждое из трех мест можно класть по две! И, наконец, весь процесс укладки деталей производится одновременно одним механизмом, равно, как и готовые автомобили снимаются одновременно по три штуки.

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

Собственно, вот мы и пришли к идеологии микроархитектуры К7/К8. Надо отдать должное инженерам AMD, конструкция получилась элегантная и эффективная, при этом существенно расширена «параллельность» конвейера. Также весьма интересно, что концепция позволяет рост как «вширь», так и «вглубь».

Теперь понятно, что даже сходным образом звучащая фраза, справедливая для обеих архитектур — в современных процессорах х86-команды превращаются в «RISC-подобные» команды — означает в действительности совершенно разные вещи. Что же, согласитесь, это достаточно интересные сведения, на которых стоило остановиться!

Декодеры и конвейеры, ч.2. К7 и К8.

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

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

Прежде всего определимся с терминологией; дело в том, что в архитектуре К7 термин «декодер» употребляется в нескольких контекстах, а именно:

  • Предекодер (Predecoder) анализирует инструкции до их записи в I — cache, определяет адреса их начала и конца, местоположение префиксов и путь (способ) декодирования (DirectPath либо VectorPath). Вся эта информация записывается в специальные биты предекодирования (Decode Array) и помещается в L1-кэш. Одновременно производится распознавание инструкций перехода и подготовка специальных селекторов (branch selectors) для последующего быстрого предсказания и вычисления адресов переходов. Предекодирование осуществляется в темпе не более 4 байтов за такт. Здесь у нас возникли новые термины, DirectPath и VectorPath, значение которых будет пояснено ниже.
  • Собственно декодер, который и занимается преобразованием х86-инструкций, считанных из I-кэша, выровненных и размеченных, в макрооперации. На выходе мы имеем сформированные тройки mOP-ов, которые движутся дальше по конвейеру
  • Мы видим, что уже в К7 декодирование представляет собой фактически целую совокупность операций. Эту совокупность мы будем обозначать термином «декодер», пока не вдаваясь в подробности. Теперь поясним два новых термина, DirectPath и VectorPath, которые мы ввели в пункте 1. Сам декодер в К7 может обрабатывать х86-инструкции двумя путями, DirectPath и VectorPath. Первый из них, DirectPath, занимается теми и только теми х86-инструкциями, которые превращаются ровно в одну mOP, и ни копейкой больше. Все остальные инструкции в К7 обрабатываются VectorPath декодером, который превращает их в последовательность двух и более mOPs. Для таких х86-инструкций (включая самые сложные, например, целочисленное деление), используется устройство Microcode Engine («микрокодовое устройство»), которое, пользуясь встроенными таблицами, заменяет х86-инструкцию на целую последовательность mOPs.

Рассмотрим, как происходит работа декодера и конвейера в К7 (называя попутно этапы конвейера):

  1. FETCH «выборка»: предекодер считывает 16 байт инструкций из I-cache, попутно определяя адрес следующего блока для выборки. Кстати, для К8 считывается также 16 байт. В определенных случаях (если размер одной х86 инструкции больше, чем 16/3 байт) эта стадия может стать ограничивающим фактором; правда, обычно средний размер х86-инструкции порядка 5 — 6 байт.
  2. SCAN «сканирование»: на этом этапе при помощи записанных ранее битов предекодирования инструкции отделяются друг от друга, разделяются по пути декодирования (DirectPath или VectorPath). До 6 отделенных друг от друга инструкций отправляются на дальнейший этап DirectPath, и не более одной инструкции отправляется в VectorPath, в Microcode Engine.
  3. ALIGN1 «выравнивание 1»: на этом этапе возможна буферизация до 9 DP инструкций (до 24 байт), три из которых каждый такт могут отсылаться дальше на исполнение в трех каналах исполнения. Номер этого канала 0/1/2 закрепляется за mOP-ом, в который трансформируется DP инструкция, на все последующие этапы, вплоть до «отставки» (retirement). Общая скорость исполнения на этой стадии для DP инструкций составляет 3 инструкции за такт. Инструкции типа VectorPath также проходят через этот этап для того, чтобы на выходе из декодера обеспечить порядок следования mOP-ов, соответствующий исходному порядку инструкций. VectorPath-инструкция занимает (блокирует) сразу все три канала декодирования и не может сочетаться с предшествующими DirectPath инструкциями. Если в предшествующем такте набралось меньше трех DirectPath-инструкций, то в оставшиеся каналы ничего не отсылается и они остаются незанятыми.

Здесь прервемся на секунду, и обратим внимание, что недостаток VectorPath инструкции состоит в том, что она «занимает» все три канала декодирования, не позволяя работать DP декодерам параллельно. Важно отметить, что сама по себе VectorPath инструкция не является «плохой» — Microcode Engine работает с той же скоростью «3 mOP-а в такт», что и DP декодеры, при этом полученные из VectorPath mOP-ы ничем не хуже полученных из DirectPath. Напротив, для сложных инструкций, дающих десятки команд (для деления, или для многих системных инструкций), VectorPath - прекрасное решение! Проблема в VectorPath заключается в побочных эффектах, связанных с положением VP инструкции в «тройке». А именно:

  • Если VP инструкция — первая в тройке (имеет нулевую позицию), то она направляется на Microcode Engine, которая и генерирует последовательность mOP-ов (используя внутренние таблицы). mOP-ы выдаются тройками; если в последней тройке меньше трех mOP-ов, то в пустующие позиции проставляется NULL-ROP («пустышка»). Оставшиеся две инструкции из блока, содержащего обработанную VP-инструкцию, сдвигаются на одну позицию влево (т.е. в нулевую позицию) и дополняются до тройки следующей инструкцией.
  • Если VP инструкция не является первой в тройке, то сперва декодируются предшествующие ей DP инструкции, причем недостающие позиции mOP-ов дополняются до тройки нужным числом NULL-ROP (одним или двумя). Далее — как в предыдущем пункте, то есть VP инструкция начинает обрабатываться со следующей «строки».

Нетрудно заметить, что, если, например, двух-mOP-овая VP-инструкция в потоке DP-инструкций занимает позицию #