Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | .file "reg_u_mul.S" /*---------------------------------------------------------------------------+ | reg_u_mul.S | | | | Core multiplication routine | | | | Copyright (C) 1992,1993,1995,1997 | | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | | E-mail billm@suburbia.net | | | | | +---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------+ | Basic multiplication routine. | | Does not check the resulting exponent for overflow/underflow | | | | FPU_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); | | | | Internal working is at approx 128 bits. | | Result is rounded to nearest 53 or 64 bits, using "nearest or even". | +---------------------------------------------------------------------------*/ #include "exception.h" #include "fpu_emu.h" #include "control_w.h" #ifndef NON_REENTRANT_FPU /* Local storage on the stack: */ #define FPU_accum_0 -4(%ebp) /* ms word */ #define FPU_accum_1 -8(%ebp) #else /* Local storage in a static area: */ .data .align 4,0 FPU_accum_0: .long 0 FPU_accum_1: .long 0 #endif NON_REENTRANT_FPU .text ENTRY(FPU_u_mul) pushl %ebp movl %esp,%ebp #ifndef NON_REENTRANT_FPU subl $8,%esp #endif NON_REENTRANT_FPU pushl %esi pushl %edi pushl %ebx movl PARAM1,%esi movl PARAM2,%edi #ifdef PARANOID testl $0x80000000,SIGH(%esi) jz L_bugged testl $0x80000000,SIGH(%edi) jz L_bugged #endif PARANOID xorl %ecx,%ecx xorl %ebx,%ebx movl SIGL(%esi),%eax mull SIGL(%edi) movl %eax,FPU_accum_0 movl %edx,FPU_accum_1 movl SIGL(%esi),%eax mull SIGH(%edi) addl %eax,FPU_accum_1 adcl %edx,%ebx /* adcl $0,%ecx // overflow here is not possible */ movl SIGH(%esi),%eax mull SIGL(%edi) addl %eax,FPU_accum_1 adcl %edx,%ebx adcl $0,%ecx movl SIGH(%esi),%eax mull SIGH(%edi) addl %eax,%ebx adcl %edx,%ecx /* Get the sum of the exponents. */ movl PARAM6,%eax subl EXP_BIAS-1,%eax /* Two denormals can cause an exponent underflow */ cmpl EXP_WAY_UNDER,%eax jg Exp_not_underflow /* Set to a really low value allow correct handling */ movl EXP_WAY_UNDER,%eax Exp_not_underflow: /* Have now finished with the sources */ movl PARAM3,%edi /* Point to the destination */ movw %ax,EXP(%edi) /* Now make sure that the result is normalized */ testl $0x80000000,%ecx jnz LResult_Normalised /* Normalize by shifting left one bit */ shll $1,FPU_accum_0 rcll $1,FPU_accum_1 rcll $1,%ebx rcll $1,%ecx decw EXP(%edi) LResult_Normalised: movl FPU_accum_0,%eax movl FPU_accum_1,%edx orl %eax,%eax jz L_extent_zero orl $1,%edx L_extent_zero: movl %ecx,%eax jmp fpu_reg_round #ifdef PARANOID L_bugged: pushl EX_INTERNAL|0x205 call EXCEPTION pop %ebx jmp L_exit L_exit: popl %ebx popl %edi popl %esi leave ret #endif PARANOID |