|
|
1.1 ! root 1: .file "reg_u_sub.S" ! 2: /*---------------------------------------------------------------------------+ ! 3: | reg_u_sub.S | ! 4: | | ! 5: | Core floating point subtraction routine. | ! 6: | | ! 7: | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | ! 8: | Australia. E-mail [email protected] | ! 9: | | ! 10: | Call from C as: | ! 11: | void reg_u_sub(reg *arg1, reg *arg2, reg *answ) | ! 12: | | ! 13: +---------------------------------------------------------------------------*/ ! 14: ! 15: /* ! 16: | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ). ! 17: | Takes two valid reg f.p. numbers (TW_Valid), which are ! 18: | treated as unsigned numbers, ! 19: | and returns their difference as a TW_Valid or TW_Zero f.p. ! 20: | number. ! 21: | The first number (arg1) must be the larger. ! 22: | The returned number is normalized. ! 23: | Basic checks are performed if PARANOID is defined. ! 24: */ ! 25: ! 26: #include "exception.h" ! 27: #include "fpu_asm.h" ! 28: ! 29: ! 30: .text ! 31: .align 2,144 ! 32: .globl reg_u_sub ! 33: reg_u_sub: ! 34: pushl %ebp ! 35: movl %esp,%ebp ! 36: pushl %esi ! 37: pushl %edi ! 38: pushl %ebx ! 39: ! 40: movl PARAM1,%esi /* source 1 */ ! 41: movl PARAM2,%edi /* source 2 */ ! 42: ! 43: // xorl %ecx,%ecx ! 44: movl EXP(%esi),%ecx ! 45: subl EXP(%edi),%ecx /* exp1 - exp2 */ ! 46: ! 47: #ifdef PARANOID ! 48: /* source 2 is always smaller than source 1 */ ! 49: // jc L_bugged ! 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 EXP(%esi),%edx ! 68: movl %edx,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: L_shift_r: ! 78: cmpl $32,%ecx /* 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: ! 87: L_more_than_31: ! 88: cmpl $64,%ecx ! 89: jnc L_more_than_63 ! 90: ! 91: subb $32,%cl ! 92: shrd %cl,%eax,%edx ! 93: movl %eax,%ebx ! 94: shr %cl,%ebx ! 95: xorl %eax,%eax ! 96: jmp L_shift_done ! 97: ! 98: L_more_than_63: ! 99: cmpl $66,%ecx ! 100: jnc L_more_than_65 ! 101: ! 102: subb $64,%cl ! 103: movl %eax,%edx ! 104: shr %cl,%edx ! 105: xorl %ebx,%ebx ! 106: xorl %eax,%eax ! 107: jmp L_shift_done ! 108: ! 109: L_more_than_65: ! 110: /* just copy the larger reg to dest */ ! 111: movw SIGN(%esi),%ax ! 112: movw %ax,SIGN(%edi) ! 113: movl EXP(%esi),%eax ! 114: movl %eax,EXP(%edi) ! 115: movl SIGL(%esi),%eax ! 116: movl %eax,SIGL(%edi) ! 117: movl SIGH(%esi),%eax ! 118: movl %eax,SIGH(%edi) ! 119: jmp L_exit // Does not underflow ! 120: ! 121: L_shift_done: ! 122: L_subtr: ! 123: /*------------------------------+ ! 124: | Do the subtraction | ! 125: +------------------------------*/ ! 126: xorl %ecx,%ecx ! 127: subl %edx,%ecx ! 128: movl %ecx,%edx ! 129: movl SIGL(%esi),%ecx ! 130: sbbl %ebx,%ecx ! 131: movl %ecx,%ebx ! 132: movl SIGH(%esi),%ecx ! 133: sbbl %eax,%ecx ! 134: movl %ecx,%eax ! 135: ! 136: #ifdef PARANOID ! 137: /* We can never get a borrow */ ! 138: jc L_bugged ! 139: #endif PARANOID ! 140: ! 141: /*--------------------------------------+ ! 142: | Normalize the result | ! 143: +--------------------------------------*/ ! 144: testl $0x80000000,%eax ! 145: jnz L_round /* no shifting needed */ ! 146: ! 147: orl %eax,%eax ! 148: jnz L_shift_1 /* shift left 1 - 31 bits */ ! 149: ! 150: orl %ebx,%ebx ! 151: jnz L_shift_32 /* shift left 32 - 63 bits */ ! 152: ! 153: // A rare case, the only one which is non-zero if we got here ! 154: // is: 1000000 .... 0000 ! 155: // -0111111 .... 1111 1 ! 156: // -------------------- ! 157: // 0000000 .... 0000 1 ! 158: ! 159: cmpl $0x80000000,%edx ! 160: jnz L_must_be_zero ! 161: ! 162: /* Shift left 64 bits */ ! 163: subl $64,EXP(%edi) ! 164: movl %edx,%eax ! 165: jmp L_store ! 166: ! 167: L_must_be_zero: ! 168: #ifdef PARANOID ! 169: orl %edx,%edx ! 170: jnz L_bugged_3 ! 171: #endif PARANOID ! 172: ! 173: /* The result is zero */ ! 174: movb TW_Zero,TAG(%edi) ! 175: movl $0,EXP(%edi) /* exponent */ ! 176: movl $0,SIGL(%edi) ! 177: movl $0,SIGH(%edi) ! 178: jmp L_exit // Does not underflow ! 179: ! 180: L_shift_32: ! 181: movl %ebx,%eax ! 182: movl %edx,%ebx ! 183: movl $0,%edx ! 184: subl $32,EXP(%edi) /* Can get underflow here */ ! 185: ! 186: /* We need to shift left by 1 - 31 bits */ ! 187: L_shift_1: ! 188: bsrl %eax,%ecx /* get the required shift in %ecx */ ! 189: subl $31,%ecx ! 190: negl %ecx ! 191: shld %cl,%ebx,%eax ! 192: shld %cl,%edx,%ebx ! 193: shl %cl,%edx ! 194: subl %ecx,EXP(%edi) /* Can get underflow here */ ! 195: ! 196: L_round: ! 197: /*------------------------------+ ! 198: | Round the result | ! 199: +------------------------------*/ ! 200: cmpl $0x80000000,%edx ! 201: jc L_store ! 202: ! 203: jne L_round_up ! 204: ! 205: testb $1,%dl ! 206: jz L_store ! 207: ! 208: L_round_up: ! 209: addl $1,%ebx ! 210: adcl $0,%eax ! 211: jnc L_store ! 212: ! 213: /* We just rounded up to (1) 00 00 */ ! 214: /* This *is* possible, if the subtraction is of the ! 215: form (1. + x) - (x + y) where x is small and y is ! 216: very small. */ ! 217: incl EXP(%edi) ! 218: movl $0x80000000,%eax ! 219: ! 220: L_store: ! 221: /*------------------------------+ ! 222: | Store the result | ! 223: +------------------------------*/ ! 224: movl %eax,SIGH(%edi) ! 225: movl %ebx,SIGL(%edi) ! 226: ! 227: movb TW_Valid,TAG(%edi) /* Set the tags to TW_Valid */ ! 228: ! 229: cmpl EXP_UNDER,EXP(%edi) ! 230: jle L_underflow ! 231: ! 232: L_exit: ! 233: popl %ebx ! 234: popl %edi ! 235: popl %esi ! 236: leave ! 237: ret ! 238: ! 239: ! 240: L_underflow: ! 241: push %edi ! 242: call arith_underflow ! 243: pop %ebx ! 244: jmp L_exit ! 245: ! 246: ! 247: #ifdef PARANOID ! 248: L_bugged_1: ! 249: pushl EX_INTERNAL|0x206 ! 250: call EXCEPTION ! 251: pop %ebx ! 252: jmp L_exit ! 253: ! 254: L_bugged_2: ! 255: pushl EX_INTERNAL|0x209 ! 256: call EXCEPTION ! 257: pop %ebx ! 258: jmp L_exit ! 259: ! 260: L_bugged_3: ! 261: pushl EX_INTERNAL|0x210 ! 262: call EXCEPTION ! 263: pop %ebx ! 264: jmp L_exit ! 265: ! 266: L_bugged_4: ! 267: pushl EX_INTERNAL|0x211 ! 268: call EXCEPTION ! 269: pop %ebx ! 270: jmp L_exit ! 271: ! 272: L_bugged: ! 273: pushl EX_INTERNAL|0x212 ! 274: call EXCEPTION ! 275: pop %ebx ! 276: jmp L_exit ! 277: #endif PARANOID
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.