Assembler для начинающих


Десять в степени X



Десять в степени X


      Второй пример использования сопроцессора 8087 гораздо глубже
    раскрывает перед нами его работу.  Этот пример - подпрограмма,
    которая будет использоваться в дальнейшем.  Подпрограмма
    предполагает, что исходное число находится в вершине стека; после
    возврата из подпрограммы в вершине стека находится число, равное
    десяти в степени X.  Исходный текст этой подпрограммы приведен на
    Фиг. 7.24.
      Сопроцессор 8087 не имеет команды возведения 10 в произвольную
    степень, но мы можем возводить в любую степень двойки.  Поэтому
    нужжно пользоваться формулой
 
      10**X = 2**(X*Log2(10))


 
      Первые две команды программы формируют показатель степени двух.
    Программа загружает константу Log210, а затем умножает ее на
    исходное число X, давая необходимую степень 2, называемую здесь E.
    Поле комментариев в примере используется для иллюстрации элементов
    стека сопроцессора 8087.  Символ "?" означает, что значение
            Microsoft (R) Macro Assembler Version 5.00             1/1/80 04:04:40
            Фиг. 7.24 Вычисление 10**ST                       Page         1-1
 
                                          PAGE    ,132
                                          TITLE   Фиг. 7.24 Вычисление 10**ST
             0000                   CODE    SEGMENT PUBLIC
                                          ASSUME  CS:CODE,DS:CODE
                                          PUBLIC  TEN_TO_X
             0000  ????             OLD_CW  DW      ?
             0002  ????             NEW_CW  DW      ?
                                    ;--------------------------------------------
                                    ; Эта программа извлекает число с вершины стека
                                    ;  сопроцессора 8087 и возводит 10 в эту степень.
                                    ; Параметры: X в ST(0)
                                    ; Результат: 10**X в ST(0)
                                    ; Эта программа использует две ячейки в стеке 8087
                                    ;  плюс параметр - всего три ячейки.
                                    ;--------------------------------------------
             0004                   TEN_TO_X          PROC    NEAR
                                                            ;----ST(0)------;-----ST(1)-----;--ST(2)--
                                                            ; X         ; ?         ; ?
             0004  9B D9 E9                     FLDL2T                  ; LOG2(10)      ; X            ; ?
             0007  9B DE C9                     FMULP   ST(1),ST(0)     ; X*LOG2(10)=E  ; ?            ; ?
             000A  D9 3E 0000 R                 FNSTCW  OLD_CW          ;---------------;---------------;--------
             000E  9B                     FWAIT             ; Выборка текущего слова состояния
             000F  A1 0000 R                    MOV     AX,OLD_CW      ; Сохранение слова сотояния
             0012  25 F3FF                      AND     AX,NOT 0C00H   ; Установка способа округления к минус
             0015  0D 0400                      OR      AX,0400H       ;      бесконечности
             0018  A3 0002 R                    MOV     NEW_CW,AX
             001B  9B D9 2E 0002 R              FLDCW   NEW_CW          ;---------------;---------------;--------
             0020  9B D9 E8                     FLD1              ; 1         ; E         ; ?
             0023  9B D9 E0                     FCHS              ; -1        ; E         ; ?
             0026  9B D9 C1                     FLD     ST(1)           ; E         ; -1        ; E
             0029  9B D9 FC                     FRNDINT                 ; INT(E) = I    ; -1            ; E
             002C  9B D9 2E 0000 R              FLDCW   OLD_CW          ;           ;           ;
             0031  9B D9 CA                     FXCH    ST(2)           ; E         ; -1        ; I
             0034  9B D8 E2                     FSUB    ST(0),ST(2)     ; E - I = F     ; -1            ; I
             0037  9B D9 FD                     FSCALE                  ; F*2**-1 = F/2 ; -1            ; I
             003A  9B D9 F0                     F2XM1             ; (2**F/2)-1    ; -1          ; I
             003D  9B DE E1                     FSUBRP  ST(1),ST(0)     ; 2**F/2          ; I            ; ?
             0040  9B D8 8E 0000 U              FMUL    ST(0)           ; 2**F            ; I            ; ?
             0045  9B D9 FD                     FSCALE                  ; (2**F)*(2**I) ; I            ; ?
             0048  9B D9 C9                     FXCH    ST(1)           ; I         ; 2**(I+F)      ; ?
             004B  9B D8 D9                     FCOMP             ; 2**(I+F)      ; ?           ; ?
             004E  C3                     RET               ; 10**X           ; ?         ; ?
             004F                   TEN_TO_X          ENDP
             004F                   CODE    ENDS
                                          END
 
                  Фиг. 7.24 Вычисление 10**ST
 
    соответствующего элемента стека неопределено.  В подпрограмме
    используется всего три элемента стека, так что в поле комментариев
    есть три колонки.
      Хотя теперь мы имеем нужную степень двух, у сопроцессора 8087
    отсутствует команда, завершившая бы всю работу за один шаг.
    Команда F2XM1 возводит 2 в степень X, но только если X меньше или
    равен 1/2.    Это означает, что степень E мы должны разделить на
    целую и дробную части; затем команда FSCALE сможет возвести 2 в
    целую степень, а команда F2XM1 обработает дробную часть.
 
      Перед разделением E на две части программа выполняет некоторые
    вспомогательные действия.  Эти действия - команды сопроцессора
    8087, которые читают управляющее слово и устанавливают режим
    округления в направлении меньшего числа.  Теперь, когда мы возьмем
    целую часть показателя степени, его значение будет округляться
    влево, в направлении минус бесконечности.  Дробная часть показателя
    будет положительным числом, что также требуется для команды F2XM1.
 
      Обратите внимание на использование команды FWAIT после команды
    FNSTCW.  Ожидать окончания выполнения умножения перед записью
    управляющего слова не надо, так как умножение не меняет код в
    управляющем слове.  Но перед чтением управляющего слова из главной
    памяти и модификацией его нужна гарантия, что сопроцессор 8087 уже
    завершил запись.  Значит, нужно выполнить команду ожидания FWAIT
    перед чтением.
 
      После установки способа округления команда FRNDINT округляет
    показатель степени E до целого значения.  Так как мы также
    запомнили и исходное значение E в стеке, можно вычесть целую часть
    из E и получить дробную часть показателя степени.  То есть теперь E
    = I + F, и можно записать
 
      2**E = 2**I*2**F
 
      Но перед тем обратим внимание на одну маленькую деталь.
    Дробная часть F может оказаться значением большим 1/2, и поэтому не
    может быть аргументом команды F2XM1.  Сейчас мы используем число
    -1, ранее помещенное в стек, чтобы разделить F на 2, получив при
    этом F/2.  Чтобы это сделать, воспользуемся командой FSCALE, так
    как эта команда умножает содержимое ST0 на 2 в степени,
    содержащейся в ST1.  Поскольку в элементе ST1 содержится -1,
    результирующим эффектом будет умножение на 1/2.  Теперь можно
    утверждать, что содержимое регистра ST0 меньше 1/2.
 
      Далее команда F2XM1 возводит 2 в степень F/2, а -1 в стеке
    помогает ликвидировать -1, порождаемую в результате работы команды
    F2XM1.  Обратное вычитание с извлечением из стека избавляется и от
    -1 в стеке.  Затем 2F/2 умножается само на себя, в элементе ST0
    получается число 2F.  Так как целая часть показателя степени теперь
    переместилась в элементе ST1, команда FSCALE умножает 2I на число
    2F, которое уже находится в элементе ST0, давая искомый результат.
    Команда FCOMP удаляет из стека число I перед возвратом из
    подпрограммы.




Содержание раздела