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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i386/] [math-emu/] [reg_compare.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
 |  reg_compare.c                                                            |
3
 |                                                                           |
4
 | Compare two floating point registers                                      |
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
 | 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
int compare(FPU_REG const *b)
25
{
26
  int diff;
27
  char         st0_tag;
28
  FPU_REG      *st0_ptr;
29
 
30
  st0_ptr = &st(0);
31
  st0_tag = st0_ptr->tag;
32
 
33
  if ( st0_tag | b->tag )
34
    {
35
      if ( st0_tag == TW_Zero )
36
        {
37
          if ( b->tag == TW_Zero ) return COMP_A_eq_B;
38
          if ( b->tag == TW_Valid )
39
            {
40
              return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
41
#ifdef DENORM_OPERAND
42
                | ((b->exp <= EXP_UNDER) ?
43
                   COMP_Denormal : 0)
44
#endif DENORM_OPERAND
45
                  ;
46
            }
47
        }
48
      else if ( b->tag == TW_Zero )
49
        {
50
          if ( st0_tag == TW_Valid )
51
            {
52
              return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
53
                      : COMP_A_lt_B)
54
#ifdef DENORM_OPERAND
55
                | ((st0_ptr->exp <= EXP_UNDER )
56
                   ? COMP_Denormal : 0 )
57
#endif DENORM_OPERAND
58
                  ;
59
            }
60
        }
61
 
62
      if ( st0_tag == TW_Infinity )
63
        {
64
          if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) )
65
            {
66
              return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B
67
                      : COMP_A_lt_B)
68
#ifdef DENORM_OPERAND
69
              | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ?
70
                COMP_Denormal : 0 )
71
#endif DENORM_OPERAND
72
;
73
            }
74
          else if ( b->tag == TW_Infinity )
75
            {
76
              /* The 80486 book says that infinities can be equal! */
77
              return (st0_ptr->sign == b->sign) ? COMP_A_eq_B :
78
                ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
79
            }
80
          /* Fall through to the NaN code */
81
        }
82
      else if ( b->tag == TW_Infinity )
83
        {
84
          if ( (st0_tag == TW_Valid) || (st0_tag == TW_Zero) )
85
            {
86
              return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
87
#ifdef DENORM_OPERAND
88
                | (((st0_tag == TW_Valid)
89
                    && (st0_ptr->exp <= EXP_UNDER)) ?
90
                   COMP_Denormal : 0)
91
#endif DENORM_OPERAND
92
                  ;
93
            }
94
          /* Fall through to the NaN code */
95
        }
96
 
97
      /* The only possibility now should be that one of the arguments
98
         is a NaN */
99
      if ( (st0_tag == TW_NaN) || (b->tag == TW_NaN) )
100
        {
101
          if ( ((st0_tag == TW_NaN) && !(st0_ptr->sigh & 0x40000000))
102
              || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) )
103
            /* At least one arg is a signaling NaN */
104
            return COMP_No_Comp | COMP_SNaN | COMP_NaN;
105
          else
106
            /* Neither is a signaling NaN */
107
            return COMP_No_Comp | COMP_NaN;
108
        }
109
 
110
      EXCEPTION(EX_Invalid);
111
    }
112
 
113
#ifdef PARANOID
114
  if (!(st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
115
  if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid);
116
#endif PARANOID
117
 
118
 
119
  if (st0_ptr->sign != b->sign)
120
    {
121
      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
122
#ifdef DENORM_OPERAND
123
        |
124
          ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
125
           COMP_Denormal : 0)
126
#endif DENORM_OPERAND
127
            ;
128
    }
129
 
130
  diff = st0_ptr->exp - b->exp;
131
  if ( diff == 0 )
132
    {
133
      diff = st0_ptr->sigh - b->sigh;  /* Works only if ms bits are
134
                                              identical */
135
      if ( diff == 0 )
136
        {
137
        diff = st0_ptr->sigl > b->sigl;
138
        if ( diff == 0 )
139
          diff = -(st0_ptr->sigl < b->sigl);
140
        }
141
    }
142
 
143
  if ( diff > 0 )
144
    {
145
      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B)
146
#ifdef DENORM_OPERAND
147
        |
148
          ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
149
           COMP_Denormal : 0)
150
#endif DENORM_OPERAND
151
            ;
152
    }
153
  if ( diff < 0 )
154
    {
155
      return ((st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B)
156
#ifdef DENORM_OPERAND
157
        |
158
          ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
159
           COMP_Denormal : 0)
160
#endif DENORM_OPERAND
161
            ;
162
    }
163
 
164
  return COMP_A_eq_B
165
#ifdef DENORM_OPERAND
166
    |
167
      ( ((st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ?
168
       COMP_Denormal : 0)
169
#endif DENORM_OPERAND
170
        ;
171
 
172
}
173
 
174
 
175
/* This function requires that st(0) is not empty */
176
int compare_st_data(FPU_REG const *loaded_data)
177
{
178
  int f, c;
179
 
180
  c = compare(loaded_data);
181
 
182
  if (c & COMP_NaN)
183
    {
184
      EXCEPTION(EX_Invalid);
185
      f = SW_C3 | SW_C2 | SW_C0;
186
    }
187
  else
188
    switch (c & 7)
189
      {
190
      case COMP_A_lt_B:
191
        f = SW_C0;
192
        break;
193
      case COMP_A_eq_B:
194
        f = SW_C3;
195
        break;
196
      case COMP_A_gt_B:
197
        f = 0;
198
        break;
199
      case COMP_No_Comp:
200
        f = SW_C3 | SW_C2 | SW_C0;
201
        break;
202
#ifdef PARANOID
203
      default:
204
        EXCEPTION(EX_INTERNAL|0x121);
205
        f = SW_C3 | SW_C2 | SW_C0;
206
        break;
207
#endif PARANOID
208
      }
209
  setcc(f);
210
  if (c & COMP_Denormal)
211
    {
212
      return denormal_operand();
213
    }
214
  return 0;
215
}
216
 
217
 
218
static int compare_st_st(int nr)
219
{
220
  int f, c;
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
  c = compare(&st(nr));
231
  if (c & COMP_NaN)
232
    {
233
      setcc(SW_C3 | SW_C2 | SW_C0);
234
      EXCEPTION(EX_Invalid);
235
      return !(control_word & CW_Invalid);
236
    }
237
  else
238
    switch (c & 7)
239
      {
240
      case COMP_A_lt_B:
241
        f = SW_C0;
242
        break;
243
      case COMP_A_eq_B:
244
        f = SW_C3;
245
        break;
246
      case COMP_A_gt_B:
247
        f = 0;
248
        break;
249
      case COMP_No_Comp:
250
        f = SW_C3 | SW_C2 | SW_C0;
251
        break;
252
#ifdef PARANOID
253
      default:
254
        EXCEPTION(EX_INTERNAL|0x122);
255
        f = SW_C3 | SW_C2 | SW_C0;
256
        break;
257
#endif PARANOID
258
      }
259
  setcc(f);
260
  if (c & COMP_Denormal)
261
    {
262
      return denormal_operand();
263
    }
264
  return 0;
265
}
266
 
267
 
268
static int compare_u_st_st(int nr)
269
{
270
  int f, c;
271
 
272
  if ( !NOT_EMPTY(0) || !NOT_EMPTY(nr) )
273
    {
274
      setcc(SW_C3 | SW_C2 | SW_C0);
275
      /* Stack fault */
276
      EXCEPTION(EX_StackUnder);
277
      return !(control_word & CW_Invalid);
278
    }
279
 
280
  c = compare(&st(nr));
281
  if (c & COMP_NaN)
282
    {
283
      setcc(SW_C3 | SW_C2 | SW_C0);
284
      if (c & COMP_SNaN)       /* This is the only difference between
285
                                  un-ordered and ordinary comparisons */
286
        {
287
          EXCEPTION(EX_Invalid);
288
          return !(control_word & CW_Invalid);
289
        }
290
      return 0;
291
    }
292
  else
293
    switch (c & 7)
294
      {
295
      case COMP_A_lt_B:
296
        f = SW_C0;
297
        break;
298
      case COMP_A_eq_B:
299
        f = SW_C3;
300
        break;
301
      case COMP_A_gt_B:
302
        f = 0;
303
        break;
304
      case COMP_No_Comp:
305
        f = SW_C3 | SW_C2 | SW_C0;
306
        break;
307
#ifdef PARANOID
308
      default:
309
        EXCEPTION(EX_INTERNAL|0x123);
310
        f = SW_C3 | SW_C2 | SW_C0;
311
        break;
312
#endif PARANOID
313
      }
314
  setcc(f);
315
  if (c & COMP_Denormal)
316
    {
317
      return denormal_operand();
318
    }
319
  return 0;
320
}
321
 
322
/*---------------------------------------------------------------------------*/
323
 
324
void fcom_st()
325
{
326
  /* fcom st(i) */
327
  compare_st_st(FPU_rm);
328
}
329
 
330
 
331
void fcompst()
332
{
333
  /* fcomp st(i) */
334
  if ( !compare_st_st(FPU_rm) )
335
    pop();
336
}
337
 
338
 
339
void fcompp()
340
{
341
  /* fcompp */
342
  if (FPU_rm != 1)
343
    {
344
      FPU_illegal();
345
      return;
346
    }
347
  if ( !compare_st_st(1) )
348
      poppop();
349
}
350
 
351
 
352
void fucom_()
353
{
354
  /* fucom st(i) */
355
  compare_u_st_st(FPU_rm);
356
 
357
}
358
 
359
 
360
void fucomp()
361
{
362
  /* fucomp st(i) */
363
  if ( !compare_u_st_st(FPU_rm) )
364
    pop();
365
}
366
 
367
 
368
void fucompp()
369
{
370
  /* fucompp */
371
  if (FPU_rm == 1)
372
    {
373
      if ( !compare_u_st_st(1) )
374
        poppop();
375
    }
376
  else
377
    FPU_illegal();
378
}

powered by: WebSVN 2.1.0

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