Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
0002     .file   "reg_u_sub.S"
0003 /*---------------------------------------------------------------------------+
0004  |  reg_u_sub.S                                                              |
0005  |                                                                           |
0006  | Core floating point subtraction routine.                                  |
0007  |                                                                           |
0008  | Copyright (C) 1992,1993,1995,1997                                         |
0009  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
0010  |                  E-mail   billm@suburbia.net                              |
0011  |                                                                           |
0012  | Call from C as:                                                           |
0013  |    int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
0014  |                                                int control_w)             |
0015  |    Return value is the tag of the answer, or-ed with FPU_Exception if     |
0016  |    one was raised, or -1 on internal error.                               |
0017  |                                                                           |
0018  +---------------------------------------------------------------------------*/
0019 
0020 /*
0021  |    Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ).
0022  |    Takes two valid reg f.p. numbers (TAG_Valid), which are
0023  |    treated as unsigned numbers,
0024  |    and returns their difference as a TAG_Valid or TAG_Zero f.p.
0025  |    number.
0026  |    The first number (arg1) must be the larger.
0027  |    The returned number is normalized.
0028  |    Basic checks are performed if PARANOID is defined.
0029  */
0030 
0031 #include "exception.h"
0032 #include "fpu_emu.h"
0033 #include "control_w.h"
0034 
0035 .text
0036 SYM_FUNC_START(FPU_u_sub)
0037     pushl   %ebp
0038     movl    %esp,%ebp
0039     pushl   %esi
0040     pushl   %edi
0041     pushl   %ebx
0042 
0043     movl    PARAM1,%esi /* source 1 */
0044     movl    PARAM2,%edi /* source 2 */
0045     
0046     movl    PARAM6,%ecx
0047     subl    PARAM7,%ecx /* exp1 - exp2 */
0048 
0049 #ifdef PARANOID
0050     /* source 2 is always smaller than source 1 */
0051     js  L_bugged_1
0052 
0053     testl   $0x80000000,SIGH(%edi)  /* The args are assumed to be be normalized */
0054     je  L_bugged_2
0055 
0056     testl   $0x80000000,SIGH(%esi)
0057     je  L_bugged_2
0058 #endif /* PARANOID */
0059 
0060 /*--------------------------------------+
0061  |  Form a register holding the     |
0062  |  smaller number                  |
0063  +--------------------------------------*/
0064     movl    SIGH(%edi),%eax /* register ms word */
0065     movl    SIGL(%edi),%ebx /* register ls word */
0066 
0067     movl    PARAM3,%edi /* destination */
0068     movl    PARAM6,%edx
0069     movw    %dx,EXP(%edi)   /* Copy exponent to destination */
0070 
0071     xorl    %edx,%edx   /* register extension */
0072 
0073 /*--------------------------------------+
0074  |  Shift the temporary register    |
0075  |      right the required number of    |
0076  |  places.             |
0077  +--------------------------------------*/
0078 
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     /* Shift right by 64 bits */
0118     movl    %eax,%edx
0119     orl %ebx,%ebx
0120     jz  L_more_63_no_low
0121 
0122     orl $1,%edx
0123     jmp L_more_63_no_low
0124 
0125 L_more_than_64:
0126     jne L_more_than_65
0127 
0128     /* Shift right by 65 bits */
0129     /* Carry is clear if we get here */
0130     movl    %eax,%edx
0131     rcrl    %edx
0132     jnc L_shift_65_nc
0133 
0134     orl $1,%edx
0135     jmp L_more_63_no_low
0136 
0137 L_shift_65_nc:
0138     orl %ebx,%ebx
0139     jz  L_more_63_no_low
0140 
0141     orl $1,%edx
0142     jmp L_more_63_no_low
0143 
0144 L_more_than_65:
0145     movl    $1,%edx     /* The shifted nr always at least one '1' */
0146 
0147 L_more_63_no_low:
0148     xorl    %ebx,%ebx
0149     xorl    %eax,%eax
0150 
0151 L_shift_done:
0152 L_subtr:
0153 /*------------------------------+
0154  |  Do the subtraction  |
0155  +------------------------------*/
0156     xorl    %ecx,%ecx
0157     subl    %edx,%ecx
0158     movl    %ecx,%edx
0159     movl    SIGL(%esi),%ecx
0160     sbbl    %ebx,%ecx
0161     movl    %ecx,%ebx
0162     movl    SIGH(%esi),%ecx
0163     sbbl    %eax,%ecx
0164     movl    %ecx,%eax
0165 
0166 #ifdef PARANOID
0167     /* We can never get a borrow */
0168     jc  L_bugged
0169 #endif /* PARANOID */
0170 
0171 /*--------------------------------------+
0172  |  Normalize the result        |
0173  +--------------------------------------*/
0174     testl   $0x80000000,%eax
0175     jnz L_round     /* no shifting needed */
0176 
0177     orl %eax,%eax
0178     jnz L_shift_1   /* shift left 1 - 31 bits */
0179 
0180     orl %ebx,%ebx
0181     jnz L_shift_32  /* shift left 32 - 63 bits */
0182 
0183 /*
0184  *   A rare case, the only one which is non-zero if we got here
0185  *         is:           1000000 .... 0000
0186  *                      -0111111 .... 1111 1
0187  *                       -------------------- 
0188  *                       0000000 .... 0000 1 
0189  */
0190 
0191     cmpl    $0x80000000,%edx
0192     jnz L_must_be_zero
0193 
0194     /* Shift left 64 bits */
0195     subw    $64,EXP(%edi)
0196     xchg    %edx,%eax
0197     jmp fpu_reg_round
0198 
0199 L_must_be_zero:
0200 #ifdef PARANOID
0201     orl %edx,%edx
0202     jnz L_bugged_3
0203 #endif /* PARANOID */ 
0204 
0205     /* The result is zero */
0206     movw    $0,EXP(%edi)        /* exponent */
0207     movl    $0,SIGL(%edi)
0208     movl    $0,SIGH(%edi)
0209     movl    TAG_Zero,%eax
0210     jmp L_exit
0211 
0212 L_shift_32:
0213     movl    %ebx,%eax
0214     movl    %edx,%ebx
0215     movl    $0,%edx
0216     subw    $32,EXP(%edi)   /* Can get underflow here */
0217 
0218 /* We need to shift left by 1 - 31 bits */
0219 L_shift_1:
0220     bsrl    %eax,%ecx   /* get the required shift in %ecx */
0221     subl    $31,%ecx
0222     negl    %ecx
0223     shld    %cl,%ebx,%eax
0224     shld    %cl,%edx,%ebx
0225     shl %cl,%edx
0226     subw    %cx,EXP(%edi)   /* Can get underflow here */
0227 
0228 L_round:
0229     jmp fpu_reg_round   /* Round the result */
0230 
0231 
0232 #ifdef PARANOID
0233 L_bugged_1:
0234     pushl   EX_INTERNAL|0x206
0235     call    EXCEPTION
0236     pop %ebx
0237     jmp L_error_exit
0238 
0239 L_bugged_2:
0240     pushl   EX_INTERNAL|0x209
0241     call    EXCEPTION
0242     pop %ebx
0243     jmp L_error_exit
0244 
0245 L_bugged_3:
0246     pushl   EX_INTERNAL|0x210
0247     call    EXCEPTION
0248     pop %ebx
0249     jmp L_error_exit
0250 
0251 L_bugged_4:
0252     pushl   EX_INTERNAL|0x211
0253     call    EXCEPTION
0254     pop %ebx
0255     jmp L_error_exit
0256 
0257 L_bugged:
0258     pushl   EX_INTERNAL|0x212
0259     call    EXCEPTION
0260     pop %ebx
0261     jmp L_error_exit
0262 
0263 L_error_exit:
0264     movl    $-1,%eax
0265 
0266 #endif /* PARANOID */
0267 
0268 L_exit:
0269     popl    %ebx
0270     popl    %edi
0271     popl    %esi
0272     leave
0273     RET
0274 SYM_FUNC_END(FPU_u_sub)