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