| go back

# Introduction to Floating Point Programming This article will give a general overview of the Intel Architcture Floating Point Unit (FPU). It will describe the various data types used byt the FPU, and will also cover the FPU's internal architecture, including all of the internal registers. ## FPU Data Formats The FPU uses 3 different types of data: signed integer, BCD, and floating point. The following table shows the various data types used by the FPU, along with their size and approximate range.
Type | Length | Range
Word Integer | 16 bit | -32768 to 32768
Short Integer | 32 bit | -2.14e9 to 2.14e9
Long Integer | 64 bit | -9.22e18 to 9.22e18
Single Real | 32 bit | 1.18e-38 to 3.40e38
Double Real | 64 bit | 2.23e-308 to 1.79e308
Extended Real | 80 bit | 3.37e-1932 to 1.18e4932
Packed BCD | 80 bit | -1e18 to 1e18
The following sections will describe each of these data types: including how they are internally represented and how they can be defined. ### Signed Integers Positive signed integers are stored in normal format, with the left-most sign bit set to 0. Negative numbers are stored in 2's-complement form, with the left-most sign bit equal to 1. Following shows how to define the various integer types, and what their binary representations are:
      0024                  var1   dw        24
      FFFE                  var2   dw        -2
      000004D2              var3   dd        1234
      FFFFFF85              var4   dd        -123
      0000000000002694      var5   dq        9876
      FFFFFFFFFFFFFEBF      var6   dq        -321
### BCD (Binary Coded Decimal) BCD numbers are 10-bytes in size. Each number is stored as 18 digits, with 2 digits per byte. The highest order byte stores the sign of the number, with the highest order bit of this byte being the sign bit. Note that both positive and negative numbers are stored in true form, and not in complemented form. The DT directive can be used to define a BCD number. Following is an example of some BCD numbers, and their hex representations:
      00000000000000012345         var1   dt    12345
      80000000000000000100         var2   dt    -100
### Floating Point Numbers A floating point (or real) number has three parts: a sign bit, a biased exponent, and a significand. They are written using binary scientific notation. There are three types of floating point numbers: short (32-bit), long (64-bit), and extended (80-bit). The following diagram shows the format of the different types of numbers: Floating point data types can be defined using DD or REAL4 for short, DQ or REAL8 for long, and DT or REAL10 for extended precision floating point numbers. The following table show examples of defining various floating point numbers, and the hex representation of them:
      C377999A                     var1   dd      -247.6
      40000000                     var2   dd      2.0
      486F4200                     var3   real4   2.45E+5
      4059100000000000             var4   dq      100.25
      3F543BF727136A40             var5   real8   0.00123

      C377999A                     var1   dd      -247.6
      40000000                     var2   dd      2.0
      486F4200                     var3   real4   2.45E+5
      4059100000000000             var4   dq      100.25
      3F543BF727136A40             var5   real8   0.001235
      400487F34D6A161E4F76         var6   real10  33.9876
## FPU Data Registers The FPU is divided into 2 main sections: the control unit and the numeric execution unit. The control unit interfaces FPU to the main microprocessor. The numeric execution unit is responsible for executing the actual floating point instructions. ### Stack Registers All operands for floating point instructions, as well as all of the results are stored in an internal 8 register stack. Instructions either directly address a specific stack data register or use a push and pop to work off of the top of the stack. Typically, ST(0) refers to the top of the stack. When data is pushed onto the stack, the new data is stored in ST(0), while the rest of the stack is pushed down by one. Similarly, when an item is popped from the stack, it is taken from ST(0), and the rest of the stack items are moved up. (Note that ST(0) need not always refer to the top of the stack. For these examples we will asume it does). The following diagram illustrates how this works: The stack contains eight 80-bit registers. These always contain 80-bit extended precision floating point numbers. The FPU automatically converts signed integers, BCD, single precision, or double precision numbers to extended form as data is moved between memory and the FPU stack. ### Status Register The status register reflects the overall status of the FPU. The following diagram shows the format of the status regster.
B | Busy Bit: indicates that the fpu is busy executing a task. newer coprocessors are automatically synchrnoized with the cpu, so use of this flag is not normally not neeed.
C3-C0 | Condition Code Bits: indicate contitions about the coprocessor. these bits have varying meanings, dependng on the instruction.
ST | Top of Stack: indicates the current register addressed as the top of stack. normally, this is register 0.
ES | Error Summary: set if any error bit (pe, ue, oe, ze, de, or ie) is set.
PE | Precision Error: indicates that the result or operands exceed the current precision (set in control register).
UE | Underflow Error: indicates the result is too small to represent with the current precision (set in control register)
OE | Overflow Error: indicates result is too large to be represented by the current precision (set in control register).
ZE | Zero Error: indicates divisor was 0, while the dividend is non-infinite or non-zero.
DE | Denormalized Error: indicates at least one of the operands is denormalized.
IE | Invalid Error: indicates stack overflow or underflow, indeterminate form, or use of nan as an operand.
The status register can be accessed using the FSTSW instruction, which copies the register into a word of memory. FSTSW AX can be used to copy the status register into register ax. From there, the contents of the register can be tested. One method of testing these bits is with the TEST instruction. Another method uses SAHF to store the status register conte The status register can be accessed using the FSTSW instruction, which copies the register into a word of memory. FSTSW AX can be used to copy the status register into register ax. From there, the contents of the register can be tested. One method of testing these bits is with the TEST instruction. Another method uses SAHF to store the status register contents in the flags register. SAHF puts C0 into the carry flag, C2 into the parity flag, and C3 into the zero flag. The following table describes the meanings of the condition code bits for the instructions FTST, FCOM, FPREM, and FXAM.
Instruction | C3 | C2 | C1 | C0 | Meaning
FTST, FCOM | 0 | 0 | X | 0 | ST > Operand
| 0 | 0 | X | 1 | ST < Operand
| 1 | 0 | X | 1 | ST = Operand
| 1 | 1 | X | 1 | ST is not comparable
FPREM | Q1 | 0 | Q0 | Q2 | Rightmost 3 bits of quotient
| ? | 1 | ? | ? | Incomplete
FXAM | 0 | 0 | 0 | 0 | + unnormal
| 0 | 0 | 0 | 1 | + NAN
| 0 | 0 | 1 | 0 | - unnormal
| 0 | 0 | 1 | 1 | - NAN
| 0 | 1 | 0 | 0 | + normal
| 0 | 1 | 0 | 1 | + infinity
| 0 | 1 | 1 | 0 | - normal
| 0 | 1 | 1 | 0 | - normal
| 0 | 1 | 1 | 1 | - infinity
| 1 | 0 | 0 | 0 | + 0
| 1 | 0 | 0 | 1 | Empty
| 1 | 0 | 1 | 0 | - 0
| 1 | 1 | 0 | 0 | + denormal
| 1 | 1 | 0 | 1 | Empty
| 1 | 1 | 1 | 0 | - denormal
| 1 | 1 | 1 | 1 | Empty
Unnormal: Leading bits of the significand are zero. Denormal: Exponent is at its most negative value. Normal: Standard floating point form. NAN: (Not-a-Number) An exponent of all ones and a significand not equal to zero. ### Control Register The control register is used to select the precision, rounding, and infinity control. It is also used to mask the 6 error bits of the status register. The following diagram shows the control register:
IC | Infinity Control: Selects Projective or Affine infinity. Affine infinity allows positive and negative infinity, while projective assumes unsigned infinity. 0 = Projective 1 = Affine
RC | Rounding Control: Determines the type of rounding: 00 = Round to nearest or even 01 = Round down towards minus infinity 10 = Round up towards positive infinity 11 = Truncate towards zero
PC | Precision Control: Sets the precision of the result: 00 = Single Precision (short) 01 = Reserved 10 = Double Precision (long) 11 = Extended Precision
PM | Precision Error Mask: Determines whether a precision error is indicated in the status registers PE bit. A 1 masks the error.
UM | Underflow Error Mask Determines whether a underflow error is indicated in the status registers UE bit. A 1 masks the error.
OM | Overflow Error Mask: Determines whether a overflow error is indicated in the status registers OE bit. A 1 masks the error.
ZM | Zero Error Mask: Determines whether a zero error is indicated in the status registers ZE bit. A 1 masks the error.
DM | Denormalized Error Mask: Determines whether a denormalized error is indicated in the status registers DE bit. A 1 masks the error.
IM | Invalid Error Mask: Determines whether an invalid operation error is indicated in the status registers IE bit. A 1 masks the error.
### Tag Register The tag register is used to indicate the contents of each register of the FPU stack. The tag indicates whether the register is valid, zero, infinity/invalid, or empty. The tag register is as follows: Tag Register Values: 00 = Valid 01 = Zero 10 = Invalid or Infinity 11 = Empty The only way to view the tag regster is by storing the FPU environment using either the FSTENV, FSAVE, or FRSTOR instructions. These instructions store the tag register along with the other FPU data. ## Conclusion This article should have provided a good introduction the the internal registers of the FPU. It should also have described the data formats used by the FPU. The next article will introduce the FPU's instruction set. April 12, 2001 Copyright (C) 2001 by Bill Tyler (billasm@usa.net)

asmcode@hotmail.com