Кодирование fpu инструкций Intel x87

Тема в разделе "WASM.ARTICLES", создана пользователем Mikl___, 8 окт 2021.

  1. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.792
    Конструкторы микропроцессоров от i8080 до i80386 не смогли реализовать все математические функции на одном кристалле, так как это оказалось слишком сложным. Вместо этого они создали набор функций более низкого уровня, из которых можно программно построить любые математические функции. Вот так программист должен был вычислять, используя арифметические операции, функции синуса, экспоненты или логарифма:
    [math]sin(x)=x-\frac{\displaystyle x^{3}}{\displaystyle 3!}+\frac{\displaystyle x^{5}}{\displaystyle 5!}-...+(-1)^{n}\times \frac{\displaystyle x^{2n+1}}{\displaystyle (2n+1)!}[/math]
    [math]e^{x}=1+\frac{\displaystyle x}{\displaystyle 1!}+\frac{\displaystyle x^{2}}{\displaystyle 2!}+...+\frac{\displaystyle x^{n}}{\displaystyle n!}[/math]
    [math]ln(x)=(x-1)-\frac{\displaystyle (x-1)^{2}}{\displaystyle 2}+\frac{\displaystyle (x-1)^{3}}{\displaystyle 3}-...+(-1)^{n-1}\times\frac{\displaystyle (x-1)^{n}}{\displaystyle n}[/math]
    Для обработки чисел с плавающей запятой в 1980 году компания Intel выпустила специальную микросхему i8087 – математический сопроцессор. Сопроцессор i8087 работал с первыми 16-разрядными микропроцессорами Intel 8086 и 8088. Основной микропроцессор и сопроцессор работали во взаимодействии друг с другом. Когда основной микропроцессор считывал специальную команду Esc=1101.1XXX2 (код от 1101.10002=D816 до 1101.11112=DF16), управление передавалось сопроцессору, который выполнял следующий за этой командой машинный код – одну из 68 команд для вычисления логарифма, тригонометрических функций, возведения в степень и так далее. Получив команду на выполнение, сопроцессор запускал набор собственных команд, записанных в ПЗУ. Обычно выполнение внутренних команд сопроцессора сопряжено с вычислением в цикле, поэтому основной микропроцессор в это время простаивал, ожидая получения результата от микропроцессора.
    И все же, сопроцессор позволял ускорить вычисления, по сравнению с тем, если бы основному микропроцессору пришлось обрабатывать числа с плавающей запятой программным способом. Начиная с микропроцессора i80486 произошло объединение на одном кристалле математического сопроцессора с основным микропроцессором. Поэтому хватит вычислять значения синуса рядами, а воспользуемся командами, специально предназначенными для этого.
    Каждый FPU (Floating Point Execute Unit – блок обработки чисел с плавающей запятой) имеет собственный набор команд и средства для выполнения операций с плавающей запятой, такие как экспоненциальные, логарифмические и тригонометрические функции. Блок FPU содержит восемь 80-битовых регистров (от ST(0) до ST(7)) для обработки чисел с плавающей запятой, которые могут представлять числовые значения от 10-400 до 10400.
    Регистры данных блока FPU, в отличие от регистров общего назначения, не независимы, а организованы в стек, то есть операнды считываются в порядке, обратном их записи.
    Вычисления с плавающей точкой выполняются блоком FPU параллельно с работой основной программы, иногда даже быстрее вычислений, производимых блоком IEU. И программисты стали перекладывать основную тяжесть вычислений на блок FPU.
    Блок FPU поддерживает следующие типы данных:

    Типы данных, обрабатываемых блоком FPU


    ТипРезервирование
    памяти с
    помощью​
    Размер
    (байт)​
    Диапазон значений
    Короткое
    вещественное​
    DD/REAL44От ±1,18×10-38 до ±3,4×1038
    Длинное
    вещественное​
    DQ/REAL88От ±2,23×10-308 до ±1,79×10308
    Расширенное
    вещественное​
    DT/REAL1010От ±3,37×10-4932 до ±1,18×104932
    Целое словоDW/SWORD2От -32768 до +32767
    Короткое целоеDD/SDWORD4 От -231 до +231-1
    Длинное целоеDQ/SQWORD8От -263 до +263-1
    Упакованное двоично-
    десятичное целое​
    DT/TBYTE10От -999999999999999999 до +999999999999999999

    Вещественные форматы IEEE, применяемые в микропроцессорах Intel

    ТипРазмер
    (байт)
    Соответствие
    вещественному
    числу в C/C++
    Формат числа (в битах)
    знакпорядокмантисса
    DD/REAL44короткое (float)
    1​
    8​
    23​
    DQ/REAL88длинное (long, double)
    1​
    11​
    52​
    DT/REAL1010расширенное (long double)
    1​
    15​
    64​
    Процессор передает числовые данные в блок FPU, который осуществляет необходимые вычисления и возвращает результат.
    Для ассемблирования команд FPU, если модель вашего микропроцессора младше i80486, необходимо добавлять параметр – .8087,.287,.387
    Названия всех команд FPU начинаются с буквы F. Чтобы вам было легче запомнить назначение команд FPU, обратите внимание на следующую таблицу:

    Расшифровка аббревиатур в командах FPU


    Буква
    в команде​
    ОбозначениеПример
    I после буквы F​
    Операнд – целое число (Integer - целое)fild, fist, fiadd, fisub, ficomp
    B после буквы F​
    Операнд – упакованное двоично-десятичное число
    (packed Binary-coded decimal)​
    fbld,fbstp
    P после буквы F​
    partial - частичныйfptan, fprem, fprem1
    после буквы F
    название операции​
    Операнд – действительное числоfld, fst, fadd, fsub
    P в конце
    команды​
    выборка операнда из стека
    (to pop - вытолкнуть)​
    fstp, faddp, fsubp
    PP в конце командывыборка из стека двух операндовfcompp
    R в конце
    команды или перед P​
    Обратный (Reverse - переставленный) порядок операндовfdivr, fsubr
    Специальные численные значения
    Знак
    (79 бит)
    Порядок
    (78-64 биты)
    Мантисса
    (63-0 биты)
    Название числа
    0​
    000...00000000000...00000000000+0
    1​
    000...00000000000...00000000000-0
    х​
    000...00000000ххх...хххххххххххДенормализованные числа, используются для работы с очень
    маленькими числами от ±10-4932 до ±10-16445
    0​
    111...11111111000...00000000000+
    1​
    111...11111111000...00000000000-
    х​
    111...1111111110ххх...хххххххххНечисло типа SNAN (Signal Non A Number). Среди х есть единицы.
    FPU реагирует на появление SNAN возбуждением исключения
    недействительной операции
    х​
    111...1111111111ххх...хххххххххНечисло типа QNAN (Quiet Non A Number). Среди х есть единицы
    1​
    111...111111111100...0000000000Неопределенность (один из вариантов QNAN)
    Несмотря на большой диапазон вещественных значений, представимых в регистрах данных FPU, значения, например, - и + находятся за пределами этого диапазона. Для того, чтобы иметь возможность реагировать на некоторые вычислительные ситуации, которые могут возникнуть в результате математических операций в блоке FPU, предусмотрены специальные комбинации битов, называемые специальными численными значениями. Над специальными численными значениями можно выполнять некоторые операции. Программист может и сам кодировать специальные численные значения директивой DT (х – любое значение бита).
    Если в результате вычислений мантисса и порядок равны нулю, то, несмотря на скрытую единицу в целой части числа REAL4/8, все число полагается равным нулю. Любой конечный результат операции FPU, который из-за ограниченности поля порядка не может быть представлен в 23/52/64 разрядах для REAL4/8/10, соответственно вызывает особый случай некорректности представления числа.

    Программная модель FPU

    Блок FPU предоставляет для программирования восемь регистров для хранения данных (R0-R7) и пять вспомогательных регистров: регистр SWR (State Word Register регистр состояния), регистр CWR (Control Word Register регистр управления), регистр TW (Tag Word регистр атрибутов) и регистры FIP (FPU Instruction Pointer) и FDP (FPU Data Pointer).

    Регистры данных R0-R7

    Регистры данных не адресуются по именам, а рассматриваются в качестве стека, вершина которого называется ST(0). Если в какой-то момент вершина стека (поле TOP регистра SWR) указывает на регистр R5 и его считают ST(0), то после записи числа в R5, вершина стека будет указывать на регистр R4 и уже он будет ST(0), а R5 – ST(1) и так далее.
    Регистр тэгов TW
    Регистр тэгов хранит состояние содержимого каждого регистра данных (на каждый регистр данных отведено по 2 бита). Содержимое регистра данных может быть
    Tag
    Field​
    Содержимое
    00Число в формате с плавающей запятой (valid)
    01Нулевое значение
    10Специальное значение (SNAN, QNAN, бесконечность, денормализованное или не поддерживаемое число)
    11Пусто (empty)
    Регистры FIP и FDP
    Регистры FIP (FPU Instruction Pointer) и FDP (FPU Data Pointer) содержат адрес последней выполненной команды (за исключением команд FINT, FCLEX, FLDCW, FSTSW, FSTSWAX, FSTENV, FLDENV, FSAVE, FRSTORE и FWAIT) и адрес ее операнда соответственно, и используются в обработчиках исключений для анализа вызвавшей его команды.

    Регистр состояний RSW

    Регистр состояния фиксирует различные ошибки, хранит код условий для некоторых команд, определяет регистр – вершину стека и показывает состояние занятости блока FPU:
    БитНазваниеНазначение
    15​
    FPU busyЗанятость FPU. Этот флаг существует для совместимости с i8087, и его значение всегда совпадает с ES.
    14,10-8
    Condition Code
    3210)
    Условные флаги. Употребляются так же, как и биты состояния в регистре EFLAGS, значения С0–С3 отражают результат выполнения предыдущей команды блока FPU и используются для условных переходов. Значения С0–С3 копируют в регистр EFLAGS: флаг С0 переходит в CF, C2→ PF, C3→ ZF, флаг C1 теряется.
    13-11​
    Тop of Stack PointerЧисло от 0 до 7, показывающее, какой из регистров данных R0–R7 в настоящий момент является вершиной стека.
    7​
    Error Summary StatusОбщий флаг ошибки. Если ES=1, произошло хотя бы одно немаскированное исключение.
    6​
    Stack FaultОшибка стека. Если С1=1, произошло переполнение (команда пыталась писать в непустую позицию в стеке), если С1=0, произошло антипереполнение (команда пыталась считать число из пустой позиции в стеке).
    5​
    precisionФлаг неточного результата – результат не может быть представлен точно.
    4​
    UnderflowФлаг антипереполнения – результат слишком маленький.
    3​
    overflowФлаг переполнения – результат слишком большой.
    2​
    Zero DivideФлаг деления на ноль – выполнено деление на ноль.
    1​
    Denormalized OperandФлаг денормализованного операнда – выполнена операция над денормализованным числом.
    0​
    Invalid OperationФлаг недопустимой операции – произошла ошибка стека (SF=1) или выполнена недопустимая операция.
    Биты 0–5 отражают различные ошибочные ситуации, которые могут возникать при выполнении команд FPU. Они рассмотрены в описании управляющих регистров.
    Регистр управления RCW
    Регистр управления содержит слово управления блока FPU:
    БитыНазваниеНазначение
    12Infinity Controlуправление бесконечностью (поддерживается для
    совместимости с i8087 и i80287 –
    вне зависимости от значения этого бита +∞ больше чем -∞)​
    11–10Rounding Controlуправление округлением
    9–8precision Controlуправление точностью
    5precision Maskмаска неточного результата
    4Underflow Maskмаска антипереполнения
    3overflow Maskмаска переполнения
    2Zero divide Maskмаска деления на ноль
    1Denormalized Operand Maskмаска денормализованного операнда
    0Invalid Operation Maskмаска недействительной операции
    Биты 0–5 регистра CRW маскируют соответствующие исключения – если маскирующий бит установлен, исключения не происходит, а результат вызвавшей его команды определяется правилами для каждого исключения специально.​
    00.png
    С появлением Pentium MMX произошло расширение системы команд за счет включения 57 новых инструкций, разработанных для более эффективной работы с мультимедийными данными. Параллельное исполнение повторяющихся последовательностей команд целочисленной арифметики, часто встречающихся при работе мультимедиа-приложений, происходит в 64-битных регистрах MM0-MM7. Физически никаких новых регистров с введением технологии MMX не появилось, регистры MM0-MM7 – это мантиссы восьми регистров блока FPU от R0 до R7. При записи числа в регистр MMX оно оказывается в битах 63-0 соответствующего регистра FPU. А порядок (биты 78-64) и ее знаковый бит (бит 79) заполняются единицами. Запись числа в регистр FPU также приводит к изменению содержания соответствующего регистра MMX.
    Любая команда MMX, кроме EMMS, приводит к тому, что поле TOP регистра SR и весь регистр TW в FPU обнуляется. Команда EMMS заполняет регистр TW единицами. Нельзя одновременно пользоваться командами для работы с числами с плавающей запятой и командами MMX, если возникла такая необходимость – применяют команды FSAVE/FRSTOR при переходе от FPU к MMX. Для доступа к регистрам данных (R0-R7) FPU можно использовать команды для доступа к регистрам MM0-MM7.

    Пример работы с FPU

    Напишем программу с использованием команд FPU
    Код (ASM):
    1. .686P
    2. .model flat,stdcall
    3. includelib c:\masm32\lib\user32.lib
    4. includelib c:\masm32\lib\msvcrt.lib
    5. includelib c:\masm32\lib\kernel32.lib
    6. extern _imp__MessageBoxA@16:dword
    7. extern _imp__sprintf:dword
    8. extern _imp__ExitProcess@4:dword
    9. .data
    10. quotient dq 0
    11. buffer db 80 dup (0)
    12. format db 'Quotient: %f',0
    13. caption db 'Divide',0;заголовок
    14. .code
    15. start: finit
    16. push 3
    17. fild dword ptr [esp]
    18. mov dword ptr [esp], 2
    19. fild dword ptr [esp]
    20. add esp, 4
    21. fdivp st(1),st(0)
    22. fstp qword ptr quotient
    23. push dword ptr quotient+4
    24. push dword ptr quotient
    25. push offset format
    26. push offset buffer
    27. call _imp__sprintf
    28. add esp,4*4;балансируем стек после вызова sprintf
    29. push 0
    30. push offset caption
    31. push offset buffer
    32. push 0
    33. call _imp__MessageBoxA@16;выводим на экран
    34. push 0
    35. call _imp__ExitProcess@4
    36. end start
    Запускаем программу и любуемся на результат
    04.png
    Команда fild dword ptr [esp] (Integer LOAD) – загружает целое число =3 из верхушки стека в ST(0). При загрузке числа блок FPU преобразует входное значение из формата знакового целого (16-, 32-, 64-битного) в формат с плавающей точкой. Затем на вершину стека помещается число 2, снова загрузка в ST(0), число 3 перемещается в регистр ST(1). Затем делим содержимое ST(1) на ST(0) командой fdivp st(1),st(0). Команда fstp qword ptr quotient копирует результат из ST(0) в ячейку памяти quotient, при этом выполняется обратное преобразование из внутреннего формата FPU в вещественный формат с округлением результата. Текущий режим округления – к ближайшему значению – установлен в результате выполнения команды finit (Floating-point unit INITIALIZE). Результат выводим на экран
    Система команд блока FPU
    Команды блока FPU по выполняемым им функциям делят на шесть групп:
    1. передача данных
    2. арифметические
    3. сравнения
    4. трансцендентальные
    5. оперирующие константами
    6. команды управления
    Кодировка всех команд блока FPU начинается с 1101.1xxx (с 0D8h по 0DFh) (ESC1-ESC7 «ESC-коды»).
    Команды передачи данных
    Команда FLD
    (загрузка числа в FPU ”Floating point LOAD”)
    Синтаксис команды: FLD <SRC>
    Алгоритм работы: загрузки числа в регистр данных блока FPU.
    Возможные варианты команды:
    • fild mem
    • fbld mem
    • fld mem
    • fld st(i)
    Псевдокод команды:
    IF SRC =ST(i)
    _THEN temp←ST(i)
    ENDIF
    TOP←TOP-1
    IF SRC is memory-operand
    _THEN ST(0)←ConvertToDoubleExtendedPrecisionFP(SRC)
    _ELSE ST(0)← temp
    END IF
    Применение:
    • FILD SRC – загрузка в регистр FPU ST(0) целого числа из ячейки памяти SRC. Область памяти SRC должна быть 16-, 32-, 64-битной;
    • FBLD SRC – загрузка в ST(0) десятичного упакованного числа из 80-битной области памяти SRC;
    • FLD SRC – загрузка в ST(0) действительного числа из памяти. Область памяти SRC должна быть 32-, 64-, 80-битной;
    • FLD ST(i) – загрузка в регистр ST(0) содержимого регистра ST(i).
    Все команды помещаются число в ST(0), увеличивая указатель стека на 1 (ST(0)→ST(1)) и уменьшая значение поля TOP в регистре TW на 1.
    Хотя используется одна и та же инструкция FLD SRC, но по типу имени операнда SRC ассемблер подбирает одну из четырех команд с разными опкодами (в кодах ясно угадывается адрес ячейки памяти 400174h, записанный в обратном порядке 74014000, и индекс регистра FPU), то же можно сказать и о команде FILD SRC.
    Командаhex для
    MOD=00 и
    R/M=101
    ОпкодESCOPAModOPBR/Mадрес
    FLD dword ptr [400174h]D905.74014000D9/0ESC001MOD000R/M400174
    FLD qword ptr [400174h]DD05.74014000DD/0ESC101MOD000R/M400174
    FLD tbyte ptr [400174h]DB2D.74014000DB/5ESC011MOD101R/M400174
    FLD ST(i)D9CiD9C0+iESC00111000
    ST(i)​
    FILD word ptr [400174h]DF05.74014000DF/0ESC111MOD000R/M400174
    FILD dword ptr [400174h]DB05.74014000DB/0ESC011MOD000R/M400174
    FILD qword ptr [400174h]DF2D.74014000DF/5ESC111MOD101R/M400174
    FBLD tbyte ptr [400174h]DF25.74014000DF/4ESC111MOD100R/M400174
    Команда FLD ST(0) дублирует вершину стека. После нее регистры ST(0) и ST(1) имеют одинаковое значение.
    Командаhex для
    MOD=00
    R/M=101
    ОпкодESCOPAModOPBR/M
    FLD m32fpD905D9/0ESC001MOD000R/M
    FLD m64fpDD05DD/0ESC101MOD000R/M
    FLD m80fpDB2DDB/5ESC011MOD101R/M
    FLD ST(i)D9CiD9C0+iESC00111000ST(i)
    FILD m16intDF05DF/0ESC111MOD000R/M
    FILD m32intDB05DB/0ESC011MOD000R/M
    FILD m64intDF2DDF/5ESC111MOD101R/M
    FBLD m80bcdDF25DF/4ESC111MOD100R/M
    Mod=11 режим регистровой адресации. R/M=ST(i)
    Mod=00 R/M=101 режим прямой адресации,
    в следующем байте 32-битное смещение ячейки памяти
     

    Вложения:

    • 02.png
      02.png
      Размер файла:
      11,3 КБ
      Просмотров:
      287
    • 03.png
      03.png
      Размер файла:
      17,4 КБ
      Просмотров:
      1.155
    ml64, Artem_N, TermoSINteZ и 3 другим нравится это.
  2. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.792
    Команда FLD ST(3) помещает содержимое ST(3) в ST(0). Число, которое имело адрес ST(3), имеет теперь адрес ST(4). Но если специально не указывать номер регистра данных FPU, то по команде FLD загружаемое в FPU число попадает в ST(0), при этом числа, уже хранящиеся в других регистрах, смещаются на шаг от вершины стека. Стек FPU может хранить только 8 чисел – столько, сколько в нем регистров. Попытка загрузить в стек девятое число приведет к потере числа, далее всего отстоящего от вершины. Но и ST(0) при этом не воспримет то, что в него загружается, и будет содержать некое значение, которое с точки зрения FPU не может быть числом. Загрузим FPU числами 1, 2, 3, …, 9. Первым в FPU оказалось число 1.0. Оно заняло вершину стека, то есть регистр ST(0). Далее в ST(0) было загружено число 2.0, а число 1.0 спустилось ниже – в регистр ST(1). Затем в ST(0) побывали числа 3.0, 4.0, 5.0, 6.0, 7.0, 8.0. Число 1.0, попавшее в ST(0) первым, спускалось все ниже и оказалось, наконец, в регистре ST(7), когда в ST(0) было число 8.0. Но, при попытке поместить в ST(0) девятое число, случилась авария: число 1.0, загруженное первым, покинуло стек, а на его вершине оказалось неверное значение, которое в регистре тэгов помечено атрибутом NAN (Non A Number нечисло). Кроме «нечисел» в стеке могут быть нормальные числа, помеченные атрибутом valid (правильный). Таковы все числа кроме первого. У регистров ST(0)-ST(7) может быть еще один атрибут empty (пустой). Так блок FPU помечает регистр, в который можно загрузить число. Если регистр занят, то его нужно перед использованием освободить. Делается это командой ffree (FREE Floating-point register). Чтобы, например, освободить третий регистр, нужна команда ffree ST(3). Есть еще одна команда finit, которая разом освобождает сразу все регистры и чаще всего используется для приведения стека данных в «исходное» состояние.
    Команда FST
    (извлечение числа из FPU в память ”STORE Floating point value”)
    Синтаксис команды: FST <DEST>
    Алгоритм работы: сохранение числа из регистра данных блока FPU в ячейку памяти.
    Возможные варианты команды:
    • fist mem
    • fistp mem
    • fistpp mem
    • fisttp mem
    • fbstp mem
    • fstp mem
    Псевдокод команды:
    IF Команда = FSTP
    _THEN DEST←ST(0)
    ELSE IF Команда = FBSTP
    _THEN DEST←Преобразовать_в_BCD(ST(0))
    ELSE IF Команда = FISTP или FIST
    _THEN DEST←Преобразовать_в_целое(ST(0))
    ENDIF;
    IF Команда = FISTP или FSTP или FBSTP
    _THEN Вытолкнуть_содержимое_регистра_из_стека
    ENDIF;
    Применение: команда FST извлекает число из вершины стека и записывает его в ячейку памяти DEST. Область памяти DEST должна быть 16-, 32-, 64-, 80-битной. Команда FSTP выполняет операцию записи данных из FPU в память и извлекает число из стека.
    Сравним команды FLD/FST/FSTP/FILD/FIST/FISTP. Отличие всего в одном бите (FLD d=0/FST d=1)
    КомандаhexОпкодESCOPAMODOPBR/MДействие
    FST m32fpD915D9/2ESC001000dp101d=1 p=0
    FSTP m32fpD91DD9/3ESC001000dp101d=1 p=1
    FLD m32fpD905D9/0ESC001000dp101d=0 p=0
    FST m64fpDD15DD/2ESC101000dp101d=1 p=0
    FSTP m64fpDD1DDD/3ESC101000dp101d=1 p=1
    FLD m64fpDD05DD/0ESC101000dp101d=0 p=0
    FST ST(i)DDD0-7DDD0+iESC101110dpST(i)d=1 p=0
    FSTP ST(i)DDD8-FDDD8+iESC101110dpST(i)d=1 p=1
    FSTP8 ST(i)DFD0-7DFD0+iESC11111010ST(i)
    FSTP9 ST(i)DFD8-FDFD8+iESC11111011ST(i)
    FLD ST(i)D9C0-7D9C0+iESC001110dpST(i)d=0 p=0
    FIST m16intDF15DF/2ESC111000dp101d=1 p=0
    FISTP m16intDF1DDF/3ESC111000dp101d=1 p=1
    FILD m16intDF05DF/0ESC111000dp101d=0 p=0
    FIST m32intDB15DB/2ESC011000dp101d=1 p=0
    FISTP m32intDB1DDB/3ESC011000dp101d=1 p=1
    FILD m32intDB05DB/0ESC011000d0101d=0
    FST m80fpESC
    FSTP m80fpDB3DDB/7ESC011001d1101d=1
    FLD m80fpDB2DDB/5ESC011001d1101d=0
    FIST m64intESC
    FISTP m64intDF3DDF/7ESC011001d1101d=1
    FILD m64intDF2DDF/5ESC111001d1101d=0
    FISTTP m64intDD0DDD/1ESC10100001101Store Integer with
    Truncation and Pop​
    FISTTP m32intDB0DDB/1ESC01100001101
    FISTTP m16intDF0DDF/1ESC11100001101
    FBST m80bcdESC
    FBSTP m80bcdDF35DF/6ESC011001d0101d=1
    FBLD m80bcdDF25DF/4ESC111001d0101d=0
    Команда FXCH
    (обмен значениями в регистрах FPU = ”EXCHGE register contents”)
    Синтаксис команды: FXCH <SRC>
    Семантика команды: команда обмена значения в регистре стека ST(0) со значением регистра ST(i)
    Возможные варианты команды:
    • fxch st(i)
    • fxch
    Псевдокод команды:
    IF количество_операндов=1
    THEN
    _temp←ST(0)
    _ST(0)←SRC
    _SRC←temp
    ELSE
    _temp←ST(0)
    _ST(0)←ST(1)
    _ST(1)←temp
    ENDIF
    командаhexESCOPAModOPBR/M
    FXCH ST(i)D9C8-FESC00111001ST(i)
    FXCH4 ST(i)DDC8-FESC10111001ST(i)
    FXCH7 ST(i)DFC8-FESC11111001ST(i)
    FXCHD9C9ESC00111001ST(1)
    Команда FXCH меняет местами содержимое ST(0) с содержимым ST(i). Если операнд не указан, то обмениваются ST(0) и ST(1).
    Арифметические команды
    Команда FADD
    (сложение значений в регистрах FPU ” Floating point ADDITION”)
    Синтаксис команды: FADD <DEST>,<SRC>
    Семантика команды: команда сложения вещественных чисел.
    Возможные варианты команды:
    • fadd st(0),st(i)
    • fadd st(i),st(0)
    • fadd mem
    • faddp st(i),st(0)
    • fiaddp mem
    Псевдокод команды:
    IF Команда=FIADD
    _THEN DEST ← DEST + ConvertToDoubleExtendedPrecisionFP(SRC)
    ELSE; операнд в SRC представлен в виде числа с плавающей запятой
    _DEST ← DEST + SRC
    ENDIF
    IF Команда=FADDP
    _THEN Вытолкнуть_содержимое_регистра_из_стека
    ENDIF
    9-8 биты регистра управления RCW – биты PC (Precision Control) определяют точность результатов команд FADD, FSUB, FSUBR, FMUL, FDIV, FDIVR и FSQRT .
    PCТочность результатов
    00одинарная точность (32-битные числа)
    01зарезервировано
    10двойная точность (64-битные числа)
    11расширенная точность (80-битные числа)
    Кодировка FADD
    OP опкод команды, может состоять из двух частей OPA и OPB
    MF = Memory Format
    0032-разрядное вещественное
    0132-разрядное целое
    1064-разрядное вещественное
    1116-разрядное целое
    P = Pop
    0Не выталкивает аргумент из стека
    1Выталкивает из стека после выполнения команды
    d = Направление (direction)
    0ST(0)
    1ST(i), память
    ПримерhexОпкодESCOPAModOPBR/MДействие
    FADDPDEC1DEC1ESCd P 0
    11​
    000ST(1)d=1 P=1
    ST(1) ← ST(0) + ST(1),
    извлечь из стека
    FADD
    ST(0),ST(i)
    D8C0-7D8C0+iESCd P 0
    11​
    000ST(i)d=0 P=0
    ST(0) ← ST(0) + ST(i)
    FADD
    ST(i),ST(0)
    DCC0-7DCC0+iESCd P 0
    11​
    000ST(i)d=1 P=0
    ST(i) ← ST(0) + ST(i)
    FADDP
    ST(i),ST(0)
    DEC0-7DEC0+iESCd P 0
    11​
    000ST(i)d=1 P=1
    ST(i) ← ST0 + ST(i),
    извлечь из стека
    FADD
    m32fp
    D800-7
    D840-7
    D880-7
    D8/0ESCMF 0MOD=00
    MOD=01
    MOD=10
    000R/MST(0) ← ST(0) + [m32fp]
    FADD
    m64fp
    DC00-7
    DC40-7
    DC80-7
    DC/0ESCMF 0MOD=00
    MOD=01
    MOD=10
    000R/MST(0) ← ST(0) + [m64fp]
    FIADD
    m32int
    DA00-7
    DA40-7
    DA80-7
    DA/0ESCMF 0MOD=00
    MOD=01
    MOD=10
    000R/MST(0) ← ST(0) + [m32int]
    FIADD
    m16int
    DE00-7
    DE40-7
    DE80-7
    DE/0ESCMF 0MOD=00
    MOD=01
    MOD=10
    000R/MST(0) ← ST(0) + [m16int]

    Команда FSUB
    (вычитание значений в регистрах FPU
    ”Floating point SUBTRACT”)

    Синтаксис команды: FSUB <DEST>,<SRC>
    Семантика команды: команда вычитания вещественных чисел.
    Возможные варианты команды:
    • fsub
    • fsub st(0),st(i)
    • fsub st(i),st(0)
    • fsub mem
    • fisub st(i),st(0)
    • fsubr
    • fsubr st(0),st(i)
    • fsubr st(i),st(0)
    • fsubr mem
    • fsubrp st(i),st(0)
    • fisubrp mem
    Псевдокод команды:
    IF Команда=FISUB
    _THEN DEST ← DEST - ConvertToDoubleExtendedPrecisionFP(SRC)
    ELSE IF Команда=FSUB
    ; операнд в SRC представлен в виде числа с плавающей запятой
    _DEST ← DEST - SRC
    ELSE IF Команда=FISUBR
    _DEST ←ConvertToDoubleExtendedPrecisionFP(SRC) - DEST
    ELSE IF Команда=FSUBR
    ; операнд в SRC представлен в виде числа с плавающей запятой
    _DEST ← SRC - DEST
    ENDIF
    IF Команда=FSUBP или FSUBRP
    _THEN Вытолкнуть_содержимое_регистра_из_стека
    ENDIF
    Кодировка FSUB
    [math]Reverse = d \oplus R[/math]
    ОперацияhexОпкодESCOPAModOPBR/MДействие
    FSUB
    m32fp
    D820-7
    D860-7
    D8A0-7
    D8/4ESCMF 0MOD=00
    MOD=01
    MOD=10
    10 RR/MR=0
    ST(0) ← ST(0) - [m32fp]
    FSUBR
    m32fp
    D828-F
    D868-F
    D8A8-F
    D8/5ESCMF 0MOD=00
    MOD=01
    MOD=10
    10 RR/MR=1
    ST(0) ← [m32fp] - ST(0)
    FSUB
    m64fp
    DC20-7
    DC60-7
    DCA0-7
    DC/4ESCMF 0MOD=00
    MOD=01
    MOD=10
    10 RR/MR=0
    ST(0) ← ST(0) -[m64fp]
    FSUBR
    m64fp
    DC28-F
    DC68-F
    DCA8-F
    DC/5ESCMF 0MOD=00
    MOD=01
    MOD=10
    10 RR/MR=1
    ST(0) ← [m64fp] -ST(0)
    FSUB
    ST(0),ST(i)
    D8E0-7D8E0+iESCd P 0
    11​
    10 RST(i)d=0 P=0 R=0
    ST(0) ← ST(0) -ST(i)
    FSUB
    ST(i),ST(0)
    DCE8-FDCE8+iESCd P 0
    11​
    10 RST(i)d=1 P=0 R=1
    ST(i) ← ST(i) -ST(0)
    FSUBP
    ST(i),ST(0)
    DEE8-FDEE8+iESCd P 0
    11​
    10 RST(i)d=1 P=1 R=1
    ST(i) ← ST(i) -ST(0),
    извлечь из стека
    FSUBPDEE9DEE9ESCd P 0
    11​
    10 RST(1)d=1 P=1 R=1
    ST(1) ← ST(0) -ST(1),
    извлечь из стека
    FISUB
    m32int
    DA20-7
    DA60-7
    DAA0-7
    DA/4ESCMF 0MOD=00
    MOD=01
    MOD=10
    10 RR/MR=0
    ST(0) ← ST(0) - [m32int]
    FISUBR
    m32int
    DA28-F
    DA68-F
    DAA8-F
    DA/5ESCMF 0MOD=00
    MOD=01
    MOD=10
    10 RR/MR=1
    ST(0) ← [m32int]-ST(0)
    FISUB
    m16int
    DE20-7
    DE60-7
    DEA0-7
    DE/4ESCMF 0MOD=00
    MOD=01
    MOD=10
    10 RR/MR=0
    ST(0) ← ST(0) -[m16int]
    FISUBR
    m16int
    DE28-F
    DE68-F
    DEA8-F
    DE/5ESCMF 0MOD=00
    MOD=01
    MOD=10
    10 RR/MR=1
    ST(0) ← [m16int]-ST(0)
    FSUBR
    ST(0),ST(i)
    D8E0-7D8E0+iESCd P 0
    11​
    10 RST(i)d=0 P=0 R=0
    ST(0) ← ST(i) -ST(0)
    FSUBR
    ST(i),ST(0)
    DCE0-7DCE0+iESCd P 0
    11​
    10 RST(i)d=1 P=0 R=0
    ST(i) ← ST(0) -ST(i)
    FSUBRP
    ST(i),ST(0)
    DEE0-7DEE0+iESCd P 0
    11​
    10 RST(i)d=1 P=1 R=0
    ST(i) ← ST(0) -ST(i),
    извлечь из стека
    FSUBRPDEE1DEE1ESCd P 0
    11​
    10 RST(1)d=1 P=1 R=1
    ST(1)← ST(1) -ST(0),
    извлечь из стека
    команда FSUB mem это ST(0) ← ST(0) - [mem] если ST(0)=0 тогда ST(0) = -[mem] получаем эквивалент команды, которой нет FCHS mem
    Результаты действия fsubp, fsubrp и fsub st(0),st(1) эквивалентны.
    Команды FMUL
    (умножение значений в регистрах FPU ”Floating point MULTIPLY”)
    Синтаксис команды: FMUL <DEST>,<SRC>
    Семантика команды: команда умножения вещественных чисел
    Возможные варианты команды:
    • fmul
    • fmul st(i),st(0)
    • fmul st(0),st(i)
    • fmul mem
    • fmulp
    • fimul mem
    Псевдокод команды:
    IF Команда=FIMUL
    _THEN DEST ← DEST × ConvertToDoubleExtendedPrecisionFP(SRC)
    ELSE; операнд в SRC представлен в виде числа с плавающей запятой
    _DEST ← DEST × SRC
    ENDIF
    IF Команда=FMULP
    _THEN Вытолкнуть_содержимое_регистра_из_стека
    ENDIF
    Кодировка FMUL
    ОперацияhexОпкодESCOPAModOPBR/MДействие
    FMUL
    m32fp
    D808-F
    D848-F
    D888-F
    D8/1ESCMF 0MOD=00
    MOD=01
    MOD=10
    001R/MST(0)← [m32fp]× ST(0)
    FMUL
    m64fp
    DC08-F
    DC48-F
    DC88-F
    DC/1ESCMF 0MOD=00
    MOD=01
    MOD=10
    001R/MST(0)← [m64fp] × ST(0)
    FMUL
    ST(0),ST(i)
    D8C8-FD8C8+iESCd P 0
    11​
    001ST(i)d=0 P=0
    ST(0)← ST(i) × ST(0)
    FMUL
    ST(i),ST(0)
    DCC8-FDCC8+iESCd P 0
    11​
    001ST(i)d=1 P=0
    ST(i)← ST(i) × ST(0)
    FMULP
    ST(i),ST(0)
    DEC8-FDEC8+iESCd P 0
    11​
    001ST(i)d=1 P=1
    ST(i)← ST(i) × ST(0),
    извлечь из стека
    FMULPDEC9DEC9ESCd P 0
    11​
    001ST(1)d=1 P=1
    ST(1)← ST(1) × ST(0),
    извлечь из стека
    FIMUL
    m32int
    DA08-F
    DA48-F
    DA88-F
    DA/1ESCMF 0MOD=00
    MOD=01
    MOD=10
    001R/MST(0)← [m32int] × ST(0)
    FIMUL
    m16int
    DE08-F
    DE4-8-F
    DE88-F
    DE/1ESCMF 0MOD=00
    MOD=01
    MOD=10
    001R/MST(0)← [m16int] × ST(0)
    Операция деления в FPU происходит дольше, чем операция умножения, поэтому старайтесь заменять деление на константу на умножение на (1/константа).
    Варианты возведения числа X в квадрат ST(0)← X2
    Код (ASM):
    1. fld x
    2. fld st(0)
    3. fmul
    Код (ASM):
    1. fld x
    2. fmul x
    Код (ASM):
    1. fld x
    2. fmul st(0),st(0)
    Команды FDIV
    (деление значений в регистрах FPU ”Floating point DIVIDE”)
    Синтаксис команды: FDIV <DEST>,<SRC>
    Семантика команды: команда деления вещественных чисел.
    Возможные варианты команды:
    • fdiv mem
    • fdiv st(0),st(i)
    • fdiv st(i),st(0)
    • fdivp st(i),st(0)
    • fdivp
    • fidiv mem
    Псевдокод команды:
    IF (Команда=FIDIV или FDIV) и SRC=0
    _THEN #Z
    ELSE IF (Команда=FIDIVR или FDIVR) и DEST=0
    _THEN #Z
    ELSE IF Команда=FIDIV
    _THEN DEST ← ConvertToDoubleExtendedPrecisionFP(SRC)/DEST
    ELSE IF Команда=FDIV
    ; операнд в DEST представлен в виде числа с плавающей запятой
    _DEST ← SRC/ DEST
    ENDIF
    IF Команда=FDIVP или FDIVRP
    _THEN Вытолкнуть_содержимое_регистра_из_стека
    ENDIF
    Кодировка FDIV
    ОперацияhexОпкодESCOPAModOPBR/MДействие
    FDIV
    m32fp
    D830-7
    D870-7
    D8B0-7
    D8/6ESCMF 0MOD=00
    MOD=01
    MOD=10
    11 RR/MR=0
    ST(0) ← ST(0) / [m32fp]
    FDIV
    m64fp
    DC30-7
    DC70-7
    DCB0-7
    DC/6ESCMF 0MOD=00
    MOD=01
    MOD=10
    11 RR/MR=0
    ST(0) ← ST(0) /[m64fp]
    FDIV
    ST(0),ST(i)
    D8F0-7D8F0+iESCd P 0
    11​
    11 RST(i)d=0 P=0 R=0
    ST(0) ← ST(0) /ST(i)
    FDIV
    ST(i),ST(0)
    DCF8-FDCF8+iESCd P 0
    11​
    11 RST(i)d=1 P=0 R=1
    ST(i) ← ST(i) /ST(0)
    FDIVP
    ST(i),ST(0)
    DEF8-FDEF8+iESCd P 0
    11​
    11 RST(i)d=1 P=1 R=1
    ST(i) ← ST(i) /ST(0),
    извлечь из стека
    FDIVPDEF9DEF9ESCd P 0
    11​
    11 RST(1)d=1 P=1 R=1
    ST(1) ← ST(1) /ST(0),
    извлечь из стека
    FIDIV
    m32int
    DA30-7
    DA70-7
    DAB0-7
    DA/6ESCMF 0MOD=00
    MOD=01
    MOD=10
    11 RR/MR=0
    ST(0) ← ST(0) / [m32int]
    FIDIV
    m16int
    DE30-7
    DE70-7
    DEB0-7
    DE/6ESCMF 0MOD=00
    MOD=01
    MOD=10
    11 RR/MR=0
    ST(0) ← ST(0) /[m16int]
    FDIVR
    m32fp
    D838-F
    D878-F
    D8B8-F
    D8/7ESCMF 0MOD=00
    MOD=01
    MOD=10
    11 RR/MR=1
    ST(0) ← [m32fp] / ST(0)
    FDIVR
    m64fp
    DC38-F
    DC78-F
    DCB8-F
    DC/7ESCMF 0MOD=00
    MOD=01
    MOD=10
    11 RR/MR=1
    ST(0) ← [m64fp] /ST(0)
    FDIVR
    ST(0),ST(i)
    D8F8-FD8F8+iESCd P 0
    11​
    11 RST(i)d=0 P=0 R=1
    ST(0) ← ST(i) /ST(0)
    FDIVR
    ST(i),ST(0)
    DCF0-7DCF0+iESCd P 0
    11​
    11 RST(i)d=1 P=0 R=0
    ST(i) ← ST(0) /ST(i)
    FDIVRP
    ST(i),ST(0)
    DEF0-7DEF0+iESCd P 0
    11​
    11 RST(i)d=1 P=1 R=0
    ST(i) ← ST(0) /ST(i),
    извлечь из стека
    FDIVRPDEF1DEF1ESCd P 0
    11​
    11 RST(1)d=1 P=1 R=0
    ST(1) ← ST(0) /ST(1),
    извлечь из стека
    FIDIVR
    m32int
    DA38-F
    DA78-F
    DAB8-F
    DA/7ESCMF 0MOD=00
    MOD=01
    MOD=10
    11 RR/MR=1
    ST(0) ← [m32int]/ST(0)
    FIDIVR
    m16int
    DE38-F
    DE78-F
    DEB8-F
    DE/7ESCMF 0MOD=00
    MOD=01
    MOD=10
    11 RR/MR=1
    ST(0) ← [m16int]/ST(0)
     
  3. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.792
    Команда FPREM
    (вычисления частичного остатка ”Partial REMAINDER”)
    Синтаксис команды: FPREM
    Семантика команды: команда вычисления частичного остатка.
    Remainder ← ST(0) - (Q×ST(1))
    Псевдокод команды:
    D ← exponent(ST(0)) - exponent(ST(1))
    IF D<64 THEN
    _Q ← Integer(TruncateTowardZero(ST(0)/ST(1)))
    _ST(0) ← ST(0) - (ST(1)×Q)
    _C2←0
    _C0,C3,C1←LeastSignificantBits(Q); (*Q2Q1Q0 *)
    ELSE
    _C2 ← 1
    _N ← число между 32 и 63
    _QQ ← Integer(TruncateTowardZero(ST(0)/ST(1))/2D-N)
    _ST(0)←ST(0) -(ST(1)×QQ×2D-N)
    ENDIF
    Эта команда за один раз уменьшает содержимое вершины стека максимум на 264. Команда выполняет нахождение истинного остатка от деления ST(0) на ST(1) и требует очень много времени для уменьшения большого числа по очень маленькому основанию. Если функция не завершена, команда FPREM устанавливает флаг C2 равным 1, а когда завершает вычисление остатка, то устанавливает другие три флага C3, C1 и C0 равными трем младшим битам частного. Когда команда FPREM используется в простых тригонометрических функциях для ограничения величины угла, это оказывается необходимым для определения октанта первоначального угла.
    Код (ASM):
    1. ;контроль выполнения частичного остатка (c2=pf=1)
    2. a1: fprem1
    3.      fstsw ax
    4.      sahf
    5.      jp a1
    Команда FPREM1
    Синтаксис команды: FPREM1
    Семантика команды: команда вычисления частичного остатка. Remainder← ST(0) -(Q× ST(1)) Псевдокод команды:
    D ← exponent(ST(0))-exponent(ST(1))
    IF D<64 THEN
    _Q←Integer(RoundTowardNearestInteger(ST(0)/ST(1)))
    _ST(0) ← ST(0) - (ST(1)×Q)
    _C2←0
    _C0,C3,C1 ← LeastSignificantBits(Q); (* _Q2Q1Q0 *)
    ELSE
    _C2← 1
    _N ←число между 32 и 63
    _QQ← Integer(TruncateTowardZero(ST(0)/ST(1))/2D-N)
    _ST(0) ← ST(0) - (ST(1) × QQ × 2D-N)
    ENDIF
    Также как и команда FPREM, команда FPREM1 выполняет деление ST(0) на ST(1) и помещает остаток от деления в ST(0). Деление осуществляется при помощи последовательных вычитаний ST(1) из ST(0), но за один раз выполняется не более 64 таких вычитаний.
    Команда FRNDINT
    (округления вещественного числа до целого
    ”Floating point ROUND to INTEGER”)
    Синтаксис команды: FRNDINT
    Семантика команды: команда округления до целого.
    Псевдокод команды:
    ST(0)← RoundToIntegerValue(ST(0))
    Эта команда округляет текущее содержимое вершины стека до целого числа. Биты RC (Rounding Control) в регистре управления (RCW) определяют способ округления результатов команд блока FPU до заданной точности.
    RCСпособ округления
    00к ближайшему числу near
    01к -∞down
    10к +∞up
    11к нулюchop/zero
    Код (ASM):
    1. ;пример управления округлением
    2. fstcw ax
    3. and eax,1111xx1111111111b;11-10 bits rc
    4. or eax,xx0000000000b
    5. push eax
    6. fldcw word ptr [esp]
    7. pop eax
    8. frndint

    Команда FSQRT
    (извлечения квадратного корня ”Floating point SQUARE ROOT”)

    Синтаксис команды: FSQRT
    Алгоритм работы: извлечения квадратного корня.
    Псевдокод команды:
    ST(0) ← [math]\sqrt{ST(0)}[/math]
    ST(0) не должно быть отрицательно.
    Пример, найдем корни квадратного уравнения, заданного формулой: [math]a\cdot x^{2}+b\cdot x + c=0[/math]
    Из школьного курса математики известно, что решением этого уравнения является [math]x_{1,2}=\frac{- b\pm \sqrt{b^{2}-4\cdot a\cdot c}}{2\cdot a}[/math].
    Программа для решения этого уравнения:
    Код (ASM):
    1. .data
    2. A dd ? ;место под коэффициенты
    3. B dd ?
    4. C1 dd ?
    5. STATUS DW ?
    6. ROOT1 dd ? ;место под 1-ый корень уравнения
    7. ROOT2 dd ?;место под 2-ой корень уравнения
    8. .code
    9.            FNINIT ;инициализируем блок FPU
    10.            FLD B ;загрузить число в регистр стека ST(0)<-B
    11.            FMUL ST,ST ;перемножить числа ST(0)=B*B
    12.            FLD A ;загрузить число в регистр стека, ST(0)=A
    13.            FADD ST,ST
    14.            FADD ST,ST; умножить число в ST(0) на 4.0, ST(0)=4a
    15.            FMUL C1 ;умножить число в ST(0) на C, ST(0)=4ac
    16.            FSUBRP ST(1),ST ; ST(0)=b*b - 4ac
    17. ;проверяем дискриминант на отрицательность
    18.            FSQRT ;извлекаем квадратный корень в ST(0)
    19.            FNSTSW STATUS;записываем в память управляющий регистр FPU
    20.            MOV AH,BYTE PTR STATUS; Читаем в AH
    21.            SAHF; помещаем содержимое регистра AH в регистр флагов
    22.            JC IMAGINARY;если корни мнимые переходим на сообщение об ошибке
    23.            FLD ST(0) ; ST(0) = ST(1)
    24.            FCHS ;ST(0)=-SQRT(D)
    25.            FSUB B;ST(0)=-B-SQRT(D)      
    26.            FLD A
    27.            FADD ST(0),ST(0);ST(0)=2a
    28.            FLD ST;ST(0)=ST(1)=2a
    29.            FDIVP ST(2),ST ;ST(0)= (-B-SQRT(D))/2A
    30.            FXCH
    31.            FST ROOT1;сохраняем в памяти 1-ый результат из ST(0)
    32.            FXCH
    33.            FSUB B;ST(0)= -B+SQRT(D)
    34.            FDIV ST,ST(1);ST(0)=(-B+SQRT(D))/2A
    35.            FSTP ROOT2 ;сохраняем в памяти 2-ой результат
    Возможна проблема с потерей точности
    Еще раз вернемся к нашей задаче. Решением квадратного уравнения является [math]x_{1,2}=\frac{- b\pm \sqrt{b^{2}-4ac}}{2\cdot a}[/math]
    Пусть [math]b[/math] много больше [math]4ac[/math], тогда [math]\sqrt{b^{2} - 4ac}[/math] приблизительно равно [math]b[/math]. Таким образом, можно получить, что [math]-b+b=0[/math], значит [math]x_{1}=0[/math], что не является решением задачи. Преобразуем выражение для [math]x_{1}[/math]:
    [math]x_{1}=\frac{-b+\sqrt{D}}{2a}=\frac{-b+\sqrt{D}}{2a}\frac{b+\sqrt{D}}{b+\sqrt{D}}=\frac{D-b^{2}}{2a(b+\sqrt{D})}=\frac{b^{2}-4ac-b^{2}}{2a(b+\sqrt{D})}=-\frac{2c}{b+\sqrt{D}}[/math] и при [math]b[/math], намного большем [math]4ac[/math] получаем, что [math]x_{1}[/math] стремится к [math]-\frac{2c}{b}[/math].
    Команды масштабирования
    (Возведение числа 2 в произвольную степень)
    • Возведение числа 2 в целую степень. Команда FSCALE
      (Масштабирование числа ”Floating point SCALE ST(0) by ST(1)”)

      Синтаксис команды: FSCALE
      Семантика команды: команда для возведения 2 в степень, равную целому числу, находящемуся в ST(1) и умножение на содержимое ST(0). Результат в ST(0).
      Псевдокод команды: ST(0)← ST(0)×2ST(1)
    • Возведение числа 2 в дробную степень. Команда F2XM1
      (вычисление 2X -1”Floating point compute 2X-1”)

      Синтаксис команды: F2XM1
      Семантика команды: команда вычисления 2 в степени X минус 1.
      Псевдокод команды: ST(0)← 2ST(1)-1
      Эта функция выполняет возведение в степень; она возводит число 2 в степень, указанную в ST(0). Исходное число должно находиться в диапазоне 0 ≤ ST(0) ≤ 0,5 и, чтобы возвести в степень большую 0,5, эту команду нужно использовать вместе с командой FSCALE.
    С помощью команд FLD, загружающих специальные константы, программа может возвести в степень и числа отличные от 2, для этого можно воспользоваться формулами:
    • 2x = (2x-1)+1 = F2XM1(x)+1
    • eX=2X·log2e= 1+F2XM1(x·log2(e)) = 1+ F2XM1(x·FLDL2E)
    • 10X=2X·log210= 1+F2XM1(x·log2(10)) = 1+ F2XM1(x·FLDL2T)
    • XY=2Y·log2X= 1+F2XM1(y·log2(x)) = 1+ F2XM1(FYL2X(y,x))
    Команда FXTRACT
    (выделения порядка и значащей части
    ”EXTRACT exponent and significand”)
    Синтаксис команды: FXTRACT
    Семантика команды: выделения порядка и значащей части вещественного числа.
    Псевдокод команды:
    temp← дробная_часть(ST(0))
    ST(0)←показательная_степень_числа_2ST(0)
    TOP← TOP-1
    ST(0)← temp
    Эта команда разбивает текущую вершину стека на компоненты, ее операндом является вершина стека. Значение показателя степени замещает содержимое вершины стека, а затем дробная часть аргумента помещается в стек и становится новой вершиной стека. Действия команды FXTRACT обратные действиям команды FSCALE. Если в вершине стека находится некоторое число, то выполнение последовательно команд FXTRACT и FSCALE оставляет в вершине стека то же число. Но команда FSCALE не удаляет из стека показатель степени, так что теперь в стеке дополнительно окажется еще одно число.
    Команда FABS
    (вычисления абсолютного значения
    ”Floating point ABSOLUTE value”)
    Синтаксис команды: FABS
    Семантика команды: вычисления абсолютного значения вещественных чисел.
    Псевдокод команды:
    Знаковый_бит(ST(0))← 0
    Эта команда сбрасывает знаковый разряд числа в ST(0) (что соответствует положительному значению).
    Команда FCHS
    (изменения знака ”Floating point CHANGE Sign”)
    Синтаксис команды: FCHS
    Семантика команды: изменения знака вещественного числа.
    Псевдокод команды:
    Знаковый_бит(ST(0))← NOT (Знаковый_бит(ST(0)))
    Команда изменяет знаковый разряд числа в ST(0) на противоположный.
    Кодировка трансцендентальных и прочих функций
    ОперацияОпкодESCOPAModOPBДействие
    FCHSD9E0ESC0011110.0000ST(0)← -1× ST(0)
    FABSD9E1ESC0011110.0001ST(0)← абсолютное значение ST(0)
    F2XM1D9F0ESC0011111.0000ST(0)←(2ST(1)-1)
    FYL2XD9F1ESC0011111.0001ST(0)← ST(1) × log2 (ST(0))
    FPTAND9F2ESC0011111.0010ST(1)← tg(ST(0)) ST(0)← 1.0
    FPATAND9F3ESC0011111.0011ST(0)← Arctg(ST(1)/ST(0))
    FXTRACTD9F4ESC0011111.0100
    FPREM1D9F5ESC0011111.0101
    FPREMD9F8ESC0011111.1000
    FYL2XP1D9F9ESC0011111.1001ST(0)← ST(1)× log2(ST(0)+1)
    FSQRTD9FAESC0011111.1010ST((0)← [math]\sqrt{ST(0)}[/math]
    FSINCOSD9FBESC0011111.1011ST(0)← Sin(ST(0)) ST(1)← Cos(ST(0))
    FRNDINTD9FCESC0011111.1100
    FSCALED9FDESC0011111.1101ST(0)← ST(0)× 2ST(1)
    FSIND9FEESC0011111.1110ST(0)← Sin(ST(0))
    FCOSD9FFESC0011111.1111ST(0)← Cos(ST(0))

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

    Операция сравнения чисел FPU отличается от целочисленной операции сравнения. Это отличие в большем количестве ситуаций и возможных результатов сравнения двух чисел. Числа могут быть:
    1. сравнимы
    2. несравнимы
    3. логически сравнимы
    В первой группе сравниваемые числа могут быть больше, меньше, равны и так далее.
    Во второй группе операнды не сравнимы. На пример, пытаются сравнить число и не число, число и денормализованное число и так далее.
    В третью группу входят ситуации второй группы, но логически переосмысленные. Например, сравнивая число с денормализованным числом, представляют его как сравнение с нулём, или как сравнение числа и бесконечности.
    Как видите третья группа – условна и зависит от постановки задачи, от её особенностей, и того, что имеет смысл, а что нет.
    Всё это вызывает достаточно значительные проблемы. Если вы устанавливаете исключения на все случаи, то есть исключаете ситуацию появления «ненормализованных» чисел – то ваш код можно будет реализовывать как обычно, не обращая внимания на ситуации с образованием ненормализованных результатов. Иначе, потребуется дополнительный анализ после сравнения. При этом заметьте, что в вашей задаче может иметь смысл денормализованный операнд, но не имеет смысла бесконечность, или наоборот.
    Команды FCOM (FCOMP, FCOMPP, FICOM, FICOMP)
    (сравнение вещественных чисел ”COMPARE Floating point values”)
    Синтаксис команды: FCOM <SRC>
    Семантика команды: команда сравнения вещественных чисел.
    Возможные варианты команды:
    • fcom mem
    • fcom st(i)
    • fcomp mem
    • fcomp st(i)
    • fcompp mem
    • fcompp st(i)
    • ficom mem
    • ficom st(i)
    • ficomp mem
    • ficomp st(i)
    Псевдокод команды:
    CASE (relation of operands) OF
    __ST(0)>SRC: C3,C2,C0←000
    __ST(0)<SRC: C3,C2,C0←001
    __ST(0)=SRC: C3,C2,C0←100
    __Unordered: C3,C2,C0←111
    ENDCASE
    В команде FCOM SRC всегда участвует вершина стека ST(0) и явно указанный регистр или операнд в памяти SRC. Команда FCOM SRC выполняет сравнение ST(0) с операндом SRC и устанавливает или сбрасывает биты состояния C3 и C0. При этом указатель стека TOP не модифицируется, если это не команда FCOMP. Особой командой сравнения является FCOMPP, которая не имеет операндов. Она всегда сравнивает два верхних элемента стека ST(0) и ST(1), после сравнения они оба исчезают из стека. Команды FICOM/FICOMP сравнивают содержимое регистра ST(0) и 16- или 32-битной переменной SRC, считается что в SRC содержится целое число. В остальном команды FICOM/FICOMP эквивалентны командам FCOM/FCOMP.
    Флаги состояния C3, C2 и C0 в FPU расположены на тех же местах, что и флаги нуля (ZF), паритета (PF) и переноса (CF) регистра EFLAGS.
    Регистр состояния SWRBC3TOPC2C1C0
    регистр EFLAGSSFZF-AF-PF-CF
    биты76543210
    Для опроса флагов состояния, программа считывает содержимое SWR и записывает его в память командой FSTSW (FNSTSW), которая сохраняет содержимое регистра SWR в 16-битной переменной, или регистре AX. При помощи команды SAHF содержимое флагов C3 и C0 заносится в регистр флагов микропроцессора, правда при этом флаг C1 попадает на неиспользуемый в EFLAGS 1-бит и его значение теряется. Вместо SAHF можно также использовать команду POPF.
    Результат выполнения FCOM SRC
    C0/CFC3/ZFC2/PFЗначение
    000ST(0) > SRC
    100ST(0) < SRC
    010ST = SRC
    111ST(0) и SRC не могут быть сравнены
    ОперацияhexопкодESCOPAModOPBR/MДействие
    FCOMD8D1D8D1ESC00011010ST(1)Сравнить ST(0) c ST(1)
    FCOM
    m32fp​
    D810-7
    D850-7
    D890-7​
    D8/2ESCMF 0MOD=00
    MOD=01
    MOD=10​
    010R/MСравнить ST(0)
    c содержимым ячейки памяти​
    FCOM
    m64fp​
    DC10-7
    DC50-7
    DC90-7​
    DC/2ESCMF 0MOD=00
    MOD=01
    MOD=10​
    010R/MСравнить ST(0)
    c содержимым ячейки памяти​
    FCOM
    ST(i)​
    D8D0-7D8D0+iESC000
    11​
    010ST(i)Сравнить ST(0) c ST(i)
    FCOM2
    ST(i)​
    DCD0-7DCD0+iESC100
    11​
    010ST(i)Сравнить ST(0) c ST(i)
    FCOMPD8D9D8D9ESC000
    11​
    011ST(1)Сравнить ST(0) c ST(1) и
    вытолкнуть ST(0) из стека​
    FCOMP m32fpD818-F
    D858-F
    D898-F​
    D8/3ESCMF 0MOD=00
    MOD=01
    MOD=10​
    011R/MСравнить ST(0) c содержимым ячейки
    памяти и вытолкнуть ST(0) из стека​
    FCOMP m64fpDC18-F
    DC58-F
    DC98-F​
    DC/3ESCMF 0MOD=00
    MOD=01
    MOD=10​
    011R/MСравнить ST(0) c содержимым ячейки
    памяти и вытолкнуть ST(0) из стека​
    FCOMP
    ST(i)​
    D0D8-FD0D8+iESC00011011ST(i)Сравнить ST(0) c ST(i) и
    вытолкнуть ST(0) из стека​
    FCOM5
    ST(i)​
    DED0-7DED0+iESC11011010ST(i)Сравнить ST(0) c ST(i)
    FCOMPPDED9DED9ESC11011011ST(1)Сравнить ST(0) c ST(1) и
    вытолкнуть ST(0)
    и ST(1) из стека​
    FTSTD9E4D9E4ESC00111100100Сравнить ST(0) c нулем
    FICOM
    m16int​
    DE10-7
    DE50-7
    DE90-7​
    DE/2ESCMF 0MOD=00
    MOD=01
    MOD=10​
    010R/MСравнить ST(0) c m16int
    FICOM
    m32int​
    DA10-7
    DA50-7
    DA90-7​
    DA/2ESCMF 0MOD=00
    MOD=01
    MOD=10​
    010R/MСравнить ST(0) c m32int
    FICOMP
    m16int​
    DE18-F
    DE58-F
    DE98-F​
    DE/3ESCMF 0MOD=00
    MOD=01
    MOD=10​
    011R/MСравнить ST(0) c m16int,
    вытолкнуть ST(0)из стека​
    FICOMP
    m32int​
    DA18-F
    DA58-F
    DA98-F​
    DA/3ESCMF 0MOD=00
    MOD=01
    MOD=10​
    011R/MСравнить ST(0) c m32int,
    вытолкнуть ST(0)из стека​
    Команда FUCOM (FUCOMP, FUCOMPP) (сравнение вещественных
    чисел без учета порядка ”Unordered COMPARE Floating point values”)[/CENTER]
    Синтаксис команды: FUCOM<DEST>, <SRC>
    Алгоритм работы: сравнения вещественных чисел без учета порядка.
    Возможные варианты команды:
    • fucom st(0),st(i)
    • fucomp st(0),st(i)
    • fucompp st(0),st(i)
    Псевдокод команды:
    CASE (relation of operands) OF
    __ST(0)>SRC: C3,C2,C0← 000
    __ST(0)<SRC: C3,C2,C0← 001
    __ST(0)=SRC: C3,C2,C0← 100
    ENDCASE
    IF ST(0) or SRC=QNaN, but not SnaN or unsupported format
    __THEN C3,C2,C0← 111
    ELSE;ST(0) or SRC=SnaN or unsupported format
    #IA
    IF FPUControlWord.IM=1
    __THEN C3,C2,C0← 111
    __ENDIF
    ENDIF
     

    Вложения:

    • 01.png
      01.png
      Размер файла:
      1,4 КБ
      Просмотров:
      2.618
    • 02.png
      02.png
      Размер файла:
      11,3 КБ
      Просмотров:
      2.598
    Последнее редактирование: 8 дек 2021
    Indy_ нравится это.
  4. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.792
    Команды FCOMI, FCOMIP, FUCOMI, FCOMIP появились в процессорах P6 и позволяют напрямую заносить результаты сравнения в регистр EFLAGS, не используя команды FSTSW AX/SAHF.
    ОперацияОпкодESCOPAModOPBR/MДействие
    FCOMI ST(0),ST(i)DBF0+iESCP 1111110ST(i)P=0
    Сравнить ST(0) и ST(i),
    установить EFLAGS
    FCOMIP ST(0),ST(i)DFF0+iESCP 1111110ST(i)P=1
    Сравнить ST(0) и ST(i),
    установить EFLAGS,
    извлечь из стека
    FUCOMI ST(0),ST(i)DBE8+iESCP 1111101ST(i)P=0
    Сравнить без учета
    порядков значения в ST(0)
    и ST(i), установить EFLAGS
    FUCOMIP ST(0),ST(i)DFE8+iESCP 1111101ST(i)P=1
    Сравнить без учета
    порядков значения в ST(0)
    и ST(i), установить
    EFLAGS, извлечь из стека
     
    Последнее редактирование: 23 окт 2021
  5. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.792

    Результат выполнения FUCOM SRC

    CFZFPFЗначение
    000ST(0) > SRC
    100ST(0) < SRC
    010ST = SRC
    111ST(0) и SRC не могут быть сравнены
     
    Последнее редактирование: 22 окт 2021
  6. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.792
    ОперацияhexОпкодESCOPAModOPBR/MДействиеРезультат
    FCOM st(i)D8D0-7D8D0+iESC00011010ST(i)Сравнение вещественного
    значения, находящегося в ST(0),
    с оператором, находящемся в
    памяти или ST(i)
    Флаги FPU
    FCOM m32fpD810-7
    D850-7
    D890-7
    D8/2ESC000MOD=00
    MOD=01
    MOD=10
    010R/MФлаги FPU
    FCOM m64fpDC10-7
    DC50-7
    DC90-7
    DC/2ESC100MOD=00
    MOD=01
    MOD=10
    010R/MФлаги FPU
    FCOMP st(i)D8D8-FD8D8+iESC00011011ST(i)Сравнение вещественного
    значения, находящегося в ST(0),
    с оператором, находящемся в
    памяти или ST(i), с выталкиванием
    вещественного значения с
    вершины стека
    Флаги FPU
    FCOMP m32fpD818-F
    D858-F
    D898-F
    D8/3ESC000MOD=00
    MOD=01
    MOD=10
    011R/MФлаги FPU
    FCOMP m64fpDC18-F
    DC58-F
    DC98-F
    DC/3ESC100MOD=00
    MOD=01
    MOD=10
    011R/MФлаги FPU
    FCOMPPDED9DED9ESC110
    11​
    011ST(1)Сравнивает вещественное значение,
    находящееся в ST(0) и ST(1), с оператором,
    находящемся в памяти или в ST(i), с
    выталкиванием вещественного значения
    из ST(0) и ST(1)
    Флаги FPU
    FCOMIDBF0-7DBF0+iESC011
    11​
    110ST(i)Сравнение вещественного значения,
    находящегося в ST(0), с оператором
    ST(i)
    Флаги CPU
    FCOMIPDFF0-7DFF0+iESC111
    11​
    110ST(i)Сравнение вещественного значения,
    находящегося в ST(0), с оператором
    ST(i) с выталкиванием вещественного
    значения с вершины стека
    Флаги CPU
    FUCOMIDBE8-FDBE8+iESC011
    11​
    101ST(i)Неупорядоченно сравнивает вещественное
    значение, находящееся в ST(0), с
    оператором ST(i)
    Флаги CPU
    FUCOMIPDFE8-FDFE8+iESC111
    11​
    101ST(i)Неупорядоченно сравнивает вещественное
    значение, находящееся в ST(0), с
    оператором ST(i) с выталкиванием
    вещественного значения с
    вершины стека
    Флаги CPU
    Кроме команд сравнения также доступны команды анализа FTST и FXAM.
    Команда FTST (сравнение вещественных чисел без
    учета порядка ”TEST Floating point values”)
    Синтаксис команды: FTST
    Алгоритм работы: команда FTST сравнивает содержимое вершины стека ST(0) с нулём, и устанавливает коды условий.
    Результат выполнения FTST
    C0/CFC3/ZFC2/PFЗначение
    0​
    0​
    0​
    ST(0) > 0​
    1​
    0​
    0​
    ST(0) < 0​
    0​
    1​
    0​
    ST (0)= 0​
    1​
    1​
    1​
    ST(0) и 0 не могут быть сравнены
    Команда FXAM (проверка числа на вершине стека ”Floating point EXAMINE”)
    Синтаксис команды: FXAM
    Алгоритм работы: проверка числа на вершине стека.
    Команда FXAM устанавливает флаги регистра состояния от C0 до C3, показывая какое число находится на вершине стека.
    C3/ZFC2/PFC1C0/CFЗначение
    0000+ ненормализованное
    0001+ NAN (не число)
    0010- ненормализованное
    0011- NAN
    0100+ нормализованное
    0101+∞
    0110- нормализованное
    0111-∞
    1000+ 0
    1001Пусто
    1010- 0
    1011Пусто
    1100+ денормализованное
    1101пусто
    1110- денормализованное
    1111пусто
    Если очень внимательно рассмотреть таблицу результата выполнения команды FXAM, то можно заметить, что C1 отвечает за знак (C1=0 – знак положительный, C1=1 – знак отрицательный). Если число конечное (ноль, ненормализованное число, нормализованное число, денормализованное число) – С0 = 0, если число неконечное (нечисло, бесконечность, пусто) – С0 = 1.
    C1=0C1=1C3/ZFC2/PFC0/CF
    +ненормализованное-ненормализованное
    0​
    0​
    0
    +нормализованное-нормализованное
    0​
    1​
    0
    +0-0
    1​
    0​
    0
    +денормализованное-денормализованное
    1​
    1​
    0
    +NAN (нечисло)-NAN (нечисло)
    0​
    0​
    1
    +∞-∞
    0​
    1​
    1
    ПустоПусто
    1​
    0​
    1
    ПустоПусто
    1​
    1​
    1
    Команда FCMOVcc
    (Условная пересылка данных ”Floating point Condition MOVE”)
    Синтаксис команды: FCMOVcc <DEST>, <SRC>
    Семантика команды: условная пересылка данных.
    Возможные варианты команды:
    • fcmove st(0),st(i)
    • fcmovne st(0),st(i)
    • fcmovb st(0),st(i)
    • fcmovbe st(0),st(i)
    • fcmovnb st(0),st(i)
    • fcmovnbe st(0),st(i)
    • fcmovu st(0),st(i)
    • fcmovnu st(0),st(i)
    Псевдокод команды:
    IF condition TRUE
    THEN ST(0)← ST(i)
    ENDIF
    Это набор команд, каждая из которых копирует содержимое регистра ST(i)) в ST(0), если выполняется соответствующее условие. Реально, каждое условие соответствует тем или иным значениям флагов регистра EFLAGS, но после команд fcom ; (или другие команды сравнения)
    Код (ASM):
    1. fstsw ax
    2.  sahf
    3. fcmovcc
    в регистр FLAGS загружаются флаги С0, С1 и С3, и последующая команда из набора FCMOVcc приобретает смысл обработки результата предыдущего сравнения.
    ОперацияОпкодЗначения
    флагов​
    ESCOPAModOPBR/MДействие после FCOM
    FCMOVB ST(0),ST(i)DAC0-7ZF = 1ESC010
    11​
    000ST(i)если равно
    FCMOVE ST(0),ST(i)DAC8-FZF = 0ESC010
    11​
    001ST(i)если не равно
    FCMOVBE ST(0),ST(i)DAD0-7CF = 1ESC010
    11​
    010ST(i)если меньше
    FCMOVU ST(0),ST(i)DAD8-F
    CF = 1 и​
    ZF = 1​
    ESC010
    11​
    011ST(i)если меньше или равно
    FCMOVNB ST(0),ST(i)DBC0-7CF = 0ESC011
    11​
    000ST(i)если не меньше
    FCMOVNE ST(0),ST(i)DBC8-F
    CF = 0 и​
    ZF = 0​
    ESC011
    11​
    001ST(i)если не меньше или равно
    FCMOVNBE ST(0),ST(i)DBD0-7PF = 1ESC010
    11​
    010ST(i)если несравнимы
    FCMOVNU ST(0),ST(i)DBD8-FPF = 0ESC010
    11​
    011ST(i)если сравнимы
    ОперацияhexОпкодESCOPAModOPBR/MДействие
    FTSTD9E4D9E4ESC001
    11​
    100100Сравнить ST(0) с 0.0
    FXAMD9E5D9E5ESC001
    11​
    100101Классифицировать значение в ST(0)
    FNSTSW AXDFE0DFE0ESC111
    11​
    100000
    FNSTSW m2byteDD38-F
    DD78-F
    DDA8-F​
    DD/7ESC101MOD=00
    MOD=01
    MOD=10​
    111R/M
    FNSTSW AXDFE0DFE0ESC111
    11​
    100000
    Трансцендентальные функции
    Числа, не удовлетворяющие никакому алгебраическому уравнению с целыми коэффициентами, называются трансцендентальными. π=3,141592... и e=2,71828... – трансцендентальные числа. Если a и b – положительные алгебраические числа, то число loga(b) либо рациональное, либо трансцендентальное. Числа log2(3), lg(5), ln(27) и тому подобные – трансцендентальны.
    Десятичный логарифм любого целого числа, не изображаемого единицей с нулями (1, 10, 100, 0.1, 0.01) – трансцендентальное число.
    Трансцендентальные функции – это аналитические функции, не являющиеся алгебраическими. К элементарным трансцендентным функциям относятся:
    • тригонометрические (sin, cos, tg,...);
    • обратные тригонометрические (arcsin, arccos, arctg,...);
    • логарифмические функции (log2x, lg(x), ln(x));
    • показательные функции (xy, 2y, 10x, ex);
    • гиперболические функции (sh, ch, th, ...);
    • обратные гиперболические (arcsh, arch, arcth, ...);
    FPU не реализует их все. В нём представлены только основные функции, которые необходимы для вычисления всех остальных возможных.
    Тригонометрические функции
    Команда FCOS
    (вычисление косинуса ”Floating point COSINE)
    Синтаксис команды: FCOS
    Семантика команды: команда вычисления косинуса.
    Псевдокод команды:
    IF |ST(0)|< 263
    _THEN C2← 0
    _ST(0)← Cos(ST(0))
    ELSE;операнд выходит за пределы
    _C2← 1
    ENDIF
    Косинус числа, находящегося в ST(0). Операнд считается заданным в радианах и имеет пределы 263 и -263. Если операнд выходит за эти пределы, флаг C2 = 1, а ST(0) не изменяется.
    Команда FSIN
    (вычисление синуса =”Floating point SINE)
    Синтаксис команды: FSIN
    Семантика команды: команда вычисления синуса.
    Псевдокод команды:
    IF |ST(0)|<263
    THEN C2←0
    ST(0)← Sin(ST(0))
    ELSE;операнд выходит за пределы
    C2← 1
    ENDIF
    Синус числа, находящегося в ST(0). Операнд считается заданным в радианах и имеет пределы 263 и -263. Если операнд выходит за эти пределы, флаг C2 = 1, а содержимое ST(0) не изменяется.
    Имея вычисленный sin2(x), легко получить cos2(x): sin2(x)+cos2(x)=1
    sin(2x) = 2 sin(x) cos(x)
    [math]cos^{2}(\frac{x}{2})=\frac{cos(x)+1}{2}[/math]
    [math]cos(2x) = cos^{2}(x)-sin^{2}(x)[/math]
    Команда FSINCOS
    (вычисление косинуса и синуса числа =”Floating point SINE and COSINE)
    Синтаксис команды: FSINCOS
    Семантика команды: команда вычисления косинуса и синуса числа. Псевдокод команды:
    IF |ST(0)|<263
    _THEN C2← 0
    _temp← Cos(ST(0))
    _ST(0)← Sin(ST(0))
    _TOP← TOP-1
    _ST(0)← temp
    ELSE;операнд выходит за пределы
    _C2← 1
    ENDIF
    ST(0)←угол в радианах, результат вычислений в ST(0)=Cos(угол) и ST(1)=Sin(угол)
    Команда FPTAN
    (вычисление частичного тангенса=”Floating point Partial TANGENT”)
    Синтаксис команды: FPTAN
    Семантика команды: команда вычисления частичного тангенса числа.
    Псевдокод команды:
    IF |ST(0)|<263
    _THEN C2← 0
    _ST(0)← tg(ST(0))
    _TOP← TOP-1
    _ST(0)← 1.0
    ELSE;операнд выходит за пределы
    _C2← 1
    ENDIF
    ST(0)← X ST(1)← Y, где Y/X = tg([math]\alpha[/math])
    ST(0)← ST(1)/ST(0)Исходное число – угол α, выраженный в радианах, значение которого должно быть в интервале 0<α< π/4, помещается в вершину стека. Уменьшить угол α до правильного значения можно с помощью команды FPREM. Результатом является отношение Y/X, которое равно тангенсу угла α; Y передается в ST(0), а затем в ST(0) помещается X.
    Вычисляется тангенс. Результат помещается в ST(0), после чего в ST(0) помещается 1, так что: ST(0) = 1, ST(1) = tg(ST(0)). Единица в ST(0) была нужна для дальнейших вычислений значений sin/cos (инструкции fsin/fcos появились позже, до их появления cos(x) и sin(x) приходилось вычислять через fptan по формулам [math]cos(x)=\frac{1}{\sqrt{1+tg^{2}(x)}}[/math] и [math]sin(x)=\frac{tg(x)}{\sqrt{1+tg^{2}(x)}}[/math]
    ST(0)=1 и ST(1)=tg(ST(0)) упрощают вычисление ctg(x)
    вычисляем ctg(x) через fptan
    Код (ASM):
    1.  fld x ;st(0)=x
    2. fptan  ;st(0)=1    st(1)=tg(x)
    3. fdivr  ;  st(0)=1/tg(x)=ctg(x)
    если котангенс не нужен, то избавится от единицы в ST(0) можно разделив на 1 командой fdivp или вытолкнуть 1 из стека командой fstp st(0)
    вычисляем COS(π/4) через FPTAN
    Код (ASM):
    1. .data
    2. buffer db 100 dup(?)
    3. fMtStrinG   db " %1.15f",0
    4.  . . .
    5.  .code
    6.  . . .
    7.     push eax
    8.     fldpi
    9.     push 4
    10.     fild dword ptr [esp]
    11.     fdiv; fdivp  st(1),st;3,1415926535897932384626433832795/4=0,78539816339744830961566084581988
    12.     fptan;st(1)=tg(pi/4)=0,9999999999999999387 st(0)=1,0
    13.     fxch ;fxch st(1)
    14.     fmul st,st
    15.     fadd st,st(1);st(0)=2.0
    16.     fsqrt;st(0)=1,4142135623730950488016887242097
    17.     fdiv; fdivp st(1),st   st(0)=0,70710678118654752440084436210485
    18.     fstp qword ptr [esp]      
    19.     invoke crt_sprintf,ADDR buffer,ADDR fMtStrinG,dword ptr [esp+4],dword ptr [esp+4]
    20.     add esp,8
    21.     invoke MessageBox,0,ADDR buffer,ADDR aTitle,MB_OK
    Команда FPATAN (вычисление частичного арктангенса
    ”Floating point Partial ARCTANGENT”)
    Синтаксис команды: FPATAN
    Семантика команды: команда вычисления частичного арктангенса от вещественного числа.
    Псевдокод команды:
    IF 0\leq |ST(1)|<|ST(0)|<+∞
    THEN ST(1)← arctg(ST(1)/ST(0))
    PopRegisterStack
    ENDIF
    ST(0)← [math]arctg(\frac{Y}{X})=arctg(\frac{ST(1)}{ST(0)})[/math]
    Эта функция дополняет предыдущую, FPTAN. Команда FPATAN вычисляет угол в соответствии с отношением чисел ST(1) и ST(0). Она извлекает из стека число X, а затем записывает результирующий угол вместо числа Y в качестве новой вершины стека. Исходные значения должны подчиняться неравенству 0<Y<X<+∞.
    Вычисляет арктангенс числа ST(1)/ST(0). Результат записывается в ST(1), а ST(0) выталкивается. Результат имеет знак ST(1) и меньше числа p по абсолютной величине.
    Для вычисления arcsin(x) и arccos(x) используется свойство cos2(x)+sin2(x)=1.
    [math]tg(x)=\frac{sin(x)}{\sqrt{1-sin^{2}(x)}}=\frac{\sqrt{1-cos^{2}(x)}}{cos(x)}[/math]
    Обратные тригонометрические функции
    [math]arcsin(x)=arctg(\frac{x}{\sqrt{1-x^{2}}})[/math]
    Код (ASM):
    1. ; вычисляем арксинус числа, находящегося в st(0) (-1 <= х <= +1)
    2. ; по формуле arcsin(x) = arctg(x/sqrt(1-x*x))
    3. ; результат возвращается в st(0), в стеке FPU должно быть
    4. ; два свободных регистра
    5.         fld  x             ; х (начальное состояние стека)
    6.         fld  st(0)      ; st(0)=х      st(1)=х
    7.         fmul  st, st(1)  ; st(0)=x*x   st(1)=x
    8.         fld1       ; st(0)=1   st(1)=x*x    st(2)=x
    9.         fsubr    ; st(0)=1-x*x    st(1)=x
    10.         fsqrt     ; st(0)=sqrt(1-x*x)    st(1)=x
    11.         fpatan  ; arctg(x/sqrt(1-x*x))
    [math]arccos(x)=arctg(\sqrt{\frac{1-x}{1+x}})[/math]
    [math]arcsec(x)=arccos(\frac{1}{x})[/math]
    Логарифмические функции
    Команда FYL2X (вычисление Y·log2X = ”Compute Y·log2(X)”)
    Синтаксис команды: FYL2X
    Алгоритм работы: вычисление Y·log2(X)
    Псевдокод команды:
    ST(1)← ST(1)·log2(ST(0))
    PopRegisterStack
    Эта функция выполняет операцию логарифмирования. Она берет логарифм по основанию 2 от содержимого ST(0) и затем умножает его на содержимое ST(1). Команда FYL2X извлекает из стека число X и замещает результат числом Y. Исходные числа должны удовлетворять следующим соотношениям:
    0<X<+ и -<Y<+
    Результат размещается в ST(1), а ST(0) выталкивается из стека. При этом ST(0)>0, если ST(0) = 0, тогда результат (ZM = 1) равен бесконечности со знаком, обратным ST(1).
    Логарифмические функции на основе FYL2X
    А что делать, если требуется вычислить логарифм по основанию, не равному 2? С помощью формулы [math]log_{Y}X=\frac{log_{2}X}{log_{2}Y}[/math] вычисляется логарифм числа X по основанию Y. Команды загрузки FLDLG2 (загрузка lg(2)) и FLDLN2 (загрузка ln(2)) позволяют работать с десятичными (бригговыми) и натуральными (неперовыми или гиперболическими) логарифмами:
    log2(X) = FYL2X(x);
    ln(X) = ln(2)·log2(X) = FYL2X(ln(2), X) = FYL2X (FLDLN2,X)
    lg(X) = lg(2)·log2(X) = FYL2X(lg(2), X) = FYL2X (FLDLG2,X)

    Команда FYL2XP1
    (вычисление Y·log2(X+1) = ”Compute Y·log2(X+1)”)


    Синтаксис команды: FYL2XP1
    Алгоритм работы: вычисление Y·log2(X+1)
    Псевдокод команды:
    ST(1)← ST(1)·log2(ST(0)+1.0)
    PopRegisterStack
    Эта функция идентична функции FYL2X, за исключением того, что к X прибавляется 1. Функция FYL2XP1 накладывает более жесткие ограничения на X и предназначена для вычисления логарифмов чисел, значения которых очень близки к 1. Эта функция дает наиболее высокую точность, если [math]0<|X|< 1-\frac{\sqrt{2}}{2}[/math].
    Вычисляет ST(1)·log2(ST(0)+1). ST(1) равен результату, после чего ST(0) выталкивается из стека. При этом первоначальный ST(0) принадлежит [math](-a,a)[/math], где [math]a = 1-\frac{1}{\sqrt{2}}[/math]. Наличие этой команды обусловлено тем, что она даёт большую точность, чем FYL2X для суммы ST(0)+1 для чисел, близких к нулю.

    Команды загрузки констант

    Команды загружают в стек заранее известные величины. Все команды загрузки констант не имеют операндов и могут работать только с ST(0).
    ОперацияОпкодESCOPДействие
    FLD1D9E8ESC001.1110.1000Команда загрузки единицы (+1.0)
    FLDL2TD9E9ESC001.1110.1001Команда загрузки log2(10)=3,32192809488736234780…
    FLDL2ED9EAESC001.1110.1010Команда загрузки log2(e)= 1,44269504088896340725…
    FLDPID9EBESC001.1110.1011Команда загрузки числа π = 3,141593265358979323…
    FLDLG2D9ECESC001.1110.1100Команда загрузки lg(2)=0,3010299956639811952202…
    FLDLN2D9EDESC001.1110.1101Команда загрузки ln(2)=0,6931471805599453094172…
    FLDZD9EEESC001.1110.1110Команда загрузки нуля (+0.0)

    Как можно скрыть команды загрузки констант от "исследователя программ"


    Если вспомнить формулу [math]log_{A}(B)=1/log_{B}(A)[/math], тогда часть команд для загрузки констант можно спрятать.
    FP-опкодОписаниечислоэквивалент
    FLDL2EПомещает константу = log2(e) в стек1,4426950408889634073599246810019=1/ln(2)
    FLDL2TПомещает константу = log2(10) в стек3,3219280948873623478703194294894=1/lg(2)
    FLDLG2Помещает константу = lg(2) в стек0,30102999566398119521373889472449=1/log2(10)
    FLDLN2Помещает константу = ln(2) в стек0,69314718055994530941723212145818=1/log2(e)
    FLDZ заменить на FSUB st(0),st(0)
    FLD1 заменить на FDIV st(0),st(0)
    Замена FLDPI
    Код (ASM):
    1.  fld1
    2.  fadd st,st;st(0)=2.0
    3.  fld st
    4.  fld st
    5.  fpatan;ST(1)=arctg(ST(1)/ST(0))=arctg(1.0)=pi/4=0.7853981633974, вытолкнуть из стека
    6.  fscale; ST(0)=ST(0)x2^{ST(1)}   0.7853981633974 * 4=3.141593265358979323…

    Команды управления FPU

    Команды управления ничего не вычисляют, однако они необходимы для управления FPU. Обычно эти команды требуются в подпрограммах и процедурах прерываний, в которых происходит совместная работа блоков IEU и FPU, а также при обработке ошибок блока FPU. Некоторые команды (например, FINIT/FNINIT) имеют альтернативную мнемонику с символом N, предназначенные для использования в тех случаях, когда команда WAIT не нужна.
    Команда инициализации FINIT/FNINIT (FPU INITIALIZE) сбрасывает FPU в состояние, в которое он попадает при включении питания. Рекомендуется использовать эту команду перед обращением к FPU. В результате FINIT:
    • rc=0 (режим округления к ближайшему числу);
    • флаги особых ситуаций в регистре SWR сброшены;
    • флаги запрета прерываний в регистре CWR по особым ситуациям установлены;
    • TOP=7.
    Команда FSTSW/FNSTSW (FPU STORE Status Word) записывает в 16-битную ячейку памяти значение регистра состояния FPU. Допускается использование регистра AX.
    Команда FSTCW/FNSTCW (FPU STORE Control Word) записывает в 16-битную ячейку памяти значение регистра управления FPU.
    Команда FFREE ST(i) (FPU FREE register) отмечает атрибут регистра ST(i) в регистре TW как незанятый.
    Команда FCLEX (FPU CLEAR EXCEPTION) сбрасывает признаки особых ситуаций в регистре SWR.
    Структура области памяти с рабочей средой сопроцессора
    Команда FLDCW SRC (FPU LOAD Control Word) записывает в регистр RCW содержимое 16-битной ячейки памяти. Подобная команда для записи в регистр RSW не предусмотрена.
    Пустая команда FNOP (FPU Not OPERATION) используется для синхронизации совместных действий процессора и FPU и в отладочных целях. Может быть заменена некоторыми командами управления (FNENI - enable interrupts, FNDISI- disable interrupts), унаследованными от i8087, i80287 и недействительными в P6.
    Команды FDECSTP/FINCSTP (FPU DECREMENT/INCREMENT Stack-Top Pointer) уменьшают/увеличивают величину TOP на единицу, «передвигая» по кольцу значения между регистрами ST(i).
    Команда FSTENV DEST (FPU STORE ENVIRONMENT) считывает в ячейку DEST (m14byte, если use16 либо m28byte, если use32) в системной памяти содержимое регистров TW, RSW, RCW, FIP, FDP. Устанавливает в RCW флаги запрета прерываний по особым ситуациям.
    Код (ASM):
    1. 401000h: sub esp,28h
    2. 401003h: ftst ;<-- получим eip этой команды
    3. 401005h: fstenv (28-byte) ptr [esp]
    4. 401008h: mov eax,dword ptr [esp+0Ch]; eax=401003h
    5. 40100Ch: add esp,28h
    6. ;-----esp=18FF64h--FPU Environment--
    7. 18FF64h: FFFF027F; FCW=027Fh
    8. 18FF68h: FFFF4541; FST=4541h
    9. 18FF6Ch: FFFFFFFF
    10. 18FF70h: 00401003; EIP=401003h
    11. 18FF74h: 00000023
    12. 18FF78h: 00000000
    13. 18FF7Ch: FFFF0000
    14. 18FF80h: 00000000
    15. 18FF84h: 00000000
    16. 18FF88h: 00000000
    Команда FLDENV SRC (FPU LOAD ENVIRONMENT) записывает в FPU образ его регистров из ячейки SRC (m14byte, если use16 либо m28byte, если use32) системной памяти.
     
    Последнее редактирование: 3 фев 2023
  7. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.792
    ОперацияhexОпкодESCOPAModOPBR/MДействие
    FWAIT/WAIT
    9B​
    9B​
    wait for x87 FPU ready
    FNOPD9D0D9D0ESC=1101.1
    001.1101.0000​
    No operations
    FNENIDBE0DBE0ESC=1101.1
    101.1110.0000​
    Treated as Integer NOP
    FNDISIDBE1DBE1ESC=1101.1
    101.1110.0001​
    Treated as Integer NOP
    FDECSTPD9F6D9F6ESC=1101.1
    001.1111.011i​
    i=0 Decrement stack pointer
    TOP←(TOP-1)& 7
    FINCSTPD9F7D9F7ESC=1101.1
    001.1111.011i​
    i=1 Increment stack pointer
    TOP←(TOP+1)& 7
    FLDCW m2byteD928-F
    D968-F
    D9A8-F
    D9/5ESC=1101.1001MOD=00
    MOD=01
    MOD=10
    101R/MLoad control word
    FNCLEXDBE2DBE2ESC=1101.1
    011.1110.0010​
    Clear exceptions
    FNINITDBE3DBE3ESC=1101.1
    011.1110.0011​
    Initialize MCP
    RCW←37Fh RSW←0 TW←0FFFFh FDP←0 FIP←0 LastInstructionOpcode←0
    FSETPMDBE4DBE4ESC=1101.1
    011.1110.0100​
    Enter Protected Mode, сейчас #UD
    FFREE ST(i)DDC0-7DDC0+iESC=1101.1101
    11​
    000ST(i)TAG(i)←11b
    FFREEP ST(i)DFC0-7DFC0+iESC=1101.1111
    11​
    000ST(i)FFREE ST(i)
    FSTP ST(0)
    FLDENV m14/28byteD920-7
    D960-7
    D9A0-7
    D9/4ESC=1101.1001MOD=00
    MOD=01
    MOD=10
    100R/MLoad environment
    RCW←SRC, RSW←(SRC+2), TW←(SRC+4), FIP←(SRC+6), FDP←(SRC+10)
    FNSAVE m94/108byteDD28-F
    DD68-F
    DDA8-F
    DD/5ESC=1101.1101MOD=00
    MOD=01
    MOD=10
    101R/MSave state
    FSTENV m14/28byteD930-7
    D970-7
    D9B0-7
    D9/6ESC=1101.1001MOD=00
    MOD=01
    MOD=10
    110R/MStore environment
    DEST←RCW,(DEST+2)←RSW,(DEST+4)←TW,(DEST+6)←FIP, (DEST+10)←FDP
    FRSTOR
    m94/108byte
    DD20-7
    DD60-7
    DDA0-7
    DD/4ESC=1101.1101MOD=00
    MOD=01
    MOD=10
    100R/MRestore state
    FXRSTOR
    m512byte
    0FAE08-F
    0FAE48-F
    0FAE88-F
    0FAE/10000.1111.1010.1110MOD=00
    MOD=01
    MOD=10
    001R/MRestore x87 FPU, MMX, XMM, and MXCS register state from m512byte
    FXSAVE
    m512byte
    0FAE00-7
    0FAE40-7
    0FAE80-7
    0FAE/00000.1111.1010.1110MOD=00
    MOD=01
    MOD=10
    000R/MSave the x87 FPU, MMX, XMM, and MXCSR
    register state to m512byte
    Команда FSAVE DEST (FPU SAVE State) считывает в ячейку DEST (m94byte, если use16 либо m108byte, если use32) в системной памяти данные из FPU целиком, включая R0-R7, и выполняет FINIT. За первыми 14/28 байтами окружения следуют копии R0-R7.
    Команда FRSTOR SRC (FPU RESTORE State) восстанавливает состояние FPU полностью, в соответствии с образом из ячейки SRC (m94byte, если use16 либо m108byte, если use32) в системной памяти
    Команда FWAIT/WAIT останавливает центральный процессор до завершения текущей операции в FPU. В P6 имеет смысл только при обработке аппаратных прерываний, возникающих в связи с ошибками в блоке FPU.
    Опкоды основных команд FPU
    Для команд с операндом в регистре st(i) используется режим регистровой адресации (Mod=11 R/M=st(i)), для команд с операндом в ячейке памяти выбран режим прямой адресации (Mod=00 R/M=101). Для режимов с косвенной адресацией:
    • Mod=00
      • R/M=000 - [EAX]
      • R/M=001 - [ECX]
      • R/M=010 - [EDX]
      • R/M=011 - [EBX]
      • R/M=100 - за R/M следует байт SIB
      • R/M=110 - [ESI]
      • R/M=111 - [EDI]
    • Mod=01
      • R/M=000 - [EAX + 8-битное смещение]
      • R/M=001 - [ECX + 8-битное смещение]
      • R/M=010 - [EDX + 8-битное смещение]
      • R/M=011 - [EBX + 8-битное смещение]
      • R/M=100 - за R/M следует SIB, а далее 8-битное смещение
      • R/M=101 - [EBP + 8-битное смещение]
      • R/M=110 - [ESI + 8-битное смещение]
      • R/M=111 - [EDI + 8-битное смещение]
    • Mod=10
      • R/M=000 - [EAX + 32-битное смещение]
      • R/M=001 - [ECX + 32-битное смещение]
      • R/M=010 - [EDX + 32-битное смещение]
      • R/M=011 - [EBX + 32-битное смещение]
      • R/M=100 - за R/M следует SIB, а далее 32-битное смещение
      • R/M=101 - [EBP + 32-битное смещение]
      • R/M=110 - [ESI + 32-битное смещение]
      • R/M=111 - [EDI + 32-битное смещение]
    командаm32fpm64fpm80fpst(i)m16intm32intm64intm80bcd
    FADD/FIADDD805DC05D8C0+iDE05DA05
    FMUL/FIMULD80DDC0DDCC8+iDE0DDA0D
    FCOM/FICOMD815DC15D8D0+iDE15DA15
    FCOMP/FICOMPD81DDC1DD8D8+iDE1DDA1D
    FSUB/FISUBD825DC25D8E0+iDE25DA25
    FDIV/FIDIVD835DC35D8F0+iDE35DA35
    FLD/FILD/FBLDD905DD05DB2DD9C0+iDF051DB05DF2DDF252
    FST/FISTD915DD15DDD0+iDF15DB15
    FSTP/FISTP/FBSTPD91DDD1DDB3DDDD8+iDF1DDB1DDF3DDF35
    FADDPDEC0+i
    FMULPDEC8+i
    FSUBPDEE8+i
    FDIVPDEF8+i
    FSUBRPDEE0+i
    FDIVRPDEF0+i
    15-11109876543210Добавочные поля
    111011
    OPA​
    1​
    MOD1OPB
    R/M​
    SIB​
    смещение​
    2
    MF​
    0​
    MOD
    OP​
    R/M​
    SIB​
    смещение​
    3
    MF​
    1​
    MOD
    OP​
    R/M​
    SIB​
    смещение​
    4
    D​
    POPA
    11​
    OPB​
    ST(i)​
    ―​
    5
    0​
    0
    1​
    11​
    1
    OP​
    ―​
    6
    0​
    1
    1​
    11​
    1
    OP​
    ―​
    OP опкод команды, может состоять из двух частей OPA и OPB
    MF = Memory Format
    00m32fp
    01m32int
    10m64fp
    11m16int
    P = Pop
    0Не выталкивает аргумент из стека
    1Выталкивает из стека после выполнения команды
    D = Место назначения (Destination)
    0ST(0)
    1ST(i) или память
    1 Под командой FLD mXXint подразумевается команда FILD mXXint
    2 Под командой FLD m80bcd подразумевается команда FBLD m80bcd
     
    Последнее редактирование: 11 ноя 2021
    aa_dav нравится это.