Додавання й віднімання
Команди ADD і SUB виконують додавання й віднімання байтів або слів, що містять двійкові дані. Віднімання виконується у комп'ютері по методу додавання із двійковим доповненням: для другого операнда встановлюються зворотні значення бітів і додається 1, а потім відбувається додавання з першим операндом. У всьому, крім першого кроку, операції додавання й віднімання ідентичні. Можливі п'ять ситуацій:
ADD / SUB регістр-регістр;
ADD / SUB пам'ять-регістр;
ADD / SUB регістр-пам'ять;
ADD / SUB регістр-безпосереднє значення;
ADD / SUB пам’ять-безпосереднє значення.
Переповнення.
При виконанні арифметичних операцій можливе переповнення. Один байт містить знаковий біт і сім біт даних, тобто значення від -128 до +127. Результат арифметичної операції може легко перевищити розрядність однобайтового регістра. Наприклад, результат додавання в регістрі AL, що перевищує його розрядність, автоматично не переходить у регістр AH. Припустимо, що регістр AL містить 60h, тоді результат команди ADD AL,20h генерує в AL суму -.80h. Але операція також встановлює прапорець переповнення і прапорець знаку у стан "негативно". Причина в тому, що.80h або двійкове 1000 0000 є від’ємним числом. Т.ч. в результаті, замість +128, ми одержимо -128. Оскільки регістр AL занадто малий для такої операції то варто скористатися регістром AX. Для розширення AL до AX можна скористатися командою CBW (Convert Byte to Word - перетворити байт у слово).
CBW
ADD AX,20H
Але повне слово має також обмеження: один знаковий біт і 15 біт даних, що відповідає значенням від -32768 до +32767. Розглянемо далі як можна обробляти числа, перевищуючі ці межі.
Додавання багатобайтних чисел
Наведемо універсальну процедуру додавання двох чисел довільної розмірності, використовуючи додавання окремих слів.
При цьому слід: 1) забезпечити сусідство слів; 2) виконувати обробку від молодшого до старшого слова; 3) завантажити в регістр CX кількість слів, що будуть додаватися
Дія починається з додавання наймолодших полів, тобто тих слів, що розташовані в пам’яті за молодшими адресами. У першому циклі додаються ліві слова, а у другому - слова, розташовані правіше. При цьому адреси в регістрах SI, DI і BX збільшуються на 2. Цю операцію виконують по дві команди INC для кожного регістра. Застосовувати команду ADD reg,02 у цьому випадку не можна, тому що при цьому буде очищений прапорець переносу, що приведе до спотворення результату додавання. Оскільки використовується цикл, виконується лише команда додавання ADC. Перед циклом команда CLC (CLear Carry - очистити прапор переносу) установлює нульове значення прапорця переносу.
DOSSEG
.MODEL SMALL
.STACK 100h
.DATA
X DW 1111h, 2222h
Y DW 3333h,4444h
Z DW 3 dup(0)
.CODE
mov ax,@data
mov ds,ax
clc
mov cx,2
lea si,X
lea di,y
lea bx,z
l1:
mov ax,[si]
adc ax,[di]
mov [bx],ax
inc si
inc si
inc di
inc di
inc bx
inc bx
loop l1
adc [bx],0
cmp [bx],0
je Lexit
mov [bx],0ffffh
Lexit:
mov ah,4Ch
int 21h
Беззнакові й знакові дані.
Числові поля можуть трактуватися як знакові, або як беззнакові. Це контролюється при написанні програми самостійно.
Для беззнакових величин всі біти є бітами даних і замість обмеження +32767 регістр може містити числа до +65535. Для знакових величин лівий біт є знаковим. Команди ADD і SUB не роблять різниці між знаковими і беззнаковими величинами, вони просто додають і віднімають біти.
Наприклад при додаванні двох двійкових чисел, одне з яких містить одиничний лівий біт можливе такі випадки. Для беззнакового числа біти представляють додатнє позитивне число 249, для знакового – від’ємна число -7:
| Беззнакове | Знакове |
11111001 | 249 | -7 |
00000010 | 2 | +2 |
11111011 | 251 | -5 |
Двійкове представлення результату додавання однакове для беззнакового й знакового числа. Однак, біти представляють +251 для беззнакового числа й -5 для знакового. Таким чином, числовий вміст поля може інтерпретуватися по різному. Стан "перенос" виникає в тому випадку, коли є пеpенос у знаковий розряд. Стан "переповнення" виникає у тому випадку, коли перенос у знаковий розряд не створює переносу з розрядної сітки або перенос із розрядної сітки відбувається без переносу в знаковий розряд. При виникненні переносу при додаванні беззнакових чисел, результат одержується неправильний:
| Беззнакове | Знакове | CF | OF |
11111100 | 252 | -4 |
|
|
00000101 | 5 | +5 |
|
|
00000001 | 1 | 1 | 1 | 0 |
| (неправильно) |
|
|
|
При виникненні переповнення при додаванні знакових чисел, результат виходить неправильний:
| Беззнакове | Знакове | CF | OF |
01111001 | 121 | +121 |
|
|
00001011 | 11 | +11 |
|
|
10000100 | 132 | -124 | 0 | 1 |
|
| (неправильно) |
|
|
При операціях додавання й віднімання може одночасно виникнути й переповнення, і перенос:
| Беззнакове | Знакове | CF | OF |
11110110 | 246 | -10 |
|
|
10001001 | 137 | -119 |
|
|
01111111 | 127 | +127 | 1 | 1 |
| (неправильно) | (неправильно) |
|
|
Таким чином, в попередній програмі перенос, що може виникати при додаванні найстарших слів, слід трактувати для беззнакових даних як значущий біт і враховувати його в загальній сумі, а для знакових, вважати ознакою від’ємного числа.
Таким чином, універсальна програма для додавання знакових чисел повинна у випадку від’ємного результату заміняти найстарше слово результату.
Для віднімання багатобайтних чисел слід використовувати команду SBB (віднімання з запозиченням), яка є еквівалентом ADD.