Регистры
Для доступа к регистрам процессору не нужно занимать внешнюю шину Данных, да и цикл доступа к регистру обычно очень короток и совпадает с циклом работы АЛУ. Следовательно, чем больше у процессора регистров, тем быстрее он может работать с оперативными данными. В те времена, когда компьютеры были большими, стремление к увеличению количества регистров упиралось в стоимостные и электротехнические ограничения.
У компьютеров первых поколений для реализации регистров использовались отдельные транзисторы или микросхемы малой степени интеграции, Поэтому они стоили гораздо дороже (в расчете на один бит памяти), потребляли гораздо больше энергии и рассеивали гораздо больше тепла, чем ферритовая память. Переход на современные кристаллы высокой интеграции изменил положение, но не принципиально: триггеры, которые используются для реализации регистров, по перечисленным параметрам всегда хуже, чем исполненное по той же технологии динамическое ОЗУ. Поэтому компьютеры первых поколений обычно имели лишь несколько регистров, а мини – и микрокомпьютеры 70-х и начала 80-х прошлого века – не более нескольких десятков.
У современных процессоров количество регистров измеряется сотнями, а иногда и тысячами. Например, вместо буфера на одну только текущую команду, все без исключения современные процессоры имеют так называемую очередь предварительной выборки команд. У микроконтроллеров PIC и Atmel то, что в спецификациях указано как ОЗУ (у младших моделей 128 или 256 байт, а у старших – много килобайт), фактически представляет собой регистры.
Регистровое окно SPARC
RISC-процессор SPARC [www.sparc.com v9] имеет регистровый файл, объем которого у старых версий процессора составлял 136 32-разрядных слов, а у современных 520 и более. Этот файл состоит из групп по 8 регистров.
Программе одновременно доступно 32 регистра, нумеруемые от 0 до 31, называемые регистровым окном. Из них регистр 0 (обозначаемый как % g0) – выделенный, чтение из него всегда возвращает 0. Следующие 7 регистров (обозначаемые как %g1-%g7) используются для глобальных переменных. Эти регистры не входят в регистровое окно. Регистры с r8 по r15 (%о0-%о7) используются для передачи параметров вызываемой процедуре (r15 используется для хранения адреса возврата подпрограммы), регистры с r24 по r31 (%i0-%i7) – для доступа к параметрам, и, наконец, регистры с r16 по г23 (%10-%17) – для хранения локальных переменных. При вызове подпрограммы, команда save сдвигает регистровое окно, так что регистры %оО-%о7 вызывающей процедуры становятся регистрами %о0-%о7 процедуры вызванной. Регистры rО-r7 сдвигом регистрового окна не затрагиваются.
Таким образом, регистровый файл выполняет функции стека вызовов – в нем сохраняются адреса возврата, передаются параметры и хранятся локальные переменные. Впрочем, такой подход при всей его привлекательности имеет большой недостаток– глубина стека вызовов оказывается ограничена глубиной регистрового файла. Способ устранения этого ограничения описан в разд. "Косвенный регистровый режим со смещением".
Важно еще раз отметить, "что обычно далеко не все имеющиеся регистры непосредственно доступны программе. Так, в системе команд х86 предусмотрено всего восемь регистров общего назначения, но современные суперскалярные реализации этой архитектуры (Pentium II, Athlon и т. д.) имеют более сотни физических регистров и несколько арифметико-логических устройств. Логика предварительной выборки дешифрует несколько команд и назначает исполнение этих команд на свободные АЛУ, по мере их поступления, с использованием свободных копий регистров, при этом, не нарушая связи по данным между последовательными командами.
При наличии большого количества регистров существует два подхода к их выбору. Первый состоит в том, что каждый код операции работает только со СВОИМ регистром. Команда move %eax, %ebx – это одна команда, a move %еах, %esp – совсем другая. При этом бывает и так, что некоторые команды Для некоторых регистров не определены.
Второй подход, более симпатичный автору, называется ортогональной системой команд, и состоит в том, что все команды (или хотя бы большинство) могут работать с любыми регистрами. Номер регистра при этом кодируется специальным битовым полем в коде команды (или несколькими битовыми полями, если команда оперирует несколькими регистрами) (рис. 2.3).
Рис. 2.3. Формат команды микропроцессора SPARC (цит. по [www.sparc.com v9])
При всех недостатках первого подхода, ортогональная система команд создает специфическую проблему: увеличение количества регистров оказывается невозможным. Ведь это требует расширения битового поля номера регистра, а изменение размера битовых полей команд – это нарушение бинарной совместимости. Впрочем, в разд. "Вытесняющая многозадачность" мы поймем, почему даже в неортогональных системах команд расширение номенклатуры регистров практически невозможно.