Арифметические команды Ассемблера
Команды сложения - ADD, ADC
Команды ADD (add - сложить) и ADC (add with carry- сложить с переносом) могут складывать как 8-, так и 16-битовые операнды.
Команда ADD складывает содержимое операнда-источника и операнда-приемника и помещает результат в операнд-приемник.
Формат команды: ADD приемник, источник
В символической нотации ее действия можно описать следующим образом: приемник := приемник + источник (в приемник записывается сумма содержимого приемника и источника).
Команда ADC делает то же, что и команда ADD, но складывает не два, а три слагаемых: приемник, источник и флаг переноса.
Формат команды: ADC приемник, источник + CF
В символической нотации ее действия можно описать как:
приемник := приемник + источник + содержимое флага переноса.
Перенос при сложении двоичных чисел аналогичен переносу при сложении десятичных чисел в столбик. Когда ЭВМ складывает двоичные числа и сумма не помещается в операнде-приемнике, то генерируется перенос. Как известно, 8-битовый регистр может содержать значения без знака в диапазоне от 0 до 255. Если мы, например, выполним двоичное сложение чисел 250 и 10, то получим следующий результат:
1111 1010; двоичное представление числа 250.
0000 1010; двоичное представление числа 10.
1 0000 0100; двоичное представление суммы, равной 260.
Результат верен, но занимает 9 двоичных битов. Если использовались 8 - битовые регистры, то младшие 8 битов будут занесены в регистр-приемник, а девятый бит- во флаг переноса CF.
Теперь понятно, почему микропроцессор 8086 имеет две разные команды сложения. Одна из них (ADD) может складывать значения, представляемые байтами или словами, а также младшие части значений повышенной точности. Другая команда (ADC) используется для сложения старших частей значений повышенной точности.
Складываемые операнды могут находиться в памяти, регистре или иметь непосредственное значение. Например:
ADD АХ,MEM_WORD; прибавить содержимое ячейки памяти к регистру,
ADD MEM_WORD,AX; или наоборот, прибавить содержимое регистра к ячейки памяти.
ADD AL, 10; прибавить константу к содержимому регистра.
ADD MEM_BYTE,8H; сложить константу и содержимое ячейки памяти.
Допускается большинство возможных комбинаций, но нельзя складывать содержимое двух ячеек памяти или использовать в качестве приемника непосредственное значение (число).
Команды ADD и ADC могут воздействовать на следующие шесть флагов:
флаг переноса CF равен 1, если результат сложения не помещается в операнде-приемнике, в противном случае он равен 0;
флаг четности PF равен 1, если результат имеет четное число битов со значением 1, в противном случае он равен 0;
вспомогательный флаг переноса AF равен 1, если результат сложения десятичных чисел требует коррекции;
флаг нуля ZF равен 1, если результат равен 0;
флаг знака SF равен 1, если результат отрицателен (старший бит равен 1), в противном случае он равен 0;
флаг переполнения OF равен 1, если слагаемое двух чисел одного знака превышает диапазон допустимых значений приемника в обратном коде, а сам приемник при этом меняет знак. Иначе флаг OF равен 0.
Команда увеличения значения приемника на единицу – INC
Команда INC(increment - прирастить) добавляет 1 к содержимому регистра или ячейки памяти, но в отличие от команды ADD не воздействует на флаг переноса CF. Формат команды: INC приемник.
Команда INC удобна для увеличения значений счетчиков в циклах команд. Ее можно использовать и для увеличения значения индексного регистра при доступе к последовательно расположенным ячейкам памяти. Операнд интерпретируется как число без знака.
Например:
INC CX; увеличить значение 16-битового
INC AL; или 8-битового регистра на единицу.
INC MEM_BYTE; увеличить значение байта
INC MEM_WORD; или слова памяти на единицу.
Не допускается использовать в качестве операнда непосредственное значение.
Команды вычитания - SUB, и вычитания с заемом SBB
Команды SUB (substract - вычесть) и SBB (substract with borrow - вычесть с заемом) аналогичны соответственно командам сложения ADD и ADC, только при вычитании флаг переноса CF действует как признак заема. Формат команды: SUB приемник,источник;
Команда SUB вычитает операнд -источник из операнда -приемника и помещает результат в приемник, в символической нотации:
приемник := приемник – источник.
Команда SBB делает то же самое, но дополнительно вычитает из приемника значение флага переноса CF:
SUB приемник,источник – СF;
Приемник := приемник - источник - содержимое флага переноса.
Как и в случае сложения, команды SUB и SBB выполняют две отдельные функции. Первая команда вычитает числа размером в байт или слово, а также младшие биты чисел повышенной точности (младшая часть числа расположена в регистре АХ, а старшая часть в регистре DX). Вторая команда вычитает старшие биты чисел повышенной точности. Например, команда SUB AX,CX; вычитает содержимое регистра СХ из содержимого регистра АХ и возвращает результат в регистр АХ.
Если размеры операндов превышают 16 бит, то необходимо применить следующую последовательность команд:
SUB АХ,CX; Вычесть младшие 16 бит;
SBB BX,DX; а затем старшие 16 бит.
Здесь мы вычитаем из 32-битового числа, помещенного в регистры АХ и ВХ, 32-битовое число, находящееся в регистрах СХ и DX. При вычитании содержимого регистра DX из содержимого регистра ВХ команда SBB учитывает возможность заема при выполнении первого вычитания.
Можно вычитать из содержимого регистра содержимое ячейки памяти (и наоборот) или вычитать из содержимого регистра либо ячейки памяти непосредственное значение. Примеры допустимых команд:
SUB АХ, MEM; Вычесть из регистра содержимое ячейки памяти.
SUB MEM [BX],AX; Вычесть из ячейки памяти регистр.
SUB AL,1O; Вычесть константу из регистра.
SUB MEM_BYTE,OFh; Вычесть константу из ячейки памяти.
Нельзя непосредственно вычесть содержимое одной ячейки памяти из другой или использовать непосредственное значение как приемник.
Команды SUB и SBB могут воздействовать на шесть флагов следующим образом:
· устанавливают флаг переноса CF в 1, если требуется заем, в противном случае он равен 0;
· устанавливают флаг четности PF в 1, если результат вычитания имеет четное число битов со значением 1, в противном случае он равен 0;
· устанавливают вспомогательный флаг переноса AF в 1, если результат вычитания десятичных чисел требует коррекции, в противном случае он равен 0;
· устанавливают флаг нуля ZF в 1, если результат равен 0, в противном случае он равен 0;
· устанавливают флаг знака SF в 1, если результат отрицателен (старший бит равен 1), в противном случае флаг равен 0;
· устанавливают флаг переполнения OF в 1, если при вычитании результат превышает диапазон значений приемника в обратном коде, а сам приемник изменяет знак.
Флаги SF и OF имеют смысл только при вычитании чисел со знаком, а флаг AF- только при вычитании десятичных чисел.
Команда уменьшения содержимого приемника - DEC
КомандаDEC приемник (decrement-уменьшить) вычитает 1 из содержимого регистра или ячейки памяти, но при этом (в отличие от команды SUB) не воздействует на флаг переноса CF.
Команда DEC часто используется в циклах для уменьшения значения счетчика до тех пор, пока оно не станет нулевым или отрицательным. Ее можно использовать также для уменьшения значения индексного регистра или указателя при доступе к последовательно расположенным ячейкам памяти. Например:
DEC CX; Уменьшить значение 16-битового,
DEC AL; или 8-битового регистра.
DEC MEM_BYTE; Уменьшить значение байтовой,
DEC MEM_WORD[BX]; или словной ячейки памяти.
Команды деления - DIV, IDIV
КомандаDIV (divide - разделить) выполняет деление чисел без знака, а команда IDIV (integer divide - разделить целые числа) выполняет деление чисел со знаком. Эти команды имеют формат:
DIV источник; где источник - делитель размером в байт или слово,
IDIV источник;находящийся в регистре общего назначения или в ячейке памяти.
Обратите внимание на следующее:
1. Делимое по отношению к делителю должно иметь двойной размер.
2. Делимое всегда должно находиться в регистре АХ (при делении на 8-битовое число) или в регистрах DX и АХ (при делении на 16-битовое число).
3. Результаты команды возвращаются следующим образом:
· если операнд-источник представляет собой байт, то частное возвращается в регистр AL, а остаток в регистр АН;
· если операнд-источник представляет собой слово, то частное возвращается в регистр АХ, а остаток - в регистр DX.
Обе команды оставляют состояние флагов неопределенными, но если частное не помещается в регистре-приемнике (AL или АХ), то микропроцессор генерирует прерывание типа 0 (деление на 0).
4. Переполнение результата деления возникает при следующих условиях:
· делитель равен 0;
· при делении байтов без знака делимое, по меньшей мере, в 256 раз превышает делитель;
· при делении слов без знака делимое, по меньшей мере, в 65 536 раз превышает делитель;
· при делении байтов со знаком частное лежит вне диапазона -128 до +127;
· при делении слов со знаком частное лежит вне диапазона от
-32768 до 32767.
Приведем несколько типичных примеров операций деления:
DIV BX; Разделить DX:AX на ВХ, без знака.
DIV MEM_BYTE; Разделить АХ на байт памяти, без знака.
IDIV DL; Разделить АХ на DL со знаком.
IDIV MEM WORD; Разделить DX:AX на слово памяти, со знаком.
Команды DIV и IDIV не позволяют прямо разделить на непосредственное значение, так как процессор не может определить тип данных делителя.
Команды умножения - MUL, IMUL
Команда MUL (multiply-умножить) умножает числа без знака, a IMUL(integer multiply-умножить) умножает целые числа со знаком. Множимое и множитель у обеих команд должны быть данные одного типа, то есть байты, слова, двойные слова и т. д.
Эти команды имеют следующий формат:
MUL источник; гдеисточник - регистр общего назначения,
IMUL источник; или ячейка памяти размером в байт или слово.
В качестве первого операнда (множимого) команды MUL и IMUL используют содержимое регистра AL (при операциях над байтами) или регистра АХ (при операциях над словами). Произведение имеет двойной размер и возвращается следующим образом:
· умножение байтов -возвращает 16-битовое произведение в регистры АН (старший байт) и AL (младший байт);
· умножение слов -возвращает 32- битовое произведение в регистры DX (старшее слово) и АХ (младшее слово). Таким образом, размер произведения n- битных сомножителей равен 2n.
После исполнения команды MUL флаги CF и OF равны 0, если старшая половина произведения равна 0; в противном случае оба этих флага равны 1.
После исполнения команды IMUL флаги CF и OF равны 0, если старшая половина произведения представляет собой лишь расширение знака младшей половины. В противном случае они равны 1.
Несколько примеров умножения:
MUL BX; Умножить АХ на без ВХ знака.
MUL MEM_BYTE; Умножить содержимое ячейки памяти на AL.
IMUL DL; Умножить DL на AL со знаком.
IMUL MEM_WORD; Умножить ячейку памяти на АХ со знаком.
Команды MUL и IMUL не дозволяют в качестве операнда использовать непосредственное число.
Команды преобразования типов данных – CBW, CWD,CDQ
Существуют команды, позволяющие выполнять операции над смешанными данными за счет удвоения размера операнда со знаком.
Команда CBW (convert byte to wordпреобразовать байт в слово) копирует седьмой бит регистра AL во всех битах регистра АН.
Команда CWD (convert word to double word – преобразовать слово в двойное слово) копирует 15-й бит регистра АХ во всех битах регистра DX.
Команда CWDE копирует 15-й бит регистра АХ во всех битах регистра ЕАХ.
Команда CDQ – преобразовать двойное слово в учетверенное слово, копирует 31- й бит EAX во все битах EDX.
Таким образом, команда CBW позволяет сложить байт и слово, вычесть слово из байта и т.д. Аналогично команда CWD позволяет разделить слово на слово. Приведем несколько примеров:
CBW; Расширить AL до AX (байт до слова).
ADD AX,BX; Сложить байт в AL со словом в ВХ.
CBW; Расширить AL до AX.
IMUL ВХ; Умножить содержимое AL на содержимое ВХ.
CWD; Расширить AХ в DX (слово до двойного слова).
IDIV ВХ; Разделить слово в АХ на слово в ВХ.