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

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

1. Используем команду ввод для считывания с клавиатуры первого числа. Но нам еще надо указать ячейку, в которую должно быть записано первое число. Дальше команду ввод повторим, но укажем другой адрес для записи второго числа:

Код операции

Адрес 1

Ввод

А1

Ввод

А2

2. Теперь введем команду сложения +. Складывать будем содержимое ячейки с адресом А1 и ячейки с адресом А2. Результат, полученный в процессоре, необходимо записать в память, например, в ячейку А3:

Код операции

Адрес 1

Адрес 2

Адрес 3

+

А1

А2

А3

3. Далее выведем результат из ячейки А3 командой вывод, указав, например, адрес принтера:

Код операции

Адрес 1

Адрес 2

Адрес 3

Вывод

А3

Принтер

4. Для завершения программы осталось ввести последнюю команду для остановки машины — стоп:

Код операции

Адрес 1

Адрес 2

Адрес 3

стоп

В итоге программа будет иметь вид:

Код операции

Адрес 1

Адрес 2

Адрес 3

Ввод

А1

Ввод

А2

+

А1

А2

А3

Вывод

А3

Принтер

Стоп

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

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

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

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

,

Одноадресные команды обычно по некоторому правилу модифицируют операнд. Сюда можно отнести команды изменения знака, очистки ячейки, инвертирования, прибавления или вычитания 1 и т.п. Команды имеют следующий формат:

КОП

D

где D является операндом или определяет адрес операнда.

Двухадресные команды обрабатывают два операнда и могут иметь, например, такой формат:

,

КОП

S

D

где S — источник, а D — приемник (порядок следования внутри команды S и D в разных семействах машин различный). Операция производится в следующем порядке:

D <операция> S è D,

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

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

Команды пересылки данных

Команды этой группы пересылают данные из одного места компьютера в другое: между регистрами и памятью. Ниже перечислены основные команды этой группы.

Система команд

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

В процессорах 80686 и выше введены команды условной пересылки CMOVcc. Эти команды производят передачу данных только в случае установленного условия (cc), которое задается различными значениями признаков, установленных в регистре флагов. В этом же процессоре появились команды условной установки бит: SETcc — при выполнении заданного условия значение операнда устанавливается равным 1, в противном случае — 0.

BSWAP производит обмен байтов внутри регистра.

PUSH копирует операнд в вершину стека и сдвигает указатель стека вниз.

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

PUSHA, PUSHAD, РОРА, POPAD выполняют запись в стек и извлечение из него восьми регистров общего назначения. При этом последовательно заполняются или освобождаются восемь 16- или 32-разрядных ячеек стека. При этом PUSHA, РОРА оперируют с 16-разрядными регистрами, а PUSHAD POPAD с 32-разрядными.

IN/OUT производят пересылку данных между аккумулятором ЕАХ (АХ, AL) и адресуемым портом. Адрес порта может задаваться непосредственно операндом или содержимым регистра DX.

Команда MOVSX пересылает данные из меньшего (по числу бит) операнда в больший с расширением знакового разряда.

Команда MOVZX — аналогично, без расширения знакового разряда.

XCHG предназначена для обмена содержимым двух регистров или регистра и ячейки памяти.

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

Рассмотрим двухпроцессорную систему. Допустим, в ячейке A находится число 4, в регистре AX первого процессора — число 5 и в регистре AX второго процессора число 2. Оба процессора почти одновременно начали выполнять команду XCHG AX, A. Ее выполнение, с точки зрения шины, состоит из двух операций: чтения из ячейки А и записи в ячейку. Если шина не монополизируется, последовательность операций может быть такой:

Операция

на шине

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

T1

T2

AX1

AX2

A

x

x

5

2

4

T1 ← A

4

x

5

2

4

T2 ← A

4

4

5

2

4

A ← AX1

4

4

5

2

5

A ← AX2

4

4

5

2

2

AX1 ← T1

4

4

4

2

2

AX2 ← T2

4

4

4

4

2

Здесь T1, T2 — программно недоступные промежуточные регистры процессоров.

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