Типы архитектур набора инструкций

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

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

Есть также машины с нулевым операндом — это стековые машины, и есть машины с одним операндом — это машины-аккумуляторы.

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

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

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

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

Другие инструкции целенаправленно увеличивают счетчик программ (несколько за пределы значения по умолчанию для следующей инструкции) — это делается для того, чтобы пропустить (опустить) определенные инструкции в программе. Это делается в конструкции if-then, где мы не хотим выполнять часть then при определенных условиях, поэтому пропускаем ее. Это также делается для if-then-else, например, как всякий раз, когда мы выполняем часть then: мы также хотим пропустить часть else.

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

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

Это называется адресацией относительно ПК, когда она используется для доступа «код-данные» или «код-код» с использованием дельты от текущей инструкции до цели.

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

Аккумуляторная машина

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

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

Аккумулятор является как неявным (т.е. неуказанным) источником, так и неявной целью в большинстве инструкций — аккумулятор не указан в языке ассемблера или машинном коде.

На аккумуляторной машине, a = b + c выглядит примерно так:

ИнструкцияКомментарии
load bнеявно нацеливает аккумулятор на результат загрузки
add cнеявные источники, а затем нацелены на аккумулятор
store aнеявно источник аккумулятора для хранения значения

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

Стек машины

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

У них есть (1) инструкции с одним операндом, которые обмениваются данными между памятью и стеком выражений: это формы push а также pop. И (2) инструкции с нулевым операндом для арифметики, вычислений, индексации и т. д., которые потребляют свои источники из стека и возвращают свои вычисления обратно в стек. Вычислительные инструкции неявным образом являются источником и целевым объектом для стека, поэтому стек не упоминается ни в языке ассемблера, ни в машинном коде.

На стековой машине a = b + c выглядит примерно так:

ИнструкцияКомментарии
push bнеявно нацеливает аккумулятор на результат загрузки
push cтакой же
addнеявно создает и нацеливает стек
pop aнеявно создает стек для хранения значения

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

Стек обычно также упрощает вызов процедур.

Однако из-за постоянно меняющейся вершины стека стековые машины труднее сделать аппаратно быстрыми.

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

Зарегистрировать машину

Регистровые машины имеют несколько регистров. Они могут варьироваться от 8 до 64 регистров. Сегодня популярны 16 и 32 (x64/Arm32 и AArch64/MIPS/RISC V соответственно).

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

68000 подразделяет свои 16 32-битных регистров на 8 «адресных» регистров и 8 регистров «данных», которые имеют некоторые перекрывающиеся функции, но каждый набор также имеет некоторые функции, которые не может использовать другая половина. , но только регистры данных поддерживали умножение и логические операции, такие как И и ИЛИ, в то время как только регистры адреса поддерживали адресацию памяти (режимы).

Даже более ранние 6502 и 8008, а также ряд других 8-битных процессоров, которые изначально разрабатывались для самых ранних интегральных схем, имели несколько регистров, также разделенных аналогичным образом, регистры «данных», как правило, были только 8-битными. и тогда как «адрес» регистрируется 16-битным. Снова поддерживаются адресные регистры (16-разрядные) сложения, в то время как регистры данных поддерживают 8-разрядное умножение (если оно вообще присутствует) и (8-разрядные) логические операции, такие как И и ИЛИ.

На регистрационной машине, a = b + c выглядит примерно так:

ИнструкцияКомментарии
добавить r1, r2, r3добавляет r2 держа b а также r3 держа c и магазины в r1 за a

Эта простая форма возможна, когда имеется достаточно регистров ЦП для хранения локальных переменных одновременно с некоторыми временными значениями. Когда регистровой машине не хватает регистров для этого, качество кода страдает, так как для переполнения приходится использовать память.

Регистровая машина обычно использует один из своих регистров для указателя стека. Иногда указатель стека представляет собой произвольно выбранный регистр, поскольку все регистры одинаковы (MIPS/RISC V); однако на других машинах специальное использование указателя стека кодируется иначе, чем для других инструкций (x86/x64, которые изменили push & pop инструкции по работе со стеком, полезные для передачи параметров в памяти и в функции вход/выход, он же пролог/эпилог.)

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

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

Количество операндов: два против трех

Регистровые машины различаются по количеству операндов, что позволяет использовать бинарные операторы, такие как сложение. Некоторые регистровые машины допускают три инструкции операнда, например:
r1 = r2 + r3
тогда как другие только две инструкции операнда — например:
register1 += register2.

В архитектуре набора команд все является компромиссом. Чтобы использовать систему с двумя операндами, часто mov Инструкция (задание) необходима:
r1 = r2; r1 += r3.

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

Загрузка/сохранение архитектур

Некоторые наборы инструкций являются архитектурами загрузки/сохранения (MIPS/RISC V), тогда как другие нет (x86/x64). Архитектура загрузки/сохранения ограничивает операции с памятью этими двумя инструкциями, и это упрощает аппаратное обеспечение, а также уменьшает кодирование, необходимое для режимов адресации.


Эта статья защищена авторским правом (C) 2019, Эрик Л. Эйдт.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *