root/kernel/FPU-emu/reg_add_sub.c

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

DEFINITIONS

This source file includes following definitions.
  1. reg_add
  2. reg_sub

   1 /*---------------------------------------------------------------------------+
   2  |  reg_add_sub.c                                                            |
   3  |                                                                           |
   4  | Functions to add or subtract two registers and put the result in a third. |
   5  |                                                                           |
   6  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   7  |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
   8  |                                                                           |
   9  |                                                                           |
  10  +---------------------------------------------------------------------------*/
  11 
  12 /*---------------------------------------------------------------------------+
  13  | For each function, the destination may be any FPU_REG, including one of   |
  14  | the source FPU_REGs.                                                      |
  15  +---------------------------------------------------------------------------*/
  16 
  17 #include "exception.h"
  18 #include "reg_constant.h"
  19 #include "fpu_emu.h"
  20 
  21 
  22 
  23 void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
     /* [previous][next][first][last][top][bottom][index][help] */
  24 {
  25   int diff;
  26   
  27   if ( !(a->tag | b->tag) )
  28     {
  29       /* Both registers are valid */
  30       if (!(a->sign ^ b->sign))
  31         {
  32           /* signs are the same */
  33           reg_u_add(a, b, dest);
  34           dest->sign = a->sign;
  35           return;
  36         }
  37       
  38       /* The signs are different, so do a subtraction */
  39       diff = a->exp - b->exp;
  40       if (!diff)
  41         {
  42           diff = a->sigh - b->sigh;  /* Works only if ms bits are identical */
  43           if (!diff)
  44             diff = a->sigl > b->sigl;
  45         }
  46       
  47       if (diff > 0)
  48         {
  49           reg_u_sub(a, b, dest);
  50           dest->sign = a->sign;
  51           return;
  52         }
  53       else
  54         {
  55           reg_u_sub(b, a, dest);
  56           dest->sign = b->sign;
  57           return;
  58         }
  59     }
  60   else
  61     {
  62       if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
  63         { real_2op_NaN(a, b, dest); return; }
  64       else if (a->tag == TW_Zero)
  65         { reg_move(b, dest); return; }
  66       else if (b->tag == TW_Zero)
  67         { reg_move(a, dest); return; }
  68       else if (a->tag == TW_Infinity)
  69         {
  70           if (b->tag != TW_Infinity)
  71             { reg_move(a, dest); return; }
  72           /* They are both + or - infinity */
  73           if (a->sign == b->sign)
  74             { reg_move(a, dest); return; }
  75           reg_move(&CONST_QNaN, dest);  /* inf - inf is undefined. */
  76           return;
  77         }
  78       else if (b->tag == TW_Infinity)
  79         { reg_move(b, dest); return; }
  80     }
  81 #ifdef PARANOID
  82   EXCEPTION(EX_INTERNAL|0x101);
  83 #endif
  84 }
  85 
  86 
  87 /* Subtract b from a.  (a-b) -> dest */
  88 void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90   int diff;
  91 
  92   if ( !(a->tag | b->tag) )
  93     {
  94       /* Both registers are valid */
  95       diff = a->exp - b->exp;
  96       if (!diff)
  97         {
  98           diff = a->sigh - b->sigh;  /* Works only if ms bits are identical */
  99           if (!diff)
 100             diff = a->sigl > b->sigl;
 101         }
 102       
 103       switch (a->sign*2 + b->sign)
 104         {
 105         case 0: /* P - P */
 106         case 3: /* N - N */
 107           if (diff > 0)
 108             {
 109               reg_u_sub(a, b, dest);
 110               dest->sign = a->sign;
 111             }
 112           else
 113             {
 114               reg_u_sub(b, a, dest);
 115               dest->sign = a->sign ^ SIGN_POS^SIGN_NEG;
 116             }
 117           return;
 118         case 1: /* P - N */
 119           reg_u_add(a, b, dest);
 120           dest->sign = SIGN_POS;
 121           return;
 122         case 2: /* N - P */
 123           reg_u_add(a, b, dest);
 124           dest->sign = SIGN_NEG;
 125           return;
 126         }
 127     }
 128   else
 129     {
 130       if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
 131         { real_2op_NaN(a, b, dest); return; }
 132       else if (b->tag == TW_Zero)
 133         { reg_move(a, dest); return; }
 134       else if (a->tag == TW_Zero)
 135         {
 136           reg_move(b, dest);
 137           dest->sign ^= SIGN_POS^SIGN_NEG;
 138           return;
 139         }
 140       else if (a->tag == TW_Infinity)
 141         {
 142           if (b->tag != TW_Infinity)
 143             { reg_move(a, dest); return; }
 144           if (a->sign == b->sign)
 145             { reg_move(&CONST_QNaN, dest); return; }
 146           reg_move(a, dest);
 147           return;
 148         }
 149       else if (b->tag == TW_Infinity)
 150         {
 151           reg_move(b, dest);
 152           dest->sign ^= SIGN_POS^SIGN_NEG;
 153           return;
 154         }
 155     }
 156 #ifdef PARANOID
 157   EXCEPTION(EX_INTERNAL|0x110);
 158 #endif
 159 }
 160 

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