162306a36Sopenharmony_ci| 262306a36Sopenharmony_ci| setox.sa 3.1 12/10/90 362306a36Sopenharmony_ci| 462306a36Sopenharmony_ci| The entry point setox computes the exponential of a value. 562306a36Sopenharmony_ci| setoxd does the same except the input value is a denormalized 662306a36Sopenharmony_ci| number. setoxm1 computes exp(X)-1, and setoxm1d computes 762306a36Sopenharmony_ci| exp(X)-1 for denormalized X. 862306a36Sopenharmony_ci| 962306a36Sopenharmony_ci| INPUT 1062306a36Sopenharmony_ci| ----- 1162306a36Sopenharmony_ci| Double-extended value in memory location pointed to by address 1262306a36Sopenharmony_ci| register a0. 1362306a36Sopenharmony_ci| 1462306a36Sopenharmony_ci| OUTPUT 1562306a36Sopenharmony_ci| ------ 1662306a36Sopenharmony_ci| exp(X) or exp(X)-1 returned in floating-point register fp0. 1762306a36Sopenharmony_ci| 1862306a36Sopenharmony_ci| ACCURACY and MONOTONICITY 1962306a36Sopenharmony_ci| ------------------------- 2062306a36Sopenharmony_ci| The returned result is within 0.85 ulps in 64 significant bit, i.e. 2162306a36Sopenharmony_ci| within 0.5001 ulp to 53 bits if the result is subsequently rounded 2262306a36Sopenharmony_ci| to double precision. The result is provably monotonic in double 2362306a36Sopenharmony_ci| precision. 2462306a36Sopenharmony_ci| 2562306a36Sopenharmony_ci| SPEED 2662306a36Sopenharmony_ci| ----- 2762306a36Sopenharmony_ci| Two timings are measured, both in the copy-back mode. The 2862306a36Sopenharmony_ci| first one is measured when the function is invoked the first time 2962306a36Sopenharmony_ci| (so the instructions and data are not in cache), and the 3062306a36Sopenharmony_ci| second one is measured when the function is reinvoked at the same 3162306a36Sopenharmony_ci| input argument. 3262306a36Sopenharmony_ci| 3362306a36Sopenharmony_ci| The program setox takes approximately 210/190 cycles for input 3462306a36Sopenharmony_ci| argument X whose magnitude is less than 16380 log2, which 3562306a36Sopenharmony_ci| is the usual situation. For the less common arguments, 3662306a36Sopenharmony_ci| depending on their values, the program may run faster or slower -- 3762306a36Sopenharmony_ci| but no worse than 10% slower even in the extreme cases. 3862306a36Sopenharmony_ci| 3962306a36Sopenharmony_ci| The program setoxm1 takes approximately ??? / ??? cycles for input 4062306a36Sopenharmony_ci| argument X, 0.25 <= |X| < 70log2. For |X| < 0.25, it takes 4162306a36Sopenharmony_ci| approximately ??? / ??? cycles. For the less common arguments, 4262306a36Sopenharmony_ci| depending on their values, the program may run faster or slower -- 4362306a36Sopenharmony_ci| but no worse than 10% slower even in the extreme cases. 4462306a36Sopenharmony_ci| 4562306a36Sopenharmony_ci| ALGORITHM and IMPLEMENTATION NOTES 4662306a36Sopenharmony_ci| ---------------------------------- 4762306a36Sopenharmony_ci| 4862306a36Sopenharmony_ci| setoxd 4962306a36Sopenharmony_ci| ------ 5062306a36Sopenharmony_ci| Step 1. Set ans := 1.0 5162306a36Sopenharmony_ci| 5262306a36Sopenharmony_ci| Step 2. Return ans := ans + sign(X)*2^(-126). Exit. 5362306a36Sopenharmony_ci| Notes: This will always generate one exception -- inexact. 5462306a36Sopenharmony_ci| 5562306a36Sopenharmony_ci| 5662306a36Sopenharmony_ci| setox 5762306a36Sopenharmony_ci| ----- 5862306a36Sopenharmony_ci| 5962306a36Sopenharmony_ci| Step 1. Filter out extreme cases of input argument. 6062306a36Sopenharmony_ci| 1.1 If |X| >= 2^(-65), go to Step 1.3. 6162306a36Sopenharmony_ci| 1.2 Go to Step 7. 6262306a36Sopenharmony_ci| 1.3 If |X| < 16380 log(2), go to Step 2. 6362306a36Sopenharmony_ci| 1.4 Go to Step 8. 6462306a36Sopenharmony_ci| Notes: The usual case should take the branches 1.1 -> 1.3 -> 2. 6562306a36Sopenharmony_ci| To avoid the use of floating-point comparisons, a 6662306a36Sopenharmony_ci| compact representation of |X| is used. This format is a 6762306a36Sopenharmony_ci| 32-bit integer, the upper (more significant) 16 bits are 6862306a36Sopenharmony_ci| the sign and biased exponent field of |X|; the lower 16 6962306a36Sopenharmony_ci| bits are the 16 most significant fraction (including the 7062306a36Sopenharmony_ci| explicit bit) bits of |X|. Consequently, the comparisons 7162306a36Sopenharmony_ci| in Steps 1.1 and 1.3 can be performed by integer comparison. 7262306a36Sopenharmony_ci| Note also that the constant 16380 log(2) used in Step 1.3 7362306a36Sopenharmony_ci| is also in the compact form. Thus taking the branch 7462306a36Sopenharmony_ci| to Step 2 guarantees |X| < 16380 log(2). There is no harm 7562306a36Sopenharmony_ci| to have a small number of cases where |X| is less than, 7662306a36Sopenharmony_ci| but close to, 16380 log(2) and the branch to Step 9 is 7762306a36Sopenharmony_ci| taken. 7862306a36Sopenharmony_ci| 7962306a36Sopenharmony_ci| Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ). 8062306a36Sopenharmony_ci| 2.1 Set AdjFlag := 0 (indicates the branch 1.3 -> 2 was taken) 8162306a36Sopenharmony_ci| 2.2 N := round-to-nearest-integer( X * 64/log2 ). 8262306a36Sopenharmony_ci| 2.3 Calculate J = N mod 64; so J = 0,1,2,..., or 63. 8362306a36Sopenharmony_ci| 2.4 Calculate M = (N - J)/64; so N = 64M + J. 8462306a36Sopenharmony_ci| 2.5 Calculate the address of the stored value of 2^(J/64). 8562306a36Sopenharmony_ci| 2.6 Create the value Scale = 2^M. 8662306a36Sopenharmony_ci| Notes: The calculation in 2.2 is really performed by 8762306a36Sopenharmony_ci| 8862306a36Sopenharmony_ci| Z := X * constant 8962306a36Sopenharmony_ci| N := round-to-nearest-integer(Z) 9062306a36Sopenharmony_ci| 9162306a36Sopenharmony_ci| where 9262306a36Sopenharmony_ci| 9362306a36Sopenharmony_ci| constant := single-precision( 64/log 2 ). 9462306a36Sopenharmony_ci| 9562306a36Sopenharmony_ci| Using a single-precision constant avoids memory access. 9662306a36Sopenharmony_ci| Another effect of using a single-precision "constant" is 9762306a36Sopenharmony_ci| that the calculated value Z is 9862306a36Sopenharmony_ci| 9962306a36Sopenharmony_ci| Z = X*(64/log2)*(1+eps), |eps| <= 2^(-24). 10062306a36Sopenharmony_ci| 10162306a36Sopenharmony_ci| This error has to be considered later in Steps 3 and 4. 10262306a36Sopenharmony_ci| 10362306a36Sopenharmony_ci| Step 3. Calculate X - N*log2/64. 10462306a36Sopenharmony_ci| 3.1 R := X + N*L1, where L1 := single-precision(-log2/64). 10562306a36Sopenharmony_ci| 3.2 R := R + N*L2, L2 := extended-precision(-log2/64 - L1). 10662306a36Sopenharmony_ci| Notes: a) The way L1 and L2 are chosen ensures L1+L2 approximate 10762306a36Sopenharmony_ci| the value -log2/64 to 88 bits of accuracy. 10862306a36Sopenharmony_ci| b) N*L1 is exact because N is no longer than 22 bits and 10962306a36Sopenharmony_ci| L1 is no longer than 24 bits. 11062306a36Sopenharmony_ci| c) The calculation X+N*L1 is also exact due to cancellation. 11162306a36Sopenharmony_ci| Thus, R is practically X+N(L1+L2) to full 64 bits. 11262306a36Sopenharmony_ci| d) It is important to estimate how large can |R| be after 11362306a36Sopenharmony_ci| Step 3.2. 11462306a36Sopenharmony_ci| 11562306a36Sopenharmony_ci| N = rnd-to-int( X*64/log2 (1+eps) ), |eps|<=2^(-24) 11662306a36Sopenharmony_ci| X*64/log2 (1+eps) = N + f, |f| <= 0.5 11762306a36Sopenharmony_ci| X*64/log2 - N = f - eps*X 64/log2 11862306a36Sopenharmony_ci| X - N*log2/64 = f*log2/64 - eps*X 11962306a36Sopenharmony_ci| 12062306a36Sopenharmony_ci| 12162306a36Sopenharmony_ci| Now |X| <= 16446 log2, thus 12262306a36Sopenharmony_ci| 12362306a36Sopenharmony_ci| |X - N*log2/64| <= (0.5 + 16446/2^(18))*log2/64 12462306a36Sopenharmony_ci| <= 0.57 log2/64. 12562306a36Sopenharmony_ci| This bound will be used in Step 4. 12662306a36Sopenharmony_ci| 12762306a36Sopenharmony_ci| Step 4. Approximate exp(R)-1 by a polynomial 12862306a36Sopenharmony_ci| p = R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5)))) 12962306a36Sopenharmony_ci| Notes: a) In order to reduce memory access, the coefficients are 13062306a36Sopenharmony_ci| made as "short" as possible: A1 (which is 1/2), A4 and A5 13162306a36Sopenharmony_ci| are single precision; A2 and A3 are double precision. 13262306a36Sopenharmony_ci| b) Even with the restrictions above, 13362306a36Sopenharmony_ci| |p - (exp(R)-1)| < 2^(-68.8) for all |R| <= 0.0062. 13462306a36Sopenharmony_ci| Note that 0.0062 is slightly bigger than 0.57 log2/64. 13562306a36Sopenharmony_ci| c) To fully utilize the pipeline, p is separated into 13662306a36Sopenharmony_ci| two independent pieces of roughly equal complexities 13762306a36Sopenharmony_ci| p = [ R + R*S*(A2 + S*A4) ] + 13862306a36Sopenharmony_ci| [ S*(A1 + S*(A3 + S*A5)) ] 13962306a36Sopenharmony_ci| where S = R*R. 14062306a36Sopenharmony_ci| 14162306a36Sopenharmony_ci| Step 5. Compute 2^(J/64)*exp(R) = 2^(J/64)*(1+p) by 14262306a36Sopenharmony_ci| ans := T + ( T*p + t) 14362306a36Sopenharmony_ci| where T and t are the stored values for 2^(J/64). 14462306a36Sopenharmony_ci| Notes: 2^(J/64) is stored as T and t where T+t approximates 14562306a36Sopenharmony_ci| 2^(J/64) to roughly 85 bits; T is in extended precision 14662306a36Sopenharmony_ci| and t is in single precision. Note also that T is rounded 14762306a36Sopenharmony_ci| to 62 bits so that the last two bits of T are zero. The 14862306a36Sopenharmony_ci| reason for such a special form is that T-1, T-2, and T-8 14962306a36Sopenharmony_ci| will all be exact --- a property that will give much 15062306a36Sopenharmony_ci| more accurate computation of the function EXPM1. 15162306a36Sopenharmony_ci| 15262306a36Sopenharmony_ci| Step 6. Reconstruction of exp(X) 15362306a36Sopenharmony_ci| exp(X) = 2^M * 2^(J/64) * exp(R). 15462306a36Sopenharmony_ci| 6.1 If AdjFlag = 0, go to 6.3 15562306a36Sopenharmony_ci| 6.2 ans := ans * AdjScale 15662306a36Sopenharmony_ci| 6.3 Restore the user FPCR 15762306a36Sopenharmony_ci| 6.4 Return ans := ans * Scale. Exit. 15862306a36Sopenharmony_ci| Notes: If AdjFlag = 0, we have X = Mlog2 + Jlog2/64 + R, 15962306a36Sopenharmony_ci| |M| <= 16380, and Scale = 2^M. Moreover, exp(X) will 16062306a36Sopenharmony_ci| neither overflow nor underflow. If AdjFlag = 1, that 16162306a36Sopenharmony_ci| means that 16262306a36Sopenharmony_ci| X = (M1+M)log2 + Jlog2/64 + R, |M1+M| >= 16380. 16362306a36Sopenharmony_ci| Hence, exp(X) may overflow or underflow or neither. 16462306a36Sopenharmony_ci| When that is the case, AdjScale = 2^(M1) where M1 is 16562306a36Sopenharmony_ci| approximately M. Thus 6.2 will never cause over/underflow. 16662306a36Sopenharmony_ci| Possible exception in 6.4 is overflow or underflow. 16762306a36Sopenharmony_ci| The inexact exception is not generated in 6.4. Although 16862306a36Sopenharmony_ci| one can argue that the inexact flag should always be 16962306a36Sopenharmony_ci| raised, to simulate that exception cost to much than the 17062306a36Sopenharmony_ci| flag is worth in practical uses. 17162306a36Sopenharmony_ci| 17262306a36Sopenharmony_ci| Step 7. Return 1 + X. 17362306a36Sopenharmony_ci| 7.1 ans := X 17462306a36Sopenharmony_ci| 7.2 Restore user FPCR. 17562306a36Sopenharmony_ci| 7.3 Return ans := 1 + ans. Exit 17662306a36Sopenharmony_ci| Notes: For non-zero X, the inexact exception will always be 17762306a36Sopenharmony_ci| raised by 7.3. That is the only exception raised by 7.3. 17862306a36Sopenharmony_ci| Note also that we use the FMOVEM instruction to move X 17962306a36Sopenharmony_ci| in Step 7.1 to avoid unnecessary trapping. (Although 18062306a36Sopenharmony_ci| the FMOVEM may not seem relevant since X is normalized, 18162306a36Sopenharmony_ci| the precaution will be useful in the library version of 18262306a36Sopenharmony_ci| this code where the separate entry for denormalized inputs 18362306a36Sopenharmony_ci| will be done away with.) 18462306a36Sopenharmony_ci| 18562306a36Sopenharmony_ci| Step 8. Handle exp(X) where |X| >= 16380log2. 18662306a36Sopenharmony_ci| 8.1 If |X| > 16480 log2, go to Step 9. 18762306a36Sopenharmony_ci| (mimic 2.2 - 2.6) 18862306a36Sopenharmony_ci| 8.2 N := round-to-integer( X * 64/log2 ) 18962306a36Sopenharmony_ci| 8.3 Calculate J = N mod 64, J = 0,1,...,63 19062306a36Sopenharmony_ci| 8.4 K := (N-J)/64, M1 := truncate(K/2), M = K-M1, AdjFlag := 1. 19162306a36Sopenharmony_ci| 8.5 Calculate the address of the stored value 2^(J/64). 19262306a36Sopenharmony_ci| 8.6 Create the values Scale = 2^M, AdjScale = 2^M1. 19362306a36Sopenharmony_ci| 8.7 Go to Step 3. 19462306a36Sopenharmony_ci| Notes: Refer to notes for 2.2 - 2.6. 19562306a36Sopenharmony_ci| 19662306a36Sopenharmony_ci| Step 9. Handle exp(X), |X| > 16480 log2. 19762306a36Sopenharmony_ci| 9.1 If X < 0, go to 9.3 19862306a36Sopenharmony_ci| 9.2 ans := Huge, go to 9.4 19962306a36Sopenharmony_ci| 9.3 ans := Tiny. 20062306a36Sopenharmony_ci| 9.4 Restore user FPCR. 20162306a36Sopenharmony_ci| 9.5 Return ans := ans * ans. Exit. 20262306a36Sopenharmony_ci| Notes: Exp(X) will surely overflow or underflow, depending on 20362306a36Sopenharmony_ci| X's sign. "Huge" and "Tiny" are respectively large/tiny 20462306a36Sopenharmony_ci| extended-precision numbers whose square over/underflow 20562306a36Sopenharmony_ci| with an inexact result. Thus, 9.5 always raises the 20662306a36Sopenharmony_ci| inexact together with either overflow or underflow. 20762306a36Sopenharmony_ci| 20862306a36Sopenharmony_ci| 20962306a36Sopenharmony_ci| setoxm1d 21062306a36Sopenharmony_ci| -------- 21162306a36Sopenharmony_ci| 21262306a36Sopenharmony_ci| Step 1. Set ans := 0 21362306a36Sopenharmony_ci| 21462306a36Sopenharmony_ci| Step 2. Return ans := X + ans. Exit. 21562306a36Sopenharmony_ci| Notes: This will return X with the appropriate rounding 21662306a36Sopenharmony_ci| precision prescribed by the user FPCR. 21762306a36Sopenharmony_ci| 21862306a36Sopenharmony_ci| setoxm1 21962306a36Sopenharmony_ci| ------- 22062306a36Sopenharmony_ci| 22162306a36Sopenharmony_ci| Step 1. Check |X| 22262306a36Sopenharmony_ci| 1.1 If |X| >= 1/4, go to Step 1.3. 22362306a36Sopenharmony_ci| 1.2 Go to Step 7. 22462306a36Sopenharmony_ci| 1.3 If |X| < 70 log(2), go to Step 2. 22562306a36Sopenharmony_ci| 1.4 Go to Step 10. 22662306a36Sopenharmony_ci| Notes: The usual case should take the branches 1.1 -> 1.3 -> 2. 22762306a36Sopenharmony_ci| However, it is conceivable |X| can be small very often 22862306a36Sopenharmony_ci| because EXPM1 is intended to evaluate exp(X)-1 accurately 22962306a36Sopenharmony_ci| when |X| is small. For further details on the comparisons, 23062306a36Sopenharmony_ci| see the notes on Step 1 of setox. 23162306a36Sopenharmony_ci| 23262306a36Sopenharmony_ci| Step 2. Calculate N = round-to-nearest-int( X * 64/log2 ). 23362306a36Sopenharmony_ci| 2.1 N := round-to-nearest-integer( X * 64/log2 ). 23462306a36Sopenharmony_ci| 2.2 Calculate J = N mod 64; so J = 0,1,2,..., or 63. 23562306a36Sopenharmony_ci| 2.3 Calculate M = (N - J)/64; so N = 64M + J. 23662306a36Sopenharmony_ci| 2.4 Calculate the address of the stored value of 2^(J/64). 23762306a36Sopenharmony_ci| 2.5 Create the values Sc = 2^M and OnebySc := -2^(-M). 23862306a36Sopenharmony_ci| Notes: See the notes on Step 2 of setox. 23962306a36Sopenharmony_ci| 24062306a36Sopenharmony_ci| Step 3. Calculate X - N*log2/64. 24162306a36Sopenharmony_ci| 3.1 R := X + N*L1, where L1 := single-precision(-log2/64). 24262306a36Sopenharmony_ci| 3.2 R := R + N*L2, L2 := extended-precision(-log2/64 - L1). 24362306a36Sopenharmony_ci| Notes: Applying the analysis of Step 3 of setox in this case 24462306a36Sopenharmony_ci| shows that |R| <= 0.0055 (note that |X| <= 70 log2 in 24562306a36Sopenharmony_ci| this case). 24662306a36Sopenharmony_ci| 24762306a36Sopenharmony_ci| Step 4. Approximate exp(R)-1 by a polynomial 24862306a36Sopenharmony_ci| p = R+R*R*(A1+R*(A2+R*(A3+R*(A4+R*(A5+R*A6))))) 24962306a36Sopenharmony_ci| Notes: a) In order to reduce memory access, the coefficients are 25062306a36Sopenharmony_ci| made as "short" as possible: A1 (which is 1/2), A5 and A6 25162306a36Sopenharmony_ci| are single precision; A2, A3 and A4 are double precision. 25262306a36Sopenharmony_ci| b) Even with the restriction above, 25362306a36Sopenharmony_ci| |p - (exp(R)-1)| < |R| * 2^(-72.7) 25462306a36Sopenharmony_ci| for all |R| <= 0.0055. 25562306a36Sopenharmony_ci| c) To fully utilize the pipeline, p is separated into 25662306a36Sopenharmony_ci| two independent pieces of roughly equal complexity 25762306a36Sopenharmony_ci| p = [ R*S*(A2 + S*(A4 + S*A6)) ] + 25862306a36Sopenharmony_ci| [ R + S*(A1 + S*(A3 + S*A5)) ] 25962306a36Sopenharmony_ci| where S = R*R. 26062306a36Sopenharmony_ci| 26162306a36Sopenharmony_ci| Step 5. Compute 2^(J/64)*p by 26262306a36Sopenharmony_ci| p := T*p 26362306a36Sopenharmony_ci| where T and t are the stored values for 2^(J/64). 26462306a36Sopenharmony_ci| Notes: 2^(J/64) is stored as T and t where T+t approximates 26562306a36Sopenharmony_ci| 2^(J/64) to roughly 85 bits; T is in extended precision 26662306a36Sopenharmony_ci| and t is in single precision. Note also that T is rounded 26762306a36Sopenharmony_ci| to 62 bits so that the last two bits of T are zero. The 26862306a36Sopenharmony_ci| reason for such a special form is that T-1, T-2, and T-8 26962306a36Sopenharmony_ci| will all be exact --- a property that will be exploited 27062306a36Sopenharmony_ci| in Step 6 below. The total relative error in p is no 27162306a36Sopenharmony_ci| bigger than 2^(-67.7) compared to the final result. 27262306a36Sopenharmony_ci| 27362306a36Sopenharmony_ci| Step 6. Reconstruction of exp(X)-1 27462306a36Sopenharmony_ci| exp(X)-1 = 2^M * ( 2^(J/64) + p - 2^(-M) ). 27562306a36Sopenharmony_ci| 6.1 If M <= 63, go to Step 6.3. 27662306a36Sopenharmony_ci| 6.2 ans := T + (p + (t + OnebySc)). Go to 6.6 27762306a36Sopenharmony_ci| 6.3 If M >= -3, go to 6.5. 27862306a36Sopenharmony_ci| 6.4 ans := (T + (p + t)) + OnebySc. Go to 6.6 27962306a36Sopenharmony_ci| 6.5 ans := (T + OnebySc) + (p + t). 28062306a36Sopenharmony_ci| 6.6 Restore user FPCR. 28162306a36Sopenharmony_ci| 6.7 Return ans := Sc * ans. Exit. 28262306a36Sopenharmony_ci| Notes: The various arrangements of the expressions give accurate 28362306a36Sopenharmony_ci| evaluations. 28462306a36Sopenharmony_ci| 28562306a36Sopenharmony_ci| Step 7. exp(X)-1 for |X| < 1/4. 28662306a36Sopenharmony_ci| 7.1 If |X| >= 2^(-65), go to Step 9. 28762306a36Sopenharmony_ci| 7.2 Go to Step 8. 28862306a36Sopenharmony_ci| 28962306a36Sopenharmony_ci| Step 8. Calculate exp(X)-1, |X| < 2^(-65). 29062306a36Sopenharmony_ci| 8.1 If |X| < 2^(-16312), goto 8.3 29162306a36Sopenharmony_ci| 8.2 Restore FPCR; return ans := X - 2^(-16382). Exit. 29262306a36Sopenharmony_ci| 8.3 X := X * 2^(140). 29362306a36Sopenharmony_ci| 8.4 Restore FPCR; ans := ans - 2^(-16382). 29462306a36Sopenharmony_ci| Return ans := ans*2^(140). Exit 29562306a36Sopenharmony_ci| Notes: The idea is to return "X - tiny" under the user 29662306a36Sopenharmony_ci| precision and rounding modes. To avoid unnecessary 29762306a36Sopenharmony_ci| inefficiency, we stay away from denormalized numbers the 29862306a36Sopenharmony_ci| best we can. For |X| >= 2^(-16312), the straightforward 29962306a36Sopenharmony_ci| 8.2 generates the inexact exception as the case warrants. 30062306a36Sopenharmony_ci| 30162306a36Sopenharmony_ci| Step 9. Calculate exp(X)-1, |X| < 1/4, by a polynomial 30262306a36Sopenharmony_ci| p = X + X*X*(B1 + X*(B2 + ... + X*B12)) 30362306a36Sopenharmony_ci| Notes: a) In order to reduce memory access, the coefficients are 30462306a36Sopenharmony_ci| made as "short" as possible: B1 (which is 1/2), B9 to B12 30562306a36Sopenharmony_ci| are single precision; B3 to B8 are double precision; and 30662306a36Sopenharmony_ci| B2 is double extended. 30762306a36Sopenharmony_ci| b) Even with the restriction above, 30862306a36Sopenharmony_ci| |p - (exp(X)-1)| < |X| 2^(-70.6) 30962306a36Sopenharmony_ci| for all |X| <= 0.251. 31062306a36Sopenharmony_ci| Note that 0.251 is slightly bigger than 1/4. 31162306a36Sopenharmony_ci| c) To fully preserve accuracy, the polynomial is computed 31262306a36Sopenharmony_ci| as X + ( S*B1 + Q ) where S = X*X and 31362306a36Sopenharmony_ci| Q = X*S*(B2 + X*(B3 + ... + X*B12)) 31462306a36Sopenharmony_ci| d) To fully utilize the pipeline, Q is separated into 31562306a36Sopenharmony_ci| two independent pieces of roughly equal complexity 31662306a36Sopenharmony_ci| Q = [ X*S*(B2 + S*(B4 + ... + S*B12)) ] + 31762306a36Sopenharmony_ci| [ S*S*(B3 + S*(B5 + ... + S*B11)) ] 31862306a36Sopenharmony_ci| 31962306a36Sopenharmony_ci| Step 10. Calculate exp(X)-1 for |X| >= 70 log 2. 32062306a36Sopenharmony_ci| 10.1 If X >= 70log2 , exp(X) - 1 = exp(X) for all practical 32162306a36Sopenharmony_ci| purposes. Therefore, go to Step 1 of setox. 32262306a36Sopenharmony_ci| 10.2 If X <= -70log2, exp(X) - 1 = -1 for all practical purposes. 32362306a36Sopenharmony_ci| ans := -1 32462306a36Sopenharmony_ci| Restore user FPCR 32562306a36Sopenharmony_ci| Return ans := ans + 2^(-126). Exit. 32662306a36Sopenharmony_ci| Notes: 10.2 will always create an inexact and return -1 + tiny 32762306a36Sopenharmony_ci| in the user rounding precision and mode. 32862306a36Sopenharmony_ci| 32962306a36Sopenharmony_ci| 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci| Copyright (C) Motorola, Inc. 1990 33262306a36Sopenharmony_ci| All Rights Reserved 33362306a36Sopenharmony_ci| 33462306a36Sopenharmony_ci| For details on the license for this file, please see the 33562306a36Sopenharmony_ci| file, README, in this same directory. 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci|setox idnt 2,1 | Motorola 040 Floating Point Software Package 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci |section 8 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci#include "fpsp.h" 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ciL2: .long 0x3FDC0000,0x82E30865,0x4361C4C6,0x00000000 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ciEXPA3: .long 0x3FA55555,0x55554431 34662306a36Sopenharmony_ciEXPA2: .long 0x3FC55555,0x55554018 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ciHUGE: .long 0x7FFE0000,0xFFFFFFFF,0xFFFFFFFF,0x00000000 34962306a36Sopenharmony_ciTINY: .long 0x00010000,0xFFFFFFFF,0xFFFFFFFF,0x00000000 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ciEM1A4: .long 0x3F811111,0x11174385 35262306a36Sopenharmony_ciEM1A3: .long 0x3FA55555,0x55554F5A 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ciEM1A2: .long 0x3FC55555,0x55555555,0x00000000,0x00000000 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ciEM1B8: .long 0x3EC71DE3,0xA5774682 35762306a36Sopenharmony_ciEM1B7: .long 0x3EFA01A0,0x19D7CB68 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ciEM1B6: .long 0x3F2A01A0,0x1A019DF3 36062306a36Sopenharmony_ciEM1B5: .long 0x3F56C16C,0x16C170E2 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ciEM1B4: .long 0x3F811111,0x11111111 36362306a36Sopenharmony_ciEM1B3: .long 0x3FA55555,0x55555555 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ciEM1B2: .long 0x3FFC0000,0xAAAAAAAA,0xAAAAAAAB 36662306a36Sopenharmony_ci .long 0x00000000 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ciTWO140: .long 0x48B00000,0x00000000 36962306a36Sopenharmony_ciTWON140: .long 0x37300000,0x00000000 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ciEXPTBL: 37262306a36Sopenharmony_ci .long 0x3FFF0000,0x80000000,0x00000000,0x00000000 37362306a36Sopenharmony_ci .long 0x3FFF0000,0x8164D1F3,0xBC030774,0x9F841A9B 37462306a36Sopenharmony_ci .long 0x3FFF0000,0x82CD8698,0xAC2BA1D8,0x9FC1D5B9 37562306a36Sopenharmony_ci .long 0x3FFF0000,0x843A28C3,0xACDE4048,0xA0728369 37662306a36Sopenharmony_ci .long 0x3FFF0000,0x85AAC367,0xCC487B14,0x1FC5C95C 37762306a36Sopenharmony_ci .long 0x3FFF0000,0x871F6196,0x9E8D1010,0x1EE85C9F 37862306a36Sopenharmony_ci .long 0x3FFF0000,0x88980E80,0x92DA8528,0x9FA20729 37962306a36Sopenharmony_ci .long 0x3FFF0000,0x8A14D575,0x496EFD9C,0xA07BF9AF 38062306a36Sopenharmony_ci .long 0x3FFF0000,0x8B95C1E3,0xEA8BD6E8,0xA0020DCF 38162306a36Sopenharmony_ci .long 0x3FFF0000,0x8D1ADF5B,0x7E5BA9E4,0x205A63DA 38262306a36Sopenharmony_ci .long 0x3FFF0000,0x8EA4398B,0x45CD53C0,0x1EB70051 38362306a36Sopenharmony_ci .long 0x3FFF0000,0x9031DC43,0x1466B1DC,0x1F6EB029 38462306a36Sopenharmony_ci .long 0x3FFF0000,0x91C3D373,0xAB11C338,0xA0781494 38562306a36Sopenharmony_ci .long 0x3FFF0000,0x935A2B2F,0x13E6E92C,0x9EB319B0 38662306a36Sopenharmony_ci .long 0x3FFF0000,0x94F4EFA8,0xFEF70960,0x2017457D 38762306a36Sopenharmony_ci .long 0x3FFF0000,0x96942D37,0x20185A00,0x1F11D537 38862306a36Sopenharmony_ci .long 0x3FFF0000,0x9837F051,0x8DB8A970,0x9FB952DD 38962306a36Sopenharmony_ci .long 0x3FFF0000,0x99E04593,0x20B7FA64,0x1FE43087 39062306a36Sopenharmony_ci .long 0x3FFF0000,0x9B8D39B9,0xD54E5538,0x1FA2A818 39162306a36Sopenharmony_ci .long 0x3FFF0000,0x9D3ED9A7,0x2CFFB750,0x1FDE494D 39262306a36Sopenharmony_ci .long 0x3FFF0000,0x9EF53260,0x91A111AC,0x20504890 39362306a36Sopenharmony_ci .long 0x3FFF0000,0xA0B0510F,0xB9714FC4,0xA073691C 39462306a36Sopenharmony_ci .long 0x3FFF0000,0xA2704303,0x0C496818,0x1F9B7A05 39562306a36Sopenharmony_ci .long 0x3FFF0000,0xA43515AE,0x09E680A0,0xA0797126 39662306a36Sopenharmony_ci .long 0x3FFF0000,0xA5FED6A9,0xB15138EC,0xA071A140 39762306a36Sopenharmony_ci .long 0x3FFF0000,0xA7CD93B4,0xE9653568,0x204F62DA 39862306a36Sopenharmony_ci .long 0x3FFF0000,0xA9A15AB4,0xEA7C0EF8,0x1F283C4A 39962306a36Sopenharmony_ci .long 0x3FFF0000,0xAB7A39B5,0xA93ED338,0x9F9A7FDC 40062306a36Sopenharmony_ci .long 0x3FFF0000,0xAD583EEA,0x42A14AC8,0xA05B3FAC 40162306a36Sopenharmony_ci .long 0x3FFF0000,0xAF3B78AD,0x690A4374,0x1FDF2610 40262306a36Sopenharmony_ci .long 0x3FFF0000,0xB123F581,0xD2AC2590,0x9F705F90 40362306a36Sopenharmony_ci .long 0x3FFF0000,0xB311C412,0xA9112488,0x201F678A 40462306a36Sopenharmony_ci .long 0x3FFF0000,0xB504F333,0xF9DE6484,0x1F32FB13 40562306a36Sopenharmony_ci .long 0x3FFF0000,0xB6FD91E3,0x28D17790,0x20038B30 40662306a36Sopenharmony_ci .long 0x3FFF0000,0xB8FBAF47,0x62FB9EE8,0x200DC3CC 40762306a36Sopenharmony_ci .long 0x3FFF0000,0xBAFF5AB2,0x133E45FC,0x9F8B2AE6 40862306a36Sopenharmony_ci .long 0x3FFF0000,0xBD08A39F,0x580C36C0,0xA02BBF70 40962306a36Sopenharmony_ci .long 0x3FFF0000,0xBF1799B6,0x7A731084,0xA00BF518 41062306a36Sopenharmony_ci .long 0x3FFF0000,0xC12C4CCA,0x66709458,0xA041DD41 41162306a36Sopenharmony_ci .long 0x3FFF0000,0xC346CCDA,0x24976408,0x9FDF137B 41262306a36Sopenharmony_ci .long 0x3FFF0000,0xC5672A11,0x5506DADC,0x201F1568 41362306a36Sopenharmony_ci .long 0x3FFF0000,0xC78D74C8,0xABB9B15C,0x1FC13A2E 41462306a36Sopenharmony_ci .long 0x3FFF0000,0xC9B9BD86,0x6E2F27A4,0xA03F8F03 41562306a36Sopenharmony_ci .long 0x3FFF0000,0xCBEC14FE,0xF2727C5C,0x1FF4907D 41662306a36Sopenharmony_ci .long 0x3FFF0000,0xCE248C15,0x1F8480E4,0x9E6E53E4 41762306a36Sopenharmony_ci .long 0x3FFF0000,0xD06333DA,0xEF2B2594,0x1FD6D45C 41862306a36Sopenharmony_ci .long 0x3FFF0000,0xD2A81D91,0xF12AE45C,0xA076EDB9 41962306a36Sopenharmony_ci .long 0x3FFF0000,0xD4F35AAB,0xCFEDFA20,0x9FA6DE21 42062306a36Sopenharmony_ci .long 0x3FFF0000,0xD744FCCA,0xD69D6AF4,0x1EE69A2F 42162306a36Sopenharmony_ci .long 0x3FFF0000,0xD99D15C2,0x78AFD7B4,0x207F439F 42262306a36Sopenharmony_ci .long 0x3FFF0000,0xDBFBB797,0xDAF23754,0x201EC207 42362306a36Sopenharmony_ci .long 0x3FFF0000,0xDE60F482,0x5E0E9124,0x9E8BE175 42462306a36Sopenharmony_ci .long 0x3FFF0000,0xE0CCDEEC,0x2A94E110,0x20032C4B 42562306a36Sopenharmony_ci .long 0x3FFF0000,0xE33F8972,0xBE8A5A50,0x2004DFF5 42662306a36Sopenharmony_ci .long 0x3FFF0000,0xE5B906E7,0x7C8348A8,0x1E72F47A 42762306a36Sopenharmony_ci .long 0x3FFF0000,0xE8396A50,0x3C4BDC68,0x1F722F22 42862306a36Sopenharmony_ci .long 0x3FFF0000,0xEAC0C6E7,0xDD243930,0xA017E945 42962306a36Sopenharmony_ci .long 0x3FFF0000,0xED4F301E,0xD9942B84,0x1F401A5B 43062306a36Sopenharmony_ci .long 0x3FFF0000,0xEFE4B99B,0xDCDAF5CC,0x9FB9A9E3 43162306a36Sopenharmony_ci .long 0x3FFF0000,0xF281773C,0x59FFB138,0x20744C05 43262306a36Sopenharmony_ci .long 0x3FFF0000,0xF5257D15,0x2486CC2C,0x1F773A19 43362306a36Sopenharmony_ci .long 0x3FFF0000,0xF7D0DF73,0x0AD13BB8,0x1FFE90D5 43462306a36Sopenharmony_ci .long 0x3FFF0000,0xFA83B2DB,0x722A033C,0xA041ED22 43562306a36Sopenharmony_ci .long 0x3FFF0000,0xFD3E0C0C,0xF486C174,0x1F853F3A 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci .set ADJFLAG,L_SCR2 43862306a36Sopenharmony_ci .set SCALE,FP_SCR1 43962306a36Sopenharmony_ci .set ADJSCALE,FP_SCR2 44062306a36Sopenharmony_ci .set SC,FP_SCR3 44162306a36Sopenharmony_ci .set ONEBYSC,FP_SCR4 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci | xref t_frcinx 44462306a36Sopenharmony_ci |xref t_extdnrm 44562306a36Sopenharmony_ci |xref t_unfl 44662306a36Sopenharmony_ci |xref t_ovfl 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci .global setoxd 44962306a36Sopenharmony_cisetoxd: 45062306a36Sopenharmony_ci|--entry point for EXP(X), X is denormalized 45162306a36Sopenharmony_ci movel (%a0),%d0 45262306a36Sopenharmony_ci andil #0x80000000,%d0 45362306a36Sopenharmony_ci oril #0x00800000,%d0 | ...sign(X)*2^(-126) 45462306a36Sopenharmony_ci movel %d0,-(%sp) 45562306a36Sopenharmony_ci fmoves #0x3F800000,%fp0 45662306a36Sopenharmony_ci fmovel %d1,%fpcr 45762306a36Sopenharmony_ci fadds (%sp)+,%fp0 45862306a36Sopenharmony_ci bra t_frcinx 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci .global setox 46162306a36Sopenharmony_cisetox: 46262306a36Sopenharmony_ci|--entry point for EXP(X), here X is finite, non-zero, and not NaN's 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci|--Step 1. 46562306a36Sopenharmony_ci movel (%a0),%d0 | ...load part of input X 46662306a36Sopenharmony_ci andil #0x7FFF0000,%d0 | ...biased expo. of X 46762306a36Sopenharmony_ci cmpil #0x3FBE0000,%d0 | ...2^(-65) 46862306a36Sopenharmony_ci bges EXPC1 | ...normal case 46962306a36Sopenharmony_ci bra EXPSM 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ciEXPC1: 47262306a36Sopenharmony_ci|--The case |X| >= 2^(-65) 47362306a36Sopenharmony_ci movew 4(%a0),%d0 | ...expo. and partial sig. of |X| 47462306a36Sopenharmony_ci cmpil #0x400CB167,%d0 | ...16380 log2 trunc. 16 bits 47562306a36Sopenharmony_ci blts EXPMAIN | ...normal case 47662306a36Sopenharmony_ci bra EXPBIG 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ciEXPMAIN: 47962306a36Sopenharmony_ci|--Step 2. 48062306a36Sopenharmony_ci|--This is the normal branch: 2^(-65) <= |X| < 16380 log2. 48162306a36Sopenharmony_ci fmovex (%a0),%fp0 | ...load input from (a0) 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci fmovex %fp0,%fp1 48462306a36Sopenharmony_ci fmuls #0x42B8AA3B,%fp0 | ...64/log2 * X 48562306a36Sopenharmony_ci fmovemx %fp2-%fp2/%fp3,-(%a7) | ...save fp2 48662306a36Sopenharmony_ci movel #0,ADJFLAG(%a6) 48762306a36Sopenharmony_ci fmovel %fp0,%d0 | ...N = int( X * 64/log2 ) 48862306a36Sopenharmony_ci lea EXPTBL,%a1 48962306a36Sopenharmony_ci fmovel %d0,%fp0 | ...convert to floating-format 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci movel %d0,L_SCR1(%a6) | ...save N temporarily 49262306a36Sopenharmony_ci andil #0x3F,%d0 | ...D0 is J = N mod 64 49362306a36Sopenharmony_ci lsll #4,%d0 49462306a36Sopenharmony_ci addal %d0,%a1 | ...address of 2^(J/64) 49562306a36Sopenharmony_ci movel L_SCR1(%a6),%d0 49662306a36Sopenharmony_ci asrl #6,%d0 | ...D0 is M 49762306a36Sopenharmony_ci addiw #0x3FFF,%d0 | ...biased expo. of 2^(M) 49862306a36Sopenharmony_ci movew L2,L_SCR1(%a6) | ...prefetch L2, no need in CB 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ciEXPCONT1: 50162306a36Sopenharmony_ci|--Step 3. 50262306a36Sopenharmony_ci|--fp1,fp2 saved on the stack. fp0 is N, fp1 is X, 50362306a36Sopenharmony_ci|--a0 points to 2^(J/64), D0 is biased expo. of 2^(M) 50462306a36Sopenharmony_ci fmovex %fp0,%fp2 50562306a36Sopenharmony_ci fmuls #0xBC317218,%fp0 | ...N * L1, L1 = lead(-log2/64) 50662306a36Sopenharmony_ci fmulx L2,%fp2 | ...N * L2, L1+L2 = -log2/64 50762306a36Sopenharmony_ci faddx %fp1,%fp0 | ...X + N*L1 50862306a36Sopenharmony_ci faddx %fp2,%fp0 | ...fp0 is R, reduced arg. 50962306a36Sopenharmony_ci| MOVE.W #$3FA5,EXPA3 ...load EXPA3 in cache 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci|--Step 4. 51262306a36Sopenharmony_ci|--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL 51362306a36Sopenharmony_ci|-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*A5)))) 51462306a36Sopenharmony_ci|--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R 51562306a36Sopenharmony_ci|--[R+R*S*(A2+S*A4)] + [S*(A1+S*(A3+S*A5))] 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci fmovex %fp0,%fp1 51862306a36Sopenharmony_ci fmulx %fp1,%fp1 | ...fp1 IS S = R*R 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci fmoves #0x3AB60B70,%fp2 | ...fp2 IS A5 52162306a36Sopenharmony_ci| MOVE.W #0,2(%a1) ...load 2^(J/64) in cache 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci fmulx %fp1,%fp2 | ...fp2 IS S*A5 52462306a36Sopenharmony_ci fmovex %fp1,%fp3 52562306a36Sopenharmony_ci fmuls #0x3C088895,%fp3 | ...fp3 IS S*A4 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci faddd EXPA3,%fp2 | ...fp2 IS A3+S*A5 52862306a36Sopenharmony_ci faddd EXPA2,%fp3 | ...fp3 IS A2+S*A4 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci fmulx %fp1,%fp2 | ...fp2 IS S*(A3+S*A5) 53162306a36Sopenharmony_ci movew %d0,SCALE(%a6) | ...SCALE is 2^(M) in extended 53262306a36Sopenharmony_ci clrw SCALE+2(%a6) 53362306a36Sopenharmony_ci movel #0x80000000,SCALE+4(%a6) 53462306a36Sopenharmony_ci clrl SCALE+8(%a6) 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci fmulx %fp1,%fp3 | ...fp3 IS S*(A2+S*A4) 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci fadds #0x3F000000,%fp2 | ...fp2 IS A1+S*(A3+S*A5) 53962306a36Sopenharmony_ci fmulx %fp0,%fp3 | ...fp3 IS R*S*(A2+S*A4) 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci fmulx %fp1,%fp2 | ...fp2 IS S*(A1+S*(A3+S*A5)) 54262306a36Sopenharmony_ci faddx %fp3,%fp0 | ...fp0 IS R+R*S*(A2+S*A4), 54362306a36Sopenharmony_ci| ...fp3 released 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci fmovex (%a1)+,%fp1 | ...fp1 is lead. pt. of 2^(J/64) 54662306a36Sopenharmony_ci faddx %fp2,%fp0 | ...fp0 is EXP(R) - 1 54762306a36Sopenharmony_ci| ...fp2 released 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci|--Step 5 55062306a36Sopenharmony_ci|--final reconstruction process 55162306a36Sopenharmony_ci|--EXP(X) = 2^M * ( 2^(J/64) + 2^(J/64)*(EXP(R)-1) ) 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci fmulx %fp1,%fp0 | ...2^(J/64)*(Exp(R)-1) 55462306a36Sopenharmony_ci fmovemx (%a7)+,%fp2-%fp2/%fp3 | ...fp2 restored 55562306a36Sopenharmony_ci fadds (%a1),%fp0 | ...accurate 2^(J/64) 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci faddx %fp1,%fp0 | ...2^(J/64) + 2^(J/64)*... 55862306a36Sopenharmony_ci movel ADJFLAG(%a6),%d0 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci|--Step 6 56162306a36Sopenharmony_ci tstl %d0 56262306a36Sopenharmony_ci beqs NORMAL 56362306a36Sopenharmony_ciADJUST: 56462306a36Sopenharmony_ci fmulx ADJSCALE(%a6),%fp0 56562306a36Sopenharmony_ciNORMAL: 56662306a36Sopenharmony_ci fmovel %d1,%FPCR | ...restore user FPCR 56762306a36Sopenharmony_ci fmulx SCALE(%a6),%fp0 | ...multiply 2^(M) 56862306a36Sopenharmony_ci bra t_frcinx 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ciEXPSM: 57162306a36Sopenharmony_ci|--Step 7 57262306a36Sopenharmony_ci fmovemx (%a0),%fp0-%fp0 | ...in case X is denormalized 57362306a36Sopenharmony_ci fmovel %d1,%FPCR 57462306a36Sopenharmony_ci fadds #0x3F800000,%fp0 | ...1+X in user mode 57562306a36Sopenharmony_ci bra t_frcinx 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ciEXPBIG: 57862306a36Sopenharmony_ci|--Step 8 57962306a36Sopenharmony_ci cmpil #0x400CB27C,%d0 | ...16480 log2 58062306a36Sopenharmony_ci bgts EXP2BIG 58162306a36Sopenharmony_ci|--Steps 8.2 -- 8.6 58262306a36Sopenharmony_ci fmovex (%a0),%fp0 | ...load input from (a0) 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci fmovex %fp0,%fp1 58562306a36Sopenharmony_ci fmuls #0x42B8AA3B,%fp0 | ...64/log2 * X 58662306a36Sopenharmony_ci fmovemx %fp2-%fp2/%fp3,-(%a7) | ...save fp2 58762306a36Sopenharmony_ci movel #1,ADJFLAG(%a6) 58862306a36Sopenharmony_ci fmovel %fp0,%d0 | ...N = int( X * 64/log2 ) 58962306a36Sopenharmony_ci lea EXPTBL,%a1 59062306a36Sopenharmony_ci fmovel %d0,%fp0 | ...convert to floating-format 59162306a36Sopenharmony_ci movel %d0,L_SCR1(%a6) | ...save N temporarily 59262306a36Sopenharmony_ci andil #0x3F,%d0 | ...D0 is J = N mod 64 59362306a36Sopenharmony_ci lsll #4,%d0 59462306a36Sopenharmony_ci addal %d0,%a1 | ...address of 2^(J/64) 59562306a36Sopenharmony_ci movel L_SCR1(%a6),%d0 59662306a36Sopenharmony_ci asrl #6,%d0 | ...D0 is K 59762306a36Sopenharmony_ci movel %d0,L_SCR1(%a6) | ...save K temporarily 59862306a36Sopenharmony_ci asrl #1,%d0 | ...D0 is M1 59962306a36Sopenharmony_ci subl %d0,L_SCR1(%a6) | ...a1 is M 60062306a36Sopenharmony_ci addiw #0x3FFF,%d0 | ...biased expo. of 2^(M1) 60162306a36Sopenharmony_ci movew %d0,ADJSCALE(%a6) | ...ADJSCALE := 2^(M1) 60262306a36Sopenharmony_ci clrw ADJSCALE+2(%a6) 60362306a36Sopenharmony_ci movel #0x80000000,ADJSCALE+4(%a6) 60462306a36Sopenharmony_ci clrl ADJSCALE+8(%a6) 60562306a36Sopenharmony_ci movel L_SCR1(%a6),%d0 | ...D0 is M 60662306a36Sopenharmony_ci addiw #0x3FFF,%d0 | ...biased expo. of 2^(M) 60762306a36Sopenharmony_ci bra EXPCONT1 | ...go back to Step 3 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ciEXP2BIG: 61062306a36Sopenharmony_ci|--Step 9 61162306a36Sopenharmony_ci fmovel %d1,%FPCR 61262306a36Sopenharmony_ci movel (%a0),%d0 61362306a36Sopenharmony_ci bclrb #sign_bit,(%a0) | ...setox always returns positive 61462306a36Sopenharmony_ci cmpil #0,%d0 61562306a36Sopenharmony_ci blt t_unfl 61662306a36Sopenharmony_ci bra t_ovfl 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci .global setoxm1d 61962306a36Sopenharmony_cisetoxm1d: 62062306a36Sopenharmony_ci|--entry point for EXPM1(X), here X is denormalized 62162306a36Sopenharmony_ci|--Step 0. 62262306a36Sopenharmony_ci bra t_extdnrm 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci .global setoxm1 62662306a36Sopenharmony_cisetoxm1: 62762306a36Sopenharmony_ci|--entry point for EXPM1(X), here X is finite, non-zero, non-NaN 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci|--Step 1. 63062306a36Sopenharmony_ci|--Step 1.1 63162306a36Sopenharmony_ci movel (%a0),%d0 | ...load part of input X 63262306a36Sopenharmony_ci andil #0x7FFF0000,%d0 | ...biased expo. of X 63362306a36Sopenharmony_ci cmpil #0x3FFD0000,%d0 | ...1/4 63462306a36Sopenharmony_ci bges EM1CON1 | ...|X| >= 1/4 63562306a36Sopenharmony_ci bra EM1SM 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ciEM1CON1: 63862306a36Sopenharmony_ci|--Step 1.3 63962306a36Sopenharmony_ci|--The case |X| >= 1/4 64062306a36Sopenharmony_ci movew 4(%a0),%d0 | ...expo. and partial sig. of |X| 64162306a36Sopenharmony_ci cmpil #0x4004C215,%d0 | ...70log2 rounded up to 16 bits 64262306a36Sopenharmony_ci bles EM1MAIN | ...1/4 <= |X| <= 70log2 64362306a36Sopenharmony_ci bra EM1BIG 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ciEM1MAIN: 64662306a36Sopenharmony_ci|--Step 2. 64762306a36Sopenharmony_ci|--This is the case: 1/4 <= |X| <= 70 log2. 64862306a36Sopenharmony_ci fmovex (%a0),%fp0 | ...load input from (a0) 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci fmovex %fp0,%fp1 65162306a36Sopenharmony_ci fmuls #0x42B8AA3B,%fp0 | ...64/log2 * X 65262306a36Sopenharmony_ci fmovemx %fp2-%fp2/%fp3,-(%a7) | ...save fp2 65362306a36Sopenharmony_ci| MOVE.W #$3F81,EM1A4 ...prefetch in CB mode 65462306a36Sopenharmony_ci fmovel %fp0,%d0 | ...N = int( X * 64/log2 ) 65562306a36Sopenharmony_ci lea EXPTBL,%a1 65662306a36Sopenharmony_ci fmovel %d0,%fp0 | ...convert to floating-format 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci movel %d0,L_SCR1(%a6) | ...save N temporarily 65962306a36Sopenharmony_ci andil #0x3F,%d0 | ...D0 is J = N mod 64 66062306a36Sopenharmony_ci lsll #4,%d0 66162306a36Sopenharmony_ci addal %d0,%a1 | ...address of 2^(J/64) 66262306a36Sopenharmony_ci movel L_SCR1(%a6),%d0 66362306a36Sopenharmony_ci asrl #6,%d0 | ...D0 is M 66462306a36Sopenharmony_ci movel %d0,L_SCR1(%a6) | ...save a copy of M 66562306a36Sopenharmony_ci| MOVE.W #$3FDC,L2 ...prefetch L2 in CB mode 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci|--Step 3. 66862306a36Sopenharmony_ci|--fp1,fp2 saved on the stack. fp0 is N, fp1 is X, 66962306a36Sopenharmony_ci|--a0 points to 2^(J/64), D0 and a1 both contain M 67062306a36Sopenharmony_ci fmovex %fp0,%fp2 67162306a36Sopenharmony_ci fmuls #0xBC317218,%fp0 | ...N * L1, L1 = lead(-log2/64) 67262306a36Sopenharmony_ci fmulx L2,%fp2 | ...N * L2, L1+L2 = -log2/64 67362306a36Sopenharmony_ci faddx %fp1,%fp0 | ...X + N*L1 67462306a36Sopenharmony_ci faddx %fp2,%fp0 | ...fp0 is R, reduced arg. 67562306a36Sopenharmony_ci| MOVE.W #$3FC5,EM1A2 ...load EM1A2 in cache 67662306a36Sopenharmony_ci addiw #0x3FFF,%d0 | ...D0 is biased expo. of 2^M 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci|--Step 4. 67962306a36Sopenharmony_ci|--WE NOW COMPUTE EXP(R)-1 BY A POLYNOMIAL 68062306a36Sopenharmony_ci|-- R + R*R*(A1 + R*(A2 + R*(A3 + R*(A4 + R*(A5 + R*A6))))) 68162306a36Sopenharmony_ci|--TO FULLY UTILIZE THE PIPELINE, WE COMPUTE S = R*R 68262306a36Sopenharmony_ci|--[R*S*(A2+S*(A4+S*A6))] + [R+S*(A1+S*(A3+S*A5))] 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci fmovex %fp0,%fp1 68562306a36Sopenharmony_ci fmulx %fp1,%fp1 | ...fp1 IS S = R*R 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci fmoves #0x3950097B,%fp2 | ...fp2 IS a6 68862306a36Sopenharmony_ci| MOVE.W #0,2(%a1) ...load 2^(J/64) in cache 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci fmulx %fp1,%fp2 | ...fp2 IS S*A6 69162306a36Sopenharmony_ci fmovex %fp1,%fp3 69262306a36Sopenharmony_ci fmuls #0x3AB60B6A,%fp3 | ...fp3 IS S*A5 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci faddd EM1A4,%fp2 | ...fp2 IS A4+S*A6 69562306a36Sopenharmony_ci faddd EM1A3,%fp3 | ...fp3 IS A3+S*A5 69662306a36Sopenharmony_ci movew %d0,SC(%a6) | ...SC is 2^(M) in extended 69762306a36Sopenharmony_ci clrw SC+2(%a6) 69862306a36Sopenharmony_ci movel #0x80000000,SC+4(%a6) 69962306a36Sopenharmony_ci clrl SC+8(%a6) 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci fmulx %fp1,%fp2 | ...fp2 IS S*(A4+S*A6) 70262306a36Sopenharmony_ci movel L_SCR1(%a6),%d0 | ...D0 is M 70362306a36Sopenharmony_ci negw %d0 | ...D0 is -M 70462306a36Sopenharmony_ci fmulx %fp1,%fp3 | ...fp3 IS S*(A3+S*A5) 70562306a36Sopenharmony_ci addiw #0x3FFF,%d0 | ...biased expo. of 2^(-M) 70662306a36Sopenharmony_ci faddd EM1A2,%fp2 | ...fp2 IS A2+S*(A4+S*A6) 70762306a36Sopenharmony_ci fadds #0x3F000000,%fp3 | ...fp3 IS A1+S*(A3+S*A5) 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci fmulx %fp1,%fp2 | ...fp2 IS S*(A2+S*(A4+S*A6)) 71062306a36Sopenharmony_ci oriw #0x8000,%d0 | ...signed/expo. of -2^(-M) 71162306a36Sopenharmony_ci movew %d0,ONEBYSC(%a6) | ...OnebySc is -2^(-M) 71262306a36Sopenharmony_ci clrw ONEBYSC+2(%a6) 71362306a36Sopenharmony_ci movel #0x80000000,ONEBYSC+4(%a6) 71462306a36Sopenharmony_ci clrl ONEBYSC+8(%a6) 71562306a36Sopenharmony_ci fmulx %fp3,%fp1 | ...fp1 IS S*(A1+S*(A3+S*A5)) 71662306a36Sopenharmony_ci| ...fp3 released 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci fmulx %fp0,%fp2 | ...fp2 IS R*S*(A2+S*(A4+S*A6)) 71962306a36Sopenharmony_ci faddx %fp1,%fp0 | ...fp0 IS R+S*(A1+S*(A3+S*A5)) 72062306a36Sopenharmony_ci| ...fp1 released 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci faddx %fp2,%fp0 | ...fp0 IS EXP(R)-1 72362306a36Sopenharmony_ci| ...fp2 released 72462306a36Sopenharmony_ci fmovemx (%a7)+,%fp2-%fp2/%fp3 | ...fp2 restored 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci|--Step 5 72762306a36Sopenharmony_ci|--Compute 2^(J/64)*p 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci fmulx (%a1),%fp0 | ...2^(J/64)*(Exp(R)-1) 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci|--Step 6 73262306a36Sopenharmony_ci|--Step 6.1 73362306a36Sopenharmony_ci movel L_SCR1(%a6),%d0 | ...retrieve M 73462306a36Sopenharmony_ci cmpil #63,%d0 73562306a36Sopenharmony_ci bles MLE63 73662306a36Sopenharmony_ci|--Step 6.2 M >= 64 73762306a36Sopenharmony_ci fmoves 12(%a1),%fp1 | ...fp1 is t 73862306a36Sopenharmony_ci faddx ONEBYSC(%a6),%fp1 | ...fp1 is t+OnebySc 73962306a36Sopenharmony_ci faddx %fp1,%fp0 | ...p+(t+OnebySc), fp1 released 74062306a36Sopenharmony_ci faddx (%a1),%fp0 | ...T+(p+(t+OnebySc)) 74162306a36Sopenharmony_ci bras EM1SCALE 74262306a36Sopenharmony_ciMLE63: 74362306a36Sopenharmony_ci|--Step 6.3 M <= 63 74462306a36Sopenharmony_ci cmpil #-3,%d0 74562306a36Sopenharmony_ci bges MGEN3 74662306a36Sopenharmony_ciMLTN3: 74762306a36Sopenharmony_ci|--Step 6.4 M <= -4 74862306a36Sopenharmony_ci fadds 12(%a1),%fp0 | ...p+t 74962306a36Sopenharmony_ci faddx (%a1),%fp0 | ...T+(p+t) 75062306a36Sopenharmony_ci faddx ONEBYSC(%a6),%fp0 | ...OnebySc + (T+(p+t)) 75162306a36Sopenharmony_ci bras EM1SCALE 75262306a36Sopenharmony_ciMGEN3: 75362306a36Sopenharmony_ci|--Step 6.5 -3 <= M <= 63 75462306a36Sopenharmony_ci fmovex (%a1)+,%fp1 | ...fp1 is T 75562306a36Sopenharmony_ci fadds (%a1),%fp0 | ...fp0 is p+t 75662306a36Sopenharmony_ci faddx ONEBYSC(%a6),%fp1 | ...fp1 is T+OnebySc 75762306a36Sopenharmony_ci faddx %fp1,%fp0 | ...(T+OnebySc)+(p+t) 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ciEM1SCALE: 76062306a36Sopenharmony_ci|--Step 6.6 76162306a36Sopenharmony_ci fmovel %d1,%FPCR 76262306a36Sopenharmony_ci fmulx SC(%a6),%fp0 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci bra t_frcinx 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ciEM1SM: 76762306a36Sopenharmony_ci|--Step 7 |X| < 1/4. 76862306a36Sopenharmony_ci cmpil #0x3FBE0000,%d0 | ...2^(-65) 76962306a36Sopenharmony_ci bges EM1POLY 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ciEM1TINY: 77262306a36Sopenharmony_ci|--Step 8 |X| < 2^(-65) 77362306a36Sopenharmony_ci cmpil #0x00330000,%d0 | ...2^(-16312) 77462306a36Sopenharmony_ci blts EM12TINY 77562306a36Sopenharmony_ci|--Step 8.2 77662306a36Sopenharmony_ci movel #0x80010000,SC(%a6) | ...SC is -2^(-16382) 77762306a36Sopenharmony_ci movel #0x80000000,SC+4(%a6) 77862306a36Sopenharmony_ci clrl SC+8(%a6) 77962306a36Sopenharmony_ci fmovex (%a0),%fp0 78062306a36Sopenharmony_ci fmovel %d1,%FPCR 78162306a36Sopenharmony_ci faddx SC(%a6),%fp0 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci bra t_frcinx 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ciEM12TINY: 78662306a36Sopenharmony_ci|--Step 8.3 78762306a36Sopenharmony_ci fmovex (%a0),%fp0 78862306a36Sopenharmony_ci fmuld TWO140,%fp0 78962306a36Sopenharmony_ci movel #0x80010000,SC(%a6) 79062306a36Sopenharmony_ci movel #0x80000000,SC+4(%a6) 79162306a36Sopenharmony_ci clrl SC+8(%a6) 79262306a36Sopenharmony_ci faddx SC(%a6),%fp0 79362306a36Sopenharmony_ci fmovel %d1,%FPCR 79462306a36Sopenharmony_ci fmuld TWON140,%fp0 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci bra t_frcinx 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ciEM1POLY: 79962306a36Sopenharmony_ci|--Step 9 exp(X)-1 by a simple polynomial 80062306a36Sopenharmony_ci fmovex (%a0),%fp0 | ...fp0 is X 80162306a36Sopenharmony_ci fmulx %fp0,%fp0 | ...fp0 is S := X*X 80262306a36Sopenharmony_ci fmovemx %fp2-%fp2/%fp3,-(%a7) | ...save fp2 80362306a36Sopenharmony_ci fmoves #0x2F30CAA8,%fp1 | ...fp1 is B12 80462306a36Sopenharmony_ci fmulx %fp0,%fp1 | ...fp1 is S*B12 80562306a36Sopenharmony_ci fmoves #0x310F8290,%fp2 | ...fp2 is B11 80662306a36Sopenharmony_ci fadds #0x32D73220,%fp1 | ...fp1 is B10+S*B12 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci fmulx %fp0,%fp2 | ...fp2 is S*B11 80962306a36Sopenharmony_ci fmulx %fp0,%fp1 | ...fp1 is S*(B10 + ... 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci fadds #0x3493F281,%fp2 | ...fp2 is B9+S*... 81262306a36Sopenharmony_ci faddd EM1B8,%fp1 | ...fp1 is B8+S*... 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci fmulx %fp0,%fp2 | ...fp2 is S*(B9+... 81562306a36Sopenharmony_ci fmulx %fp0,%fp1 | ...fp1 is S*(B8+... 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci faddd EM1B7,%fp2 | ...fp2 is B7+S*... 81862306a36Sopenharmony_ci faddd EM1B6,%fp1 | ...fp1 is B6+S*... 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci fmulx %fp0,%fp2 | ...fp2 is S*(B7+... 82162306a36Sopenharmony_ci fmulx %fp0,%fp1 | ...fp1 is S*(B6+... 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci faddd EM1B5,%fp2 | ...fp2 is B5+S*... 82462306a36Sopenharmony_ci faddd EM1B4,%fp1 | ...fp1 is B4+S*... 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci fmulx %fp0,%fp2 | ...fp2 is S*(B5+... 82762306a36Sopenharmony_ci fmulx %fp0,%fp1 | ...fp1 is S*(B4+... 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci faddd EM1B3,%fp2 | ...fp2 is B3+S*... 83062306a36Sopenharmony_ci faddx EM1B2,%fp1 | ...fp1 is B2+S*... 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci fmulx %fp0,%fp2 | ...fp2 is S*(B3+... 83362306a36Sopenharmony_ci fmulx %fp0,%fp1 | ...fp1 is S*(B2+... 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci fmulx %fp0,%fp2 | ...fp2 is S*S*(B3+...) 83662306a36Sopenharmony_ci fmulx (%a0),%fp1 | ...fp1 is X*S*(B2... 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci fmuls #0x3F000000,%fp0 | ...fp0 is S*B1 83962306a36Sopenharmony_ci faddx %fp2,%fp1 | ...fp1 is Q 84062306a36Sopenharmony_ci| ...fp2 released 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci fmovemx (%a7)+,%fp2-%fp2/%fp3 | ...fp2 restored 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci faddx %fp1,%fp0 | ...fp0 is S*B1+Q 84562306a36Sopenharmony_ci| ...fp1 released 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci fmovel %d1,%FPCR 84862306a36Sopenharmony_ci faddx (%a0),%fp0 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci bra t_frcinx 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ciEM1BIG: 85362306a36Sopenharmony_ci|--Step 10 |X| > 70 log2 85462306a36Sopenharmony_ci movel (%a0),%d0 85562306a36Sopenharmony_ci cmpil #0,%d0 85662306a36Sopenharmony_ci bgt EXPC1 85762306a36Sopenharmony_ci|--Step 10.2 85862306a36Sopenharmony_ci fmoves #0xBF800000,%fp0 | ...fp0 is -1 85962306a36Sopenharmony_ci fmovel %d1,%FPCR 86062306a36Sopenharmony_ci fadds #0x00800000,%fp0 | ...-1 + 2^(-126) 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci bra t_frcinx 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci |end 865