root/kernel/FPU-emu/precision.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. round_to_53_bits
  2. round_to_24_bits

   1 /*---------------------------------------------------------------------------+
   2  |  precision.c                                                              |
   3  |                                                                           |
   4  | The functions which adjust the precision of a result.                     |
   5  |                                                                           |
   6  | Copyright (C) 1993    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   7  |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
   8  |                                                                           |
   9  |                                                                           |
  10  +---------------------------------------------------------------------------*/
  11 
  12 
  13 #include <asm/segment.h>
  14 
  15 #include "fpu_system.h"
  16 #include "exception.h"
  17 #include "reg_constant.h"
  18 #include "fpu_emu.h"
  19 #include "control_w.h"
  20 
  21 
  22 /* Round the result to 53 bits */
  23 int round_to_53_bits(FPU_REG *reg)
     /* [previous][next][first][last][top][bottom][index][help] */
  24 {
  25 
  26   if (reg->tag == TW_Valid)
  27     {
  28       unsigned long increment = 0;      /* avoid gcc warnings */
  29 
  30       switch (control_word & CW_RC)
  31         {
  32         case RC_RND:
  33           /* Rounding can get a little messy.. */
  34           increment = ((reg->sigl & 0x7ff) > 0x400) |   /* nearest */
  35             ((reg->sigl & 0xc00) == 0xc00);             /* odd -> even */
  36           break;
  37         case RC_DOWN:   /* towards -infinity */
  38           increment = (reg->sign == SIGN_POS) ? 0 : reg->sigl & 0x7ff;
  39           break;
  40         case RC_UP:     /* towards +infinity */
  41           increment = (reg->sign == SIGN_POS) ? reg->sigl & 0x7ff : 0;
  42           break;
  43         case RC_CHOP:
  44           increment = 0;
  45           break;
  46         }
  47 
  48       /* Truncate the mantissa */
  49       reg->sigl &= 0xfffff800;
  50 
  51       if ( increment )
  52         {
  53           if ( reg->sigl >= 0xfffff800 )
  54             {
  55               /* the sigl part overflows */
  56               if ( reg->sigh == 0xffffffff )
  57                 {
  58                   /* The sigh part overflows */
  59                   reg->sigh = 0x80000000;
  60                   reg->exp++;
  61                   if (reg->exp >= EXP_OVER)
  62                     { arith_overflow(reg); return 1; }
  63                 }
  64               else
  65                 {
  66                   reg->sigh ++;
  67                 }
  68               reg->sigl = 0x00000000;
  69             }
  70           else
  71             {
  72               /* We only need to increment sigl */
  73               reg->sigl += 0x00000800;
  74             }
  75         }
  76     }
  77 
  78   return 0;
  79 
  80 }
  81 
  82 
  83 /* Round the result to 24 bits */
  84 int round_to_24_bits(FPU_REG *reg)
     /* [previous][next][first][last][top][bottom][index][help] */
  85 {
  86 
  87   if (reg->tag == TW_Valid)
  88     {
  89       unsigned long increment = 0;              /* avoid gcc warnings */
  90       unsigned long sigh = reg->sigh;
  91       unsigned long sigl = reg->sigl;
  92 
  93       switch (control_word & CW_RC)
  94         {
  95         case RC_RND:
  96           increment = ((sigh & 0xff) > 0x80)           /* more than half */
  97             || (((sigh & 0xff) == 0x80) && sigl)       /* more than half */
  98             || ((sigh & 0x180) == 0x180);              /* round to even */
  99           break;
 100         case RC_DOWN:   /* towards -infinity */
 101           increment = (reg->sign == SIGN_POS) ? 0 : (sigl | (sigh & 0xff));
 102           break;
 103         case RC_UP:     /* towards +infinity */
 104           increment = (reg->sign == SIGN_POS) ? (sigl | (sigh & 0xff)) : 0;
 105           break;
 106         case RC_CHOP:
 107           increment = 0;
 108           break;
 109         }
 110 
 111       /* Truncate the mantissa */
 112       reg->sigl = 0;
 113 
 114       if (increment)
 115         {
 116           if ( sigh >= 0xffffff00 )
 117             {
 118               /* The sigh part overflows */
 119               reg->sigh = 0x80000000;
 120               reg->exp++;
 121               if (reg->exp >= EXP_OVER)
 122                 { arith_overflow(reg); return 1; }
 123             }
 124           else
 125             {
 126               reg->sigh &= 0xffffff00;
 127               reg->sigh += 0x100;
 128             }
 129         }
 130     }
 131 
 132   return 0;
 133 
 134 }

/* [previous][next][first][last][top][bottom][index][help] */