Особенности арифметических операций c двоичными данными. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Особенности арифметических операций c двоичными данными.



Особенности арифметических операций c двоичными данными.

В этом разделе даются примеры программ с операциями сложения, вычитания, умножения и деления двоичных данных.

4.13.1 Сложение и вычитание

Команды ADD и SUB выполняют сложение и вычитание байтов или слов, содержащих двоичные данные. Вычитание осуществляется в компьютере по методу сложения с двоичным дополнением: для второго операнда устанавливаются обратные значения битов и прибавляется 1, а затем происходит сложение с первым операндом. Во всем, кроме первого шага, операции сложения и вычитания идентичны.

На рис. 4.24 представлены примеры команд ADD и SUB, обрабатывающих байты или слова. В процедуре B10ADD используется команда ADD для сложения байтов, а в процедуре C10SUB команда SUB вычитает слова. Примеры показывают все пять возможных ситуаций:

сложение/вычитание регистр - регистр;

сложение/вычитание память - регистр;

сложение/вычитание регистр - память;

сложение/вычитание регистр - непосредственное значение;

сложение/вычитание память - непосредственное значение.

.CODE

ORG 100H

BEGIN: JMP SHORT MAIN

.DATA

BYTEA DB 64Н;Элементы данных

BYTEB DB 40H

BYTEC DB 16H

WORDA DW 4000H

WORDB DW 2000H

UORDC DW 1000H

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

CALL B10ADD;Вызвать сложение ADD

CALL C10SUB;Вызвать вычитание SUB

RET

MAIN END

; Пример сложения байт:

B10ADD: PUSH AX;Сохранение регистров

PUSH BX

MOV AL,BYTEA

MOV BL,BYTEB

ADD AL,BL;Регистр и регистр

ADD AL,BYTEC;Память и регистр

ADD BYTEA,AL;Регистр и память

ADD BL,10H;Непосредств.и регистр

ADD BYTEC,25H;Непосредств.и память RET

ADD BYTEB,AL;Регистр и память

POP AX

POP BX

RET

; Пример вычитания слов:

C10SUB: PUSH AX

PUSH BX

MOV AX,WORDA

MOV BX.WORDB

SUB AX,BX;Регистр из регистра

SUB AX,WORDC;Память из регистра

SUB BX, 1000H;Непосредств. из peг.

SUB WORDA, BX;Регистр из памяти

SUB WORDA,256H;Непосредств. из пам.

POP AX

POP BX

RET

Рис. 4.24. Примеры команд ADD и SUB

Поскольку прямой операции память-память не существует, то данная операция выполняется через регистр. В следующем примере к содержимому слова WORDB прибавляется содержимое слова WORDA, описанные как DW:

MOV AX,WORDA

ADD AX,WORDB

MOV WORDB,AX

Переполнения

Опасайтесь переполнений в арифметических операциях. Один байт содержит знаковый бит и семь битов данных, т.е. значения от -128 до + 127. Результат арифметической операции может легко превзойти емкость однобайтового регистра. Например, результат сложения в регистре AL, превышающий его емкость, автоматически не переходит в регистр АН. Предположим, что регистр AL содержит 60Н, тогда команда

ADD AL, 20H

генерирует в AL сумму - 80Н. Но операция также устанавливает флаг переполнения и знаковый флаг в состояние "отрицательно". Причина заключается в том, что 80H или двоичное 1000 0000 является отрицательным числом. Таким образом, вместо + 128 сумма равна -128. Так как регистр AL слишком мал для такой операции, следует воспользоваться регистром AX. В следующем примере команда CBW (Convert Byte to Word - преобразовать байт в слово) преобразует 60Н в регистре AL в 0060Н в регистре AX, передавая при этом знаковый бит (0) через регистр АН. Команда ADD генерирует теперь в регистре AX правильный результат: 0080Н, или +128:

CBW; Расширение AL до AX

ADD AX, 20Н;Прибавить к AX

Но полное слово имеет также ограничение: один знаковый бит и 15 бит данных, что соответствует значениям от -32768 до + 32767. Рассмотрим далее, как можно обрабатывать числа, превышающие эти пределы.

Многословное сложение

Максимально возможное значение в регистре + 32767 ограничивает возможности компьютера для выполнения арифметических операций. Рассмотрим два способа представления арифметических операций. Первый способ более прост, но специфичен, второй— сложнее, но имеет общий характер.

На рис. 4.24 процедура D10DWD демонстрирует простой способ сложения содержимого одной пары слов (WORD1A и WORD1B) с содержимым второй пары слов (WORD2A и WORD2B) и сохранения суммы в третьей паре слов (WORD3A и WORD3B). Сначала выполняется сложение правых слов:

WORD1B ВС62

WORD2B 553А

Сумма: 1119C

Сумма 1119СН превышает емкость регистр AX. Переполнение вызывает установку флага переноса в 1. Затем выполняется сложение левых слов, но в данном случае вместо команды ADD используется команда сложения с переносом ADC (ADd with Carry). Эта команда складывает два значения, и если флаг CF уже установлен, к сумме прибавляется 1:

WORD1A 0123

WORD2A 0012

Плюс перенос 1

Сумма: 0136

 

.CODESG SEGMENT PARA 'Code'

ASSUME CS:COOESG,DS:COOESG,SS:CODESG

ORG 100H

BEGIN: JMP SHORT MAIN

WORD1A DW 0123Н;Элементы данных

WORD1B DW BC62H

WORDRSV1 DW 8 DUP (?)

WORD2A DW 0012H

WORD2B DW 553AH

WORDRSV2 DW 8 DUP (?)

WORDRSV3 DW 10 DUP (?)

WORD3A DW EQU WORDRSV3

WORD3B DW EQU WORDRSV3+4

NUMBER DW?

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

CALL D10DWD;Вызвать сложение 1

CALL E10DWD;Вызвать сложение 2

RET

MAIN ENDP

; Пример сложения двойных слов:

D10DWD PROC

MOV AX, WORD1B;Сложить правые слова

ADD AX, WORD2B

MOV WORD3B,AX

MOV AX,WORD1A;Сложить левые слова

ADC AX,WORD2A;с переносом

MOV WORD3A, AX

RET

D10DWD ENDP

; Сложение чисел любой длины:

E10DWD PROC FAR

PUSH FX;Сохранение регистра Флагов

PUSHAD;Сохранить все регистры

CLC;Очистить Флаг переноса

MOV ECX,NUMBER;Установить счетчик

LEA SI, WORD1A;Старшее слово числа DWORD1

LEA DI,WORD2A;Старшее слово числа DWORD2

LEA BX,WORD3A; Старшее слово числа суммы

Е20:

MOV AX,[SI+ECX];Поместить слово в AX

ADC AX,[DI+ECX];Сложить с переносом

MOV [BX+ECX],AX;Сохранить слово

DEC SI

DEC SI

DEC DI

DEC DI

DEC BX

DEC BX

LOOP Е20; Повторить цикл

POPAD

POP FX

RET

E10DWD ENDP

CODESG ENDS

END BEGIN

Рис. 4.24. Сложение двойных слов и слов любой длины

На рис.4.24 процедура E10DWD демонстрирует подход к сложению значений любой длины. Действие начинается со сложения самых правых слов складываемых полей. В первом цикле складываются правые слова, во втором - слова, расположенные левее и т.д. При этом адреса в регистрах SI, DI и BX уменьшаются на 2. По две команды DEC выполняют эту операцию для каждого регистра. Применять команду

SUB reg,02

в данном случае нельзя, так как при этом будет очищен флаг переноса, что приведет к искажению результата сложения.

Ввиду наличия цикла используется только одна команда сложения ADC. Перед циклом команда CLC (CLear Carry -очистить флаг переноса) устанавливает нулевое значение флага переноса. Для работы данного метода необходимо: 1) обеспечить смежность слов, 2) выполнять обработку справа налево и 3) загрузить в регистр CX число складываемых слов.

Для многословного вычитания используется команда SBB (SuBtract with Borrow - вычитание с заемом), эквивалентная команде ADC. Заменив в процедуре E10DWD (рис. 12.2) команду ADC на SBB, получим процедуру для вычитания.

Буззнаковые и знаковые данные

Многие числовые поля являются беззнаковыми, например номер абонента, адрес памяти. Некоторые числовые поля предполагаются всегда положительными, например норма выплаты, день недели, число PI. Другие числовые поля являются знаковыми, так как их содержимое может быть положительным или отрицательным. Например, алгебраическое число или долговой баланс покупателя, который может быть отрицательным при переплатах.

Для беззнаковых данных все биты являются битами данных и вместо ограничения + 32767 регистр может содержать числа до + 65535. Для знаковых данных левый байт является знаковым битом. Команды. ADD и SUB не делают разницы между знаковыми и беззнаковыми данными, они просто складывают и вычитают биты.

В следующем примере сложения двух двоичных чисел первое число содержит единичный левый бит. Для беззнакового числа биты представляют положительное число 249, для знакового -отрицательное число -7:

Беззнаковое Знаковое

11111001 249 -7

00000010 2 +2

11111011 251 -5

Двоичное представление результата сложения одинаково для беззнакового и знакового числа. Однако биты представляют + 251 для беззнакового числа и -5 для знакового. Таким образом, числовое содержимое поля может интерпретироваться по-разному.

Состояние переноса возникает в случае, когда имеется перенос в знаковый разряд. Состояние переполнения возникает в случае, когда перенос в знаковый разряд не создает переноса из разрядной сетки или перенос из разрядной сетки происходит без переноса в знаковый разряд.

Если при сложении беззнаковых чисел возникает перенос, то результат получается неправильным:

Беззнаковое Знаковое CF OF

11111100 252 -4

00000101 5 +5

00000001 1 1 1 0

(неправильно)

В случае возникновения переполнения при сложении знаковых чисел результат получается неправильный:

Беззнаковое Знаковое CF OF

01111001 121 +121

00001011 11 +11

10000100 132 -124 0 1

(неправильно)

При операциях сложения и вычитания может одновременно возникнуть и переполнение и перенос:

Беззнаковое Знаковое CF OF

11110110 246 -10

10001001 137 -119

01111111 127 +127 1 1

(неправильно) (неправильно)

Умножение

Операция умножения для беззнаковых данных выполняется командой MUL, а для знаковых - IMUL (Integer MULtiplication -умножение целых чисел).

Ответственность за контроль над форматом обрабатываемых чисел и за выбор подходящей команды умножения лежит на самом программисте. Существуют две основные операции умножения целых чисел.

Умножение байта на байт.

Умножение слова на слово.

MULTB DB 1Ah

MULTW DW 2E13H

MULTD DD 0B2E13CAH

IMUL EBX, MULTW;Умножение слова I-32 на слово I-32,

;результат слово I-32 в регистре EBX

MUL MULTB;Умножение байта на байт, результат в рег.AX

IMUL MULTW;Умножение слова I-32 (Двойного слова) на;слово I-32, результат четверное слово(64 bit)

; в регистрах EDX:EAX

Рис. 4.25 Фрагмент программы с операциями умножения

На рис 4.25 приведены варианты применения команды умножения. Как было сказано в разделе 4.11.1, в результате умножения двух 32-разрядных чисел получается произведение двойной длины, то есть 64-разрядное значение. Однако для многих приложений достаточно иметь результат одинарной длины, то есть 32-разрядное значение. В подобных ситуациях используются разные команды. Команда, приведенная на рисунке первой, умножает 32 разрядные сомножители, результат получается тоже 32 разрядный. Исход­ный операнд может находиться либо в регистре, либо в памяти. В случае 64-раз­рядного результата команда в единственном операнде команд MUL и IMUL указывается множитель, множимое уже должно находиться в AL или EAX соответственно. Рассмотрим следующую команду:

MUL MULTB

Так как поле MULTB определено как байт (DB), то операция предполагает умножение содержимого AL на значение байта из поля MULTB.

Если поле MULTD определено по терминологии Intel как двойное слово (DD) или слово I-32, то операция предполагает умножение содержимого EAX на значение слова из поля MULTD.

Умножение байта на байт. Множимое уже находится в регистре AL, а множитель - в байте памяти или в однобайтовом регистре. После умножения произведение находится в регистре AX. Операция игнорирует и стирает любые данные, которые находились в регистре АН.

До АН AL После AX

умножения: Множимое Множитель умножения: произведение

Умножение слова на слово. Множимое находится в регистре EAX, а множитель - в слове памяти или в регистре. После умножения произведение образуется в двойном слове, для которого требуется два регистра: старшая (левая) часть произведения находится в регистре EDX, а младшая (правая) часть - в регистре EAX. Операция игнорирует и стирает любые данные, которые были в регистре EDX.

До | EAX | После EDX EAX

умножения: |Множимое | умножения: Старшая Младшая

Часть часть

Произведение

Если множитель находится в регистре, то длина регистра определяет тип операции, как показано ниже:

C10MUL ENDP

; Пример умножения IMUL:

D10 IMUL PROC

MOV AL, BYTE1;Байт * байт

IMUL BYTE2;произведение в AX

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

IMUL WORD2;произвед, в DX:AX

MOV AL,BYTE1;Байт * слово

CBW;расшир. множимого в АН

IMUL WORD1;произвед, в DX:AX

RET

D10 IMUL ENDP

CODESG ENDS

END BEGIN

Рис.4.26. Беззнаковое и знаковое умножение

Первый пример команды IMUL перемножает 80H (отрицательное число) на 40H (положительное число). Произведение Е000H получается в регистре AX. Используя те же данные, команда MUL дает в результате 2000 (12810 (80H) * 6410 (40H) = 819210 или 2000H, а команда IMUL дополняет результат знаковыми единицами и получает Е000H), так что можно видеть разницу в использовании команд MUL и IMUL. Команда MUL рассматривает 80H как +128, а команда IMUL - как -128. В результате умножения -128 на +64 получается -8192 или шестнадцатиричное Е000. (Попробуйте преобразовать Е000 в десятичный формат.)

Второй пример команды IMUL перемножает 8000H (отрицательное значение) на 2000Н (положительное значение). Произведение F0000000 получается в регистрах DX:AX и представляет собой отрицательное значение.

Третий пример команды IMUL перед умножением выполняет расширение байта BYTE1 до размеров слова в регистре AX. Так как значения предполагаются знаковые, то в примере используется команда CBW для перевода левого знакового бита в регистр АН:

шестнадцатиричное 80 в регистре AL превращается в FF80 в регистре AX. Поскольку множитель в слове WORD1 имеет также отрицательное значение, то произведение будет положительным. В самом деле, 00400000Н в регистрах DX:AX - такой же результат, как и в случае умножения командой MUL, которая предполагала положительные сомножители.

Таким образом, если множимое и множитель имеют одинаковый знаковый бит, то команды MUL и IMUL генерируют одинаковый результат. Но если сомножители имеют разные знаковые биты, то команда MUL вырабатывает положительный результат умножения, а команда IMUL - отрицательный.

Можно обнаружить это, используя трассировкe примеров.

Повышение эффективности умножения.

При умножении на степень числа 2 (2,4,8 и т.д.) более эффективен сдвиг влево на требуемое число битов. Сдвиг более чем на 1 требует загрузки счетчика сдвига в регистр CL. В следующих примерах предположим, что множимое находится в регистре AL или AX:

Умножение на 2:

SHL AL,1

Умножение на 8:

MOV CL,3

SHL AX,CL

Многословноe умножение

Обычно умножение бывает двух типов: умножение байта на байт и умножение слова на слово. Как было показано, максимальное знаковое значение в слове + 32767. Умножение больших чисел требует выполнения некоторых дополнительных действий. Рассматриваемый подход предполагает умножение каждого слова отдельно и затем сложение полученных результатов.

Рассмотрим следующее умножение в десятичном формате:

x12

1365

 

Представим, что Десятичная арифметика может умножать только двузначные числа. Тогда можно умножить 13 и 65 на 12 раздельно:

13 65

x12x12

26 130

13 65

156 780

Теперь сложим полученные произведения, но поскольку число 13 представляло сотни, то первое произведение в действительности будет 15600:

15600 +780 =16380

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

Умножение двойного слова на слово. Процедура E10XMUL на рис. 4.27 умножает двойное слово на слово.

Множимое MULTCND состоит из двух слов, содержащих соответственно 3206Н и 2521Н. Определение данных в виде двух слов (DW) вместо двойного слова (DD) обусловлено необходимостью правильной адресации для команд MOV, пересылающих слова в регистр AX.

Множитель MULTPLR содержит 6400Н.

Область для записи произведения PRODUCT состоит из трех слов.

Первая команда MUL перемножает MULTPLR и правое слово поля MULTCND; произведение 0Е80 Е400 записывается в PRODUCT+2 и PRODUCT+4.

Вторая команда MUL перемножает MULTPLR и левое слово поля MULTCND, получая в результате 138А 5800.

Далее выполняется сложение двух произведений следующим образом:

Произведение 1: 0000 0Е80 Е400 Произведение 2: 138А 5800 Результат: 138А 6680 Е400

Так как первая команда ADD может выработать перенос, то второе сложение выполняется командой сложения с переносом ADC (ADd with Carry). В силу обратного представления байтов в словах в процессорах 8086/8088 область PRODUCT в действительности будет содержать значение 8А13 8066 00Е4. Программа предполагает, что первое слово в области PRODUCT имеет начальное значение 0000.

Умножение двойного слова на двойное слово.

Умножение двух двойных слов включает следующие четыре операции умножения:

Множимое Множитель

слово 2 х слово 2

слово 2 х слово 1

слово 1 х слово 2

слово 1 х слово 1

 

TITLE EXDWMUL - Умножение двойных слов

CODESG SEGMENT PARA 'Code'

ASSUME CS:CODESG,OS:CODESG,SS:CODESG

ORG 100H

BEGIN: JMP SHORT MAIN

MULTCND DW 3206H;Элементы данных

DW 2521H

MULTPLR DW 6400Н

DW 0A26H

PRODUCT DW 0

DW 0

DW 0

DW 0

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

CALL E10XMUL;Вызвать 1-е умножение

CALL Z10ZERO;Очистить произведение

CALL E10XMUL;Вызвать 2-е умножение

RET

MAIN ENDP

; Умножение дв.слова на слово:

E10XMUL PROC

MOV AX,MULTCND+2;Умнож. прав. cл.

MUL MULTPLR;множимого

MOV PRODUCT+4,AX;3аписать произв.

MOV PRODUCT+2,DX

MOV AX,MULTCND;Умножить лев. cл.

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,AX

MOV AX,MULTCND+2 Слово-2 множимого

MUL MULTPLR * слово-1 множителя

ADD PRODUCT+4,AX Сложить с пред.

ADC PRODUCT+6,AX

ADC PRODUCT,00 Прибавить перенос

MOV AX,MULTCND Слово-1 множимого

MUL MULTPLR+2 * Слово-2 множителя

ADC PRODUCT+4,AX Сложить с пред.

ADC PROOUCT+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

Рис. 4.27. Многословное умножение

Каждое произведение в регистровой паре DX:AX складывается с соответствующим словом в окончательном результате. Пример такого умножения приведен в процедуре F10XMUL на рис. 4.27. Множимое MULTCND содержит 3206 2521, множитель MULTPLR -6400 0A26. Результат заносится в область PRODUCT, состоящую из четырех слов.

Хотя логика умножения двойных слов аналогична умножению двойного слова на слово, имеется одна особенность. После пары команд сложения ADD/ADC используется еще одна команда ADC, которая прибавляет 0 к значению в поле PRODUCT. Это необходимо потому, что первая команда ADC сама может вызвать перенос, который последующие команды могут стереть. Поэтому вторая команда ADC прибавит 0, если переноса нет, и прибавит 1, если перенос есть.

Финальная пара команд ADD/ADC не требует дополнительной команды ADC, так как область PRODUCT достаточно велика для генерации окончательного результата и переноса на последнем этапе не будет.

Окончательный результат 138А 687С 8Е5С ССЕ6 получится а поле PRODUCT в обратной последовательности байтов в словах.

Сдвиг влево на 4 бита

MOV ECX,04;4 цикла

С20: SHL EDX,1;EDX на 1 бит влево

SHL EAX,1;EAX на 1 бит влево

ADC EАX,00;Плюс перенос

LOOP С20;Повторить

Сдвиг вправо на 4 бита

MOV ECX,04;4 цикла

D20: SHR EAX,1;EAX на 1 бит вправо

SHR EDX,1;EDX на 1 бит вправо

JNC D30;Если есть перенос,

OR EАX,80000000H;то 1 в EAX

D30: LOOP 020;Повторить

Ниже приведен более эффективный способ для сдвига влево для пары AX:DX, не требующий организации цикла. В этом примере фактор сдвига записывается в регистр CL. Пример написан для сдвига на 4 бита, но может быть адаптирован для других значений сдвигов:

MOV CL,04;Установить фактор сдвига

SHL DX,CL;DX влево на 4 бита

MOV BL,АН;Сохранить АН в BL

SHL AX,CL;AX влево на 4 бита

SHL BL, CL;BL влево на 4 бита

OR DL,BL;4 бита из BL в DL

Деление

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

Существуют две основные операции деления:

Деление слова на байт. Делимое находится в регистре AX, а делитель - в байте памяти или в однобайтовом регистре. После деления остаток получается в регистре АН, а частное - в AL. Так как однобайтовое частное, очень мало - максимально + 255 (0FFH) для беззнакового деления и +127 (7FH) для знакового, то данная операция имеет ограниченное использование:

До AX После АН AL

деления: Делимое) деления: Остаток Частное

Деление четверного слова на двойное слово(Деление двойного слова на слово). Делимое находится в регистровой паре EDX:EAX, а делитель - в двойном слове памяти или в регистре. После деления остаток получается в регистре EDX, а частное - в регистре EAX. Частное в одном слове допускает максимальное значение + FFFFFFFF для беззнакового деления и 7FFFFFFF для знакового:

До EDX EAX После EDX | EAX

деления: Старшая Младшая деле-

часть часть ния: Остаток | частное

Делимое

 

В единственном операнде команд DIV и IDIV указывается делитель. Если делимое находится только в EAX, то его расширяют до EDX специальной командой CDQ. Рассмотрим следующую команду:

DIV DIVISOR

Если поле DIVISOR определено как байт (DB), то операция предполагает деление слова на байт. Если поле DIVISOR определено как слово (DW), то операция предполагает деление двойного слова на слово. Если поле DIVISOR определено как двойное слово (DD), то операция предполагает деление четверного слова на двойное слово.

При делении, например, 13 на 3 получается результат 4 1/3. Частное здесь 4, а остаток - 1. Заметим, что ручной калькулятор (или программа на языке БЕЙСИК) выдает в этом случае результат 4,333... Значение содержит целую часть (4) и дробную часть (,333). Значения 1/3 и,333... - дробные части, в то время как 1 -остаток от деления.

Переполнения и прерывания

Используя команды DIV и особенно IDIV, очень просто вызвать переполнение. Прерывания приводят (по крайней мере в системе, используемой при тестировании этих программ) к непредсказуемым результатам. В операциях деления предполагается, что частное значительно меньше, чем делимое. Деление на нуль всегда вызывает прерывание. Но деление на 1 генерирует частное, которое равно делимому, что может также легко вызвать прерывание.

Рекомендуется использовать следующее правило: если делитель - байт, то его значение должно быть меньше, чем левый байт (АН) делимого; если делитель - слово, то его значение должно быть меньше, чем левое слово (DX) делимого.

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

Операция деления:

Делимое Делитель Частное

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

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

В обоих случаях частное превышает возможный размер. Для того чтобы избежать подобных ситуаций, полезно вставлять перед командами DIV и IDIV соответствующую проверку. В первом из следующих примеров предположим, что DIVBYTE - однобайтовый делитель, а делимое находится уже в регистре AX. Во втором примере предположим, что DIVWORD - двухбайтовый делитель, а делимое находится в регистровой паре DX:AX.

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

CMP AH,DIVBYTE CMP DX,DIVWORD

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

DIV DIVBYTE DIV DIVWORD

 

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

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

Если частное велико, а делитель маленький, то деление можно выполнить с помощью циклического вычитания. Метод заключается в том, что делитель вычитается из делимого и в этом же цикле частное увеличивается на 1. Вычитание продолжается до тех пор, пока делимое остается больше делителя. В следующем примере делитель находится в регистре AX, а делимое - в EBX, частное вырабатывается в CX:

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

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

JB СЗ0;то выйти

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

INC CX;Инкремент частного

JMP С20;Повторить цикл

СЗ0: RET;Частное в CX, остаток в AX

В конце подпрограммы регистр CX будет содержать частное, а AX - остаток. Пример умышленно примитивен, цель его -продемонстрировать данный способ деления. Если частное получается в регистровой паре DX:AX, то необходимо сделать два дополнения:

1. В метке С20 сравнивать AX и BX только при нулевом DX.

2. После команды SUB вставить команду SBB DX,00 (Вычитание с заимствованием).

Примечание: очень большое частное и малый делитель могут вызвать тысячи циклов.

4.13.4 Преобразование знака

Команда NEG обеспечивает преобразование знака двоичных чисел из положительного в отрицательное и наоборот. Практически команда NEG устанавливает противоположные значения битов и прибавляет 1. Примеры:

NEG AX

NEG BL

NEG BINAMT;(байт или слово в памяти)

Преобразование знака для 64-битового (или большего) числа включает большее количество шагов. Предположим, что регистровая пара EDX:EAX содержит 64-битовое двоичное число. Так как команда NEG не может обрабатывать два регистра

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

NOT EDX Инвертирование битов

NOT EAX Инвертирование битов

ADD EAX,1 Прибавление 1 к EAX

ADC EDX, 0 Прибавление переноса к EDX

Остается одна незначительная проблема: над числами, представленными в двоичном формате, удобно выполнять арифметические операции, если сами числа определены в программе. Данные, вводимые в программу с дискового файла, могут также иметь двоичный формат. Но данные, вводимые с клавиатуры, представлены в ASCII-формате. Хотя ASCII-коды удобны для отображения и печати, они требуют специальных преобразований в двоичный формат для арифметических вычислений.

Выводы

В настоящем разделе были рассмотрены системы команд процессоров Intel IA-32. Так как эта система команд IA-32 основана на архитектуре CISC, то в ней реализован широчайший набор команд для выполнения самых разных операций над различными типами данных.

 

 

Особенности арифметических операций c двоичными данными.

В этом разделе даются примеры программ с операциями сложения, вычитания, умножения и деления двоичных данных.

4.13.1 Сложение и вычитание

Команды ADD и SUB выполняют сложение и вычитание байтов или слов, содержащих двоичные данные. Вычитание осуществляется в компьютере по методу сложения с двоичным дополнением: для второго операнда устанавливаются обратные значения битов и прибавляется 1, а затем происходит сложение с первым операндом. Во всем, кроме первого шага, операции сложения и вычитания идентичны.

На рис. 4.24 представлены примеры команд ADD и SUB, обрабатывающих байты или слова. В процедуре B10ADD используется команда ADD для сложения байтов, а в процедуре C10SUB команда SUB вычитает слова. Примеры показывают все пять возможных ситуаций:

сложение/вычитание регистр - регистр;

сложение/вычитание память - регистр;

сложение/вычитание регистр - память;

сложение/вычитание регистр - непосредственное значение;

сложение/вычитание память - непосредственное значение.

.CODE

ORG 100H

BEGIN: JMP SHORT MAIN

.DATA

BYTEA DB 64Н;Элементы данных

BYTEB DB 40H

BYTEC DB 16H

WORDA DW 4000H

WORDB DW 2000H

UORDC DW 1000H

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

CALL B10ADD;Вызвать сложение ADD

CALL C10SUB;Вызвать вычитание SUB

RET

MAIN END

; Пример сложения байт:

B10ADD: PUSH AX;Сохранение регистров

PUSH BX

MOV AL,BYTEA

MOV BL,BYTEB

ADD AL,BL;Регистр и регистр

ADD AL,BYTEC;Память и регистр

ADD BYTEA,AL;Регистр и память

ADD BL,10H;Непосредств.и регистр

ADD BYTEC,25H;Непосредств.и память RET

ADD BYTEB,AL;Регистр и память

POP AX

POP BX

RET

; Пример вычитания слов:

C10SUB: PUSH AX

PUSH BX

MOV AX,WORDA

MOV BX.WORDB

SUB AX,BX;Регистр из регистра

SUB AX,WORDC;Память из регистра

SUB BX, 1000H;Непосредств. из peг.

SUB WORDA, BX;Регистр из памяти

SUB WORDA,256H;Непосредств. из пам.

POP AX

POP BX

RET

Рис. 4.24. Примеры команд ADD и SUB

Поскольку прямой операции память-память не существует, то данная операция выполняется через регистр. В следующем примере к содержимому слова WORDB прибавляется содержимое слова WORDA, описанные как DW:

MOV AX,WORDA

ADD AX,WORDB

MOV WORDB,AX

Переполнения

Опасайтесь переполнений в арифметических операциях. Один байт содержит знаковый бит и семь битов данных, т.е. значения от -128 до + 127. Результат арифметической операции может легко превзойти емкость однобайтового регистра. Например, результат сложения в регистре AL, превышающий его емкость, автоматически не переходит в регистр АН. Предположим, что регистр AL содержит 60Н, тогда команда

ADD AL, 20H

генерирует в AL сумму - 80Н. Но операция также устанавливает флаг переполнения и знаковый флаг в состояние "отрицательно". Причина заключается в том, что 80H или двоичное 1000 0000 является отрицательным числом. Таким образом, вместо + 128 сумма равна -128. Так как регистр AL слишком мал для такой операции, следует воспользоваться регистром AX. В следующем примере команда CBW (Convert Byte to Word - преобразовать байт в слово) преобразует 60Н в регистре AL в 0060Н в регистре AX, передавая при этом знаковый бит (0) через регистр АН. Команда ADD генерирует теперь в регистре AX правильный результат: 0080Н, или +128:

CBW; Расширение AL до AX

ADD AX, 20Н;Прибавить к AX

Но полное слово имеет также ограничение: один знаковый бит и 15 бит данных, что соответствует значениям от -32768 до + 32767. Рассмотрим далее, как можно обрабатывать числа, превышающие эти пределы.

Многословное сложение

Максимально возможное значение в регистре + 32767 ограничивает возможности компьютера для выполнения арифметических операций. Рассмотрим два способа представления арифметических операций. Первый способ более прост, но специфичен, второй— сложнее, но имеет общий характер.

На рис. 4.24 процедура D10DWD демонстрирует простой способ сложения содержимого одной пары слов (WORD1A и WORD1B) с содержимым второй пары слов (WORD2A и WORD2B) и сохранения суммы в третьей паре слов (WORD3A и WORD3B). Сначала выполняется сложение правых слов:

WORD1B ВС62

WORD2B 553А

Сумма: 1119C

Сумма 1119СН превышает емкость регистр AX. Переполнение вызывает установку флага переноса в 1. Затем выполняется сложение левых слов, но в данном случае вместо команды ADD используется команда сложения с переносом ADC (ADd with Carry). Эта команда складывает два значения, и если флаг CF уже установлен, к сумме прибавляется 1:

WORD1A 0123

WORD2A 0012

Плюс перенос 1

Сумма: 0136

 

.CODESG SEGMENT PARA 'Code'

ASSUME CS:COOESG,DS:COOESG,SS:CODESG

ORG 100H

BEGIN: JMP SHORT MAIN

WORD1A DW 0123Н;Элементы данных

WORD1B DW BC62H

WORDRSV1 DW 8 DUP (?)

WORD2A DW 0012H

WORD2B DW 553AH

WORDRSV2 DW 8 DUP (?)

WORDRSV3 DW 10 DUP (?)

WORD3A DW EQU WORDRSV3

WORD3B DW EQU WORDRSV3+4

NUMBER DW?

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

CALL D10DWD;Вызвать сложение 1

CALL E10DWD;Вызвать сложение 2

RET

MAIN ENDP

; Пример сложения двойных слов:

D10DWD PROC

MOV AX, WORD1B;Сложить правые слова

ADD AX, WORD2B

MOV WORD3B,AX

MOV AX,WORD1A;Сложить левые слова

ADC AX,WORD2A;с переносом

MOV WORD3A, AX

RET

D10DWD ENDP

; Сложение чисел любой длины:

E10DWD PROC FAR

PUSH FX;Сохранение регистра Флагов

PUSHAD;Сохранить все регистры

CLC;Очистить Флаг переноса

MOV ECX,NUMBER;Установить счетчик

LEA SI, WORD1A;Старшее слово числа DWORD1

LEA DI,WORD2A;Старшее слово числа DWORD2

LEA BX,WORD3A; Старшее слово числа суммы

Е20:

MOV AX,[SI+ECX];Поместить слово в AX

ADC AX,[DI+ECX];Сложить с переносом

MOV [BX+ECX],AX;Сохранить слово

DEC SI

DEC SI

DEC DI

DEC DI

DEC BX

DEC BX

LOOP Е20; Повторить цикл

POPAD

POP FX

RET

E10DWD ENDP

CODESG ENDS

END BEGIN

Рис. 4.24. Сложение двойных слов и слов любой длины

На рис.4.24 процедура E10DWD демонстрирует подход к сложению значений любой длины. Действие начинается со сложения самых правых слов складываемых полей. В первом цикле складываются правые слова, во втором - слова, расположенные левее и т.д. При этом адреса в регистрах SI, DI и BX уменьшаются на 2. По две команды DEC выполняют эту операцию для каждого регистра. Применять команду

SUB reg,02

в данном случае нельзя, так как при этом будет очищен флаг переноса, что приведет к искажению результата сложения.

Ввиду наличия цикла используется только одна команда сложения ADC. Перед циклом команда CLC (CLear Carry -очистить флаг переноса) устанавливает нулевое значение флага переноса. Для работы данного метода необходимо: 1) обеспечить смежность слов, 2) выполнять обработку справа налево и 3) загрузить в регистр CX число складываемых слов.

Для многословного вычитания используется команда SBB (SuBtract with Borrow - вычитание с заемом), эквивалентная команде ADC. Заменив в процедуре E10DWD (рис. 12.2) команду ADC на SBB, получим процедуру для вычитания.



Поделиться:


Последнее изменение этой страницы: 2016-09-13; просмотров: 355; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.118.227.69 (0.327 с.)