FPU, числа с плавающей точкой

Регистры FPU

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

Для работы с плавающей точкой в архитектуре x86-64 имеются регистры FPU (Floating Point Unit). В общей сложности это 14 регистров:

  • 8 регистров данных (data register), которые аналогичны регистрам общего назначения x86-64, поскольку все вычисления с плавающей точкой происходят в этих регистрах.

  • Регистр управления (control register) позволяет пользователю выбрать один из нескольких возможных режимов работы FPU

  • Регистр состояния (status register) аналогичен регистру FLAGS в x86-64; он содержит биты кода состояния и несколько других флагов, которые описывают состояние FPU.

  • Регистр тега (tag register) содержит несколько групп битов, которые определяют состояние значения в каждом из восьми регистров данных.

  • Регистр инструкции (Instruction Pointer)

  • Регистр указателя данных (Data Pointer)

  • Регистр кода операции (opcode register)

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

FPU предоставляет восемь 80-битных регистров данных, организованных в виде стека, что значительно отличается от организации регистров общего назначения в x86-64. MASM называет эти регистры ST(0), ST(1), ... SТ(7).

Регистры FPU в ассемблере x86-64

ST(0) располагается на вершине стека, ST(1) идет ниже в стеке и так далее. Многие инструкции с плавающей точкой помещают и извлекают элементы из стека. Поэтому ST(1) будет хранить ссылку на ранее добаленные данные по отношению к регистру ST(0).

Регистр управления

Регистр управления FPU, который позволяет пользователю выбрать один из нескольких возможных режимов работы FPU.

Регистр управления FPU в ассемблере x86-64

10 и 11 биты регистра управляют округлением. По умолчанию эти биты равны 00 (то есть оба бита равны 0). Если они равны 00, то FPU округляет до ближайшего значения - если число выше пяти - в сторону повышения, если меньше 5 - в сторону понижения. Если значение битов - 01, округление идет в сторону понижения, если 10 - в сторону повышения. При значении 11, число усекается (обычно применяется для преобразования числа с плавающей точкой в целое число).

Биты 8 и 9 регистра определяют точность при вычислении.

8-9 биты

Точность

00

24 бита

01

Зарезервировано

10

53 бита

11

64 бита

Как правило, процессор по умолчанию устанавливает эти биты равными 11, чтобы выбрать 64-битную точность мантиссы. Но некоторые процессоры могут работать быстрее со значениями с плавающей точкой, точность которых составляет 53 бита (то есть 64-битный формат с плавающей точкой), а не 64 бита (то есть 80-битный формат с плавающей точкой).

Биты с 0 по 5 являются масками исключений. Они аналогичны биту разрешения прерывания в регистре FLAGS x86-64. Если эти биты содержат 1, соответствующее условие игнорируется FPU. Однако если какой-либо бит содержит 0 и возникает соответствующее условие, то FPU немедленно генерирует прерывание для последующей обработки программой.

Бит 0 соответствует недопустимой операции, которая обычно возникает в результате ошибки при программирования. Это может быть помещение в стек более восьми элементов или попытку извлечения элемента из пустого стека, извлечение квадратного корня из отрицательного числа или загрузку непустого регистра.

Бит 1 маскирует денормализованное прерывание, которое возникает, когда в FPU загружаются произвольные значения расширенной точности или при работе с очень маленькими числами, выходящими за пределы возможностей FPU.

Бит 2 маскирует исключение деления на ноль. Если этот бит содержит 0, FPU сгенерирует прерывание, если вы попытаетесь разделить ненулевое значение на 0. Если не включить исключение деления на ноль, FPU будет выдавать NaN (Not a Number) при делении на ноль.

Бит 3 маскирует исключение переполнения. FPU вызовет это исключение переполнения, если при вычислении возникнет переполнение или при сохранении значения, которое слишком велико, чтобы поместиться в целевой операнд (например, сохранение большого значения расширенной точности в переменной одинарной точности).

Бит 4, если он установлен, маскирует исключение отрицательного переполнения или потери значимости (underflow). Это исключение происходит, когда результат слишком мал, чтобы поместиться в операнд назначения. Подобно переполнению, это исключение может возникать при сохранении небольшого значения расширенной точности в переменную одинарной или двойной точности или когда результат вычисления слишком мал для расширенной точности.

Бит 5 определяет, может ли произойти исключение точности. Исключение точности возникает, когда FPU выдает неточный результат, как правило, результат внутренней операции округления. Например, деление 1 на 10 даст неточный результат. Таким образом, этот бит обычно равен 1, поскольку неточные результаты являются обычным явлением.

Биты 6-7 и 12-15 в настоящее время не определены и зарезервированы для использования в будущем.

Для загрузки содержимого регистра FPU предоставляет инструкцию fldcw, а для сохранения регистра - инструкцию fstcw. Эти инструкции принимают один операнд - 16-битный адрес памяти. Инструкция fldcw загружает данные из указанного адреса памяти в регистр, а fstcw сохраняет данные регистра по указанному адресу. Пример сохранения-восстановления данных:

.data
    controlReg word ?   ; переменная для хранения данных регистра
.code
main proc
    xor eax, eax
    fstcw controlReg    ; сохраняем данные в controlReg
    mov ax, controlReg  ; помещаем в регистр AX
    and ax, 0f0ffh      ; Сбрасываем биты 8-11
    or ax, 0c00h        ; устанавливаем 11-10, 9-8 биты - округление = 11, точность = 00
    mov controlReg, ax  ; из AX в controlReg
    fldcw controlReg    ; загружаем в регистр данные из controlReg
    ret
main endp
end

Здесь сохраняем данные регистра в переменную controlReg, а из нее в регистр AX. С помощью операции AND сбрасываем 8-11 биты (биты округления и точности). Далее с помощью операции OR устанавливаем эти биты. В конце данные из регистра AX загружаем в переменную, а из нее - в регистр управления FPU. В итоге регистр будет иметь следующее значение: 0000110001111111.

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

16-битный регистр состояния предоставляет данные о состоянии FPU.

Регистр состояния в FPU в ассемблере x86-64

Биты 0-5 являются флагами исключений. Эти биты появляются в том же порядке, что и маски исключений в регистре управления. Если соответствующее условие существует, бит устанавливается. Эти биты не зависят от масок исключений в регистре управления. FPU устанавливает и сбрасывает эти биты независимо от соответствующей настройки маски.

Бит 6 указывает на ошибку стека. Ошибка стека возникает, когда происходит переполнение стека или потеря значимости (underflow). Когда этот бит установлен, бит кода состояния C1 определяет, имело ли место состояние переполнения стека (C1 = 1) или потеря значимости (C1 = 0).

Бит 7 устанавливается, если установлен какой-либо бит состояния ошибки. Это результат операции OR битов от 0 до 5. Программа может проверить этот бит, чтобы быстро определить, существует ли состояние ошибки.

Биты 8, 9, 10 и 14 являются битами кода состояния..

Биты с 11-13 предоставляют номер регистра вершины стека. Во время вычислений FPU добавляет номера логических регистров, предоставленные программистом, к этим 3 битам, чтобы определить номер физического регистра во время выполнения.

Бит 15 регистра состояния является битом занятости. Он устанавливается, когда FPU занят.

Для чтения данных регистра состояния в переменную типа word применяется инструкция fstsw.

Типы данных FPU

FPU поддерживает 7 типов данных: 3 целочисленных типа, упакованный десятичный тип (packed decimal type) и три типа с плавающей точкой. Целочисленные типы представлены 16-, 32- и 64-разрядными целыми числами. Упакованный десятичный тип предоставляет 18-разрядное десятичное число со знаком (BCD). Основной целью формата BCD является преобразование между строками и значениями с плавающей точкой. Остальные три типа данных — это 32-, 64- и 80-битные числа с плавающей точкой.

Обычно FPU хранит значения в нормализованном формате. Старший бит мантиссы всегда равен 1 при нормализации числа с плавающей точкой. В 32- и 64-битных форматах с плавающей точкой FPU фактически не хранит этот бит; FPU всегда предполагает, что это 1. Поэтому 32- и 64-битные числа с плавающей точкой всегда нормализованы. Нормализованные значения обеспечивают наибольшую точность. Однако многие ненормализованные значения не могут быть представлены в 80-битном формате. Эти значения очень близки к 0 и представляют набор значений, у которых старший бит мантиссы не равен 0. FPU поддерживают специальную 80-битную форму, известную как денормализованные значения. Денормализованные значения позволяют FPU кодировать очень маленькие значения, которые нельзя кодировать с помощью нормализованных значений, но денормализованные значения обеспечивают меньшую точность битов, чем нормализованные значения. Поэтому использование денормализованных значений в вычислениях может привести к некоторой неточности. Поэтому при работе с очень маленькими значениями можно потерять некоторую точность в вычислениях. Один из битов регистра состояния FPU позволяет узнать, когда FPU использует денормализованное значение в вычислениях.

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