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

В приводимых ниже таблицах указывается мнемоника всех допустимых инструкций для МП 8086/8088. Для удобства пользования все команды разбиты на 6 функциональных групп - пересылки данных, арифметические, битовые, строковые, передачи управления, прерываний. Внутри каждой группы команды объединяются в подгруппы по общим дополнительным признакам.

Детальный анализ всех команд МП 8086/8088 занял бы слишком много места, поэтому в идущих за таблицами пояснениях рассматриваются лишь наиболее популярные команды. Исчерпывающее описание всех команд Вы найдете в [1], [20].

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

Мнемоника

Формат

Пояснение

Команды общего назначения

MOV

MOV приемник, источник

Переслать значение

PUSH

PUSH источник

Поместить в стек

POP

POP приемник

Извлечь из стека

XCHG

XCHG приемник, источник

Обменять значения

XLAT

XLAT таблица

Загрузить в AL байт из таблицы

Команды ввода-вывода

IN

IN аккумулятор, порт

Читать из порта

OUT

OUT порт, аккумулятор

Записать в порт

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

LEA

LEA регистр 16, память 16

Загрузить исполнительный адрес

LDS

LDS регистр 16, память32

Загрузить в DS:регистр16 полный адрес

LES

LES регистр 16, память32

Загрузить в ES:регистр16 полный адрес

Команды пересылки флагов

LAHF

LAHF

Загрузить флаги в АН

SAHF

SAHF

Установить флаги из АН

PUSHF

PUSHF

Поместить флаги в стек

POPF

POPF

Извлечь флаги из стека

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

mov ах,Table {Пересылка слова из памяти в АХ} 

mov Table,ah {Пересылка байта из АН в память}

mov ds,ax {Пересылка в сегмент данных}

mov es:[bx],ax {Пересылка слова в память: базовая адресация с заменой сегмента}

mov ch,-17 {Переслать константу в регистр} 

mov Table,$FF {Переслать константу в память}

С помощью MOV нельзя пересылать: 

mov Mem1,Mem2

следует использовать

mov ax,Mem2 

mov Mem1,ax

mov DS,Data_Seg

нужно:

mov ax,Data_Seg 

mov ds,ax

mov es, ds 

но можно

mov ax,ds 

mov es,ax

Для временного сохранения регистров и данных, а также для обмена значениями между регистрами широко используются стековые команды PUSH и POP. Каждая из них работает со словом, т.е. в стек нельзя поместить или извлечь из него одиночный байт. При выполнении PUSH вначале уменьшается на 2 содержимое указателя SP, а затем операнд помещается по адресу SS: SP. При извлечении из стека сначала читается память по адресу SS: SP, а затем SP увеличивается на 2. Таким образом, при заполнении указатель вершины стека SP смещается к младшим адресам, а при освобождении -к старшим. При работе со стеком следует помнить о специфике использования стековой памяти («последним пришел - первым ушел»), а также о том, что эта память интенсивно используется при вызове процедур, т.е. состояние стека к моменту выхода из процедуры должно быть строго согласовано с дальнейшей работой программы. Первое условие определяет порядок извлечения данных из стека - он должен быть обратным порядку, в котором эти данные помещались в стек. Второе условие фактически означает, что после выхода из процедуры указатель SP должен содержать то же смещение, что и к моменту входа в нее. Иными словами, процедура не должна «забыть» в стеке лишнее слово или взять из него больше нужного.

Команда загрузки адреса LEA загружает в регистр адрес (смещение) нужного участка памяти. Этого же можно достичь с помощью зарезервированного слова OFFSET, стоящего перед именем переменной. Например:

var

X: Word;

..........

asm

mov ax, OFFSET X {Загружаем смещение X в АХ} 

lea ax,X {To же действие} 

end ;

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

Две другие команды адресной загрузки - LDS и LES загружают первое 16-разрядное слово из источника в регистр-приемник, а затем следующее слово - в регистр DS или ES, т.е. они рассчитаны на загрузку полного адреса операнда (сегмента и смещения).

Арифметические команды

Мнемоника

Формат

Комментарий

Команды сложения

ADD

ADD приемник, источник

Сложить

ADC

ADC приемник, источник

Сложить, добавить перенос

ААА

ААА

Скорректировать сложение для таблицы ASCII

DAA

DAA

Скорректировать сложение для двоично-десятичных чисел

INC

INC приемник

Увеличить на единицу

Команды вычитания

SUB

SUB приемник, источник

Вычесть

SBB

SBB приемник, источник

Вычесть с заемом

AAS

AAS

Скорректировать вычитание для таблицы ASCII

DAS

DAS

Скорректировать вычитание для двоично-десятичных чисел

DEC

DEC приемник

Уменьшить на единицу

NEG

NEG приемник

Обратить знак

СМР

СМР приемник, источник

Сравнить

Команды умножения

MUL

MUL источник

Умножить без знака

IMUL

IMUL источник

Умножить со знаком

AАМ

ААМ

Скорректировать умножение для таблицы ASCII

Команды деления

DIV

DIV источник

Делить без знака

IDIV

IDIV источник

Делить со знаком

AAD

AAD

Скорректировать деление для таблицы ASCII

Команды расширения знака

CBW

CBW

Преобразовать байт в слово

CWD

CWD

Преобразовать слово в двойное слово

При использовании арифметических команд следует помнить о том, что МП может обрабатывать знаковые числа, числа без знака, а также двоично-десятичные числа. В беззнаковых числах для представления значения используются все биты. т.е. они эквивалентны типам Byte и Word, в то время как знаковые числа в старшем разряде хранят знак числа и эквивалентны типам Shortlnt и Integer. Двоично-десятичные числа используют по 4 бита для каждого десятичного разряда и могут быть упакованными или неупакованными. В первом случае один байт хранит 2 десятичные цифры (старшая - в старшем полубайте), во втором - только одну (старший полубайт не используется). Основные арифметические команды МП (ADD, SUB, MUL, DIV) не учитывают двоично-десятичную форму представления чисел, поэтому в архитектуру МП включены команды коррекции результата.

Битовые команды

Мнемоника

Формат

Комментарий

Логические команды

AND

AND приемник, источник

Выполнить AND

OR

OR приемник, источник

Выполнить OR

XOR

XOR приемник, источник

Выполнить XOR

NOT

NOT приемник

Выполнить NOT

TEST

TEST приемник, источник

Проверить

Сдвиговые команды

SAL/SHL

SAL приемник, счетчик

Сдвинуть влево

SAR/SHR

SAR приемник, счетчик

Сдвинуть вправо

ROL

ROL приемник, счетчик

Сдвинуть влево циклически

ROR

ROR приемник, счетчик

Сдвинуть вправо циклически

RCL

RCL приемник, счетчик

Сдвинуть влево с переносом

RCR

RCR приемник, счетчик

Сдвинуть вправо с переносом

Битовые команды используются при исчислении логических выражений, а также в тех случаях, когда необходимо изменить отдельные разряды операнда. Логические команды AND, OR, XOR и NOT эквивалентны соответствующим операциям Турбо Паскаля в случае, когда операндами являются целочисленные выражения. Команда TEST выполняет целочисленную операцию поразрядного суммирования AND, но не изменяет значения операндов, а лишь устанавливает флаги в соответствии со значением результата сравнения: обнуляет CF и OF, изменяет PF, ZF, SF и не меняетAF (флаг ZF установится в 1 в том случае, когда оба операнда содержат по единице хотя бы в одном соответствующем разряде). Команды сдвига SHL/SHR эквивалентны одноименным операциям Турбо Паскаля и отличаются от команд циклического сдвига ROLIROR тем, что вытесненные в ходе их выполнения значащие разряды теряются, в то время как при циклическом сдвиге эти разряды появляются «с другой стороны». Например, если выполнить фрагмент

mov al,1 {Загружаем в AL единицу}

shr al,1 {Сдвигаем вправо ,на 1 разряд}

регистр AL будет содержать 0 (вытесненная вправо единица будет помещена в CF), в то время как после замены команды SHR на ROR в нем будет значение $80=128 (вытесненная единица будет помещена в старший бит регистра).

Заметим, что счетчиком в командах сдвига может быть цифра 1 или количество сдвигов, указываемое в регистре CL.

Команды передачи управления

Мнемоника

Формат

Комментарий

Безусловные переходы

CALL

CALL имя

Войти в процедуру

RET

RET [количество параметров]

Вернуться из процедуры

JUMP

JUMP имя

Перейти

Условные переходы

JA/JNBE

JA близкая_метка

Перейти, если выше (после сравнения

беззнаковых операндов)

JAE/JNB

JAE близкая_метка

Перейти, если выше или равно

JB/JBAE/JC

JB близкая_метка

Перейти, если ниже

JBE/JNA

JBE близкая_метка

Перейти, если ниже или равно

JCXZ

JCXZ близкая_метка

Перейти, если СХ=0

JE/JZ

JE близкая_метка

Перейти, если равно

JG/JNLE

JG близкая_метка

Перейти, если больше (после сравнения

знаковых операндов)

JGE/JNL

LGE близкая_метка

Перейти, если больше или равно

JL/JNGE

JL близкая_метка

Перейти, если меньше

JLE/JNG

JLE близкая_метка

Перейти, если меньше или равно

JNC

JNC близкая_метка

Перейти, если нет переноса

JNE/JNZ

JNE близкая_метка

Перейти, если не равно

JNO

JNO близкая_метка

Перейти, если нет переполнения

JNP/ JPO

JNP близкая_метка

Перейти, если нечетный

JO

JO близкая_метка

Перейти, если перенос

JP/JPE

JP близкая_метка

Перейти, если четный

JS

JS близкая_метка

Перейти, если отрицательный

Команды управления циклами

LOOP

LOOP близкая_метка

Повторить цикл

LOOPE/LOOPZ

LOOPE близкая_метка

Повторять, пока равны

LOOPNE/LOOPNZ

LOOPNE близкая_метка

Повторять, пока не равны

Команды безусловных переходов CALL, RET, JMP могут использовать дальнюю или ближнюю модель памяти, в то время как команды условных переходов - только малую (в пределах -128...+127 байтов). При дальней модели памяти (устанавливается опцией Options/Compiler/Force far calls среды Турбо Паскаля или директивой компилятора {F+}) осуществляется как внутрисегментная, так и межсегментная передача управления, при ближней - только внутрисегментная.

Инструкция CALL работает следующим образом. Вначале адрес следующей за CALL инструкции (адрес возврата) помещается в стек, затем в регистр IP (или в пару CS:IP) помещается адрес точки входа в процедуру, таким образом сразу за командой CALL будет исполняться уже первая команда процедуры. Оба адреса (точки входа и возврата) будут 16-битовыми смещениями для внутрисегментного вызова или 32-битовыми полными адресами - для межсегментного. Все процедуры (функции) Паскаля, оттранслированные в режиме {F+} или содержащие зарезервированное слово FAR в заголовке, должны вызываться как дальние. Для этого за инструкцией CALL следует указать модель памяти:

Procedure MyProc; Far;

.......

asm

call FAR MyProc {Вызов дальней процедуры}

.......

end;

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

При выходе из дальней процедуры команда RET извлекает из стека оба 16-разрядных слова и помещает первое в IP, а второе в CS, а при выходе из ближней извлекает из стека только смещение и помещает его в IP.

Команды условных переходов способны передавать управление на метку, расположенную в пределах ближайших плюс-минус 128 байт от самой команды. Если нужно передать управление на метку, расположенную дальше в том же сегменте, или на метку в другом сегменте, сразу за командой условной передачи располагают безусловную команду JMP или CAL, например:

стр ах,0 {Проверяем АХ} 

jne@NotZero {AX=0 ?} 

jmp IsZero {Да - переходим на дальнюю метку}

....... {Нет - продолжаем работу}

.......

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

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

Условие

Для беззнаковых чисел

Для чисел со знаками

Приемник больше источника

JA

JG

Приемник и источник равны

JE

JE

Приемник меньше источника

JB

JL

Приемник не меньше источника

JAE

JGE

Приемник не больше источника

JBE

JLE

Приемник и источник не равны

JNE

JNE

Например:

сmр ах,5 {АХ>5 ?} 

ja @AboveS {Да, больше - переходим} 

стр bх,- 3 {ВХ<=-3 ?} 

jle @LessM3 {Да, меньше или равен}

Команды LOOP/LOOPE/LOOPNE служат для организации циклов. Все они используют содержимое регистра СХ как счетчик числа повторений. Команда LOOP уменьшает СХ на единицу и передает управление на метку начала цикла, если содержимое этого регистра отлично от нуля. Команды LOOPE/LOOPNE также уменьшают счетчик СХ, но передают управление в начало цикла при совместном условии установки (или сброса) флага ZF и неравенства нулю счетчика СХ.

Вот как, например, можно отыскать нулевой байт в массиве АОВ:

var

АОВ: array [1..1000] of Byte;

.......

asm

mov ex, It)00 {Инициируем счетчик СХ} 

lea bx,AOB {Помещаем адрес АОВ в ВХ} 

dec bx {Готовим цикл} 

{Здесь начало цикла проверки}

@@Test: inc bx {Адрес очередного байта}

cmp BYTE PTR [bx],0 {Проверяем байт} 

loopne ©Test {Замыкаем цикл} 

jnz ©NotZero {Если не найден нулевой байт}

....... {Нашли нулевой байт}

end;

Строковые команды

Мнемоника

Формат

Комментарий

Пересылка строк

MOVSB

MOVSB

Пересылать байты

MOVSW

MOVSW

Пересылать слова

Сравнение строк

CMPSB

CMPSB

Сравнивать байты

CMPSW

CMPSW

Сравнивать слова

Сканирование

SCASB

SCASB

Искать байт

SCASW

SCASW

Искать слово

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

LODSB

LODSB

Загружать байты

LODSW

LODSW

Загружать слова

STOSB

STOSB

Сохранять байты

STOSW

STOSW

Сохранять слова

Строковые команды рассчитаны на обработку строк. Замечу, что термин «строка» здесь отнюдь не эквивалентен аналогичному термину Турбо Паскаля и означает произвольную цепочку байт или слов длиной до 64 Кбайт. Эти команды оперируют пятью примитивами, каждый из которых обрабатывает лишь один байт или одно слово за раз. Перед примитивом обычно указывается префикс повторения REP/REPE/REPNE, заставляющий выполняться примитив до тех пор, пока не обнулится счетчик повторений СХ или не будет нарушено соответствующее условие.

При использовании строковых команд важно помнить два обстоятельства. Во-первых, эти команды всегда берут адрес строки-источника из пары DS:SI, а строки-приемника - из пары ES:DI. Таким образом, перед исполнением строковой команды необходимо инициировать сегментные регистры нужным образом. Во-вторых, строковые команды используют индексную адресацию с автоматическим изменением смещения в SI/DI после однократного исполнения примитива. Содержимое этих регистров изменяется на 1 при обработке байтов и на 2 при обработке слов, причем наращивается, если флаг направления DF сброшен, и уменьшается, если он равен 1.

Вот как можно осуществить пересылку массива А в массив В:

var

А,В: array [1..250] of Integer;

.......

asm

lea si, A {Смещение А - в SI (источник)'} 

push ds pop es {Инициируем ES := DS} 

lea di,B {Смещение В - в DI (приемник)} 

mov ex,250 {Счетчик- переноса} 

сld {Направление переноса - наращивать}

rep movsw {Переносим 500 байт}

end;

В программе на Турбо Паскале регистр DS всегда содержит сегмент данных, поэтому инициировать его необязательно. Что касается регистра дополнительного сегмента ES, такого правила нет, и хотя в большинстве случаев он также ссылается на сегмент данных, рекомендуется проводить его инициацию перед использованием строковой команды (см. выше команды push ds, popes).

Команды прерываний

Мнемоника

Формат

Комментарий

INT

INT номер

Выполнить прерывание

INTO

INTO

Выполнить прерывание по переполнению

IRET

IRET

Вернуться из прерывания

Выполнение прерываний во многом напоминает косвенный вызов дальней процедуры. По команде INT (INTO) в стек помещается регистр флагов, сегмент CS и указатель IP, а новые значения этих регистров берутся из 4-байтного вектора прерывания, соответствующего номеру прерывания в команде INT, или из вектора 4 -для команды INTO. Таким образом, единственным отличием от команды CALL является то, что в стек предварительно заносится регистр флагов. Следует, правда, оговориться: перед передачей управления программе обработки прерывания микропроцессор сбрасывает флаги трассировки TF и прерываний IF; сброс TF необходим для обеспечения нормальной работы отладчиков, использующих прерывание по вектору 1 или 4, сброс IF блокирует вмешательство других процессов в ход обработки прерывания.

Команда INTO представляет собой условное прерывание и выполняется, если в этот момент взведен флаг переполнения OF. Команда IRET реализует правильный выход из программы обработки прерывания: она считывает из стека 3 двухбайтные слова и помещает их в регистры IP, CS и регистр флагов.

Команды управления

Мнемоника

Формат

Комментарий

Управление флагами

STC

STC

Установить перенос

CLC

CLC

Очистить перенос

CMC

CMC

Инвертировать CF

STD

STD

Установить направление

CLD

CLD

Очистить направление

STI

STI

Разрешить прерывания

CLI

CLI

Запретить прерывания

Внешняя синхронизация

HLT

HLT

Остановить вычисления

WAIT

WAIT

Ждать активности на шине

ESC

ESC код, источник

Передать команду

LOCK

LOCK

Захватить шину

Пустая команда

NOP

NOP

Нет операции

Команды внешней синхронизации работают следующим образом.

HAL Т переводит МП в состояние останова, из которого его можно вывести только при перезагрузке системы или при наступлении немаскируемого прерывания.

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

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

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