Примеры

      Этот раздел главы с помощью примеров исполльзования наиболее

    распространенных операций научит вас применять сопроцессор 8087,

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

    т.е.  в них не делается попыток обработки всех возможных ошибок или

    реакции на какие=либо специальные числа, с которыми может работать

    микросхема 8087.  Сопроцессор 8087, конечно же, имеет такие

    возможности, но эти действия относятся к более сложным.  Когда вы

    освоите основы техники, вы сможете добавить к этим примерам

    некоторые фрагменты, которые превратят их в настоящие подпрограммы

    общего назначения.

Степени десяти

      Первый пример - исходный текст программы на Фиг. 7.23.      Эта

    программа распечатывает короткое действительное представление

    степеней 10 от 103 до 1039.  Как мы уже видели в разделе,

    посвященном представлению данных, Макроассемблер фирмы IBM не имеет

    возможностей непосредственно генерировать действительные числа.

    Наличие такой таблицы чисел облегчит вам представление в виде

    констант степеней 10.  По этой таблице вы сможете определить

    шестнадцатеричное представление числа, которое нужно использовать в

    программе.

 

      Программа вычисляет только каждую третью степень 10, и

    использует короткий действительный формат.  Если вы работаете с

    много большими числами, или вам нужна большая точность, тогда нужно

    выполнить этот пример, используя длинный действительный формат

    чисел, а также построить каждую степень 10.  Выполните это в

    качестве упражнения.

 

      Первоочередная цель этого примера - введение в программирование

    и работу на сопроцессоре 8087.  Это отдельная самостоятельная

    программа, предназначенная для выполнения в виде файла типа .EXE.

    Прежде чем разобраться в самой программе, заметим, что в нее входит

    сегмент STACK, необходимый в файле типа .EXE.  Сначала в сегменте

    CODE записаны поля данных, а выполнение программы начинается с

    метки CALCULATE_POWER.  Заглянув вперед, на оператор END, вы

    увидите, что первой выполняемой командой будет команда, помеченная

    CALCULATE_POWER, так как она указана в операторе END.

 

      Первая часть программы выполняет инициализацию.  Перед

    загрузкой указателя на сегмент CODE в регистр DS программа помещает

    в стек адрес возврата из файла типа .EXE.  Затем с помощью команды

    FINIT инициализируется сопроцессор 8087, что аналогично аппаратному

    сбросу.  Тем самым сопроцессор 8087 оказывается настроенным на

    обработку особых ситуаций по умолчанию, что наилучшим образом

    подходит для примеров этой книги.  Команда FINIT также сбрасывает

    регистровый стек сопроцессора 8087, освобождая все его восемь

    позиций.  Программа должна использовать команду FINIT только в

    момент запуска.  Команда FINIT никогда не должна быть использована

    внутри подпрограммы для сопроцессора 8087.

 

      Следующие команды загружают число 1000 в регистр ST1 и число 1

    в регистр ST0.  Все следующие команды сопроцессора 8087 используют

    эти два регистра стека.  В регистре ST0 находится текущая степень

    десяти, а в регистре ST1 находится значение 103.  Мы будем

    использовать число в регистре ST1 для увеличения числа в регистре

    ST0 после каждой итерации программы.  Целая переменная POWER

    содержит текущую степень 10, находящуюся в регистре ST0.

 

      После метки POWER_LOOP элемент ST0 умножается на элемент ST1,

    (в котором содержится число 1000), чтобы увеличить содержимое

    регистра ST0 в 103 раз.  Команда FST записывает результат в память.

    Оставшаяся часть программы после метки POWER_LOOP печатает

    результаты вычислений.  В подпрограмме TRANSLATE шестнадцатеричный

    байт преобразуется в двухбайтовую строку в коде ASCII так, что

    программа может его распечатать.  Текущее значение POWER (степень

    десяти), а также шестнадцатеричная строка, записанная процессором

    8087, преобразуются в код ASCII.  Затем функция DOS печатает строку

    на дисплее.  Цикл POWER_LOOP продолжается до тех пор, пока

    последнее напечатанное значение не станет больше 1038.  Это

    значение выбрано потому, что 1038 - это максимальное число, которое

    может быть представлено в коротком действительном формате.    Если бы

    использовался длинный действительный формат чисел, это значение

    было бы равно 10308.  Заключительная часть Фиг. 7.23 показывает,

    как выглядит результат работы этой программы на дисплее.

 

           Microsoft (R) Macro Assembler Version 5.00              1/1/80 04:04:33

           Фиг. 7.23 Степени 10                             Page   1-1

 

 

                                         PAGE    ,132

                                         TITLE   Фиг. 7.23 Степени 10

 

            0000                   STACK   SEGMENT STACK

            0000  0040[                  DW      64 DUP (?)

                  ????

                              ]

 

            0080                   STACK   ENDS

 

            0000                   CODE    SEGMENT

                                         ASSUME  CS:CODE

 

            0000  ????????               POWER_OF_TEN    DD      ?                 ; Область данных для 10**x,

                                                                 ;      короткое плавающее

            0004  0002[            OUTPUT_POWER    DB      2 DUP (' ')     ; Текстовый буфер для значения

                  20

                              ]

 

            0006  48 20 20 20 20                     DB      'H    '         ;  степени

            000B  0008[            OUTPUT_STRING   DB      8 DUP ('         ')     ; Текстовый буфер для результата -

                  20 20 20 20 20

                  20 20 20 20

                              ]

            0053  48 0D 0A 24                        DB      'H',13,10,'$'   ; Конец строки

            0057  00                     POWER       DB      0               ; Текущая степень 10

            0058  03E8             THOUSAND          DW      1000      ; Константа

            005A  03BF             CONTROL_87      DW      03BFH

 

            005C                   CALCULATE_POWER PROC    FAR

            005C  1E                           PUSH    DS        ; Занесение в стек адреса возврата

            005D  B8 0000                      MOV     AX, 0

            0060  50                           PUSH    AX

            0061  0E                           PUSH    CS

            0062  1F                           POP     DS

                                         ASSUME  DS:CODE         ; Адресация области данных

            0063  9B DB E3                     FINIT             ; Инициализация сопроцессора 8087

 

                  Фиг. 7.23 (а) (начало)

            0066  9B DF 06 0058 R              FILD    THOUSAND        ; Загрузка 10**3 в стек сопроцессора 8087

            006B  9B D9 E8                     FLD1              ; Загрузка начального значения в стек 8087

            006E                   POWER_LOOP:

            006E  9B DC 8E 0000                FMUL    ST(1)           ; Умножение ST(0) на ST(1)

            0073  9B D9 16 0000 R              FST     POWER_OF_TEN    ; Сохранение в памяти результата

            0078  80 06 0057 R 03              ADD     POWER, 3        ; Увеличение показателя степени

            007D  A0 0057 R                    MOV     AL, POWER       ; Выборка показателя степени

            0080  8D 1E 0004 R                 LEA     BX, OUTPUT_POWER

            0084  E8 00AC R                    CALL    TRANSLATE

            0087  B9 0004                      MOV     CX, 4

            008A  8D 1E 000B R                 LEA     BX, OUTPUT_STRING

            008E  8D 36 0003 R                 LEA     SI, POWER_OF_TEN+3

            0092  FD                           STD               ; Установка пересылки с уменьшением адреса

            0093                   VALUE_OUTPUT:

 

            0093  AC                           LODSB             ; Выборка байта результата

            0094  E8 00AC R                    CALL    TRANSLATE       ; Занесение символа в выводимую строку

            0097  E2 FA                  LOOP    VALUE_OUTPUT    ; Цикл по всем байтам результата

 

            0099  8D 16 0004 R                 LEA     DX, OUTPUT_POWER

            009D  B4 09                  MOV     AH, 9H

            009F  CD 21                  INT     21H

            00A1  80 3E 0057 R 26              CMP     POWER, 38

            00A6  72 C6                  JB      POWER_LOOP

            00A8  9B DE D9                     FCOMPP            ; Удаление из стека двух чисел

            00AB  CB                           RET

            00AC                   CALCULATE_POWER ENDP

 

            00AC                   TRANSLATE         PROC    NEAR

            00AC  50                           PUSH    AX        ; Сохранение исходного значения

            00AD  51                           PUSH    CX

            00AE  B1 04                  MOV     CL, 4           ; Сдвиг старшей цифры выводимого числа

            00B0  D2 E8                  SHR     AL, CL          ;      на место младшей цифры

            00B2  59                           POP     CX

            00B3  E8 00CB R                    CALL    XLAT_OUTPUT     ; Вывод старшей цифры выводимого числа

            00B6  58                           POP     AX        ; Восстановление младшей цифры

            00B7  E8 00CB R                    CALL    XLAT_OUTPUT     ; Вывод младшей цифры выводимого числа

            00BA  C3                           RET

            00BB                   TRANSLATE         ENDP

 

            00BB  30 31 32 33 34 35 36     ASCII_TABLE     DB      '0123456789ABCDEF'

                37 38 39 41 42 43 44

                45 46

            00CB                   XLAT_OUTPUT     PROC    NEAR

            00CB  24 0F                  AND     AL, 0FH         ; Выделение младшей цифры

            00CD  53                           PUSH    BX

            00CE  8D 1E 00BB R                 LEA     BX, ASCII_TABLE ; Адрес таблицы трансляции

            00D2  D7                           XLAT    ASCII_TABLE     ; Преобразование в символьную форму

            00D3  5B                           POP     BX

            00D4  88 07                  MOV     [BX], AL        ; Сохранение очередного символа результата

            00D6  43                           INC     BX        ; Переключение на следующий символ

            00D7  C3                           RET

            00D8                   XLAT_OUTPUT     ENDP

            00D8                   CODE    ENDS

                                         END     CALCULATE_POWER

                  Фиг. 7.23 (а) (продолжение)

            A>PRINT10

            03H   447A0000H

            06H   49742400H

            09H   4E6E6B28H

            0CH   5368D4A5H

            0FH   58635FA9H

            12H   5D5E0B6BH

            15H   6258D727H

            18H   6753C21CH

            1BH   6C4ECB8FH

            1EH   7149F2CAH

            21H   76453719H

            24H   7B4097CEH

            27H   7F800000H

 

                  Фиг. 7.23 (b)

 

          Фиг. 7.23 (a) Степени 10; (b) Вывод процедуры степеней 10

 

      Вам нужно посмотреть часть программы TRANSLATE, несмотря на то,

    что она не использует ни одной команды сопроцессора 8087.  Эта

    часть - пример подготовки чисел к печати.  В частности, команда

    XLAT преобразует для печати шестнадцатеричную тетраду (значение от

    0 до 0FH) в правильный символ кода ASCII (от 0 до F).  Просто

    прибавлять значение тетрады к значению 0 нельзя, так как в коде

    ASCII символы от A до F не следуют непосредственно за символами от

    0 до 9; преобразование прекрасно выполняет команда перекодировки.

    Мы используем аналогичный метод, когда преобразуем число с

    плавающей точкой в пригодную для печати десятичную форму.