Математический сопроцессор
Floating-point unit, FPU — блок процессора предназначенный для обратки чисел с плавающей точкой. Раньше сопроцессор был отдельной микросхемой. Теперь чаще всего он находится непосредственно на кристале процессора.
Типы данных
Сопроцессор архитектуры х86 способен обрабатывать следующие типы данных:
- single (float)
- double
- extended (80 бит)
- int (16/32/64 бит)
- bcd80 — двоично-десятичный 10-байтовый формат, каждый полубайт которого хранит одну десятичную цифру
Регистры
Регистры общего назначения не подходят для обработки чисел с плавающей точкой. Для этих чисел существуют 8 специальных регистров организованных в кольцевой стек.
Это 80-битовые регистры r0-r7, однако в программе к ним обращаются по именам st(*)(без скобок при компиляции в yasm).
st(2) | r7 |
st(1) | r6 |
st(0) | r5 |
st(7) | r4 |
st(6) | r3 |
st(5) | r2 |
st(4) | r1 |
st(3) | r0 |
При добавлении в стек еще однго элемента произойдет сдвиг этих имен. st(7) станет st(0) — вершиной стека.
st(3) | r7 |
st(2) | r6 |
st(1) | r5 |
st(0) | r4 |
st(7) | r3 |
st(6) | r2 |
st(5) | r1 |
st(4) | r0 |
Управляющие регистры
Так же существуют несколько специальных регистров:
- cr \\управляющий регистр. Позволяет контролировать режимы округления и пр.
- sr \\регистр состония
- tw \\метки (пустой, число, не число, ...)
При обработке исключений так же используются:
- fip \\регистр указателя команд
- fdp \\регистр указателя данных
Команды
- fld/fild/fbl
загрузка из памяти или копирование из другого fpu регистра в st(0). Например:
fld st(0)
fild dword [eax]
- fst(p)/fist(p)/fbstp *(p) +выталкивает вершину
загрузка в память или st(*) из st(0) регистра
- fxch \\swap(st(0), st(*))
- fcmov_cc \\условная загрузка
- fcom st(2)(p(p)) \\сравнение с вершиной
- fstsw ax
- sahf
флаги сопроцессора в флаги процессора
- fucom(p) \\еще одно сравнение
- ficom(p) \\сравнение с памятью
- fcomi(p) \\результат сравнения в flags
- fucomi(p)
Вычисления
- fadd(p)/fiadd \\st(0) = arg + st(0)
- fsub(p)/fisub \\st(0) = st(0) - arg
- sfubr(p)/fisubr \\st(0) = arg - st(0)
- fmul(p)/fimul
- fdiv(p)/fidiv
- dfivr(p)/fidivr
- frem/frem1 st(0) - n * st(1) \\остаток получаемый вычитаниями (не блолее 64 штук)
- fchs
изменить знак на противоположный.
Работают с st(0) Не нуждаются в отдельныз пояснениях.
- fabs
- frndint
- fsin
- fcos
- fsincos
- fptan
- fpatanb
- fld1/z/pi/...
загрузка констант
- fincstp
- fdecstp
двигаем указатель стека, не меняя состояние регистров (пустой/полный)
- ffree
освободить регистр
- fnop
поделать ничего. Теперь и на fpu.