Annotation of coherent/b/kernel/emulator/reg_add_sub.c, revision 1.1

1.1     ! root        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 [email protected]    |
        !             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 "fpu_system.h"
        !            18: #include "exception.h"
        !            19: #include "reg_constant.h"
        !            20: #include "fpu_emu.h"
        !            21: 
        !            22: 
        !            23: 
        !            24: void reg_add(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
        !            25: {
        !            26:   int diff;
        !            27:   
        !            28:   if ( !(a->tag | b->tag) )
        !            29:     {
        !            30:       /* Both registers are valid */
        !            31:       if (!(a->sign ^ b->sign))
        !            32:        {
        !            33:          /* signs are the same */
        !            34:          reg_u_add(a, b, dest);
        !            35:          dest->sign = a->sign;
        !            36:          return;
        !            37:        }
        !            38:       
        !            39:       /* The signs are different, so do a subtraction */
        !            40:       diff = a->exp - b->exp;
        !            41:       if (!diff)
        !            42:        {
        !            43:          diff = a->sigh - b->sigh;  /* Works only if ms bits are identical */
        !            44:          if (!diff)
        !            45:            diff = a->sigl > b->sigl;
        !            46:        }
        !            47:       
        !            48:       if (diff > 0)
        !            49:        {
        !            50:          reg_u_sub(a, b, dest);
        !            51:          dest->sign = a->sign;
        !            52:          return;
        !            53:        }
        !            54:       else
        !            55:        {
        !            56:          reg_u_sub(b, a, dest);
        !            57:          dest->sign = b->sign;
        !            58:          return;
        !            59:        }
        !            60:     }
        !            61:   else
        !            62:     {
        !            63:       if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
        !            64:        { real_2op_NaN(a, b, dest); return; }
        !            65:       else if (a->tag == TW_Zero)
        !            66:        { reg_move(b, dest); return; }
        !            67:       else if (b->tag == TW_Zero)
        !            68:        { reg_move(a, dest); return; }
        !            69:       else if (a->tag == TW_Infinity)
        !            70:        {
        !            71:          if (b->tag != TW_Infinity)
        !            72:            { reg_move(a, dest); return; }
        !            73:          /* They are both + or - infinity */
        !            74:          if (a->sign == b->sign)
        !            75:            { reg_move(a, dest); return; }
        !            76:          reg_move(&CONST_QNaN, dest);  /* inf - inf is undefined. */
        !            77:          return;
        !            78:        }
        !            79:       else if (b->tag == TW_Infinity)
        !            80:        { reg_move(b, dest); return; }
        !            81:     }
        !            82: #ifdef PARANOID
        !            83:   EXCEPTION(EX_INTERNAL|0x101);
        !            84: #endif
        !            85: }
        !            86: 
        !            87: 
        !            88: /* Subtract b from a.  (a-b) -> dest */
        !            89: void reg_sub(FPU_REG *a, FPU_REG *b, FPU_REG *dest)
        !            90: {
        !            91:   int diff;
        !            92: 
        !            93:   if ( !(a->tag | b->tag) )
        !            94:     {
        !            95:       /* Both registers are valid */
        !            96:       diff = a->exp - b->exp;
        !            97:       if (!diff)
        !            98:        {
        !            99:          diff = a->sigh - b->sigh;  /* Works only if ms bits are identical */
        !           100:          if (!diff)
        !           101:            diff = a->sigl > b->sigl;
        !           102:        }
        !           103:       
        !           104:       switch (a->sign*2 + b->sign)
        !           105:        {
        !           106:        case 0: /* P - P */
        !           107:        case 3: /* N - N */
        !           108:          if (diff > 0)
        !           109:            {
        !           110:              reg_u_sub(a, b, dest);
        !           111:              dest->sign = a->sign;
        !           112:            }
        !           113:          else
        !           114:            {
        !           115:              reg_u_sub(b, a, dest);
        !           116:              dest->sign = a->sign ^ SIGN_POS^SIGN_NEG;
        !           117:            }
        !           118:          return;
        !           119:        case 1: /* P - N */
        !           120:          reg_u_add(a, b, dest);
        !           121:          dest->sign = SIGN_POS;
        !           122:          return;
        !           123:        case 2: /* N - P */
        !           124:          reg_u_add(a, b, dest);
        !           125:          dest->sign = SIGN_NEG;
        !           126:          return;
        !           127:        }
        !           128:     }
        !           129:   else
        !           130:     {
        !           131:       if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) )
        !           132:        { real_2op_NaN(a, b, dest); return; }
        !           133:       else if (b->tag == TW_Zero)
        !           134:        { reg_move(a, dest); return; }
        !           135:       else if (a->tag == TW_Zero)
        !           136:        {
        !           137:          reg_move(b, dest);
        !           138:          dest->sign ^= SIGN_POS^SIGN_NEG;
        !           139:          return;
        !           140:        }
        !           141:       else if (a->tag == TW_Infinity)
        !           142:        {
        !           143:          if (b->tag != TW_Infinity)
        !           144:            { reg_move(a, dest); return; }
        !           145:          if (a->sign == b->sign)
        !           146:            { reg_move(&CONST_QNaN, dest); return; }
        !           147:          reg_move(a, dest);
        !           148:          return;
        !           149:        }
        !           150:       else if (b->tag == TW_Infinity)
        !           151:        {
        !           152:          reg_move(b, dest);
        !           153:          dest->sign ^= SIGN_POS^SIGN_NEG;
        !           154:          return;
        !           155:        }
        !           156:     }
        !           157: #ifdef PARANOID
        !           158:   EXCEPTION(EX_INTERNAL|0x110);
        !           159: #endif
        !           160: }
        !           161: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.