Материал: 1117

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

main:

;точка входа в программу

. . .

 

xor ax,ax

 

mov al,25

 

mul rez_l

 

jnc m1

;если переполнение, то на m1

mov rez_h,ah

;старшую часть результата в rez_h

m1:

 

mov rez_l,al

 

exit:

 

mov ax,4c00h

;стандартный выход

int 21h

 

end main

;конец программы

Здесь производится умножение значения в rez_l на число в регистре al. Согласно табл. 4.4, результат умножения будет располагаться в регистре al (младшая часть) и регистре ah (старшая часть). Для выяснения размера результата командой условного перехода jnc анализируется состояние флага cf, и если оно не равно 1, то результат остался в рамках регистра al. Если же cf = 1, то выполняется команда, которая формирует в поле rez_h старшее слово результата. Команда mov rez_l,al формирует младшую часть результата. Теперь обратите внимание на строку с директивой label в сегменте данных. Мы еще не раз будем сталкиваться с этой директивой. В данном случае она назначает еще одно символическое имя rez адресу, на который уже указывает другой идентификатор rez_l. Отличие заключается в типах этих идентификаторов — имя rez имеет тип слова, который ему назначается директивой label (имя типа указано в качестве операнда label). Введя эту директиву в программу, мы подготовились к тому, что, возможно, результат операции умножения будет занимать слово в памяти. Обратите внимание, что мы не нарушили принципа: младший байт по младшему адресу. Далее, используя имя rez, можно обращаться к значению в этой области как к слову.

Примечание. Для умножения сомножителей со знаком используется инструкция imul (см. уч. пос., ч.4).

4.65. Деление целых чисел без знака

Процессор 8086 может выполнять отдельные типы операций деления:

–16-битового значения на 8-битовое (знаковое и беззнаковое);

–32-битового операнда на 16-битовый операнд (знаковое и беззнаковое).

71

Здесь рассматриваются только варианты беззнакового деления (инструкция div). Для деления со знаком используется инструкция idiv (см.

уч. пос., ч.4).

В общем виде команда деления чисел без знака может быть представлена следующим образом:

div делитель

Делитель может находиться в памяти или в регистре и иметь размер 8 или 16 битов (для МП 8086) или размер 8, 16 или 32 бита (для МП 80386). Местонахождение делимого фиксировано и так же, как в команде умножения, зависит от размера операнда. Результатом команды деления являются значения частного и остатка.

Варианты местоположения и размеров операндов операции деления и результатов деления (МП 8086) показаны в табл. 4.5.

 

 

 

Таблица 4.5

Делимое

Делитель

Частное

Остаток

Слово (16 битов)

Байт

Байт

Байт

в регистре ax

в регистре или ячейке

в регистре al

в регистре ah

 

памяти

 

 

Двойное слово (32 бита)

Слово (16 битов)

Слово (16 битов)

Слово (16 битов)

dx — старшая часть

в регистре или ячейке

в регистре ax

в регистре dx

ax — младшая часть

памяти

 

 

После выполнения команды деления возможно возникновение прерывания с номером 0, называемого “деление на ноль”. Этот вид прерывания относится к так называемым исключениям. Данная разновидность прерываний возникает внутри микропроцессора из-за некоторых аномалий во время вычислительного процесса. Прерывание 0, т.е. “деление на ноль”, при выполнении команды div может возникнуть по одной из следующих причин:

1)делитель равен нулю;

2)частное не входит в отведенную под него разрядную сетку, что может случиться в следующих случаях:

- при делении слова на байт, если значение делимого более чем в 256 раз больше значения делителя;

- при делении двойного слова на слово, если значение делимого более чем в 65 536 раз больше значения делителя;

- при делении учетверенного слова на двойное слово, если значение делимого более чем в 4 294 967 296 раз больше значения делителя.

72

4.66. Беззнаковое деление 16-битового значения на 8-битовое

При беззнаковом делении 16-битового значения на 8-битовое значение делимое должно быть записано в регистре ax. 8-битовый делитель может храниться в любом 8-битовом общем регистре или переменной в памяти соответствующего размера. Инструкция div всегда записывает 8-битовое частное в регистр al, а 8-битовый остаток – в ah. Например:

mov

ax,51

; делимое

mov

dl,10

; делитель

div

dl

; после выполнения деления в al – частное, в ah – остаток

Заметим,

что

частное представляет собой 8-битовое значение. Это

означает, что результат деления 16-битового операнда на 8-битовый операнд не должен превышать 255. Если частное слишком велико, то генерируется прерывание 0 (прерывание по делению на 0). Инструкции:

mov

ax,0fffh

mov

bl,1

div

bl

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

Пример деления значения del (20 001) на значение delt (200):

stacksg

segment para ‘Stack’

db 256 dup (0)

stacksg

ends

datasg segment para ‘Data’

del_b

label byte

del

dw 20001

delt

db 200

datasg ends

codesg segment para ‘Code’ ;сегмент кода

main:

;точка входа в программу

. . .

xor ax,ax

;последующие две команды эквивалентны одной mov ax,del, но копируют слово побайтно

mov ah,del_b

;старший байт делимого в ah

mov al,del_b+1;младший байт делимого в al

div delt

;в al — частное (здесь 100), в ah — остаток (здесь 1)

. . .

 

end main

;конец программы

73

4.67. Беззнаковое деление 32-битового значения на 16-битовое

При делении 32-битового операнда на 16-битовый операнд делимое должно записываться в регистрах dx:ax. 16-битовый делитель может находиться в любом из 16-битовых регистров общего назначения или в переменной в памяти соответствующего размера. Например, в результате выполнения инструкций:

mov ax,2

mov dx,1 ; в (dx:ax) загрузить 10002h mov bx,10h

div bx

частное 1000h (результат деления 10002h на 10h) будет записано в регистре ax, а 2 (остаток от деления) – в регистре dx.

Как и при умножении, при делении имеет значение, используются операнды со знаком или без знака. Для деления беззнаковых операндов используется операция div, а для деления операндов со знаком – idiv (см.

уч. пос., ч.4).

4.68. Изменение знака

Фактически инструкция neg операнд выполняет одно действие: операнд = 0 – операнд, то есть вычитает операнд из нуля.

Команду neg операнд можно применять:

–для смены знака;

–для выполнения вычитания из константы.

Смена знака. Инструкция neg позволяет изменить (инвертировать) знак содержимого общего регистра или переменной в памяти. Например, после выполнения инструкций:

mov

ax,1 ; установить в регистр ax значение 1

neg

ax ; отрицание ax, он становится равным -1

mov

bx,ax ; скопировать содержимое ax в bx, т.е. bx :=ax=-1

neg

bx ; отрицание bx, он становится равным 1

в регистре ax будет содержаться значение -1, а в регистре bx – значение 1. Вычитание из константы. В связи с тем, что команды sub и sbb не позволяют вычесть что-либо из константы, так как константа не может служить операндом-приемником в этих операциях, данную операцию

выполняют с помощью двух команд:

neg ax

;смена знака содержимого регисра ax (т.е. ax:=-ax)

add ax,340

;фактически вычитание: ax := 340-ax

4.69. Преобразование размеров беззнаковых данных

Что делать, если размеры операндов, участвующих в арифметических операциях, разные? Например, предположим, что в операции сложения

74

один операнд является словом, а другой занимает двойное слово. Если числа без знака, то выход найти просто: можно на базе исходного операнда сформировать новый (формата двойного слова), старшие разряды которого просто заполнить нулями.

Аналогично преобразование беззнакового байтового значения в слово заключается просто в обнулении старшего байта слова. Например:

mov cl,12 mov al,cl mov ah,0

преобразуют беззнаковое значение 12 в регистре cl в значение 12 размером в слово в регистре ax.

Обратные преобразования двойного слова в слово или слова в байт тоже возможны (при определенных значениях!) Рассмотрим преобразование слова в байт. Например:

mov ax,5 mov bl,al

Здесь значение 5 размером в слово в регистре ax преобразуется в байтовое значение 5 в регистре bl. Естественно, что преобразуемое значение вместится в байт. Попытка преобразовать в байт значение 100h с помощью инструкций:

mov dx,100h mov al,dl

была бы безуспешной, так как в регистр al был бы записан только младший (нулевой) байт.

Для преобразования байтового значения со знаком в регистре al в слово со знаком существует инструкция cbw. Для преобразования слова со знаком в регистре ax в двойное слово со знаком в регистрах dx: ax (старшее слово содержится в регистре dx) предусмотрена специальная инструкция cwd (см. уч. пос., ч.4). Там же – про cdq (двойное из eax – в учетверенное в edx:eax) и cwde (слово из ax в двойное слово в eax).

4.70. Доступ к сегментным регистрам

Если одним из операндов инструкции mov является сегментный регистр, то другим операндом должен быть регистр общего назначения или ячейка памяти. Невозможно загрузить константу в сегментный регистр непосредственно, и непосредственно скопировать один сегментный регистр в другой сегментный регистр.

Вот, например, два способа установки регистра es в значение сегмента данных с именем

datasg segment para ‘Data’ ;сегмент данных

DataSeg dw datasg

75

Источник: https://studfile.net/preview/16407174/