величиной +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
ORG 100H
BEGIN: JMP SHORT MAIN
; ---------------------------------------------
MULTCND DW 3206H ;Элементы данных
DW 2521H
MULTPLR DW 6400H
DW 0A26H
PRODUCT DW 0
DW 0
DW 0
DW 0
; ---------------------------------------------
MAIN PROC NEAR ;Основная процедура
CALL E10XMUL ;Вызвать 1-е умножение
CALL Z10ZERO ;Очистить произведение
CALL F10XMUL ;Вызвать 2-е умножение
RET
MAIN ENDP
; Умножение двойного слова на слово:
; -----------------------------------------------
E10XMUL PROC
MOV AX,MULTCND+2 ;Умножить правое слова
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
MOV AX,MULTCND+2 ;Слово-2 множимого
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
END BEGIN
__________________________________________________________________________
Рис.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. Заметьте, что сдвиг единичного
бита за разрядную сетку устанавливает флаг переноса.
Сдвиг влево на 4 бита
MOV CX,04 ;Инициализация на 4 цикла
C20: SHL DX,1 ;Сдвинуть DX на 1 бит влево
SHL AX,1 ;Сдвинуть AX на 1 бит влево
ADC DX,00 ;Прибавить значение переноса
LOOP C20 ;Повторить
Сдвиг вправо на 4 бита
MOV CX,04 ;Инициализация на 4 цикла
D20: SHR AX,1 ;Сдвинуть AX на 1 бит вправо
SHR DX,1 ;Сдвинуть DX на 1 бит вправо
JNC D30 ;Если есть перенос,
OR AH,10000000B ; то вставить 1 в AH
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.