Jazik_Assemblera_dlja_IBM_PC_i_programmir
.pdf
|
DEC |
BX |
|
|
DEC |
BX |
;Повторить цикл |
|
LOOP |
Е20 |
|
E10DWD |
RET |
|
|
ENDP |
|
|
|
CODESG |
ENDS |
BEGIN |
|
|
END |
|
__________________________________________________________________________
Рис.12.2. Сложение двойных слов.
На рис.12.2 процедура D10DWD демонстрирует простой способ сложения содержимого одной пары слов (WORD1A и WORD1B) с содержимым второй пары слов (WORD2A и WORD2B) и сохранения суммы в третьей паре слов (WORD3A и WORD3B). Сначала выполняется сложение правых слов:
WORD1B |
BC62 |
WORD2B |
553A |
Сумма: |
----- |
1119C |
Сумма - шест.1119C превышает емкость регистра AX. Переполнение вызывает установку флага переноса в 1. Затем выполняется сложение левых слов, но в данном случае, вместо команды ADD используется команда сложения с переносом ADC (ADd with Carry). Эта команда складывает два значения, и если флаг CF уже установлен, то к сумме прибавляется 1:
WORD1A |
0123 |
WORD2A |
0012 |
Плюс перенос |
1 |
Сумма: |
---- |
0136 |
При использовании отладчика DEBUG для трассировки арифметических команд можно увидеть эту сумму 0136 в регистре AX, и обpатные значения
3601 в поле WORD3A и 9C11 в поле WORD3B.
На рис.12.2 процедура E10DWD демонстрирует подход к сложению значений
любой длины. |
Действие начинается со сложения самых |
|
правых |
|
слов |
||||
складываемых полей. |
В первом цикле складываются правые cлова, во втором - |
||||||||
слова, расположенные левее. При этом адреса |
в регистрах |
SI, |
DI |
и |
BX |
||||
уменьшаются на |
2. По две команда DEC выполняют эту |
операцию |
для |
каждого |
|||||
регистра. Применять команду |
|
|
|
|
|
|
|
||
|
SUB |
reg,02 |
|
|
|
|
|
|
|
в данном случае нельзя, т.к. при этом будет |
очищен |
флаг |
переноса, |
что |
|||||
приведет к искажению результата сложения. |
|
|
|
сложения |
|
ADC. |
|||
Ввиду наличия цикла, используется только одна команда |
|
||||||||
Перед циклом |
команда CLC (CLear Carry - очистить флаг |
переноса) |
|||||||
устанавливает нулевое значение флага переноса. |
Для работы данного |
метода |
|||||||
необходимо: 1) |
обеспечить смежность слов, 2) |
выполнять |
обработку |
справа |
|||||
налево и 3) загрузить в регистр CX число складываемых слов. |
|
|
|
with |
|||||
Для многословного вычитания используется команда SBB |
(SuBtract |
|
|||||||
Borrow - вычитание с заемом) эквивалентная команде ADC. Заменив в
процедуре E10DWD (рис.12.2) команду ADC на SBB, |
получим |
процедуру |
для |
вычитания. |
|
|
|
БЕЗЗНАКОВЫЕ И ЗНАКОВЫЕ ДАННЫЕ |
|
|
|
________________________________________________________________ |
|
||
Многие числовые поля не имеют знака, например, номер абонента, |
aдрес |
||
памяти. Некоторые числовые поля предлагаются |
всегда |
положительные, |
|
например, норма выплаты, день недели, значение числа ПИ. Другие числовые поля являются знаковые, так как их содержимое может быть положительным или отрицательным. Например, долговой баланс покупателя, который может быть отрицательным при переплатах, или алгебраическое число.
Для беззнаковых величин все биты являются битами данных и вместо ограничения +32767 регистр может содержать числа до +65535. Для знаковых величин левый байт является знаковым битом. Команды ADD и SUB не делают разницы между знаковыми и беззнаковыми величинами, они просто складывают и
вычитают биты. В следующем примере сложения двух двоичных |
чисел, |
первое |
||
число содержит единичный левый бит. Для |
беззнакового |
числа |
биты |
|
представляют положительное число 249, для знакового - отрицательное |
число |
|||
-7: |
|
|
|
|
11111001 |
Беззнаковое |
Знаковое |
|
|
249 |
-7 |
|
|
|
00000010 |
2 |
+2 |
|
|
11111011 |
--- |
-- |
|
|
251 |
-5 |
|
|
|
Двоичное представление результата сложения одинаково |
для |
беззнакового |
и |
|||||
знакового числа. |
Однако, биты представляют +251 для беззнакового числа |
и |
||||||
-5 для знакового. Таким образом, числовое содержимое |
поля |
может |
||||||
интерпретироваться по разному. |
|
|
|
|
пеpенос |
в |
||
Состояние "перенос" возникает в том случае, когда имеется |
||||||||
знаковый разряд. |
Состояние "переполнение" возникает в том |
случае, |
когда |
|||||
перенос в знаковый разряд не |
создает переноса из |
разрядной |
сетки |
|
или |
|||
перенос из разрядной сетки происходит без переноса в |
знаковый разряд. |
|
При |
|||||
возникновении переноса при |
сложении |
беззнаковых |
чисел, |
результат |
||||
получается неправильный: |
|
|
|
|
|
|
|
|
11111100 |
Беззнаковое |
Знаковое |
CF |
OF |
|
|
|
|
252 |
-4 |
|
|
|
|
|
||
00000101 |
5 |
+5 |
|
|
|
|
|
|
00000001 |
--- |
-- |
1 |
0 |
|
|
|
|
1 |
1 |
|
|
|
||||
(неправильно)
При возникновении переполнения при сложении знаковых чисел, результат получается неправильный:
01111001 |
Беззнаковое |
Знаковое |
CF |
OF |
121 |
+121 |
|
|
|
00001011 |
11 |
+11 |
|
|
10000100 |
--- |
---- |
0 |
1 |
132 |
-124 |
|||
|
(неправильно) |
|
|
|
При операциях сложения и вычитания может |
одновременно |
возникнуть и |
||
переполнение, и перенос: |
|
|
|
|
11110110 |
Беззнаковое |
Знаковое |
CF |
OF |
246 |
-10 |
|
|
|
10001001 |
137 |
-119 |
|
|
01111111 |
--- |
---- |
1 |
1 |
127 |
+127 |
|||
|
(неправильно) |
(неправильно) |
|
|
УМНОЖЕНИЕ
________________________________________________________________
Операция умножения для беззнаковых данных выполняется командой MUL, а для знаковых - IMUL (Integer MULtiplication - умножение целых чисел). Ответственность за контроль над форматом обрабатываемых чисел и за выбор
подходящей команды умножения лежит на самом программисте. |
Существуют |
две |
|||
основные операции |
умножения: |
|
|
|
|
"Б а й т н |
а б а й т". |
Множимое находится в |
регистре AL, |
а |
|
множитель в байте |
памяти или |
в |
однобайтовом регистре. |
После умножения |
|
произведение находится в регистре AX. |
Операция игнорирует и стиpает любые |
|||
данные, которые находились в регистре AH. |
|
|
||
| AH | AL | |
| |
AX |
| |
|
До умножения: | |
|Множимое| |
После: |Произведение| |
||
"С л о в о н а с л о в о". Множимое находится в регистре AX, а множитель - в слове памяти или в регистре. После умножения произведение находится в двойном слове, для которого требуется два регистра: старшая (левая) часть произведения находится в регистре DX, а младшая (правая) часть в регистре AX. Операция игнорирует и стирает любые данные, которые находились в регистре DX.
| AX | |
| |
DX |
|| AX |
| |
До умножения:|Множимое| |
После: |Ст.часть||Мл.часть| |
|||
|
| |
Произведение |
| |
|
В единственном операнде команд |
MUL и |
IMUL |
указывается |
множитель. |
Рассмотрим следующую команду: MUL MULTR
Если поле MULTR определено как байт (DB), то операция предполагает умножение содержимого AL на значение байта из поля MULTR. Если поле MULTR определено как слово (DW), то операция предполагает умножение содержимого AX на значение слова из поля MULTR. Если множитель находится в регистре, то длина регистра определяет тип операции, как это показано ниже:
MUL CL ;Байт-множитель: множимое в AL, произвед. в AX MUL BX ;Слово-множитель:множимое в AX, произвед. в DX:AX
Беззнаковое умножение: Команда MUL
------------------------------------
Команда MUL (MULtiplication - умножение) умножает беззнаковые числа. На рис.12.3 в процедуре C10MUL дано три примера умножения: байт на байт, слово на слово и слово на байт. Первый пример команды MUL умножает шест.80 (128) на шест.47 (64). Произведение шест.2000 (8192) получается в регистре
AX.
__________________________________________________________________________
TITLE |
page 60,132 |
|
|
EXMULT |
(COM) Пример команд умножения |
||
CODESG |
SEGMENT |
PARA 'Code' |
|
|
ASSUME |
CS:CODESG,DS:CODESG,SS:CODESG |
|
BEGIN: |
OR6 |
100H |
|
JMP |
SHORT MAIN |
|
|
; ------------------------------------------- |
DB |
80H |
|
BYTE1 |
|
||
BYTE2 |
DB |
40H |
|
WORD1 |
DW |
8000H |
|
WORD2 |
DW |
4000H |
|
; ------------------------------------------- |
PROC |
NEAR |
;Основная процедура: |
MAIN |
|||
|
CALL |
C10MUL |
;Вызвать умнож. MUL |
|
CALL |
D10IMUL |
;Вызвать умнож. IMUL |
MAIN |
RET |
|
|
ENDP |
|
|
|
;Пример умножения MUL:
; |
PROC |
-------------------- |
|
|
C10MUL |
AL,BYTE1 |
;Байт * байт |
||
|
MOV |
|||
|
MUL |
BYTE2 |
; |
произведение в AХ |
|
MOV |
AX,WORD1 |
;Слово * слово |
|
|
MUL |
WORD2 |
; |
произведение в DX:AX |
|
MOV |
AL,BYTE1 |
;Байт * слово |
|
|
SUB |
AН,AН |
; расшир. множ. в AН |
|
|
MUL |
WORD1 |
; |
произведение в DX:AX |
C10MUL |
RET |
|
|
|
ENDP |
|
|
|
|
;Пример умножения IMUL:
; |
--------------------- |
|
D10IMUL PROC |
AL,BYTE1 |
;Байт * байт |
MOV |
||
IMUL |
BYTE2 |
; произведение в AХ |
MOV |
AX,WORD1 |
;Слово * слово |
IMUL |
WORD2 |
; произвед. в DX:AX |
MOV |
AL,BYTE1 |
;Байт * слово |
CBW |
WORD1 |
; расшир. множ. в AН |
IMUL |
; произвед. в DX:AX |
|
RET |
|
|
D10IMUL ENDP |
|
|
CODESG ENDS |
BEGIN |
|
END |
|
|
__________________________________________________________________________
Рис.12.3. Беззнаковое и знаковое умножение.
Второй пример команды MUL генерирует шест.10000000 в регистpах DX:AX. Третий пример команды MUL выполняет умножение слова на байт и требует расширение байта BYTE1 до размеров слова. Так как предполагаются беззнаковые величины, то в примере левый бит регистра AH равен нулю. (При использовании команды CBW значение левого бита регистpа AL может быть 0
или 1). Произведение - шест.00400000 получается в регистрах DX:AX.
Знаковое умножение: Команда IMUL
----------------------------------
Команда IMUL (Integer MULtiplication - умножение целых чисел)
умножает знаковые числа. На рис.12.3 в процедуре D10IMUL используются те же три примера умножения, что и в процедуре C10MUL, но вместо команд MUL записаны команды IMUL.
Первый пример команды IMUL умножает шест.80 (отрицательное число) на шест.40 (положительное число). Произведение - шест.E000 получается в
регистре AX. |
Используя те |
|
же |
данные, |
команда |
MUL |
дает в |
результате |
|||||
шест.2000, так что можно видеть разницу в использовании команд MUL и IMUL. |
|||||||||||||
Команда MUL рассматривает шест.80 как +128, а команда IMUL - как |
-128. В |
||||||||||||
результате умножения |
-128 |
|
на |
+64 |
получается |
-8192 |
или |
шест.E000. |
|||||
(Попробуйте преобразовать шест.Е000 в десятичный формат). |
(отрицательное |
||||||||||||
Второй |
пример |
команды |
IMUL |
умножает шест.8000 |
|||||||||
значение) на шест.2000 (положительное |
значение). |
|
Произведение |
- |
|||||||||
шест.F0000000 |
получается |
в |
регистрах |
DX:AX |
и |
представляет |
собой |
||||||
oтрицательное значение. |
|
IMUL |
перед |
умножением |
выполняет |
расширение |
|||||||
Третий пример команды |
|
||||||||||||
байта BYTE1 |
до |
размеров |
|
слова в регистре AX. Так |
как |
значения |
|||||||
предполагаются |
знаковые, |
то в |
примере |
используется |
команда |
CBW |
для |
||||||
перевода левого знакового бита в регистр AH: шест.80 в pегистре AL превращается в шест.FF80 в регистре AX. Поскольку множитель в слове WORD1 имеет также отрицательное значение, то произведение должно получится положительное. В самом деле: шест.00400000 в регистрах DX:AX - такой же
результат, как и в случае умножения командой MUL, которая предполагала положительные сомножители.
Таким образом, если множимое и множитель имеет одинаковый знаковый бит, то команды MUL и IMUL генерируют одинаковый результат. Но, если сомножители имеют разные знаковые биты, то команда MUL вырабатывает положительный результат умножения, а команда IMUL - отрицательный.
Можно обнаружить это, используя отладчик DEBUG для трассировки примеров.
П о в ы ш е н и е э ф ф е к т и в н о с т и у м н о ж е н и я: При умножении на степень числа 2 (2,4,8 и т.д.) более эффективным является сдвиг влево на требуемое число битов. Сдвиг более чем на 1 требует загрузки величины сдвига в регистр CL. В следующих примерах предположим, что множимое находится в регистре AL или AX:
Умножение на 2: |
SHL |
AL,1 |
Умножение на 8: |
MOV |
CL,3 |
|
SHL |
AX,CL |
Многословное умножение |
|
------------------------ |
на слово". |
Обычно умножение имеет два типа: "байт на байт" и "слово |
|
Как уже было показано, максимальное знаковое значение в слове |
ограничено |
величиной +32767. Умножение больших чисел требует выполнения |
некоторых |
дополнительных действий. Рассматриваемый подход предполагает умножение каждого слова отдельно и сложение полученных результатов. Рассмотрим следующее умножение в десятичном формате:
1365 х12
-----
2730
1365
-----
16380
Представим, что десятичная арифметика может умножать только двузначные числа. Тогда можно умножить 13 и 65 на 12 раздельно, cледующим образом:
13 |
65 |
х12 |
х12 |
--- |
--- |
26 |
130 |
13 |
65 |
--- |
--- |
156 |
780 |
Следующим шагом сложим полученные произведения, но поскольку число 13 представляло сотни, то первое произведение в действительности будет 15600:
15600
+780
-----
16380
Ассемблерная программа использует аналогичную технику за исключением того, что данные имеют размерность слов (четыре цифры) в шестнадцатеричном формате.
У м н о ж е н и е д в о й н о г о |
с л о в а |
н а |
с л о в о. |
|
Процедура E10XMUL на рис.12.4 умножает двойное слово на |
слово. Множимое, |
|||
MULTCND, состоит из двух слов, |
содержащих |
соответственно |
шест.3206 и |
|
шест.2521. Определение данных в |
виде двух слов (DW) вместо двойного слова |
|||
(DD) обусловлено необходимостью правильной адресации для команд MOV, пересылающих слова в регистр AX. Множитель MULTPLR содержит шест.6400. Область для записи произведения, PRODUCT, состоит из трех слов. Первая команда MUL перемножает MULTPLR и правое cлово поля MULTCND; произведение
- шест.0E80 E400 записывается в PRODUCT+2 и PRODUCT+4. Вторая команда MUL
перемножает MULTPLR и левое слово поля MULTCND, получая в результате шест. 138A 5800. Далее выполняется сложение двух произведений следующим образом:
Произведение 1: |
0000 |
0E80 |
E400 |
Произведение 2: |
138A |
5800 |
|
Результат: |
-------------- |
||
138A |
6680 |
E400 |
|
Так как первая команда ADD может выработать перенос, то второе cложение выполняется командой сложения с переносом ADC (ADd with Carry). В силу обратного представления байтов в словах в процессоpах 8086/8088, область PRODUCT в действительности будет содержать значение 8A13 8066 00E4. Программа предполагает, что первое слово в области PRODUCT имеет начальное значение 0000.
__________________________________________________________________________
TITLE |
EXDWMUL |
- Умножение двойных слов |
||
CODESG |
SEGMENT |
PARA 'Code' |
|
|
|
ASSUME |
CS:CODESG,DS:CODESG,SS:CODESG |
||
BEGIN: |
ORG |
100H |
|
|
JMP |
SHORT MAIN |
|
||
; --------------------------------------------- |
|
3206H |
;Элементы данных |
|
MULTCND DW |
||||
|
DW |
2521H |
|
|
MULTPLR DW |
6400H |
|
||
|
DW |
0A26H |
|
|
PRODUCT DW |
0 |
|
||
|
DW |
0 |
|
|
|
DW |
0 |
|
|
; |
DW |
0 |
|
|
PROC |
NEAR |
;Основная процедура |
||
MAIN |
||||
|
CALL |
E10XMUL |
;Вызвать 1-е умножение |
|
|
CALL |
Z10ZERO |
;Очистить произведение |
|
|
CALL |
F10XMUL |
;Вызвать 2-е умножение |
|
MAIN |
RET |
|
|
|
ENDP |
Умножение двойного слова на слово: |
|||
; |
|
|||
; ----------------------------------------------- |
|
|
|
|
E10XMUL PROC |
AX,MULTCND+2 |
;Умножить правое слова |
||
|
MOV |
|||
|
MUL |
MULTPLR |
; множимого |
|
|
MOV |
PRODUCT+4,AX |
;Записать произведение |
|
|
MOV |
PRODUCT+2,DX |
|
|
|
MOV |
AX,MULTCND |
;Умножить левое слово |
|
|
MUL |
MULTPLR |
; множимого |
|
|
ADD |
PRODUCT+2,AX |
;Сложить с полученным ранее |
|
|
ADC |
PRODUCT,DX |
|
|
|
RET |
|
|
|
E10XMUL ENDP |
Перемножение двух двойных слов: |
|||
; |
|
|||
; -------------------------------------------- |
|
|
|
|
F10XMUL PROC |
AX,MULTCND+2 |
;Слово-2 множимого |
||
|
MOV |
|||
|
MUL |
MULTPLR+2 |
; * слово-2 множителя |
|
|
MOV |
PRODUCT+6,AX |
;Сохранить результат |
|
|
MOV |
PRODUCT+4,DX |
|
|
MOV |
AX,MULTCND+2 |
;Слово-2 множимого |
MUL |
MULTPLR |
; * слово-1 множителя |
ADD |
PRODUCT+4,AX |
;Сложить с предыдущим |
ADC |
PRODUCT+6,DX |
;Прибавить перенос |
ADC |
PRODUCT,00 |
|
MOV |
AX,MULTCND |
;Слово-1 множимого |
MUL |
MULTPLR+2 |
; * слово-2 множителя |
ADD |
PRODUCT+4,AX |
;Сложить с предыдущим |
ADC |
PRODUCT+6,DX |
;Прибавить перенос |
ADC |
PRODUCT,00 |
|
MOV |
AX,MULTCND |
;Слово-1 множимого |
MUL |
MULTPLR |
; * слово-1 множителя |
ADD |
PRODUCT+2,AX |
;Сложить с предыдущим |
ADC |
PRODUCT,DX |
|
RET |
|
|
F10XMUL ENDP |
|
|
;Очистка области результата:
;----------------------------------------
Z10XMUL PROC
MOV |
PRODUCT,0000 |
MOV |
PRODUCT+2,0000 |
MOV |
PRODUCT+4,0000 |
MOV |
PRODUCT+6,0000 |
RET |
|
Z10XMUL ENDP |
|
CODESG ENDS |
BEGIN |
END |
__________________________________________________________________________
Рис.12.4. Многословное умножение.
У м н о ж е н и е "д в о й н о г о с л о в а н а д в о й н о е с л о в о". Умножение двух двойных слов включает следующие четыре операции умножения:
Множимое |
|
Множитель |
||
слово 2 |
х |
слово 2 |
||
слово 2 |
х |
слово 1 |
||
слово |
1 |
х |
слово |
2 |
слово |
1 |
х |
слово |
1 |
Каждое произведение в регистрах DX и AX складывается |
с |
соответствующим |
||||||
словом в окончательном результате. |
Пример |
такого |
умножения приведен в |
|||||
процедуре F10XMUL на рис.12.4. Множимое MULTCND содержит шест.3206 |
2521, |
|||||||
множитель MULTPLR - шест.6400 |
0A26. |
Результат заносится в область PRODUCT, |
||||||
состоящую из четырех слов. |
|
слов |
аналогична |
умножению |
двойного |
|||
Хотя логика умножения двойных |
||||||||
слова на слово, имеется одна |
особенность, |
после |
пары |
команд |
сложения |
|||
ADD/ADC используется еще одна команда ADC, которая |
прибавляет 0 к значению |
|||||||
в поле PRODUCT. Это необходимо потому, что первая |
команда ADC сама |
может |
||||||
вызвать перенос, который последующие команды могут стереть. Поэтому вторая
команда ADC прибавит 0, если переноса нет, |
и прибавит 1, если перенос |
|
есть. Финальная пара команд ADD/ADC не требует дополнительной команды ADC, |
||
так как область PRODUCT достаточно |
велика |
для генерации окончательного |
результата и переноса на последнем этапе не |
будет. |
|
Окончательный результат 138A |
687C 8E5C |
CCE6 получится в поле PRODUCT |
в обратной записи байт в словах. |
Выполните трассировку этого примера с |
|
помощью отладчика DEBUG. |
|
|
СДВИГ РЕГИСТРОВОЙ ПАРЫ DX:AX
________________________________________________________________
Следующая подпрограмма может быть полезна для сдвига содержимого pегистровой пары DX:AX вправо или влево. Можно придумать более эффективный метод, но данный пример представляет общий подход для любого числа циклов (и, соответственно, сдвигов) в регистре CX. Заметьте, что сдвиг единичного бита за разрядную сетку устанавливает флаг переноса.
MOV |
Сдвиг влево на 4 бита |
4 |
цикла |
|
CX,04 |
;Инициализация на |
|||
C20: SHL |
DX,1 |
;Сдвинуть DX на 1 |
бит влево |
|
SHL |
AX,1 |
;Сдвинуть AX на 1 |
бит влево |
|
ADC |
DX,00 |
;Прибавить значение |
переноса |
|
LOOP |
C20 |
;Повторить |
|
|
MOV |
Сдвиг вправо на 4 бита |
4 |
цикла |
|
CX,04 |
;Инициализация на |
|||
D20: SHR |
AX,1 |
;Сдвинуть AX на 1 |
бит вправо |
|
SHR |
DX,1 |
;Сдвинуть DX на 1 |
бит вправо |
|
JNC |
D30 |
;Если есть перенос, |
в AH |
|
OR |
AH,10000000B ; то вставить |
1 |
||
D30: LOOP |
D20 |
;Повторить |
|
|
Ниже приведен более эффективный способ для сдвига влево, не требующий организации цикла. В этом примере фактор сдвига записывается в регистр CL. Пример написан для сдвига на 4 бита, но может быть адаптирован для других величин сдвигов:
MOV |
CL,04 |
;Установить фактор сдвига |
SHL |
DX,CL |
;Сдвинуть DX влево на 4 бита |
MOV |
BL,AH |
;Сохранить AH в BL |
SHL |
AX,CL |
;Сдвинуть AX влево на 4 бита |
SHL |
BL,CL |
;Сдвинуть BL вправо на 4 бита |
OR |
DL,BL |
;Записать 4 бита из BL в DL |
ДЕЛЕНИЕ
________________________________________________________________
Операция деления для беззнаковых данных выполняется командой DIV, a для знаковых - IDIV. Ответственность за подбор подходящей команды лежит на программисте. Существуют две основные операции деления:
Д е л е н и е "с л о в а н а б а й т". Делимое находится в регистре AX, а делитель - в байте памяти или а однобайтовом регистре. После деления остаток получается в регистре AH, а частное - в AL. Так как однобайтовое частное очень мало (максимально +255 (шест.FF) для беззнакового деления и +127 (шест.7F) для знакового), то данная операция имеет ограниченное использование.
| AX | |
| AH | AL | |
До деления: |Делимое| |
После: |Остаток|Частное| |
Д е л е н и е "д в о й н о г о с л о в а н а с л о в о". Делимое находится в регистровой паре DX:AX, а делитель - в слове памяти или а регистре. После деления остаток получается в регистре DX, а частное в регистре AX. Частное в одном слове допускает максимальное значение +32767 (шест.FFFF) для беззнакового деления и +16383 (шест.7FFF) для знакового.
| |
DX |
|| AX |
| |
| AH || AL | |
До деления: |Ст.часть||Мл.часть| |
После: |Остаток||Частное| |
|||
| |
|
Делимое |
| |
|
В единственном операнде команд DIV и IDIV указывается делитель. Рассмотрим следующую команду:
DIV DIVISOR
Если поле DIVISOR определено как байт (DB), то операция предполагает деление слова на байт. Если поле DIVISOR определено как слово (DW), то операция предполагает деление двойного слова на слово.
При делении, например, 13 на 3, получается результат 4 1/3. Частное есть 4, а остаток - 1. Заметим, что ручной калькулятор (или программа на языке BASIC) выдает в этом случае результат 4,333.... Значение содержит целую часть (4) и дробную часть (,333). Значение 1/3 и 333... есть дробные части, в то время как 1 есть остаток от деления.
Беззнаковое деление: Команда DIV
----------------------------------
Команда DIV делит беззнаковые числа. На рис.12.5 в процедуре D10DIV дано четыре примера деления: слово на байт, байт на байт, двойное слово на слово и слово на слово. Первый пример команды DIV делит шест.2000 (8092) на шест.80 (128). В результате остаток 00 получается в регистре AH, а частное шест.40 (64) - в регистре AL.
Второй пример команды DIV выполняет прежде расширение байта BYTE1 до размеров слова. Так как здесь предполагается беззнаковая величина, то в примере левый бит регистра AH равен нулю. В результате деления остаток - шест.12 получается в регистре AH, а частное шест.05 - в регистре AL.
Третий пример команды DIV генерирует остаток шест.1000 в регистре DX
ичастное шест.0080 в регистре AX.
Вчетвертом примере команды DIV сначала выполняется расширение слова WORD1 до двойного слова в регистре DX. После деления остаток шест.0000 получится в регистре DX, а частное шест.0002 - в регистре AX.
__________________________________________________________________________
TITLE |
page |
60,132 |
|
EXDIV |
(COM) Пример операций DIV и IDIV |
||
CODESG |
SEGMENT |
PARA 'Code' |
|
BEGIN: |
ORG |
100H |
|
JMP |
SHORT MAIN |
|
|
; --------------------------------------------- |
DB |
80H |
;Data items |
BYTE1 |
|||
BYTE2 |
DB |
16H |
|
WORD1 |
DW |
2000H |
|
WORD2 |
DW |
0010H |
|
WORD3 |
DW |
1000H |
|
; --------------------------------------------- |
PROC |
NEAR |
;Основная процедура |
MAIN |
|||
|
CALL |
D10DIV |
;Вызов подпрограммы DIV |
MAIN |
CALL |
E10IDIV |
;Вызов подпрограммы IDIV |
ENDP |
Примеры с командой DIV: |
||
; |
|
||
; --------------------------------------------- |
PROC |
|
|
D10DIV |
AX,WORD1 |
;Слово / байт |
|
|
MOV |
||
|
DIV |
BYTE1 |
; остаток:частное в AH:AL |
|
MOV |
AL,BYTE1 |
;Байт / байт |
|
SUB |
AH,AH |
; расширить делимое в AH |
|
DIV |
BYTE3 |
; остаток:частное в AH:AL |
|
MOV |
DX,WORD2 |
;Двойное слово / слово |
|
MOV |
AX,WORD3 |
; делимое в DX:AX |
|
DIV |
WORD1 |
; остаток:частное в DX:AX |
|
MOV |
AX,WORD1 |
;Слово / слово |
|
SUB |
DX,DX |
; расширить делимое в DX |
DIV |
WORD3 |
; остаток:частное в DX:AX |
RET |
|
|
D10DIV ENDP |
|
|
;Примеры с командой IDIV:
;---------------------------------------------
E10IDIV PROC
|
MOV |
AX,WORD1 |
;Слово / байт |
|
IDIV |
BYTE1 |
; остаток:частное в AH:AL |
|
MOV |
AL,BYTE1 |
;Байт / байт |
|
CBW |
BYTE3 |
; расширить делимое в AH |
|
IDIV |
; остаток:частное в AH:AL |
|
|
MOV |
DX,WORD2 |
;Двойное слово / слово |
|
MOV |
AX,WORD3 |
; делимое в DX:AX |
|
IDIV |
WORD1 |
; остаток:частное в DX:AX |
|
MOV |
AX,WORD1 |
;Слово / слово |
|
CWD |
WORD3 |
; расширить делимое в DX |
|
IDIV |
; остаток:частное в DX:AX |
|
E10DIV |
RET |
|
|
ENDP |
|
|
|
CODESG |
ENDS |
BEGIN |
|
|
END |
|
__________________________________________________________________________
Рис.12.5. Беззнаковое и знаковое деление.
Знаковое деление: Команда IDIV |
|
|
|
|
|||
-------------------------------- |
знаковых |
чисел. На |
|||||
Команда IDIV (Integer DIVide) выполняет деление |
|||||||
рис.12.5 в процедуре E10IDIV используются те же |
четыре примера |
деления, |
|||||
что и в процедуре D10DIV, но вместо |
команд DIV |
записаны |
команды |
IDIV. |
|||
Первый пример команды IDIV делит шест.2000 |
(положительное число) на |
||||||
шест.80 (отрицательное число). |
Остаток от деления - шест. 00 получается в |
||||||
регистре AH , а частное - шест. |
C0 (-64) - в регистре |
AL. |
Команда |
DIV, |
|||
используя те же числа, генерирует частное +64. |
|
примеров |
деления |
||||
Шестнадцатиричные результаты |
трех остальных |
||||||
приведены ниже: |
|
|
|
|
|
|
|
Пример команды IDIV |
|
Остаток |
Частное |
|
|
|
|
2 |
|
EE (-18) |
FB (-5) |
|
|
|
|
3 |
|
1000 (4096) |
0080 (128) |
|
|
|
|
4 |
|
0000 |
0002 |
|
|
|
|
Только в примере 4 вырабатывается такой же результат, что и для команды DIV. Таким образом, если делимое и делитель имеют одинаковый знаковый бит, то команды DIV и IDIV генерируют одинаковый pезультат. Но, если делимое и делитель имеют разные знаковые биты, то команда DIV генерирует положительное частное, а команда IDIV - отрицательное частное. Можно обнаружить это, используя отладчик DEBUG для трассировки этих примеров.
Повышение производительности. При делении на степень числа 2 (2, 4, и т.д.) более эффективным является сдвиг вправо на требуемое число битов. В следующих примерах предположим, что делимое находится в регистре AX:
Деление на 2: |
SHR |
AX,1 |
Деление на 8: |
MOV |
CL,3 |
|
SHR |
AX,CL |
Переполнения и прерывания |
|
--------------------------- |
вызвать |
Используя команды DIV и особенно IDIV, очень просто |
