xref: /OK3568_Linux_fs/kernel/arch/m68k/fpsp040/setox.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun|
2*4882a593Smuzhiyun|	setox.sa 3.1 12/10/90
3*4882a593Smuzhiyun|
4*4882a593Smuzhiyun|	The entry point setox computes the exponential of a value.
5*4882a593Smuzhiyun|	setoxd does the same except the input value is a denormalized
6*4882a593Smuzhiyun|	number.	setoxm1 computes exp(X)-1, and setoxm1d computes
7*4882a593Smuzhiyun|	exp(X)-1 for denormalized X.
8*4882a593Smuzhiyun|
9*4882a593Smuzhiyun|	INPUT
10*4882a593Smuzhiyun|	-----
11*4882a593Smuzhiyun|	Double-extended value in memory location pointed to by address
12*4882a593Smuzhiyun|	register a0.
13*4882a593Smuzhiyun|
14*4882a593Smuzhiyun|	OUTPUT
15*4882a593Smuzhiyun|	------
16*4882a593Smuzhiyun|	exp(X) or exp(X)-1 returned in floating-point register fp0.
17*4882a593Smuzhiyun|
18*4882a593Smuzhiyun|	ACCURACY and MONOTONICITY
19*4882a593Smuzhiyun|	-------------------------
20*4882a593Smuzhiyun|	The returned result is within 0.85 ulps in 64 significant bit, i.e.
21*4882a593Smuzhiyun|	within 0.5001 ulp to 53 bits if the result is subsequently rounded
22*4882a593Smuzhiyun|	to double precision. The result is provably monotonic in double
23*4882a593Smuzhiyun|	precision.
24*4882a593Smuzhiyun|
25*4882a593Smuzhiyun|	SPEED
26*4882a593Smuzhiyun|	-----
27*4882a593Smuzhiyun|	Two timings are measured, both in the copy-back mode. The
28*4882a593Smuzhiyun|	first one is measured when the function is invoked the first time
29*4882a593Smuzhiyun|	(so the instructions and data are not in cache), and the
30*4882a593Smuzhiyun|	second one is measured when the function is reinvoked at the same
31*4882a593Smuzhiyun|	input argument.
32*4882a593Smuzhiyun|
33*4882a593Smuzhiyun|	The program setox takes approximately 210/190 cycles for input
34*4882a593Smuzhiyun|	argument X whose magnitude is less than 16380 log2, which
35*4882a593Smuzhiyun|	is the usual situation.	For the less common arguments,
36*4882a593Smuzhiyun|	depending on their values, the program may run faster or slower --
37*4882a593Smuzhiyun|	but no worse than 10% slower even in the extreme cases.
38*4882a593Smuzhiyun|
39*4882a593Smuzhiyun|	The program setoxm1 takes approximately ??? / ??? cycles for input
40*4882a593Smuzhiyun|	argument X, 0.25 <= |X| < 70log2. For |X| < 0.25, it takes
41*4882a593Smuzhiyun|	approximately ??? / ??? cycles. For the less common arguments,
42*4882a593Smuzhiyun|	depending on their values, the program may run faster or slower --
43*4882a593Smuzhiyun|	but no worse than 10% slower even in the extreme cases.
44*4882a593Smuzhiyun|
45*4882a593Smuzhiyun|	ALGORITHM and IMPLEMENTATION NOTES
46*4882a593Smuzhiyun|	----------------------------------
47*4882a593Smuzhiyun|
48*4882a593Smuzhiyun|	setoxd
49*4882a593Smuzhiyun|	------
50*4882a593Smuzhiyun|	Step 1.	Set ans := 1.0
51*4882a593Smuzhiyun|
52*4882a593Smuzhiyun|	Step 2.	Return	ans := ans + sign(X)*2^(-126). Exit.
53*4882a593Smuzhiyun|	Notes:	This will always generate one exception -- inexact.
54*4882a593Smuzhiyun|
55*4882a593Smuzhiyun|
56*4882a593Smuzhiyun|	setox
57*4882a593Smuzhiyun|	-----
58*4882a593Smuzhiyun|
59*4882a593Smuzhiyun|	Step 1.	Filter out extreme cases of input argument.
60*4882a593Smuzhiyun|		1.1	If |X| >= 2^(-65), go to Step 1.3.
61*4882a593Smuzhiyun|		1.2	Go to Step 7.
62*4882a593Smuzhiyun|		1.3	If |X| < 16380 log(2), go to Step 2.
63*4882a593Smuzhiyun|		1.4	Go to Step 8.
64*4882a593Smuzhiyun|	Notes:	The usual case should take the branches 1.1 -> 1.3 -> 2.
65*4882a593Smuzhiyun|		 To avoid the use of floating-point comparisons, a
66*4882a593Smuzhiyun|		 compact representation of |X| is used. This format is a
67*4882a593Smuzhiyun|		 32-bit integer, the upper (more significant) 16 bits are
68*4882a593Smuzhiyun|		 the sign and biased exponent field of |X|; the lower 16
69*4882a593Smuzhiyun|		 bits are the 16 most significant fraction (including the
70*4882a593Smuzhiyun|		 explicit bit) bits of |X|. Consequently, the comparisons
71*4882a593Smuzhiyun|		 in Steps 1.1 and 1.3 can be performed by integer comparison.
72*4882a593Smuzhiyun|		 Note also that the constant 16380 log(2) used in Step 1.3
73*4882a593Smuzhiyun|		 is also in the compact form. Thus taking the branch
74*4882a593Smuzhiyun|		 to Step 2 guarantees |X| < 16380 log(2). There is no harm
75*4882a593Smuzhiyun|		 to have a small number of cases where |X| is less than,
76*4882a593Smuzhiyun|		 but close to, 16380 log(2) and the branch to Step 9 is
77*4882a593Smuzhiyun|		 taken.
78*4882a593Smuzhiyun|
79*4882a593Smuzhiyun|	Step 2.	Calculate N = round-to-nearest-int( X * 64/log2 ).
80*4882a593Smuzhiyun|		2.1	Set AdjFlag := 0 (indicates the branch 1.3 -> 2 was taken)
81*4882a593Smuzhiyun|		2.2	N := round-to-nearest-integer( X * 64/log2 ).
82*4882a593Smuzhiyun|		2.3	Calculate	J = N mod 64; so J = 0,1,2,..., or 63.
83*4882a593Smuzhiyun|		2.4	Calculate	M = (N - J)/64; so N = 64M + J.
84*4882a593Smuzhiyun|		2.5	Calculate the address of the stored value of 2^(J/64).
85*4882a593Smuzhiyun|		2.6	Create the value Scale = 2^M.
86*4882a593Smuzhiyun|	Notes:	The calculation in 2.2 is really performed by
87*4882a593Smuzhiyun|
88*4882a593Smuzhiyun|			Z := X * constant
89*4882a593Smuzhiyun|			N := round-to-nearest-integer(Z)
90*4882a593Smuzhiyun|
91*4882a593Smuzhiyun|		 where
92*4882a593Smuzhiyun|
93*4882a593Smuzhiyun|			constant := single-precision( 64/log 2 ).
94*4882a593Smuzhiyun|
95*4882a593Smuzhiyun|		 Using a single-precision constant avoids memory access.
96*4882a593Smuzhiyun|		 Another effect of using a single-precision "constant" is
97*4882a593Smuzhiyun|		 that the calculated value Z is
98*4882a593Smuzhiyun|
99*4882a593Smuzhiyun|			Z = X*(64/log2)*(1+eps), |eps| <= 2^(-24).
100*4882a593Smuzhiyun|
101*4882a593Smuzhiyun|		 This error has to be considered later in Steps 3 and 4.
102*4882a593Smuzhiyun|
103*4882a593Smuzhiyun|	Step 3.	Calculate X - N*log2/64.
104*4882a593Smuzhiyun|		3.1	R := X + N*L1, where L1 := single-precision(-log2/64).
105*4882a593Smuzhiyun|		3.2	R := R + N*L2, L2 := extended-precision(-log2/64 - L1).
106*4882a593Smuzhiyun|	Notes:	a) The way L1 and L2 are chosen ensures L1+L2 approximate
107*4882a593Smuzhiyun|		 the value	-log2/64	to 88 bits of accuracy.
108*4882a593Smuzhiyun|		 b) N*L1 is exact because N is no longer than 22 bits and
109*4882a593Smuzhiyun|		 L1 is no longer than 24 bits.
110*4882a593Smuzhiyun|		 c) The calculation X+N*L1 is also exact due to cancellation.
111*4882a593Smuzhiyun|		 Thus, R is practically X+N(L1+L2) to full 64 bits.
112*4882a593Smuzhiyun|		 d) It is important to estimate how large can |R| be after
113*4882a593Smuzhiyun|		 Step 3.2.
114*4882a593Smuzhiyun|
115*4882a593Smuzhiyun|			N = rnd-to-int( X*64/log2 (1+eps) ), |eps|<=2^(-24)
116*4882a593Smuzhiyun|			X*64/log2 (1+eps)	=	N + f,	|f| <= 0.5
117*4882a593Smuzhiyun|			X*64/log2 - N	=	f - eps*X 64/log2
118*4882a593Smuzhiyun|			X - N*log2/64	=	f*log2/64 - eps*X
119*4882a593Smuzhiyun|
120*4882a593Smuzhiyun|
121*4882a593Smuzhiyun|		 Now |X| <= 16446 log2, thus
122*4882a593Smuzhiyun|
123*4882a593Smuzhiyun|			|X - N*log2/64| <= (0.5 + 16446/2^(18))*log2/64
124*4882a593Smuzhiyun|					<= 0.57 log2/64.
125*4882a593Smuzhiyun|		 This bound will be used in Step 4.
126*4882a593Smuzhiyun|
127*4882a593Smuzhiyun|	Step 4.	Approximate exp(R)-1 by a polynomial
128*4882a593Smuzhiyun|			p = R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5))))
129*4882a593Smuzhiyun|	Notes:	a) In order to reduce memory access, the coefficients are
130*4882a593Smuzhiyun|		 made as "short" as possible: A1 (which is 1/2), A4 and A5
131*4882a593Smuzhiyun|		 are single precision; A2 and A3 are double precision.
132*4882a593Smuzhiyun|		 b) Even with the restrictions above,
133*4882a593Smuzhiyun|			|p - (exp(R)-1)| < 2^(-68.8) for all |R| <= 0.0062.
134*4882a593Smuzhiyun|		 Note that 0.0062 is slightly bigger than 0.57 log2/64.
135*4882a593Smuzhiyun|		 c) To fully utilize the pipeline, p is separated into
136*4882a593Smuzhiyun|		 two independent pieces of roughly equal complexities
137*4882a593Smuzhiyun|			p = [ R + R*S*(A2 + S*A4) ]	+
138*4882a593Smuzhiyun|				[ S*(A1 + S*(A3 + S*A5)) ]
139*4882a593Smuzhiyun|		 where S = R*R.
140*4882a593Smuzhiyun|
141*4882a593Smuzhiyun|	Step 5.	Compute 2^(J/64)*exp(R) = 2^(J/64)*(1+p) by
142*4882a593Smuzhiyun|				ans := T + ( T*p + t)
143*4882a593Smuzhiyun|		 where T and t are the stored values for 2^(J/64).
144*4882a593Smuzhiyun|	Notes:	2^(J/64) is stored as T and t where T+t approximates
145*4882a593Smuzhiyun|		 2^(J/64) to roughly 85 bits; T is in extended precision
146*4882a593Smuzhiyun|		 and t is in single precision. Note also that T is rounded
147*4882a593Smuzhiyun|		 to 62 bits so that the last two bits of T are zero. The
148*4882a593Smuzhiyun|		 reason for such a special form is that T-1, T-2, and T-8
149*4882a593Smuzhiyun|		 will all be exact --- a property that will give much
150*4882a593Smuzhiyun|		 more accurate computation of the function EXPM1.
151*4882a593Smuzhiyun|
152*4882a593Smuzhiyun|	Step 6.	Reconstruction of exp(X)
153*4882a593Smuzhiyun|			exp(X) = 2^M * 2^(J/64) * exp(R).
154*4882a593Smuzhiyun|		6.1	If AdjFlag = 0, go to 6.3
155*4882a593Smuzhiyun|		6.2	ans := ans * AdjScale
156*4882a593Smuzhiyun|		6.3	Restore the user FPCR
157*4882a593Smuzhiyun|		6.4	Return ans := ans * Scale. Exit.
158*4882a593Smuzhiyun|	Notes:	If AdjFlag = 0, we have X = Mlog2 + Jlog2/64 + R,
159*4882a593Smuzhiyun|		 |M| <= 16380, and Scale = 2^M. Moreover, exp(X) will
160*4882a593Smuzhiyun|		 neither overflow nor underflow. If AdjFlag = 1, that
161*4882a593Smuzhiyun|		 means that
162*4882a593Smuzhiyun|			X = (M1+M)log2 + Jlog2/64 + R, |M1+M| >= 16380.
163*4882a593Smuzhiyun|		 Hence, exp(X) may overflow or underflow or neither.
164*4882a593Smuzhiyun|		 When that is the case, AdjScale = 2^(M1) where M1 is
165*4882a593Smuzhiyun|		 approximately M. Thus 6.2 will never cause over/underflow.
166*4882a593Smuzhiyun|		 Possible exception in 6.4 is overflow or underflow.
167*4882a593Smuzhiyun|		 The inexact exception is not generated in 6.4. Although
168*4882a593Smuzhiyun|		 one can argue that the inexact flag should always be
169*4882a593Smuzhiyun|		 raised, to simulate that exception cost to much than the
170*4882a593Smuzhiyun|		 flag is worth in practical uses.
171*4882a593Smuzhiyun|
172*4882a593Smuzhiyun|	Step 7.	Return 1 + X.
173*4882a593Smuzhiyun|		7.1	ans := X
174*4882a593Smuzhiyun|		7.2	Restore user FPCR.
175*4882a593Smuzhiyun|		7.3	Return ans := 1 + ans. Exit
176*4882a593Smuzhiyun|	Notes:	For non-zero X, the inexact exception will always be
177*4882a593Smuzhiyun|		 raised by 7.3. That is the only exception raised by 7.3.
178*4882a593Smuzhiyun|		 Note also that we use the FMOVEM instruction to move X
179*4882a593Smuzhiyun|		 in Step 7.1 to avoid unnecessary trapping. (Although
180*4882a593Smuzhiyun|		 the FMOVEM may not seem relevant since X is normalized,
181*4882a593Smuzhiyun|		 the precaution will be useful in the library version of
182*4882a593Smuzhiyun|		 this code where the separate entry for denormalized inputs
183*4882a593Smuzhiyun|		 will be done away with.)
184*4882a593Smuzhiyun|
185*4882a593Smuzhiyun|	Step 8.	Handle exp(X) where |X| >= 16380log2.
186*4882a593Smuzhiyun|		8.1	If |X| > 16480 log2, go to Step 9.
187*4882a593Smuzhiyun|		(mimic 2.2 - 2.6)
188*4882a593Smuzhiyun|		8.2	N := round-to-integer( X * 64/log2 )
189*4882a593Smuzhiyun|		8.3	Calculate J = N mod 64, J = 0,1,...,63
190*4882a593Smuzhiyun|		8.4	K := (N-J)/64, M1 := truncate(K/2), M = K-M1, AdjFlag := 1.
191*4882a593Smuzhiyun|		8.5	Calculate the address of the stored value 2^(J/64).
192*4882a593Smuzhiyun|		8.6	Create the values Scale = 2^M, AdjScale = 2^M1.
193*4882a593Smuzhiyun|		8.7	Go to Step 3.
194*4882a593Smuzhiyun|	Notes:	Refer to notes for 2.2 - 2.6.
195*4882a593Smuzhiyun|
196*4882a593Smuzhiyun|	Step 9.	Handle exp(X), |X| > 16480 log2.
197*4882a593Smuzhiyun|		9.1	If X < 0, go to 9.3
198*4882a593Smuzhiyun|		9.2	ans := Huge, go to 9.4
199*4882a593Smuzhiyun|		9.3	ans := Tiny.
200*4882a593Smuzhiyun|		9.4	Restore user FPCR.
201*4882a593Smuzhiyun|		9.5	Return ans := ans * ans. Exit.
202*4882a593Smuzhiyun|	Notes:	Exp(X) will surely overflow or underflow, depending on
203*4882a593Smuzhiyun|		 X's sign. "Huge" and "Tiny" are respectively large/tiny
204*4882a593Smuzhiyun|		 extended-precision numbers whose square over/underflow
205*4882a593Smuzhiyun|		 with an inexact result. Thus, 9.5 always raises the
206*4882a593Smuzhiyun|		 inexact together with either overflow or underflow.
207*4882a593Smuzhiyun|
208*4882a593Smuzhiyun|
209*4882a593Smuzhiyun|	setoxm1d
210*4882a593Smuzhiyun|	--------
211*4882a593Smuzhiyun|
212*4882a593Smuzhiyun|	Step 1.	Set ans := 0
213*4882a593Smuzhiyun|
214*4882a593Smuzhiyun|	Step 2.	Return	ans := X + ans. Exit.
215*4882a593Smuzhiyun|	Notes:	This will return X with the appropriate rounding
216*4882a593Smuzhiyun|		 precision prescribed by the user FPCR.
217*4882a593Smuzhiyun|
218*4882a593Smuzhiyun|	setoxm1
219*4882a593Smuzhiyun|	-------
220*4882a593Smuzhiyun|
221*4882a593Smuzhiyun|	Step 1.	Check |X|
222*4882a593Smuzhiyun|		1.1	If |X| >= 1/4, go to Step 1.3.
223*4882a593Smuzhiyun|		1.2	Go to Step 7.
224*4882a593Smuzhiyun|		1.3	If |X| < 70 log(2), go to Step 2.
225*4882a593Smuzhiyun|		1.4	Go to Step 10.
226*4882a593Smuzhiyun|	Notes:	The usual case should take the branches 1.1 -> 1.3 -> 2.
227*4882a593Smuzhiyun|		 However, it is conceivable |X| can be small very often
228*4882a593Smuzhiyun|		 because EXPM1 is intended to evaluate exp(X)-1 accurately
229*4882a593Smuzhiyun|		 when |X| is small. For further details on the comparisons,
230*4882a593Smuzhiyun|		 see the notes on Step 1 of setox.
231*4882a593Smuzhiyun|
232*4882a593Smuzhiyun|	Step 2.	Calculate N = round-to-nearest-int( X * 64/log2 ).
233*4882a593Smuzhiyun|		2.1	N := round-to-nearest-integer( X * 64/log2 ).
234*4882a593Smuzhiyun|		2.2	Calculate	J = N mod 64; so J = 0,1,2,..., or 63.
235*4882a593Smuzhiyun|		2.3	Calculate	M = (N - J)/64; so N = 64M + J.
236*4882a593Smuzhiyun|		2.4	Calculate the address of the stored value of 2^(J/64).
237*4882a593Smuzhiyun|		2.5	Create the values Sc = 2^M and OnebySc := -2^(-M).
238*4882a593Smuzhiyun|	Notes:	See the notes on Step 2 of setox.
239*4882a593Smuzhiyun|
240*4882a593Smuzhiyun|	Step 3.	Calculate X - N*log2/64.
241*4882a593Smuzhiyun|		3.1	R := X + N*L1, where L1 := single-precision(-log2/64).
242*4882a593Smuzhiyun|		3.2	R := R + N*L2, L2 := extended-precision(-log2/64 - L1).
243*4882a593Smuzhiyun|	Notes:	Applying the analysis of Step 3 of setox in this case
244*4882a593Smuzhiyun|		 shows that |R| <= 0.0055 (note that |X| <= 70 log2 in
245*4882a593Smuzhiyun|		 this case).
246*4882a593Smuzhiyun|
247*4882a593Smuzhiyun|	Step 4.	Approximate exp(R)-1 by a polynomial
248*4882a593Smuzhiyun|			p = R+R*R*(A1+R*(A2+R*(A3+R*(A4+R*(A5+R*A6)))))
249*4882a593Smuzhiyun|	Notes:	a) In order to reduce memory access, the coefficients are
250*4882a593Smuzhiyun|		 made as "short" as possible: A1 (which is 1/2), A5 and A6
251*4882a593Smuzhiyun|		 are single precision; A2, A3 and A4 are double precision.
252*4882a593Smuzhiyun|		 b) Even with the restriction above,
253*4882a593Smuzhiyun|			|p - (exp(R)-1)| <	|R| * 2^(-72.7)
254*4882a593Smuzhiyun|		 for all |R| <= 0.0055.
255*4882a593Smuzhiyun|		 c) To fully utilize the pipeline, p is separated into
256*4882a593Smuzhiyun|		 two independent pieces of roughly equal complexity
257*4882a593Smuzhiyun|			p = [ R*S*(A2 + S*(A4 + S*A6)) ]	+
258*4882a593Smuzhiyun|				[ R + S*(A1 + S*(A3 + S*A5)) ]
259*4882a593Smuzhiyun|		 where S = R*R.
260*4882a593Smuzhiyun|
261*4882a593Smuzhiyun|	Step 5.	Compute 2^(J/64)*p by
262*4882a593Smuzhiyun|				p := T*p
263*4882a593Smuzhiyun|		 where T and t are the stored values for 2^(J/64).
264*4882a593Smuzhiyun|	Notes:	2^(J/64) is stored as T and t where T+t approximates
265*4882a593Smuzhiyun|		 2^(J/64) to roughly 85 bits; T is in extended precision
266*4882a593Smuzhiyun|		 and t is in single precision. Note also that T is rounded
267*4882a593Smuzhiyun|		 to 62 bits so that the last two bits of T are zero. The
268*4882a593Smuzhiyun|		 reason for such a special form is that T-1, T-2, and T-8
269*4882a593Smuzhiyun|		 will all be exact --- a property that will be exploited
270*4882a593Smuzhiyun|		 in Step 6 below. The total relative error in p is no
271*4882a593Smuzhiyun|		 bigger than 2^(-67.7) compared to the final result.
272*4882a593Smuzhiyun|
273*4882a593Smuzhiyun|	Step 6.	Reconstruction of exp(X)-1
274*4882a593Smuzhiyun|			exp(X)-1 = 2^M * ( 2^(J/64) + p - 2^(-M) ).
275*4882a593Smuzhiyun|		6.1	If M <= 63, go to Step 6.3.
276*4882a593Smuzhiyun|		6.2	ans := T + (p + (t + OnebySc)). Go to 6.6
277*4882a593Smuzhiyun|		6.3	If M >= -3, go to 6.5.
278*4882a593Smuzhiyun|		6.4	ans := (T + (p + t)) + OnebySc. Go to 6.6
279*4882a593Smuzhiyun|		6.5	ans := (T + OnebySc) + (p + t).
280*4882a593Smuzhiyun|		6.6	Restore user FPCR.
281*4882a593Smuzhiyun|		6.7	Return ans := Sc * ans. Exit.
282*4882a593Smuzhiyun|	Notes:	The various arrangements of the expressions give accurate
283*4882a593Smuzhiyun|		 evaluations.
284*4882a593Smuzhiyun|
285*4882a593Smuzhiyun|	Step 7.	exp(X)-1 for |X| < 1/4.
286*4882a593Smuzhiyun|		7.1	If |X| >= 2^(-65), go to Step 9.
287*4882a593Smuzhiyun|		7.2	Go to Step 8.
288*4882a593Smuzhiyun|
289*4882a593Smuzhiyun|	Step 8.	Calculate exp(X)-1, |X| < 2^(-65).
290*4882a593Smuzhiyun|		8.1	If |X| < 2^(-16312), goto 8.3
291*4882a593Smuzhiyun|		8.2	Restore FPCR; return ans := X - 2^(-16382). Exit.
292*4882a593Smuzhiyun|		8.3	X := X * 2^(140).
293*4882a593Smuzhiyun|		8.4	Restore FPCR; ans := ans - 2^(-16382).
294*4882a593Smuzhiyun|		 Return ans := ans*2^(140). Exit
295*4882a593Smuzhiyun|	Notes:	The idea is to return "X - tiny" under the user
296*4882a593Smuzhiyun|		 precision and rounding modes. To avoid unnecessary
297*4882a593Smuzhiyun|		 inefficiency, we stay away from denormalized numbers the
298*4882a593Smuzhiyun|		 best we can. For |X| >= 2^(-16312), the straightforward
299*4882a593Smuzhiyun|		 8.2 generates the inexact exception as the case warrants.
300*4882a593Smuzhiyun|
301*4882a593Smuzhiyun|	Step 9.	Calculate exp(X)-1, |X| < 1/4, by a polynomial
302*4882a593Smuzhiyun|			p = X + X*X*(B1 + X*(B2 + ... + X*B12))
303*4882a593Smuzhiyun|	Notes:	a) In order to reduce memory access, the coefficients are
304*4882a593Smuzhiyun|		 made as "short" as possible: B1 (which is 1/2), B9 to B12
305*4882a593Smuzhiyun|		 are single precision; B3 to B8 are double precision; and
306*4882a593Smuzhiyun|		 B2 is double extended.
307*4882a593Smuzhiyun|		 b) Even with the restriction above,
308*4882a593Smuzhiyun|			|p - (exp(X)-1)| < |X| 2^(-70.6)
309*4882a593Smuzhiyun|		 for all |X| <= 0.251.
310*4882a593Smuzhiyun|		 Note that 0.251 is slightly bigger than 1/4.
311*4882a593Smuzhiyun|		 c) To fully preserve accuracy, the polynomial is computed
312*4882a593Smuzhiyun|		 as	X + ( S*B1 +	Q ) where S = X*X and
313*4882a593Smuzhiyun|			Q	=	X*S*(B2 + X*(B3 + ... + X*B12))
314*4882a593Smuzhiyun|		 d) To fully utilize the pipeline, Q is separated into
315*4882a593Smuzhiyun|		 two independent pieces of roughly equal complexity
316*4882a593Smuzhiyun|			Q = [ X*S*(B2 + S*(B4 + ... + S*B12)) ] +
317*4882a593Smuzhiyun|				[ S*S*(B3 + S*(B5 + ... + S*B11)) ]
318*4882a593Smuzhiyun|
319*4882a593Smuzhiyun|	Step 10.	Calculate exp(X)-1 for |X| >= 70 log 2.
320*4882a593Smuzhiyun|		10.1 If X >= 70log2 , exp(X) - 1 = exp(X) for all practical
321*4882a593Smuzhiyun|		 purposes. Therefore, go to Step 1 of setox.
322*4882a593Smuzhiyun|		10.2 If X <= -70log2, exp(X) - 1 = -1 for all practical purposes.
323*4882a593Smuzhiyun|		 ans := -1
324*4882a593Smuzhiyun|		 Restore user FPCR
325*4882a593Smuzhiyun|		 Return ans := ans + 2^(-126). Exit.
326*4882a593Smuzhiyun|	Notes:	10.2 will always create an inexact and return -1 + tiny
327*4882a593Smuzhiyun|		 in the user rounding precision and mode.
328*4882a593Smuzhiyun|
329*4882a593Smuzhiyun|
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun|		Copyright (C) Motorola, Inc. 1990
332*4882a593Smuzhiyun|			All Rights Reserved
333*4882a593Smuzhiyun|
334*4882a593Smuzhiyun|       For details on the license for this file, please see the
335*4882a593Smuzhiyun|       file, README, in this same directory.
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun|setox	idnt	2,1 | Motorola 040 Floating Point Software Package
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun	|section	8
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun#include "fpsp.h"
342*4882a593Smuzhiyun
343*4882a593SmuzhiyunL2:	.long	0x3FDC0000,0x82E30865,0x4361C4C6,0x00000000
344*4882a593Smuzhiyun
345*4882a593SmuzhiyunEXPA3:	.long	0x3FA55555,0x55554431
346*4882a593SmuzhiyunEXPA2:	.long	0x3FC55555,0x55554018
347*4882a593Smuzhiyun
348*4882a593SmuzhiyunHUGE:	.long	0x7FFE0000,0xFFFFFFFF,0xFFFFFFFF,0x00000000
349*4882a593SmuzhiyunTINY:	.long	0x00010000,0xFFFFFFFF,0xFFFFFFFF,0x00000000
350*4882a593Smuzhiyun
351*4882a593SmuzhiyunEM1A4:	.long	0x3F811111,0x11174385
352*4882a593SmuzhiyunEM1A3:	.long	0x3FA55555,0x55554F5A
353*4882a593Smuzhiyun
354*4882a593SmuzhiyunEM1A2:	.long	0x3FC55555,0x55555555,0x00000000,0x00000000
355*4882a593Smuzhiyun
356*4882a593SmuzhiyunEM1B8:	.long	0x3EC71DE3,0xA5774682
357*4882a593SmuzhiyunEM1B7:	.long	0x3EFA01A0,0x19D7CB68
358*4882a593Smuzhiyun
359*4882a593SmuzhiyunEM1B6:	.long	0x3F2A01A0,0x1A019DF3
360*4882a593SmuzhiyunEM1B5:	.long	0x3F56C16C,0x16C170E2
361*4882a593Smuzhiyun
362*4882a593SmuzhiyunEM1B4:	.long	0x3F811111,0x11111111
363*4882a593SmuzhiyunEM1B3:	.long	0x3FA55555,0x55555555
364*4882a593Smuzhiyun
365*4882a593SmuzhiyunEM1B2:	.long	0x3FFC0000,0xAAAAAAAA,0xAAAAAAAB
366*4882a593Smuzhiyun	.long	0x00000000
367*4882a593Smuzhiyun
368*4882a593SmuzhiyunTWO140:	.long	0x48B00000,0x00000000
369*4882a593SmuzhiyunTWON140:	.long	0x37300000,0x00000000
370*4882a593Smuzhiyun
371*4882a593SmuzhiyunEXPTBL:
372*4882a593Smuzhiyun	.long	0x3FFF0000,0x80000000,0x00000000,0x00000000
373*4882a593Smuzhiyun	.long	0x3FFF0000,0x8164D1F3,0xBC030774,0x9F841A9B
374*4882a593Smuzhiyun	.long	0x3FFF0000,0x82CD8698,0xAC2BA1D8,0x9FC1D5B9
375*4882a593Smuzhiyun	.long	0x3FFF0000,0x843A28C3,0xACDE4048,0xA0728369
376*4882a593Smuzhiyun	.long	0x3FFF0000,0x85AAC367,0xCC487B14,0x1FC5C95C
377*4882a593Smuzhiyun	.long	0x3FFF0000,0x871F6196,0x9E8D1010,0x1EE85C9F
378*4882a593Smuzhiyun	.long	0x3FFF0000,0x88980E80,0x92DA8528,0x9FA20729
379*4882a593Smuzhiyun	.long	0x3FFF0000,0x8A14D575,0x496EFD9C,0xA07BF9AF
380*4882a593Smuzhiyun	.long	0x3FFF0000,0x8B95C1E3,0xEA8BD6E8,0xA0020DCF
381*4882a593Smuzhiyun	.long	0x3FFF0000,0x8D1ADF5B,0x7E5BA9E4,0x205A63DA
382*4882a593Smuzhiyun	.long	0x3FFF0000,0x8EA4398B,0x45CD53C0,0x1EB70051
383*4882a593Smuzhiyun	.long	0x3FFF0000,0x9031DC43,0x1466B1DC,0x1F6EB029
384*4882a593Smuzhiyun	.long	0x3FFF0000,0x91C3D373,0xAB11C338,0xA0781494
385*4882a593Smuzhiyun	.long	0x3FFF0000,0x935A2B2F,0x13E6E92C,0x9EB319B0
386*4882a593Smuzhiyun	.long	0x3FFF0000,0x94F4EFA8,0xFEF70960,0x2017457D
387*4882a593Smuzhiyun	.long	0x3FFF0000,0x96942D37,0x20185A00,0x1F11D537
388*4882a593Smuzhiyun	.long	0x3FFF0000,0x9837F051,0x8DB8A970,0x9FB952DD
389*4882a593Smuzhiyun	.long	0x3FFF0000,0x99E04593,0x20B7FA64,0x1FE43087
390*4882a593Smuzhiyun	.long	0x3FFF0000,0x9B8D39B9,0xD54E5538,0x1FA2A818
391*4882a593Smuzhiyun	.long	0x3FFF0000,0x9D3ED9A7,0x2CFFB750,0x1FDE494D
392*4882a593Smuzhiyun	.long	0x3FFF0000,0x9EF53260,0x91A111AC,0x20504890
393*4882a593Smuzhiyun	.long	0x3FFF0000,0xA0B0510F,0xB9714FC4,0xA073691C
394*4882a593Smuzhiyun	.long	0x3FFF0000,0xA2704303,0x0C496818,0x1F9B7A05
395*4882a593Smuzhiyun	.long	0x3FFF0000,0xA43515AE,0x09E680A0,0xA0797126
396*4882a593Smuzhiyun	.long	0x3FFF0000,0xA5FED6A9,0xB15138EC,0xA071A140
397*4882a593Smuzhiyun	.long	0x3FFF0000,0xA7CD93B4,0xE9653568,0x204F62DA
398*4882a593Smuzhiyun	.long	0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x1F283C4A
399*4882a593Smuzhiyun	.long	0x3FFF0000,0xAB7A39B5,0xA93ED338,0x9F9A7FDC
400*4882a593Smuzhiyun	.long	0x3FFF0000,0xAD583EEA,0x42A14AC8,0xA05B3FAC
401*4882a593Smuzhiyun	.long	0x3FFF0000,0xAF3B78AD,0x690A4374,0x1FDF2610
402*4882a593Smuzhiyun	.long	0x3FFF0000,0xB123F581,0xD2AC2590,0x9F705F90
403*4882a593Smuzhiyun	.long	0x3FFF0000,0xB311C412,0xA9112488,0x201F678A
404*4882a593Smuzhiyun	.long	0x3FFF0000,0xB504F333,0xF9DE6484,0x1F32FB13
405*4882a593Smuzhiyun	.long	0x3FFF0000,0xB6FD91E3,0x28D17790,0x20038B30
406*4882a593Smuzhiyun	.long	0x3FFF0000,0xB8FBAF47,0x62FB9EE8,0x200DC3CC
407*4882a593Smuzhiyun	.long	0x3FFF0000,0xBAFF5AB2,0x133E45FC,0x9F8B2AE6
408*4882a593Smuzhiyun	.long	0x3FFF0000,0xBD08A39F,0x580C36C0,0xA02BBF70
409*4882a593Smuzhiyun	.long	0x3FFF0000,0xBF1799B6,0x7A731084,0xA00BF518
410*4882a593Smuzhiyun	.long	0x3FFF0000,0xC12C4CCA,0x66709458,0xA041DD41
411*4882a593Smuzhiyun	.long	0x3FFF0000,0xC346CCDA,0x24976408,0x9FDF137B
412*4882a593Smuzhiyun	.long	0x3FFF0000,0xC5672A11,0x5506DADC,0x201F1568
413*4882a593Smuzhiyun	.long	0x3FFF0000,0xC78D74C8,0xABB9B15C,0x1FC13A2E
414*4882a593Smuzhiyun	.long	0x3FFF0000,0xC9B9BD86,0x6E2F27A4,0xA03F8F03
415*4882a593Smuzhiyun	.long	0x3FFF0000,0xCBEC14FE,0xF2727C5C,0x1FF4907D
416*4882a593Smuzhiyun	.long	0x3FFF0000,0xCE248C15,0x1F8480E4,0x9E6E53E4
417*4882a593Smuzhiyun	.long	0x3FFF0000,0xD06333DA,0xEF2B2594,0x1FD6D45C
418*4882a593Smuzhiyun	.long	0x3FFF0000,0xD2A81D91,0xF12AE45C,0xA076EDB9
419*4882a593Smuzhiyun	.long	0x3FFF0000,0xD4F35AAB,0xCFEDFA20,0x9FA6DE21
420*4882a593Smuzhiyun	.long	0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x1EE69A2F
421*4882a593Smuzhiyun	.long	0x3FFF0000,0xD99D15C2,0x78AFD7B4,0x207F439F
422*4882a593Smuzhiyun	.long	0x3FFF0000,0xDBFBB797,0xDAF23754,0x201EC207
423*4882a593Smuzhiyun	.long	0x3FFF0000,0xDE60F482,0x5E0E9124,0x9E8BE175
424*4882a593Smuzhiyun	.long	0x3FFF0000,0xE0CCDEEC,0x2A94E110,0x20032C4B
425*4882a593Smuzhiyun	.long	0x3FFF0000,0xE33F8972,0xBE8A5A50,0x2004DFF5
426*4882a593Smuzhiyun	.long	0x3FFF0000,0xE5B906E7,0x7C8348A8,0x1E72F47A
427*4882a593Smuzhiyun	.long	0x3FFF0000,0xE8396A50,0x3C4BDC68,0x1F722F22
428*4882a593Smuzhiyun	.long	0x3FFF0000,0xEAC0C6E7,0xDD243930,0xA017E945
429*4882a593Smuzhiyun	.long	0x3FFF0000,0xED4F301E,0xD9942B84,0x1F401A5B
430*4882a593Smuzhiyun	.long	0x3FFF0000,0xEFE4B99B,0xDCDAF5CC,0x9FB9A9E3
431*4882a593Smuzhiyun	.long	0x3FFF0000,0xF281773C,0x59FFB138,0x20744C05
432*4882a593Smuzhiyun	.long	0x3FFF0000,0xF5257D15,0x2486CC2C,0x1F773A19
433*4882a593Smuzhiyun	.long	0x3FFF0000,0xF7D0DF73,0x0AD13BB8,0x1FFE90D5
434*4882a593Smuzhiyun	.long	0x3FFF0000,0xFA83B2DB,0x722A033C,0xA041ED22
435*4882a593Smuzhiyun	.long	0x3FFF0000,0xFD3E0C0C,0xF486C174,0x1F853F3A
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun	.set	ADJFLAG,L_SCR2
438*4882a593Smuzhiyun	.set	SCALE,FP_SCR1
439*4882a593Smuzhiyun	.set	ADJSCALE,FP_SCR2
440*4882a593Smuzhiyun	.set	SC,FP_SCR3
441*4882a593Smuzhiyun	.set	ONEBYSC,FP_SCR4
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun	| xref	t_frcinx
444*4882a593Smuzhiyun	|xref	t_extdnrm
445*4882a593Smuzhiyun	|xref	t_unfl
446*4882a593Smuzhiyun	|xref	t_ovfl
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun	.global	setoxd
449*4882a593Smuzhiyunsetoxd:
450*4882a593Smuzhiyun|--entry point for EXP(X), X is denormalized
451*4882a593Smuzhiyun	movel		(%a0),%d0
452*4882a593Smuzhiyun	andil		#0x80000000,%d0
453*4882a593Smuzhiyun	oril		#0x00800000,%d0		| ...sign(X)*2^(-126)
454*4882a593Smuzhiyun	movel		%d0,-(%sp)
455*4882a593Smuzhiyun	fmoves		#0x3F800000,%fp0
456*4882a593Smuzhiyun	fmovel		%d1,%fpcr
457*4882a593Smuzhiyun	fadds		(%sp)+,%fp0
458*4882a593Smuzhiyun	bra		t_frcinx
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun	.global	setox
461*4882a593Smuzhiyunsetox:
462*4882a593Smuzhiyun|--entry point for EXP(X), here X is finite, non-zero, and not NaN's
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun|--Step 1.
465*4882a593Smuzhiyun	movel		(%a0),%d0	 | ...load part of input X
466*4882a593Smuzhiyun	andil		#0x7FFF0000,%d0	| ...biased expo. of X
467*4882a593Smuzhiyun	cmpil		#0x3FBE0000,%d0	| ...2^(-65)
468*4882a593Smuzhiyun	bges		EXPC1		| ...normal case
469*4882a593Smuzhiyun	bra		EXPSM
470*4882a593Smuzhiyun
471*4882a593SmuzhiyunEXPC1:
472*4882a593Smuzhiyun|--The case |X| >= 2^(-65)
473*4882a593Smuzhiyun	movew		4(%a0),%d0	| ...expo. and partial sig. of |X|
474*4882a593Smuzhiyun	cmpil		#0x400CB167,%d0	| ...16380 log2 trunc. 16 bits
475*4882a593Smuzhiyun	blts		EXPMAIN	 | ...normal case
476*4882a593Smuzhiyun	bra		EXPBIG
477*4882a593Smuzhiyun
478*4882a593SmuzhiyunEXPMAIN:
479*4882a593Smuzhiyun|--Step 2.
480*4882a593Smuzhiyun|--This is the normal branch:	2^(-65) <= |X| < 16380 log2.
481*4882a593Smuzhiyun	fmovex		(%a0),%fp0	| ...load input from (a0)
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun	fmovex		%fp0,%fp1
484*4882a593Smuzhiyun	fmuls		#0x42B8AA3B,%fp0	| ...64/log2 * X
485*4882a593Smuzhiyun	fmovemx	%fp2-%fp2/%fp3,-(%a7)		| ...save fp2
486*4882a593Smuzhiyun	movel		#0,ADJFLAG(%a6)
487*4882a593Smuzhiyun	fmovel		%fp0,%d0		| ...N = int( X * 64/log2 )
488*4882a593Smuzhiyun	lea		EXPTBL,%a1
489*4882a593Smuzhiyun	fmovel		%d0,%fp0		| ...convert to floating-format
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun	movel		%d0,L_SCR1(%a6)	| ...save N temporarily
492*4882a593Smuzhiyun	andil		#0x3F,%d0		| ...D0 is J = N mod 64
493*4882a593Smuzhiyun	lsll		#4,%d0
494*4882a593Smuzhiyun	addal		%d0,%a1		| ...address of 2^(J/64)
495*4882a593Smuzhiyun	movel		L_SCR1(%a6),%d0
496*4882a593Smuzhiyun	asrl		#6,%d0		| ...D0 is M
497*4882a593Smuzhiyun	addiw		#0x3FFF,%d0	| ...biased expo. of 2^(M)
498*4882a593Smuzhiyun	movew		L2,L_SCR1(%a6)	| ...prefetch L2, no need in CB
499*4882a593Smuzhiyun
500*4882a593SmuzhiyunEXPCONT1:
501*4882a593Smuzhiyun|--Step 3.
502*4882a593Smuzhiyun|--fp1,fp2 saved on the stack. fp0 is N, fp1 is X,
503*4882a593Smuzhiyun|--a0 points to 2^(J/64), D0 is biased expo. of 2^(M)
504*4882a593Smuzhiyun	fmovex		%fp0,%fp2
505*4882a593Smuzhiyun	fmuls		#0xBC317218,%fp0	| ...N * L1, L1 = lead(-log2/64)
506*4882a593Smuzhiyun	fmulx		L2,%fp2		| ...N * L2, L1+L2 = -log2/64
507*4882a593Smuzhiyun	faddx		%fp1,%fp0		| ...X + N*L1
508*4882a593Smuzhiyun	faddx		%fp2,%fp0		| ...fp0 is R, reduced arg.
509*4882a593Smuzhiyun|	MOVE.W		#$3FA5,EXPA3	...load EXPA3 in cache
510*4882a593Smuzhiyun
511*4882a593Smuzhiyun|--Step 4.
512*4882a593Smuzhiyun|--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL
513*4882a593Smuzhiyun|-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5))))
514*4882a593Smuzhiyun|--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R
515*4882a593Smuzhiyun|--[R+R*S*(A2+S*A4)] + [S*(A1+S*(A3+S*A5))]
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun	fmovex		%fp0,%fp1
518*4882a593Smuzhiyun	fmulx		%fp1,%fp1		| ...fp1 IS S = R*R
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun	fmoves		#0x3AB60B70,%fp2	| ...fp2 IS A5
521*4882a593Smuzhiyun|	MOVE.W		#0,2(%a1)	...load 2^(J/64) in cache
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun	fmulx		%fp1,%fp2		| ...fp2 IS S*A5
524*4882a593Smuzhiyun	fmovex		%fp1,%fp3
525*4882a593Smuzhiyun	fmuls		#0x3C088895,%fp3	| ...fp3 IS S*A4
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun	faddd		EXPA3,%fp2	| ...fp2 IS A3+S*A5
528*4882a593Smuzhiyun	faddd		EXPA2,%fp3	| ...fp3 IS A2+S*A4
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun	fmulx		%fp1,%fp2		| ...fp2 IS S*(A3+S*A5)
531*4882a593Smuzhiyun	movew		%d0,SCALE(%a6)	| ...SCALE is 2^(M) in extended
532*4882a593Smuzhiyun	clrw		SCALE+2(%a6)
533*4882a593Smuzhiyun	movel		#0x80000000,SCALE+4(%a6)
534*4882a593Smuzhiyun	clrl		SCALE+8(%a6)
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun	fmulx		%fp1,%fp3		| ...fp3 IS S*(A2+S*A4)
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun	fadds		#0x3F000000,%fp2	| ...fp2 IS A1+S*(A3+S*A5)
539*4882a593Smuzhiyun	fmulx		%fp0,%fp3		| ...fp3 IS R*S*(A2+S*A4)
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun	fmulx		%fp1,%fp2		| ...fp2 IS S*(A1+S*(A3+S*A5))
542*4882a593Smuzhiyun	faddx		%fp3,%fp0		| ...fp0 IS R+R*S*(A2+S*A4),
543*4882a593Smuzhiyun|					...fp3 released
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun	fmovex		(%a1)+,%fp1	| ...fp1 is lead. pt. of 2^(J/64)
546*4882a593Smuzhiyun	faddx		%fp2,%fp0		| ...fp0 is EXP(R) - 1
547*4882a593Smuzhiyun|					...fp2 released
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun|--Step 5
550*4882a593Smuzhiyun|--final reconstruction process
551*4882a593Smuzhiyun|--EXP(X) = 2^M * ( 2^(J/64) + 2^(J/64)*(EXP(R)-1) )
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun	fmulx		%fp1,%fp0		| ...2^(J/64)*(Exp(R)-1)
554*4882a593Smuzhiyun	fmovemx	(%a7)+,%fp2-%fp2/%fp3	| ...fp2 restored
555*4882a593Smuzhiyun	fadds		(%a1),%fp0	| ...accurate 2^(J/64)
556*4882a593Smuzhiyun
557*4882a593Smuzhiyun	faddx		%fp1,%fp0		| ...2^(J/64) + 2^(J/64)*...
558*4882a593Smuzhiyun	movel		ADJFLAG(%a6),%d0
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun|--Step 6
561*4882a593Smuzhiyun	tstl		%d0
562*4882a593Smuzhiyun	beqs		NORMAL
563*4882a593SmuzhiyunADJUST:
564*4882a593Smuzhiyun	fmulx		ADJSCALE(%a6),%fp0
565*4882a593SmuzhiyunNORMAL:
566*4882a593Smuzhiyun	fmovel		%d1,%FPCR		| ...restore user FPCR
567*4882a593Smuzhiyun	fmulx		SCALE(%a6),%fp0	| ...multiply 2^(M)
568*4882a593Smuzhiyun	bra		t_frcinx
569*4882a593Smuzhiyun
570*4882a593SmuzhiyunEXPSM:
571*4882a593Smuzhiyun|--Step 7
572*4882a593Smuzhiyun	fmovemx	(%a0),%fp0-%fp0	| ...in case X is denormalized
573*4882a593Smuzhiyun	fmovel		%d1,%FPCR
574*4882a593Smuzhiyun	fadds		#0x3F800000,%fp0	| ...1+X in user mode
575*4882a593Smuzhiyun	bra		t_frcinx
576*4882a593Smuzhiyun
577*4882a593SmuzhiyunEXPBIG:
578*4882a593Smuzhiyun|--Step 8
579*4882a593Smuzhiyun	cmpil		#0x400CB27C,%d0	| ...16480 log2
580*4882a593Smuzhiyun	bgts		EXP2BIG
581*4882a593Smuzhiyun|--Steps 8.2 -- 8.6
582*4882a593Smuzhiyun	fmovex		(%a0),%fp0	| ...load input from (a0)
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun	fmovex		%fp0,%fp1
585*4882a593Smuzhiyun	fmuls		#0x42B8AA3B,%fp0	| ...64/log2 * X
586*4882a593Smuzhiyun	fmovemx	 %fp2-%fp2/%fp3,-(%a7)		| ...save fp2
587*4882a593Smuzhiyun	movel		#1,ADJFLAG(%a6)
588*4882a593Smuzhiyun	fmovel		%fp0,%d0		| ...N = int( X * 64/log2 )
589*4882a593Smuzhiyun	lea		EXPTBL,%a1
590*4882a593Smuzhiyun	fmovel		%d0,%fp0		| ...convert to floating-format
591*4882a593Smuzhiyun	movel		%d0,L_SCR1(%a6)			| ...save N temporarily
592*4882a593Smuzhiyun	andil		#0x3F,%d0		 | ...D0 is J = N mod 64
593*4882a593Smuzhiyun	lsll		#4,%d0
594*4882a593Smuzhiyun	addal		%d0,%a1			| ...address of 2^(J/64)
595*4882a593Smuzhiyun	movel		L_SCR1(%a6),%d0
596*4882a593Smuzhiyun	asrl		#6,%d0			| ...D0 is K
597*4882a593Smuzhiyun	movel		%d0,L_SCR1(%a6)			| ...save K temporarily
598*4882a593Smuzhiyun	asrl		#1,%d0			| ...D0 is M1
599*4882a593Smuzhiyun	subl		%d0,L_SCR1(%a6)			| ...a1 is M
600*4882a593Smuzhiyun	addiw		#0x3FFF,%d0		| ...biased expo. of 2^(M1)
601*4882a593Smuzhiyun	movew		%d0,ADJSCALE(%a6)		| ...ADJSCALE := 2^(M1)
602*4882a593Smuzhiyun	clrw		ADJSCALE+2(%a6)
603*4882a593Smuzhiyun	movel		#0x80000000,ADJSCALE+4(%a6)
604*4882a593Smuzhiyun	clrl		ADJSCALE+8(%a6)
605*4882a593Smuzhiyun	movel		L_SCR1(%a6),%d0			| ...D0 is M
606*4882a593Smuzhiyun	addiw		#0x3FFF,%d0		| ...biased expo. of 2^(M)
607*4882a593Smuzhiyun	bra		EXPCONT1		| ...go back to Step 3
608*4882a593Smuzhiyun
609*4882a593SmuzhiyunEXP2BIG:
610*4882a593Smuzhiyun|--Step 9
611*4882a593Smuzhiyun	fmovel		%d1,%FPCR
612*4882a593Smuzhiyun	movel		(%a0),%d0
613*4882a593Smuzhiyun	bclrb		#sign_bit,(%a0)		| ...setox always returns positive
614*4882a593Smuzhiyun	cmpil		#0,%d0
615*4882a593Smuzhiyun	blt		t_unfl
616*4882a593Smuzhiyun	bra		t_ovfl
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun	.global	setoxm1d
619*4882a593Smuzhiyunsetoxm1d:
620*4882a593Smuzhiyun|--entry point for EXPM1(X), here X is denormalized
621*4882a593Smuzhiyun|--Step 0.
622*4882a593Smuzhiyun	bra		t_extdnrm
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun	.global	setoxm1
626*4882a593Smuzhiyunsetoxm1:
627*4882a593Smuzhiyun|--entry point for EXPM1(X), here X is finite, non-zero, non-NaN
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun|--Step 1.
630*4882a593Smuzhiyun|--Step 1.1
631*4882a593Smuzhiyun	movel		(%a0),%d0	 | ...load part of input X
632*4882a593Smuzhiyun	andil		#0x7FFF0000,%d0	| ...biased expo. of X
633*4882a593Smuzhiyun	cmpil		#0x3FFD0000,%d0	| ...1/4
634*4882a593Smuzhiyun	bges		EM1CON1	 | ...|X| >= 1/4
635*4882a593Smuzhiyun	bra		EM1SM
636*4882a593Smuzhiyun
637*4882a593SmuzhiyunEM1CON1:
638*4882a593Smuzhiyun|--Step 1.3
639*4882a593Smuzhiyun|--The case |X| >= 1/4
640*4882a593Smuzhiyun	movew		4(%a0),%d0	| ...expo. and partial sig. of |X|
641*4882a593Smuzhiyun	cmpil		#0x4004C215,%d0	| ...70log2 rounded up to 16 bits
642*4882a593Smuzhiyun	bles		EM1MAIN	 | ...1/4 <= |X| <= 70log2
643*4882a593Smuzhiyun	bra		EM1BIG
644*4882a593Smuzhiyun
645*4882a593SmuzhiyunEM1MAIN:
646*4882a593Smuzhiyun|--Step 2.
647*4882a593Smuzhiyun|--This is the case:	1/4 <= |X| <= 70 log2.
648*4882a593Smuzhiyun	fmovex		(%a0),%fp0	| ...load input from (a0)
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun	fmovex		%fp0,%fp1
651*4882a593Smuzhiyun	fmuls		#0x42B8AA3B,%fp0	| ...64/log2 * X
652*4882a593Smuzhiyun	fmovemx	%fp2-%fp2/%fp3,-(%a7)		| ...save fp2
653*4882a593Smuzhiyun|	MOVE.W		#$3F81,EM1A4		...prefetch in CB mode
654*4882a593Smuzhiyun	fmovel		%fp0,%d0		| ...N = int( X * 64/log2 )
655*4882a593Smuzhiyun	lea		EXPTBL,%a1
656*4882a593Smuzhiyun	fmovel		%d0,%fp0		| ...convert to floating-format
657*4882a593Smuzhiyun
658*4882a593Smuzhiyun	movel		%d0,L_SCR1(%a6)			| ...save N temporarily
659*4882a593Smuzhiyun	andil		#0x3F,%d0		 | ...D0 is J = N mod 64
660*4882a593Smuzhiyun	lsll		#4,%d0
661*4882a593Smuzhiyun	addal		%d0,%a1			| ...address of 2^(J/64)
662*4882a593Smuzhiyun	movel		L_SCR1(%a6),%d0
663*4882a593Smuzhiyun	asrl		#6,%d0			| ...D0 is M
664*4882a593Smuzhiyun	movel		%d0,L_SCR1(%a6)			| ...save a copy of M
665*4882a593Smuzhiyun|	MOVE.W		#$3FDC,L2		...prefetch L2 in CB mode
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun|--Step 3.
668*4882a593Smuzhiyun|--fp1,fp2 saved on the stack. fp0 is N, fp1 is X,
669*4882a593Smuzhiyun|--a0 points to 2^(J/64), D0 and a1 both contain M
670*4882a593Smuzhiyun	fmovex		%fp0,%fp2
671*4882a593Smuzhiyun	fmuls		#0xBC317218,%fp0	| ...N * L1, L1 = lead(-log2/64)
672*4882a593Smuzhiyun	fmulx		L2,%fp2		| ...N * L2, L1+L2 = -log2/64
673*4882a593Smuzhiyun	faddx		%fp1,%fp0	 | ...X + N*L1
674*4882a593Smuzhiyun	faddx		%fp2,%fp0	 | ...fp0 is R, reduced arg.
675*4882a593Smuzhiyun|	MOVE.W		#$3FC5,EM1A2		...load EM1A2 in cache
676*4882a593Smuzhiyun	addiw		#0x3FFF,%d0		| ...D0 is biased expo. of 2^M
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun|--Step 4.
679*4882a593Smuzhiyun|--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL
680*4882a593Smuzhiyun|-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*(A5 + R*A6)))))
681*4882a593Smuzhiyun|--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R
682*4882a593Smuzhiyun|--[R*S*(A2+S*(A4+S*A6))] + [R+S*(A1+S*(A3+S*A5))]
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun	fmovex		%fp0,%fp1
685*4882a593Smuzhiyun	fmulx		%fp1,%fp1		| ...fp1 IS S = R*R
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun	fmoves		#0x3950097B,%fp2	| ...fp2 IS a6
688*4882a593Smuzhiyun|	MOVE.W		#0,2(%a1)	...load 2^(J/64) in cache
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun	fmulx		%fp1,%fp2		| ...fp2 IS S*A6
691*4882a593Smuzhiyun	fmovex		%fp1,%fp3
692*4882a593Smuzhiyun	fmuls		#0x3AB60B6A,%fp3	| ...fp3 IS S*A5
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun	faddd		EM1A4,%fp2	| ...fp2 IS A4+S*A6
695*4882a593Smuzhiyun	faddd		EM1A3,%fp3	| ...fp3 IS A3+S*A5
696*4882a593Smuzhiyun	movew		%d0,SC(%a6)		| ...SC is 2^(M) in extended
697*4882a593Smuzhiyun	clrw		SC+2(%a6)
698*4882a593Smuzhiyun	movel		#0x80000000,SC+4(%a6)
699*4882a593Smuzhiyun	clrl		SC+8(%a6)
700*4882a593Smuzhiyun
701*4882a593Smuzhiyun	fmulx		%fp1,%fp2		| ...fp2 IS S*(A4+S*A6)
702*4882a593Smuzhiyun	movel		L_SCR1(%a6),%d0		| ...D0 is	M
703*4882a593Smuzhiyun	negw		%d0		| ...D0 is -M
704*4882a593Smuzhiyun	fmulx		%fp1,%fp3		| ...fp3 IS S*(A3+S*A5)
705*4882a593Smuzhiyun	addiw		#0x3FFF,%d0	| ...biased expo. of 2^(-M)
706*4882a593Smuzhiyun	faddd		EM1A2,%fp2	| ...fp2 IS A2+S*(A4+S*A6)
707*4882a593Smuzhiyun	fadds		#0x3F000000,%fp3	| ...fp3 IS A1+S*(A3+S*A5)
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun	fmulx		%fp1,%fp2		| ...fp2 IS S*(A2+S*(A4+S*A6))
710*4882a593Smuzhiyun	oriw		#0x8000,%d0	| ...signed/expo. of -2^(-M)
711*4882a593Smuzhiyun	movew		%d0,ONEBYSC(%a6)	| ...OnebySc is -2^(-M)
712*4882a593Smuzhiyun	clrw		ONEBYSC+2(%a6)
713*4882a593Smuzhiyun	movel		#0x80000000,ONEBYSC+4(%a6)
714*4882a593Smuzhiyun	clrl		ONEBYSC+8(%a6)
715*4882a593Smuzhiyun	fmulx		%fp3,%fp1		| ...fp1 IS S*(A1+S*(A3+S*A5))
716*4882a593Smuzhiyun|					...fp3 released
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun	fmulx		%fp0,%fp2		| ...fp2 IS R*S*(A2+S*(A4+S*A6))
719*4882a593Smuzhiyun	faddx		%fp1,%fp0		| ...fp0 IS R+S*(A1+S*(A3+S*A5))
720*4882a593Smuzhiyun|					...fp1 released
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun	faddx		%fp2,%fp0		| ...fp0 IS EXP(R)-1
723*4882a593Smuzhiyun|					...fp2 released
724*4882a593Smuzhiyun	fmovemx	(%a7)+,%fp2-%fp2/%fp3	| ...fp2 restored
725*4882a593Smuzhiyun
726*4882a593Smuzhiyun|--Step 5
727*4882a593Smuzhiyun|--Compute 2^(J/64)*p
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun	fmulx		(%a1),%fp0	| ...2^(J/64)*(Exp(R)-1)
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun|--Step 6
732*4882a593Smuzhiyun|--Step 6.1
733*4882a593Smuzhiyun	movel		L_SCR1(%a6),%d0		| ...retrieve M
734*4882a593Smuzhiyun	cmpil		#63,%d0
735*4882a593Smuzhiyun	bles		MLE63
736*4882a593Smuzhiyun|--Step 6.2	M >= 64
737*4882a593Smuzhiyun	fmoves		12(%a1),%fp1	| ...fp1 is t
738*4882a593Smuzhiyun	faddx		ONEBYSC(%a6),%fp1	| ...fp1 is t+OnebySc
739*4882a593Smuzhiyun	faddx		%fp1,%fp0		| ...p+(t+OnebySc), fp1 released
740*4882a593Smuzhiyun	faddx		(%a1),%fp0	| ...T+(p+(t+OnebySc))
741*4882a593Smuzhiyun	bras		EM1SCALE
742*4882a593SmuzhiyunMLE63:
743*4882a593Smuzhiyun|--Step 6.3	M <= 63
744*4882a593Smuzhiyun	cmpil		#-3,%d0
745*4882a593Smuzhiyun	bges		MGEN3
746*4882a593SmuzhiyunMLTN3:
747*4882a593Smuzhiyun|--Step 6.4	M <= -4
748*4882a593Smuzhiyun	fadds		12(%a1),%fp0	| ...p+t
749*4882a593Smuzhiyun	faddx		(%a1),%fp0	| ...T+(p+t)
750*4882a593Smuzhiyun	faddx		ONEBYSC(%a6),%fp0	| ...OnebySc + (T+(p+t))
751*4882a593Smuzhiyun	bras		EM1SCALE
752*4882a593SmuzhiyunMGEN3:
753*4882a593Smuzhiyun|--Step 6.5	-3 <= M <= 63
754*4882a593Smuzhiyun	fmovex		(%a1)+,%fp1	| ...fp1 is T
755*4882a593Smuzhiyun	fadds		(%a1),%fp0	| ...fp0 is p+t
756*4882a593Smuzhiyun	faddx		ONEBYSC(%a6),%fp1	| ...fp1 is T+OnebySc
757*4882a593Smuzhiyun	faddx		%fp1,%fp0		| ...(T+OnebySc)+(p+t)
758*4882a593Smuzhiyun
759*4882a593SmuzhiyunEM1SCALE:
760*4882a593Smuzhiyun|--Step 6.6
761*4882a593Smuzhiyun	fmovel		%d1,%FPCR
762*4882a593Smuzhiyun	fmulx		SC(%a6),%fp0
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun	bra		t_frcinx
765*4882a593Smuzhiyun
766*4882a593SmuzhiyunEM1SM:
767*4882a593Smuzhiyun|--Step 7	|X| < 1/4.
768*4882a593Smuzhiyun	cmpil		#0x3FBE0000,%d0	| ...2^(-65)
769*4882a593Smuzhiyun	bges		EM1POLY
770*4882a593Smuzhiyun
771*4882a593SmuzhiyunEM1TINY:
772*4882a593Smuzhiyun|--Step 8	|X| < 2^(-65)
773*4882a593Smuzhiyun	cmpil		#0x00330000,%d0	| ...2^(-16312)
774*4882a593Smuzhiyun	blts		EM12TINY
775*4882a593Smuzhiyun|--Step 8.2
776*4882a593Smuzhiyun	movel		#0x80010000,SC(%a6)	| ...SC is -2^(-16382)
777*4882a593Smuzhiyun	movel		#0x80000000,SC+4(%a6)
778*4882a593Smuzhiyun	clrl		SC+8(%a6)
779*4882a593Smuzhiyun	fmovex		(%a0),%fp0
780*4882a593Smuzhiyun	fmovel		%d1,%FPCR
781*4882a593Smuzhiyun	faddx		SC(%a6),%fp0
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun	bra		t_frcinx
784*4882a593Smuzhiyun
785*4882a593SmuzhiyunEM12TINY:
786*4882a593Smuzhiyun|--Step 8.3
787*4882a593Smuzhiyun	fmovex		(%a0),%fp0
788*4882a593Smuzhiyun	fmuld		TWO140,%fp0
789*4882a593Smuzhiyun	movel		#0x80010000,SC(%a6)
790*4882a593Smuzhiyun	movel		#0x80000000,SC+4(%a6)
791*4882a593Smuzhiyun	clrl		SC+8(%a6)
792*4882a593Smuzhiyun	faddx		SC(%a6),%fp0
793*4882a593Smuzhiyun	fmovel		%d1,%FPCR
794*4882a593Smuzhiyun	fmuld		TWON140,%fp0
795*4882a593Smuzhiyun
796*4882a593Smuzhiyun	bra		t_frcinx
797*4882a593Smuzhiyun
798*4882a593SmuzhiyunEM1POLY:
799*4882a593Smuzhiyun|--Step 9	exp(X)-1 by a simple polynomial
800*4882a593Smuzhiyun	fmovex		(%a0),%fp0	| ...fp0 is X
801*4882a593Smuzhiyun	fmulx		%fp0,%fp0		| ...fp0 is S := X*X
802*4882a593Smuzhiyun	fmovemx	%fp2-%fp2/%fp3,-(%a7)	| ...save fp2
803*4882a593Smuzhiyun	fmoves		#0x2F30CAA8,%fp1	| ...fp1 is B12
804*4882a593Smuzhiyun	fmulx		%fp0,%fp1		| ...fp1 is S*B12
805*4882a593Smuzhiyun	fmoves		#0x310F8290,%fp2	| ...fp2 is B11
806*4882a593Smuzhiyun	fadds		#0x32D73220,%fp1	| ...fp1 is B10+S*B12
807*4882a593Smuzhiyun
808*4882a593Smuzhiyun	fmulx		%fp0,%fp2		| ...fp2 is S*B11
809*4882a593Smuzhiyun	fmulx		%fp0,%fp1		| ...fp1 is S*(B10 + ...
810*4882a593Smuzhiyun
811*4882a593Smuzhiyun	fadds		#0x3493F281,%fp2	| ...fp2 is B9+S*...
812*4882a593Smuzhiyun	faddd		EM1B8,%fp1	| ...fp1 is B8+S*...
813*4882a593Smuzhiyun
814*4882a593Smuzhiyun	fmulx		%fp0,%fp2		| ...fp2 is S*(B9+...
815*4882a593Smuzhiyun	fmulx		%fp0,%fp1		| ...fp1 is S*(B8+...
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun	faddd		EM1B7,%fp2	| ...fp2 is B7+S*...
818*4882a593Smuzhiyun	faddd		EM1B6,%fp1	| ...fp1 is B6+S*...
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun	fmulx		%fp0,%fp2		| ...fp2 is S*(B7+...
821*4882a593Smuzhiyun	fmulx		%fp0,%fp1		| ...fp1 is S*(B6+...
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun	faddd		EM1B5,%fp2	| ...fp2 is B5+S*...
824*4882a593Smuzhiyun	faddd		EM1B4,%fp1	| ...fp1 is B4+S*...
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun	fmulx		%fp0,%fp2		| ...fp2 is S*(B5+...
827*4882a593Smuzhiyun	fmulx		%fp0,%fp1		| ...fp1 is S*(B4+...
828*4882a593Smuzhiyun
829*4882a593Smuzhiyun	faddd		EM1B3,%fp2	| ...fp2 is B3+S*...
830*4882a593Smuzhiyun	faddx		EM1B2,%fp1	| ...fp1 is B2+S*...
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun	fmulx		%fp0,%fp2		| ...fp2 is S*(B3+...
833*4882a593Smuzhiyun	fmulx		%fp0,%fp1		| ...fp1 is S*(B2+...
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun	fmulx		%fp0,%fp2		| ...fp2 is S*S*(B3+...)
836*4882a593Smuzhiyun	fmulx		(%a0),%fp1	| ...fp1 is X*S*(B2...
837*4882a593Smuzhiyun
838*4882a593Smuzhiyun	fmuls		#0x3F000000,%fp0	| ...fp0 is S*B1
839*4882a593Smuzhiyun	faddx		%fp2,%fp1		| ...fp1 is Q
840*4882a593Smuzhiyun|					...fp2 released
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun	fmovemx	(%a7)+,%fp2-%fp2/%fp3	| ...fp2 restored
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun	faddx		%fp1,%fp0		| ...fp0 is S*B1+Q
845*4882a593Smuzhiyun|					...fp1 released
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun	fmovel		%d1,%FPCR
848*4882a593Smuzhiyun	faddx		(%a0),%fp0
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun	bra		t_frcinx
851*4882a593Smuzhiyun
852*4882a593SmuzhiyunEM1BIG:
853*4882a593Smuzhiyun|--Step 10	|X| > 70 log2
854*4882a593Smuzhiyun	movel		(%a0),%d0
855*4882a593Smuzhiyun	cmpil		#0,%d0
856*4882a593Smuzhiyun	bgt		EXPC1
857*4882a593Smuzhiyun|--Step 10.2
858*4882a593Smuzhiyun	fmoves		#0xBF800000,%fp0	| ...fp0 is -1
859*4882a593Smuzhiyun	fmovel		%d1,%FPCR
860*4882a593Smuzhiyun	fadds		#0x00800000,%fp0	| ...-1 + 2^(-126)
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun	bra		t_frcinx
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun	|end
865