fld, fst, fstp, and fxch
. The fld
instructions always pushes its operand onto the floating point stack. The fstp
instruction always pops the top of stack after storing the top of stack (tos) into its operation. The remaining instructions do not affect the number of items on the stack.
fld
instruction loads a 32 bit, 64 bit, or 80 bit floating point value onto the stack. This instruction converts 32 and 64 bit operand to an 80 bit extended precision value before pushing the value onto the floating point stack.fld
instruction first decrements the tos pointer (bits 11-13 of the status register) and then stores the 80 bit value in the physical register specified by the new tos pointer. If the source operand of the fld
instruction is a floating point data register, ST
(i), then the actual register the 80x87 uses for the load operation is the register number before decrementing the tos pointer. Therefore, fld st
or fld st(0)
duplicates the value on the top of the stack.fld
instruction sets the stack fault bit if stack overflow occurs. It sets the the denormalized exception bit if you load an 80 bit denormalized value. It sets the invalid operation bit if you attempt to load an empty floating point register onto the stop of stack (or perform some other invalid operation).fld st(1) fld mem_32 fld MyRealVar fld mem_64[bx]
fst
and fstp
instructions copy the value on the top of the floating point register stack to another floating point register or to a 32, 64, or 80 bit memory variable. When copying data to a 32 or 64 bit memory variable, the 80 bit extended precision value on the top of stack is rounded to the smaller format as specified by the rounding control bits in the FPU control register.fstp
instruction pops the value off the top of stack when moving it to the destination location. It does this by incrementing the top of stack pointer in the status register after accessing the data in st(0)
. If the destination operand is a floating point register, the FPU stores the value at the specified register number before popping the data off the top of the stack.fstp st(0)
instruction effectively pops the data off the top of stack with no data transfer. Examples:fst mem_32 fstp mem_64 fstp mem_64[ebx*8] fst mem_80 fst st(2) fstp st(1)
The last example above effectively pops st(1)
while leaving st(0)
on the top of the stack.
The fst
and fstp
instructions will set the stack exception bit if a stack underflow occurs (attempting to store a value from an empty register stack). They will set the precision bit if there is a loss of precision during the store operation (this will occur, for example, when storing an 80 bit extended precision value into a 32 or 64 bit memory variable and there are some bits lost during conversion). They will set the underflow exception bit when storing an 80 bit value value into a 32 or 64 bit memory variable, but the value is too small to fit into the destination operand. Likewise, these instructions will set the overflow exception bit if the value on the top of stack is too big to fit into a 32 or 64 bit memory variable. The fst
and fstp
instructions set the denormalized flag when you try to store a denormalized value into an 80 bit register or variable[7]. They set the invalid operation flag if an invalid operation (such as storing into an empty register) occurs. Finally, these instructions set the C1
condition bit if rounding occurs during the store operation (this only occurs when storing into a 32 or 64 bit memory variable and you have to round the mantissa to fit into the destination).
fxch
instruction exchanges the value on the top of stack with one of the other FPU registers. This instruction takes two forms: one with a single FPU register as an operand, the second without any operands. The first form exchanges the top of stack with the specified register. The second form of fxch
swaps the top of stack with st(1)
.fsqrt
, operate only on the top of the register stack. If you want to perform such an operation on a value that is not on the top of stack, you can use the fxch
instruction to swap that register with tos, perform the desired operation, and then use the fxch
to swap the tos with the original register. The following example takes the square root of st(2)
:fxch st(2) fsqrt fxch st(2)
The fxch
instruction sets the stack exception bit if the stack is empty. It sets the invalid operation bit if you specify an empty register as the operand. This instruction always clears the C1
condition code bit.
fld
and fst/fstp
instructions are conversion instructions as well as data movement instructions because they automatically convert between the internal 80 bit real format and the 32 and 64 bit memory formats. Nonetheless, we'll simply classify them as data movement operations, rather than conversions, because they are moving real values to and from memory. The 80x87 FPU provides five routines which convert to or from integer or binary coded decimal (BCD) format when moving data. These instructions are fild
, fist
, fistp
, fbld
, and fbstp
.
fild
(integer load) instruction converts a 16, 32, or 64 bit two's complement integer to the 80 bit extended precision format and pushes the result onto the stack. This instruction always expects a single operand. This operand must be the address of a word, double word, or quad word integer variable. Although the instruction format for fild
uses the familiar mod/rm fields, the operand must be a memory variable, even for 16 and 32 bit integers. You cannot specify one of the 80386's 16 or 32 bit general purpose registers. If you want to push an 80x86 general purpose register onto the FPU stack, you must first store it into a memory variable and then use fild
to push that value of that memory variable.fild
instruction sets the stack exception bit and C1
(accordingly) if stack overflow occurs while pushing the converted value. Examples:fild mem_16 fild mem_32[ecx*4] fild mem_64[ebx+ecx*8]
fist
and fistp
instructions convert the 80 bit extended precision variable on the top of stack to a 16, 32, or 64 bit integer and store the result away into the memory variable specified by the single operand. These instructions convert the value on tos to an integer according to the rounding setting in the FPU control register (bits 10 and 11). As for the fild
instruction, the fist
and fistp
instructions will not let you specify one of the 80x86's general purpose 16 or 32 bit registers as the destination operand.fist
instruction converts the value on the top of stack to an integer and then stores the result; it does not otherwise affect the floating point register stack. The fistp
instruction pops the value off the floating point register stack after storing the converted value.C1
bits if rounding occurs (that is, if there is any fractional component to the value in st(0)
). These instructions set the underflow exception bit if the result is too small (i.e., less than one but greater than zero or less than zero but greater than -1). Examples:fist mem_16[bx] fist mem_64 fistp mem_32
Don't forget that these instructions use the rounding control settings to determine how they will convert the floating point data to an integer during the store operation. Be default, the rouding control is usually set to "round" mode; yet most programmers expect fist/fistp
to truncate the decimal portion during conversion. If you want fist/fistp
to truncate floating point values when converting them to an integer, you will need to set the rounding control bits appropriately in the floating point control register.
fbld
and fbstp
instructions load and store 80 bit BCD values. The fbld
instruction converts a BCD value to its 80 bit extended precision equivalent and pushes the result onto the stack. The fbstp
instruction pops the extended precision real value on tos, converts it to an 80 bit BCD value (rounding according to the bits in the floating point control register), and stores the converted result at the address specified by the destination memory operand. Note that there is no fbst
instruction which stores the value on tos without popping it.fbld
instruction sets the stack exception bit and C1
if stack overflow occurs. It sets the invalid operation bit if you attempt to load an invalid BCD value. The fbstp
instruction sets the stack exception bit and clears C1
if stack underflow occurs (the stack is empty). It sets the underflow flag under the same conditions as fist
and fistp
. Examples:; Assuming fewer than eight items on the stack, the following ; code sequence is equivalent to an fbst instruction: fld st(0) ;Duplicate value on TOS. fbstp mem_80 ; The following example easily converts an 80 bit BCD value to ; a 64 bit integer: fbld bcd_80 ;Get BCD value to convert. fist mem_64 ;Store as an integer.
fadd faddp fadd st(i), st(0) fadd st(0), st(i) faddp st(i), st(0) fadd mem
The first two forms are equivalent. They pop the two values on the top of stack, add them, and push their sum back onto the stack.
The next two forms of the fadd
instruction, those with two FPU register operands, behave like the 80x86's add
instruction. They add the value in the second register operand to the value in the first register operand. Note that one of the register operands must be st(0)
[8].
The faddp
instruction with two operands adds st(0)
(which must always be the second operand) to the destination (first) operand and then pops st(0)
. The destination operand must be one of the other FPU registers.
The last form above, fadd
with a memory operand, adds a 32 or 64 bit floating point variable to the value in st(0)
. This instruction will convert the 32 or 64 bit operands to an 80 bit extended precision value before performing the addition. Note that this instruction does not allow an 80 bit memory operand.
These instructions can raise the stack, precision, underflow, overflow, denormalized, and illegal operation exceptions, as appropriate. If a stack fault exception occurs, C1
denotes stack overflow or underflow.
fsub fsubp fsubr fsubrp fsub st(i). st(0) fsub st(0), st(i) fsubp st(i), st(0) fsub mem fsubr st(i). st(0) fsubr st(0), st(i) fsubrp st(i), st(0) fsubr mem
With no operands, the fsub
and fsubp
instructions operate identically. They pop st(0)
and st(1)
from the register stack, compute st(0)-st(1)
, and the push the difference back onto the stack. The fsubr
and fsubrp
instructions (reverse subtraction) operate in an almost identical fashion except they compute st(1)-st(0)
and push that difference.
With two register operands (destination, source ) the fsub
instruction computes destination := destination - source. One of the two registers must be st(0)
. With two registers as operands, the fsubp
also computes destination := destination - source and then it pops st(0)
off the stack after computing the difference. For the fsubp
instruction, the source operand must be st(0)
.
With two register operands, the fsubr
and fsubrp
instruction work in a similar fashion to fsub
and fsubp
, except they compute destination := source - destination.
The fsub mem
and fsubr mem
instructions accept a 32 or 64 bit memory operand. They convert the memory operand to an 80 bit extended precision value and subtract this from st(0)
(fsub
) or subtract st(0)
from this value (fsubr
) and store the result back into st(0)
.
These instructions can raise the stack, precision, underflow, overflow, denormalized, and illegal operation exceptions, as appropriate. If a stack fault exception occurs, C1
denotes stack overflow or underflow.
fmul
and fmulp
instructions multiply two floating point values. These instructions allow the following forms:fmul fmulp fmul st(0), st(i) fmul st(i), st(0) fmul mem fmulp st(i), st(0)
With no operands, fmul
and fmulp
both do the same thing - they pop st(0)
and st(1)
, multiply these values, and push their product back onto the stack. The fmul
instructions with two register operands compute destination := destination * source. One of the registers (source or destination) must be st(0)
.
The fmulp st(i), st(0)
instruction computes st(i) := st(i) * st(0)
and then pops st(0)
. This instruction uses the value for i before popping st(0)
. The fmul mem
instruction requires a 32 or 64 bit memory operand. It converts the specified memory variable to an 80 bit extended precision value and the multiplies st(0)
by this value.
These instructions can raise the stack, precision, underflow, overflow, denormalized, and illegal operation exceptions, as appropriate. If rounding occurs during the computation, these instructions set the C1
condition code bit. If a stack fault exception occurs, C1
denotes stack overflow or underflow.
fdiv fdivp fdivr fdivrp fdiv st(0), st(i) fdiv st(i), st(0) fdivp st(i), st(0) fdivr st(0), st(i) fdivr st(i), st(0) fdivrp st(i), st(0) fdiv mem fdivr mem
With zero operands, the fdiv
and fdivp
instructions pop st(0)
and st(1)
, compute st(0)/st(1)
, and push the result back onto the stack. The fdivr
and fdivrp
instructions also pop st(0)
and st(1)
but compute st(1)/st(0)
before pushing the quotient onto the stack.
With two register operands, these instructions compute the following quotients:
fdiv st(0), st(i) ;st(0) := st(0)/st(i) fdiv st(i), st(0) ;st(i) := st(i)/st(0) fdivp st(i), st(0) ;st(i) := st(i)/st(0) fdivr st(i), st(i) ;st(0) := st(0)/st(i) fdivrp st(i), st(0) ;st(i) := st(0)/st(i)
The fdivp
and fdivrp
instructions also pop st(0)
after performing the division operation. The value for i in this two instructions is computed before popping st(0)
.
These instructions can raise the stack, precision, underflow, overflow, denormalized, zero divide, and illegal operation exceptions, as appropriate. If rounding occurs during the computation, these instructions set the C1
condition code bit. If a stack fault exception occurs, C1
denotes stack overflow or underflow.
fsqrt
routine does not allow any operands. It computes the square root of the value on tos and replaces st(0)
with this result. The value on tos must be zero or positive, otherwise fsqrt
will generate an invalid operation exception.fsqrt
sets the C1
condition code bit. If a stack fault exception occurs, C1
denotes stack overflow or underflow.; Compute Z := sqrt(x**2 + y**2); fld x ;Load X. fld st(0) ;Duplicate X on TOS. fmul ;Compute X**2. fld y ;Load Y. fld st(0) ;Duplicate Y on TOS. fmul ;Compute Y**2. fadd ;Compute X**2 + Y**2. fsqrt ;Compute sqrt(x**2 + y**2). fst Z ;Store away result in Z.
fscale
instruction pops two values off the stack. It multiplies st(0)
by 2st(1)
and pushes the result back onto the stack. If the value in st(1)
is not an integer, fscale
truncates it towards zero before performing the operation. C1
since stack underflow occurs). It raises the precision exception if there is a loss of precision due to this operation (this occurs when st(1)
contains a large, negative, value). Likewise, this instruction sets the underflow or overflow exception bits if you multiply st(0)
by a very large positive or negative power of two. If the result of the multiplication is very small, fscale
could set the denormalized bit. Also, this instruction could set the invalid operation bit if you attempt to fscale
illegal values. Fscale
sets C1
if rounding occurs in an otherwise correct computation. Example:fild Sixteen ;Push sixteen onto the stack. fld x ;Compute x * (2**16). fscale . . . Sixteen word 16
fprem
and fprem1
instructions compute a partial remainder. Intel designed the fprem
instruction before the IEEE finalized their floating point standard. In the final draft of the IEEE floating point standard, the definition of fprem
was a little different than Intel's original design. Unfortunately, Intel needed to maintain compatibility with the existing software that used the fprem
instruction, so they designed a new version to handle the IEEE partial remainder operation, fprem1
. You should always use fprem1
in new software you write, therefore we will only discuss fprem1
here, although you use fprem
in an identical fashion.Fprem1
computes the partial remainder of st(0)/st(1)
. If the difference between the exponents of st(0)
and st(1)
is less than 64, fprem1 can compute the exact remainder in one operation. Otherwise you will have to execute the fprem1
two or more times to get the correct remainder value. The C2
condition code bit determines when the computation is complete. Note that fprem1
does not pop the two operands off the stack; it leaves the partial remainder in st(0)
and the original divisor in st(1)
in case you need to compute another partial product to complete the result.fprem1
instruction sets the stack exception flag if there aren't two values on the top of stack. It sets the underflow and denormal exception bits if the result is too small. It sets the invalid operation bit if the values on tos are inappropriate for this operation. It sets the C2
condition code bit if the partial remainder operation is not complete. Finally, it loads C3
, C1
, and C0
with bits zero, one, and two of the quotient, respectively.; Compute Z := X mod Y fld y fld x PartialLp: fprem1 fstsw ax ;Get condition bits in AX. test ah, 100b ;See if C2 is set. jnz PartialLp ;Repeat if not done yet. fstp Z ;Store remainder away. fstp st(0) ;Pop old y value.
fxtract
instruction is the complement to the fscale
instruction. It pops the value off the top of the stack and pushes a value which is the integer equivalent of the exponent (in 80 bit real form), and then pushes the mantissa with an exponent of zero (3fffh in biased form).C1
determines whether stack overflow or underflow occurs). If the original top of stack was zero, fxtract sets the zero division exception flag. The denormalized flag is set if the result warrants it; and the invalid operation flag is set if there are illegal input values when you execute fxtract
.; The following example extracts the binary exponent of X and ; stores this into the 16 bit integer variable Xponent. fld x fxtract fstp st(0) fistp Xponent
Fabs
computes the absolute value of st(0)
by clearing the sign bit of st(0)
. It sets the stack exception bit and invalid operation bits if the stack is empty.; Compute X := sqrt(abs(x)); fld x fabs fsqrt fstp x
; Compute X := -X if X is positive, X := X if X is negative. fld x fabs fchs fstp x
st(0)
quite a bit when programming the 80x87, MASM allows you to use the abbreviation st
for st(0)
. However, this text will explicitly state st(0)
so there will be no confusion.