ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 24.12.2021
Просмотров: 6740
Скачиваний: 8
268
Глава 4. Микроархитектурный уровень
LV, поскольку она считывает значение из набора констант, а не из фрейма локаль-
ных переменных. (Существует еще и краткая форма этой команды — LDC, но мы не
стали включать ее в машину IJVM, поскольку полная форма содержит в себе все
варианты краткой формы, хотя при этом занимает 3 байта вместо 2.)
Адрес
0x1FF
0x115
0x100
0хС4
0x15
0x00
Управляющая память
wide iloadi
Maini
widei
iloadi
Порядок выполнения
микрокоманд
WIDE
ILOAD ILOAD
3
Рис.
4.15. Начало последовательности микрокоманд для ILOAD и WIDE ILOAD.
Адреса приводятся в качестве примера
Команда IINC — единственная команда кроме
ISTORE,
которая может изменять
локальную переменную. Она включает в себя два операнда по одному байту, как
показано на рис. 4.16.
1INC
(0x84)
ИНДЕКС
КОНСТАНТА
Рис. 4.16. Команда IINC содержит два поля операндов
Поле индекса нужно для того, чтобы определить смещение от начала фрейма
локальных переменных. Команда считывает эту переменную, увеличивает ее на
константу (константа содержится во втором поле) и помещает результат обратно
в ту же ячейку памяти. Отметим, что константа является 8-битным числом со зна-
ком в промежутке от-128 до +127. В машине JVM есть расширенная версия этой
команды, в которой длина каждого операнда составляет два байта.
Рассмотрим первую команду перехода: GOTO. Эта команда изменяет значение
регистра PC таким образом, чтобы следующая команда IJVM находилась в ячейке
памяти с адресом, который вычисляется путем прибавления 16-битного смещения
(со знаком) к адресу кода операции GOTO. Сложность здесь в том, что смещение
связано с тем значением, которое содержится в регистре PC в начале декодирова-
Пример реализации микроархитектуры
269
ния команды, а не тем, которое содержится в том же регистре после вызова двух
байтов смещения.
Чтобы лучше это понять, посмотрите на рис. 4.17,
а.
Здесь изображена ситуа-
ция, которая имеет место в начале цикла Mainl. Код операции уже находится в ре-
гистре MBR, но значение PC еще не увеличилось. На рис. 4.17, 6 мы видим ситуа-
цию в начале цикла gotol. В данном случае значение PC уже увеличено на 1 и первый
байт смещения уже передан в MBR. В следующей микрокоманде (рис. 4.17,
в)
ста-
рое значение PC, которое указывает на код операции, сохраняется в регистре ОРС.
Это значение нам нужно, поскольку именно от него, а не от текущего значения PC,
зависит смещение команды GOTO. И именно для этого предназначен регистр ОРС.
Память
п+3
П+2
п+1
п
-1 байт-
БАЙТ
СМЕЩЕНИЯ 2
БАЙТ
СМЕЩЕНИЯ 1
GOTO (0xA7)
БАЙТ
СМЕЩЕНИЯ 2
БАЙТ
СМЕЩЕНИЯ 1
GOTO (0xA7)
БАЙТ
СМЕЩЕНИЯ 2
БАЙТ
СМЕЩЕНИЯ 1
GOTO (0xA7)
БАЙТ
СМЕЩЕНИЯ 2
БАЙТ
СМЕЩЕНИЯ 1
GOTO (0xA7)
БАЙТ
СМЕЩЕНИЯ 2
БАЙТ
СМЕЩЕНИЯ 1
GOTO (0xA7)
Регистры
PC
ОРС
MBR
-1 байт-
п
0хА7
п+1
БАЙТ
СМЕЩЕНИЯ 1
п+1
п
БАЙТ
СМЕЩЕНИЯ 1
П+2
П
БАЙТ
СМЕЩЕНИЯ 1
П+2
п
БАЙТ
СМЕЩЕНИЯ 2
OFFSET 1 «8
Рис. 4.17.
Ситуация вначале выполнения различных микрокоманд- Mainl (a); gotol (б);
goto2 (в); goto3 (г); goto4 (д)
Микрокоманда goto2 начинает вызов второго байта смещения, что приводит к
ситуации, показанной на рис. 4.17, г (микрокоманда goto3). После того как первый
байт смещения сдвигается влево на 8 битов и копируется в регистр Н, мы переходим
к микрокоманде goto4 (см. рис. 4.17,
д).
Теперь у нас первый байт смещения, сдвину-
тый влево, находится в регистре Н, второй байт смещения — в регистре MBR, а основа
смещения — в регистре ОРС. В микрокоманде goto5 путем прибавления полного
16-битного смещения к основе смещения мы получаем новый адрес, который по-
мещается в регистр PC. Отметим, что в goto4 вместо MBR мы используем MBRU,
поскольку нам не нужно знаковое расширение второго байта. 16-битное смещение
строится путем логического сложения (операция ИЛИ) двух половинок. Нако-
270 Глава 4. Микроархитектурный уровень
нец, поскольку программа перед переходом к Mainl требует, чтобы в MBR был по-
мещен следующий код операции, мы должны вызвать этот код. Последний цикл,
goto6, нужен для того, чтобы вовремя помесить данные из памяти в регистр MBR.
Смещения, которые используются в команде goto, представляют собой 16-бит-
ные значения со знаком в промежутке от -32768 до +32767. Это значит, что пере-
ходы на более дальние расстояния невозможны. Это свойство можно рассматри-
вать либо как дефект, либо как особенность машины IJVM (а также JVM). Те, кто
считает это дефектом, скажут, что машина JVM не должна ограничивать возмож-
ности программирования. Те, кто считает это особенностью, скажут, что работа
многих программистов продвинулась бы кардинальным образом, если бы им в ноч-
ных кошмарах снилось следующее сообщение компилятора:
Program is too big and hairy. You must rewrite it. Compilation aborted. (Программа
слишком длинная и сложная. Вы должны переписать ее. Компиляция прекращена.)
К сожалению (это наша точка зрения), это сообщение появляется только в том
случае, если выражение el se или then превышает 32 Кбайт, что составляет, по край-
ней мере, 50 страниц текста на языке Java.
А теперь рассмотрим три команды условного перехода: IFLT, IFEQ и IFICMPEQ.
Первые две выталкивают верхнее слово из стека и совершают переход в том слу-
чае, если это слово меньше 0 или равно 0 соответственно. Команда IFICMPEQ берет
два верхних слова из стека и совершает переход, если они равны. Во всех трех случа-
ях необходимо считывать новое верхнее слово стека и помещать его в регистр TOS.
Эти три команды сходны. Сначала операнд или операнды помещаются в регис-
тры, затем в TOS записывается новое верхнее слово стека, и, наконец, происходит
сравнение и осуществляется переход. Сначала рассмотрим IFLT. Слово, которое
нужно проверить, уже находится в регистре TOS, но поскольку команда IFLT вы-
талкивает слово из стека, нужно считать из памяти новую вершину стека и сохра-
нить ее в регистре TOS. Процесс считывания начинается в микрокоманде ifltl.
Во время iflt2 слово, которое нужно проверить, сохраняется в регистре ОРС, по-
этому новое значение можно сразу помесить в регистр TOS, и при этом предыду-
щее значение не пропадет. В цикле iflt3 новое верхнее слово стека, которое уже
находится в MDR, копируется в регистр TOS. Наконец, в цикле i f 114 проверяемое
слово (в данный момент оно находится в регистре ОРС) пропускается через АЛУ
без сохранения результата, после чего проверяется бит N. Если после проверки
условие подтверждается, микрокоманда осуществляет переход к Т, а если не под-
тверждается — то к F.
Если условие подтверждается, то происходят те же действия, что и в начале
команды GOTO, и далее осуществляется переход к goto2. Если условие не подтверж-
дается, необходима короткая последовательность микрокоманд (F, F2 и F3), чтобы
пропустить оставшуюся часть команды (смещение), возвратиться к Mainl и перей-
ти к следующей команде.
Команда IFEQ аналогична команде IFLT, только вместо битаЫ используется бит Z.
В обоих случаях ассемблер должен убедиться, что адреса микрокоманд F и Т разли-
чаются только крайним левым битом.
Команда IF_ICMPEQ в целом сходна с командой IFLT, только здесь нужно считы-
вать еще и второй операнд. Второй операнд сохраняется в регистре Н во время
цикла i f_i cmpeq3, где начинается чтение нового верхнего слова стека. Текущее верх-
нее слово стека сохраняется в ОРС, а новое загружается в регистр TOS. Наконец,
микрокоманда if_icmpeq6 аналогична ifeq4.
Разработка микроархитектурного уровня 271
Теперь рассмотрим команды INVOKEVIRTUAL и IRETURN. Как было описано в разделе
«Набор команд IJVM», они служат для вызова процедуры и выхода из нее. Коман-
да INVOKEVIRTUAL представляет собой последовательность из 22 микрокоманд. Это
самая сложная команда машины IJVM. Последовательность действий при выпол-
нении этой команды показана на рис. 4.10. 16-битное смещение используется для
того, чтобы определить адрес процедуры, которую нужно вызвать. Номер адреса
процедуры находится в наборе констант. Следует помнить, что первые 4 байта каж-
дой процедуры — не команды. Это два 16-битных указателя. Первый из них выдает
число параметров (включая OBJREF — см. рис. 4.10), а второй — размер облас-
ти локальных переменных (в словах). Эти поля вызываются через 8-битный порт
и объединяются таким же образом, как 16-битное смещение в одной команде.
Затем требуется специальная информация для восстановления предыдущего
состояния машины — адрес начала прежней области локальных переменных и ста-
рое значение регистра PC. Они сохранены непосредственно над областью локаль-
ных переменных под новым стеком. Наконец, вызывается следующий код опера-
ции, значение регистра PC увеличивается, происходит переход к циклу Mainl и
начинается выполнение следующей команды.
IRETURN — простая команда без операндов. Эта команда просто обращается к
первому слову области локальных переменных, чтобы извлечь информацию для
возвращения к прежнему состоянию. Затем она восстанавливает предыдущие зна-
чения регистров SP, LV и PC и копирует результат выполнения процедуры из но-
вого стека в предыдущий стек, как показано на рис. 4.11.
Разработка микроархитектурного уровня
При разработке микроархитектурного уровня (как и при разработке других уров-
ней) постоянно приходится идти на компромисс. У компьютера есть много важ-
ных характеристик: скорость, цена, надежность, простота использования, количе-
ство потребляемой энергии, физические размеры. При разработке центрального
процессора очень важную роль играет выбор между высокой скоростью и низкой
стоимостью. В этом разделе мы подробно рассмотрим данную проблему, покажем
преимущества и недостатки каждого из вариантов, а также узнаем, какой произво-
дительности можно достичь, какова при этом будет стоимость компьютера и на-
сколько сложным будет аппаратное обеспечение.
Скорость и стоимость
С развитием технологий скорость работы компьютеров стремительно растет. Су-
ществует три основных подхода, которые позволяют увеличить скорость выпол-
нения операций:
1. Сокращение количеств циклов, необходимых для выполнения команды.
2. Упрощение организации машины таким образом, чтобы можно было сде-
лать цикл короче.
3. Выполнение нескольких операций одновременно.
272 Глава 4. Микроархитектурный уровень
Первые два подхода очевидны, но существует огромное количество различных
вариантов разработки, которые могут очень сильно повлиять на число циклов, пе-
риод или (что бывает чаще всего) и то и другое вместе. В этом разделе мы приве-
дем пример того, как кодирование и декодирование операции могут подейство-
вать на цикл.
Число циклов, необходимых для выполнения набора операций, называется
длиной пути.
Иногда длину пути можно уменьшить с помощью дополнительного
аппаратного обеспечения. Например, если к регистру PC добавить инкрементор
(по сути, это сумматор, у которого один из входов постоянно связан с единицей),
то нам больше не придется использовать для этого АЛУ, и следовательно, количе-
ство циклов сократится. Однако такой подход не настолько эффективен, как хоте-
лось бы. Часто в том же цикле, в котором значение PC увеличивается на 1, происхо-
дит еще и операция чтения, и следующая команда в любом случае не может начаться
раньше, поскольку она зависит от данных, которые должны поступить из памяти.
Для сокращения числа циклов, необходимых для вызова команды, требуется
нечто большее, чем простое добавление схемы, которая увеличивает PC на 1. Что-
бы повысить скорость вызова команды, нужно применить третью технологию —
параллельное выполнение команд. Весьма эффективно отделение схем для вызо-
ва команд (8-битного порта памяти и регистров PC и MBR), если этот блок сде-
лать функционально независимым от основного тракта данных. Таким образом,
он может сам вызывать следующий код операции или операнд. Возможно, он даже
будет работать асинхронно относительно другой части процессора и вызывать одну
или несколько команд заранее.
Один из наиболее трудоемких процессов при выполнении команд — вызов дву-
байтного смещения и сохранение его в регистре Н для подготовки к сложению
(например, при переходе к РС±п байтов). Одно из возможных решений — увеличить
порт памяти до 16 битов, но это сильно усложняет операцию, поскольку требуемые
16 битов могут перекрывать границы слова, поэтому даже считывание из памяти
32 битов за один раз не обязательно приведет к вызову обоих нужных нам байтов.
Одновременное выполнение нескольких операций — самый продуктивный под-
ход. Он дает возможность очень сильно повысить скорость работы компьютера.
Даже простое перекрытие вызова и выполнения команды чрезвычайно эффектив-
но. При более сложных технологиях допустимо одновременное выполнение не-
скольких команд. Вообще говоря, эта идея является основой проектов современ-
ных компьютеров. Ниже мы обсудим некоторые технические приемы, позволяющие
воплотить этот подход.
На одной чаше весов находится скорость, на другой — стоимость. Стоимость
можно измерять различными способами, но точное определение стоимости дать
очень трудно. В те времена, когда процессоры конструировались из дискретных
компонентов, достаточно было подсчитать общее число этих компонентов. В на-
стоящее время процессор целиком помещается на одну микросхему, но большие и
более сложные микросхемы стоят гораздо дороже, чем более простые микросхемы
небольшого размера. Можно подсчитать отдельные компоненты (транзисторы, вен-
тили, функциональные блоки), но обычно это число не так важно, как размер кон-
тактного участка, необходимого для интегральной схемы. Чем больше участок, тем