Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Абель.docx
Скачиваний:
13
Добавлен:
26.11.2018
Размер:
569.84 Кб
Скачать

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.

В четвертом примере команды DIV сначала выполняется расширение слова

WORD1 до двойного слова в регистре DX. После деления остаток шест.0000

получится в регистре DX, а частное шест.0002 - в регистре AX.

__________________________________________________________________________

page 60,132

TITLE EXDIV (COM) Пример операций DIV и IDIV

CODESG SEGMENT PARA 'Code'

ORG 100H

BEGIN: JMP SHORT MAIN

; ---------------------------------------------

BYTE1 DB 80H ;Data items

BYTE2 DB 16H

WORD1 DW 2000H

WORD2 DW 0010H

WORD3 DW 1000H

; ---------------------------------------------

MAIN PROC NEAR ;Основная процедура

CALL D10DIV ;Вызов подпрограммы DIV

CALL E10IDIV ;Вызов подпрограммы IDIV

MAIN ENDP

; Примеры с командой DIV:

; ---------------------------------------------

D10DIV PROC

MOV AX,WORD1 ;Слово / байт

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 ; расширить делимое в AH

IDIV BYTE3 ; остаток:частное в AH:AL

MOV DX,WORD2 ;Двойное слово / слово

MOV AX,WORD3 ; делимое в DX:AX

IDIV WORD1 ; остаток:частное в DX:AX

MOV AX,WORD1 ;Слово / слово

CWD ; расширить делимое в DX

IDIV WORD3 ; остаток:частное в DX:AX

RET

E10DIV ENDP

CODESG ENDS

END BEGIN

__________________________________________________________________________

Рис.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, очень просто вызвать

пеpеполнение. Прерывания приводят (по крайней мара в системе, используемой

при тестировании этих программ) к непредсказуемым результатам. В операциях

деления предполагается, что частное значительно меньше, чем делимое.

Деление на ноль всегда вызывает прерывание. Но деление на 1 генерирует

частное, которое равно делимому, что может также легко вызвать прерывание.

Рекомендуется использовать следующее правило: если делитель - байт,

то его значение должно быть меньше, чем левый байт (AH) делителя: если

делитель - слово, то его значение должно быть меньше, чем левое слово (DX)

делителя. Проиллюстрируем данное правило для делителя, равного 1:

Операция деления: Делимое Делитель Частное

Слово на байт: 0123 01 (1)23

Двойное слово на слово: 0001 4026 0001 (1)4026

В обоих случаях частное превышает возможный размер. Для того чтобы

избежать подобных ситуаций, полезно вставлять перед командами DIV и IDIV

соответствующую проверку. В первом из следующих примеpов предположим, что

DIVBYTE - однобайтовый делитель, а делимое находится уже в регистре AX. Во

втором примере предположим, что DIVWORD - двухбайтовый делитель, а делимое

находится в регистровой паре DX:AX.

Слово на байт Двойное слово на байт

CMP AH,DIVBYTE CMP DX,DIVWORD

JNB переполнение JNB переполнение

DIV DIVBYTE DIV DIVWORD

Для команды IDIV данная логика должна учитывать тот факт, что либо

делимое, либо делитель могут быть отрицательными, а так как сравниваются

абсолютные значения, то необходимо использовать команду NEG для временного

перевода отрицательного значения в положительное.

Деление вычитанием

--------------------

Если частное слишком велико, то деление можно выполнить с помощью

циклического вычитания. Метод заключается в том, что делитель вычитается

из делимого и в этом же цикле частное увеличивается на 1. Вычитание

продолжается, пока делимое остается больше делителя. В cледующем примере,

делитель находится в регистре AX, а делимое - в BX, частное вырабатывается

в CX:

SUB CX,CX ;Очистка частного

C20: CMP AX,BX ;Если делимое < делителя,

JB C30 ; то выйти

SUB AX,BX ;Вычитание делителя из делимого