root/arch/x86/math-emu/reg_u_add.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /* SPDX-License-Identifier: GPL-2.0 */
   2         .file   "reg_u_add.S"
   3 /*---------------------------------------------------------------------------+
   4  |  reg_u_add.S                                                              |
   5  |                                                                           |
   6  | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the  |
   7  |   result in a destination FPU_REG.                                        |
   8  |                                                                           |
   9  | Copyright (C) 1992,1993,1995,1997                                         |
  10  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
  11  |                  E-mail   billm@suburbia.net                              |
  12  |                                                                           |
  13  | Call from C as:                                                           |
  14  |   int  FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
  15  |                                                int control_w)             |
  16  |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
  17  |    one was raised, or -1 on internal error.                               |
  18  |                                                                           |
  19  +---------------------------------------------------------------------------*/
  20 
  21 /*
  22  |    Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ).
  23  |    Takes two valid reg f.p. numbers (TAG_Valid), which are
  24  |    treated as unsigned numbers,
  25  |    and returns their sum as a TAG_Valid or TAG_Special f.p. number.
  26  |    The returned number is normalized.
  27  |    Basic checks are performed if PARANOID is defined.
  28  */
  29 
  30 #include "exception.h"
  31 #include "fpu_emu.h"
  32 #include "control_w.h"
  33 
  34 .text
  35 ENTRY(FPU_u_add)
  36         pushl   %ebp
  37         movl    %esp,%ebp
  38         pushl   %esi
  39         pushl   %edi
  40         pushl   %ebx
  41 
  42         movl    PARAM1,%esi             /* source 1 */
  43         movl    PARAM2,%edi             /* source 2 */
  44 
  45         movl    PARAM6,%ecx
  46         movl    %ecx,%edx
  47         subl    PARAM7,%ecx                     /* exp1 - exp2 */
  48         jge     L_arg1_larger
  49 
  50         /* num1 is smaller */
  51         movl    SIGL(%esi),%ebx
  52         movl    SIGH(%esi),%eax
  53 
  54         movl    %edi,%esi
  55         movl    PARAM7,%edx
  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         movw    %dx,EXP(%edi)           /* Copy exponent to destination */
  67 
  68         xorl    %edx,%edx               /* clear the extension */
  69 
  70 #ifdef PARANOID
  71         testl   $0x80000000,%eax
  72         je      L_bugged
  73 
  74         testl   $0x80000000,SIGH(%esi)
  75         je      L_bugged
  76 #endif /* PARANOID */
  77 
  78 /* The number to be shifted is in %eax:%ebx:%edx */
  79         cmpw    $32,%cx         /* shrd only works for 0..31 bits */
  80         jnc     L_more_than_31
  81 
  82 /* less than 32 bits */
  83         shrd    %cl,%ebx,%edx
  84         shrd    %cl,%eax,%ebx
  85         shr     %cl,%eax
  86         jmp     L_shift_done
  87 
  88 L_more_than_31:
  89         cmpw    $64,%cx
  90         jnc     L_more_than_63
  91 
  92         subb    $32,%cl
  93         jz      L_exactly_32
  94 
  95         shrd    %cl,%eax,%edx
  96         shr     %cl,%eax
  97         orl     %ebx,%ebx
  98         jz      L_more_31_no_low        /* none of the lowest bits is set */
  99 
 100         orl     $1,%edx                 /* record the fact in the extension */
 101 
 102 L_more_31_no_low:
 103         movl    %eax,%ebx
 104         xorl    %eax,%eax
 105         jmp     L_shift_done
 106 
 107 L_exactly_32:
 108         movl    %ebx,%edx
 109         movl    %eax,%ebx
 110         xorl    %eax,%eax
 111         jmp     L_shift_done
 112 
 113 L_more_than_63:
 114         cmpw    $65,%cx
 115         jnc     L_more_than_64
 116 
 117         movl    %eax,%edx
 118         orl     %ebx,%ebx
 119         jz      L_more_63_no_low
 120 
 121         orl     $1,%edx
 122         jmp     L_more_63_no_low
 123 
 124 L_more_than_64:
 125         movl    $1,%edx         /* The shifted nr always at least one '1' */
 126 
 127 L_more_63_no_low:
 128         xorl    %ebx,%ebx
 129         xorl    %eax,%eax
 130 
 131 L_shift_done:
 132         /* Now do the addition */
 133         addl    SIGL(%esi),%ebx
 134         adcl    SIGH(%esi),%eax
 135         jnc     L_round_the_result
 136 
 137         /* Overflow, adjust the result */
 138         rcrl    $1,%eax
 139         rcrl    $1,%ebx
 140         rcrl    $1,%edx
 141         jnc     L_no_bit_lost
 142 
 143         orl     $1,%edx
 144 
 145 L_no_bit_lost:
 146         incw    EXP(%edi)
 147 
 148 L_round_the_result:
 149         jmp     fpu_reg_round   /* Round the result */
 150 
 151 
 152 
 153 #ifdef PARANOID
 154 /* If we ever get here then we have problems! */
 155 L_bugged:
 156         pushl   EX_INTERNAL|0x201
 157         call    EXCEPTION
 158         pop     %ebx
 159         movl    $-1,%eax
 160         jmp     L_exit
 161 
 162 L_exit:
 163         popl    %ebx
 164         popl    %edi
 165         popl    %esi
 166         leave
 167         ret
 168 #endif /* PARANOID */
 169 ENDPROC(FPU_u_add)

/* [<][>][^][v][top][bottom][index][help] */