OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i386/] [math-emu/] [poly_l2.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1623 jcastillo
/*---------------------------------------------------------------------------+
2
 |  poly_l2.c                                                                |
3
 |                                                                           |
4
 | Compute the base 2 log of a FPU_REG, using a polynomial approximation.    |
5
 |                                                                           |
6
 | Copyright (C) 1992,1993,1994                                              |
7
 |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
8
 |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
9
 |                                                                           |
10
 |                                                                           |
11
 +---------------------------------------------------------------------------*/
12
 
13
 
14
#include "exception.h"
15
#include "reg_constant.h"
16
#include "fpu_emu.h"
17
#include "control_w.h"
18
#include "poly.h"
19
 
20
 
21
 
22
static void log2_kernel(FPU_REG const *arg,
23
                        Xsig *accum_result, long int *expon);
24
 
25
 
26
/*--- poly_l2() -------------------------------------------------------------+
27
 |   Base 2 logarithm by a polynomial approximation.                         |
28
 +---------------------------------------------------------------------------*/
29
void    poly_l2(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result)
30
{
31
  long int             exponent, expon, expon_expon;
32
  Xsig                 accumulator, expon_accum, yaccum;
33
  char                 sign;
34
  FPU_REG              x;
35
 
36
 
37
  exponent = arg->exp - EXP_BIAS;
38
 
39
  /* From arg, make a number > sqrt(2)/2 and < sqrt(2) */
40
  if ( arg->sigh > (unsigned)0xb504f334 )
41
    {
42
      /* Treat as  sqrt(2)/2 < arg < 1 */
43
      significand(&x) = - significand(arg);
44
      x.sign = SIGN_NEG;
45
      x.tag = TW_Valid;
46
      x.exp = EXP_BIAS-1;
47
      exponent++;
48
      normalize(&x);
49
    }
50
  else
51
    {
52
      /* Treat as  1 <= arg < sqrt(2) */
53
      x.sigh = arg->sigh - 0x80000000;
54
      x.sigl = arg->sigl;
55
      x.sign = SIGN_POS;
56
      x.tag = TW_Valid;
57
      x.exp = EXP_BIAS;
58
      normalize(&x);
59
    }
60
 
61
  if ( x.tag == TW_Zero )
62
    {
63
      expon = 0;
64
      accumulator.msw = accumulator.midw = accumulator.lsw = 0;
65
    }
66
  else
67
    {
68
      log2_kernel(&x, &accumulator, &expon);
69
    }
70
 
71
  sign = exponent < 0;
72
  if ( sign ) exponent = -exponent;
73
  expon_accum.msw = exponent; expon_accum.midw = expon_accum.lsw = 0;
74
  if ( exponent )
75
    {
76
      expon_expon = 31 + norm_Xsig(&expon_accum);
77
      shr_Xsig(&accumulator, expon_expon - expon);
78
 
79
      if ( sign ^ (x.sign == SIGN_NEG) )
80
        negate_Xsig(&accumulator);
81
      add_Xsig_Xsig(&accumulator, &expon_accum);
82
    }
83
  else
84
    {
85
      expon_expon = expon;
86
      sign = x.sign;
87
    }
88
 
89
  yaccum.lsw = 0; XSIG_LL(yaccum) = significand(y);
90
  mul_Xsig_Xsig(&accumulator, &yaccum);
91
 
92
  expon_expon += round_Xsig(&accumulator);
93
 
94
  if ( accumulator.msw == 0 )
95
    {
96
      reg_move(&CONST_Z, y);
97
    }
98
  else
99
    {
100
      result->exp = expon_expon + y->exp + 1;
101
      significand(result) = XSIG_LL(accumulator);
102
      result->tag = TW_Valid; /* set the tags to Valid */
103
      result->sign = sign ^ y->sign;
104
    }
105
 
106
  return;
107
}
108
 
109
 
110
/*--- poly_l2p1() -----------------------------------------------------------+
111
 |   Base 2 logarithm by a polynomial approximation.                         |
112
 |   log2(x+1)                                                               |
113
 +---------------------------------------------------------------------------*/
114
int     poly_l2p1(FPU_REG const *arg, FPU_REG const *y, FPU_REG *result)
115
{
116
  char                 sign;
117
  long int             exponent;
118
  Xsig                 accumulator, yaccum;
119
 
120
 
121
  sign = arg->sign;
122
 
123
  if ( arg->exp < EXP_BIAS )
124
    {
125
      log2_kernel(arg, &accumulator, &exponent);
126
 
127
      yaccum.lsw = 0;
128
      XSIG_LL(yaccum) = significand(y);
129
      mul_Xsig_Xsig(&accumulator, &yaccum);
130
 
131
      exponent += round_Xsig(&accumulator);
132
 
133
      result->exp = exponent + y->exp + 1;
134
      significand(result) = XSIG_LL(accumulator);
135
      result->tag = TW_Valid; /* set the tags to Valid */
136
      result->sign = sign ^ y->sign;
137
 
138
      return 0;
139
    }
140
  else
141
    {
142
      /* The magnitude of arg is far too large. */
143
      reg_move(y, result);
144
      if ( sign != SIGN_POS )
145
        {
146
          /* Trying to get the log of a negative number. */
147
          return 1;
148
        }
149
      else
150
        {
151
          return 0;
152
        }
153
    }
154
 
155
}
156
 
157
 
158
 
159
 
160
#undef HIPOWER
161
#define HIPOWER 10
162
static const unsigned long long logterms[HIPOWER] =
163
{
164
  0x2a8eca5705fc2ef0LL,
165
  0xf6384ee1d01febceLL,
166
  0x093bb62877cdf642LL,
167
  0x006985d8a9ec439bLL,
168
  0x0005212c4f55a9c8LL,
169
  0x00004326a16927f0LL,
170
  0x0000038d1d80a0e7LL,
171
  0x0000003141cc80c6LL,
172
  0x00000002b1668c9fLL,
173
  0x000000002c7a46aaLL
174
};
175
 
176
static const unsigned long leadterm = 0xb8000000;
177
 
178
 
179
/*--- log2_kernel() ---------------------------------------------------------+
180
 |   Base 2 logarithm by a polynomial approximation.                         |
181
 |   log2(x+1)                                                               |
182
 +---------------------------------------------------------------------------*/
183
static void log2_kernel(FPU_REG const *arg, Xsig *accum_result,
184
                        long int *expon)
185
{
186
  char                 sign;
187
  long int             exponent, adj;
188
  unsigned long long   Xsq;
189
  Xsig                 accumulator, Numer, Denom, argSignif, arg_signif;
190
 
191
  sign = arg->sign;
192
 
193
  exponent = arg->exp - EXP_BIAS;
194
  Numer.lsw = Denom.lsw = 0;
195
  XSIG_LL(Numer) = XSIG_LL(Denom) = significand(arg);
196
  if ( sign == SIGN_POS )
197
    {
198
      shr_Xsig(&Denom, 2 - (1 + exponent));
199
      Denom.msw |= 0x80000000;
200
      div_Xsig(&Numer, &Denom, &argSignif);
201
    }
202
  else
203
    {
204
      shr_Xsig(&Denom, 1 - (1 + exponent));
205
      negate_Xsig(&Denom);
206
      if ( Denom.msw & 0x80000000 )
207
        {
208
          div_Xsig(&Numer, &Denom, &argSignif);
209
          exponent ++;
210
        }
211
      else
212
        {
213
          /* Denom must be 1.0 */
214
          argSignif.lsw = Numer.lsw; argSignif.midw = Numer.midw;
215
          argSignif.msw = Numer.msw;
216
        }
217
    }
218
 
219
#ifndef PECULIAR_486
220
  /* Should check here that  |local_arg|  is within the valid range */
221
  if ( exponent >= -2 )
222
    {
223
      if ( (exponent > -2) ||
224
          (argSignif.msw > (unsigned)0xafb0ccc0) )
225
        {
226
          /* The argument is too large */
227
        }
228
    }
229
#endif PECULIAR_486
230
 
231
  arg_signif.lsw = argSignif.lsw; XSIG_LL(arg_signif) = XSIG_LL(argSignif);
232
  adj = norm_Xsig(&argSignif);
233
  accumulator.lsw = argSignif.lsw; XSIG_LL(accumulator) = XSIG_LL(argSignif);
234
  mul_Xsig_Xsig(&accumulator, &accumulator);
235
  shr_Xsig(&accumulator, 2*(-1 - (1 + exponent + adj)));
236
  Xsq = XSIG_LL(accumulator);
237
  if ( accumulator.lsw & 0x80000000 )
238
    Xsq++;
239
 
240
  accumulator.msw = accumulator.midw = accumulator.lsw = 0;
241
  /* Do the basic fixed point polynomial evaluation */
242
  polynomial_Xsig(&accumulator, &Xsq, logterms, HIPOWER-1);
243
 
244
  mul_Xsig_Xsig(&accumulator, &argSignif);
245
  shr_Xsig(&accumulator, 6 - adj);
246
 
247
  mul32_Xsig(&arg_signif, leadterm);
248
  add_two_Xsig(&accumulator, &arg_signif, &exponent);
249
 
250
  *expon = exponent + 1;
251
  accum_result->lsw = accumulator.lsw;
252
  accum_result->midw = accumulator.midw;
253
  accum_result->msw = accumulator.msw;
254
 
255
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.