0% found this document useful (0 votes)
57 views24 pages

Chapter 6 - Using Floating-Poin

This document provides an overview of how to work with floating-point numbers in MASM. It discusses declaring floating-point variables and constants using directives like REAL4 and REAL8. It explains how numbers are stored in IEEE floating-point format with the sign, exponent, and significand fields. It also covers using a math coprocessor or emulation routines to perform floating-point operations, describing the coprocessor's register architecture and instruction set.

Uploaded by

Gyula Solymosi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as RTF, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
57 views24 pages

Chapter 6 - Using Floating-Poin

This document provides an overview of how to work with floating-point numbers in MASM. It discusses declaring floating-point variables and constants using directives like REAL4 and REAL8. It explains how numbers are stored in IEEE floating-point format with the sign, exponent, and significand fields. It also covers using a math coprocessor or emulation routines to perform floating-point operations, describing the coprocessor's register architecture and instruction set.

Uploaded by

Gyula Solymosi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as RTF, PDF, TXT or read online on Scribd
You are on page 1/ 24

Using Floating-Point Numbers Top Previous Next

CHAPTER 6

Using Floating-Point and Binary Coded


Decimal
Numbers
MASM requires different techniques for handling floating-point (r eal) numbe rs and binary code d decimal (BCD)
numbers tha n for handling integers. You have two choices for working with real numbers — a math c
oprocessor
or emulation routines.

Math c oprocessors — the 8087, 80287, and 80387 chips — work with the ma in processor to handle re
al-number
calculations. The 80486 processor perfor ms floating-point operations direc tly. All information in
this c hapte
pertaining to rthe 80387 coproc essor applies to the 80486DX processor as we ll. It does not apply to the
80486SX,
which does not provide an on-chip coprocessor.

This chapter begins with a summary of the directives a nd forma ts of floating-point da ta that you need to
allocate
memory storage and initialize variables before you can work with floating-point numbers.

The chapter then explains how to use a math coprocessor for floating-point operations. It covers:

The a rchitecture of the registers.


The operands for the coprocessor instruction formats.
The c oordination of coprocessor and main processor memory access.
The basic groups of coproc essor instructions — for loading and storing data, doing arithmetic ca
controlling
lculations, andprogram flow.

The next ma in se ction de sc ribe s e mulation libra rie s. The emulation routines provided with all M icrosoft high-
level
la nguages enable you to use coprocessor instructions as though your c omputer had a math coprocessor.
However,
some coprocessor instructions a re not handled by emulation, as this section explains.

Finally, be cause math coproc essor and emulation routines can also operate on BCD numbers,
this chapte
includes r
the instruction set for these numbers.
Before using floating-point da ta in your pr ogram, you need to alloc ate the memor y stora ge for the
data. You canva ria bles either as real numbers in decimal form or as encoded hexadecima ls. The a ssembler
then initialize
store s
allocated da ta in 10- byte IEEE format. This section covers floa ting-point declarations and
floating-point
formats. data

Declaring Floating-Point Variables and Constants


You can a lloca te real c onsta nts using the REAL4, REAL8, a nd REAL10 dire ctives. These direc tives allocate
the
following floating-point numbers:

Directive Size

REAL4 Short (32-bit) real numbers


REAL8 Long (64-bit) real numbe rs
REAL10 10-byte (80-bit) real numbers and BCD numbers

Table 6.1 lists the possible ranges for floating-point va ria bles. T he numbe r of significant digits
can va ry operation
arithmetic in an a s the lea st-significant digit may be lost through rounding errors. This occ urs
regularly
short and forlong re al numbers, so you should assume the lesser va lue of significant digits shown in Table
6.1. Te n-
byte real numbers are much less susce ptible to rounding errors for reasons described in the next section. However,
under certain circumstances, 10-byte real operations can have a precision of only 18 digits.

Table 6.1 Ranges of Floating-Point Variables

Data Type Bits Significant Approximate Range


Digits

Short real 32 6–7 1.18 x 10-38 to 3.40 x 103 8

Long re al 64 15–16 2.23 x 10-30 8 to 1.79 x 103 08

10-byte real 80 19 3.37 x 10-49 32 to 1.18 x 1049 32

With versions of MASM prior to 6.0, the DD, DQ, and DT directives could alloca te real constants.
MASM 6.1
still supports these direc tives, but the varia bles are intege rs rather than floating-point values. Although this
makes
no difference in the assembly code, CodeView displays the values incorrectly.

You can specify floating-point c onsta nts either a s decimal constants or as e ncode d hexadecimal consta
nts. You decimal real-number constants in the form:
can express

[[+ | –]] integer[[fraction]][[E[[+ | –]]exponent]]

For example, the num bers 2.523E 1 and -3.6E-2 are written in the correc t decimal format. You
cnumbers
an useas initializers
the se for real-number variables.

The assembler always eva luates digits of real numbe rs a s base 10. It conve rts rea l-number c
onstants give n toin a binary format. The sign, exponent, and de cimal part of the re al number ar e
decimal format
enc oded
fields asthe
within bit number.

You can also specify the encoded format directly with hexade cimal digits (0–9 plus A–F). T he number must
begin
with a decimal digit (0–9) a nd end with the real- numbe r designa tor (R). It ca nnot be signed.
For example,
hexadecimal the 3F800000r can serve as an initializer for a doubleword-sized variable.
number

The maximum range of expone nt value s and the numbe r of digits required in the hexa decimal number de
pend on
the directive . The number of digits for encoded numbers used with REAL4, REAL8, and REAL10
must be 8,
16, a nd 20 digits, respectively. If the number has a leading zero, the number must be 9, 17, or 21 digits.
Examples of decimal constant and hexadecimal specifications are shown here:

; Real numbers
short REAL4 25.23 ; IEEE format
double REAL8 2.523E1 ; IEEE format
tenbyte REAL10 2523.0E-2 ; 10-byte real format

; Encoded as hexadecimals
ieeeshort REAL4 3F800000r ; 1.0 as IEEE short
ieeedouble REAL8 3FF0000000000000r ; 1.0 as IEEE long
temporary REAL10 3FFF8000000000000000r ; 1.0 as 10-byte

; real
The section “Storing Numbers in Floating-Point Forma t,” following, explains the IEEE formats —
the way r actually
assemble the stores the data.

Pa scal or C progra mmer s may prefe r to cre ate language-specific TYPEDEF declarations, as
illustrated
example: in this

; C-language specific
floa t TYPEDEF REAL4
double TYPEDEF REAL8
long_double TYPEDEF REAL10
; Pa scal-language specific
SINGLE TYPEDEF REAL4
DOUBLE TYPEDEF REAL8
EXTENDED TYPEDEF REAL10

For applications of TYPEDEF, see “Defining Pointer Types with TYPEDEF,” page 75.

Storing Numbers in Floating-Point Format


The a ssemble r stores floating-point variable s in the IEEE format. MASM 6.1 doe s not
support .MSFLOAT
Microsoft binary format, whic h are ava ilable in version 5.1 and ea rlie r. Figure 6.1 illustr ate s the IEEE
format for
encoding short (4-byte), long (8-byte), and 10-byte real numbers. Although this figure places the most
significant
bit first for illustration, low bytes actually appear first in memory.
Figure 6.1 Encoding for Real Numbers in IEEE Format

The following list expla ins how the parts of a real number are stored in the IEE E format. Ea
ch
refersitem
to aninitem
thein Figure
list 6.1.
Sign bit (0 for positive or 1 for negative) in the upper bit of the first byte.
Exponent in the ne xt bits in sequence (8 bits for a short real number , 11 bits for a long real number,
for
a nda 15
10-byte
bits real number).
The integer part of the significand in bit 63 for the 10-byte real format. By absorbing carry va lues,
10-byte real ope ra tions to pre serve prec ision to 19 digits. The integer part is alwa ys 1 in
this bit allows
short andconsequently,
numbers; long real these formats do not provide a bit for the integer, since there is no point in storing it.
Decimal part of the significand in the r emaining bits. The length is 23 bits for short real numbers, 52 bits for
real numbers, and 63 bits for 10-byte re al numbers.
long

The e xponent fie ld re prese nts a multiplier 2n. T o ac commodate nega tive exponents (such a s 2-6), the value in
the
exponent fie ld is biased; tha t is, the a ctual e xponent is determined by subtracting the appr opriate bia s value
from
the value in the expone nt field. For e xample, the bias for short real numbers is 127. If the va lue in
the exponent
field is 130, the exponent represents a value of 2130-127, or 23. The bias for long real numbe rs is
1,023. The bias
for 10-byte real numbers is 16,383.

Once you have dec lared floating-point data for your program, you can use coprocessor or emulator instruc tions to
acce ss the data . The next section foc use s on the c oprocessor architecture, instructions, and ope rands require
dfloa
forting-point operations.

Using a Math Coprocessor


When used with real numbers, packed BCD numbers, or long integers, coprocessors (the 8087,
80287, 80387,c alculate m any times faste r than the 8086-ba sed processors. The coproce ssor ha ndles
and 80486)
data with its The organization of these registers c an be one of the four formats for using operands
own registers.
explained in and Operand Formats,” later in this section.
“Instruction

This se ction de scribe s how the coproc essor transfe rs data to and from the coproc essor, coordinates proc essor
and
coprocessor operations, and controls program flow.

Coprocessor Architecture
The coprocessor accesses memory as the CPU does, but it has its own da ta and control
registers
registers — eight
orga nizeddata
as a stack and seve n control registers similar to the 8086 flag re giste rs. The
cinstruction
oproc essor’s
set provides direct access to these registers.

The eight 80-bit data registers of the 8087-base d coproce ssors are organize d as a sta ck, although they need
not
usedbe as a stack. As data items are pushed into the top re giste r, previous data items move into
higher-numbered
registers, which a re lower on the stack. Register 0 is the top of the sta ck; register 7 is the bottom. The
synta x forregiste rs is:
specifying

ST [[(number)]]

The number must be a digit between 0 and 7 or a constant expression that eva luates to a number from 0 to 7.
is another way to refer to ST(0).

All c oprocessor data is store d in registers in the 10-byte real format. The registers and the
register format ar e
shown in Figure 6.2.

Figure 6.2 Coprocessor Data Registers

Inte rnally, all ca lculations are done on numbers of the same type. Since 10-byte re al numbers
have the grea
precision, test
lower-precision numbers are guarante ed not to lose prec ision a s a r esult of ca
lculations. The
instructions that transfer value s between the main me mory and the c oprocessor automatica lly convert
numbers
and from to
the 10-byte real format.

Instruction and Operand Formats


Because of the stac k organization of r egisters, you ca n consider registers either as ele ments on
aregisters
stac k mor
uchas like 8086- family r egisters. Table 6.2 lists the four main groups of coproc essor instruc tions a
nd the
general syntax for each. The name s given to the instruction forma t reflect the wa y the
instruc tion registers.
coprocessor uses theThe instruction operands are plac ed in the c oprocessor data re giste rs before the instr
uction
executes.
Table 6.2 Coprocessor Operand Formats

Instruction Syntax Implied Example


Format Oper ands

Classical stac k Finstruction ST, ST(1) fadd


Memory Finstruction memory ST fadd memloc
Register Finstruction ST(num), ST — fadd st(5), st fadd st, st(3)
Finstruction ST, ST(num)
Register pop FinstructionP ST(num), ST — faddp st(4), st

You can easily recognize coprocessor instr uctions because, unlike all 8086-fa mily instruction
mnemonics,
start with the they
letter F. Coproc essor instruc tions can ne ver have immediate operands a nd, with the
exception of the
FSTSW instruction, the y ca nnot have processor registers as ope rands.

Classical-Stack Format
Instructions in the cla ssical-stack format treat the c oprocessor re gisters like items on a sta ck —
thus
Items itsarename .
pushed onto or poppe d off the top e le ments of the stack. Since only the top ite m can be a
ccessed on sta
traditional a ck, there is no need to spe cify operands. The first (top) register (and the sec ond, if
the
needsinstruction
two operands) is always assumed.

ST (the top of the stack) is the source ope ra nd in coproc essor arithmetic operations. ST(1), the sec ond
register, is tion. The result of the operation replaces the de stina tion operand, and the source is
the destina
popped
stack. Thisoffleaves
the the result at the top of the stack.

The following example illustr ates the classica l-stac k forma t; Figure 6.3 shows the sta tus of the register stack
aeach
fte rinstruction.

fld1 ; Push 1 into first position


fldpi ; Push pi into first position
fadd ; Add pi and 1 and pop

Figure 6.3 Status of the Register Stack

Memory Format
Instructions that use the memory format, such as data transfer instr uctions, also treat c oprocessor
re
itegisters
ms on a like
stack. However, with this for mat, items ar e pushed from memory onto the top ele ment of the
stack,
poppedorfrom the top element to memory. You must specify the memory operand.

Some instructions tha t use the memory format spec ify how a memory ope ra nd is to be interpreted — as an
inte
(I) ger
or as a binary coded decimal (B). The letter I or B follows the initial F in the syntax.
For example,
interpre ts its ope ra nd as an inte ger and FBLD interprets its operand as a BCD numbe r. If the
instruc
does nottion name
include a type letter, the instruction works on real numbers.

You can also use memory operands in calculation instructions tha t operate on two va lues (see “Using Copr
ocessor
Instructions,” later in this section). The memory ope rand is always the source. The stac k top (ST)
is alwaysdestination.
implied the

The result of the operation replaces the de stina tion without changing its sta ck position, as shown in
this example
and in Figure 6.4:

.DATA
m1 REAL4 1.0
m2 REAL4 2.0
.CODE
.
.
.
fld m1 ; Push m1 into first position
fld m2 ; Push m2 into first position
fadd m1 ; Add m2 to first position
fstp m1 ; Pop first position into m1
fst m2 ; Copy first position to m2

Figure 6.4 Status of the Register Stack and Memory Loc ations

Register Format
Instructions tha t use the register format treat coprocessor registers as registers rathe r than as
stack eleme nts.
Instructions that use this forma t require two register operands; one of them must be the stack top (ST).

In the re gister format, spec ify all opera nds by name. The first operand is the de stina tion; its value is replac ed
with
the result of the ope ra tion. The se cond operand is the sour ce ; it is not affecte d by the oper
ation. The
positions stack
of the operands do not change.

The only instructions that use the register operand format a re the FXCH instruction and arithme tic instructions
for
calculations on two values. With the FXCH instruction, the stack top is implied and need not
be spec
shown in ified, as
this example a nd in Figure 6.5:

fadd st(1), st ; Add second position to first -


; result goes in second position
fadd st, st(2) ; Add first position to third -
; result goes in first position
fxch st(1) ; Exchange first and second positions

Figure 6.5 Status of the Previously Initialized Register Stack

Register-Pop Format
The register-pop format tre ats coprocessor registers as a modified stack. The source register must
always
stack top.beSpecify
the the destination with the register’s name.

Instructions with this format plac e the result of the operation into the destination oper and, a nd the top pops off the
stack. The re giste r-pop format is used only for instructions for c alculations on two value s, as in this
example
in Figureand
6.6:

faddp st(2), st ; Add first and third positions and pop -


; first position destroyed;
; third moves to se cond a nd holds result
Figure 6.6 Status of the Already Initialized Register Stack

Coordinating Memory Access


The math coprocessor and ma in proce ssor work simulta neously. Howe ver, since the coprocessor
cannot
device handle
input or output, data originates in the main processor.

The main proce ssor and the c oprocessor have their own r egisters, which are separate and
inaccessible to e ach data through me mory, since memory is ava ilable to both.
other. They exchange

When using the coprocessor, follow these three steps:

1. Load data from memory to coprocessor registers.


2. Proce ss the data.
3. Store the data from coprocessor registers back to memory.

Ste p 2, proce ssing the data , c an occ ur while the main processor is ha ndling othe r tasks. Ste ps 1
and 3 must
coordinated withbethe ma in processor so that the processor and coprocessor do not try to ac cess the sam e
memory
at the same time; othe rwise , problems of coordinating memory acc ess c an occ ur. Since the
processor
coprocessor andwork independently, they may not finish working on memory in the order in which
you give
instructions. The two potential timing conflicts that can occur are handled in different ways.

One timing conflic t results from a copr oce ssor instruction following a processor instruc tion. The
proc
have essor m ay
to wait until the coprocessor finishes if the ne xt processor instruction requires the result of the c oproc
essor’s
calculation. You do not have to write your c ode to avoid this conflict, however . The assembler c
oordinates this
timing a utomatica lly for the 8088 a nd 8086 proce ssors, and the proc essor c oordinates it
automatically on the This is the c ase shown in the first e xample that follows.
80186–80486 processors.

Another conflict results from a pr ocessor instruction that acc esses memor y following a
coprocessor
that accesses instr
the uction
same memory. Theprocessor ca n try to load a variable that is still being used by the c
oprocessor.
You ne ed careful synchronization to control the timing, and this synchroniz ation is not automatic
on the 8087For code to run corre ctly on the 8087, you m ust include WAIT or FWAIT (mne
coprocessor.
monics for the to ensur e that the c oprocessor finishe s before the proc essor begins, a s shown
same instruction)
in the second
example.
In this situation, the processor does not generate the FWAIT instruction automatically.

; Processor instruction first - No wait needed

mov WORD PTR mem32[0], ax ; Load memory


mov WORD PTR mem32[2], dx
fild mem32 ; Load to register

; Coprocessor instruc tion first - Wait needed (for 8087)


fist mem32 ; Store to memory
fwait ; Wait until coprocessor
;
is done mov ax, WORD PTR mem32[0] ; Move to register
mov dx, WORD PTR mem32[2]

When gener ating c ode for the 8087 coprocessor, the assemble r automatica lly inserts a WAIT
instruction
the coprocbeessor
fore instruction. However, if you use the .286 or .386 directive, the compiler assumes
that the
coprocessor instruc tions ar e for the 80287 or 80387 and does not inse rt the WAIT instruction. If your code
does
not need to run on an 8086 or 8088 proc essor, you ca n make your progra ms sm aller and more effic
ient by using
the .286 or .386 directive.

Using Coprocessor Instructions


The 8087 family of coprocessors has separa te instructions for each of the following operations:

Loading and storing data


Doing arithmetic calculations
Controlling program flow

The following sections expla in the available instr uctions and show how to use them for each of these
ope rations. syntax information, see “Instruction a nd Opera nd Formats,” earlier in this section.
For general

Loading and Storing Data


Data- transfer instructions copy data betwe en main memory and the coproce ssor registers or be
tween different
coprocessor registers. Two principles govern data transfers:

The choice of instruction deter mines whe ther a value in me mory is considered a n intege r, a
BCDreanumber,
l number.orThea value is a lways considered a 10-byte real number onc e transferred to the coprocessor.
The size of the ope rand determines the size of a value in memory. Value s in the c oprocessor
always
bytes.take up 10

You c an transfer da ta to stack registers using load c ommands. These commands push data onto the stac
kme from
mory or from coprocessor registe rs. Store c omm ands remove data. Some store c omm ands pop
data off stack
register the into memory or coprocessor registers; others simply copy the data without changing it on the stack.

If you use constants as operands, you cannot load them dire ctly into coprocessor registers. You
must
me moryallocate
a nd initialize a var iable to a consta nt value. That variable can then be loaded by using
one of thein the
instructions loadfollowing list.
The math coprocessor offer s a few special instructions for loading ce rta in constants. You can load 0,
1,
sevepi,ral and
common logarithmic values directly. Using these instructions is faster and often more precise than
loading
the values from initialized variables.

All instructions tha t loa d constants have the stack top a s the implied destination oper and. T he
constant to implied
loaded is the be source operand.

The c oprocessor data area, or parts of it, ca n also be moved to mem ory and late r loaded back. You
may
do thiswant to the c urrent state of the coprocessor before e xecuting a procedur e. After the procedure ends, re
to save
store
the previous sta tus. Saving c oprocessor data is also useful whe n you want to modify coproc essor
behavior by data to ma in memory, operating on the data with 8086-family instruc tions, and the n loading it back
writing certain
to the coprocessor data area.

Use the following instructions for transferring numbers to and from registers:

Instruction(s) Description

FLD, FST, FSTP Loads and stores real numbers


FILD, FIST, FISTP Loads and stores binary integers
FBLD Loads BCD
FBSTP Stores BCD
FXCH Exchanges register values
FLDZ Pushes 0 into ST
FLD1 Pushes 1 into ST
FLDPI Pushes the value of pi into ST
FLDCW mem2byte Loads the control word into the coprocessor
F[[N]]STCW me m2byte Stores the control word in memory
FLDENV mem14byte Loads environment from memory
F[[N]]STENV mem14byte Stores environment in memory
FRSTOR mem94byte Restores state from memory
F[[N]]SAVE mem94byte Saves state in memory
FLDL2E Pushes the value of log2e into ST
FLDL2T Pushes log210 into ST
FLDLG2 Pushes log102 into ST
FLDLN2 Pushes loge2 into ST

The following e xample and Figure 6.7 illustrate some of these instructions:

.DATA
m1 REAL4 1.0
m2 REAL4 2.0
.CODE
fld m1 ; Push m1 into first item
fld st(2) ; Push third item into first
fst m2 ; Copy first item to m2
fxch st(2) ; Exchange first and third items
fstp m1 ; Pop first item into m1
Figure 6.7 Status of the Register Stack: Main Memory and Coprocessor

Doing Arithmetic Calculations


Most of the coproc essor instructions for a rithmetic ope ra tions have several forms, de pending on the operand used.
You do not need to specify the operand type in the

instruction if both opera nds a re stac k re giste rs, since r egister value s are always 10- byte rea l
numbers. In most
the arithmetic of listed here, the result replaces the destination register. The instructions include:
instructions
Instruction Description

FADD Adds the source and destination


FSUB Subtracts the source from the destination
FSUBR Subtracts the destination from the source
FMUL Multiplies the source and the destination
FDIV Divides the destination by the source
FDIVR Divides the source by the destination
FABS Sets the sign of ST to positive
FCHS Reverses the sign of ST
FRNDINT Rounds ST to an integer
FSQRT Replaces the contents of ST with its square root
FSCALE Multiplies the stack-top value by 2 to the power contained in ST(1)
FPREM Calculates the remainder of ST divided by ST(1)

80387 Only
Instruction Description

FSIN Calculates the sine of the value in ST


FCOS Calculates the cosine of the value in ST
FSINCOS Calculates the sine and cosine of the value in ST
FPREM1 Calculates the partial remainder by performing modulo division on the top two stack registers
FXTRACT Breaks a number down into its e xpone nt and mantissa and pushe s the ma ntissa onto the
re giste r stack
F2XM1 Calculates 2x–1
FYL2X Calculates Y * log2 X
FYL2XP1 Calculates Y * log2 (X+1)
FPTAN Calculates the tangent of the value in ST
FPATAN Calculates the arctangent of the ratio Y/X
F[[N]]INIT Resets the coprocessor and restores all the default conditions in the control and status words
F[[N]]CLEX Clears all exception flags and the busy flag of the status word
FINCSTP Adds 1 to the stack pointer in the status word
FDECSTP Subtracts 1 from the stack pointer in the status word
FFREE Marks the specified register a s empty

The following e xample illustrate s seve ra l arithmetic instructions. The code solves quadratic equations, but does
no
error checking and fails for some values be cause it attempts to find the square root of a negative
number . Both
Help and the M ATH.ASM sam ple file show a complete ve rsion of this procedure. The c omplete
form use s theZero) instruction to che ck for a ne gative numbe r or 0 before calculating the square root.
FTST (Test for

.DATA
a REAL4 3.0
b REAL4 7.0
cc REAL4 2.0
posx REAL4 0.0
negx REAL4 0.0

.CODE
.
.
.
; Solve quadratic equation - no error checking
; The formula is: -b +/- squareroot(b2 - 4ac) / (2a)
fld1 ; Get constants 2 and 4
fadd st,st ; 2 at bottom
fld st ; Copy it
fmul a ; = 2a

fmul st(1),st ; = 4a
fxch ; Exchange
fmul cc ; = 4ac

fld b ; Load b
fmul st,st ; = b2
fsubr ; = b2 - 4ac
; Negative value here produces error
fsqrt ; = square root(b2 - 4ac)
fld b ; Load b
fchs ; Make it negative
fxch ; Exchange

fld st ; Copy square root


fadd st,st(2) ; Plus version = -b + root(b2 - 4ac)
fxch ; Exchange
fsubp st(2),st ; Minus version = -b - root(b2 - 4ac)

fdiv st,st(2) ; Divide plus version


fstp posx ; Store it
fdivr ; Divide minus version
fstp negx ; Store it

Controlling Program Flow


The math coprocessor has se veral instructions that set control flags in the sta tus word. The 8087-
family
flags cancontrol
be used with conditional jumps to dire ct program flow in the same way that 8086-family flags
are used.
Since the coproc essor does not have jump instr uctions, you must transfer the status word to memory so
that
flags cthe
an be used by 8086-family instructions.

An e asy way to use the status word with conditional jumps is to move its upper byte into the
lowe r byte
processor flags,ofas the
shown in this example:

fstsw mem16 ; Store status word in memory


fwait ; Make sure coproc essor is done
mov ax, mem16 ; Move to AX
sahf ; Store upper word in flags
The SAHF (Store AH into Fla gs) instruction in this example transfers AH into the low bits of the flags register.

You can save se veral steps by loading the status word directly to AX on the 80287 with the
FSTSW
FNSTSW instructions. This is the only c ase in which data can be transferred directly
between
coprocessorprocessor
registers, asand
shown in this example:

fstsw ax

The coprocessor control flags and their relationship to the status word are de scribe d in
“Control
following. Re giste rs,”

The 8087-family coproce ssors provide several instr uctions for comparing oper ands and testing control
flags.
these All
instructions compare the stac k top ( ST) to a source oper and, which may either be spec ified
or implie
ST(1). d as

The c ompar e instructions affect the C3, C2, and C0 c ontrol flags, but not the C1 flag. Table 6.3 shows the
flags’
settings for each possible result of a comparison or test.

Table 6.3 Control-Flag Settings After Comparison or Te st

After FCOM After FTEST C3 C2 C0

ST > source ST is positive 000


ST < source ST is negative 001
ST = source ST is 0 100
Not comparable ST is NAN or projective infinity 1 1 1

Variations on the compa re instructions a llow you to pop the stac k once or twice a nd to compare integers and
zero.
For each instruction, the stack top is alwa ys the implied destination operand. If you do not give an operand, ST( 1)
is the implie d source. With some compa re instructions, you can specify the source as a
memory
operand. or re giste r

All instructions summar ize d in the following list have implie d operands: either ST as a single-destination
operand
or ST as the destination and ST (1) as the source. Ea ch instruction in the list has implied
operands.
instructionsSome
have a wa it ve rsion and a no-wait ver sion. The no-wa it ve rsions have N as the
sec ond letter. The
instructions for comparing and testing flags include:
Instruction Desc ription

FCOM Compares the stack top to the source. The


source and destination are unaffected by the comparison.
FTST Compares ST to 0.
FCOMP Compares the stack top to the source and then pops the stack.
FUCO M, FUCOMP, Compares the source to ST and sets the condition code s of the status
FUCOMPP word
according to the result (80386/486 only).
F[[N]]STSW mem2byte Stores the status word in memory.
FXAM Sets the value of the control flags based on the type of the number in ST.
FPREM Finds a c orrect re mainde r for large operands. It uses the C2 fla g to indicate whether
the remainder re turned is partia l (C2 is se t) or comple te (C2 is cle ar). If
the bit
set, the is operation should be repeated. It also returns the lea st-significant
of the quotient
three bits in C0, C3, and C1.
FNOP Copies the sta ck top onto itse lf, thus padding the executa ble file and
taking up time without having any effect on registers or memory.
processing
FDISI, FNDISI, FENI, Enables or disable s interrupts (8087 only).
FNENI
FSETPM Sets protec ted mode. Re quires a .286P or .386P direc tive (80287, 80387, and
80486 only).

The following exa mple illustra tes some of these instructions. Notice how conditional blocks ar e used
to e nhacode.
80287 nce

.DATA
down REAL4 10.35 ; Sides of a rectangle
across REAL4 13.07
diamtr REAL4 12.93 ; Diameter of a circle
status WORD ?
P287 EQU (@Cpu AND 00111y)
.CODE
.
.
.
; Get area of rectangle
fld across ; Load one side
fmul down ; Multiply by the other

; Get area of circle: Area = PI * (D/2)2


fld1 ; Load one and
fadd st, st ; double it to get constant 2
fdivr diamtr ; Divide diameter to ge t radius
fmul st, st ; Square ra dius
fldpi ; Load pi
fmul ; Multiply it

; Compare area of circle and rectangle


fcompp ; Compare and throw both away
IF p287
fstsw ax ; (For 287+, skip memory)
ELSE
fnstsw status ; Load from coprocessor to memory
mov ax, status ; Transfer memory to register
ENDIF
sahf ; Transfer AH to flags register
jp nocomp ; If parity set, can't compare
jz same ; If zero set, they're the same
jc rectangle ; If carry set, recta ngle is bigger
jmp circle ; else circle is bigger

nocomp: ; Error handler


.
.
.
same : ; Both e qual
.
.
.
rectangle: ; Rectangle bigger
.
.
.
circle: ; Circle bigger

Additional instr uctions for the 80387/486 are FLDENVD and FLDENVW for loading the envir
onment;
FNSTENVD, FNSTENVW, FSTENVD, and FSTENVW for storing the e nvironment state;
FNSAVED
FNSAVEW, FSAVED, and FSAVEW for saving the coprocessor state; and FRSTORD and
FRSTORW
restoring the coprocessor state.

The size of the code se gment, not the ope ra nd siz e, determines the number of bytes loaded or
stored with Tthese
instructions. he instructions ending with W store the 16-bit form of the control registe r da ta, and the instruc
tions
ending with D store the 32-bit form. For exa mple, in 16-bit mode FSAVEW saves the 16-bit c ontrol register data.
If you need to store the 32-bit form of the control register data, use FSAVED.

Control Registers
Some of the flags of the seven 16-bit control registers control coproc essor oper ations, while
other s status
current maintain
of thethe
coprocessor. In this sense, they are much like the 8086-family flags registers (see Figure 6.8).
Figure 6.8 Coprocessor Control Registers

The status word registe r is the only commonly used control re giste r. (The othe rs are used
mostly
programmeby rs.)
systems
The forma t of the status word registe r is shown in Figure 6.9, which shows how the
coprocessor
control flags align with the pr oce ssor flags. C3 overwrite s the zero flag, C2 overwrites the
parity flag, the
overwrites and c C0
arry flag. C1 over wr ites a n undefined bit, so it cannot be used directly with
conditional jumps,
although you can use the TEST instruction to

check C1 in memory or in a r egister. T he status wor d register also overwrites the sign and auxilia ry-c arry flags,
so
you cannot count on their being unchanged after the operation.

Figure 6.9 Coprocessor and Processor Control Flags

Using An Emulator Library


If you do not have a math coprocessor or an 80486 processor , you ca n do most floating-
point operations by
writing assembly-langua ge proce dures a nd acc essing an emula tor from a high-level la nguage. All M icrosoft
high-
level languages come with emulator libraries for all memory models.

To use emula tor functions, first write your asse mbly-language procedure using coprocessor
instruc tions. Then
assemble the module with the /FPi option a nd link it with your high-leve l – language modules.
You
optionsc anin enter
the Progra mmer’s WorkBench ( PWB) environment, or you ca n use the OPTION
EMULATOR
your source code.

In emula tion mode, the a ssembler generates instructions for the linker that the Microsoft emula tor
can
for muse.
of The
the OPTION directive in the following example tells the assembler to use emulation
mode. Thisin Chapter
(introduced option 1) can be defined only once in a module.

OPTION EMULATOR
You c an use emulator functions in a stand-a lone assembler program by assembling with the /Cx
comma
option nd-line
and linking with the appropriate emulator library. The following fragme nt outlines a small-model
program
that contains floating-point instructions served by an emulator:

.MODEL small, c
OPTION EMULATOR
.
.
.
PUBLIC main
.CODE
main: ; Program entry point must
.STARTUP ; have name 'main'
.
fadd st, st ; Floating-point instructions
fldpi ; emulate
d
Emulator libraries do not allow for all of the coprocessor instructions. The following floating-point
instruc
are not tions
emulated:

FBLD
FBSTP
FCOS
FDECSTP
FINCSTP
FINIT
FLDENV
FNOP
FPREM1
FRSTOR
FRSTORW
FRSTORD
FSAVE
FSAVEW
FSAVED
FSETPM
FSIN
FSINCOS
FSTENV
FUCOM
FUCOMP
FUCOMPP
FXTRACT

For information about writing assembly-language proc edures for high- level langua ges, see Chapte r
12, “M ixed-
Language Progra mming.”

Using Binary Coded Decimal Numbers


Binary coded de cimal (BCD) numbers allow calculations on la rge numbers without rounding
errors. T his makes BCD numbers a common choice for monetary calc ulations. Although BCDs ca n
characteristic
represent
integers of any precision, the 8087-based coprocessors ac commodate BCD number s only in the
range
±999,999,999,999,999,999.

This se ction explains how to define BCD number s, how to access the m with a math coprocessor or e mulator ,
and
how to perform simple BCD c alculations on the main processor.

Defining BCD Constants and Variables


Unpacked BCD numbe rs ar e made up of bytes containing a single dec imal digit in the lower 4
bits of each
Pa cked BCD byte.
number s a re made up of byte s containing two decimal digits: one in the upper 4 bits and
one in the
lower 4 bits. The leftmost digit holds the sign (0 for positive, 1 for negative).

Pa cked BCD number s are encoded in the 8087 coprocessor’s packed BCD format. They can be up
to
long,18 digits
packed two digits per byte . The assembler z er o-pads BCDs initialized with fewer tha n 18 digits.
Digit 20 is a nd digit 19 is reserved.
the sign bit,

When you define an inte ger constant with the TBYTE dire ctive and the curre nt radix is decima l (t), the
assembler
interprets the number as a packed BCD number.

The syntax for specifying pac ked BCDs is the same as for other integers.

pos1 TBYTE 1234567890 ; Encoded a s 00000000001234567890h


neg1 TBYTE -1234567890 ; Encoded as 80000000001234567890h

Unpacked BCD numbers a re stored one digit to a byte, with the value in the lower 4 bits.
They ca BYTE
using the n be directive.
defined For example, an unpacked BCD number could be define d and initialized as follows:

unpackedr BYTE 1,5,8,2,5,2,9 ; Initialized to 9,252,851


unpackedf BYTE 9,2,5,2,8,5,1 ; Initialized to 9,252,851

As the se two lines show, you can arra nge digits backward or forward, de pending on how you write the calc
ulation
routines that handle the numbers.

BCD Calculations on a Coprocessor


As the pre vious section explains, BCDs diffe r from other numbers only in the way a pr ogram
stores
me mory.theInternally,
m in a math coproc essor does not distinguish BCD intege rs from any other type . The copr
ocessor
can load, calculate, and store pac ked BCD integers up to 18 digits long.

The coprocessor instruction

fbld bcd1

pushe s the pa cked BCD number at bcd1 onto the c oproc essor sta ck. When your code complete s ca
lculations
the number,on
place the result back into memory in BCD format with the instruction

fbstp bcd1

which discards the variable from the stack top.

BCD Calculations on the Main Processor


The 8086-fa mily of processors can perform simple arithme tic operations on BCD integers, but only one digit
at
timea . The main processor, like the coprocessor, operates inte rnally on the number’s bina ry va
lue. It recode
additional quires
to translate the binary result back into BCD format.

The main processor provide s instr uctions spec ifically designed to translate to and from BCD
format. The se
instructions are ca lled “ASCII-a djust” and “de cimal-adjust” instructions. They ge t their names
from Intel
mnemonics that use the term “ASCII” to refe r to unpacke d BCD numbe rs and “ decima l” to refer to packed
BCD
numbers.

Unpacked BCD Numbers


When a ca lculation using two one -digit va lues produc es a two-digit result, the instructions AAA,
AAS
and AAD place the first digit in AL and the sec ond in AH. If the digit in AL needs to c arry to or borrow fr om
the
digit in AH, the instructions set the carry a nd auxiliary ca rry fla gs. The four ASCII-adjust
instruc
unpackedtions forare:
BCDs

Instruction Description

AAA Adjusts after an addition operation.


AAS Adjusts after a subtraction operation.
AAM Adjusts after a multiplication opera tion. Always use with MUL, not with IMUL.
AAD Adjusts be fore a division operation. Unlike other BCD instructions, AAD converts a BCD
value to a binary value before the operation. After the operation, use AAM to adjust the
quotient.
remainder Theis lost. If you need the re mainde r, sa ve it in a nother register before
quotient.
adjusting Then
the move it bac k to AL and adjust if necessary.
instruction to adjust the re sult. The decimal-adjust instructions do not ta ke an operand a nd always
For
work processor arithmetic on unpa cked BCD numbers, you must do the 8-bit a rithmetic ca lculations on e
value
ach inonthe the
digit AL register.
sepa rately, and assign the result to the AL register. After e ach operation, use the corresponding BCD
instruction
to adjust the result. The ASCII-adjust instructions do not take a n operand and always work on the value in the AL
The 8086-family proc essors provide the instructions DAA ( Dec im al Adjust a fter Addition) and
register.
DAS
Adjust De
( aftercimal
Subtraction) for adjusting packed BCD numbers after addition and subtraction.
The following exa mples show how to use eac h of these instr uctions in BCD a ddition, subtra ction,
These examples use DAA and DAS to add and subtract BCDs.
multiplication,
and division.
;To
; Toadd
add88 and333:
9 and as BCDs:
mov ax, 8833h ; Load 88 and 33 as packed BCDs
mov ax, 9 ; Load 9
add
mov al,
bx,ah3 ; Add
; and 88 and
3 a s33 to get 0BBh
unpacked BCDs
daa ; Adjust 0BBh to 121 (packed BCD:)
add al, bl ; Add 09h and 03h to get 0Ch
aaa ;; Adjust
1 in carry
0Ch inandAL21toin02h,
AL
; increment AH to 01h, set carry
;To subtract 38 from 83: ; Result 12 (unpacked BCD in AX)
mov ax, 3883h ; Load 83 and 38 as packed BCDs
; To subtract 4 from 13:
sub
mov al,
ax,ah103h ; Subtract
; Load 13 38 from 83 to get 04Bh
das ; Adjust 04Bh to 45 (pa cked
mov bx, 4 ; and 4 a s unpacked BCDsBCD:)
sub al, bl ; ;Subtract
0 in carry and3 45
4 from in AL
to get FFh (-1)
aas ; Adjust 0FFh in AL to 9,
Unlike the ASCII-adjust; de instructions,
crement AH the deccarry
to 0, set imal-adjust instructions ne ver a ffect AH. The
assembler se ts the ; Result
auxiliary carry flag if the digit in the9lower
(unpacked
4 bits BCD
carriesintoAX)
or borrows from the digit in the upper 4 bits, a nd it sets
; To multiply 9 time s 3:
the carry flag if the digit in the upper 4 bits ne eds to carry to or borrow from another byte.
mov ax, 903h ; Load 9 and 3 as unpacked BCDs
mul ah
Multidigit BCD numbers are usually ; Multiply 9 and 3 in
processed to loops.
get 1BhEach byte is processed and adjusted in turn.
aam ; Adjust 1Bh in AL
; to get 27 (unpacked BCD in AX)

; To divide 25 by 2:
mov ax, 205h ; Load 25
mov bl, 2 ; and 2 as unpacked BCDs
aad ; Adjust 0205h in AX
; to get 19h in AX
div bl ; Divide by 2 to get
; quotient 0Ch in AL
; rema inder 1 in
AH aam ; Adjust 0Ch in AL
; to 12 (unpacked BCD in AX)
; (remainder destroyed)

If you process multidigit BCD numbers in loops, each digit is processed and a djusted in turn.

Packed BCD Numbers


Pa cked BCD number s a re made up of byte s containing two decimal digits: one in the upper 4 bits and
one
lowerin the
4 bits. The 8086-fa mily proce ssors provide instructions for adjusting pac ked BCD numbers
after addition
and subtraction. You must write your own routines to adjust for multiplication and division.

For processor calculations on pac ked BCD numbers, you must do the 8-bit arithme tic calculations
on eacrately,
sepa h byte placing the result in the AL register. After each operation, use the corresponding
decima l-adjust

You might also like