Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции препода / Лекции для 3 курса.doc
Скачиваний:
86
Добавлен:
30.04.2013
Размер:
1.51 Mб
Скачать

3.3. Арифметические команды

Процессор 80286 имеет четыре базовые арифметические операции в нескольких различных формах (табл. 3.6). Операции выполняются над 8-и 16-битными знаковыми и беззнаковыми операндами. Кроме того, предусмотрены команды для обработки десятичных чисел.

Таблица 3.6 Арифметические команды

Мнемоника команды

Описание команды

Сложение

ADD (сложить)

ПРИЁМНИК + ИСТОЧНИК ПРИЁМНИК

ADC (сложить с переносом)

ПРИЁМНИК + ИСТОЧНИК + CFПРИЁМНИК

INC (инкремент)

ПРИЁМНИК +1 ПРИЁМНИК

Вычитание

SUB (вычесть)

ПРИЁМНИК – ИСТОЧНИК ПРИЁМНИК

SBB вычесть с заёмом)

ПРИЁМНИК - ИСТОЧНИК – CF ПРИЁМНИК

DEC(декремент)

ПРИЁМНИК –1 ПРИЁМНИК

NEG(изменить знак)

0 - ПРИЁМНИК ПРИЁМНИК

CMP (сравнить)

ПРИЁМНИК – ИСТОЧНИК ?

Умножение

MUL (умножить)

AL*ИСТОЧНИК8 AX

AX*ИСТОЧНИК16 DX, AX

IMUL(умножить со знаком)

Команда MUL, но операнды знаковые.

Деление

DIV (разделить)

AX/ИСТОЧНИК8 AL

Остаток AH

ИСDX, AX/ИСТОЧНИК16 AX

Остаток DX

IDIV (разделить со знаком)

Команда DIV, но операнды знаковые.

Различие между знаковыми и беззнаковыми числами заключается в интерпретации двоичных наборов. Беззнаковые числа - это обычные двоичные числа (все биты значащие), а знаковые числа представлены в дополнительном коде. На рис. 3.7 показаны диапазон и представление знаковых и беззнаковых чисел. Операции сложения и вычитания одинако­вы для обоих типов чисел, т.е. обычные команды двоичного сложения и вычитания, разработанные для беззнаковых чисел, дают правильный результат и применительно к знаковым числам. Единственное различие между знаковыми и беззнаковыми сложением и вычитанием заключается в механизме обнаружения выхода за диапазон. Команды сложения и вычитания устанавливают флажок CF, если результат, интерпретируемый как беззнаковое число, оказывается вне диапазона; они уже устанавлива­ют флажок OF, если результат, интерпретируемый как знаковое число, выходит за диапазон. Возможны ситуации, когда знаковый или беззнако­вый результат будет вне диапазона, хотя другой результат оказывается в диапазоне (рис. 3.8).

Большинство арифметических команд устанавливают или сбрасывают шесть флажков состояния, показывающих определенные свойства резуль­тата. В общем, флажки фиксируют следующие особенности:

флажок CF устанавливается, если операция дала беззнаковый резуль­тат вне диапазона;

флажок OF устанавливается, если в операции получился знаковый результат, находящийся вне диапазона (так называемое знаковое перепол­нение);

флажок ZF устанавливается, если результат операции (знаковый или беззнаковый) равен нулю;

флажок SF устанавливается, если старший бит результата операции содержит 1, показывая отрицательное число;

флажок PF устанавливается, если результат операции содержит четыре число единичных бит (так называемый четный паритет);

флажок AF устанавливается, если в десятичных операциях требуется коррекция (подробнее см. далее).

Поведение флажков в арифметических операциях показано далее в табл. 3.22.

В арифметике многократной точности беззнаковые числа, длина которых более 16 бит, разделяются на 8- или 16-битные поля, а затем операции циклически выполняются над последовательными полями, начиная с младших. Если любая из этих операций дает результат вне диапазона, результат оказывается правильным, но 1 либо переносится (сложение), либо занимается (вычитание) в операции над следующими полями. Рассмотрим, например, сложение 24-битных чисел 0011 1010 0000 0111 1011 0010 и 0010 0000 1100 0010 0101 0011. Его можно выполнить за три сложения 8-битных чисел.

  1. Складываются младшие 8 бит:

+1011 0010

0101 0011

0000 0101 CF = 1

2. Суммируются средние 8 бит с учетом переноса, образованного в предыдущем сложении:

1(последний CF)

+0000 0111

1100 0010

1100 1010 CF = 0

3. Наконец, складываются старшие 8 бит с учетом переноса от предыду­щего сложения:

0(последний CF)

+0011 1010

0010 0000

0101 1010 CF = 0

Получен результат 0101 1010 1100 1010 0000 0101.

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

В арифметике многократной точности следует учитывать, что резуль­тат сложения и вычитания может оказаться вне диапазона. Это обычная ситуация, и она не свидетельствует об ошибке. Но выходящий за диапазон знаковый результат обычно не ожидается. Он показывает, что возникла ошибка и до продолжения расчетов результат необходимо скоррек­тировать.

Команды сложения. К командам сложения относятся ADD, ADC и INC. В общем, они применимы к любым операндам.

Команда ADD (табл. 3.7) суммирует байты или слова источника и приемника и помещает результат в приемник. Один из операндов может находиться в регистре или памяти, а другой - в регистре или в самой команде (непосредственный операнд).

Команда ADC аналогична команде ADD, но она привлекает для сложе­ния начальное значение CF, что упрощает реализацию арифметики с многократной точностью. Формы команды ADC такие же, как и у команды ADD (табл. 3.7).

Команда INC имеет всего один операнд. Она прибавляет 1 к содержи­мому операнда и помещает результат в этот же операнд. Примеры коман­ды INC показаны в табл. 3.8. Команда INC идентична команде ADD с непо­средственным операндом 1, но требует меньше байт. Она включена в систему команд потому, что прибавление (и вычитание) 1 встречается очень часто и должно осуществляться командой с минимальной длиной.

Таблица 3.7 Примеры двухоперандных и арифметических и логических команд

Операнды

Слово

Байт

Регистр с регистром в регистр

КОП AX, BX

КОП BL, CL

Регистр с памятью в регистр

КОП CX, MEMW

КОП DL, MEMB

Регистр с памятью в память

КОП MEMW, CX

КОП MEMB, DL

Регистр с непосредственным операндом в регистр

КОП DX, 490

КОП BL, 50

Память с непосредственным операндом в память

КОП MEMW, 490

КОП MEMB, 50

КОП обозначает: ADD, ADC,SUB, SBB, CMP, AND, OR, XOR, TEST

Таблица 3.8 Примеры однооперандных арифметических и логических команд

Операнд

Слово

Байт

Регистр

КОП BX

КОП DL

Память

КОП MEMW

КОП MEMB

КОП обозначает: INC, DEC, NEG, NOT

Команды вычитания. К командам вычитания относятся SUB, SBB, DEC, NEC и СМР. Первые три из них аналогичны трем командам сложе­ния. Примеры команд SUB, SBB и СМР показаны в табл. 3.7, а команд DEC и NEG - в табл. 3.8.

Команда NEG изменяет знак своего операнда. Если, например, опе­ранд содержит представление -1 (1111 1111), то команда NEG изменит его на +1(0000 0001).

Команда СМР аналогична команде вычитания, но результат не запоми­нается в приемнике. По существу, результат не запоминается нигде; он просто теряется в процессоре. Наверное, вы удивитесь: "Зачем нужна команда, результат которой теряется?" Оказывается, что состояние флаж­ков, отражающих определенные свойства результата, важнее чем сам результат. Благодаря им можно определить отношение между двумя операндами, участвующими в вычитании. Если, например, ZF = 1, то ре­зультат равен нулю и значения операндов должны быть одинаковыми.

Состояния флажков для всех возможных отношений показаны в табл. 3.9. После команды СМР обычно находится команда условного перехода (см. далее), которая проверяет по флажкам, удовлетворяется ли конкретное отношение.

Таблица 3.9 Состояния флажков после выполнения команды CMP

Отношение между приёмником и источником

CF

ZF

SF

OF

Равны

0

1

0

0

Знаковые операторы

Меньше

-

0

1

0

Меньше

-

0

0

1

Больше

-

0

0

0

Больше

-

0

1

1

Беззнаковые операнды

Ниже

1

0

-

-

Выше

0

0

-

-

Вместо прочерка может быть 0 или 1 в зависимость от значения операндов

Команды умножения и деления. Умножение двух 8-битных чисел мо­жет дать произведение длиной до 16 бит. Пример умножения беззнаковых

чисел показан на рис. 3.9.

Аналогично произведение двух 16-битных чисел может иметь длину 32 бита. Команды умножения процессора 80286 позволяют умножать 8- или 16-битную ве­личину, находящуюся в регистрахAL или АХ, на операнд такого же размера, определяемый в команде. Произведение длиной 16 или 32 бита помещается в реги­стре АХ я при необходимости в регистре DX, как показано на рис. 3.10.

Команды деления рассчитаны на противоположное по отношению к умножению действие. Они делят 16-битное число из регистра АХ (или 32-битное число из регистров АХ иDX) на операнд половинного размера, определяемый в команде. Частное помещается в регистр AL (АХ), а оста­ток - в АН (DX), как показано на рис. 3.11.

В отличие от команд сложения и вычитания команды обычного двоич­ного умножения и деления, работающие с беззнаковыми числами, не дают правильных результатов для знаковых чисел (рис. 3.12). Следовательно, для знаковых чисел потребуются специальные команды умножения и деления. В процессоре 80286 имеются команды MUL (беззнаковое умноже­ние), IMUL (знаковое умножение, которое иногда называется целочислен­ным

умножением),DIV (беззнаковое деление) и IDIV (знаковое деление, которое иногда называется целочисленным делением). Примеры команд умножения и деления приведены в табл. 3.10.

Таблица 3.10 Примеры команд умножение и деления

Операнд

Слова

Байты

AX (AL) с регистром

КОП BX

КОП CL

AX (AL) с памятью

КОП MEMW

КОП MEMB

КОП обозначает команды MUL, IMUL, DIV, IDIV

Поскольку при программировании часто возникает необходимость умножения на константу, в команде IMUL (но не в командах MUL, DIV или IDIV) разрешается определять множитель как непосредственный операнд. При этом множимое не обязательно должно быть в регистре АХ (AL), a может находиться в любом 16-битном регистре или в 16-битной ячейке памяти. Результат длиной 16 бит (а не 32 бита) допускается разместить в любом 16-битном регистре. Примеры такой команды IMUL показаны в табл. 3.11. Команды умножения IMUL с непосредственным операндом в микро­процессоре 8086 нет. Такую команду удобно применять для вычисления адресов элементов массивов с нечетным размером.

Таблица 3.11 Примеры команды IMUL с непосредственным операндом

Слово в регистре

IMUL DX, BX, 115

; BX*115 DX

Слово в памяти

IMUL CX, MEMW, 632

; MEMW*632 CX

Сделаем замечание о знаковом делении. Если разделить -26 на +7, можно получить частное -4 и остаток +2, но можно получить частное -3 и остаток -5. Любая пара чисел дает правильный результат, но в первом случае остаток положителен, а во втором - отрицателен. Команда знако­вого деления IDIV действует так, что остаток всегда имеет такой же знак, как и делимое. В приведенном примере будут получены частное -3 и остаток -5. Определенное таким образом деление дает частное (и остаток) с одним и тем же абсолютным значением при делении -26 на +7, +26 на +7 и +26 на -7.

В табл. 3.12 показано число бит операндов и результатов различных арифметических команд. Команды действуют так, чтобы результат двой­ной длины при умножении можно было использовать в последующем делении. А если вам нужно использовать результат умножения для чего-то еще, кроме деления? Как, например, умножить 17 (0001 0001) на 10 (0000 1010) и прибавить к произведению 20 (0001 0100)? Для этого нужно просто отбросить старшие 8 бит произведения. Однако теперь возникает проблема деления числа, которое не образовано предыдущим умножением. Попробуйте, например, поделить 8-битное число 35 (0010 0011) на 7 (0000 0111). В команде деления предполагается, что 16-битное делимое находится в регистре АХ. Простое размещение 8-битного делимого в регистре AL не дает правильного результата, так как в делении будет участвовать "му­сор", находящийся в регистре АН. Однако трудность преодолевается, если очистить регистр АН перед 8-битным делением или регистр DX перед 16-битным делением.

Таблица 3.12 Размеры операндов и результатов

Операция

Первый операнд

Второй операнд

Результат

СЛОЖЕНИЕ

8 (слагаемое)

8 (слагаемое)

8 (сумма)

16 (слагаемое)

16 (слагаемое)

16 (сумма)

ВЫЧИТАНИЕ

8 (уменьшаемое)

8 (вычитаемое)

8 (разность)

16 (уменьшаемое)

16 (вычитаемое)

16 (разность)

УМНОЖЕНИЕ

8 (множимое)

8 (множитель)

16 (произведение)

16 (множимое)

16 (множитель)

32 (произведение)

ДЕЛЕНИЕ

16 (делимое)

8 (делитель)

8 (частное)

8 (остаток)

32 (делимое)

16 (делитель)

16 (частное)

16 (остаток)

Сброс старшей половины делимого двойной длины хорошо действует для беззнакового деления, а как быть со знаковым делением? Преобразо­вание 8-битного числа -2 (1111 1110) в 16-битное (1111 1111 1111 1110) связано с установкой 8 старших бит в 1, а преобразование 8-битного числа +3 (0000 0011) в 16-битное (0000 0000 0000 0011) - с установкой 8 старших бит в 0. Правило преобразования довольно простое: нужно продублиро­вать левый бит (иногда называемый знаковым) 8-битного числа в каждом разряде старшей половины 16-битного числа. Напомним, что "удлинение" чисел путем дублирования знакового бита называется расширением со знаком. Для этой операции предусмотрены специальные команды. Сначала они называлисьSEX (Sign Extend), а затем их переименовали в более умеренные по звучанию команды CBW (преобразовать байт в слово) и CWD (преобразовать слово в двойное слово). Команда CBW расширяет знаковый бит регистра AL во все биты регистра АН, а команда CWD расширяет знаковый бит регистра АХ во все биты регистра DX. На рис. 3.13 показано, как осуществить деление 8- и 16-битных операндов.

Десятичная арифметика.До сих пор мы рассматривали арифметичес­кие операции над двоичными числами. Компьютеры работают с двоичными числами, но для людей более привычны десятичные. Мы живем в "деся­тичном мире", и если бы всевышний захотел, чтобы мы работали с двоич­ными числами, мы бы рождались всего с двумя пальцами. Поэтому первая проблема, с которой мы сталкиваемся при общении с компьютером, заключается в преобразовании входных чисел на язык компьютеров и в обратном преобразовании результатов. Конечно, на эти преобразования расходуется время. Но гораздо хуже то, что компьютер решает задачи не так, как мы, а это может приводить к удивительным результатам. Напри­мер, нас привело бы в замешательство то, что показания компьютеризо­ванного спидометра в автомобиле сбрасывались бы после 131 072 миль (а не 99 999) только потому, что 131 072 является степенью числа два.

Почему же большинство компьютеров "мыслят по двоичным зако­нам"? Только потому, что они работают всего с двумя уровнями напряже­ния (0 и 1) и должны представлять числа в двоичной системе счисления. Конечно, нулями и единицами можно закодировать каждую десятичную цифру в отдельности. Например, вместо представления десятичного числа 37 его двоичным эквивалентом 0010 0101 можно взять двоичные коды 3 (0011) и 7 (0111), что дает представление 0011 0111. Такое двоичное изобра­жение десятичных цифр называется двоично-десятичным кодированием (BCD). В табл. 3.13 показано кодирование всех десятичных цифр. Применение в компьютерах двоичных чисел вместо двоично-десятичных объясня­ется тем, что двоичное представление компактнее. Например, число 125 можно представить в 8 битах как двоичное число 01111101, но для BCD-ко­да потребуется 12 бит - 0001 0010 0101.

Таблица 3.13 BCD-кодирование десятичных чисел

Цифра

0

1

2

3

4

5

6

7

8

9

Код

0000

0001

0010

0011

0100

0101

0110

0111

1000

1001

Как же выполнять арифметические операции с BCD-числами? Можно ли их складывать, вычитать, умножать и делить? Для этого в системе команд компьютера наряду (или вместо) с командами двоичных операций потребовалось бы ввести команды BCD-сложения, BCD-вычитания, BCD-умножения и BCD-деления. Но можно как второй вариант применить команды двоичной арифметики к BCD-числам, заранее зная о неправиль­ном результате, а затем выполнить специальную команду коррекции, которая сформирует правильный BCD-результат. Именно такой вариант выбран в процессоре 80286.

Рассмотрим сложение BCD-чисел 23 и 14 с помощью команды 8-битного двоичного сложения. Будет получено:

+0010 0011 = 23

0001 0100 =14

0011 0111 = 37

Здесь двоичное сложение дает правильный BCD-результат! Коррекции не требуется. Попробуем теперь сложить 29 и 14:

+0010 1001 = 29

0001 0100 =14

0011 1101 =3?

Ответ неверен, так как код 1101 не соответствует никакой десятичной цифре. В четырех битах можно представить 16 различных цифр, но десятич­ных цифр всего десять. Поэтому сложение двух цифр, когда сумма превы­шает 9, ведет в запрещенный диапазон и дает неправильный результат. Коррекция заключается в том, чтобы прибавить 6 к сумме в тех разрядах, где получена запрещенная комбинация, компенсируя этим 6 запрещенных комбинации. В предыдущем примере сумма корректируется так:

+0011 1101 = 3?

0110 = 06

0100 0011 = 43

Получен правильный результат 43. Здесь переход в запрещенный диапазон обнаруживается очень просто. Более сложная ситуация возника­ет, когда сумма "проскакивает" запрещенный диапазон и становится допустимой цифрой. Рассмотрим, например, сложение BCD-чисел 29 и 18:

+0010 1001 = 29

0001 1000 = 18

0100 0001 = 41

Результат оказался неверным, так как младшая цифра суммы "проско­чила" запрещенный диапазон, поэтому ее нужно скорректировать, прибав­ляя 6. Однако необходимость такой коррекции по самому результату установить невозможно. Признаком "проскакивания" цифрой запрещенно­го диапазона служит перенос из соответствующего бита (разряда). В приве­денном примере им будет перенос из младшего (десятичного) разряда в старший. Следовательно, результат можно скорректировать, если знать переносы из десятичных разрядов. Флажок переноса CF показывает, что при сложении возник перенос из старшего бита (и, следовательно, из стар­шего десятичного разряда). Флажок вспомогательного переноса AF предна­значен только для регистрации переноса из младшего десятичного разря­да, зная который можно осуществить BCD-коррекцию. В приведенном вы­ше примере после двоичного сложения CF = 0 и AF = 1.

Арифметические операции можно выполнять и над многоразрядными BCD-числами. Покажем сложение чисел 2889 и 3714, которое реализуется двумя операциями сложения и коррекции.1. Суммируются младшие пары цифр:

+1000 1001 = 89

0001 0100 = 14

1001 1101 = 9? CF = 0,AF = 0

2. Выполняется коррекция:

+1001 1101 =9?

0110 = коррекция

+1010 0011 = ?3

0110 = коррекция

0000 0011 = 03 CF=1, AF =0

3. Суммируются старшие пары цифр с учетом флажка CF:

1(последнее значение CF)

+0010 1000 =28

0011 0111 =37

0110 0000 =60 CF = 0, AF=1

4. Производится коррекция:

01100000 = 60

0110 = коррекция

0110 0110 = 66

5. Окончательный результат равен 0110 0110 0000 0011 = 6603

Десятичную коррекцию осуществляет команда DAA (десятичная коррекция для сложения), в которой предполагается, что сумма находится в регистре AL. С учетом содержимого регистра AL и состояний флажков AF и CF команда DAA определяет необходимость коррекции и реализует ее для регистра AL. Аналогичная команда DAS (десятичная коррекция для вычитания) корректирует результат после операции вычитания. Для умножения применить коррекцию невозможно, так как в BCD-результате "замешаны" перекрестные члены произведения. По аналогичной причине невозможно скорректировать результат деления. Следовательно, при необходимости умножения и деления десятичных чисел потребуется перейти к другому представлению десятичных чисел, на котором мы и остановимся.

Рассмотренный BCD-формат точнее назвать упакованным десятичным форматом, так как в байте упакованы две цифры. В неупакованном форма­те байт содержит всего одну десятичную цифру. Она находится в четырех младших битах, а старшие биты не влияют на значение цифры. Примером неупакованного десятичного формата служит код ASCII, в котором симво­лы представляются семью битами. Кодирование цифр показано в табл. 3.14. Здесь четыре старших бита содержат 0011, но эта комбинация на значение цифры не влияет.

Таблица 3.14 Представление цифр в коде ASII

Цифра

Код ASII

Цифра

Код ASII

0

0011 0000

5

0011 0101

1

0011 0001

6

0011 0110

2

0011 0010

7

0011 0111

3

0011 0011

8

0011 1000

4

0011 0100

9

0011 1001

Результат двоичного сложения и вычитания ASCII-чисел можно скор­ректировать аналогично BCD-коррекции, причем корректируется только младшая цифра. Команды, осуществляющие коррекцию, называются командами ASCII-коррекции: ААА (ASCII-коррекция для сложения), AAS (ASCII-коррекция для вычитания), ААМ (ASCII-коррекция для умножения) и AAD (ASCII-коррекция для деления).

Как пример ASCII-умножения, рассмотрим умножение числа 9 на 4. Предположим, что число 9 (0000 1001) находится в регистре BL, а число 4 (0000 0100) - в регистре AL. Команда беззнакового двоичного умножения с множителем BL (т.е. команда MUL AL, BL) образует в регистре АХ 16-бит-ное произведение, равное 36 (0000 0000 0010 0100). Команда коррекции ААМ должна "разложить" результат на 3 (0000 0011) в регистре АН и на 6 (0000 0110) в регистре AL. Для этого нужно просто разделить содержимое AL на десять и поместить частное в регистр АН, а остаток в AL. Оказывает­ся, не случайно команда ААМ имеет длину два байта (ведь было бы доста­точно одного байта), причем второй байт - это двоичное представление десяти (1010). По существу, команда ААМ является разновидностью команд деления (хотя она и не помещает частное и остаток в те же регист­ры, что и команды DIV и IDIV), в которой второй байт команды содержит делитель. Мы не удивимся, если изменение второго байта с 10 (0000 1010) на 7 (0000 0111) приведет к команде "деления на 7", хотя фирма Intel этого не обещает. Но можно предположить также, что при размещении во втором байте числа 16 (0001 0000) реализуется преобразование упакованного BCD-числа из регистра AL в неупакованное число в регистрах АН и AL.

В рассмотренном примере операнды 0000 1001 и 0000 0100 были неупа­кованными числами с нулями в четырех старших битах. Если бы в них были не нули, при умножении появились бы перекрестные члены, которые скрыли бы нужный результат 0010 0100 (именно такие члены делают невозможной коррекцию BCD-умножения). Поэтому перед умножением неупакованных чисел нужно сбросить четыре старших бита каждого опе­ранда, если в исходном состоянии они не содержат нулей. Для сброса вы­бираемых бит в байте удобно воспользоваться командой AND (см. далее).

Мы рассмотрели умножение одноразрядных неупакованных деся­тичных чисел, а теперь попробуем умножить многоразрядное число на одну цифру, например 539 на 6. В школе нас учили умножать следующим образом:

девять, умноженное на 6, дает 54. Записываем 4 и переносим 5 ("четы­ре пишем, пять в уме"). Три умножаем на 6, получаем 18, прибавляем 5 и имеем 23. Записываем 3 и переносим 2. Пять умножаем на 6, полу­чаем 30, прибавляем 2 и окончательно записываем 32. Процесс умножения выглядит примерно так:

25 (переносы)

x539

6

3234

Теперь посмотрим, как эту задачу решает процессор 80286. Предполо­жим, что неупакованное число 539 хранится в переменных а3, а2 и a1, a число 6 - в переменной b. Будем полагать, что в старших четырех битах а3, а2, a1 и b находятся нули. Мы хотим умножить значения а3, а2, a1 на значение переменной b и поместить результат в переменные с4, с3, c2, c1:

Xa3a2a1

b

c4c3c2c1

Программа такого умножения состоит из следующих шагов:

Отметим в программе наличие команд сложения и соответствующих команд коррекции ААА. Рассмотрим одну из команд ААА подробнее. Когда команда ААА в строке 8 превращает неверное число в регистреAL (0000 1101) в правильное 3 (0000 0011), возникает перенос из младшей цифры регистра AL. Этот перенос не подается в старшую цифру регистра AL, а направляется в младшую цифру регистра АН, корректируя содержи­мое АН с 1 (0000 0001) на 2 (0000 0010). Следовательно, команда ААА осу­ществляет коррекцию содержимого не только регистра AL, а обоих регист­ров АН и AL. Такое действие команды ААА было бы ненужным, если бы она применялась только для сложения, а не умножения.

Более компактный алгоритм с циклом для многоразрядного неупако­ванного умножения показан на рис. 3.14. Хотя мы рассмотрели только одноразрядные множители, обобщение алгоритма на многоразрядные множители не вызывает серьезных трудностей.

Обратимся теперь к делению неупакованных чисел, например разде­лим 42 на 6. Будем считать, что 42 находится в регистре АХ (0000 0100 - в АН, 0000 0010 в AL), а 6 (0000 0110) - в BL. Неупакованное представле­ние одноразрядного числа, например 6, является и его двоичным представ­лением. Следовательно, делимое 42 нужно преобразовать в двоичное число. Для этого содержимое АН умножается на 10 и прибавляется k содержимому регистра AL. Тогда двоичное деление содержимого регистра AL (двоичного числа 42) на содержимое регистра BL (6) образует в AL двоичное представление 7, которое совпадает с неупакованным представ­лением 7; на этом неупакованное деление закончено.

Подчеркнем в рассмотренном примере три важных момента. Во-пер­вых, коррекция деления (AAD) заключается в умножении содержимого, регистра АН на 10 и прибавлении к содержимому регистра AL (не случайно второй байт команды AAD содержит число 10). Во-вторых, коррекция деления предшествует операции деления, а в сложении, вычитании и умножении коррекция производится после соответствующей арифметичес­кой операции. Другими словами, коррекция сложения, вычитания и умножения исправляет "плохой" результат, а коррекция деления пре­дотвращает получение "плохого" результата. В-третьих, делимое и дели­тель должны иметь нули в старших четырех битах. Это же требование относится и к умножению, но не обязательно для сложения и вычитания.

Многоразрядное делимое можно разделить на одноразрядный дели­тель примерно так же, как это было сделано для умножения (см. алгоритм на рис. 3.14). К сожалению, этот метод не допускает обобщения на много­разрядный делитель. Можно рекомендовать алгоритм деления, в котором делается предположение о частном, затем с помощью умножения и вычита­ния неупакованных чисел проверяется правильность предположения и оно последовательно уточняется. Примерно так мы осуществляем деление длинных чисел на бумаге. Однако имеются и более совершенные алгорит­мы деления.

ЛЕКЦИЯ 5. ЛОГИЧЕСКИЕ КОМАНДЫ

Логические команды процессора 80286 состоят из булевых команд и команд сдвигов /циклических сдвигов (см. табл. 3.15).

Таблица 3. 15 Логические команды

Мнемоника команды

Описание команды

AND

ПРИЁМНИК  ИСТОЧНИК ПРИЁМНИК

TEST

ПРИЁМНИК  ПРИЁМНИК ?

OR

ПРИЁМНИК  ИСТОЧНИК ПРИЁМНИК

XOR

ПРИЁМНИК  ИСТОЧНИК ПРИЁМНИК

NOT

ПРИЁМНИК ПРИЁМНИК

SHL (сдвиг логический влево)

CF ПРИЁМНИК 0

SHR (сдвиг логический вправо)

0 ПРИЁМНИК CF

SAL (сдвиг арифметический влево)

Аналогично SHL

SAR (сдвиг арифметический вправо)

Знак ПРИЁМНИК CF

ROL (циклический сдвиг влево)

ROR (циклический сдвиг вправо)

RCL (циклический сдвиг влево через перенос)

RCR (циклический сдвиг вправо через перенос)

Булевы команды. К булевым относятся команды NOT, AND, OR, XOR и TEST. Примеры их были приведены в табл. 3.7 и 3.8.

Команды AND, OR и XOR выполняют логическую функцию над соот­ветствующими битами источника и приемника, помещая результат в приемник. Команда NOT имеет всего один операнд; она выполняет инвер­сию каждого его бита и помещает результат в то же место. Логические функции, реализуемые рассматриваемыми командами, определены в табл. 3.16.

Таблица 3. 16 Определение логических функций

Однооперандная

Бит источника

NOT

0

1

1

0

Двухоперандные

Бит источника

Бит приёмника

AND

OR

XOR

0

0

0

0

0

0

1

0

1

1

1

0

0

1

1

1

1

1

1

0

Функцию AND (И) удобно применять для сброса (маскирования) указанных разрядов в числе; один операнд определяет разряды, а второй - само число. Например, можно сбросить старшие четыре бита в 8-битном числе, объединяя его по И с набором 0000 1111. (Напомним, что сброс этих бит требуется до выполнения десятичного умножения и деления.)

Функции OR (ИЛИ) и XOR (исключающее ИЛИ) применяются для установки в 1 и инвертирования указанных разрядов в числе. Например, для установки в 1 старшего бита 8-битного числа следует объединить его по ИЛИ с набором 1000 0000, а для инвертирования средних четырех бит 8-битного числа нужно объединить его по исключающему ИЛИ с набором ООП 1100. Команда XOR позволяет также сбросить содержимое регистра в нуль (регистр должен быть и источником, и приемником). Функция NOT (НЕ) инвертирует все биты числа; она эквивалентна команде XOR с операн­дом-источником 1111 1111.

Команда TEST объединяет возможности команд AND и СМР. Как команда AND, она выполняет объединение по И соответствующих бит операндов; как команда СМР, она сохраняет только состояния флажков, а не результат. Она удобна для проверки того, есть ли в указанных разрядах числа хотя бы одна 1. Здесь один операнд определяет разряды, а второй - число. Если (уничтожаемый) результат не равен 0, о чем сигнализирует флажок ZF = 0, то, по крайней мере, один из указанных разрядов содержит 1. Например, для проверки наличия 1 в четырех младших битах регистра BL следует поместить 0000 1111 в регистр ВН, выполнить команду TEST BL, ВН, а затем воспользоваться командой условного перехода, которая передает управление, если ZF = 0. Конечно, вместо команды TEST можно применить команду AND, но при этом операнд-приемник будет уничтожен.

Команды сдвигов. Команды сдвигов являются эффективным средст­вом увеличения и уменьшения числа вдвое (меньше байт и тактов, чем в умножении и делении). Для удвоения беззнакового числа нужно сдвинуть все биты на один разряд влево, а в освобождающийся правый бит помес­тить 0. Если выдвинутый слева бит передать во флажок CF, то можно зафиксировать выход за диапазон, проверив условие CF - 1. Например, удвоение числа 65 (0100 0001) с помощью сдвига влево дает 130 (1000 0010) и CF = 0 (в диапазоне), а сдвиг влево числа 130 (1000 0010) дает 4 (0000 0100) и CF = 1 (вне диапазона). Аналогично уменьшение беззнакового числа вдвое осуществляется сдвигом всех бит на один разряд вправо, в освобож­дающийся бит помещается 0, а выдвигаемый справа бит передается во флажок CF. В этом случае CF = 1 показывает, что число было нечетным. Например, сдвиг вправо числа 9 (0000 1001) дает 4 (0000 0100) и CF = 1.

С беззнаковыми числами работают команды SHL (сдвиг влево) и SHR (сдвиг вправо), а команды SAL (арифметический сдвиг влево) и SAR (арифметический сдвиг вправо) предназначены для знаковых чисел.

Различие между уменьшением вдвое знакового числа (SAR) и беззна кового числа (SHR) заключается в том, что в первом случае левый бит (знак) изменяться не должен. Например, уменьшение вдвое числа +6 (0000 0110) должно дать +3 (0000 0011), а числа -120 (1000 1000) - дать результат -60 (1100 0100). Следовательно, команда SAR сдвигает все биты на один разряд вправо, но сохраняет знаковый бит неизменным; команда же SHR помещает в знаковый бит 0.

Отметим, что результатом команды SAR с операндом +5 (0000 0101) будет число +2 (0000 0010), а с операндом -5 (1111 1011) - число -3 (1111 1101). Сдвиг вправо нечетного числа всегда дает результат, который меньше половины числа (-3 < -21/2). К сожалению, это число не совпадает с результатом команды DIV; деление числа -5 на 2 с использованием DIV дает-2.

Различий между удвоением знакового и беззнакового чисел нет. Поэтому мнемоники SHL и SAL относятся к одной и той же команде.

Команды циклического сдвига позволяют переставить биты в числе. Команды ROL (циклический сдвиг влево) и ROR (циклический сдвиг вправо) обеспечивают циклический сдвиг влево и вправо: выдвигающийся бит подается в освобождающийся бит. В команде RCL (циклический сдвиг влево через перенос) и RCR (циклический сдвиг вправо через перенос) в кольцо сдвига включается флажок CF: выдвигающийся бит подается во флажок CF, а состояние флажка CF передается в освобождающийся бит.

Операнд команд сдвигов может находиться в памяти или в регистре; длина операнда равна 8 или 16 бит. Сдвиг осуществляется на предопреде­ленное число бит (фиксированный сдвиг) или на любое число бит (перемен­ный сдвиг). В первом случае число сдвигов определяется в команде, а во втором - содержимым регистра CL, называемого счетчиком (вот еще один пример специализации одного из регистров общего назначения). Примеры команд сдвигов показаны в табл. 3.17. (В микропроцессоре 8086 фиксиро­ванный сдвиг осуществляется только на один бит.)

Таблица 3. 17 Примеры команд сдвигов

Фиксированный сдвиг

Операнд

Слово

Байт

Регистр

КОП BX, 13

КОП DL, 1

Память

КОП MEMW, 1

КОП MEMB, 7

Переменный сдвиг

Операнд

Слово

Байт

Регистр

КОП AX, CL

КОП BL, CL

Память

КОП MEMW, CL

КОП MEMB, CL

Соседние файлы в папке Лекции препода