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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [i386/] [math-emu/] [reg_compare.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*---------------------------------------------------------------------------+
2
 |  reg_compare.c                                                            |
3
 |                                                                           |
4
 | Compare two floating point registers                                      |
5
 |                                                                           |
6
 | Copyright (C) 1992,1993,1994,1997                                         |
7
 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8
 |                  E-mail   billm@suburbia.net                              |
9
 |                                                                           |
10
 |                                                                           |
11
 +---------------------------------------------------------------------------*/
12
 
13
/*---------------------------------------------------------------------------+
14
 | compare() is the core FPU_REG comparison function                         |
15
 +---------------------------------------------------------------------------*/
16
 
17
#include "fpu_system.h"
18
#include "exception.h"
19
#include "fpu_emu.h"
20
#include "control_w.h"
21
#include "status_w.h"
22
 
23
 
24
static int compare(FPU_REG const *b, int tagb)
25
{
26
  int diff, exp0, expb;
27
  u_char                st0_tag;
28
  FPU_REG       *st0_ptr;
29
  FPU_REG       x, y;
30
  u_char                st0_sign, signb = getsign(b);
31
 
32
  st0_ptr = &st(0);
33
  st0_tag = FPU_gettag0();
34
  st0_sign = getsign(st0_ptr);
35
 
36
  if ( tagb == TAG_Special )
37
    tagb = FPU_Special(b);
38
  if ( st0_tag == TAG_Special )
39
    st0_tag = FPU_Special(st0_ptr);
40
 
41
  if ( ((st0_tag != TAG_Valid) && (st0_tag != TW_Denormal))
42
       || ((tagb != TAG_Valid) && (tagb != TW_Denormal)) )
43
    {
44
      if ( st0_tag == TAG_Zero )
45
        {
46
          if ( tagb == TAG_Zero ) return COMP_A_eq_B;
47
          if ( tagb == TAG_Valid )
48
            return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
49
          if ( tagb == TW_Denormal )
50
            return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
51
            | COMP_Denormal;
52
        }
53
      else if ( tagb == TAG_Zero )
54
        {
55
          if ( st0_tag == TAG_Valid )
56
            return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
57
          if ( st0_tag == TW_Denormal )
58
            return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
59
            | COMP_Denormal;
60
        }
61
 
62
      if ( st0_tag == TW_Infinity )
63
        {
64
          if ( (tagb == TAG_Valid) || (tagb == TAG_Zero) )
65
            return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
66
          else if ( tagb == TW_Denormal )
67
            return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
68
              | COMP_Denormal;
69
          else if ( tagb == TW_Infinity )
70
            {
71
              /* The 80486 book says that infinities can be equal! */
72
              return (st0_sign == signb) ? COMP_A_eq_B :
73
                ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
74
            }
75
          /* Fall through to the NaN code */
76
        }
77
      else if ( tagb == TW_Infinity )
78
        {
79
          if ( (st0_tag == TAG_Valid) || (st0_tag == TAG_Zero) )
80
            return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B);
81
          if ( st0_tag == TW_Denormal )
82
            return ((signb == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
83
                | COMP_Denormal;
84
          /* Fall through to the NaN code */
85
        }
86
 
87
      /* The only possibility now should be that one of the arguments
88
         is a NaN */
89
      if ( (st0_tag == TW_NaN) || (tagb == TW_NaN) )
90
        {
91
          int signalling = 0, unsupported = 0;
92
          if ( st0_tag == TW_NaN )
93
            {
94
              signalling = (st0_ptr->sigh & 0xc0000000) == 0x80000000;
95
              unsupported = !((exponent(st0_ptr) == EXP_OVER)
96
                              && (st0_ptr->sigh & 0x80000000));
97
            }
98
          if ( tagb == TW_NaN )
99
            {
100
              signalling |= (b->sigh & 0xc0000000) == 0x80000000;
101
              unsupported |= !((exponent(b) == EXP_OVER)
102
                               && (b->sigh & 0x80000000));
103
            }
104
          if ( signalling || unsupported )
105
            return COMP_No_Comp | COMP_SNaN | COMP_NaN;
106
          else
107
            /* Neither is a signaling NaN */
108
            return COMP_No_Comp | COMP_NaN;
109
        }
110
 
111
      EXCEPTION(EX_Invalid);
112
    }
113
 
114
  if (st0_sign != signb)
115
    {
116
      return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
117
        | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
118
            COMP_Denormal : 0);
119
    }
120
 
121
  if ( (st0_tag == TW_Denormal) || (tagb == TW_Denormal) )
122
    {
123
      FPU_to_exp16(st0_ptr, &x);
124
      FPU_to_exp16(b, &y);
125
      st0_ptr = &x;
126
      b = &y;
127
      exp0 = exponent16(st0_ptr);
128
      expb = exponent16(b);
129
    }
130
  else
131
    {
132
      exp0 = exponent(st0_ptr);
133
      expb = exponent(b);
134
    }
135
 
136
#ifdef PARANOID
137
  if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
138
  if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
139
#endif /* PARANOID */
140
 
141
  diff = exp0 - expb;
142
  if ( diff == 0 )
143
    {
144
      diff = st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
145
                                              identical */
146
      if ( diff == 0 )
147
        {
148
        diff = st0_ptr->sigl > b->sigl;
149
        if ( diff == 0 )
150
          diff = -(st0_ptr->sigl < b->sigl);
151
        }
152
    }
153
 
154
  if ( diff > 0 )
155
    {
156
      return ((st0_sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
157
        | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
158
            COMP_Denormal : 0);
159
    }
160
  if ( diff < 0 )
161
    {
162
      return ((st0_sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
163
        | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
164
            COMP_Denormal : 0);
165
    }
166
 
167
  return COMP_A_eq_B
168
    | ( ((st0_tag == TW_Denormal) || (tagb == TW_Denormal)) ?
169
        COMP_Denormal : 0);
170
 
171
}
172
 
173
 
174
/* This function requires that st(0) is not empty */
175
int FPU_compare_st_data(FPU_REG const *loaded_data, u_char loaded_tag)
176
{
177
  int f = 0, c;
178
 
179
  c = compare(loaded_data, loaded_tag);
180
 
181
  if (c & COMP_NaN)
182
    {
183
      EXCEPTION(EX_Invalid);
184
      f = SW_C3 | SW_C2 | SW_C0;
185
    }
186
  else
187
    switch (c & 7)
188
      {
189
      case COMP_A_lt_B:
190
        f = SW_C0;
191
        break;
192
      case COMP_A_eq_B:
193
        f = SW_C3;
194
        break;
195
      case COMP_A_gt_B:
196
        f = 0;
197
        break;
198
      case COMP_No_Comp:
199
        f = SW_C3 | SW_C2 | SW_C0;
200
        break;
201
#ifdef PARANOID
202
      default:
203
        EXCEPTION(EX_INTERNAL|0x121);
204
        f = SW_C3 | SW_C2 | SW_C0;
205
        break;
206
#endif /* PARANOID */
207
      }
208
  setcc(f);
209
  if (c & COMP_Denormal)
210
    {
211
      return denormal_operand() < 0;
212
    }
213
  return 0;
214
}
215
 
216
 
217
static int compare_st_st(int nr)
218
{
219
  int f = 0, c;
220
  FPU_REG *st_ptr;
221
 
222
  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
223
    {
224
      setcc(SW_C3 | SW_C2 | SW_C0);
225
      /* Stack fault */
226
      EXCEPTION(EX_StackUnder);
227
      return !(control_word & CW_Invalid);
228
    }
229
 
230
  st_ptr = &st(nr);
231
  c = compare(st_ptr, FPU_gettagi(nr));
232
  if (c & COMP_NaN)
233
    {
234
      setcc(SW_C3 | SW_C2 | SW_C0);
235
      EXCEPTION(EX_Invalid);
236
      return !(control_word & CW_Invalid);
237
    }
238
  else
239
    switch (c & 7)
240
      {
241
      case COMP_A_lt_B:
242
        f = SW_C0;
243
        break;
244
      case COMP_A_eq_B:
245
        f = SW_C3;
246
        break;
247
      case COMP_A_gt_B:
248
        f = 0;
249
        break;
250
      case COMP_No_Comp:
251
        f = SW_C3 | SW_C2 | SW_C0;
252
        break;
253
#ifdef PARANOID
254
      default:
255
        EXCEPTION(EX_INTERNAL|0x122);
256
        f = SW_C3 | SW_C2 | SW_C0;
257
        break;
258
#endif /* PARANOID */
259
      }
260
  setcc(f);
261
  if (c & COMP_Denormal)
262
    {
263
      return denormal_operand() < 0;
264
    }
265
  return 0;
266
}
267
 
268
 
269
static int compare_u_st_st(int nr)
270
{
271
  int f = 0, c;
272
  FPU_REG *st_ptr;
273
 
274
  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
275
    {
276
      setcc(SW_C3 | SW_C2 | SW_C0);
277
      /* Stack fault */
278
      EXCEPTION(EX_StackUnder);
279
      return !(control_word & CW_Invalid);
280
    }
281
 
282
  st_ptr = &st(nr);
283
  c = compare(st_ptr, FPU_gettagi(nr));
284
  if (c & COMP_NaN)
285
    {
286
      setcc(SW_C3 | SW_C2 | SW_C0);
287
      if (c & COMP_SNaN)       /* This is the only difference between
288
                                  un-ordered and ordinary comparisons */
289
        {
290
          EXCEPTION(EX_Invalid);
291
          return !(control_word & CW_Invalid);
292
        }
293
      return 0;
294
    }
295
  else
296
    switch (c & 7)
297
      {
298
      case COMP_A_lt_B:
299
        f = SW_C0;
300
        break;
301
      case COMP_A_eq_B:
302
        f = SW_C3;
303
        break;
304
      case COMP_A_gt_B:
305
        f = 0;
306
        break;
307
      case COMP_No_Comp:
308
        f = SW_C3 | SW_C2 | SW_C0;
309
        break;
310
#ifdef PARANOID
311
      default:
312
        EXCEPTION(EX_INTERNAL|0x123);
313
        f = SW_C3 | SW_C2 | SW_C0;
314
        break;
315
#endif /* PARANOID */ 
316
      }
317
  setcc(f);
318
  if (c & COMP_Denormal)
319
    {
320
      return denormal_operand() < 0;
321
    }
322
  return 0;
323
}
324
 
325
/*---------------------------------------------------------------------------*/
326
 
327
void fcom_st()
328
{
329
  /* fcom st(i) */
330
  compare_st_st(FPU_rm);
331
}
332
 
333
 
334
void fcompst()
335
{
336
  /* fcomp st(i) */
337
  if ( !compare_st_st(FPU_rm) )
338
    FPU_pop();
339
}
340
 
341
 
342
void fcompp()
343
{
344
  /* fcompp */
345
  if (FPU_rm != 1)
346
    {
347
      FPU_illegal();
348
      return;
349
    }
350
  if ( !compare_st_st(1) )
351
      poppop();
352
}
353
 
354
 
355
void fucom_()
356
{
357
  /* fucom st(i) */
358
  compare_u_st_st(FPU_rm);
359
 
360
}
361
 
362
 
363
void fucomp()
364
{
365
  /* fucomp st(i) */
366
  if ( !compare_u_st_st(FPU_rm) )
367
    FPU_pop();
368
}
369
 
370
 
371
void fucompp()
372
{
373
  /* fucompp */
374
  if (FPU_rm == 1)
375
    {
376
      if ( !compare_u_st_st(1) )
377
        poppop();
378
    }
379
  else
380
    FPU_illegal();
381
}

powered by: WebSVN 2.1.0

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