1/* SPDX-License-Identifier: GPL-2.0 */ 2 .file "reg_u_sub.S" 3/*---------------------------------------------------------------------------+ 4 | reg_u_sub.S | 5 | | 6 | Core floating point subtraction routine. | 7 | | 8 | Copyright (C) 1992,1993,1995,1997 | 9 | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | 10 | E-mail billm@suburbia.net | 11 | | 12 | Call from C as: | 13 | int FPU_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | 14 | int control_w) | 15 | Return value is the tag of the answer, or-ed with FPU_Exception if | 16 | one was raised, or -1 on internal error. | 17 | | 18 +---------------------------------------------------------------------------*/ 19 20/* 21 | Kernel subtraction routine FPU_u_sub(reg *arg1, reg *arg2, reg *answ). 22 | Takes two valid reg f.p. numbers (TAG_Valid), which are 23 | treated as unsigned numbers, 24 | and returns their difference as a TAG_Valid or TAG_Zero f.p. 25 | number. 26 | The first number (arg1) must be the larger. 27 | The returned number is normalized. 28 | Basic checks are performed if PARANOID is defined. 29 */ 30 31#include "exception.h" 32#include "fpu_emu.h" 33#include "control_w.h" 34 35.text 36SYM_FUNC_START(FPU_u_sub) 37 pushl %ebp 38 movl %esp,%ebp 39 pushl %esi 40 pushl %edi 41 pushl %ebx 42 43 movl PARAM1,%esi /* source 1 */ 44 movl PARAM2,%edi /* source 2 */ 45 46 movl PARAM6,%ecx 47 subl PARAM7,%ecx /* exp1 - exp2 */ 48 49#ifdef PARANOID 50 /* source 2 is always smaller than source 1 */ 51 js L_bugged_1 52 53 testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */ 54 je L_bugged_2 55 56 testl $0x80000000,SIGH(%esi) 57 je L_bugged_2 58#endif /* PARANOID */ 59 60/*--------------------------------------+ 61 | Form a register holding the | 62 | smaller number | 63 +--------------------------------------*/ 64 movl SIGH(%edi),%eax /* register ms word */ 65 movl SIGL(%edi),%ebx /* register ls word */ 66 67 movl PARAM3,%edi /* destination */ 68 movl PARAM6,%edx 69 movw %dx,EXP(%edi) /* Copy exponent to destination */ 70 71 xorl %edx,%edx /* register extension */ 72 73/*--------------------------------------+ 74 | Shift the temporary register | 75 | right the required number of | 76 | places. | 77 +--------------------------------------*/ 78 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 88L_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 102L_more_31_no_low: 103 movl %eax,%ebx 104 xorl %eax,%eax 105 jmp L_shift_done 106 107L_exactly_32: 108 movl %ebx,%edx 109 movl %eax,%ebx 110 xorl %eax,%eax 111 jmp L_shift_done 112 113L_more_than_63: 114 cmpw $65,%cx 115 jnc L_more_than_64 116 117 /* Shift right by 64 bits */ 118 movl %eax,%edx 119 orl %ebx,%ebx 120 jz L_more_63_no_low 121 122 orl $1,%edx 123 jmp L_more_63_no_low 124 125L_more_than_64: 126 jne L_more_than_65 127 128 /* Shift right by 65 bits */ 129 /* Carry is clear if we get here */ 130 movl %eax,%edx 131 rcrl %edx 132 jnc L_shift_65_nc 133 134 orl $1,%edx 135 jmp L_more_63_no_low 136 137L_shift_65_nc: 138 orl %ebx,%ebx 139 jz L_more_63_no_low 140 141 orl $1,%edx 142 jmp L_more_63_no_low 143 144L_more_than_65: 145 movl $1,%edx /* The shifted nr always at least one '1' */ 146 147L_more_63_no_low: 148 xorl %ebx,%ebx 149 xorl %eax,%eax 150 151L_shift_done: 152L_subtr: 153/*------------------------------+ 154 | Do the subtraction | 155 +------------------------------*/ 156 xorl %ecx,%ecx 157 subl %edx,%ecx 158 movl %ecx,%edx 159 movl SIGL(%esi),%ecx 160 sbbl %ebx,%ecx 161 movl %ecx,%ebx 162 movl SIGH(%esi),%ecx 163 sbbl %eax,%ecx 164 movl %ecx,%eax 165 166#ifdef PARANOID 167 /* We can never get a borrow */ 168 jc L_bugged 169#endif /* PARANOID */ 170 171/*--------------------------------------+ 172 | Normalize the result | 173 +--------------------------------------*/ 174 testl $0x80000000,%eax 175 jnz L_round /* no shifting needed */ 176 177 orl %eax,%eax 178 jnz L_shift_1 /* shift left 1 - 31 bits */ 179 180 orl %ebx,%ebx 181 jnz L_shift_32 /* shift left 32 - 63 bits */ 182 183/* 184 * A rare case, the only one which is non-zero if we got here 185 * is: 1000000 .... 0000 186 * -0111111 .... 1111 1 187 * -------------------- 188 * 0000000 .... 0000 1 189 */ 190 191 cmpl $0x80000000,%edx 192 jnz L_must_be_zero 193 194 /* Shift left 64 bits */ 195 subw $64,EXP(%edi) 196 xchg %edx,%eax 197 jmp fpu_reg_round 198 199L_must_be_zero: 200#ifdef PARANOID 201 orl %edx,%edx 202 jnz L_bugged_3 203#endif /* PARANOID */ 204 205 /* The result is zero */ 206 movw $0,EXP(%edi) /* exponent */ 207 movl $0,SIGL(%edi) 208 movl $0,SIGH(%edi) 209 movl TAG_Zero,%eax 210 jmp L_exit 211 212L_shift_32: 213 movl %ebx,%eax 214 movl %edx,%ebx 215 movl $0,%edx 216 subw $32,EXP(%edi) /* Can get underflow here */ 217 218/* We need to shift left by 1 - 31 bits */ 219L_shift_1: 220 bsrl %eax,%ecx /* get the required shift in %ecx */ 221 subl $31,%ecx 222 negl %ecx 223 shld %cl,%ebx,%eax 224 shld %cl,%edx,%ebx 225 shl %cl,%edx 226 subw %cx,EXP(%edi) /* Can get underflow here */ 227 228L_round: 229 jmp fpu_reg_round /* Round the result */ 230 231 232#ifdef PARANOID 233L_bugged_1: 234 pushl EX_INTERNAL|0x206 235 call EXCEPTION 236 pop %ebx 237 jmp L_error_exit 238 239L_bugged_2: 240 pushl EX_INTERNAL|0x209 241 call EXCEPTION 242 pop %ebx 243 jmp L_error_exit 244 245L_bugged_3: 246 pushl EX_INTERNAL|0x210 247 call EXCEPTION 248 pop %ebx 249 jmp L_error_exit 250 251L_bugged_4: 252 pushl EX_INTERNAL|0x211 253 call EXCEPTION 254 pop %ebx 255 jmp L_error_exit 256 257L_bugged: 258 pushl EX_INTERNAL|0x212 259 call EXCEPTION 260 pop %ebx 261 jmp L_error_exit 262 263L_error_exit: 264 movl $-1,%eax 265 266#endif /* PARANOID */ 267 268L_exit: 269 popl %ebx 270 popl %edi 271 popl %esi 272 leave 273 ret 274SYM_FUNC_END(FPU_u_sub) 275