Загрузка данных и преобразование чисел в FPU

Последнее обновление: 02.07.2023

Для перемещения данных между регистрами и переменными 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.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850