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 | .file "reg_u_mul.S" /*---------------------------------------------------------------------------+ | reg_u_mul.S | | | | Core multiplication routine | | | | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | | Australia. E-mail apm233m@vaxc.cc.monash.edu.au | | | | | +---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------+ | Basic multiplication routine. | | Does not check the resulting exponent for overflow/underflow | | | | Internal working is at approx 96 bits. | | Result is rounded to nearest 64 bits, using "nearest or even". | +---------------------------------------------------------------------------*/ #include "exception.h" #include "fpu_asm.h" .data .align 2,0 accum_1: .long 0 .text .align 2,144 .globl _reg_u_mul _reg_u_mul: pushl %ebp movl %esp,%ebp pushl %esi pushl %edi pushl %ebx movl PARAM1,%esi movl PARAM2,%ecx #ifdef PARANOID testl $0x80000000,SIGH(%esi) jz xL_bugged testl $0x80000000,SIGH(%ecx) jz xL_bugged #endif PARANOID xorl %edi,%edi xorl %ebx,%ebx movl SIGL(%esi),%eax mull SIGL(%ecx) // movl %eax,accum_0 movl %edx,accum_1 movl SIGL(%esi),%eax mull SIGH(%ecx) addl %eax,accum_1 adcl %edx,%ebx // adcl $0,%edi // overflow here is not possible movl SIGH(%esi),%eax mull SIGL(%ecx) addl %eax,accum_1 adcl %edx,%ebx adcl $0,%edi movl SIGH(%esi),%eax mull SIGH(%ecx) addl %eax,%ebx adcl %edx,%edi movl EXP(%esi),%eax /* Compute the exponent */ addl EXP(%ecx),%eax // Have now finished with the sources movl PARAM3,%esi // Point to the destination movl %eax,EXP(%esi) // Now make sure that the result is normalized testl $0x80000000,%edi jnz L20 /* Normalize by shifting left one bit */ // shll $1,accum_0 // If using this, change next to rcll shll $1,accum_1 rcll $1,%ebx rcll $1,%edi decl EXP(%esi) L20: /* Do the rounding */ cmpl $0x80000000,accum_1 jc L40 jne L30 /* 0x80000000, round up only if previous bit is 1 */ testl $1,%ebx jz L40 L30: addl $1,%ebx adcl $0,%edi /* An overflow can occur here (rare!) */ jc xL_overflow_adjust L40: /* Copy the result to the destination register */ movl %ebx,SIGL(%esi) movl %edi,SIGH(%esi) xL_exit: popl %ebx popl %edi popl %esi leave ret xL_overflow_adjust: rcrl %edi incl EXP(%esi) jmp L40 #ifdef PARANOID xL_bugged: pushl EX_INTERNAL|0x205 call EXCEPTION pop %ebx jmp xL_exit #endif PARANOID |