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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i386/] [math-emu/] [errors.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
 |  errors.c                                                                 |
3
 |                                                                           |
4
 |  The error handling functions for wm-FPU-emu                              |
5
 |                                                                           |
6
 | Copyright (C) 1992,1993,1994,1996                                         |
7
 |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
8
 |                  E-mail   billm@jacobi.maths.monash.edu.au                |
9
 |                                                                           |
10
 |                                                                           |
11
 +---------------------------------------------------------------------------*/
12
 
13
/*---------------------------------------------------------------------------+
14
 | Note:                                                                     |
15
 |    The file contains code which accesses user memory.                     |
16
 |    Emulator static data may change when user memory is accessed, due to   |
17
 |    other processes using the emulator while swapping is in progress.      |
18
 +---------------------------------------------------------------------------*/
19
 
20
#include <linux/signal.h>
21
 
22
#include <asm/segment.h>
23
 
24
#include "fpu_system.h"
25
#include "exception.h"
26
#include "fpu_emu.h"
27
#include "status_w.h"
28
#include "control_w.h"
29
#include "reg_constant.h"
30
#include "version.h"
31
 
32
/* */
33
#undef PRINT_MESSAGES
34
/* */
35
 
36
 
37
void Un_impl(void)
38
{
39
  unsigned char byte1, FPU_modrm;
40
  unsigned long address = FPU_ORIG_EIP;
41
 
42
  RE_ENTRANT_CHECK_OFF;
43
  /* No need to verify_area(), we have previously fetched these bytes. */
44
  printk("Unimplemented FPU Opcode at eip=%p : ", (void *) address);
45
  if ( FPU_CS == USER_CS )
46
    {
47
      while ( 1 )
48
        {
49
          byte1 = get_fs_byte((unsigned char *) address);
50
          if ( (byte1 & 0xf8) == 0xd8 ) break;
51
          printk("[%02x]", byte1);
52
          address++;
53
        }
54
      printk("%02x ", byte1);
55
      FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
56
 
57
      if (FPU_modrm >= 0300)
58
        printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
59
      else
60
        printk("/%d\n", (FPU_modrm >> 3) & 7);
61
    }
62
  else
63
    {
64
      printk("cs selector = %04x\n", FPU_CS);
65
    }
66
 
67
  RE_ENTRANT_CHECK_ON;
68
 
69
  EXCEPTION(EX_Invalid);
70
 
71
}
72
 
73
 
74
/*
75
   Called for opcodes which are illegal and which are known to result in a
76
   SIGILL with a real 80486.
77
   */
78
void FPU_illegal(void)
79
{
80
  math_abort(FPU_info,SIGILL);
81
}
82
 
83
 
84
 
85
void emu_printall(void)
86
{
87
  int i;
88
  static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR",
89
                              "DeNorm", "Inf", "NaN", "Empty" };
90
  unsigned char byte1, FPU_modrm;
91
  unsigned long address = FPU_ORIG_EIP;
92
 
93
  RE_ENTRANT_CHECK_OFF;
94
  /* No need to verify_area(), we have previously fetched these bytes. */
95
  printk("At %p:", (void *) address);
96
  if ( FPU_CS == USER_CS )
97
    {
98
#define MAX_PRINTED_BYTES 20
99
      for ( i = 0; i < MAX_PRINTED_BYTES; i++ )
100
        {
101
          byte1 = get_fs_byte((unsigned char *) address);
102
          if ( (byte1 & 0xf8) == 0xd8 )
103
            {
104
              printk(" %02x", byte1);
105
              break;
106
            }
107
          printk(" [%02x]", byte1);
108
          address++;
109
        }
110
      if ( i == MAX_PRINTED_BYTES )
111
        printk(" [more..]\n");
112
      else
113
        {
114
          FPU_modrm = get_fs_byte(1 + (unsigned char *) address);
115
 
116
          if (FPU_modrm >= 0300)
117
            printk(" %02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
118
          else
119
            printk(" /%d, mod=%d rm=%d\n",
120
                   (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
121
        }
122
    }
123
  else
124
    {
125
      printk("%04x\n", FPU_CS);
126
    }
127
 
128
  partial_status = status_word();
129
 
130
#ifdef DEBUGGING
131
if ( partial_status & SW_Backward )    printk("SW: backward compatibility\n");
132
if ( partial_status & SW_C3 )          printk("SW: condition bit 3\n");
133
if ( partial_status & SW_C2 )          printk("SW: condition bit 2\n");
134
if ( partial_status & SW_C1 )          printk("SW: condition bit 1\n");
135
if ( partial_status & SW_C0 )          printk("SW: condition bit 0\n");
136
if ( partial_status & SW_Summary )     printk("SW: exception summary\n");
137
if ( partial_status & SW_Stack_Fault ) printk("SW: stack fault\n");
138
if ( partial_status & SW_Precision )   printk("SW: loss of precision\n");
139
if ( partial_status & SW_Underflow )   printk("SW: underflow\n");
140
if ( partial_status & SW_Overflow )    printk("SW: overflow\n");
141
if ( partial_status & SW_Zero_Div )    printk("SW: divide by zero\n");
142
if ( partial_status & SW_Denorm_Op )   printk("SW: denormalized operand\n");
143
if ( partial_status & SW_Invalid )     printk("SW: invalid operation\n");
144
#endif DEBUGGING
145
 
146
  printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
147
         partial_status & 0x8000 ? 1 : 0,   /* busy */
148
         (partial_status & 0x3800) >> 11,   /* stack top pointer */
149
         partial_status & 0x80 ? 1 : 0,     /* Error summary status */
150
         partial_status & 0x40 ? 1 : 0,     /* Stack flag */
151
         partial_status & SW_C3?1:0, partial_status & SW_C2?1:0, /* cc */
152
         partial_status & SW_C1?1:0, partial_status & SW_C0?1:0, /* cc */
153
         partial_status & SW_Precision?1:0, partial_status & SW_Underflow?1:0,
154
         partial_status & SW_Overflow?1:0, partial_status & SW_Zero_Div?1:0,
155
         partial_status & SW_Denorm_Op?1:0, partial_status & SW_Invalid?1:0);
156
 
157
printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d     ef=%d%d%d%d%d%d\n",
158
         control_word & 0x1000 ? 1 : 0,
159
         (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
160
         (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
161
         control_word & 0x80 ? 1 : 0,
162
         control_word & SW_Precision?1:0, control_word & SW_Underflow?1:0,
163
         control_word & SW_Overflow?1:0, control_word & SW_Zero_Div?1:0,
164
         control_word & SW_Denorm_Op?1:0, control_word & SW_Invalid?1:0);
165
 
166
  for ( i = 0; i < 8; i++ )
167
    {
168
      FPU_REG *r = &st(i);
169
      char tagi = r->tag;
170
      switch (tagi)
171
        {
172
        case TW_Empty:
173
          continue;
174
          break;
175
        case TW_Zero:
176
#if 0
177
          printk("st(%d)  %c .0000 0000 0000 0000         ",
178
                 i, r->sign ? '-' : '+');
179
          break;
180
#endif
181
        case TW_Valid:
182
        case TW_NaN:
183
/*      case TW_Denormal: */
184
        case TW_Infinity:
185
          printk("st(%d)  %c .%04lx %04lx %04lx %04lx e%+-6ld ", i,
186
                 r->sign ? '-' : '+',
187
                 (long)(r->sigh >> 16),
188
                 (long)(r->sigh & 0xFFFF),
189
                 (long)(r->sigl >> 16),
190
                 (long)(r->sigl & 0xFFFF),
191
                 r->exp - EXP_BIAS + 1);
192
          break;
193
        default:
194
          printk("Whoops! Error in errors.c: tag%d is %d ", i, tagi);
195
          continue;
196
          break;
197
        }
198
      printk("%s\n", tag_desc[(int) (unsigned) tagi]);
199
    }
200
 
201
  RE_ENTRANT_CHECK_ON;
202
 
203
}
204
 
205
static struct {
206
  int type;
207
  const char *name;
208
} exception_names[] = {
209
  { EX_StackOver, "stack overflow" },
210
  { EX_StackUnder, "stack underflow" },
211
  { EX_Precision, "loss of precision" },
212
  { EX_Underflow, "underflow" },
213
  { EX_Overflow, "overflow" },
214
  { EX_ZeroDiv, "divide by zero" },
215
  { EX_Denormal, "denormalized operand" },
216
  { EX_Invalid, "invalid operation" },
217
  { EX_INTERNAL, "INTERNAL BUG in "FPU_VERSION },
218
  { 0, NULL }
219
};
220
 
221
/*
222
 EX_INTERNAL is always given with a code which indicates where the
223
 error was detected.
224
 
225
 Internal error types:
226
       0x14   in fpu_etc.c
227
       0x1nn  in a *.c file:
228
              0x101  in reg_add_sub.c
229
              0x102  in reg_mul.c
230
              0x104  in poly_atan.c
231
              0x105  in reg_mul.c
232
              0x107  in fpu_trig.c
233
              0x108  in reg_compare.c
234
              0x109  in reg_compare.c
235
              0x110  in reg_add_sub.c
236
              0x111  in fpe_entry.c
237
              0x112  in fpu_trig.c
238
              0x113  in errors.c
239
              0x115  in fpu_trig.c
240
              0x116  in fpu_trig.c
241
              0x117  in fpu_trig.c
242
              0x118  in fpu_trig.c
243
              0x119  in fpu_trig.c
244
              0x120  in poly_atan.c
245
              0x121  in reg_compare.c
246
              0x122  in reg_compare.c
247
              0x123  in reg_compare.c
248
              0x125  in fpu_trig.c
249
              0x126  in fpu_entry.c
250
              0x127  in poly_2xm1.c
251
              0x128  in fpu_entry.c
252
              0x129  in fpu_entry.c
253
              0x130  in get_address.c
254
              0x131  in get_address.c
255
              0x132  in get_address.c
256
              0x133  in get_address.c
257
              0x140  in load_store.c
258
              0x141  in load_store.c
259
              0x150  in poly_sin.c
260
              0x151  in poly_sin.c
261
              0x160  in reg_ld_str.c
262
              0x161  in reg_ld_str.c
263
              0x162  in reg_ld_str.c
264
              0x163  in reg_ld_str.c
265
       0x2nn  in an *.S file:
266
              0x201  in reg_u_add.S
267
              0x202  in reg_u_div.S
268
              0x203  in reg_u_div.S
269
              0x204  in reg_u_div.S
270
              0x205  in reg_u_mul.S
271
              0x206  in reg_u_sub.S
272
              0x207  in wm_sqrt.S
273
              0x208  in reg_div.S
274
              0x209  in reg_u_sub.S
275
              0x210  in reg_u_sub.S
276
              0x211  in reg_u_sub.S
277
              0x212  in reg_u_sub.S
278
              0x213  in wm_sqrt.S
279
              0x214  in wm_sqrt.S
280
              0x215  in wm_sqrt.S
281
              0x220  in reg_norm.S
282
              0x221  in reg_norm.S
283
              0x230  in reg_round.S
284
              0x231  in reg_round.S
285
              0x232  in reg_round.S
286
              0x233  in reg_round.S
287
              0x234  in reg_round.S
288
              0x235  in reg_round.S
289
              0x236  in reg_round.S
290
              0x240  in div_Xsig.S
291
              0x241  in div_Xsig.S
292
              0x242  in div_Xsig.S
293
 */
294
 
295
void exception(int n)
296
{
297
  int i, int_type;
298
 
299
  int_type = 0;         /* Needed only to stop compiler warnings */
300
  if ( n & EX_INTERNAL )
301
    {
302
      int_type = n - EX_INTERNAL;
303
      n = EX_INTERNAL;
304
      /* Set lots of exception bits! */
305
      partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
306
    }
307
  else
308
    {
309
      /* Extract only the bits which we use to set the status word */
310
      n &= (SW_Exc_Mask);
311
      /* Set the corresponding exception bit */
312
      partial_status |= n;
313
      /* Set summary bits iff exception isn't masked */
314
      if ( partial_status & ~control_word & CW_Exceptions )
315
        partial_status |= (SW_Summary | SW_Backward);
316
      if ( n & (SW_Stack_Fault | EX_Precision) )
317
        {
318
          if ( !(n & SW_C1) )
319
            /* This bit distinguishes over- from underflow for a stack fault,
320
               and roundup from round-down for precision loss. */
321
            partial_status &= ~SW_C1;
322
        }
323
    }
324
 
325
  RE_ENTRANT_CHECK_OFF;
326
  if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) )
327
    {
328
#ifdef PRINT_MESSAGES
329
      /* My message from the sponsor */
330
      printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n");
331
#endif PRINT_MESSAGES
332
 
333
      /* Get a name string for error reporting */
334
      for (i=0; exception_names[i].type; i++)
335
        if ( (exception_names[i].type & n) == exception_names[i].type )
336
          break;
337
 
338
      if (exception_names[i].type)
339
        {
340
#ifdef PRINT_MESSAGES
341
          printk("FP Exception: %s!\n", exception_names[i].name);
342
#endif PRINT_MESSAGES
343
        }
344
      else
345
        printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
346
 
347
      if ( n == EX_INTERNAL )
348
        {
349
          printk("FPU emulator: Internal error type 0x%04x\n", int_type);
350
          emu_printall();
351
        }
352
#ifdef PRINT_MESSAGES
353
      else
354
        emu_printall();
355
#endif PRINT_MESSAGES
356
 
357
      /*
358
       * The 80486 generates an interrupt on the next non-control FPU
359
       * instruction. So we need some means of flagging it.
360
       * We use the ES (Error Summary) bit for this.
361
       */
362
    }
363
  RE_ENTRANT_CHECK_ON;
364
 
365
#ifdef __DEBUG__
366
  math_abort(FPU_info,SIGFPE);
367
#endif __DEBUG__
368
 
369
}
370
 
371
 
372
/* Real operation attempted on two operands, one a NaN. */
373
/* Returns nz if the exception is unmasked */
374
asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest)
375
{
376
  FPU_REG const *x;
377
  int signalling;
378
 
379
  /* The default result for the case of two "equal" NaNs (signs may
380
     differ) is chosen to reproduce 80486 behaviour */
381
  x = a;
382
  if (a->tag == TW_NaN)
383
    {
384
      if (b->tag == TW_NaN)
385
        {
386
          signalling = !(a->sigh & b->sigh & 0x40000000);
387
          /* find the "larger" */
388
          if ( significand(a) < significand(b) )
389
            x = b;
390
        }
391
      else
392
        {
393
          /* return the quiet version of the NaN in a */
394
          signalling = !(a->sigh & 0x40000000);
395
        }
396
    }
397
  else
398
#ifdef PARANOID
399
    if (b->tag == TW_NaN)
400
#endif PARANOID
401
    {
402
      signalling = !(b->sigh & 0x40000000);
403
      x = b;
404
    }
405
#ifdef PARANOID
406
  else
407
    {
408
      signalling = 0;
409
      EXCEPTION(EX_INTERNAL|0x113);
410
      x = &CONST_QNaN;
411
    }
412
#endif PARANOID
413
 
414
  if ( !signalling )
415
    {
416
      if ( !(x->sigh & 0x80000000) )  /* pseudo-NaN ? */
417
        x = &CONST_QNaN;
418
      reg_move(x, dest);
419
      return 0;
420
    }
421
 
422
  if ( control_word & CW_Invalid )
423
    {
424
      /* The masked response */
425
      if ( !(x->sigh & 0x80000000) )  /* pseudo-NaN ? */
426
        x = &CONST_QNaN;
427
      reg_move(x, dest);
428
      /* ensure a Quiet NaN */
429
      dest->sigh |= 0x40000000;
430
    }
431
 
432
  EXCEPTION(EX_Invalid);
433
 
434
  return !(control_word & CW_Invalid);
435
}
436
 
437
 
438
/* Invalid arith operation on Valid registers */
439
/* Returns nz if the exception is unmasked */
440
asmlinkage int arith_invalid(FPU_REG *dest)
441
{
442
 
443
  EXCEPTION(EX_Invalid);
444
 
445
  if ( control_word & CW_Invalid )
446
    {
447
      /* The masked response */
448
      reg_move(&CONST_QNaN, dest);
449
    }
450
 
451
  return !(control_word & CW_Invalid);
452
 
453
}
454
 
455
 
456
/* Divide a finite number by zero */
457
asmlinkage int divide_by_zero(int sign, FPU_REG *dest)
458
{
459
 
460
  if ( control_word & CW_ZeroDiv )
461
    {
462
      /* The masked response */
463
      reg_move(&CONST_INF, dest);
464
      dest->sign = (unsigned char)sign;
465
    }
466
 
467
  EXCEPTION(EX_ZeroDiv);
468
 
469
  return !(control_word & CW_ZeroDiv);
470
 
471
}
472
 
473
 
474
/* This may be called often, so keep it lean */
475
int set_precision_flag(int flags)
476
{
477
  if ( control_word & CW_Precision )
478
    {
479
      partial_status &= ~(SW_C1 & flags);
480
      partial_status |= flags;   /* The masked response */
481
      return 0;
482
    }
483
  else
484
    {
485
      exception(flags);
486
      return 1;
487
    }
488
}
489
 
490
 
491
/* This may be called often, so keep it lean */
492
asmlinkage void set_precision_flag_up(void)
493
{
494
  if ( control_word & CW_Precision )
495
    partial_status |= (SW_Precision | SW_C1);   /* The masked response */
496
  else
497
    exception(EX_Precision | SW_C1);
498
 
499
}
500
 
501
 
502
/* This may be called often, so keep it lean */
503
asmlinkage void set_precision_flag_down(void)
504
{
505
  if ( control_word & CW_Precision )
506
    {   /* The masked response */
507
      partial_status &= ~SW_C1;
508
      partial_status |= SW_Precision;
509
    }
510
  else
511
    exception(EX_Precision);
512
}
513
 
514
 
515
asmlinkage int denormal_operand(void)
516
{
517
  if ( control_word & CW_Denormal )
518
    {   /* The masked response */
519
      partial_status |= SW_Denorm_Op;
520
      return 0;
521
    }
522
  else
523
    {
524
      exception(EX_Denormal);
525
      return 1;
526
    }
527
}
528
 
529
 
530
asmlinkage int arith_overflow(FPU_REG *dest)
531
{
532
 
533
  if ( control_word & CW_Overflow )
534
    {
535
      char sign;
536
      /* The masked response */
537
/* ###### The response here depends upon the rounding mode */
538
      sign = dest->sign;
539
      reg_move(&CONST_INF, dest);
540
      dest->sign = sign;
541
    }
542
  else
543
    {
544
      /* Subtract the magic number from the exponent */
545
      dest->exp -= (3 * (1 << 13));
546
    }
547
 
548
  EXCEPTION(EX_Overflow);
549
  if ( control_word & CW_Overflow )
550
    {
551
      /* The overflow exception is masked. */
552
      /* By definition, precision is lost.
553
         The roundup bit (C1) is also set because we have
554
         "rounded" upwards to Infinity. */
555
      EXCEPTION(EX_Precision | SW_C1);
556
      return !(control_word & CW_Precision);
557
    }
558
 
559
  return 0;
560
 
561
}
562
 
563
 
564
asmlinkage int arith_underflow(FPU_REG *dest)
565
{
566
 
567
  if ( control_word & CW_Underflow )
568
    {
569
      /* The masked response */
570
      if ( dest->exp <= EXP_UNDER - 63 )
571
        {
572
          reg_move(&CONST_Z, dest);
573
          partial_status &= ~SW_C1;       /* Round down. */
574
        }
575
    }
576
  else
577
    {
578
      /* Add the magic number to the exponent. */
579
      dest->exp += (3 * (1 << 13));
580
    }
581
 
582
  EXCEPTION(EX_Underflow);
583
  if ( control_word & CW_Underflow )
584
    {
585
      /* The underflow exception is masked. */
586
      EXCEPTION(EX_Precision);
587
      return !(control_word & CW_Precision);
588
    }
589
 
590
  return 0;
591
 
592
}
593
 
594
 
595
void stack_overflow(void)
596
{
597
 
598
 if ( control_word & CW_Invalid )
599
    {
600
      /* The masked response */
601
      top--;
602
      reg_move(&CONST_QNaN, &st(0));
603
    }
604
 
605
  EXCEPTION(EX_StackOver);
606
 
607
  return;
608
 
609
}
610
 
611
 
612
void stack_underflow(void)
613
{
614
 
615
 if ( control_word & CW_Invalid )
616
    {
617
      /* The masked response */
618
      reg_move(&CONST_QNaN, &st(0));
619
    }
620
 
621
  EXCEPTION(EX_StackUnder);
622
 
623
  return;
624
 
625
}
626
 
627
 
628
void stack_underflow_i(int i)
629
{
630
 
631
 if ( control_word & CW_Invalid )
632
    {
633
      /* The masked response */
634
      reg_move(&CONST_QNaN, &(st(i)));
635
    }
636
 
637
  EXCEPTION(EX_StackUnder);
638
 
639
  return;
640
 
641
}
642
 
643
 
644
void stack_underflow_pop(int i)
645
{
646
 
647
 if ( control_word & CW_Invalid )
648
    {
649
      /* The masked response */
650
      reg_move(&CONST_QNaN, &(st(i)));
651
      pop();
652
    }
653
 
654
  EXCEPTION(EX_StackUnder);
655
 
656
  return;
657
 
658
}
659
 

powered by: WebSVN 2.1.0

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