Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Boroda_2

.doc
Скачиваний:
7
Добавлен:
20.03.2015
Размер:
1.67 Mб
Скачать

Более того, минимизация размера команд может усложнить их декодирова­ние и перекрытие. Следовательно, стремление уменьшить размер команд долж­но уравновешиваться стремлением сократить время их декодирования и выпол­нения.

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

Если пропускная способность кэш-памяти команд составляет t бит/с, а сред­няя длина команды — г бит, то кэш-память способна передавать самое большее t/r команд в секунду. Отметим, что это — верхний предел скорости, с которой процессор может выполнять команды, хотя в настоящее время предпринимают­ся попытки преодолеть данный барьер. Ясно, что скорость, с которой могут вы­полняться команды (то есть быстродействие процессора), может ограничиваться длиной команд. Чем короче команды, тем быстрее работает процессор. Поскольку современные процессоры способны выполнять несколько команд за один цикл, то вызов нескольких команд за цикл обязателен. Этот аспект применения кэш-памяти команд делает размер команд важным критерием, который нужно учитывать при разработке.

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

Третий критерий связан с числом битов в адресном поле. Рассмотрим проект машины с 8-разрядными символами и основной памятью, которая должна содер­жать 232 символов. Разработчики вольны были приписать последовательные ад­реса блокам по 8, 16, 24 или 32 бита.

Представим, что бы случилось, если бы команда разработчиков разбилась на две воюющие группы, одна из которых утверждает, что основной единицей па­мяти должен быть 8-разрядный байт, а другая требует, чтобы основной единицей памяти было 32-разрядное слово. Первая группа предложила бы память из 232 байт с номерами 0, 1, 2, 3,4 294 967 295. Вторая группа предложила бы па­мять из 230 слов с номерами 0, 1, 2, 3, ..., 1 073 741 823.

Первая группа скажет, что для того, чтобы сравнить два символа при органи­зации по 32-разрядным словам, программе приходится не только вызывать из памяти слова, содержащие эти символы, но и выделять соответствующий символ из каждого слова для сравнения. А это потребует дополнительных команд и, сле­довательно, дополнительного пространства. 8-разрядная организация, напротив, обеспечивает адресацию каждого символа, что значительно упрощает процедуру сравнения.

Сторонники 32-разрядной организации скажут, что их проект требует всего лишь 230 отдельных адресов, что дает длину адреса всего 30 бит, тогда как при 8-разрядной организации требуется целых 32 бита для обращения к той же са­мой памяти. Если адрес короткий, то и команда будет более короткой. Она зай­мет меньше пространства в памяти, и к тому же для ее вызова потребуется мень­ше времени. В качестве альтернативы они могут сохранить 32-разрядный адрес для обращения к памяти в 16 Гбайт вместо каких-то там 4 Гбайт.

Этот пример демонстрирует, что для получения оптимальной дискретно­сти памяти требуются более длинные адреса и, следовательно, более длинные команды. Одна крайность — это организация памяти, при которой адресуется ка­ждый бит (например, Burroughs В1700). Другая крайность — это память, состоя­щая из очень длинных слов (например, серия CDC Cyber содержала 60-разряд- ные слова).

Современные компьютерные системы пришли к компромиссу, который, в ка­ком-то смысле, объединил в себе худшие качества обоих вариантов. Они требу­ют, чтобы адреса были у отдельных байтов, но при обращении к памяти всегда считываются одно, два, а иногда даже четыре слова сразу. В результате считыва­ния одного байта из памяти на машине UltraSPARC III единовременно вызыва­ются минимум 16 байт (см. рис. 3.44), а иногда и вся строка кэш-памяти разме­ром 64 байта.

Расширение кода операций

В предыдущем подразделе мы увидели, что короткие адреса препятствуют удачной дискретности памяти. В этом разделе мы рассмотрим компромиссы, связанные с кодами операций и адресами. Рассмотрим команду размером п + k бит с кодом операции в k бит и одним адресом в п бит. Такая команда до­пускает 2k различных операций и 2п адресуемых ячеек памяти. В качестве аль­тернативы те же п + k бит можно разбить на код операции в k - 1 бит и адрес в п + 1 бит. При этом будет либо в два раза меньше команд, но в два раза боль­ше памяти, либо то же количество памяти, но дискретность вдвое выше. Код операции в k + 1 бит и адрес в п - 1 бит дает большее количество операций, но ценой этого является либо меньшее количество ячеек памяти, либо не очень удачная дискретность при том же объеме памяти. Наряду с подобными про­стыми компромиссами между битами кода операции и битами адреса сущест­вуют и более сложные. Обсуждаемый здесь механизм называется расширени­ем кода операций.

Понятие расширения кода операций можно пояснить на примере. Рассмот­рим машину, в которой длина команд составляет 16 бит, а длина адресов — 4 би­та, как показано на рис. 5.8. Это вполне разумно для машины, содержащей 16 ре­гистров (а следовательно, 4-разрядный адрес регистра), с которыми совершаются все арифметические операции. Один из возможных вариантов — включение в каждую команду 4-разрядного кода операции и трех адресов, что дает 16 трехадресных команд.

Рис. 5.8. Команда с 4-разрядным кодом операции и тремя 4-разрядными

адресными полями

Если разработчикам нужно 15 трехадресных команд, 14 двухадресных ко­манд, 31 одноадресная команда и 16 безадресных команд, они могут использо­вать коды операций от 0 до 14 в качестве трехадресных команд, а код операции 15 уже интерпретировать по-другому (рис. 5.9).

Это значит, что код операции 15 содержится в битах с 8-го по 15-й, а не с 12-го по 15-й. Биты с 0-го по 3-й и с 4-го по 7-й, как и раньше, формируют два адреса. Все 14 двухадресных команд содержат число 1111 в старших четырех битах и числа от 0000 до 1101 в битах с 8-го по 11-й. Команды с числом 1111 в старших четырех битах и числом 1110 или 1111 в битах с 8-го по 11-й рассматриваются особо. Они трактуются так, как будто их коды операций находятся в битах с 4-го по 15-й. В результате получаем 32 новых кода операций. А поскольку требуется всего 31 код, то код 111111111111 означает, что действительный код операции находится в битах с 0-го по 15-й, что дает 16 безадресных команд.

Как видим, код операции становится все длиннее и длиннее: трехадресные команды имеют 4-разрядный код операции, двухадресные команды — 8-разряд- ный, одноадресные команды — 12-разрядный, а безадресные команды — 16-раз - рядный.

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

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

Форматы команд процессора Pentium 4

Форматы команд процессора Pentium 4 очень сложны и нерегулярны. Они со­держат до шести полей разной длины, пять из которых не обязательны (общая модель показана на рис. 5.10). Такая ситуация сложилась из-за того, что архи­тектура развивалась на протяжении нескольких поколений, и ранее в нее были включены не очень удачные варианты команд. Из-за требования обратной со­вместимости позднее их нельзя было изменить. Например, если один из операн­дов команды находится в памяти, то другой не может там находиться. В резуль­тате, существуют команды сложения двух регистров, команды прибавления ре­гистра к слову памяти, команды прибавления слова памяти к регистру, но не существует команд для прибавления одного слова памяти к другому слову па­мяти.

В первых архитектурах Intel все коды операций были размером 1 байт, хотя для изменения некоторых команд часто использовался так называемый пре­ фиксный байт. Префиксный байт — это дополнительный код операции, который ставится перед командой, чтобы изменить ее действие. Примером применения префиксного байта может служить команда WIDE в машинах IJVM. К сожалению, в какой-то момент компания Intel исчерпала запасы кодов операций, и один код операции, OxFF, стал кодом смены алфавита и использоваться для разрешения второго байта команды.

Байты 0-5 1-2 0-1 0-1 0-4 0-4

Index, Base — масштаб, индекс, база), который дает дополнительную специфи­кацию. Эта схема не идеальна, она является компромиссом между требованием обратной совместимости и желанием учесть новые особенности, которые не бы­ли предусмотрены изначально.

Добавим еще, что некоторые команды имеют 1, 2 или 4 дополнительных бай­та для определения адреса команды (смещение), а иногда еще 1, 2 или 4 байта, содержащих константу (непосредственный операнд).

Форматы команд процессора UltraSPARC III

Архитектура команд процессора UltraSPARC III состоит из 32-разрядных ко­манд, выровненных в памяти. Команды очень просты. Каждая из них выполняет только одно действие. Типичная команда задает два регистра, в которых нахо­дятся исходные операнды, и один выходной регистр. Вместо одного из регистров команда может использовать константу со знаком. При выполнении команды LOAD два регистра (или один регистр и 13-разрядная константа) складываются вместе для определения считываемого адреса памяти. Данные оттуда записыва­ются в другой указанный в команде регистр.

Изначально машина SPARC имела ограниченное число форматов команд (рис. 5.11). Со временем добавлялись новые форматы. Когда писалась эта кни­га, количество форматов уже было равно 31, и в планах было увеличение (дол­го ли осталось ждать того дня, когда появится реклама «самого сложного в ми­ре RISC-процессора»?). Большинство новых вариантов были получены за счет отъема нескольких битов у какого-нибудь поля. Например, изначально для ко­манд перехода использовался вариант 3 формата (с 22-разрядным смещением). Когда были добавлены команды прогнозируемых ветвлений, из 22 бит было изъято 3: один из них стал использоваться для прогнозирования (совершать или не совершать переход), а два оставшихся определяли, какой набор битов условного кода нужно использовать. В результате получилось 19-разрядное смещение. Приведем другой пример. Существует много команд преобразования типов данных (целых чисел — в числа с плавающей точкой и т. д.). Для боль­шинства этих команд используется вариант lb формата, в котором поле непо­средственной константы разбито на 5-разрядное поле, указывающее входной регистр, и 8-разрядное поле, предоставляющее дополнительные биты кода опе­рации. Однако в большинстве команд все еще используются форматы, показан­ные на рисунке.

Первые 2 бита каждой команды помогают определить формат команды и со­общают аппаратному обеспечению, где найти оставшуюся часть кода операции, если она есть. В варианте 1а формата оба источника операндов представляют со­бой регистры; в варианте lb один источник — регистр, второй — константа в про­межутке от -4096 до +4095. Бит 13 определяет один из этих двух форматов. (Би­ты нумеруются с 0.) В обоих случаях местом сохранения результатов всегда является регистр. Достаточный объем пространства имеется для 64 команд, не­которые из которых зарезервированы на будущее.

Поскольку все команды 32-разрядные, включить в команду 32-разрядную константу невозможно. Команда SETHI устанавливает 22 бита, оставляя про­странство для другой команды, чтобы установить оставшиеся 10 бит. Это един­ственная команда такого необычного формата.

Рис. 5.11. Исходные форматы команд процессора SPARC

Для непрогнозируемых условных переходов используется вариант 3 формата, в котором поле условия определяет, что проверяется. Бит А нужен для того, что­бы избегать пустых операций при определенных условиях. Формат команд про­гнозируемых ветвлений тот же, только с 19-разрядным смещением, как было сказано ранее.

Последний формат используется для команды вызова процедуры CALL. Эта команда особая, поскольку только в ней для определения адреса требуется 30 бит. В данной архитектуре существует один 2-разрядный код операции. Тре­буемый адрес — это целевой адрес, разделенный на четыре. Таким образом, отно­сительно текущей команды диапазон составляет примерно 231 байт.

Форматы команд 8051

В 8051 предусмотрено шесть простых форматов команд (рис. 5.12). Размер ко­манд может быть равен 1, 2 или 3 байтам. Вариант 1 формата предусматривает наличие в команде только кода операции. Такова, к примеру, команда инкремен­та сумматора.

Вариант 2 формата также состоит из одного байта, но из 8 бит в нем 5 выде­ляется на код операции, оставшиеся 3 — на номер регистра. По этому формату строятся команды, которые одновременно обращаются к сумматору и регистру, например команды добавления значения из регистра в сумматор или переноса данных из сумматора в регистр.

Адресация

Большинство команд работают с операндами, расположение которых необходи­мо каким-то образом указать. Этот механизм, который мы обсудим в данном раз­деле, называется адресацией.

Режимы адресации

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

Команда, построенная по варианту 6 формата, содержит два 8-разрядных опе­ранда. Этот формат характерен для многих команд, например, для команды пе­реноса 8-разрядной непосредственной константы по адресу встроенной в микро­схему памяти.

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

Варианты 4 и 5 формата предназначены для команд переходов и вызовов под­программ. 11-разрядные адреса применяются в отсутствие внешней памяти, ко­гда длина адреса не превышает 4096 (в модели 8051) или 8192 (в модели 8052). Если внешняя память присутствует и ее объем составляет более 8 Кбайт, приме­няются 16-разрядные адреса.

Непосредственная адресация

Самый простой способ указания операнда — хранить в адресной части сам опе­ранд, а не адрес операнда или какую-либо другую информацию, описывающую, где находится операнд. Такой операнд называется непосредственным, поскольку он автоматически вызывается из памяти одновременно с командой; следователь­но, сразу становится непосредственно доступным. Один из вариантов команды с непосредственным адресом для загрузки в регистр R1 константы 4 показан на рис. 5.13.

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

Прямая адресация

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

Регистровая адресация

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

Такой режим называют регистровой адресацией. В архитектурах с перенаправ­лением для загрузки, например UltraSPARC II, практически все команды исполь­зуют этот режим адресации. Он не применяется только в том случае, если операнд перемещается из памяти в регистр (команда LOAD) или из регистра в память (коман­да STORE). Но даже в этих командах один из операндов является регистром — туда отправляется слово из памяти и оттуда перемещается слово в память.

Косвенная регистровая адресация

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

Чтобы понять, почему может быть полезно использовать разные слова при каждом выполнении команды, представим себе цикл, который проходит по 1024-элементному одномерному массиву целых чисел для получения в регистре R1 суммы элементов. Вне этого цикла какой-то другой регистр, например R2, может указывать на первый элемент массива, а еще один регистр, например R3, — на первый адрес после массива. Массив содержит 1024 целых числа по 4 байта каждое. Если массив начинается с элемента Д то первый адрес после массива будет А + 4096. Типичная программа на ассемблере, выполняющая это вычисление для двухадресной машины, показана в листинге 5.1.

MOV R1,#0 MOV R2JA MOV R3JA+4096 LOOP: ADD R1.(R2)

ADD R2,#4 CMP R2,R3 BLT LOOP

Листинг 5.1. Программа на ассемблере для вычисления суммы элементов массива

увеличение R2 на одно слово (4 байта)

проверка завершения

если R2 < R3, продолжать цикл

В этой маленькой программе мы использовали несколько режимов адреса­ции. В первых трех командах выполняется регистровая адресация первого опе­ранда (целевого) и непосредственная адресация второго (константа, обозначае­мая символом #). Вторая команда помещает в R2 не содержимое элемента А, а элемент А. Именно это и сообщает ассемблеру знак #. Сходным образом третья команда помещает в R3 первое слово после массива.

Интересно отметить, что само тело цикла не содержит каких-либо адресов па­мяти. В четвертой команде используются регистровая и косвенная адресация. В пятой команде применяются регистровая и непосредственная адресация, в шес­той — оба раза регистровая. Команда BLT могла бы использовать адрес памяти, однако более привлекательным является определение адреса с помощью 8-раз- рядного смещения, связанного с самой командой BLT. Таким образом, вообще без обращения по адресам памяти, мы получили короткий и быстрый цикл. Кстати, эта программа предназначена для Pentium 4, только мы переименовали команды и регистры и для простоты изменили запись.

Теоретически есть еще один способ выполнения этого фрагмента без косвен­ной регистровой адресации. Цикл мог бы содержать команду для прибавления А к регистру R1, например:

ADD R1, А

Тогда при каждом шаге команда должна увеличиваться на 4. Таким образом, после одного шага команда будет выглядеть следующим образом:

ADD R1, А + 4

И далее аналогично до завершения цикла.

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

Индексная адресация

Часто нужно уметь обращаться к словам памяти по известному смещению. По­добные примеры мы видели в машине IJVM, где локальные переменные опреде­ляются по смещению от регистра LV. Обращение к памяти по регистру и кон­станте смещения называется индексной адресацией.

В машине IJVM при доступе к локальной переменной используется указа­тель ячейки памяти (LV) в регистре плюс небольшое смещение в самой команде, как показано на рис. 4.14, а. Есть и другой способ: указатель ячейки памяти в ко­манде и небольшое смещение в регистре. Чтобы показать, как работает этот ме­ханизм, рассмотрим следующий пример. Пусть у нас есть два одномерных мас­сива А и В по 1024 слова в каждом. Нам нужно вычислить Д И В{ для всех пар, а затем соединить все эти 1024 логических произведения операцией ИЛИ, чтобы узнать, есть ли в этом наборе хотя бы одна пара, не равная нулю. Один из вари­антов — поместить адрес массива А в один регистр, а адрес массива В — в другой регистр, а затем последовательно перебирать элементы массивов аналогично то­му, как мы делали в предыдущей программе (см. листинг 5.1). Такая программа, конечно же, будет работать, но ее молено усовершенствовать, как показано в лис­тинге 5.2.

Листинг 5.2. Программа на ассемблере, выполняющая операцию ИЛИ для 1024 элементов массива

MOV R1,#0

собирает результаты выполнения ИЛИ в R1

изначально 0

MOV R2,#0

R2 = индекс, i от текущего

произведения A[i] И B[i]

MOV R3,#4096

R3 = первое ненужное значение индекса

MOV R4,A(R2) ;

; R4 = A[i]

AND R4,B(R2) ;

; R4 = А[i] И B[i]

OR R1.R4

ADD R2,#4

1=1+4

CMP R2.R3

нужно ли продолжать?

BLT LOOP

если R2 < R3, нужно продолжать

Здесь нам требуется 4 регистра:

+ R1 — содержит результаты суммирования логических произведений;

+ R2 — индекс г, который используется для перебора элементов массива;

+ R3 — константа 4096 (это самое маленькое значение г, которое не исполь­зуется);

+ R4 — временный регистр для хранения каждого произведения.

После инициализации регистров мы входим в цикл из шести команд. Команда с меткой LOOP вызывает элемент Д в регистр R4. При вычислении источника здесь используется индексная адресация. Регистр (R2) и константа (адрес элемента А) складываются, полученный результат служит для обращения к памяти. Сумма этих двух величин поступает в память, но не сохраняется ни в одном из доступных поль­зователю регистров. Следующая запись означает, что для определения приемника используется регистровая адресация, а для определения источника — индексная:

MOV R4,A(R2)

Здесь R4 — это регистр, А — смещение, R2 — регистр. Если А имеет значение, скажем, 124 300, то соответствующая машинная команда будет выглядеть так, как показано на рис. 5.14.

Рис. 5.14. Возможное представление команды MOV R4, A(R2) в памяти

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]