Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002     .file   "reg_u_add.S"
0003 /*---------------------------------------------------------------------------+
0004  |  reg_u_add.S                                                              |
0005  |                                                                           |
0006  | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the  |
0007  |   result in a destination FPU_REG.                                        |
0008  |                                                                           |
0009  | Copyright (C) 1992,1993,1995,1997                                         |
0010  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
0011  |                  E-mail   billm@suburbia.net                              |
0012  |                                                                           |
0013  | Call from C as:                                                           |
0014  |   int  FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
0015  |                                                int control_w)             |
0016  |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
0017  |    one was raised, or -1 on internal error.                               |
0018  |                                                                           |
0019  +---------------------------------------------------------------------------*/
0020 
0021 /*
0022  |    Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ).
0023  |    Takes two valid reg f.p. numbers (TAG_Valid), which are
0024  |    treated as unsigned numbers,
0025  |    and returns their sum as a TAG_Valid or TAG_Special f.p. number.
0026  |    The returned number is normalized.
0027  |    Basic checks are performed if PARANOID is defined.
0028  */
0029 
0030 #include "exception.h"
0031 #include "fpu_emu.h"
0032 #include "control_w.h"
0033 
0034 .text
0035 SYM_FUNC_START(FPU_u_add)
0036     pushl   %ebp
0037     movl    %esp,%ebp
0038     pushl   %esi
0039     pushl   %edi
0040     pushl   %ebx
0041 
0042     movl    PARAM1,%esi     /* source 1 */
0043     movl    PARAM2,%edi     /* source 2 */
0044 
0045     movl    PARAM6,%ecx
0046     movl    %ecx,%edx
0047     subl    PARAM7,%ecx         /* exp1 - exp2 */
0048     jge L_arg1_larger
0049 
0050     /* num1 is smaller */
0051     movl    SIGL(%esi),%ebx
0052     movl    SIGH(%esi),%eax
0053 
0054     movl    %edi,%esi
0055     movl    PARAM7,%edx
0056     negw    %cx
0057     jmp L_accum_loaded
0058 
0059 L_arg1_larger:
0060     /* num1 has larger or equal exponent */
0061     movl    SIGL(%edi),%ebx
0062     movl    SIGH(%edi),%eax
0063 
0064 L_accum_loaded:
0065     movl    PARAM3,%edi     /* destination */
0066     movw    %dx,EXP(%edi)       /* Copy exponent to destination */
0067 
0068     xorl    %edx,%edx       /* clear the extension */
0069 
0070 #ifdef PARANOID
0071     testl   $0x80000000,%eax
0072     je  L_bugged
0073 
0074     testl   $0x80000000,SIGH(%esi)
0075     je  L_bugged
0076 #endif /* PARANOID */
0077 
0078 /* The number to be shifted is in %eax:%ebx:%edx */
0079     cmpw    $32,%cx     /* shrd only works for 0..31 bits */
0080     jnc L_more_than_31
0081 
0082 /* less than 32 bits */
0083     shrd    %cl,%ebx,%edx
0084     shrd    %cl,%eax,%ebx
0085     shr %cl,%eax
0086     jmp L_shift_done
0087 
0088 L_more_than_31:
0089     cmpw    $64,%cx
0090     jnc L_more_than_63
0091 
0092     subb    $32,%cl
0093     jz  L_exactly_32
0094 
0095     shrd    %cl,%eax,%edx
0096     shr %cl,%eax
0097     orl %ebx,%ebx
0098     jz  L_more_31_no_low    /* none of the lowest bits is set */
0099 
0100     orl $1,%edx         /* record the fact in the extension */
0101 
0102 L_more_31_no_low:
0103     movl    %eax,%ebx
0104     xorl    %eax,%eax
0105     jmp L_shift_done
0106 
0107 L_exactly_32:
0108     movl    %ebx,%edx
0109     movl    %eax,%ebx
0110     xorl    %eax,%eax
0111     jmp L_shift_done
0112 
0113 L_more_than_63:
0114     cmpw    $65,%cx
0115     jnc L_more_than_64
0116 
0117     movl    %eax,%edx
0118     orl %ebx,%ebx
0119     jz  L_more_63_no_low
0120 
0121     orl $1,%edx
0122     jmp L_more_63_no_low
0123 
0124 L_more_than_64:
0125     movl    $1,%edx     /* The shifted nr always at least one '1' */
0126 
0127 L_more_63_no_low:
0128     xorl    %ebx,%ebx
0129     xorl    %eax,%eax
0130 
0131 L_shift_done:
0132     /* Now do the addition */
0133     addl    SIGL(%esi),%ebx
0134     adcl    SIGH(%esi),%eax
0135     jnc L_round_the_result
0136 
0137     /* Overflow, adjust the result */
0138     rcrl    $1,%eax
0139     rcrl    $1,%ebx
0140     rcrl    $1,%edx
0141     jnc L_no_bit_lost
0142 
0143     orl $1,%edx
0144 
0145 L_no_bit_lost:
0146     incw    EXP(%edi)
0147 
0148 L_round_the_result:
0149     jmp fpu_reg_round   /* Round the result */
0150 
0151 
0152 
0153 #ifdef PARANOID
0154 /* If we ever get here then we have problems! */
0155 L_bugged:
0156     pushl   EX_INTERNAL|0x201
0157     call    EXCEPTION
0158     pop %ebx
0159     movl    $-1,%eax
0160     jmp L_exit
0161 
0162 L_exit:
0163     popl    %ebx
0164     popl    %edi
0165     popl    %esi
0166     leave
0167     RET
0168 #endif /* PARANOID */
0169 SYM_FUNC_END(FPU_u_add)