7.7.4. Команды сравнения

Как и в наборе команд микропроцессора 8088, у сопроцессора 8087 есть команды, сравнивающие два числа. Сопроцессор 8087 отбрасывает результат сравнения, но устанавливает в соответствии с ним флаги состояния. Перед тем как опросить флаги состояния, программа должна считать слово состояния в память. Далее проще всего загрузить флаги состояния в регистр AH, а затем, для легкости проверки условия, - в регистр флагов макропроцессора 8088.

На Фиг. 7.18 показан листинг ассемблера команд сравнения сопроцессора 8087. Так как в операции всегда участвует вершина стека, в программе надо указать только один регистр или операнд в памяти. После сравнения в слове состояния содержится информация о соотношении двух чисел. Таблица на Фиг. 7.19 показывает возможные варианты соотношений. Для отражения результата сравнения необходимы только два бита состояния - C3 и C0; расположение C3 и C0 в слове состояния показано на Фиг. 7.8. На Фиг. 7.20 приведен фрагмент программы, которая сравнивает содержимое вершины стека и слово в памяти. Переходы в этой программе выполняются на основе результата сравнения. В одном из четырех случаев числа нельзя сравнить. Это происходит тогда, когда одно из чисел есть NAN (не число) или одна из форм бесконечности.


Microsoft (R) Macro Assembler Version 5.00                  1/1/80 04:03:56
Фиг. 7.18 Команды сравнения сопроцессора 8087                     Page  1-1
PAGE  ,132
                         TITLE    Фиг. 7.18 Команды сравнения сопроцессора 8087

0000                     CODE     SEGMENT

                                  ASSUME    CS:CODE,DS:CODE
0000                     WORD_INTEGER       LABEL   WORD
0000                     SHORT_INTEGER      LABEL   DWORD
0000                     SHORT_REAL         LABEL   DWORD
0000                     LONG_REAL          LABEL   QWORD
0000    9B D8 D1                  FCOM
0003    9B D8 D2                  FCOM      ST(2)
0006    9B DE 16 0000 R           FICOM     WORD_INTEGER
000B    9B D8 16 0000 R           FCOM      SHORT_REAL
0010    9B D8 D9                  FCOMP
0013    9B DA 1E 0000 R           FICOMP    SHORT_INTEGER
0018    9B DC 1E 0000 R           FCOMP     LONG_REAL
001D    9B DE D9                  FCOMPP
0020    9B D9 E4                  FTST
0023    9B D9 E5                  FXAM

0026                     CODE     ENDS
                         END

                         Фиг. 7.18 Команды сравнения сопроцессора 8087

Сопроцессор 8087 помещает флаги состояния C3 и C0 в точности на те же места, которые в регистре флагов микропроцессора 8088 занимают флаги нуля C3 и переноса C0. Как показано на рисунке, если программа переслала старший байт слова состояния сопроцессора 8087 в регистр флагов микропроцессора 8088, она может выполнить условный переход с помощью непосредственной проверки состояния флагов с использованием команды условного перехода, и не нужно выделять и проверять отдельные биты слова состояния.

C3 C0 Порядок
0 0 ST > источник
0 1 ST < источник
1 0 ST = источник
1 1 ST и источник несравнимы

Фиг. 7.19 Порядок сравнения

На Фиг. 7.18 демонстрируется, что существуют и другие варианты команды FCOM, в том числе и то, что для команды FCOM существует версия FICOM необходимая для ставнения целых чисел. Команды FCOMP и FICOMP идентичны командам FCOM и FICOM, за исключением того, что сопроцессор 8087 извлекает из стека содержимое вершины после выполнения операции. Это позволяет сравнить два числа с помощью сопроцессора 8087, не беспокоясь о том, что нужно удалить из стека первый операнд после операции.


Microsoft (R) Macro Assembler Version 5.00                  1/1/80 04:03:56
Фиг. 7.20 Условный переход                                        Page  1-1
PAGE  ,132
                         TITLE    Фиг. 7.20 Условный переход

0000                     CODE     SEGMENT

                                  ASSUME    CS:CODE,DS:CODE
0000                     WORD_INTEGER       LABEL   WORD
0000    ????             STATUS_WORD        DW      ?
                         ;-----  Сравнивается WORD_PTR 
                         ;-----  со словом на вершине стека сопроцессора 8087
0002    9B DE 16 0000 R           FICOM     WORD_INTEGER   ; Сравнение слова с ST
0007    9B DD 3E 0000 R           FSTSW     STATUS_WORD    ; Сохранение слова состояния 8087
000C    9B                        FWAIT                    ; Синхронизация с сопроцессором
000D    8A 26 0001 R              MOV       AH,BYTE PTR STATUS_WORD+1
0011    9E                        SAHF                     ; Занесение флагов (C0=CF,C3=ZF)
0012    72 02                     JB        CONTINUE       ; Проверка флага C0,переход если 0
0014    75 00                     JNE       ST_GREATER     ; Проверка флага C3
0016                     ST_EQUAL:          ; Попадаем сюда,если C3=1,C0=0 - значения равны
0016                     ST_GREATER:        ; Попадаем сюда,если C3=0,C0=0 - число
                                            ; на вершине стека 8087 больше WORD_PTR
0016                     CONTINUE:
0016    75 00                     JNE       ST_LESS        ; Проверка флага C3
0018                     UNORDERED:         ; Попадаем сюда,если C3=1,C0=1 - 
                                            ; невозможно определить какое из чисел больше
0018                     ST_LESS:           ; Попадаем сюда,если C3=0,C0=1 - число
                                            ; на вершине стека 8087 меньше WORD_PTR
              
0018                     CODE     ENDS
                         END

                                  Фиг. 7.20 Условный переход

У команды FCOMPP программист не указывает никаких операндов. Эта команда всегда сравнивает верхние два элемента стека. После сравнения они оба исчезают из стека.

Команды сравнения с извлечением из стека обеспечивают удобный способ очистки стека. Поскольку у сопроцессора 8087 нет команды, удобно извлекающей операнд из стека, вместо нее можно использовать команды сравнения с извлечением из стека. Эти команды также изменяют и регистр состояния, и их нельзя использовать, если биты состояния имеют значение для дальнейшей работы, но в большинстве случаев эти команды позволяют быстро извлечь из стека один или два операнда. Так как сопроцессор 8087 регистрирует ошибку при переполнении стека, необходимо удалить все операнды из стека при окончании вычислений.

Существуют две специальные команды сравнения. Команда сравнения содержимого вершины стека с нулем FTST, с помощью которой можно быстро определить знак содержимого вершины стека. (Результат сравнения иллюстрируется таблицей на Фиг. 7.19, нужно только всюду в таблице слово "источник" заменить на слово "нуль").

Команда FXAM, строго говоря, не является командой сравнения. Хотя она и работает с содержимым вершины стека, но не сравнивает содержимое вершины ни с одним другим числом. Скорее команда FXAM устанавливает все четыре флага регистра состояния (от C3 до C0 включительно), показывая, какого типа число находится в вершине стека. Так как сопроцессор 8087 может обрабатывать любые формы чисел, а не только нормализованные числа с плавающей точкой, команда FXAM определит, что же находится в вершине стека. На Фиг. 7.21 показаны значения битов состояния в каждом случае.

Если при арифметической обработке вы не делаете что=либо из ряда вон выходящее и не работаете на пределе разрядной сетки сопроцессора 8087, то не нужно рассматривать никакие из приведенных выше результатов команды FXAM; вы должны ожидать увидеть лишь положительные либо отрицательные нормализованные числа или нули. Если выясняется, что вершина стека пустая, то обычно выдается ошибка. Программа может сделать такую проверку для контроля параметра, переданного в вершине стека.

Остальные значения - это реакция микросхемы 8087 на ошибку. Когда сопроцессор 8087 обнаруживает ошибку, он пытается возбудить прерывание по особой ситуации, устанавливая соответствующие биты в слове состояния. Однако если ситуация замаскирована с помощью управляющего слова, сопроцессор 8087 сам реагирует на нее. Он решает, какая реакция соответствует данной ошибке и возбуждает появление специфического числа в регистре. Например, результат NAN возникает, если операция некорректна, как в случае извлечения квадратного корня из отрицательного числа. Бесконечность появляется, если результат операции слишком велик для представления с плавающей точкой.

C3 C2 C1 C0 Значение
0 0 0 0 +Ненормально
0 0 0 1 +NAN
0 0 1 0 -Ненормально
0 0 1 1 -NAN
0 1 0 0 +Нормально
0 1 0 1 +Бесконечность
0 1 1 0 -Нормально
0 1 1 1 -Бесконечность
1 0 0 0 +0
1 0 0 1 Пусто
1 0 1 0 -0
1 0 1 1 Пусто
1 1 0 0 +Ненормальное
1 1 0 1 Пусто
1 1 1 0 -Ненормальное
1 1 1 1 Пусто

Фиг. 7.21 Пример интерпретации кодов состояний

Денормализованные и ненормализованные числа возникают при достижении другого предела представления чисел с плавающей точкой. Когда число становится настолько маленьким, что у него уже нет смещенного порядка, оно становится денормализованным. Вместо того, чтобы заменить число нулем, процессор 8087 записывает наименьшее значение порядка и ненормализованную мантиссу. Это означает, что число теряет точность, так как у его мантиссы появляются незначащие нули. Но денормализованный результат все же точнее, чем просто нуль. И это тот случай, при котором сопроцессор 8087, продолжая работу, наилучшим образом реагирует на плохие условия. Пометка числа, как денормализованного, должна насторожить вас. При этом также устанавливается бит денормализации в регистре особых ситуаций, и остается установленным до тех пор, пока команда FCLEX не сбросит биты особых ситуаций. С помощью анализа флагов программа может зарегистрировать возникновение ошибки и отнестись к результатам с подозрением.