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