3.Умножение и деление целых чисел
В отличие от сложения и вычитания в микропроцессоре существуют по 2 операции умножения и деления: отдельно для чисел без знака и для чисел со знаком. Инструкции MUL используется для умножения беззнаковых величин, а инструкция IMUL – для умножения знаковых чисел. Обе инструкции могут изменять состояние флагов переноса CF и переполнения OF. На программиста возлагается задание формата данных, подлежащих обработке, и выбор подходящей инструкции умножения. Формат инструкций следующий: MUL регистр MUL память IMUL регистр IMUL память. Можно умножать байт на байт, слово на слово и в 32-разрядных моделях Intel – двойное слово на двойное слово. Как видно из формата, в команде указывается только один из сомножителей, второй сомножитель по умолчанию располагается в регистре AL для байтовых операндов и в регистре АХ – для двухбайтовых операндов. Для операции умножения правило операндов описано таблицей:
Примеры команды MUL: BYTE1 DB 80H BYTE2 DB 40H WORD1 DW 8000H WORD2 DW 2000H MOV AL, BYTE1 ; байт умножается на байт MUL BYTE2 ; результат в АХ, равный 2000Н (8192=128*64) (если до команды MOV AL, BYTE1 в АН содержались какие-либо данные, командой MUL BYTE2 эти данные будут затерты) MOV AX, WORD1 ; слово умножается на слово MUL WORD2 ; результат в в DX: AX, равный 1000 0000Н Как видно из таблицы, операнды-сомножители должны иметь одинаковый формат: либо оба операнда – байты, либо оба операнда – слова. Если потребуется умножить байт на слово, необходимо сначала привести в соответствие размеры операндов. В Ассемблере существуют команды CBW –преобразовать байт в слово и CWD – преобразовать слово в двойное слово. Обе команды не имеют операндов. Команда CBW по умолчанию оперирует содержимым регистра AL, а результат помещает в регистр AX. Команда CWD по умолчанию выбирает слово из регистра AX и помещает результат в DX: AX. Преобразование заключается в заполнении битом знакового разряда старших регистров результата – для команды CBW – регистра АН, а для команды CWD – регистра DX.
СBW – преобразовать байт в регистре AL в слово в регистре АХ путем распространения старшего бита AL на все биты регистра AH; CWD –преобразовать слово в регистре АХ в двойное слово в регистрах AX и DX, путем распространения старшего 15-ого бита регистра АХ на все биты регистра DX. Эти команды позволяют приводить разноформатные операнды к одному формату (большему). Обе команды дают верный результат при работе со знаковыми данными, но могут давать ошибочные результат с беззнаковыми данными. Например, MOV AL, BYTE2 CBW позволит получить результат в АХ, равный 0020Н, а команды MOV AL, BYTE1 CBW даст результат в АХ, равный FF80H, что, конечно, неверно. Поэтому для беззнаковых данных при необходимости преобразования к большему формату следует заполнить нулями старшую часть операнда расширенного формата и оперировать в последующих командах расширенным операндом, например: MOV AL, BYTE1 MOV AH, 0 ; поместили сомножитель в регистр АХ MUL WORD2 ; результат в в DX: AX, равный 1 0000Н Команда IMUL реализует перемножение знаковых чисел. Результаты применения этой инструкции к приведенным выше данным будут следующие: MOV AL, BYTE1 ; байт умножается на байт IMUL BYTE2 ; результат в АХ, равный E000Н (-8192=-128*64) MOV AX, WORD1 ; слово умножается на слово MUL WORD2 ; результат в в DX: AX, равный F0000000Н
MOV AL, BYTE1 CBW ; поместили сомножитель в регистр АХ (FF80H) IMUL WORD1 ; результат в в DX: AX, равный 0040 0000Н.
После выполнения команд флаги СF и OF показывают какая часть произведения существенна для дальнейших операций. При умножении чисел без знака эти флаги равны 0, если старшая часть результата нулевая, в противном случае (результат превысил по значащим цифрам сомножители) флаги устанавливаются в 1. Приумножении чисел со знаком флаги равны 0, если старшая половина произведения содержит расширение знакового разряда младшей половины (при положительном результате это 0, при отрицательном –1). Обратите внимание, что эти операции не позволяют иметь в качестве операнда константу (непосредственное значение). Результат перемножения правильных неупакованных BCD-чисел может быть представлен в неупакованном формате BCD-чисел с помощью команды ААМ. Команда работает с регистрами AL и AH и выполняет следующее: делит значение регистра AL на 10 и запоминает частное в регистре АН (старшая неупакованная цифра результата) и остаток – регистре AL (младшая неупакованная цифра результата). Однако очевидно, что этими операциями можно выполнить только табличное умножение. Для более сложных операций умножения необходимо разработать программу, реализующую умножение “в столбик”, получение частных произведений, их сдвиги и сложение. Операции, аналогичной ААМ для упакованных BCD-чисел в микропроцессоре не существует. В операции деления также, как и при умножении учитывается знак: операция DIV обрабатывает беззнаковые числа, а опtрация IDIV – знаковые. Подходящую команду в каждом конкретном случае выбирает программист. Основные форматы операций деления делят слово на байт, двойное слово на слово. А в 32-разрядных моделях компьютеров еще и учетверенное слово на двойное слово. Формат инструкций следующий: DIV регистр DIV память IDIV регистр IDIV память. Как видно из формата, в команде указывается только делитель, делимое по умолчанию располагается в регистре AХ или в паре регистров DX: АХ. Для деления правило расположения операндов отражается в таблице:
Примеры команды DIV: BYTE1 DB 80H BYTE2 DB 16H WORD1 DW 2000H WORD2 DW 0010H WORD3 DW 1000H MOV AX, WORD1 ; делимое -> в АХ DIV BYTE1 ; получим частное вAL, остаток – AH ; в AL – значение 40Н (8192: 128=64-частное и 0 –остаток), в АН –00Н Интерпретируем значение в BYTE1 как беззнаковое и разделим его на значение из BYTE2. MOV AH, 0 ; подготавливаем старшую часть делимого MOV AL, BYTE1 ; заполняем младшую часть делимого DIV BYTE2 ; делим слово на байт, в AL 05Н, в AH – 12Н При делении может возникать прерывание ”деление на 0”. Такой результат может получиться не только, когда делитель равен 0, но и в следующих случаях: 1) при делении чисел без знака для ситуации первой строки таблицы делимое более чем в 256 раз больше делителя, 2) при делении чисел без знака для ситуации второй строки таблицы делимое более чем в 65636 раз больше делителя, 3) при делении чисел со знаком для ситуации первой строки таблицы делимое более чем в 128 раз больше значения делителя, 4) при делении чисел со знаком для ситуации второй строки таблицы делимое более чем в 32768 раз больше значения делителя. Приведу некоторые полезные приемы программирования. Если частное слишком велико, можно выполнить деление с помощью последовательного вычитания делителя из делимого, например, делимое представляет слово, а делитель – байт, однако результат деления превышает байт (численные значения могут быть такими: делимое-64000, делитель – 80, результат деления 800 превышает максимальное значение, хранимое в одном байте). Фрагмент программы при условии, что делимое находится в регистре АХ, а делитель – в регистре ВХ, может быть следующим: SUB CX, CX ; очистка регистра частного L20: CMP AX, BX ; если делимое меньше делителя JB L30 ; вычитания закончить SUB AX, BX ; вычесть делитель из делимого INC CX ; увеличить частное на 1
JMP L20 ; идти на начало цикла вычитания L30: . . . . . . . . При попадании в точку L30 СХ содержит частное, АХ – остаток. Если делимое – двойное слово в паре DX: AX, то SUB CX, CX ; очистка регистра частного L20: CMP DX, 0 ; пока DX не 0 – делимое больше делителя JNE L30 CMP AX, BX ; если делимое меньше делителя JB L40 ; вычитания закончить L30: SUB AX, BX ; вычесть делитель из делимого SBB DX, 0 ; учесть возможный заем ; SUB AX, BX ; вычесть делитель из делимого INC CX ; увеличить частное на 1 JMP L20 ; идти на начало цикла вычитания L40: . . . . . . . . Большое делимое и малый делитель вызовут многократное повторение команд! Если необходимо разделить число на степени числа 2, то можно деление заменить сдвигами, например требуется разделить двойное слово в паре DX: AX на 16: SHR AX, 04 ; делим младшую часть делимого MOV BL, DL ; сохраняем 3-ий байт в BL SHR DX, 04 ; делим старшую часть делимого SHL BL, 04 ; умножаем 3-ий байт на 16, поскольку младший полубайт старшего слова должен перейти в старший полубайт младшего слова результата OR AH, BL добавляем полубайт к 3-ему байту результата Для вышеприведенного фрагмента можно дать следующую наглядную интерпретацию(см. рисунок 9. 1). Первая позиция рисунка отображает исходное значение двойного слова, каждая следующая позиция отражает результат выполнения команды программы. Не отражаемые в очередной позиции байты регистров не изменяются, т. е. остаются такими же, как и в предыдущей позиции. В правильности результата легко убедиться, если сдвинуть на 4 разряда вправо каждый разряд исходного кода.
DX AX
DL BL
DX BL
DX AX
Рисунок 9. 1. Наглядная интерпретация фрагмента программы деления двойного слова на 16
Процесс выполнения деления 2 неупакованных BCD-чисел может быть представлен в формате неупакованных BCD-чисел. Для этого перед операцией деления в регистре АХ получают 2 неупакованные цифры делимого (выполняет эту операцию программист удобным для него способом). Далее командой AAD преобразуется число в двоичное, которое затем является делимым в операции DIV. Причем в дальнейшей операции DIV двоичное число делится на неупакованную BCD-цифру, находящуюся в байтовом регистре или в байтовой ячейке памяти. Результат операции получается так, как описано 1-ой строкой таблицы. Понятно, что с применением этих команд можно выполнять очень простые операции деления, но команду AAD можно использовать и в контексте преобразования упакованного (или неупакованного) десятичного числа из диапазона 00-99 в двоичный эквивалент.
К группе арифметических команд относят команды расширения операнда, которые называются командами преобразования: Рассмотрев арифметические операции можно сделать следующие выводы: 1) рассмотренная нами группа команд выполняет известные арифметические операции над целыми числами, для работы с вещественными числами применяют команды сопроцессора; 2) многие команды имеют только один операнд или не имеют операндов вообще, поскольку по умолчанию работают с определенными регистрами общего назначения; 3) арифметические операции чувствительны к размерности операндов, поэтому эту характеристику необходимо отслеживать программисту; 4) контроль за правильностью арифметических операций полностью лежит на программисте; программист должен отслеживать состояние арифметических флагов во время вычислительного процесса и принимать правильные решения по дальнейшей обработке; 5) для чисел со знаком установка в 1 флага OF говорит о том, что в результате сложения чисел одного знака результат выходит за границу допустимых значений чисел со знаком в данном формате и сам результат меняет знак (имеет другой знак, чем его операнды).
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|