#236: Speedy the Math Coprocessor
Written by: Rich Collyer June 1989
This Technical Note presents an overview of the 68881 and 68882 math
coprocessors, and it covers general information about the chips as well as how
using the chips directly can help speed your mathÐintensive code.
_______________________________________________________________________________
Introduction
Generally we donÕt recommend that you assume the existence of specific
hardware. However, if your program does proper feature checking using
_SysEnvirons and there is a FloatingÐPoint Unit (FPU) available, than you can
use code which will run your math intensive code much faster. This Technical
Note is basically a condensed version of the Motorola MC68881/MC68882
FloatingÐPoint Coprocessor UserÕs Manual. I will cover some of the basics of
what the chips can do, their differences, and how to take advantage of what
they have to offer.
If _SysEnvirons returns hasFPU = FALSE, then your code should use the routines
provided by the Standard Apple Numeric Environment (SANE). The routines which
SANE provide are covered in the Apple Numerics Manual.
So What Can These Chips Do?
The MC68881 and MC68882 are floatingÐpoint coprocessors which implement the
IEEE standard for binary floatingÐpoint arithmetic. The two chips are fully
interchangeable and are primarily for use as coprocessors to the MC68020 and
MC68030 central processors. The two chips will work as peripheral processors
to the MC68000, MC68008, and MC68010 central processors.
Both chips have eight 80Ðbit general purpose floatingÐpoint data registers
(FP0-FP7), 67Ðbit arithmetic units with precision greater than the extended
format, 67Ðbit barrel shifter, 46 instructions, trigonometric and
transcendental functions, and 21 constants. The MC68882 also has the
capability of concurrent execution of multiple floatingÐpoint instructions.
Internal Registers for a Higher Capacity to Think
There are eleven separate registers in these puppies: eight data registers,
one control register, one status register, and one address register.
Data Registers
There are eight 80Ðbit floatingÐpoint data registers labeled FP0ÐFP7. The
extended format, which is used by these registers, will be covered later.
When using the FPU from an MPW C and Pascal application, you can us FP0ÐFP3
for temporary storage without saving and restoring their values. If you wish
to use FP4ÐFP7 in your assembly routine, then you must save these registers at
the start of your assembly code and restore them before you leave the assembly
code.
Control Register (FPCR)
Below is a representation of the control register. For the most part, there
is no need for you to do anything to the control register directly. It is
used internally for determining precision, rounding, and error checking.
¥¥¥Click on the Illustration button below, and refer to Figure 1.¥¥¥
Figure 1ÐControl Register
Status Register (FPSR)
The status register is diagrammed in Figure 2. This register is also used
mostly for internal chores. The conditionÐcode byte is set at the end of each
arithmetic instruction. The conditionÐcode byte is translated into a data
type; Table 1 shows the relationship between condition codes and data types.
The condition code is also used to determine logic equates. If you wish to
determine if two numbers are equal, than the Compare statement (FCMP) will
check the condition code. Table 2 shows the relationship between the
condition codes and logic equates.
The quotient byte is set at the completion of FMOD (Modulo Remainder) and FREM
(IEEE Remainder). This byte can be used before a transcendental function to
determine the quadrant of a circle in which an operand resides. The
FPÐexception status byte is used in conjunction with the exceptionÐenable byte
of the control register. The FPÐaccrued exception byte is used to keep a
history of the FP exceptions that have occurred since the last set or clear.
¥¥¥Click on the Illustration button below, and refer to Figure 2.¥¥¥
Figure 2ÐStatus Register
Negative Zero Infinity NAN Result Data Type
___________________________________________________________________
0 0 0 0 + Normalized or Denormalized
1 0 0 0 Ð Normalized or Denormalized
0 1 0 0 + zero
1 1 0 0 Ð zero
0 0 1 0 + infinity
1 0 1 0 Ð infinity
0 0 0 1 + NAN
1 0 0 1 Ð NAN
___________________________________________________________________
Table 1ÐCondition Code versus Result Data Type
Logic Equate Abbreviation Condition Code
_______________________________________________________________________
Equal to EQ Z
Not Equal NE not Z
Greater Than GT or OGT not(N or NAN or Z)
Not Greater Than NGT or UGT NAN or Z or N
Greater Than or Equal GE or OGE Z or (not(NAN or N))
Not (Greater Than or Equal) NGE or UGE NAN or (N and (not Z))
Less Than LT or OLT N and (not(NAN or Z))
Not Less Than NLT or ULT NAN or (Z and (not N))
Less Than or Equal LE or OLE Z or (N and (not NAN))
Not (Less Than or Equal NLE or ULE NAN or (not (N or Z))
Greater or Less Than GL or OGL not (NAN or Z)
Not (Greater or Less Than) NGL or UEQ NAN or Z
Greater, Less or Equal) GLE or OR not NAN
Not (Greater, Less or Equal) NGLE or UN NAN
Oxx is ordered Z Ð> Zero
Uxx is unordered N Ð> Negative
______________________________________________________________________
Table 2ÐLogic Equates
Address Register (FPIAR)
Since the coprocessor can do concurrent processing with the MC68020 and
MC68030, as well as with itself, the program counter is not necessarily
pointing to the logical address of the instruction upon which it is working.
So the address register stores the logical address of each floatingÐpoint
instruction before executing it.
FloatingÐPoint Data Formats
There are four floatingÐpoint numeric formats: singleÐprecision binary real
format, doubleÐprecision binary real format, eXtendedÐprecision binary real
format, and Pack decimal real format (a.k.a., BCD). I have given examples of
what the FPU will convert your numbers to. The number which I have used for
the four examples is PlanckÕs constant (4.136 x 10-15 eVÐsec). Other than the
size, the first three formats are very similar. The three formats all have
the same conversion method and ordering of information.
Single (S) 32 bit
Single precision is represented by 32 bits of information. The high bit (bit
31) is the sign bit (s). The next byte of information (bits 30Ð23) is the
exponent (e), and the last 23 bits (bits 22Ð0) are the fraction (f). The bits
of information are converted into a floatingÐpoint number by the following
equation:
(Ð1)s * 2(e-127) * (20 + f)
The fraction (f) is the strange value. Each bit in the fraction value
represents a negative exponent of two. So if bit 22 and bit 16 are high, and
all the rest of the bits are low, than the fraction would equal 0.5078125 or
(2-1 + 2-7). So when I give the FPU the number 4.136eÐ15, it converts the
number into the hexadecimal number $04F1503DE, which, in the above equation,
looks like:
(Ð1)0*2(79-127)* 20+2-3+2-5+2-7+2-14+2-15+2-16+2-17+2-19+2-20+2-21+2-22
This number is than converted back to a base ten number as
4.13600004803759899eÐ15. As you can see, the number is correct up to the
seventh decimal place.
Double (D) 64 bit
Double precision is represented by 64 bits of information. The high bit (bit
63) is the sign bit (s), The next 11 bits of information (bits 62Ð52) are the
exponent (e), and the last 52 bits (bits 51Ð0) are the fraction (f). The bits
of information are converted into a floatingÐpoint number by the following
equation:
(Ð1)s * 2(e-1023) * (20 + f)
When I give the FPU the number 4.136eÐ15 as a double, it converts the number
into the hexadecimal number $03CF2A07BBC5ED155. This number is than converted
back to a base ten number as 4.13600000000000015eÐ15. As you can see, the
number is correct up to the fifteenth decimal place.
EXtended (X) 96/80 bit
Extended precision is represented by 96 bits of information; SANE and FP data
register use 80Ðbit extended numbers, but the FPU extended numbers are 96 bits
with 16 unused bits, so the two are basically the same. The high bit (bit 95)
is the sign bit (s), The next 15 bits of information (bits 94Ð81) are the
exponent (e), there are 16 unused bits (bits 80Ð64), and the last 64 bits
(bits 63Ð0) are the fraction (f). The bits of information are converted into
a floatingÐpoint number by the following equation:
(Ð1)s * 2(e-16383) * (20 + f)
When I give the FPU the number 4.136eÐ15 as a extended, it converts the number
into the hexadecimal number $03FCF(0000)9503DDE2F68AA66F. This number is than
converted back to a base ten number as 4.136eÐ15. This number is correct to
about the nineteenth decimal place.
Pack Decimal Real (P) BCD Format 96 bits
Pack Decimal Real is represented by 96 bits of information. The bits of these
numbers are represented as follows:
bit 95 Sign of Mantissa
bit 94 Sign of Exponent
bit 93Ð92 used for +Ðinfinity and NANs,otherwise zero
bits 91Ð81 10Ðbit Exponent (3 digit exponent)
bits 80Ð68 unused, zero
bit 67Ð0, 68 bit Mantissa (17 digit mantissa)
When I give the FPU the number 4.136eÐ15 as a PDR, it converts the number into
the hexadecimal number $401500041360000000000000. This hexadecimal number is
filled into the above bit as follows:
bit 95 Sign of Mantissa 0 (binary)
bit 94 Sign of Exponent 1 (binary)
bit 93Ð92 used for +Ðinfinity and NANs,otherwise zero 00 (binary)
bits 91Ð80 11Ðbit Exponent (3 digit exponent) 000000010101 (binary)
bits 79Ð68 unused, zero 000000000000 (binary )
bit 67Ð0 68 bit Mantissa (17 digit mantissa) 41360000000000000
(hex)
This number is than converted back to a base ten number as 4.136eÐ15. This
number is correct to the seventeenth decimal place.
So What Tools Do I Have to Play With?
There are four types of opcodes which the math coprocessors support: moves,
monodic, dyadic, and miscellaneous conditions. When a coprocessor operation
is executed, the first operation which the coprocessor performs is to convert
the data to the internal extended precision format, and when the operation is
completed, the data is converted to the destination data format.
Moves
The first type which I will describe are the move opcodes. Below is a list of
the various formats in which the move commands come.
Move
FMOVE. , FPn
FMOVE. FPm,
FMOVE.X FPm, FPn
Move Multiple
FMOVEM , FP0 - FP3/FP7
FMOVEM FP2/FP4/FP6, ;the registers are always moved as 96 bit extended
;data without conversion
Move Register
FMOVE.L , FPCR ;move to control register
FMOVE.L FPCR, ;move from control register
Move Constants from ROM to floating-point register
FMOVECR.X #ccc, FPn ;see Table 3 for #ccc
Save and Restore Machine State
FSAVE ;virtual machine state save
FRESTORE ;virtual machine state restore
is a main processing unit (MPU) effective address operand (any 68xxx
addressing mode).
is the data format size (Byte, Word, Long, Single, Double, eXtended,
Packed decimal).
FPm and FPn are floatingÐpoint data registers.
#ccc Mathematical Representation Numeric Representation
__________________________________________________________________
$00 pi 3.14159265358979324
$0B log(base 10)(2) 0.301029995663981195
$0C e 2.71828182845904524
$0D log(base 2)(e) 1.442695040888963410
$0E log(base 10)(e) 0.434294481903251828
$0F zero 0
$30 ln(2) 0.693147180559945309
$31 ln(10) 2.302585092994045684
$32 10^0 1
$33 10^1 10
$34 10^2 100
$35 10^4 10,000
$36 10^8 100,000,000
$37 10^16 10,000,000,000,000,000
$38 10^32 100...(28 more zeros)...00
$39 10^64 100...(60 more zeros)...00
$3A 10^128 100...(124 more zeros)...00
$3B 10^256 100...(252 more zeros)...00
$3C 10^512 100...(508 more zeros)...00
$3D 10^1024 100...(1020 more zeros)...00
$3E 10^2048 100...(2044 more zeros)...00
$3F 10^4096 100...(4092 more zeros)...00
__________________________________________________________________
Table 3ÐConstants
Monodic
A monodic operation has one operand. The operand may be a floatingÐpoint data
register or an MPU effective address. The result is always stored in a
floatingÐpoint data register. The syntax for monodic operations is listed
below:
Fxxxx. , FPn
Fxxxx.X FPm, FPn
Fxxxx.X FPn
where: is (B,W,L,S,D,X,P)
xxxx is one of the Trigonometric (SIN), Transcendental (ATANH), Exponential
(ETOXM1), Misc. commands (NEG)
Dyadic
A dyadic operation has two operands. The first operand can be in a
floatingÐpoint data register, or an MPU effective address. The second operand
is the contents of a floatingÐpoint data register. The result of the
operation is stored in the second operand. The syntax for dyadic operations
is listed below:
Fxxxx. , FPn
Fxxxx.X FPm, FPn
where is (B,W,L,S,D,X,P)
xxxx is a arithmetic (ADD), compare (CMP)
Condition operations
There are four condition operations: branch (FBcc), decrement and branch
(FDBcc), set according to condition (FScc), and trap on condition (FTRAPcc).
Why and How do I Program for a 68882?
Any code which runs on a 68881 will run on a 68882 and vice versa. You do not
need to take special care to program for the 68882, but if the chip is
available, than special care can noticeably improve the speed of your code.
Figure 3 demonstrates the difference between code run on a 68881 and the same
code run on a 68882. The 68882 is completely finished running before the
68881 has even started executing the FMOVE instruction. The extra work which
you need to do to take advantage of the concurrent processing is fairly
minimal.
¥¥¥Click on the Illustration button below, and refer to Figure 3.¥¥¥
Figure 3ÐConcurrent Execution versus NonÐConcurrent Execution
Before you jump right in and start writing code, you need to understand that
there are three different levels of concurrency. The first level is the
minimum concurrency operations. These are operations which cannot run
concurrently with other operations. Most of these operations are
nonÐfloatingÐpoint format operations. The minimum concurrency operations are
listed in Table 4.
Instruction Operand Syntax Operand Format
_______________________________________________
FMOVE , FPn B,W,L,P
FPm, B,W,L
FPm, P
FPm, P
, FPcr L
FPcr, L
_______________________________________________
FMOVECR #ccc, FPn X
_______________________________________________
FMOVEM , L,X
, Dn X
, L,X
Dn, X
_______________________________________________
FTST FPm B,W,L,P
_______________________________________________
F , FPn B,W,L,P
_______________________________________________
F , FPn B,W,L,P
_______________________________________________
FSINCOS , FPc:FPs B,W,L,P
_______________________________________________
Table 4ÐMinimum Concurrency
The next level of operations are the operations which can share some of the
FPU time with other operations, these are the partial concurrency operations
and they are listed in Table 5. The partial concurrency operations include
most of the floatingÐpoint format operations.
Instruction Operand Syntax Operand Format
_______________________________________________
FTST S,D,X
FPm X
_______________________________________________
F , FPn S,D,X
FPm, FPn
_______________________________________________
F , FPn S,D,X
FPm, FPn
_______________________________________________
FSINCOS , FPc:FPs S,D,X
FPm, FPc:FPs X
_______________________________________________
Table 5ÐPartial Concurrency
The highest level of concurrency is the fullyÐconcurrent operations which are
listed in Table 6. The only operations which can run fully concurrently are
the FMOVE operations. There are certain guidelines which you need to follow
in order to achieve full concurrency, these guidelines are outlined in Table
6. The most important rule to follow is to avoid register conflict. There
are basically two type of register conflict. The first is when the
destination register of an operation is the source register of the following
operation, and the following operation is a fullyÐconcurrent operation:
FADD. , FP0
FMOVE. FP0, ;FP0 conflicts
The second type of register conflict occurs when the destination register of
an operation is the destination register of the following operation, and the
following operation is a fullyÐconcurrent operation:
FADD. , FP0
FMOVE. , FP0 ;FP0 conflicts
where is S, D, or X
Instruction Syntax Format No Concurrency Partial Concurrency
________________________________________________________________________
FMOVE FPm, FPn X a b,c,f
________________________________________________________________________
FMOVE , FPn S,D,X b,c,f
________________________________________________________________________
FMOVE FPm, S,D a b,d,e
________________________________________________________________________
FMOVE FPm, X a b
________________________________________________________________________
a: Register conflict of FPm with preceding instructionÕs destination FP
data register
b: NAN, unnormalized or denormalized data type
c: Rounding Precision in FPCR set to Single or Double
d: INEX2 bit in FPCR EXC byte is enabled
e: An overflow or underflow occurs
f: Register conflict of FPn with preceding instructionÕs destination FP
data register
Table 6ÐFully Concurrent
The next most important optimization rule is to unroll loops. If you properly
unroll your loops, than you will be able to eliminate more of the register
conflicts. Most loops are designed to do one iteration of a set of
instructions. This means that each iteration of the loop is accomplishing one
iteration of the set of instructions. If you unroll the loop, then each
iteration of the loop can accomplish two or more iterations of the set of
instructions. Figures 4 and 5 demonstrate how to unroll your code. The
second version (Figure 5) is 25Ð30 percent faster than the first.
MOVE.L #count,D0
LOOPTOP FMOVE.X , FP3
FNEG.X FP3
FETOX.X FP3
FMOVE.X FP3,FP4 ;conflict
FSUB.X , FP3
FNEG.X FP4
FSUB.X #1, FP4
FDIV.X FP4,FP3
FNEG.X FP3
FADD.X ,FP3
FMOVE.X FP3, ;conflict
DBRA D0, LOOPTOP
Figure 4ÐNewtonÐRaphsonÕs Method
Xi+1 = Xi + f(Xi)/f'(Xi) : f(X) = exp(-x) - x
MOVE.L #count,D0
FMOVE.D , FP0
LOOPTOP FNEG FP0,FP3
FETOX FP3
FMOVE FP3,FP4 ;conflict
FSUB FP0,FP3
FNEG FP4
FSUB.X #1,FP4
FDIV FP4,FP3
FSUB FP3,FP0
DBRA D0, LOOPTOP
FMOVE.D FP0,
Figure 5ÐNewtonÐRaphsonÕs Method (resisterÐbased, unrolled)
Xi+1 = Xi + f(Xi)/f'(Xi) : f(X) = exp(-x) - x
Conclusion
The last comment which I have to make is for code which is to run during
interrupt time. If you plan to use the math coprocessor during interrupt
time, you must call FSAVE at the start of your routine and FRESTORE at the end
of your routine. If you do not make these calls and you interrupt another
program which is using the FPU, then the other program will not find the FPU
in the same state that it was in before the interrupt, and this causes certain
death. For more information, refer to Technical Note #235, Cooperating with
the Coprocessor.
If you made it this far, and you are still awake, then you should be already
to start writing assembly routines for your code which will speed up your
mathÐintensive programs. Just remember that before you try to use the code,
you need to check hasFPU with a call to _SysEnvirons, and if the machine does
not have an FPU, then use an alternate SANE version of the math code.
Further Reference:
_______________________________________________________________________________
¥ Apple Numerics Manual, Second Edition
¥ Motorola MC68881/MC68882 UserÕs Manual
¥ Technical Note #129, _SysEnvirons: System 6.0 and Beyond
¥ Technical Note #235, Cooperating with the Coprocessor