Архитектура набора команд (ISA)

В этой главе даётся принципиальное описание архитектуры команд виртуального процессора (Instruction Set Architecture или ISA).

Общая характеристика системы команд

Архитектура системы команд нацелена на максимально параллельное извлечение инструкций из памяти и декодирование инструкций. Формат инструкций регулярный (длина декодируемой порции кода постоянна), но не строго фиксированный (когда все инструкции обязательно имеют одинаковую длину), а почти фиксированный (внутри регулярной порции начальные части инструкций имеют одинаковую длину, возможное продолжение также имеет фиксированную длину). Единицей потока команд является 16-байтовая связка, собранная из трёх (обычно) или двух команд.

В отличие от традиционных систем VLIW (very long instruction word), объединение в связки отражает только параллельный процесс выборки и декодирования, но не процесс диспетчеризации, исполнения или завершения инструкций. Связки команд не описывают привязку отдельных команд к функциональным устройствам, возможность (или необходимость) параллельного исполнения и/или завершения, тайминги выполнения. Для этого предполагается использование аппаратуры суперскалярного внеочередного выполнения команд. Это необходимо для переносимости программ в рамках семейства машин. Предполагается, что программу можно использовать без перекомпиляции на машинах с разными наборами функциональных устройств и таймингами.

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

Архитектура команд использует неразрушающие команды (результат не совмещён с одним из аргументов) – двухадресные унарные команды, трехадресные бинарные команды и четырехадресные команды с перекрытием.

В архитектуре POSTRISC каждая команда имеет дополнительный операнд – однобитовый квалифицирующий предикат. Выполнение команд происходит условно под предикатом. Инструкции под ложным предикатом воспринимаются как невыполняемые (nops). Некоторые команды могут требовать исполнения только под истинным предикатом.

В новой архитектуре для сокращения пути данных перекрывается (совмещается в одной машинной инструкции) ограниченное число часто встречающихся комбинаций команд: сложение (или вычитание) со сдвигом; вещественное умножение со сложением или вычитанием; сложение с константой и обращение к памяти (base+displacement addressing mode); сложение регистров (со сдвигом) и обращение к памяти (indexed (scaled) addressing mode); сравнение с переходом по результату сравнения; изменение счётчика цикла со сравнением и переходом по результату сравнения. Архитектура предполагает истинно аппаратную поддержку перекрываемых команд, а не простое уплотнение кода с аппаратным разбиением на исходные операции.

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

Для архитектуры команд POSTRISC базовой технологией является параллельное (super-scalar) внеочередное (out-of-order) выполнение сложных (fused) команд с явной предикацией.

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

Опциональные подсказки процессору о направлении и частоте переходов и о частоте и характере будущих обращений к строкам кэш-памяти осуществляются (при наличии такой информации) в отдельных командах.

Все манипуляции с целочисленными данными происходят между целочисленными регистрами, с двумя регистрами исходных операндов (может быть 16-разрядное непосредственное значение) и одним регистром результата.

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

Множество кодов скалярных операций дополнено широким набором векторных операций. Специальное векторное расширение используется для обработки мультимедийных и численных данных в вещественных регистрах.

Архитектура принадлежит к типу load/store. Обращения к памяти ограничиваются командами загрузки или записи, перемещающими данные между регистрами и памятью, и не пересекаются с одновременным использованием загруженного значения. Любая команда обращения к памяти ограничена строго одним обращением в память с единственной трансляцией виртуального адреса, для чего введены строгие ограничения по выравниванию данных в памяти.

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

Регистровые файлы

Ресурсы процессора включают в себя регистровые файлы, специальные регистры, структуры ассоциативного поиска, прерывания. Одни ресурсы доступны для программ пользователя, другие необходимы для функционирования операционной системы.

Каждый процессор имеет набор регистров, которые содержат текущее состояние процессора. Все регистры подразделяются на шесть регистровых файлов. Не существует регистров, которые не входили бы в какой-либо регистровый файл.
Регистровые файлы
Регистровый файл Количество регистров Размер регистров в битах Дополнительная информация
Регистры общего назначения12864 Регистры общего назначения предназначены для манипуляций с целыми числами длиной 1,2,4,8 байт или векторами целых чисел длиной 1 или 2 байта. Регистр g0 всегда равен нулю, запись в него игнорируется. Все остальные 127 регистров общего назначения полностью равноправны на уровне архитектуры (но возможно неравноправны с точки зрения двоичного интерфейса ABI).
Регистры плавающей точки (векторные регистры)128128 Регистры плавающей точки предназначены для манипуляций с вещественными числами четверной точности, упакованными векторами вещественных чисел одинарной и двойной точности, упакованными векторами целых чисел длиной 1,2,4,8 байт. Регистр f0 всегда равен нулю, запись в него игнорируется. Все остальные 127 регистров плавающей точки полностью равноправны на уровне архитектуры.
Регистры специального назначения12864 Как ясно из названия, у регистров специального назначения разное предназначение. Не все из 128 специальных регистров реализованы. Чтение/запись зависит от уровня приоритета, номера регистра.
Условные регистры (предикаты)641 Набор однобитовых регистров. Реализован на основе специального регистра CRF. Предикат с0 всегда равен 1 (истинен).
Регистры мониторинга2x4+64 Эти регистры предназначены для подсчёта разных внутренних событий при выполнении потока инструкций. Их количество зависит от реализации. Чтение/запись зависит от уровня приоритета, модели процессора. Они всегда используются попарно.
Отладочные регистры2x4+64 Отладочные регистры позволяют организовать перехват обращений программы в определённые диапазоны адресов с определёнными целями (например исполнение или запись), и позволяют отладчику проверять правильность программы. Их количество зависит от реализации. Чтение/запись зависит от уровня приоритета, модели процессора. Они всегда используются попарно.
Регистры идентифицирующие возможности процессора (CPUID)8+64 Эти регистры хранят информацию о текущей реализации архитектуры – об аппаратных возможностях исполняющего код процессора. Их количество зависит от реализации. Они доступны только для чтения.

Предикация или условное выполнение

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

При неправильном предсказании направления перехода, команда перехода вызывает остановку конвейера. Происходит сброс всех спекулятивно запущенных команд от стадии выборки до стадии записи результатов – практически на всю длину конвейера.

Предикация (predication) – условное выполнение команд. Цель условного выполнения состоит в удалении из программы плохо предсказуемых переходов. При этом любая команда становится аппаратно выполняемым оператором условного перехода. Например:

if(a) b=c+d.

Дополнительный аргумент a кодирует регистр логического условия. Эта технология заменяет зависимость по управлению на зависимость по данным и сдвигает возможный останов конвейера ближе к концу конвейера. Достоинством условного выполнения является ликвидация большинства переходов в коротких условных вычислениях, а значит и остановок конвейера. Однако это чисто силовой метод, сводящийся к одновременному выставлению на конвейер команд из нескольких ветвей выполнения под разными предикатами. Кроме того, требуется место в команде для явного кодирования дополнительного аргумента – регистра предиката.

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

Все команды, выданные при ложном значении предиката, отвергаются на стадии завершения (retire) или ранее (вплоть до стадии decode) без возникновения прерываний. Разумеется, существуют исключения из этого принципа, иначе, установив однажды значения всех предикатов в 0, мы бы никогда не смогли изменить хотя бы один из них на 1, так как все команды были бы отвергнуты. Поэтому один избранный предикат (c0) всегда равен 1.

Формат связок команд

Существующие RISC-архитектуры исчерпали возможности фиксированного 32-битового формата команд. Глубокое развёртывание циклов и инлайнирование функций требует наличия более чем 32 регистров общего назначения (и плавающей точки), но увеличить число регистров более 32-х при 32-битовой длине инструкции затруднительно. Борьба с непредсказуемыми переходами требует введения предикатов и условного исполнения, но для кодирования дополнительного аргумента-предиката в каждой инструкции нужно дополнительное место. Глобальные флаги и выделенные регистры мешают эффективному параллельному исполнению инструкций, но дублирование ресурсов и введение явных зависимостей между инструкциями также требует дополнительных битов для явного описания в команде.

С другой стороны, использование фиксированного 64-разрядного формата увеличивает размер программы в два раза и не оправдывает возможные выгоды. Остается единственный промежуточный формат, согласованный с выравниванием по границе 2n байт, – 3 команды по 41 биту (slots), упакованные в 128-битовые связки (bundles).

Использование 128-битового формата автоматически дает важный побочный эффект, связанный с невозможностью передать управление на любую команду в связке кроме первой и выполнить часть связки. Это дает как минимум 16-байтовую выборку при обращении в кэш инструкций. Нет необходимости реализовывать цепи обхода и буферы для старта с середины 128-битовой порции кэш-строки.

Архитектура определяет, что связка длиной 128 бит состоит из шаблона связки длиной 5 бит и трех слотов по 41 биту. Следующая таблица показывает упаковку команд в связки.

Деление связки на слоты и шаблон
ШаблонСлот 1Слот 2Слот 3
C0XXX41 бит41 бит41 бит
C11XX82 бита41 бит
C10XX41 бит82 бита

Архитектура определяет два типа команд: из одного или двух слотов связки. Связка может состоять из трех простых односложных команд, или двухсложной команды и односложной (прямой порядок), или односложной команды и двухсложной (обратный порядок).

Биты шаблона связки
01234
Бит продолжения (пока не используется, но будет задействован для статического предсказания переходов) Бит присутствия длинной команды
(1 – есть)
Бит положения длинной команды
(1 – первая)
Младший бит основного кода первой (длинной) команды Младший бит основного кода второй (короткой) команды
Бит положения длинной команды
(0 – вторая)
Младший бит основного кода первой (короткой) команды Младший бит основного кода второй (длинной) команды
Бит присутствия длинной команды
(0 – нет)
Младший бит основного кода первой (короткой) команды Младший бит основного кода второй (короткой) команды Младший бит основного кода третьей (короткой) команды

Разбиение связки на команды полностью определяется шаблоном из 5 бит, так что основные и дополнительные коды инструкций для разных длин командного формата не пересекаются, и будут описываться отдельно.

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

Поэтому односложные команды, хотя и занимают один слот длиной 41 бит, но содержат 42 бита, а двухсложные, хотя и занимают два слота по 41 биту, но содержат 83 бита.

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

Следующая таблица показывает форматы команд и длины полей команд в битах для односложных команд для любого слота связки. Нулевой по счету бит команды извлекается из шаблона связки, остальные содержатся в одном из слотов связки (всего 42 бита). Нумерация битов показана согласно порядка в памяти слева направо (little-endian).

Форматы инструкций
Название
формата
Биты (слева направо от младших к старшим)
IMBIN opcode qp dst src simm16
IMBINU opcode qp dst src uimm16
GMEM opcode qp dst/src base disp16
FMEM opcode qp dst/src base disp16
GMEMW opcode qp dst/src base opx disp14
FMEMW opcode qp dst/src base opx disp14
GMEMD opcode qp dst/src base opx disp13
FMEMD opcode qp dst/src base opx disp13
GMEMQ opcode qp dst/src base opx disp12
FMEMQ opcode qp dst/src base opx disp12
BRC opcode qp src src opx label12
BRCI opcode qp src simm opx label12
BRCIU opcode qp src uimm opx label12
BBIT opcode qp src pos 0 opx label12
EXTR opcode qp dst src shift opx pos
SHPAIR opcode qp dst src src opx pos
SHADD opcode qp dst src src scale opx
GMEMX opcode qp dst/src base index disp opx
FMEMX opcode qp dst/src base index disp opx
GMEMU opcode qp dst/src base disp stride opx
FMEMU opcode qp dst/src base disp stride opx
GBIN opcode qp dst src src opx 0
MSPR opcode qp dst/src src/dst 0 opx 0
SYS_B opcode qp 0 src 0 opx 0
SYS_BC opcode qp 0 src src opx 0
NOP opcode qp 0 opx 0
BREAK opcode qp src trap index opx 0
UNOP opcode qp dst src 0 opx 0
UMASK opcode qp dst src shift 0 opx 0
BPA opcode qp delay src 0 opx 0
BPR opcode qp delay label23
LDI opcode qp dst simm23/label23
CTIPR opcode qp opx nt s label23
CTBD opcode qp opx nt s base simm16
CTBX opcode qp opx nt s base index scale disp
CMPI opcode qp pair m src simm16
CMPUI opcode qp pair m src uimm16
CARRY opcode qp pair m dst src src opx
CMP opcode qp pair m src src opx 0
TBIT opcode qp pair m src shift 0 opx 0
PRED opcode qp pair m src 0 src 0 opx 0
FCMP opcode qp pair m src src opx 0
FTEST opcode qp pair m src count opx 0
FSEL opcode qp dst src src src opx
FDEP opcode qp dst src count src opx
FMAC opcode qp dst src src src sf
FBIN opcode qp dst src src opx sf
FUNOP opcode qp dst src count opx sf
FCVFG opcode qp dst src count opx sf
FCVTG opcode qp dst src count opx sf
Применяемые текстовые (и цветовые) обозначения
ОбозначениеДлинаОписание
opcode6Главный код операции
src7Регистр общего назначения – операнд
src7Регистр плавающей точки – операнд
src7Регистр специального назначения – операнд
src6Условный регистр (предикат) – операнд
qp6Квалифицирующий предикат
dst7Регистр общего назначения – результат
dst7Регистр плавающей точки – результат
dst7Регистр специального назначения – результат
pair6Предикат – основание предикативной пары
simm7,12,16,23Константа непосредственно в коде команды (знаково расширяемая)
uimm7,16,23Константа непосредственно в коде команды (расширяемая нулями)
shift6Номер бита, Величина сдвига 0..63
scale3Величина сдвига от 1 до 8
delay7Дистанция задержки отложенного перехода
x,opx1,2,3,4,6,7Дополнительный код операции
disp3,5,12-16Смещение (знаково расширяемая константа)
stride5Константа непосредственно в коде команды (знаково симметричная)
count6,7Непосредственная константа (номер бита)
m2Условный модификатор (условие порождения предикатов)
sf2Управляющее слово для команд с плавающей точкой
pos6Номер бита 0..63
nt,s2,1Параметры кэширования
01,2,7Не используется или зарезервировано (должны быть нули)

Следующий список показывает типичное предназначение форматов односложных команд:

  1. IMBIN: Бинарная операция для регистра общего назначения и 16-битовой константы со знаком.
    opcode qp dst src simm16
  2. IMBINU: Бинарная операция для регистра общего назначения и 16-битовой константы без знака.
    opcode qp dst src uimm16
  3. GMEM: Загрузка/запись регистра общего назначения, базовая с 16-битовым смещением адресация, любое выравнивание.
    opcode qp dst/src base disp16
  4. FMEM: Загрузка/запись вещественного регистра, базовая с 16-битовым смещением адресация, любое выравнивание.
    opcode qp dst/src base disp16
  5. GMEMW: Загрузка/запись 4-байтовых целых чисел, базовая с 16-разрядным смещением адресация, 4-байтовое выравнивание.
    opcode qp dst/src base opx disp14
  6. FMEMW: Загрузка/запись 4-байтовых вещественных чисел, базовая с 16-разрядным смещением адресация, 4-байтовое выравнивание.
    opcode qp dst/src base opx disp14
  7. GMEMD: Загрузка/запись 8-байтовых целых чисел, базовая с 16-разрядным смещением адресация, 8-байтовое выравнивание.
    opcode qp dst/src base opx disp13
  8. FMEMD: Загрузка/запись 8-байтовых вещественных чисел, базовая с 16-разрядным смещением адресация, 8-байтовое выравнивание.
    opcode qp dst/src base opx disp13
  9. GMEMQ: Загрузка/запись пары регистров общего назначения, базовая с 16-разрядным смещением адресация, 16-байтовое выравнивание.
    opcode qp dst/src base opx disp12
  10. FMEMQ: Загрузка/запись полного вещественного регистра, базовая с 16-разрядным смещением адресация, 16-байтовое выравнивание.
    opcode qp dst/src base opx disp12
  11. BRC: Условный переход по сравнению регистров общего назначения (возможно с инкрементацией или декрементацией первого регистра для циклов).
    opcode qp src src opx label12
  12. BBIT: Условный переход по значению бита в регистре общего назначения.
    opcode qp src shift 0 opx label12
  13. BRCI: Условный переход по сравнению регистра общего назначения и 7-битовой константы со знаком (возможно с инкрементацией или декрементацией первого регистра для циклов).
    opcode qp src simm opx label12
  14. BRCIU: Условный переход по сравнению регистра общего назначения и 7-битовой константы без знака (возможно с инкрементацией или декрементацией первого регистра для циклов).
    opcode qp src uimm opx label12
  15. EXTR: Фиксированные сдвиг, вращение, депозит.
    opcode qp dst src shift opx count
  16. SHPAIR: Варьируемые сдвиг, вращение, депозит.
    opcode qp dst src src opx count
  17. SHADD: Сложение/вычитание со сдвигом.
    opcode qp dst src src scale opx
  18. GMEMX: Загрузка/запись регистров общего назначения, базовая с индексированием адресация (с масштабированием или без).
    opcode qp dst/src base index disp opx
  19. FMEMX: Загрузка/запись вещественных регистров, базовая с индексированием адресация (с масштабированием или без).
    opcode qp dst/src base index disp opx
  20. GMEMU: Загрузка/запись регистров общего назначения, используя базу и смещение с модификацией базы.
    opcode qp dst/src base disp stride opx
  21. FMEMU: Загрузка/запись вещественных регистров, используя базу и смещение с модификацией базы.
    opcode qp dst/src base disp stride opx
  22. GBIN: Бинарная команда для двух регистров общего назначения.
    opcode qp dst src src opx 0
  23. MSPR: Чтение/запись специальных регистров.
    opcode qp dst/src src/dst 0 opx 0
  24. SYS_B: Возврат из процедуры или привилегированная команда с одним аргументом.
    opcode qp 0 src 0 opx 0
  25. SYS_BC: Векторный переход или привилегированная команда с двумя аргументами.
    opcode qp 0 src src opx 0
  26. NOP: Команда-пустышка NOP, неизвестная команда или команда PAL (специфичная для определённая реализации, формат зависит от реализации).
    opcode qp 0 opx 0
  27. BREAK: Прерывание, вызов PAL.
    opcode qp src trap index opx 0
  28. UNOP: Унарная команда для регистров общего назначения, связный переход по абсолютному адресу.
    opcode qp dst src 0 opx 0
  29. UMASK: Унарная команда для регистров общего назначения (дополнительный битовый параметр).
    opcode qp dst src count 0 opx 0
  30. BPA: Объявленный динамический переход по абсолютному адресу.
    opcode qp delay src 0 opx 0
  31. BPR: Объявленный статический переход относительно счётчика команд.
    opcode qp delay label23
  32. LDI: Загрузка константы или смещения относительно счётчика команд, вызов процедуры.
    opcode qp dst simm23/label23
  33. CTIPR: Управление кэшем (адресация относительно счётчика команд)
    opcode qp opx nt s label23
  34. CTBD: Управление кэшем (база+смещение)
    opcode qp opx nt s base simm16
  35. CTBX: Управление кэшем (индексированная с масштабированием адресация)
    opcode qp opx nt s base index scale disp
  36. CMPI: Сравнение регистра общего назначения с 16-битовой непосредственной константой со знаком.
    opcode qp pair m src simm16
  37. CMPUI: Сравнение регистра общего назначения с 16-битовой непосредственной константой без знака.
    opcode qp pair m src uimm16
  38. CARRY: Вычисления с битами переноса/займа.
    opcode qp pair m dst src src x
  39. CMP: Сравнение регистров общего назначения.
    opcode qp pair m src src opx 0
  40. TBIT: Проверка бита регистра общего назначения или порождение предикативной маски.
    opcode qp pair m src shift 0 opx 0
  41. PRED: Бинарные команды для предикатов.
    opcode qp pair m src 0 src 0 opx 0
  42. FCMP: Порождение группы предикатов по паре вещественных регистров (сравнение).
    opcode qp pair m src src opx 0
  43. FTEST: Порождение группы предикатов по вещественному регистру (классификация).
    opcode qp pair m src count opx 0
  44. FSEL: Побитовый выбор для вещественных регистров.
    opcode qp dst src src src x
  45. FDEP: Команды слияния для вещественных регистров (депозит, парный сдвиг).
    opcode qp dst src count src x
  46. FMAC: Команда с перекрытием «умножить-сложить» для вещественных регистров.
    opcode qp dst src src src sf
  47. FBIN: Бинарная команда для вещественных регистров.
    opcode qp dst src src opx sf
  48. FUNOP: Унарная команда для вещественных регистров (с возможным фиксированным целочисленным параметром).
    opcode qp dst src count opx sf
  49. FCVTG: Преобразование в целые из вещественных (векторных) регистров.
    opcode qp dst src 0 opx sf
  50. FCVFG: Преобразование из целых в вещественные (векторные) регистры.
    opcode qp dst src 0 opx sf

Форматы IMBIN, CMPI, CMPUI, GMEM, FMEM, GMEMW, FMEMW, GMEMD, FMEMD, GMEMQ, FMEMQ, CTIPR, CTBD, BPR, LDI, BRC, BBIT, BRCI, BRCIU допускают продолжение непосредственного значения в коде команды на следующий слот связки с образованием двухслотовой команды. Значения основных кодов односложных и двухсложных команд этих форматов совпадают.

Следующий список показывает форматы продолжения на вторые слоты для двусложных команд:

  1. Продолжение непосредственного значения для команд с форматом LDI
    imm (64 бита вместо 23)
  2. Продолжение непосредственного значения (дистанции перехода) для команд с форматами LDR, BPR и CTIPR
    imm (60 битов вместо 23) 0
  3. Продолжение непосредственного значения для команд с форматами IMBIN, CMPI, CMPUI, GMEM, FMEM, CTBD
    imm (57 бит вместо 16)
  4. Продолжение непосредственного значения для команд с форматами GMEMW, FMEMW
    imm (55 бита вместо 14)
  5. Продолжение непосредственного значения для команд с форматами GMEMD, FMEMD
    imm (54 бита вместо 13)
  6. Продолжение непосредственного значения для команд с форматами GMEMQ, FMEMQ
    imm (53 бита вместо 12)
  7. Продолжение непосредственного значения и дистанции перехода для команд типа сравнить и перейти с форматами BRC, BBIT
    label (28 бит вместо 12) не используется (0)
  8. Продолжение непосредственного значения и дистанции перехода для команд типа сравнить с константой и перейти с форматами BRCI, BRCIU
    label (28 бит вместо 12) imm (32 бита вместо 7)

Способы адресации кода

Вычисление эффективных адресов кода происходит по модулю 264 с последующим усечением.

Абсолютная адресация кода отсутствует. Архитектура не дает возможности помещать в код команд абсолютные статические адреса переходов. Доступен только PIC (position independent code) – позиционно-независимый код. Целевые адреса (для кода и констант) могут вычисляться только относительно адреса текущей связки команд или (для приватных данных) относительно базовых регистров.

Архитектура содержит четыре способа относительной адресации кода: длинное безусловное смещение – для безусловного перехода; короткое условное смещение – для условного перехода; delay – смещение вперед для предсказания места будущего перехода; последовательная выборка команд – значение 16 добавляется к адресу текущей связки команд, чтобы сформировать 64-разрядный целевой адрес следующей связки команд.

Длинное безусловное смещение занимает в командном слоте 23 бита и позволяет закодировать переход максимум на 64 мегабайта в обе стороны от текущего адреса. Если использовать двухслотовую команду, то можно закодировать переход в любое место 64-битового адресного пространства.

IP = IP + 16 × SEXT(DISP23)

Длинное безусловное смещение в инструкции
opcode qp прочее относительный адрес
продолжение (60 битов вместо 23) 0

Короткое условное смещение занимает в командном слоте 12 бит и позволяет закодировать переход максимум на 32 килобайта в обе стороны от текущего адреса. Если использовать двухслотовую команду, то смещение занимает 28 бит, и можно закодировать переход на 2 гигабайта в обе стороны. Условие перехода кодируется прочими частями команды.

IP = IP + 16 × SEXT(DISP12)

Короткое условное смещение в инструкции
opcode qp прочее относительный адрес
продолжение (28 бит вместо 12) прочее

Смещение delay указывает строго вперед максимум на 127 связок на место будущего перехода. Используется для упреждающего вычисления места будущего перехода (и - прочими частями команды - целевого адреса перехода).

EA = IP + 16 × ZEXT(DELAY)

Предсказание места будущего перехода
opcode qp delay прочее
прочее

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

Способы адресации данных

Абсолютная адресация данных отсутствует. Архитектура не дает возможности помещать в код команд абсолютные статические адреса переменных. Доступен только BIC (binding independent code) – код, независящий от привязки к месту расположения приватных данных или кода. Целевые адреса для неизменяемых данных могут вычисляться только относительно адреса текущей связки команд, а для приватных данных – только относительно зарезервированных базовых регистров.

Архитектура содержит четыре способа адресации данных: базовый со смещением (base plus displacement addressing mode) – далее просто базовая адресация; базовый с индексацией (base plus index addressing mode) – далее просто индексированная адресация; базовый с масштабируемой индексацией (base plus scaled index addressing mode) – далее просто масштабированная индексированная адресация; базовый со смещением и продвижением базы (base plus displacement with update addressing mode) – далее просто базовая адресация c продвижением базы.

Для базовой со смещением адресации поле смещения disp (16 разрядов или 57 разрядов для двойной команды) после знакового расширения складывается с содержимым базового регистра, чтобы произвести 64-разрядный целевой адрес.

EA = BASE + SEXT(DISP)

Базовая со смещением адресация
opcode qp dst/src base disp16
opcode qp dst/src base disp16

Базовая со смещением адресация далее оптимизируется для адресации объектов размером 2, 4, 8, 16 байт. Архитектура требует, чтобы любой целевой адрес объекта был выровнен по естественной для этого типа объектов границе (naturally aligned). Программная поддержка этого принципа обычно более строга и требует, чтобы любой базовый адрес был выровнен по естественной для этого типа объектов границе. При выполнении этого условия программе достаточно использовать смещения, кратные размеру нужного типа объектов, чтобы гарантировать выравнивание эффективных адресов. Соответственно, не все возможные смещения реально используются в программах при кодировании инструкций.

Для загрузки объектов длиной 8 байт, смещение disp длиной 16 бит всегда будет содержать 3 младших нулевых бита, а для загрузки векторов длиной 16 байт – 4 младших нулевых бита. Младшие биты можно использовать для хранения расширенного кода команды или модификаторов, а при вычислении целевого адреса смещение предварительно умножать (с помощью левого сдвига) на величину объекта.

EA = BASE + SEXT(DISP) × SIZE_OF_TYPE

Несмотря на сокращение длины непосредственного значения disp в коде машинной инструкции (от 16 до 12 бит для разных типов данных), все команды загрузки/записи этого типа позволяют адресовать ±32 килобайта в обе стороны от базового адреса. В ассемблере ограничены только возможные значения смещений.

Базовая со смещением адресация (разные типы)
opcode qp dst/src base x disp15
opcode qp dst/src base opx disp14
opcode qp dst/src base opx disp13
opcode qp dst/src base opx disp12
opcode qp dst/src base opx disp14
opcode qp dst/src base opx disp13
opcode qp dst/src base opx disp12

Для индексированной адресации содержимое индексного регистра index складывается со смещением disp, которое путем сдвига умножается на величину базового типа, а также складывается с содержимым базового регистра base, чтобы произвести 64-разрядный целевой адрес.

EA = BASE + INDEX + SEXT(DISP) × SIZE_OF_TYPE

Для индексированной адресации с масштабированием содержимое индексного регистра index после сложения со смещением disp путем сдвига умножается на величину базового типа и складывается с содержимым базового регистра base, чтобы произвести 64-разрядный целевой адрес.

EA = BASE + (INDEX + SEXT(DISP)) × SIZE_OF_TYPE

Индексированная (с масштабированием) адресация
opcode qp dst/src base index disp opx
opcode qp dst/src base index disp opx

Индексированную адресацию можно использовать для организации относительной адресации (например GP+GOT_variable). Индексированную адресацию с масштабированием можно использовать для обращения к массивам элементов базовых типов, для которых доступны варианты m[i], m[i+1], m[i-1].

Для базовой адресации c продвижением базы поле смещения disp (5 битов) после знакового расширения путем сдвига умножается на величину базового типа и затем складывается с содержимым базового регистра, чтобы произвести 64-разрядный целевой адрес. Поле stride (5 битов) задает продвижение базового адреса после вычисления целевого адреса (целое число не равное нулю).

EA = BASE + SEXT(DISP) × SIZE_OF_TYPE

BASE = BASE + SEXT(STRIDE) × SIZE_OF_TYPE

Базовая адресация c продвижением базы
opcode qp dst/src base disp stride opx
opcode qp dst/src base disp stride opx

Базовую адресацию c продвижением базы можно использовать для: программной реализации стека; пост- или пре-инкрементной адресации; пост- или пре-декрементной адресации; более сложных случаев возможного перекрытия команд сложения/вычитания и обращения в память в циклах с монотонным просмотром массивов.

Остальные способы адресации могут быть реализованы через четыре вышеперечисленных. Абсолютная адресация данных может быть реализована путем использования в качестве базы регистра g0, всегда равного нулю.

Адресация относительно счетчика команд может быть реализована путем предварительного помещения правильного базового адреса в один из свободных регистров. Специальная команда LDR (Load Relative Address) облегчает такую подготовку.

(qp)	ldr	base, text_hi(ip_relative_offset)
(qp)	ldd	dst, base, text_lo(ip_relative_offset)

Здесь ip_relative_offset – метка загружаемого объекта в сегменте неизменяемых данных, text_hi – встроенная функция ассемблера для вычисления относительного адреса связки команд (или выровненной 16-байтовой порции данных), text_lo – встроенная функция ассемблера для вычисления смещения внутри связки (порции). С помощью LDR можно адресовать 64 мегабайта в обе стороны от текущей позиции (или все адресное пространство, если использовать двухслотовый вариант LDR):

(qp)	ldr.l	base, text_hi(ip_relative_offset)
(qp)	ldd	dst, base, text_lo(ip_relative_offset)

Адресация приватных данных может быть реализована путем предварительного помещения правильного базового адреса в один из свободных регистров. Один регистр общего назначения gp (global pointer) зарезервирован для указания на начало приватных данных процесса в глобальном адресном пространстве. Специальная команда ADDIS (Add Immediate Shifted) позволяет вычислить ближайший базовый адрес, указывающий на середину страницы, содержащей искомый объект.

(qp)	addis	base, gp, data_hi(gp_relative_offset)
(qp)	ldd	dst, base, data_lo(gp_relative_offset)

Здесь gp_relative_offset – метка объекта в сегменте данных, data_hi – встроенная функция ассемблера для вычисления старшей части относительного смещения (относительно gp) до середины страницы данных, где расположена метка, data_lo – встроенная функция ассемблера для вычисления смещения метки относительно середины страницы. С помощью ADDIS можно адресовать 2 гигабайта приватных данных (или все адресное пространство, если использовать двухслотовый вариант ADDIS).

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

(qp)	ldd.l	dst, gp, gp_relative_offset

Для команд допускающих продолжение на второй слот, ассемблер сам определяет необходимость расширения команды на два слота по величине непосредственного значения (константы) в коде инструкции. Ассемблер также сам добавляет в код команды-пустышки NOP, если длинная инструкция не помещается в оставшуюся часть связки и нужно начинать новую связку.

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

Условные регистры и действия над предикатами

Регистровый файл из 64 однобитовых предикатов предназначен для хранения логических значений 1 или 0. Их невозможно сохранять в памяти по отдельности, но можно сохранить весь файл условных регистров, сохранив специальный регистр CRF (conditional register file). Предикат c0 всегда равен 1, запись в него игнорируется.

Любая команда содержит квалифицирующий предикат qp, управляющий её условным выполнением.

Расположение квалифицирующего предиката
opcode qp прочее

Команды для порождения предикатов всегда используют предикаты попарно. Существует 32 пары из четного и нечетного предикатов: c0 и c1, c2 и c3, и так далее до c62 и c63. Если в команде задан предикат с номером pair для записи результата, то в pair будет занесен результат тестирования, а в парный ему предикат с номером pair^1 (XOR – exclusive or) будет занесен противоположный результат.

Команды для порождения предикатов содержат в качестве параметра модификатор m, указывающий способ объединения квалифицирующего предиката qp и результата тестирования pair. Режим COND предназначен для условного простого порождения пар предикатов – если квалифицирующий предикат ложен, то результатов нет – команда отвергается как истинный NOP, а иначе порождается пара предикатов. Режим UNC специфичен тем, что сначала оба предиката из пары pair устанавливаются в ноль независимо от значения квалифицирующего предиката (команда под ложным предикатом не является истинным NOP-ом). Режим UNC предназначен для первичного (безусловного) порождения пар предикатов (возможно под контролем предиката более высокого уровня).

Расположение результирующего предиката и модификатора
opcode qp pair m прочее
if (qp is TRUE) then
begin
  value = TEST_RESULT(parameters)
  PR[pair]A = value
  PR[pair^1] = NOT value
end
else if(m is UNC) then
begin
  PR[pair] = FALSE
  PR[pair^1] = FALSE
end
endif

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

Выполняемый под предикатом блок может содержать вызов функции, если согласно правилам ABI вызванная функция сохраняет содержимое файла предикатов.

Схематические примеры использования предикации
Условный операторПредикация
if (c1) {  x1; }
else {  x2; }
(p0) p2,p3 = c1
(p2) x1
(p3) x2
if(c1) {
  x1;
  if(c2) x2; 
 else x3;
 x4;
} else {
  x5;
  if(c3) x6;
  else x7;
  x8;
}
(p0) p2,p3 = c1
(p2) x1
(p2) p4,p5 = c2
(p4) x2
(p5) x3
(p2) x4
(p3) x5
(p3) p6,p7 = c3
(p6) x6
(p7) x7
(p3) x8
if(c1) { x1;
} else if(c2) {  x2;
} else if(c3) {  x3;
} else {  x4;
}
(p0) p2,p3 = c1
(p3) p4,p5 = c2
(p5) p6,p7 = c3
(p2) x1
(p4) x2
(p6) x3
(p7) x4
if (c1 && c2) {  x1; }
else {  x2; }
(p0) p2,p3 = c1
(p2) p2,p3 = c2
(p2) x1
(p3) x2
if(c1 || c2) {  x1;
} else {  x2;
}
(p0) p2,p3 = c1
(p3) p2,p3 = c2
(p2) x1
(p3) x2
if(c1 || (c2 && c3)) {
  x1;
} else {
  x2;
}
(p0) p2,p3 = c1
(p3) p4,p5 = c2(unc)
(p4) p2,p3 = c3
(p2) x1
(p3) x2
if(c1 && (c2 || c3)) {
  x1;
} else {
  x2;
}
(p0) p2,p3 = c1
(p2) p4,p5 = c2
(p5) cond(!c3)
(p2) (p2,p3) and (p4,p5)
(p2) x1
(p3) x2

Специальные регистры

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

Прямой доступ к специальным регистрам можно получить с помощью команд MFSPR (move from special-purpose register) и MTSPR (move to special-purpose register). Можно скопировать специальный регистр в регистр общего назначения (MFSPR), произвести необходимые операции, а затем поместить новое значение в специальный регистр (MTSPR).

Не все специальные регистры доступны для прямого доступа, большинство доступны только для привилегированного ПО (на системном уровне).

Специальные регистры
Группа Регистр Описание
Доступны пользователю для прямого чтения и записи CRFConditional Registers File
CASCVCompare-and-Swap Compare Value
FPSRFloating-point Status Register
Доступен только косвенно IPInstruction Pointer
Доступны пользователю только для чтения (ITC доступен с регулируемой точностью (поле PSR.ITM) так как маскИруется для сокрытия точности) ITCInterval Time Counter
KR0Kernel Registers
KR1
KR2
KR3
KR4
KR5
KR6
KR7
Доступны для чтения и записи только на системном уровне привилегий PSRProcessor Status Register
ITCVInterval Time Compare Value
PTAPage Table Address
IVAInterruption Vector Address
Описатели контекста прерывания, теневые копии регистров общего назначения (доступны только в обработчике прерывания и на системном уровне) IIPInterruption Instruction Pointer
IPSRInterruption Processor Status Register
ISRInterruption Status Register
IFAInterruption Faulting Address
IFRInterruption Faulting Region
IIMInterruption Immediate
IHAInterruption Hash Address
SHR0Shadow Registers
SHR1
SHR2
SHR3
SHR4
SHR5
SHR6
SHR7
Работа с внешними асинхронными прерываниями (в обработчике прерываний) IVRInterrupt Vector Register
TPRTask Priority Register
EOIEnd of External Interrupt Register
IRR0External Interrupt Request Registers
IRR1
IRR2
IRR3
Управление асинхронными прерываниями от самого процессора ITVInterval Timer Vector
PMVPerformance Monitoring Vector
CMCVCorrected Machine Check Vector

Специальный регистр Processor Status Register (PSR) управляет поведением текущего потока инструкций. Доступен для записи только на самом привилегированном уровне, его изменение требует явной сериализации.

Формат регистра PSR
rv itm cpl ib ic df dp ip dt it rv ss tb lp dd id rv tgsize pm be
Поля регистра PSR
Группа Поле Бит Описание
Разное be1Big-Endian. Если 1, то обращения к памяти big-endian, если 0, то little-endian. Выборка инструкций всегда little-endian, независимо от бита PSR.BE. Этот бит имеет смысл только при физической адресации данных. При виртуальной адресации endianess – индивидуальное свойство каждой виртуальной страницы данных.
pm1 User Performance monitor enable. Если 1, монитор производительности включен и ведет подсчет событий. Если 0, монитор производительности отключен.
tgsize3Text Granula Size. Размер гранулы текста для команды LDMBA. Определяется как 216+tgsize (от 64 КБ при tgsize=0 до 8 МБ при tgsize=7). Должен быть одинаков для всех потоков и процессов в системе, если мы желаем корректно разделять код и неизменные данные динамических библиотек.
itm6Interval Time Mask – число скрываемых от пользователя младших бит в регистре ITC. Задаёт 64-битовую маску для защиты точного значения счетчика интервалов времени ITC. Чтение из регистра ITC возвращает не точное значение ITC, а результат побитовой операции AND с маской из ITM нулей в младших битах. Скрытие от пользователя точного числа прошедших тактов защищает алгоритмы шифрования/безопасности от взлома на основе анализа потактового времени исполнения. ОС может разрешить знание точного числа тактов, поместив в ITM число 0.
Отладчик id1 Instruction Debug Breakpoint fault. Если 1, instruction address breakpoints разрешены и могут породить ошибку Instruction Debug. Иначе, ошибки и ловушки на address breakpoint запрещены.
dd1 Data Debug Breakpoint fault. Если 1, data address breakpoints разрешены и могут породить ошибку Data Debug. Иначе, ошибки и ловушки на address breakpoint запрещены.
lp1 Lower Privilege transfer trap. Если 1, ловушка Lower Privilege Transfer происходит когда произошедший переход уменьшает уровень привилегий (число CPL увеличивается).
tb1 Taken Branch trap. Если 1, то любой произошедший переход вызывает отладочную ловушку Taken Branch. Прерывание и возврат из него не вызывают эту ловушку.
ss1 Single Step enable. Если 1, то отладочная ловушка Single Step происходит после успешного выполнения каждой инструкции.
Трансляция и защитаdt1 Data address Translation. Если 1, разрешает трансляцию и проверку доступа виртуальных адресов для данных. иначе для данных используется физическая адресация.
it1 Instruction address Translation. Если 1, разрешает трансляцию и проверку доступа виртуальных адресов для инструкций. иначе для инструкций используется физическая адресация.
ip1 Instruction Protection Key enable. Если 1, выборки инструкций проверяются на ключи защиты.
dp1 Data Protection Key enable. Если 1, обращения к данным проверяются на ключи защиты.
Прерывания ib1Interruption Bit. Если 1, немаскированые отложенные внешние прерывания могут прервать процессор и передать управление на обработчик внешних прерываний. Если 0, отложенные внешние прерывания не могут прервать процессор.
ic1Interruption Collection. Уровень прерывания.
df1Disabled Floating-point register set. Если 1, любое обращение к регистрам f0...f127 приводит к ошибке Disabled Floating-Point Register, все FP инструкции порождают эту ошибку (даже если и не используют регистры f0...f127).
cpl2 Current Privilege Level – текущий уровень привилегий исполняемого потока. Контролирует доступность системных регистров, инструкций и страниц виртуальной памяти. Значение 0 наиболее привилегированное, а значение 3 наименее. Изменяется командами rfi, syscall, break.

Conditional Registers File (CRF) – специальный регистр, который при чтении из него возвращает копию файла однобитовых условных регистров (предикатов), а при записи в него обновляет содержимое условных регистров c1c63. Поскольку предикат c0 всегда истинен, то нулевой бит регистра CRF всегда равен единице, запись в него игнорируется.

Формат регистра CRF
conditional registers c1…c63 1

Floating-point Status Register (FPSR) – специальный регистр для управления работой устройства с плавающей точкой FPU.

Compare-and-Swap Compare Value (CASCV). Специальный регистр длиной 64 бита для поддержки атомарной операции типа сравнение-и-обмен (compare-and-swap), которая обеспечивает неблокируемое мультипроцессорное взаимодействие. CASCV хранит сравниваемое значение. Используется инструкциями CASD и CASDD. В случае атомарной операции CASDD типа двойное (парное) сравнение-и-обмен (double-width compare-and-swap), CASCV сравнивается с первым значением из пары (это должен быть update-tag).

Instruction Pointer (IP) – специальный регистр, который хранит адрес связки выполняемой в данный момент инструкции. Регистр IP нельзя прочитать непосредственно, но можно получить адрес относительно IP (в том числе и с нулевым смещением) с помощью инструкции LDR. Регистр IP нельзя изменить непосредственно (командой MTSPR), но он автоматически увеличивается в конце выполнения связки, а также получает новое значение в результате выполнения команд перехода. Также IP – неявно подразумеваемый операнд при статическом переходе. Поскольку формат инструкций регулярен, то есть связки команд имеют фиксированную длину 16 байт и выровнены по 16-байтовой границе, то младшие 4 бита регистра IP всегда равны нулю, запись в них игнорируется.

Формат регистра IP
bundle address 0

Interval Time Counter (ITC) – счетчик интервалов времени, 64-битовое число без знака для измерения интервалов времени и синхронизации в интервалах порядка наносекунд. Прирост ITC основан на фиксированном отношении с частотой процессора. ITC увеличивается на единицу раз в N циклов, где N – определенное реализацией целое число в диапазоне 1…32. Приложения могут непосредственно читать ITC для основанных на времени вычислений и замеров производительности. ITC может быть записан только на самом привилегированном уровне. ОС должна гарантировать, что прерывание от системного таймера произойдет прежде, чем ITC переполнится. Для ITC архитектурно не гарантируется синхронизизация ни со счетчиками интервалов времени любых других процессоров в мультипроцессорной системе, ни с системными часами. Программное обеспечение должно калибровать ITC по действительному календарному времени и периодически поправлять возможный дрейф.

Interval Timer Compare Value (ITCV). Когда значение в ITC равно значению в ITCV происходит прерывание Interval Timer. Как только прерывание находится процессором и обслуживается программным обеспечением, ITC может не быть обязательно равен ITCV. ITCV доступен только на самом привилегированном уровне.

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

Специальные регистры KR0-KR7 (kernel registers) предназначены для хранения системной информации связанной с текущим процессом (потоком). Доступны пользователю только для чтения. Что именно в них хранить – на усмотрение ОС.

Специальный регистр PTA (Page Table Address) предназначен для управления аппаратными средствами PTW (Page Table Walker) поиска трансляций в памяти.

Специальные регистры IIP, IPSR, SHR0-SHR7, предназначены для сохранения части контекста (состояния) процессора при прерывании.

Специальные регистры IVA, ISR, IFA, IFR, IIM, IHA, предназначены для управления таблицей прерываний (IVA), а также распознания и обработки прерываний.

Специальные регистры IVR, TPR, EOI, IRR0-IRR3, ITV, PMV, CMCV предназначены для управления внешними прерываниями.