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

Особенности выполнения арифметических операций. Беззнаковые числа складываются по правилам двоичной арифметики. Однако факт переполнения разрядной сетки не фиксируется. Вместо этого единица переноса отбрасывается и в качестве ответа выдается искаженная сумма, а флаг CF устанавливается в 1 (если переноса не было, флаг обнуляется). Такое суммирование без учета единицы переноса называется суммированием по модулю 2k (k - размер ячейки):

 
 

 

 


При вычитании беззнаковых целых чисел при х ³ у выполняется обычное вычитание. При х < у числу х дается заем единицы (к числу х прибавляется величина 2k) и затем производится вычитание. Ошибка не фиксируется, но флаг переноса CF устанавливается в 1. Такое вычитание называют вычитанием по модулю 2k:

 

 
 

 

 


Например, при k=8 вычитание 1-2 происходит таким образом:

 

(28 + 1) – 2 = (256 + 1) – 2 = 257 – 2 = 255

 

(в двоичной системе замена 1 на 256+1 есть замена 00000001 на 100000001, т.е. добавление 1 слева) и число 255 объявляется результатом вычитания.

Рассмотрим сложение и вычитание знаковых чисел. Если целые числа со знаком представлены в дополнительном коде, то складывать и вычитать их следует по алгоритмам беззнаковых чисел. Дополнительные коды знаковых операндов рассматривают как числа без знака и в таком виде их складывают или вычитают, а полученный результат затем рассматривают в дополнительном коде.

Например, пусть надо сложить +3 и -1 (ячейка 8 бит). Их дополнительные коды – 3 и (256-1)=255. Складываем числа как беззнаковые: 3+255 (mod 256) = 258 (mod 256) = 2. Величина 2 рассматривается как дополнительный код ответа, поэтому получаем ответ +2.

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

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

В общем случае переполнение мантиссы происходит, если слагаемые одного знака и сумма оказывается вне диапазона представимых знаковых чисел ([-128, +127] при k=8). Рассмотрим сложение знаковых чисел +127 и +2. Складывая их как беззнаковые числа 127 и 2, получим число 129, которое теперь надо рассматривать как дополнительный код ответа. Поскольку 129=256-127, то суммой должно быть число -127. В результате, складывая два положительных числа, получили отрицательное; ответ равен 129=10000001b и его модуль не помещается в 7 разрядов, поэтому он перешел в знаковый разряд, изменив его на противоположный.

Переполнение мантиссы возможно и при вычитании. Например, при вычитании (+127)-(-2) = 127+2 получаем 129, а это дополнительный код числа -127, которое и выдается как результат вычитания, хотя истинной разностью является число 129. Такое переполнение мантиссы фиксирует флаг переполнения OF: он устанавливается в 1, если переполнение имело место.

Таким образом, при сложении беззнаковых чисел, интерес представляет флаг переноса CF, но если складываются знаковые числа, то анализу подлежит флаг OF (переполнение мантиссы).

При сложении и вычитании чисел меняются также флаг нуля ZF и флаг знака SF. Флаг ZF устанавливается в 1, если результат оказался нулевым, и сбрасывается в 0, если результат ненулевой. Флаг SF содержит знаковый (самый левый) бит результата. Он полезен при работе со знаковыми числами, т.к. устанавливается в 1, если результат отрицательный, и сбрасывается 0 в противном случае.

Команды сложения и вычитания. Различают обычное двоичное сложение (вычитание), с учетом переноса (заема) и инкремент (декремент) операнда. Все эти команды применимы для выполнения операций над двоичными и двоично-десятичными числами. В последнем случае следующей командой должна обязательно следовать команда коррекции результата.

Команда ADDобеспечивает сложение двух 8- или 16-разрядных двоичных чисел (табл. 15). Результат помещается на место первого операнда. Флаги OF, SF, ZF, AF и PF устанавливаются в соответствии с результатом по обычным правилам. Флаг CF свидетельствует о наличии переноса из старшего разряда результата.

 

Табл. 15. Команда ADD.

Код Инструкция Описание
00 /r ADD r/m8, r8 r/m8:= r/m8 + r8
01 /r ADD r/m16, r16 r/m16:= r/m16 + r16
02 /r ADD r8, r/m8 r8:= r8 + r/m8
03 /r ADD r16, r/m16 r16:= r16 + r/m16
04 ib ADD AL, imm8 AL:= AL + imm8
05 iw ADD AX, imm16 AX:= AX + imm16
80 /0 ib ADD r/m8, imm8 r/m8:= r/m8 + imm8
81 /0 iw ADD r/m16, imm16 r/m16:= r/m16 + imm16
83 /0 ib ADD r/m16, imm8 r/m16:= r/m16 + imm8

 

 

Примеры выполнения команды сложения:

 

MOV AL, 10 ; AL=10

ADD AL, 2 ; AL=AL+2=12

ADD AL, -12 ; AL=0 ZF=1

ADD AL, -10 ; AL=-10 SF=1

 

Командой ADD можно сложить числа размером в байт или слово. Сложение чисел другой размерности, например, двойных слов, приходиться реализовывать самостоятельно через сложение чисел размером в слово или байт. Здесь полезны команды ADC для сложения и SBB для вычитания.

Команда ADCобеспечивает сложение двух 8- или 16-разрядных двоичных чисел с учётом значения входного переноса (табл. 16). Флаги OF, SF, ZF, AF, CF и PF устанавливаются по обычным правилам. Флаг CF свидетельствует о наличии переноса из старшего разряда результата.

 

 

Табл. 16. Команда ADC.

Код Инструкция Описание
10 /r ADC r/m8, r8 r/m8:= r/m8 + r8 + CF
11 /r ADC r/m16, r16 r/m16:= r/m16 + r16 + CF
12 /r ADC r8, r/m8 r8:= r8 + r/m8 + CF
13 /r ADC r16, r/m16 r16:= r16 + r/m16 + CF
14 ib ADC AL, imm8 AL:= AL + imm8 + CF
15 iw ADC AX, imm16 AX:= AX + imm16 + CF
80 /2 ib ADC r/m8, imm8 r/m8:= r/m8 + imm8 + CF
81 /2 iw ADC r/m16, imm16 r/m16:= r/m16 + imm16 + CF
83 /2 ib ADC r/m16, imm8 r/m16:= r/m16 + imm8 + CF

 

 

Команда AAA корректирует результат сложения двух неупакованных двоично-десятичных и ASCII чисел (табл. 17). Флаги AF и CF устанавливаются в соответствии с результатом операции. Значение флагов OF, SF, ZF и PF не определено.

 

 

Табл. 17. Команда AAA.

Код Инструкция Описание
AAA Коррекция сложения неупакованных двоично-десятичных чисел.

 

 

Складываемые числа располагаются в младших полубайтах операндов, причём один из них – в младшем полубайте регистра AL. Команда AAA используется после ADD, ADC или INC. Она корректирует результат в регистре AL на основании полученного результата и состояния флага вспомогательного переноса.

Коррекция выполняется следующим образом. Если операция сложения сформировала признак вспомогательного переноса (флаг AF установлен) или если младший полубайт регистра AL больше 9, то значение младшего полубайта регистра AL увеличивается на 6, устанавливаются флаги AF и CF, регистр AH увеличивается на единицу. Если флаг AF был сброшен, а младший полубайт регистра AL содержал правильный десятичный код (значение 0–9), флаги AF и CF сбрасываются. В любом случае старший полубайт регистра AL обнуляется.

Пример сложения неупакованных двоично-десятичных чисел:

 

CLC ; CF=0

MOV AL, 9

ADD AL, 8 ; CF=0 AF=1 AL=00010001

AAA ; CF=1 AL=00000111

 

Команда DAAвыполняет коррекцию результата сложения двух упакованных двоично-десятичных чисел командами ADD или ADC (табл. 18). Флаги AF и CF устанавливаются в соответствии с результатом операции. Флаги SF, ZF и PF устанавливаются по обычным правилам в соответствии с полученным результатом. Значение флага OF не определено.

 

 

Табл. 18. Команда DAA.

Код Инструкция Описание
DAA Коррекция сложения упакованных двоично-десятичных чисел.

 

 

Действия команды во многом повторяют действия команды AAA. Если при выполнении операции сложения в младшем полубайте регистра AL получено значение больше 9 или был установлен флаг AF, то значение младшего полубайта регистра AL увеличивается на 6.

Флаг CF устанавливается, если при прибавлении 6 возник перенос из 3-го разряда (если переноса не было, значение флага CF не изменяется). Если содержимое младшего полубайта регистра AL не превышает 9, а флаг AF сброшен, никаких действий с младшим полубайтом не выполняется.

Затем проверяется содержимое старшего полубайта регистра AL. Если его значение больше 9 либо установлен флаг CF, то это значение увеличивается на 6 и устанавливается флаг CF. Если значение старшего полубайта не превышает 9, а флаг CF сброшен, никаких действий со старшим полубайтом не выполняется.

Пример сложения упакованных двоично-десятичных чисел:

 

CLC ; CF=0

MOV AL, 99h

ADD AL, 99h ; CF=1 AF=1 AL=00110010

DAA ; CF=1 AL=10011000

 

Команда INCувеличивает значение операнда на единицу (табл. 19). Флаги OF, SF, ZF, AF и PF устанавливаются в соответствии с результатом по обычным правилам. Значение флага CF не изменяется.

 

Табл. 19. Команда INC.

Код Инструкция Описание
FE /0 INC r/m8 Инкремент r/m8.
FF /0 INC r/m16 Инкремент r/m16.
40+rw INC r16 Инкремент r16.

 

 

Операндом может являться любой регистр общего назначения, одно- или двухбайтовое поле памяти:

 

INC AL

INC WORD PTR A

 

Инкремент 16-разрядных регистров общего назначения может быть выполнен двумя видами инструкций – однобайтовой (код операции 40 плюс номер регистра) и двухбайтовой (код операции FF, номер регистра определяется байтом ModRegR/M). Транслятор языка ассемблера автоматически генерирует однобайтовый код операции как более компактный; второй вариант при необходимости может быть запрограммирован вручную.

Команда SUBобеспечивает вычитание двух 8- или 16-разрядных двоичных чисел (табл. 20). Флаги OF, SF, ZF, AF, CF и PF устанавливаются по обычным правилам, а флаг CF свидетельствует о наличии заёма в старший разряд результата.

 

 

Табл. 20. Команда SUB.

Код Инструкция Описание
28 /r SUB r/m8, r8 r/m8:= r/m8 – r8
29 /r SUB r/m16, r16 r/m16:= r/m16 – r16
2A /r SUB r8, r/m8 r8:= r8 – r/m8
2B /r SUB r16, r/m16 r16:= r16 – r/m16
2C ib SUB AL, imm8 AL:= AL – imm8
2D iw SUB AX, imm16 AX:= AX – imm16
80 /5 ib SUB r/m8, imm8 r/m8:= r/m8 – imm8
81 /5 iw SUB r/m16, imm16 r/m16:= r/m16 – imm16
83 /5 ib SUB r/m16, imm8 r/m16:= r/m16 – imm8

 

 

Примеры использования команды вычитания:

 

MOV AL, 10 ; AL=10

SUB BL, 10 ; BL=AL-10=0 ZF=1

SUB BL, -10 ; BL=10

 

Команда SBBобеспечивает вычитание двух 8- или 16-разрядных двоичных чисел с учётом значения входного заёма, определяемого флагом CF (табл. 21). Флаги устанавливаются как у команды SUB.

 

 

Табл. 21. Команда SBB.

Код Инструкция Описание
18 /r SBB r/m8, r8 r/m8:= r/m8 – r8 – CF
19 /r SBB r/m16, r16 r/m16:= r/m16 – r16 – CF
1A /r SBB r8, r/m8 r8:= r8 – r/m8 – CF
1B /r SBB r16, r/m16 r16:= r16 – r/m16 – CF
1C ib SBB AL, imm8 AL:= AL – imm8 – CF
1D iw SBB AX, imm16 AX:= AX – imm16 – CF
80 /3 ib SBB r/m8, imm8 r/m8:= r/m8 – imm8 – CF
81 /3 iw SBB r/m16, imm16 r/m16:= r/m16 – imm16 – CF
83 /3 ib SBB r/m16, imm8 r/m16:= r/m16 – imm8 – CF

 

 

Команда DECуменьшает значение операнда на единицу (табл. 22). Флаги OF, SF, ZF, AF и PF устанавливаются в соответствии с результатом по обычным правилам. Значение флага CF не изменяется. Операндом может являться любой регистр общего назначения, одно- или двухбайтовое поле памяти.

Как и команда INC декремент 16-разрядных регистров общего назначения может быть выполнен двумя видами инструкций – однобайтовой (код операции 48 плюс номер регистра) и двухбайтовой (код операции FF, номер регистра определяется байтом ModRegR/M).

Выгода от команд INC и DEC заключается в том, что они занимают меньше места в памяти и выполняются быстрее, чем соответствующие команды ADD и SUB.

 

 

Табл. 22. Команда DEC.

Код Инструкция Описание
48+rw DEC r16 Декремент r16.
FE /1 DEC r/m8 Декремент r/m8.
FF /1 DEC r/m16 Декремент r/m16.

 

 

 

Команда AASобеспечивает коррекцию результата вычитания двоично-десятичных неупакованных и ASCII чисел (табл. 23). Команда AAS используется после SUB, SBB или DEC. Если установлен флаг AF или содержимое младшего полубайта регистра AL превышает 9, из этого значения вычитается 6, содержимое регистра AH уменьшается на единицу, и устанавливаются флаги AF и CF. В противном случае флаги AF и CF сбрасываются. В любом случае старший полубайт регистра AL обнуляется. Значение флагов OF, SF, ZF и PF не определено.

 

 

Табл. 23. Команда AAS.

Код Инструкция Описание
3F AAS Коррекция вычитания неупакованных двоично-десятичных чисел.

 

 

Пример вычитания неупакованных двоично-десятичных чисел:

 

CLC ; CF=0

MOV AL, 02h

SUB AL, 05h ; AL=0FDh AF=1

AAS ; AL=0FDh – 6 = 0F7h CF=1

 

Команда DASвыполняет коррекцию результата вычитания двух упакованных двоично-десятичных чисел (табл. 24). Флаги AF и CF устанавливаются в соответствии с результатом операции. Флаги SF, ZF и PF устанавливаются по обычным правилам в соответствии с полученным результатом. Значение флага OF не определено.

 

 

Табл. 24. Команда DAS.

Код Инструкция Описание
2F DAS Коррекция вычитания упакованных двоично-десятичных чисел.

 

 

Алгоритм коррекции следующий. Если при выполнении операции вычитания в младшем полубайте регистра AL получено значение, превышающее 9, или был установлен флаг AF (произошёл заём в 3-ий разряд), то значение младшего полубайта регистра AL уменьшается на 6, флаг CF устанавливается. Если содержимое младшего полубайта регистра AL не превышает 9 и флаг AF сброшен, никаких действий с младшим полубайтом не выполняется.

Затем проверяется содержимое старшего полубайта регистра AL. Если его значение больше 9 либо если установлен флаг CF, то значение уменьшается на 6 и устанавливается флаг CF. Если значение старшего полубайта не превышает 9 и флаг CF сброшен, никаких действий со старшим полубайтом не выполняется.

Пример вычитания упакованных двоично-десятичных чисел:

 

CLC ; CF=0

MOV AL, 25h

SUB AL, 52h ; AL=0D3h AF=0 CF=1

DAS ; AL=0D3h – 60h=73h CF=1

 

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

Команда MULпроизводит целочисленное умножение двух беззнаковых двоичных чисел (табл. 25). Флаги SF, ZF, AF и PF не изменяются. Флаги OF и CF устанавливаются, если разрядность результата превышает разрядность исходных операндов. Если результат вмещается в разрядность исходных операндов, флаги будут сброшены.

 

 

Табл. 25. Команда MUL.

Код Инструкция Описание
F6 /4 MUL r/m8 AX:= AL * r/m8
F7 /4 MUL r/m16 DX, AX:= AX * r/m16

 

 

Один из множителей располагается в регистре AL или AX (в зависимости от разрядности), второй – в регистре общего назначения или ячейке памяти (определяется байтом ModRegR/M).

Под результат отводится в два раза больше места, чем под сомножители, т.к. в общем случае умножение n-значных чисел дает произведение из 2n цифр. При умножении байтов результат имеет размер слова и записывается в регистр АХ (в АН – старшие цифры произведения, в AL – младшие). При умножении слов результат имеет размер двойного слова и записывается в два регистра – в регистр DX заносится старшая часть произведения, а в регистр АХ – младшая.

Команда IMULпроизводит целочисленное умножение двух знаковых двоичных чисел (табл. 26). Флаги SF, ZF, AF и PF не изменяются. Флаги OF и CF устанавливаются, если разрядность результата превышает разрядность исходных операндов.

 

 

Табл. 26. Команда IMUL.

Код Инструкция Описание
F6 /5 IMUL r/m8 AX:= AL * r/m8
F7 /5 IMUL r/m16 DX, AX:= AX * r/m16

 

 

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

Рассмотрим несколько примеров использования команд умножения:

 

N DB 10

...

MOV AL, 2

MUL N ; AX=2*10=20=0014h: AH=00h, AL=14h

MOV AL, 32

MUL N ; AX=32*10 = 320=0140h: AH=01h, AL=40h

MOV AX, 8

MOV BX, -1

IMUL BX ; (DX, AX) = -8=0FFFFFFF8h: DX=0FFFFh, AX=0FFF8h

 

С помощью анализа флагов переноса CF и переполнения OF выполняется проверка, умещается ли результат умножения в формат сомножителей:

- произведение занимает двойной формат CF=OF=1;

- произведению достаточен формат сомножителей CF=OF=0.

Во втором случае произведение байтов занимает только регистр AL, а произведение слов – только регистр АХ. Но если CF=1, то далее приходится работать с результатом как с числом удвоенного формата.

Начиная с процессора 80186, доступен упрощенный вариант команд умножения MUL и IMUL. Их мнемоника включает три операнда. Первый операнд может быть только регистром r16, второй операнд r/m16, третий операнд непосредственный imm16. Следовательно, команды позволяют оперировать только словами, и результат умножения также должен быть размером слово. Команды перемножают второй и третий операнды и помещают результат в регистр общего назначения. Такие расширения команд имеют и другие инструкции (см. команды сдвига и стековые команды).

Следует заметить, что трансляторы языка ассемблера TASM и MASM по умолчанию воспринимают только базовый набор команд процессора 8086. Чтобы сделать для них доступными расширения команд, введенные в более поздних моделях процессоров, например, в 80186, необходимо указывать специальные директивы.

Например, директива .8086 допускает использование только команд 8086, а директива .186 допускает использование команд процессора 8086 и новых команд процессора 80186. Директивы могут быть указаны в любом месте программы на языке ассемблера, и действовать они будут до появления следующей подобной директивы.

Инструкция AAMобеспечивает коррекцию результата умножения двух неупакованных двоично-десятичных чисел командой MUL (табл. 27). Флаги SF, ZF и PF устанавливаются по обычным правилам. Значение флагов OF, AF и CF не определено.

 

 

Табл. 27. Команда AAM.

Код Инструкция Описание
D4 0A AAM Коррекция умножения неупакованных двоично-десятичных чисел.

 

Коррекция заключается в том, что в регистр AH заносится целая часть от деления содержимого регистра AL на 10, а в регистр AL – остаток:

 

MOV AL, 8

MOV BL, 9

MUL BL ; AH=0 AL=72

AAM ; AH=7 AL=2

 

Команда DIVпроизводит целочисленное деление двух беззнаковых двоичных чисел (табл. 28). Флаги не изменяются. Делимое должно иметь размер 16 или 32 разряда. В первом случае оно располагается в регистре AX, во втором занимает регистровую пару DX:AX (старшая часть – в регистре DX, младшая – в регистре AX). Делитель размещается в регистре или ячейке памяти, определяемой байтом ModRegR/M. При 16-разрядном делимом делитель имеет размер байт, а при 32-разрядном делимом – слово.

Частное и остаток имеют разрядность, совпадающую с разрядностью делителя, т.е. в два раза меньше, чем у делимого. В операции деления 16-разрядного числа на 8-разрядное частное располагается в регистре AL, остаток – в регистре AH. При делении 32-разрядного числа на 16-разрядное частное будет находиться в регистре AX, а остаток – в регистре DX.

 

 

Табл. 28. Команда DIV.

Код Инструкция Описание
F6 /6 DIV r/m8 AL:= AX DIV r/m8 AH:= AX MOD r/m8
F7 /6 DIV r/m16 AX:= DX, AX DIV r/m16 DX:= DX, AX MOD r/m16

 

 

При выполнении команды деления возможно появление ошибки в двух случаях: делитель равен 0 или неполное частное не вмещается в отведенное ему место (регистр AL или АХ). Во втором случае происходит прекращение выполнение программы.

Команда IDIVпроизводит целочисленное деление двух двоичных чисел со знаком (табл. 29). Флаги не изменяются. Знак остатка всегда совпадает со знаком делимого.

 

 

Табл. 29. Команда IDIV.

Код Инструкция Описание
F6 /7 IDIV r/m8 AL:= AX DIV r/m8 AH:= AX MOD r/m8
F7 /7 IDIV r/m16 AX:= DX, AX DIV r/m16 DX:= DX, AX MOD r/m16

Команда AADвыполняет коррекцию двоично-десятичного неупакованного делимого, находящегося в регистре AX (в AH – старшая цифра, в AL – младшая) (табл. 30). Команда должна предшествовать DIV. Флаги SF, ZF и PF устанавливаются по обычным правилам. Значение флагов OF, AF и CF не определено.

 

 

Табл. 30. Команда AAD.

Код Инструкция Описание
D5 0A AAD Коррекция неупакованного двоично-десятичного делимого.

 

 

Команда корректирует делимое, состоящее из двух двоично-десятичных цифр, находящихся в младших полубайтах регистров AH и AL (старшие полубайты должны быть нулевыми). В регистр AX помещается двоичный эквивалент двоично-десятичного неупакованного числа, который вычисляется по формуле AL=10*AH + AL. После выполнения команды DIV в регистре AL будет сформировано правильное двоичное частное:

 

MOV AX, 0403h ; делимое 43 (AH=4 AL=3)

MOV BL, 5 ; делитель 5

AAD ; AX=43 (двоичное)

DIV BL ; AH=3 (остаток) AL=8 (частное)

 

Для преобразования результата в двоично-десятичный формат можно воспользоваться инструкцией AAM. Остаток в регистре AH принимает значение 0–9 в зависимости от значения исходных операндов, поэтому не нуждается в дополнительном преобразовании.

Команды изменения размера операнда. Арифметические команды не позволяют выполнять операции над операндами разного размера. Например, операция BX:=BX+AL недопустима, т.к. здесь требуется сложить слово с байтом. Поэтому для выполнения такой операции необходимо привести операнды к одной размерности – расширить байт AL до слова. Если число беззнаковое, то расширение заключается в дополнении числа слева нулями.

Например, если AL=32=20h, то AX=0020h и реализуется это записью 0 в регистр АН:

 

MOV АН, 0 ; AL > АХ (без знака)

Такое расширение называется расширением без знака. Для знаковых чисел следует учитывать знак. Если число неотрицательно, то его достаточно дополнить нулями. Если число отрицательное, тогда слева надо дописать двоичные единицы (FF в шестнадцатеричной системе). Например, число -32 (-20h) в дополнительном коде как байт имеет вид 256-32 = 100h-20h = 0E0h, а как слово -10000h-20h = 0FFE0h. Такое расширение называется расширением со знаком.

Для расширения со знаком в системе команд предусмотрена команда CBW(табл. 31).

 

 

Табл. 31. Команда CBW.

Код Инструкция Описание
CBW Расширение байта до слова.

 

 

Содержимое регистра AL, рассматриваемое как число со знаком, расширяется на регистр AH (рис. 19). Флаги не изменяются. Если в AL содержалось отрицательное число (т.е. если старший разряд регистра AL равен 1), все разряды регистра AH устанавливаются в единицу.

 

 
 

 

 


Рис. 19. Расширение со знаком байта до слова.

 

 

Если в AL содержался нуль или положительное число (старший разряд регистра AL равен 0), регистр AH обнуляется:

 

 
 


00h при AL >=0

AH =

 

0FFh при AL < 0

 

 

Приведем примеры расширения беззнаковых и знаковых чисел:

 

; числа без знака:

MOV АН, 0

AL > АХ (расширение без знака)

ADD ВХ, АХ

 

; числа со знаком:

CBW

; AL > АХ (расширение со знаком)

ADD BX, AX

 

Необходимость расширения байта до слова возникает при делении байтов. Разрешено делить слово на байт, но не байт на байт. Если такое деление необходимо, следует первый байт (делимое) расширить до слова. Обычно расширяют слово в регистре АХ до двойного слова, занимающего два регистра – DX и АХ (в DX находится старшая часть числа, а в АХ – младшая):

 

АХ > (DX, AX)

 

При этом расширение беззнакового числа АХ реализуется обнулением регистра DX:

 

MOV DX, 0 ; АХ > (DX, AX) (без знака)

Если число АХ рассматривается как знаковое, тогда для его расширения в регистр DX следует записать 0000h, если число неотрицательно, или FFFFh, если отрицательно. Для такого расширения в системе команд предусмотрена команда CWD(табл. 32).

 

 

Табл. 32. Команда CWD.

Код Инструкция Описание
CWD Расширение слова до двойного слова.

 

 

Содержимое регистра AX, рассматриваемое как число со знаком, после расширения будет занимать регистровую пару DX:AX (рис. 20). В регистр DX заносится старшая часть результата. Флаги не изменяются.

 

 
 

 

 


Рис. 20. Расширение со знаком слова до двойного слова.

 

 

Если в AX содержалось отрицательное число (т.е. старший разряд регистра AX равен 1), все разряды регистра DX устанавливаются в единицу. Если в AX содержался нуль или положительное число (старший разряд регистра AX равен 0), регистр DX обнуляется:

 

 
 


0000h при AX >=0

DX =

 

FFFFh при AX < 0

 

 

Приведем примеры применения команд изменения размерности:

 

CBW

ADD AX, DX ; сложить байт в AL со словом в DX

 

CBW

IMUL DX ; умножить байт в AL на слово в DX

 

CWD

IDIV DX ; разделить слово в AL на слово в BX

 

Последняя арифметическая команда меняет знак операнда на противоположный (табл. 33). Флаги OF, SF, ZF, AF и PF устанавливаются в соответствии с результатом. Флаг CF сбрасывается, если исходный операнд равен нулю, и устанавливается в противном случае.

 

 

Табл. 33. Команда NEG.

Код Инструкция Описание
F6 /3 NEG r/m8 r/m8:= – r/m8
F7 /3 NEG r/m16 r/m16:= – r/m16

 

 

Пример команды изменения знака операнда:

 

MOV АН, 1

NEG АН ; АН:=1 (0FFh)

 

Заметим, что для байтовых чисел, если операнд равен -128 (80h), не меняется, т.к. нет знакового числа +128. Аналогично для чисел-слов: если значение операнда равно -32768 (8000h), то команда не меняет операнд. В этом случае флаг OF получает значение 1 (при других операндах OF=0). При нулевом операнде флаг CF равен 0, при других -1. Флаги SF и ZF меняются обычным образом.

Команда NEG полезна при вычитании значения регистра или ячейки памяти из непосредственного операнда. Допустим, необходимо вычесть из 100 значение регистра AL. Команда SUB 100, AL невозможна, т.к. непосредственный операнд не может быть приемником. Поэтому можно обратить знак содержимого регистра AL и затем добавить к нему 100:

 

NEG AL

ADD AL, 100