| .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 */ | |