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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [i386/] [math-emu/] [fpu_debug.c] - Blame information for rev 199

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

Line No. Rev Author Line
1 199 simons
/* Interface with ptrace and core-dumping routines */
2
 
3
 
4
#include "fpu_system.h"
5
#include "exception.h"
6
#include "reg_constant.h"
7
#include "fpu_emu.h"
8
#include "control_w.h"
9
#include "status_w.h"
10
 
11
 
12
#define EXTENDED_Ebias 0x3fff
13
#define EXTENDED_Emin (-0x3ffe)  /* smallest valid exponent */
14
 
15
#define DOUBLE_Emax 1023         /* largest valid exponent */
16
#define DOUBLE_Ebias 1023
17
#define DOUBLE_Emin (-1022)      /* smallest valid exponent */
18
 
19
#define SINGLE_Emax 127          /* largest valid exponent */
20
#define SINGLE_Ebias 127
21
#define SINGLE_Emin (-126)       /* smallest valid exponent */
22
 
23
 
24
/* Copy and paste from round_to_int. Original comments maintained */
25
/*===========================================================================*/
26
 
27
/* r gets mangled such that sig is int, sign:
28
   it is NOT normalized */
29
/* The return value (in eax) is zero if the result is exact,
30
   if bits are changed due to rounding, truncation, etc, then
31
   a non-zero value is returned */
32
/* Overflow is signalled by a non-zero return value (in eax).
33
   In the case of overflow, the returned significand always has the
34
   largest possible value */
35
 
36
static int round_to_int_cwd(FPU_REG *r, long int user_control_word)
37
{
38
  char     very_big;
39
  unsigned eax;
40
 
41
  if (r->tag == TW_Zero)
42
    {
43
      /* Make sure that zero is returned */
44
      significand(r) = 0;
45
      return 0;        /* o.k. */
46
    }
47
 
48
  if (r->exp > EXP_BIAS + 63)
49
    {
50
      r->sigl = r->sigh = ~0;      /* The largest representable number */
51
      return 1;        /* overflow */
52
    }
53
 
54
  eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
55
  very_big = !(~(r->sigh) | ~(r->sigl));  /* test for 0xfff...fff */
56
#define half_or_more    (eax & 0x80000000)
57
#define frac_part       (eax)
58
#define more_than_half  ((eax & 0x80000001) == 0x80000001)
59
  switch (user_control_word & CW_RC)
60
    {
61
    case RC_RND:
62
      if ( more_than_half                       /* nearest */
63
          || (half_or_more && (r->sigl & 1)) )  /* odd -> even */
64
        {
65
          if ( very_big ) return 1;        /* overflow */
66
          significand(r) ++;
67
          return PRECISION_LOST_UP;
68
        }
69
      break;
70
    case RC_DOWN:
71
      if (frac_part && r->sign)
72
        {
73
          if ( very_big ) return 1;        /* overflow */
74
          significand(r) ++;
75
          return PRECISION_LOST_UP;
76
        }
77
      break;
78
    case RC_UP:
79
      if (frac_part && !r->sign)
80
        {
81
          if ( very_big ) return 1;        /* overflow */
82
          significand(r) ++;
83
          return PRECISION_LOST_UP;
84
        }
85
      break;
86
    case RC_CHOP:
87
      break;
88
    }
89
 
90
  return eax ? PRECISION_LOST_DOWN : 0;
91
 
92
}
93
 
94
 
95
 
96
/* Conver a number in the emulator format to the
97
 * hardware format.
98
 * Taken from the emulator sources, function reg_load_extended
99
 */
100
 
101
/* Get a long double from the debugger */
102
void hardreg_to_softreg(const char hardreg[10],
103
                              FPU_REG *soft_reg)
104
 
105
{
106
        unsigned long sigl, sigh, exp;
107
 
108
        sigl = *((unsigned long *) hardreg);
109
        sigh = *(1 + (unsigned long *) hardreg);
110
        exp = *(4 + (unsigned short *) hardreg);
111
 
112
        soft_reg->tag = TW_Valid;   /* Default */
113
        soft_reg->sigl = sigl;
114
        soft_reg->sigh = sigh;
115
        if (exp & 0x8000)
116
                soft_reg->sign = SIGN_NEG;
117
        else
118
                soft_reg->sign = SIGN_POS;
119
        exp &= 0x7fff;
120
        soft_reg->exp = exp - EXTENDED_Ebias + EXP_BIAS;
121
 
122
        if ( exp == 0 )
123
        {
124
                if ( !(sigh | sigl) )
125
                {
126
                        soft_reg->tag = TW_Zero;
127
                        return;
128
                }
129
                /* The number is a de-normal or pseudodenormal. */
130
                if (sigh & 0x80000000)
131
                {
132
                        /* Is a pseudodenormal. */
133
                        /* Convert it for internal use. */
134
                        /* This is non-80486 behaviour because the number
135
                           loses its 'denormal' identity. */
136
                        soft_reg->exp++;
137
                        return;
138
                }
139
                else
140
                {
141
                        /* Is a denormal. */
142
                        /* Convert it for internal use. */
143
                        soft_reg->exp++;
144
                        normalize_nuo(soft_reg);
145
                        return;
146
                }
147
        }
148
        else if ( exp == 0x7fff )
149
        {
150
                if ( !((sigh ^ 0x80000000) | sigl) )
151
                {
152
                        /* Matches the bit pattern for Infinity. */
153
                        soft_reg->exp = EXP_Infinity;
154
                        soft_reg->tag = TW_Infinity;
155
                        return;
156
                }
157
 
158
                soft_reg->exp = EXP_NaN;
159
                soft_reg->tag = TW_NaN;
160
                if ( !(sigh & 0x80000000) )
161
                {
162
                        /* NaNs have the ms bit set to 1. */
163
                        /* This is therefore an Unsupported NaN data type. */
164
                        /* This is non 80486 behaviour */
165
                        /* This should generate an Invalid Operand exception
166
                           later, so we convert it to a SNaN */
167
                        soft_reg->sigh = 0x80000000;
168
                        soft_reg->sigl = 0x00000001;
169
                        soft_reg->sign = SIGN_NEG;
170
                        return;
171
                }
172
                return;
173
        }
174
 
175
        if ( !(sigh & 0x80000000) )
176
        {
177
                /* Unsupported data type. */
178
                /* Valid numbers have the ms bit set to 1. */
179
                /* Unnormal. */
180
                /* Convert it for internal use. */
181
                /* This is non-80486 behaviour */
182
                /* This should generate an Invalid Operand exception
183
                   later, so we convert it to a SNaN */
184
                soft_reg->sigh = 0x80000000;
185
                soft_reg->sigl = 0x00000001;
186
                soft_reg->sign = SIGN_NEG;
187
                soft_reg->exp = EXP_NaN;
188
                soft_reg->tag = TW_NaN;
189
                return;
190
        }
191
        return;
192
}
193
 
194
/* Conver a number in the emulator format to the
195
 * hardware format.
196
 * Adapted from function write_to_extended
197
 */
198
 
199
 
200
void softreg_to_hardreg(const FPU_REG *rp, char d[10], long int user_control_word)
201
{
202
        long e;
203
        FPU_REG tmp;
204
        e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
205
 
206
        /*
207
          All numbers except denormals are stored internally in a
208
          format which is compatible with the extended real number
209
          format.
210
          */
211
        if (e > 0) {
212
                *(unsigned long *) d = rp->sigl;
213
                *(unsigned long *) (d + 4) = rp->sigh;
214
        } else {
215
                /*
216
                  The number is a de-normal stored as a normal using our
217
                  extra exponent range, or is Zero.
218
                  Convert it back to a de-normal, or leave it as Zero.
219
                  */
220
                reg_move(rp, &tmp);
221
                tmp.exp += -EXTENDED_Emin + 63;  /* largest exp to be 63 */
222
                round_to_int_cwd(&tmp, user_control_word);
223
                e = 0;
224
                *(unsigned long *) d= tmp.sigl;
225
                *(unsigned long *) (d + 4) = tmp.sigh;
226
        }
227
        e |= rp->sign == SIGN_POS ? 0 : 0x8000;
228
        *(unsigned short *) (d + 8) = e;
229
}
230
 

powered by: WebSVN 2.1.0

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