Операции


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

Арифметические операции

Даже если ваш компьютер РС и не тратит все время на работу с числами и вычислительные операции, вы знаете, что он может это сделать, если вам это потребуется. Кроме того, на компьютере РС может работать множество электронных таблиц, программ баз данных и инженерных пакетов. Если принять все это во внимание, то стано-вится достаточно очевидным, что компьютер IBM PС должен обладать мощными вычислительными способностями.

И это в самом деле так. Однако, хотя работающее на процессо-ре 8086 программное обеспечение может прекрасно выполнять матема-тические действия, сам процессор 8086 обеспечивает на удивление простые арифметические возможности. В процессоре 8086 отсутствуют инструкции для выполнения арифметических операций с плавающей точкой (арифметических действий с такими числами, как 5.2 и 1.03Е17), не говоря уже о тригонометрических функциях. Эти опера-ции выполняются арифметическим сопроцессором 8087. Это не означа-ет, что программы, работающие на процессоре 8086, не могут выпол-нять арифметические операции над числами с плавающей точкой. Ведь электронные таблицы могут работать и на компьютерах РС без сопро-цессора 8087. Однако программы процессора 8086 выполняют арифме-тические операции над числами с плавающей точкой медленнее, с по-мощью последовательности инструкций сдвигов, сложений и проверок, а не с помощью одной быстро выполняющейся инструкции, как в соп-роцессоре 8087.

Кроме того, в процессоре 8086 не предусмотрено арифметичес-ких и логических инструкций, которые могут непосредственно рабо-тать с операндами, размер которых превышает 16 бит.

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

Сложение и вычитание

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

Например, инструкции:

.DATA

BaseVal DW 99

Adjust DW 10

CODE

mov dx,[BaseVal]

add dx,11

sub dx,[Adjust]

сначала загружают значение, записанное в BaseVal, в регистр DX, затем прибавляют к нему константу 11 (в результате в DX получает-ся значение 110) и, наконец, вычитают из DX значение 10, записан-ное в переменной Adjust. Полученное в результате значение 100 сохраняется в регистре DX.

32-разрядные операнды

Операции ADD и SUB работают с 8- или 16-битовыми операндами.

Если вы, к примеру, хотите сложить или вычесть 32-разрядные опе-ранда, вы должны разбить операцию на ряд операций со значениями размером в слово и использовать инструкции ADC и SBB.

Когда вы складываете два операнда, процессор 8086 записывает состояние во флаг переноса (бит С в регистре флагов), которое по-казывает, был ли выполнен перенос из приемника. Вы знакомы с принципом переноса в десятичной арифметике: если вы складываете 90 и 10, то получаете перенос в третью цифру (разряд).

90

· 10

100

Рассмотрим теперь сложение двух шестнадцатиричных значений:

FFFF

· 1

10000

Младшее слово результата равно нулю, перенос равен 1, пос-кольку результат (10000h) не вмещается в 16 бит.

Инструкция ADC аналогична инструкции ADD, но в ней учитыва-ется флаг переноса (предварительно установленный предыдущим сло-жением). Всякий раз когда вы складываете два значения, превышаю-щие по размеру слово, то младшие (менее значащие) слова нужно сложить с помощью инструкции ADD, а остальные слова этих значений — с помощью одной или нескольких инструкций ADC, последними скла-дывая самые значащие слова. Например, следующие инструкции скла-дывают значение в регистрах CX:BX, размером в двойное слово, со значением, записанным в регистрах DX:AX:

add ax,bx

adc dx,cx

а в следующей группе инструкций выполняется сложение четверного слова в переменной DoubleLong1 с четверным словом в переменной DoubleLong2:

mov ax,[DoubleLong1]

add [DoubleLong2],ax

mov ax,[DoubleLong1+2]

adc [DoubleLong2+2],ax

mov ax,[DoubleLong1+4]

adc [DoubleLong1+4],ax

mov ax,[DoubleLong1+6]

adc [DoubleLong2+6],ax

Инструкция SBB работает по тому же принципу, что и инструк-ция ADC. Когда инструкция SBB выполняет вычитание, в ней учитыва-ется заем, произошедший в предыдущем вычитании. Например, следую-щие инструкции вычитают значение, записанное в регистрах CX:BX, из значения размером в двойное слово, записанного в регистрах DX:AX:

sub ax,bx

sbb dx,cx

При работе с инструкциями ADC и SBB вы должны убедиться, что флаг переноса не изменился с момента выполнения последнего сложе-ния или вычитания, иначе состояние заема/переноса, хранящееся во флаге переноса, будет потеряно. Например, в следующем фрагменте программы сложение CX:BX с DX:AX выполняется некорректно:

add ax,bx ; сложить младшие слова

sub si,si ; очистить SI (флаг переноса

; сбрасывается в 0)

adc dx,cx ; сложить старшие слова…

; это будет работать некорректно,

; так как с момента последней

; операции сложения содержимое

; флага переноса потеряно