Команды сложения
Краткое теоретическое содержание работы
Арифметические команды процессора
В язык ассемблера входит относительно небольшое количество примитивных математических операторов. Математические команды ограничиваются сложением, умножением, делением и вычитанием знаковых и беззнаковых целых двоичных чисел. Математические команды процессора 8086 представлены в табл. 2.1.
Команды сложения
Команды add и adc, суммируют два байта или слова. Inc (инкремент) —Команда быстрого добавления 1 к регистру или значению в памяти. Aaa и daa выполняют коррекцию значений, представленных в двоично-десятичном формате. Для сложения 8-битового значения в ah с 8-битовым значением в bh запишем: add ah, bh ; ahÜah+bh
Для add требуется операнд-источник и операнд-назначение. Команда суммирует два значения и записывает результат в заданное место, заменяя первоначальное значение. В примере результат записан в регистр ah. Команда adc работает аналогично, но добавляет к результату флаг переноса cf:
adc ah, bh ;ahÜah+bh+cf
Если cf равен 1, то результат получается таким же, как при добавлении 1 к сумме ah и bh. Флаг cf устанавливается в 1, если в предыдущем сложении возникло переполнение. Поэтому adc чаще используют для после add, складывающего многобайтовые значения, информируя о переносах, которые возникают при сложении отдельных байтов. Как add, так и adc могут прибавлять к регистрам и значениям в памяти непосредственные (литеральные) значения: add bx, 5 ; bxÜbx+5
Для быстрого прибавления 1 к некоторому значению, вместо add используют “inc”. Следующие команды увеличивают на 1 значения четырех регистров общего назначения: inc ax ;axÜax+1
Команда aaa преобразует содержимое регистра AL в правильную неупакованную десятичную цифру в младших четырех битах регистра AL и заполняет нулями старшие четыре бита. Она используется в контексте:
add al, bl ;Сложить неупакованные числа в al и bl
aaa ;преобразовать результат в неупакованное число
Если результат превышает 9, то команда aaa добавляет 1 к содержимому AH и устанавливает CF в 1; в противном случае CF=0. Остальные флаги считаются уничтоженными(AF, PF, ZF, SF, OF).
Команда daa преобразует содержимое регистра AL в две правельные упакованные десятичные цифры. Она используется в контексте:
aad al, bl ;Сложить упакованные десятичные числа в al и bl
daa ;преобразовать результат в упакованное число
Если результат превышает предельное значение для упакованных десятичных чисел (99), то команда daa добавляет 1 к содержимому регистра AH и устанавливает флаг CF в 1. Остальные флаги считаются не уничтоженными.
2.1.2 Команды вычитания
По форме вычитание в языке ассемблера аналогично сложению. Команда sub вычитает значения байтов или слов. Команда sbb делает тоже самое, но учитывает возможный заем при предыдущем вычитании многобайтовых или многословных значений: sub cx, bx ; axÜax-bx
Если размеры операндов превышают 16 битов, то используют следующую последовательность команд: sub ax, bx ; вычесть младшие 16 битов, ax=ax-bx
sbb dx, cx ; вычесть старшие 16 битов, dx=dx-cx-cf
Допускается вычитать два регистра или регистр и значение, записанное в памяти. Допускается вычитать непосредственные значения: sub ax, 1 ;axÜax-1
Хотя уменьшение на единицу рациональнее заменить быстрой командой dec, которая вычитает 1 из регистра или значения в памяти. Допускается уменьшать на 1 значения, представленные байтом или словом: dec [balance] ;[balance]Ü[balance]-1.
Команда aas преобразует содержимое регистра AL в правильную неупакованную десятичную цифру в младших четырех битах регистра AL и заполняет нулями старшие четыре бита. Она используется в контексте: sub al, bl ;вычесть неупакованные числа, alÞal-bl
aas ;преобразовать результат в неупакованное число
Если результат превышает 9, то команда aas вычитает 1 из содержимого регистра AH и устанавливает флаг CF в 1, в противном случае CF обнуляется. Остальные флаги считаются уничтоженными(AF, PF, ZF, SF, OF).
Команда DAS преобразует содержимое регистра AL в две правильные упакованные десятичные цифры. Она используется в контексте:
sub al, bl ;вычесть упакованное число bl из al
das ;преобразовать результат в упакованное число
Если результат превышает предельное значение для упакованных десятичных чисел (99), то команда das вычитает 1 из содержимого регистра al в две правильные десятичные цифры. Она используется в следующем контексте:
sub al, bl ;вычесть упакованные числа
das ;преобразовать результат в упакованное число
Если результат превышает предельное значение для упакованных чисел (99), то команда das вычитает 1 из содержимого регистра ah и устанавливает флаг CF в 1; в противном случае она его обнуляет. Остальные флаги считают уничтоженными.
Программа 2.1 представляет работу четырех команд—add, sub, inc и dec. Выполнить ассемблирование, компоновку и запуск программы под управлением Turbo Debuger, можно при помощи следующих команд:
Программа 2.1. ADDSUB.ASM
%TITLE «Использование команд add, sub, inc, dec»
IDEAL | |||
MODEL small | |||
STACK 256 | |||
DATASEG | |||
exCode | DB | ||
cout | DW | ||
CODESEG | |||
Start: | mov | ax, @data | ; Установка в DS адреса |
mov | ds, ax | ;сегмента данных | |
mov | ax, 4 | ||
mov | bx, 2 | ||
add | ax, bx | ; axÜax+bx | |
mov | cx, 8 | ||
add | cx, [count] | ; [count]Ücx+[count] | |
inc | [count] | ; [count] Ü[count]+1 | |
dec | [count] | ; [count]Ü[count]-1 | |
inc | ax | ; axÜax+1 | |
dec | cx | ; cxÜcx-1 | |
Exit: | mov | ah, 04Ch | ;Ф-ция DOS/ Выход из программы |
mov | al, [exCode] | ;Возврат значения кода ошибки | |
int | 21h | ;Вызов DOS. Останов программы | |
END | Start | ;Конец программы/точка выхода |
2.1.3 Использование команд neg и cmp
При выполнении команды neg процессор вычитает соответствующее значение из 0. Это значение может быть записано в регистр или память. При вычитании значения из 0 получается дополнительный код числа, что эквивалентно изменению всех нулей на единицы, единиц на нули и прибавлением 1.
neg ax ; Получение двоичного дополнения ax
neg [value] ; Получение двоичного дополнения [value]
Большинство цифровых процессоров выполняют сравнение значений путем вычитания одного из другого, проверяя затем результат. После выполнения таким способом операции сравнения устанавливаются биты различных флагов. Описывая тем самым результат. Сmp выполняет вычитание аналогично команде sub, однако сохраняет при этом только значения флагов, которые могут проверяться другими командами.
2.1.4 Умножение и деление беззнаковых чисел
Для правильного умножения и деления требуется помещать значения в соответствующие регистры. После операции необходимо правильно извлекать ответ. Для наглядности, запустите программу 2.2 в Turbo Debuger и понаблюдайте за работой команд mul, imul, div и idiv. Для ассемблирования, компоновки программы и загрузки в Turbo Debuger выполните следующие команды:
Программа 2.2. MULDIV.ASM
%TITLE | «Использование | команд mul, | div, imul, idiv» |
IDEAL | |||
MODEL | small | ||
STACK | |||
DATASEG | |||
exCode | DB | ||
opByte | DB | ||
opWord | DW | ||
sourceB | DB | ||
sourceW | DW | ||
CODESEG | |||
Start: | mov | ax, @data | ;Установить DOS адрес |
mov | ds, ax | ; сегмента данных | |
mov | al, [opByte] | ||
mul | [sourcB] | ;axÜal*[sourceb] | |
mov | ax, [opword] | ||
mul | [sourceW] | ; ax, dxÜax*[sourceW] | |
mov | ax, [opWord] | ||
mul | ax | ;ax, dxÜax*ax | |
mov | ax, [opWord] | ||
div | [sourceB] | ;alÜax div [sourceB] | |
mov | ax, [opWord] | ||
mov | dx,[opWord] | ||
div | [sourceW] | ;axÜax, dx div [sourceW] | |
Exit: | mov | ah, 04Ch | ;Ф-ция DOS/ Выход из ;программы |
mov | al, [exCode] | ;Возврат значения кода ;ошибки | |
int | 21h | ;Вызов DOS. Останов ;программы | |
END | Start | ;Конец программы/точка ;выхода |
При выполнении беззнакового умножения и деления необходимо использовать определенные регистры и иметь ввиду, что 32-битовый результат и операнды записываются в два регистра—dx и ax. Операнд-источник для команды mul и div может располагаться в памяти либо в любом другом регистре общего назначения. Так как размер операнда-источника определяет размер результата, то случайное перемножение вместо байтовых переменных, переменных длиной в слово вызовет изменение регистра dx.
2.1.5 Умножение и деление знаковых значений
Команды знакового умножения imul и деления idiv работают аналогично и используют те же регистры, что и mul и div. Отличие состоит в допустимых диапазонах значений:
- Знаковый байт изменяется от -128 до +127
- Знаковое слово изменяется от -32768 до +32767
Необходимо помнить, что отрицательный результат представляется в двоичном дополнительном коде. Любой остаток (ah—для 8-битового деления и dx—для деления слов) имеет тот же знак, что и частное. При попытке выполнить деление на 0 или если результат от деления не будет помещаться в заданный операнд-назначение, то будет генерироваться прерывание деления на 0, останавливающее программу. При использовании знаковых двоичных значений часто необходимо преобразовать 8-битовые значения байтов в 16-битовые слова, в частности при подготовке к умножению или делению. Значение может быть отрицательным числом, представленным в дополнительном коде, поэтому выполнять такие преобразования достаточно сложно, поскольку необходимо сохранять как первоначальное значение, так и его знак. Для упрощения этих операций используют команды cbw (преобразовать байт в слово) и cwd (преобразовать слово в двойное слово).
mov al, [sourceB] ; Загружает исходный байт в al
cbw ; Размножает знаковый бит по всему ax
mov ax, [sourceW] ; Загружает исходное слово в ax
cwd ; Дублирует знаковый бит ax через dx
Исходное значение для cbw должно содержаться в регистре al. 16-битовый результат всегда помещается в ax. Начальное значение для cwd должно храниться в регистре ax. 32-битовый результат всегда помещается в dx и ax.
2.2 Логические команды процессора
В табл. 2.2 представлены логические команды процессора.
Логические команды позволяют создавать выражения, объединяющие байты и слова с and, or и другими логическими операторами. Команды сдвига/ротации выполняют сдвиг и ротацию в байтах и словах. Простейшая команда not изменяет в байтах и словах значение битов с нулей на единицы и с единиц на нули. Одно из применений оператора not состоит в переключении между истинным и ложным значениями. Если ложь представляется нулевым значением, а ненулевое значение означает истину, тогда следующие команды переводят регистр dx из состояния «истина» в состояние «ложь» и затем снова возвращают в состояние «истина»:
mov dh, -1 ; Присвоить dh истинное значение (не нуль)
not dh ; Присвоить dh значение ложь
not dh ; Присвоить значение истина
2.2.1 Логические операторы
Логические операторы and, or и xor позволяют манипулировать отдельными битами в двоичных величинах. Позволяют устанавливать или сбрасывать единичные биты без влияния на другие, выделять из байта или слова один или несколько битов и выполнять другие операции.
And часто применяется для маскирования (выделения) битов в байтах и словах. Изучив табл. 2.3., можно увидеть, что a и с одновременно равны 1 только в том случае, если значение b равно 1. Это позволяет создавать фильтры для извлечения битов из байтов:
Таблица 2.3
Команда not инвертирует состояние каждого бита и не на какие флаги не воздействует.
Команда test аналогична and, отличие заключается в том, что она не сохраняет результат, однако изменяет содержимое флагов. Обнуляет CF и OF, изменяет PF, ZF, и SF, а флаг AF оставляет неопределенным.
2.2.2 Сдвиги битов
Команды сдвига битов делятся на четыре группы:
- Простые сдвиги(shl, shr)
- Простые ротации(rol, ror)
- Ротации через cf (rcl, rcr)
- Арифметические сдвиги (sal, sar)
Наиболее общая команда сдвига shl, используется следующим образом:
shl ax, n ; Сдвиг ax влево на n бит
n должно равняться 1 для процессоров 8086. Для процессоров 80386 в качестве n допускается использование беззнаковой 8-битовой константы.
Сдвиг более чем на 1 бит на процессоре 8086 выполняется в два этапа: сначала в регистр cl загружается счетчик сдвигов, затем cl используется в качестве второго операнда команды сдвига:
mov cl, 5 ;Загрузить счетчик сдвигов в cl
shl ax, cl ;Сдвиг ax на cl бит
Для счетчика сдвигов допускается использовать только регистр cl. Допускается выполнение сдвигов значений находящихся в памяти и в 8-битовых половинах регистров.
mov cl, 2 ;Загрузить счетчик сдвигов в cl
shl bh, cl ;Сдвиг влево на cl бит
shl [seconds], 1 ;Сдвиг [seconds] влево на один бит
dhl [minutes], cl ;Сдвиг [menutes] влево на cl бит
При выполнении команды shl седьмой бит (старший значащий разряд) перемещается во флаги переноса, а правый освобождающийся бит заполняется нулем. При выполнении команды shr нулевой бит (младший значащий разряд) перемещается во флаги переноса, а левый освобождающийся бит заполняется нулем. Команды ротации rol и ror не обнуляют биты слева и справа, а перемещают значения младшего или старшего значащего разряда на противоположный конец. Остальные биты переносятся в указанном направлении. Перемещаемые биты заносятся во флаги переноса. Для команд rcl и rcr однобитовый флаг переноса служит как бы расширением регистра или памяти при выполнении ротации. При выполнении команды rcl старший значащий разряд сдвигается во флаг переноса, а предыдущее значение флага переноса становится на место младшего значащего разряда. При выполнении команд rcr младший значащий разряд сдвигается во флаг переноса, а старое значение флага переноса помещается на место старшего значащего разряда. Остальные биты сдвигаются в указанном направлении. Команда sar работает аналогично shr, за исключением того, что старший значащий разряд сохраняет свое первоначальное значение. Старший значащий разряд копируется в правый от себя бит.
В отличие от других парных команд сдвига у команды sar отсутствует соответствующий левый аналог. Для устранения этого недостатка команде shl дается второе мнемоническое название - sal. Функционально команда sar заменяется командами shl/ sal, которые могут умножать отрицательные значения, представленные в виде дополнительного кода на степени числа 2, и поэтому нет необходимости в отдельной команде. Все команды сдвигов могут работать и на 16-битовых значениях.
Причины использования в программах команд сдвига:
- передвижения битов в заданные положения;
- деление и умножение на степени 2.
Например, dh равен 3, dl - 5 и программе требуется разместить эти два числа в регистре dh, причем 3 должна размещаться, начиная со старшего значащего разряда, а 5 - в младшей значащей части байта. Это выполняется следующим образом:
mov dh, 3 ; dh Ü3
mov dl, 5 ; dl Ü5
mov cl, 4 ; Загрузить счетчик в cl
shl dh, cl ; Сдвиг dh влево на четыре бита
or dh, dl ; dh Ü dh OR dl
2.2.3 Деление и умножение с помощью сдвига
Умножение - с помощью сдвига влево, деление - с помощью сдвига вправо. Например:
0110 1011 (начальное значение)
+ 0110 1011 (сложение с тем же значением)
1101 0110 (сдвиг значения влево)
Сложение значения с самим собой вызывает сдвиг всех битов на одну позицию влево. Другими словами, умножение на 2 эквивалентно сдвигу на один бит влево. Следующее умножение полученного результата на 2, т.е. начального значения на 4, или 22, снова сдвигает биты на одну позицию влево. Общее правило: чтобы умножить любое значение на степень 2, необходимо выполнить сдвиг влево на количество битов, равное показателю степени. Чтобы найти величину х*24, т.е. х*16, в значении х нужно выполнить сдвиг на четыре бита влево. Сдвиг вправо соответствует делению этого числа на значения 2, 4, 8 и т.д. Для нахождения результата деления 1010 1111 (AF в шестнадцатеричной, или 175 в десятичной системе) на 4 необходимо только дважды сдвинуть биты вправо:
1010 1111 (начальное значение)
0101 0111 (деление на два)
0010 1011 (следующее деление на два)
В результате получится значение 00101011 (2В в шестнадцатеричной, или 43 в десятичной системе), что при отбрасывании остатка равно частному от деления 175 на 4. По аналогии с умножением деление на степень числа 2 соответствует сдвигу начального значения на количество битов, равное показателю степени.
Ограничения:
- умножать и делить на степени 2 можно только беззнаковые значения;
- произведение должно по размеру соответствовать начальному значению.
В большинстве случае сдвиги выполняются быстрее, чем команды mul, imul, div, idiv. Например; для умножения какого-либо числа на 8 (23) необходимо сдвинуть это значение три раза влево:
mov ax, 6 ; ax Ü 6
mov cl, 3 ; Загрузить счетчик в cl
shl ax, cl ; ax Ü ax*8
Для деления на 16 (24) сдвиньте соответствующее значение вправо на 4 бита:
mov cl, 4 ; Загрузить счетчик в cl
shr ax, cl ; ax Ü ax/16
Единственной проблемой при умножении является возможность возникновения переполнения, которое не учитывается в этих примерах. Если значение флага после сдвига влево на один бит равняется 1, значит, результат не помещается в назначенный регистр или область памяти. При сдвиге более чем на 1 определять переполнения становиться сложно. При делении теряется остаток - деление 3 на 2 с помощью сдвига на один бит вправо дает в результате 1 и найти остаток не представляется возможным.
3 Контрольные вопросы
1. Какие флаги изменяет команда ADD?
2. Когда используется команда ADC?
3. Какими могут быть операнды в команде SUB?
4. Как складываются значения размером больше 16 бит?
5. Как используется команда AAA?
6. Как используется команда AAS?
7. Как используется команда DAA?
8. Как используется команда DAS?
9. Как используется команда AAM?
10. Как используется команда AAD?
11. Для чего используется команда TEST?
12. Перечислите логические команды процессора.
13. Куда помещается старший бит при сдвиге влево?
14. Как изменяется флаг OF при выполнении команды SAL?
4 Задание
Вычислить значение, в соответствии с указанным вариантом:
1. Вычислить
2. Вычислить
3. Вычислить
4. Вычислить
5. Вычислить
6. Вычислить
7. Вычислить
8. Вычислить
9. Вычислить
10. Вычислить
11. Вычислить
12. Вычислить
13. Вычислить
14. Вычислить
15. Вычислить
16. Вычислить
17. Вычислить
18. Вычислить
19. Вычислить
20. Вычислить
A, B, C, D, X—произвольные целые числа от 0 до 255.
5 Содержание отчета
1. Титульный лист.
2. Краткое теоретическое описание
3. Задание на лабораторную работу, включающее формулировку задачи.
4. Листинг программы.
5. Результаты выполнения программы.
Дата добавления: 2015-09-29; просмотров: 1572;