Для перемещения данных между регистрами и переменными FPU предоставляет ряд инструкций. Инструкция fld загружает в стек FPU 32-, 64- или 80-разрядное число с плавающей точкой. Перед помещением значения в стек эта инструкция преобразует 32- и 64-битные операнды в 80-битное значение повышенной точности. fld сначала уменьшает указатель TOS (Top Of the Stak Pointer - 11-13 биты регистра состояния), а затем сохраняет 80-битное значение в физическом регистре, на который указывает новый указатель TOS. Примеры применения инструкции
fld st(1) fld real4_variable fld real8_variable fld real10_variable fld real8 ptr [rbx]
Если операнд инструкции fld представляет регистр данных с плавающей точкой - ST, то фактическим регистром, который FPU использует для операции загрузки, является номер регистра до уменьшения указателя TOS. Следовательно, fld st(0) дублирует значение на вершине стека.
Инструкция fld
устанавливает бит ошибки стека, если происходит переполнение стека. Она устанавливает бит денормализованного исключения,
если загружается 80-битное денормализованное значение. Она устанавливает бит недопустимой операции при попытке загрузить пустой регистр с плавающей точкой в TOS
(или выполнить другую недопустимую операцию).
Инструкции fst и fstp копируют значение с вершины стека в другой регистр с плавающей точкой или в 32-, 64- или 80-битную переменную
(копирование в 80-битную переменную доступно только для fstp
). При копировании данных в 32- или 64-битную переменную памяти FPU округляет 80-битное значение повышенной точности в TOS до меньшего формата. Принцип округления устанавливается
битами округления в регистре управления FPU.
Инструкция fstp извлекает значение из вершины стека в операнд и увеличивает указатель TOS в регистре состояния. Если операнд представляет регистр с плавающей точкой, FPU сохраняет значение в регистре с указанным номером до непосредственного извлечения данных из вершины стека. Примеры применения инструкции:
fst real4_variable fst real8_variable fst st(2) fstp st(1)
Так, выполнение инструкции fstp st(0)
извлекает данные из вершины стека без передачи данных.
Инструкции fst и fstp установят бит исключения стека, если произойдет опустошение стека (попытка сохранить значение из пустого стека регистров). Они установят бит точности, если во время операции сохранения произойдет потеря точности (например, при сохранении 80-битного значения расширенной точности в 32- или 64-битную переменную памяти, если при преобразовании некоторые биты будут потеряны). Они будут устанавливать бит исключения потери значимости (undeflow) при сохранении 80-битного значения в 32- или 64-битную переменную, если это значение слишком мало, чтобы поместиться в операнд. Точно так же эти инструкции будут устанавливать бит исключения переполнения, если значение на вершине стека слишком велико, чтобы поместиться в 32- или 64-битную переменную. Они устанавливают флаг недопустимой операции, если происходит недопустимая операция (например, запись в пустой регистр). Наконец, эти инструкции устанавливают бит условия C1, если во время операции сохранения происходит округление или если происходит ошибка стека.
Инструкция fxch обменивает значение на вершине стека с одним из других регистров FPU. Эта инструкция имеет две формы:
одна принимает в качестве операнда регистр FPU, а вторая без операндов. Первая форма обменивает вершину стека с указанным регистром. Вторая форма fxch
меняет местами вершину стека с ST(1).
Инструкция fxch устанавливает бит исключения стека, если стек пуст; она устанавливает бит недопустимой операции, если операнд представляет пустой регистр.
Для преобразования из или в целое число FPU предоставляет 6 инструкций: fild, fist, fistp, fisttp, fbld
и fbstp
.
Инструкция fild преобразует 16-, 32- или 64-битное целое число с дополнением до двух в 80-битный формат расширенной точности и помещает результат в стек. Эта инструкция принимает один операнд: адрес целочисленной переменной типа (s)word, (s)dword или (s)qword. Если надо поместить значение регистра общего назначения x86-64 в стек FPU, еэто значение сначала необходимо сохранить в переменной, а затем использовать fild для помещения этой переменной. Инструкция fild устанавливает бит исключения стека и C1, если происходит переполнение стека. Примеры применения:
fild word_variable fild dword_val[rcx * 4] fild qword_variable fild sqword ptr [rbx]
Инструкции fist, fistp и fisttp преобразуют 80-битную переменную повышенной точности на вершине стека в 16-, 32- или (только fistp/fistpp) 64-битное целое число и сохраняют результат в операнде-переменной. Инструкции fist
и fistp
преобразуют значение на вершине стека в целое число в соответствии с настройкой округления в регистре управлентя FPU (биты 10-11). Инструкция fisttp
всегда выполняет преобразование в режиме усечения.
Инструкция fist
преобразует значение на вершине стека в целое число, а затем сохраняет результат. Инструкции fistp
и fisttp
извлекают значение из стека регистров с плавающей точкой после сохранения преобразованного значения.
Эти инструкции устанавливают бит исключения стека, если стек регистров с плавающей точкой пуст. Они устанавливают бит точности и бит C1 при округлении. Эти инструкции также устанавливают бит исключения потери значимости, если результат слишком мал (меньше 1, но больше 0, или меньше 0, но больше –1). Примеры применения:
fist dword_var fisttp dword_var fistp qword_var
Например:
.data float real8 23.65 int32 dword ? .code main proc fld float ; загружаем число float в стек FPU в ST(0) fistp int32 ; Преобразуем чисдо из ST(0) в dword mov eax, int32 ret main endp end
Здесь загружаем число float, а именно 23.65, в регистр ST(0).
fld float
Преобразуем его в 32-разрядное целое число и результат помещаем в переменную int32:
fistp int32
После преобразования в int32 будет число 24, поскольку по умолчанию идет округление в большую сторону. Однако, возможно, мы хотели бы, чтобы при преобразовании просто отбрасывалась
дробная часть. Инструкции fist
и fistp
для преобразования данных используют биты округления из регистра управления. И мы можем установить свои настройки:
.data old_state word ? new_state word ? float real8 23.65 int32 dword ? .code main proc fstcw old_state ; сохраняем старое состояние регистра управления mov ax, old_state ; для изменения состояния загружаем в AX or ax, 0c00h ; устанавливаем 10-11 биты равными 11 (отброс дробной части) mov new_state, ax ; новое состояние помещаем в переменную new_state fldcw new_state ; новое состояние сохраняем в регистр управления fld float ; загружаем число float в стек FPU в ST(0) fistp int32 ; Преобразуем число из ST(0) в dword fldcw old_state ; восставнавливаем старое состояние регистра управления mov eax, int32 ; EAX = 23 ret main endp end
Здесь определяем две дополнительные переменные - для хранения старого состояния регистра управления FPU И для хранения измененного состояния, где изменены биты округления. Сначала загружаем все состояния регистра управления в переменную old_state и для ее изменения помещаем в регистр AX
fstcw old_state ; сохраняем старое состояние регистра управления mov ax, old_state
Если мы хотим отбрасываеть дробную часть, то биты 10-11. Это можно с помощью побитового ИЛИ с маской 0c00h
or ax, 0c00h
Таким образом, в AX будет новое состояние с измененными битами округления, которое сохраняем в регистр управления
fldcw new_state
После этого результат округления будет 23.