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

Архитектура компьютера - Таненбаум Э

..pdf
Скачиваний:
486
Добавлен:
24.05.2014
Размер:
5.67 Mб
Скачать

Пример реализации микроархитектуры

263

Микрокоманда Операции

if_icmpeq4

OPC=TOS

if_icmpeq5

TOS=MDR

if_icmpeq6

Z=OPC-H, if(Z)gotoT,

 

 

else goto F

 

 

OPOPC-1; fetch;

 

 

goto goto2

F

 

PC=PC+1

F2

 

PC=PC+1; fetch

F3

 

goto Mam1

invoke

virtual!

PC=PC+1, fetch

invoke

virtual

H=MBRU«8

mvoke_virtual3

H=MBRU ИЛИ Н

invoke_virtual4

MAR=CPP+H, rd

mvoke_virtual5

OPC=PC+1

invoke_virtual6

PC=MDR, fetch

mvoke_virtual7

PC=PC+1; fetch

mvoke_virtual8

H=MBRU«8

invoke_virtual9

H=MBRU ИЛИ Н

invoke_virtual!0

PC=PC+1, fetch

invoke_virtual11 TOS=SP-H

mvoke_virtual12

TOS=MAR=TOS+1

invoke virtual 13

PC=PC+1, fetch

mvoke_virtual14

H=MBRU<<8

invoke_virtual15

 

mvoke_virtual16

MDR=SP+H+1;wr

invoke_virtual17

MAR=SP=MDR

invoke_virtual18

MDR=OPC, wr

invoke_virtual 19

MAR=SP=SP+1

mvoke_virtual20

MDR=LV, wr

invoke_virtual21

PC=PC+1, fetch

invoke_virtual22

LV=TOS, gotoMami

ireturni

MAR=SP=LV; rd

Комментарий

Временное сохранение TOS в ОРС Помещение новой вершины стека в TOS

Если два верхних слова равны, осуществляется переход к Т, если они не равны, осуществляется переход к F

То же, что gotoi, нужно для адреса целевого объекта

Пропуск первого байта смещения

PC указывает на следующий код операции Ожидание вызова кода операции

MBR = первый байт индекса; увеличение PC на 1, вызов второго байта

Сдвиг первого байта на 8 битов и сохранение значения в регистре Н Н = смещение указателя процедуры от регистра СРР

Вызов указателя процедуры из набора констант

Временное сохранение значения PC в регистре ОРС Регистр PC указывает на новую процедуру, вызов числа параметров

Вызов второго байта числа параметров

Сдвиг первого байта на 8 битов и сохранение значения в регистре Н

Н = число параметров

Вызов первого байта размера области локальных переменных

TOS = адрес OBJREF-1

TOS = адрес OBJREF {новое значение LV)

Вызов второго байта размера области локальных переменных

Сдвиг первого байта на 8 битов и сохранение значения в регистре Н

Н = размер области локальных переменных Перезапись OBJREF со связующим указателем

Установка регистров SP и MAR на адрес ячейки, в которой содержится старое значение PC

Сохранение старого значения PC над локальными переменными

SP указывает на ячейку, в которой хранится старое значение LV

Сохранение старого значения LV над сохраненным значением PC

Вызов первого кода операции новой процедуры

Установка значения LV на первый адрес фрейма локальных переменных

Переустановка регистров SP и MAR для вызова связующего указателя

продолжение!

264

Глава 4. Микроархитектурный уровень

Таблица4.4{продолжение}

 

Микрокоманда Операции

Комментарий

ireturn2

 

Процесс считывания

ireturn3

LV=MAR=MDR;rd

Установка регистра LV на связующий указатель;

 

 

вызов старого значения PC

ireturn4

MAR=LV+1

Установка регистра MAR на чтение старого

 

 

значения LV

ireturn5

PC=MDR; rd; fetch

Восстановление PC; вызов следующего кода

 

 

операции

ireturn6

MAR=SP

Установка MAR на запись TOS

ireturn7

LV=MDR

Восстановление LV

ireturn8

MDR=TOS; wr; goto Mainl

Сохранение результата в изначальной вершине

 

 

стека

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

Еще раз подчеркнем, что микрокоманды, приведенные в табл. 4.4, не расположены в памяти последовательно и что микрокоманда Mainl находится вовсе не в ячейке с адресом 0 (поскольку в этой ячейке должна находиться микрокоманда nopl). Задача микроассемблера — поместить каждую команду в подходящую ячейку и связать их в короткие последовательности, используя поле NEX1VADDRESS. Каждая последовательность начинается с адреса, который соответствует номерному значению кода операции (например, команда POP начинается с адреса 0x57), но остальные части последовательности могут находиться в любых ячейках управляющей памяти, и эти ячейки не обязательно идут подряд.

А теперь рассмотрим команду IADD. Она начинается с микрокоманды iaddl. Требуется выполнить следующие действия:

1.Значение регистра TOS уже есть, но из памяти нужно вызвать второе слово стека.

2.Значение регистра TOS нужно прибавить ко второму слову стека, вызванному из памяти.

3.Результат, который помещается в стек, должен быть сохранен в памяти и в регистре TOS.

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

Все эти действия выполняются в первом цикле (i addl). Здесь же инициируется операция чтения. Кроме того, регистр МРС получает значение из поля NEXT ADDRESS микрокоманды iaddl. Это адрес микрокоманды iadd2. Затем iadd2 счи-

Пример реализации микроархитектуры

265

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

В начале третьего цикла (iadd3) MDR содержит второе слагаемое, вызванное из памяти. В этом цикле оно прибавляется к значению регистра Н, а результат сохраняется обратно в регистры MDR и TOS. Кроме того, начинается операция записи, в процессе которой новое верхнее слово стека сохраняется в памяти. В этом цикле команда goto приписывает адрес Mainl регистру МРС, таким образом, мы возвращаемся к исходному пункту и можем начать выполнение следующей операции

Если следующий код операции, который содержится в данный момент в регистре MBR, равен 0x64 (ISUB), то повторяется практически таже последовательность действий После выполнения Mainl управление передается микрокоманде с адресом 0x64 (1 subl) За этой микрокомандой следуют i sub2, i sub3, а затем снова Mai nl Единственное различие между этой и предыдущей последовательностью состоит

втом, что в цикле isub3 содержание регистра Н не прибавляется к значению MDR,

авычитается из него

Команда IAND идентична командам IADD и ISUB, только в данном случае два верхних слова стека подвергаются логическому умножению (операция И), а не складываются и не вычитаются Нечто подобное происходит и во время выполнения команды I0R

Если код операции соответствует командам OUP, POP или SWAP, то нужно использовать стек Команда DUP дублирует верхнее слово стека Поскольку значение этого слова уже находится в регистре TOS, нужно просто увеличить SP на 1 Теперь регистр SP указывает на новый адрес В эту новую ячейку и записывается значение регистра TOS Команда POP тоже достаточно проста нужно только уменьшить значение SP на 1, чтобы отбросить верхнее слово стека Однако теперь необходимо считать новое верхнее слово стека из памяти и записать его в регистр TOS. Наконец, команда SWAP меняет местами значения двух ячеек памяти, а именно два верхних слова стека Регистр TOS уже содержит одно из этих значений, поэтому считывать его (значение) из памяти не нужно Подробнее мы обсудим эту команду немного позже.

Команда BIPUSH сложнее предыдущих, поскольку за кодом операции следует байт, как показано на рис 4 13 Этот байт представляет собой целое число со знаком Этот байт, который уже был передан в регистр MBR во время микрокоманды Mainl, нужно расширить до 32 битов (знаковое расширение) и скопировать его в регистр MDR. Наконец, значение SP увеличивается на 1 и копируется в MAR, что позволяет записать операнд на вершину стека. Этот операнд также должен копироваться в регистр TOS Отметим, что значение регистра PC должно увеличиваться на 1, чтобы в микрокоманде Mainl следующий код операции уже имелся в наличии.

BIPUSH

 

(0x10)

Б А И Т

Рис. 4.13. Формат команды BIPUSH

Теперь рассмотрим команду ILOAD В этой команде за кодом операции также следует байт (рис. 4.14, а), но этот байт представляет собой индекс (без знака),

2 6 6 Глава 4. Микроархитектурный уровень

используемый для того, чтобы найти в пространстве локальных переменных слово, которое нужно поместить в стек. Поскольку здесь имеется всего 1 байт, можно различать только 28=256 слов, а именно первые 256 слов пространства локальных переменных. Для выполнения команды ILOAD требуется и процесс чтения (чтобы вызвать слово), и процесс записи (чтобы поместить его в стек). Чтобы определить адрес для считывания, нужно прибавить смещение, которое хранится в регистре MBR (буферном регистре памяти), к содержимому регистра LV. Доступ к регистрам MBR и LV можно получить только через шину В, поэтому сначала значение LV копируется в регистр Н (в цикле iloadl), а затем прибавляется значение MBR. Результат суммирования копируется в регистр MAR, и начинается процесс чтения (в цикле iload2).

ILOAD

ИНДЕКС

WIDE

ILOAD

ИНДЕКСНЫЙ ИНДЕКСНЫЙ

(0x15)

(0хС4)

(0x15)

БАЙТ1

БАЙТ 2

 

Рис. 4.14. Команда ILOADсоднобайтным индексом (а); команда WIDE ILOAD с двубайтным индексом (б)

Однако здесь регистр MBR используется не совсем так, как в команде BIPUSH, где байт расширен по знаку. В случае с индексом смещение всегда положительно, поэтому байт смещения должен быть целым числом без знака (в отличие от BIPUSH, где байт представляет собой 8-битное целое число со знаком). Интерфейс между регистром MBR и шиной В разработан таким образом, чтобы обе операции были возможны. В случае с BIPUSH (где байт — 8-битное целое число со знаком) самый левый бит значения MBR копируется в 24 старших бита шины В. В случае с ILOAD (где байт — 8-битное целое число без знака) 24 старших бита шины В заполняются нулями. Два специальных сигнала помогают определить, какую из этих двух операций нужно выполнить (см. рис. 4.5). В микропрограмме слово MBR указывает на байт со знаком (как в команде bipush3), a MBRU — на байт без знака (как в команде iload2).

Пока ожидается поступление операнда из памяти (во время iload3), значение регистра SP увеличивается на 1 для записи новой вершины стека. Это значение также копируется в регистр MAR (это требуется для записи операнда в стек). Затем значение PC снова увеличивается на 1, чтобы вызвать следующий код операции (микрокоманда iload4). Наконец, значение MDR копируется в регистр TOS, чтобы показать новое верхнее слово стека (микрокоманда iload5).

Команда ISTORE противоположна команде ILOAD (из стека выталкивается верхнее слово и сохраняется в ячейке памяти, адрес которой равен сумме значения регистра LV и индекса данной команды). В данном случае используется такой же формат, как и в команде ILOAD (рис. 4.14, й), только здесь код операции не 0x15, а 0x36. Поскольку верхнее слово стека уже известно (оно находится в регистре TOS), его можно сразу сохранить в памяти. Однако новое верхнее слово стека все же необходимо вызвать из памяти, поэтому требуется и операция чтения, и операция записи, хотя их можно выполнять в любом порядке (или даже одновременно, если бы это было возможно).

Пример реализации микроархитектуры

267

Команды ILOAD и ISTORE имеют доступ только к первым 256 локальным переменным. Хотя для большинства программ этого пространства будет достаточно, все же нужно иметь возможность обращаться к любой локальной переменной, в какой бы части фрейма она не находилась. Чтобы обеспечить такую возможность, машина IJVM использует то же средство, что и JVM: специальный код операции WIDE (так называемый префиксный байт), за которым следует код операции ILOAD или ISTORE. Когда встречается такая последовательность, формат команды ILOAD или ISTORE меняется, и за кодом операции идет не 8-битный, а 16-битный индекс, как показано на рис. 4,14, б.

Команда WIDE декодируется обычным способом. Сначала происходит переход к микрокоманде widel, которая обрабатывает код операции WIDE. Хотя код операции, который нужно расширить, уже присутствует в регистре MBR, микрокоманда widel вызывает первый байт после кода операции, поскольку этого требует логика микропрограммы. Затем совершается еще один межуровневыи переход, но на этот раз для перехода используется байт, который следует за WIDE. Но поскольку команда WIDE ILOAD требует набора микрокоманд, отличного от ILOAD, а команда WIDE ISTORE требует набора микрокоманд, отличного от ISTORE, и т. д., при осуществлении межуровневого перехода нельзя использовать в качестве целевого адреса код операции.

Вместо этого микрокоманда wi del подвергает логическому сложению адрес Ох 100 и код операции, поместив его в регистр МРС. В результате интерпретация WIDE LOAD начинается с адреса 0x115 (а не 0x15), интерпретация WIDE ISTORE — с адреса 0x136 (а не 0x36) и т. д. Таким образом, каждый код операции WIDE начинается с адреса, который в управляющей памяти на 256 (то есть Ох 100) слов выше, чем соответствующий обычный код операции. Начальная последовательность микрокоманд для ILOAD и WIDE ILOAD показана на рис. 4.15.

Команда WIDE ILOAD отличается от обычной команды ILOAD только тем, что индекс в ней состоит из двух индексных байтов. Слияние и последующее суммирование этих байтов должно происходить по стадиям, при этом сначала первый индексный байт сдвигается влево на 8 битов и копируется в Н. Поскольку индекс — целое число без знака, то здесь используется регистр MBRU (24 старших бита заполняются нулями). Затем прибавляется второй байт индекса (операция сложения идентична слиянию, поскольку младший байт регистра Н в данный момент равен 0), при этом гарантируется, что между байтами не будет переноса. Результат снова сохраняется в регистре Н. С этого момента происходят те же действия, что и в стандартной команде ILOAD. Вместо того чтобы дублировать последние команды ILOAD (от iload3 до iload5), мы просто совершили переход от wide_iload4 к iload3. Отметим, что во время выполнения этой команды значение PC должно увеличиваться на 1 дважды, чтобы в конце этот регистр указывал на следующий код операции. Команда ILOAD увеличивает значение один раз; последовательность команд WIDE_ILOAD также увеличивает это значение один раз.

Такая же ситуация имеет место при выполнении WIDEISTORE. После выполнения первых четырех микрокоманд (от wi de_i storel до wi de_i store4) последовательность действий та же, что и в команде ISTORE после первых двух микрокоманд, поэтому мы совершаем переход от wide_istore4 к istore3.

Далее мы рассмотрим команду LDC_W. Существует два отличия этой команды от ILOAD. Во-первых, она содержит 16-битное смещение без знака (как и расширенная версия ILOAD), а во-вторых, эта команда индексируется из регистра СРР, а не из

268 Глава4. Микроархитектурныйуровень

LV, поскольку она считывает значение из набора констант, а не из фрейма локальных переменных. (Существует еще и краткая форма этой команды — LDC, но мы не стали включать ее в машину IJVM, поскольку полная форма содержит в себе все варианты краткой формы, хотя при этом занимает 3 байта вместо 2.)

Адрес

Управляющая память

 

0x1FF

Порядоквыполнения

 

 

микрокоманд

 

 

WIDE

 

ILOAD

ILOAD

0x115

wide iloadi

3

0x100

Maini

 

0хС4

widei

 

 

 

0x15

iloadi

 

0x00

Рис. 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. И именно для этого предназначен регистр ОРС.

Память

-1 байт-

 

 

 

 

 

 

 

 

 

п+3

 

 

 

 

 

П+2

БАЙТ

БАЙТ

БАЙТ

БАЙТ

БАЙТ

СМЕЩЕНИЯ 2

СМЕЩЕНИЯ 2

СМЕЩЕНИЯ 2

СМЕЩЕНИЯ 2

СМЕЩЕНИЯ 2

п+1

БАЙТ

БАЙТ

БАЙТ

БАЙТ

БАЙТ

СМЕЩЕНИЯ 1

СМЕЩЕНИЯ 1

СМЕЩЕНИЯ 1

СМЕЩЕНИЯ 1

СМЕЩЕНИЯ 1

п

GOTO (0xA7)

GOTO (0xA7)

GOTO (0xA7)

GOTO (0xA7)

GOTO (0xA7)

Регистры

 

 

 

 

 

 

-1 байт-

 

 

 

 

PC

п

п+1

п+1

П+2

П+2

 

ОРС

 

 

п

П

п

 

 

 

MBR

0хА7

БАЙТ

БАЙТ

БАЙТ

БАЙТ

СМЕЩЕНИЯ 1

СМЕЩЕНИЯ 1

СМЕЩЕНИЯ 1

СМЕЩЕНИЯ 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 f114 проверяемое слово (в данный момент оно находится в регистре ОРС) пропускается через АЛУ без сохранения результата, после чего проверяется бит 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 битов за один раз не обязательно приведет к вызову обоих нужных нам байтов.

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

На одной чаше весов находится скорость, на другой — стоимость. Стоимость можно измерять различными способами, но точное определение стоимости дать очень трудно. В те времена, когда процессоры конструировались из дискретных компонентов, достаточно было подсчитать общее число этих компонентов. В настоящее время процессор целиком помещается на одну микросхему, но большие и более сложные микросхемы стоят гораздо дороже, чем более простые микросхемы небольшогоразмера. Можно подсчитатьотдельные компоненты (транзисторы, вентили, функциональные блоки), но обычно это число не так важно, как размер контактного участка, необходимого для интегральной схемы. Чем больше участок, тем