root/kernel/FPU-emu/reg_u_add.S

/* [previous][next][first][last][top][bottom][index][help] */
   1         .file   "reg_u_add.S"
   2 /*---------------------------------------------------------------------------+
   3  |  reg_u_add.S                                                              |
   4  |                                                                           |
   5  | Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the   |
   6  |   result in a destination FPU_REG.                                        |
   7  |                                                                           |
   8  | Copyright (C) 1992    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   9  |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
  10  |                                                                           |
  11  | Call from C as:                                                           |
  12  |   void reg_u_add(reg *arg1, reg *arg2, reg *answ)                         |
  13  |                                                                           |
  14  +---------------------------------------------------------------------------*/
  15 
  16 /*
  17  |    Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ).
  18  |    Takes two valid reg f.p. numbers (TW_Valid), which are
  19  |    treated as unsigned numbers,
  20  |    and returns their sum as a TW_Valid or TW_S f.p. number.
  21  |    The returned number is normalized.
  22  |    Basic checks are performed if PARANOID is defined.
  23  */
  24 
  25 #include "exception.h"
  26 #include "fpu_asm.h"
  27 
  28 .text
  29         .align 2,144
  30 .globl _reg_u_add
  31 _reg_u_add:
  32         pushl   %ebp
  33         movl    %esp,%ebp
  34 //      subl    $16,%esp
  35         pushl   %esi
  36         pushl   %edi
  37         pushl   %ebx
  38 
  39         movl    PARAM1,%esi             /* source 1 */
  40         movl    PARAM2,%edi             /* source 2 */
  41 
  42         xorl    %ecx,%ecx
  43         movl    EXP(%esi),%ecx
  44         subl    EXP(%edi),%ecx          /* exp1 - exp2 */
  45 //      jnc     L_arg1_larger
  46         jge     L_arg1_larger
  47 
  48         /* num1 is smaller */
  49         movl    SIGL(%esi),%ebx
  50         movl    SIGH(%esi),%eax
  51 
  52         movl    %edi,%esi
  53         negw    %cx
  54         jmp     L_accum_loaded
  55 
  56 L_arg1_larger:
  57         /* num1 has larger or equal exponent */
  58         movl    SIGL(%edi),%ebx
  59         movl    SIGH(%edi),%eax
  60 
  61 L_accum_loaded:
  62         movl    16(%ebp),%edi   /* destination */
  63 
  64         movl    EXP(%esi),%edx
  65         movl    %edx,EXP(%edi)  /* Copy exponent to destination */
  66 
  67         xorl    %edx,%edx               /* clear the extension */
  68 
  69 #ifdef PARANOID
  70         testl   $0x80000000,%eax
  71         je      L_bugged
  72 
  73         testl   $0x80000000,SIGH(%esi)
  74         je      L_bugged
  75 #endif PARANOID
  76 
  77         cmpw    $32,%cx         /* shrd only works for 0..31 bits */
  78         jnc     L_more_than_31
  79 
  80 /* less than 32 bits */
  81         shrd    %cl,%ebx,%edx
  82         shrd    %cl,%eax,%ebx
  83         shr     %cl,%eax
  84         jmp     L_shift_done
  85 
  86 L_more_than_31:
  87         cmpw    $64,%cx
  88         jnc     L_more_than_63
  89 
  90         subb    $32,%cl
  91         shrd    %cl,%eax,%edx
  92         shr     %cl,%eax
  93         movl    %eax,%ebx
  94         xorl    %eax,%eax
  95         jmp     L_shift_done
  96 
  97 L_more_than_63:
  98         cmpw    $66,%cx
  99         jnc     L_more_than_65
 100 
 101         subb    $64,%cl
 102         movl    %eax,%edx
 103         shr     %cl,%edx
 104         xorl    %ebx,%ebx
 105         xorl    %eax,%eax
 106         jmp     L_shift_done
 107 
 108 L_more_than_65:
 109         /* just copy the larger reg to dest */
 110         movw    SIGN(%esi),%ax
 111         movw    %ax,SIGN(%edi)
 112         movl    SIGL(%esi),%eax
 113         movl    %eax,SIGL(%edi)
 114         movl    SIGH(%esi),%eax
 115         movl    %eax,SIGH(%edi)
 116         jmp     L_exit          // Does not overflow
 117 
 118 L_shift_done:
 119         /* Now do the addition */
 120         addl    SIGL(%esi),%ebx
 121         adcl    SIGH(%esi),%eax
 122         jnc     L_round_the_result
 123 
 124         /* Overflow, adjust the result */
 125         rcrl    $1,%eax
 126         rcrl    $1,%ebx
 127         rcrl    $1,%edx
 128 
 129         incl    EXP(%edi)
 130         
 131 L_round_the_result:
 132         /* Round the result */
 133         cmpl    $0x80000000,%edx
 134         jc      L_no_round_up
 135 
 136         jne     L_do_round_up
 137 
 138         /* Now test for round-to-even */
 139         testb   $1,%ebx
 140         jz      L_no_round_up
 141 
 142 L_do_round_up:
 143         addl    $1,%ebx
 144         adcl    $0,%eax
 145         jnc     L_no_round_up           /* Rounding done, no overflow */
 146 
 147         /* Overflow, adjust the result */
 148         rcrl    $1,%eax
 149         rcrl    $1,%ebx
 150         incl    EXP(%edi)
 151 
 152 L_no_round_up:
 153         /* store the result */
 154         movl    %eax,SIGH(%edi)
 155         movl    %ebx,SIGL(%edi)
 156 
 157         movb    TW_Valid,TAG(%edi)              /* Set the tags to TW_Valid */
 158         movb    SIGN(%esi),%al
 159         movb    %al,SIGN(%edi)          /* Copy the sign from the first arg */
 160 
 161         // The number may have overflowed
 162         cmpl    EXP_OVER,EXP(%edi)
 163         jge     L_overflow
 164 
 165 L_exit:
 166         popl    %ebx
 167         popl    %edi
 168         popl    %esi
 169         leave
 170         ret
 171 
 172 /* The addition resulted in a number too large to represent */
 173 L_overflow:
 174         push    %edi
 175         call    _arith_overflow
 176         pop     %ebx
 177         jmp     L_exit
 178 
 179 
 180 #ifdef PARANOID
 181 /* If we ever get here then we have problems! */
 182 L_bugged:
 183         pushl   EX_INTERNAL|0x201
 184         call    EXCEPTION
 185         pop     %ebx
 186         jmp     L_exit
 187 #endif PARANOID

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