double arrow

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

Арифметические операции над целыми двоичными числами.

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

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

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

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

Микропроцессор может выполнять арифметические команды над двоичными числами без знака и со знаком, а также над десятичными числами без знака (как упакованными, так и не упакованными).

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

...

.DATA

BaseVAL DW 99

Adjust DW 10

...

.CODE

...

MOV DX,[BaseVAL]

ADD DX,11

SUB DX,[Adjust]

...

В начале в DX загружается значение 99, хранящееся в BaseVAL, затем к нему добавляется константа 11, в результате в DX значение 110, и наконец из DX вычитается значение 10, хранящееся в Ajust. Результат - в DX хранится 100.

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

Когда Вы складываете 2 операнда, микропроцессор сохраняет статус во флаге переноса (бит СF в регистре флагов) который указывает, был ли перенос в назначении; это происходит, когда результат сложения был слишком большой, чтобы уместиться в назначении.

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

...

ADD AX,BX

ADC DX,CX

...

SBB работает во многом аналогично ADС. Когда SBB выполняет вычитание, она учитывает флаг переноса, который устанавливается во время предыдущего вычитания. Например, следующий код вычитает двойное слово в CX:BX из двойного слова DX:AX:

...

SUB AX,BX

SBB DX,CX

...

Используя ADC и SBB, Вы должны быть уверены, что флаг переноса не изменялся после последнего вычитания или сложения, иначе статус переноса, хранящийся во флаге переноса, будет потерян.

6.1.2 Команды приращения и уменьшения приемника на единицу

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

В соответствии с частым использованием инкремента и декремента ассемблер предоставляет инструкции INC и DEC. Как можно, ожидать INC прибавляет к регистру или переменной 1 и DEC вычитает 1 из регистра или переменной.

Например, следующий код заполняет 10 байтный массив TempArray числами 0,1,2,3,4,5,6,7,8,9:

...

.DATA

TempArray DB 10 DUP (?)

FillCount DW ?

...

.CODE

...

MOV AL,0 ;первое значение запоминается в TempArray

MOV BX,OFFSET TempArray ;BX указывает на TempArray

MOV [FillCount],10 ;# элемента для заполнения

M1:

MOV [BX],AL ;устанавливает текущий элемент TempArray

INC BX ;указатель на следующий элемент TempArray

INC AL ;следующее значение для запоминания

DEC [FillCount] ;уменьшить # элементов

JNZ M1 ;делать другой элемент, если мы не

;заполнили все элементы

...

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

Короче, INC и DEC более эффективны для инкремента и декремента регистров и переменных в памяти.

6.2 Умножение и деление.

Инструкция MUL умножает два 8 или 16-битных беззнаковых сомножителя, генерируя 16 или 32- битное число.

Один из сомножителей при умножении 8-битовых чисел должен быть запомнен в AL; другой может быть в любом 8-битном регистре общего назначения или быть операндом памяти. MUL всегда сохраняет 16 битный результат в AX. Например,

...

MOV AL,25

MOV DH,40

MUL DH

...

умножает AL на DH, сохраняя результат 1000 в AХ. Заметим, что MUL требует только один операнд; другой сомножитель всегда в AL (или в AX в случае умножения слов).

При умножении слов один сомножитель должен быть сохранен в AX, в то время как другой может быть любым 16-битным регистром общего назначения или операндом памяти. MUL помещает 32-битный результат в DX:AX с младшими 16 битами результата в AX и старшими 16 битами результата в DX. Например,

...

MOV AX,1000

MUL AX

...

загружает в AX 1000 и затем возводит AX в квадрат, помещая результат 1000000 в DX:AX.

В отличие от сложения и вычитания умножение зависит от того, знаковые операнды или беззнаковые, поэтому введена вторая инструкция умножения IMUL для перемножения байтов и слов. За исключением того, что она обрабатывает знаковые значения, IMUL аналогична MUL:

...

MOV AL,-2

MOV AH,10

IMUL AH

...

запоминает значение -20 в AX.

Команда DIV (divide –разделить) выполняет деление чисел без знака, а команда IDIV выполняет деление чисел со знаком. Команды имеют формат

DIV источник

IDIV источник

Где источник делитель размеров в байт или слово, находящееся в регистре общего назначения или в ячейке памяти. Делимое должно иметь двойной размер; оно извлекается из регистра AX (при делении на 8-битовое число) или из регистров DX и AX при делении на 16-битовое число). Результат возвращается следующим образом:

Если операнд-источник представляет собой байт, то частное возвращается в регистр AL, а остаток в AH.

Если операнд-источник слово, то частное возвращается в AX, а остаток – в регистр DX.

Обе команды оставляют состояние флагов неопределенными, но если частное не помещается в регистре приемнике (AL или AX), то генерируется прерывание типа 0 (деление на 0).

...

MOV AX,51

MOV DL,10

DIV DL

...

Результат 5 в AL и остаток 1 в AH. Пример:

...

MOV AX,0ffffh

MOV BL,1

DIV B1

...

генерирует прерывание 0. (Как Вы ожидаете, прерывание деления на 0 будет так же генерироваться, если делитель равен 0).

Как и умножение деление зависит от того, знаковые или беззнаковые операнды используются. DIV используется для беззнаковых операндов, а IDIV - для знаковых операндов. Например,

...

.DATA

TDiv DW 100

...

.CODE

...

MOV AX,-667

CDW ;установить DX:AX в -667

IDIV [TDiv]

...

сохраняет -6 в AX и -67 в DX.

6.3 Изменение знака.

Инструкции NEG может изменить знак содержимого регистра общего назначения или переменной. Например,

...

MOV AX,1 ;устанавливает AX в 1

NEG AX ;изменяет AX в -1

MOV BX,AX ;копирует AX в BX

NEG BX ;изменяет BX в 1

...

В результате получим в AX -1, а в BX 1.


Сейчас читают про: