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,1993                                                   |
   9  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  10  |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
  11  |                                                                           |
  12  | Call from C as:                                                           |
  13  |   void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
  14  |                                                int control_w)             |
  15  |                                                                           |
  16  +---------------------------------------------------------------------------*/
  17 
  18 /*
  19  |    Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ).
  20  |    Takes two valid reg f.p. numbers (TW_Valid), which are
  21  |    treated as unsigned numbers,
  22  |    and returns their sum as a TW_Valid or TW_S f.p. number.
  23  |    The returned number is normalized.
  24  |    Basic checks are performed if PARANOID is defined.
  25  */
  26 
  27 #include "exception.h"
  28 #include "fpu_asm.h"
  29 #include "control_w.h"
  30 
  31 .text
  32         .align 2,144
  33 .globl _reg_u_add
  34 _reg_u_add:
  35         pushl   %ebp
  36         movl    %esp,%ebp
  37 //      subl    $16,%esp
  38         pushl   %esi
  39         pushl   %edi
  40         pushl   %ebx
  41 
  42         movl    PARAM1,%esi             /* source 1 */
  43         movl    PARAM2,%edi             /* source 2 */
  44 
  45         xorl    %ecx,%ecx
  46         movl    EXP(%esi),%ecx
  47         subl    EXP(%edi),%ecx          /* exp1 - exp2 */
  48 //      jnc     L_arg1_larger
  49         jge     L_arg1_larger
  50 
  51         /* num1 is smaller */
  52         movl    SIGL(%esi),%ebx
  53         movl    SIGH(%esi),%eax
  54 
  55         movl    %edi,%esi
  56         negw    %cx
  57         jmp     L_accum_loaded
  58 
  59 L_arg1_larger:
  60         /* num1 has larger or equal exponent */
  61         movl    SIGL(%edi),%ebx
  62         movl    SIGH(%edi),%eax
  63 
  64 L_accum_loaded:
  65         movl    PARAM3,%edi             /* destination */
  66         movb    SIGN(%esi),%dl
  67         movb    %dl,SIGN(%edi)          /* Copy the sign from the first arg */
  68 
  69 
  70         movl    EXP(%esi),%edx
  71         movl    %edx,EXP(%edi)  /* Copy exponent to destination */
  72 
  73         xorl    %edx,%edx               /* clear the extension */
  74 
  75 #ifdef PARANOID
  76         testl   $0x80000000,%eax
  77         je      L_bugged
  78 
  79         testl   $0x80000000,SIGH(%esi)
  80         je      L_bugged
  81 #endif PARANOID
  82 
  83 // The number to be shifted is in %eax:%ebx:%edx
  84         cmpw    $32,%cx         /* shrd only works for 0..31 bits */
  85         jnc     L_more_than_31
  86 
  87 /* less than 32 bits */
  88         shrd    %cl,%ebx,%edx
  89         shrd    %cl,%eax,%ebx
  90         shr     %cl,%eax
  91         jmp     L_shift_done
  92 
  93 L_more_than_31:
  94         cmpw    $64,%cx
  95         jnc     L_more_than_63
  96 
  97         subb    $32,%cl
  98         jz      L_exactly_32
  99 
 100         shrd    %cl,%eax,%edx
 101         shr     %cl,%eax
 102         orl     %ebx,%ebx
 103         jz      L_more_31_no_low        // none of the lowest bits is set
 104 
 105         orl     $1,%edx                 // record the fact in the extension
 106 
 107 L_more_31_no_low:
 108         movl    %eax,%ebx
 109         xorl    %eax,%eax
 110         jmp     L_shift_done
 111 
 112 L_exactly_32:
 113         movl    %ebx,%edx
 114         movl    %eax,%ebx
 115         xorl    %eax,%eax
 116         jmp     L_shift_done
 117 
 118 L_more_than_63:
 119         cmpw    $65,%cx
 120         jnc     L_more_than_64
 121 
 122         movl    %eax,%edx
 123         orl     %ebx,%ebx
 124         jz      L_more_63_no_low
 125 
 126         orl     $1,%edx
 127         jmp     L_more_63_no_low
 128 
 129 L_more_than_64:
 130         movl    $1,%edx         // The shifted nr always at least one '1'
 131 
 132 L_more_63_no_low:
 133         xorl    %ebx,%ebx
 134         xorl    %eax,%eax
 135 
 136 L_shift_done:
 137         /* Now do the addition */
 138         addl    SIGL(%esi),%ebx
 139         adcl    SIGH(%esi),%eax
 140         jnc     L_round_the_result
 141 
 142         /* Overflow, adjust the result */
 143         rcrl    $1,%eax
 144         rcrl    $1,%ebx
 145         rcrl    $1,%edx
 146         jnc     L_no_bit_lost
 147 
 148         orl     $1,%edx
 149 
 150 L_no_bit_lost:
 151         incl    EXP(%edi)
 152 
 153 L_round_the_result:
 154         jmp     FPU_round       // Round the result
 155 
 156 
 157 
 158 #ifdef PARANOID
 159 /* If we ever get here then we have problems! */
 160 L_bugged:
 161         pushl   EX_INTERNAL|0x201
 162         call    EXCEPTION
 163         pop     %ebx
 164         jmp     L_exit
 165 #endif PARANOID
 166 
 167 
 168 L_exit:
 169         popl    %ebx
 170         popl    %edi
 171         popl    %esi
 172         leave
 173         ret

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