diff options
Diffstat (limited to 'libc/i386fp/fmul.x')
-rw-r--r-- | libc/i386fp/fmul.x | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/libc/i386fp/fmul.x b/libc/i386fp/fmul.x new file mode 100644 index 0000000..aa62b5c --- /dev/null +++ b/libc/i386fp/fmul.x @@ -0,0 +1,150 @@ +! bcc 386 floating point routines (version 2) -- Fmul, Fmuld, Fmulf +! author: Bruce Evans + +#include "fplib.h" + +#define FRAME_SIZE (3 * GENREG_SIZE + PC_SIZE) + + .extern Fpushf + .extern fpoverflow + .extern fpunderflow + .extern normalize2 + + .globl Fmul + .align ALIGNMENT +Fmul: + push ebp + push edi + push esi + mov eax,FRAME_SIZE+D_LOW[esp] + mov edx,FRAME_SIZE+D_HIGH[esp] + mov ebx,FRAME_SIZE+D_SIZE+D_LOW[esp] + mov ecx,FRAME_SIZE+D_SIZE+D_HIGH[esp] + call multiplication + mov FRAME_SIZE+D_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret #D_SIZE + + .globl Fmuld + .align ALIGNMENT +Fmuld: + push ebp + push edi + push esi + mov eax,FRAME_SIZE+D_LOW[esp] + mov edx,FRAME_SIZE+D_HIGH[esp] + mov ecx,D_HIGH[ebx] + mov ebx,D_LOW[ebx] + call multiplication + mov FRAME_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret + + .globl Fmulf + .align ALIGNMENT +Fmulf: + push ebp + push edi + push esi + call Fpushf + pop ebx ! yl + pop ecx ! xu + mov eax,FRAME_SIZE+D_LOW[esp] ! xl + mov edx,FRAME_SIZE+D_HIGH[esp] ! xu + call multiplication + mov FRAME_SIZE+D_LOW[esp],eax + mov FRAME_SIZE+D_HIGH[esp],edx + pop esi + pop edi + pop ebp + ret + + .align ALIGNMENT +exp_x_0: + mov edx,#1 << D_EXP_SHIFT ! change exponent from 0 to 1 + jmp x_unpacked ! XXX - check for denormal? + + .align ALIGNMENT +exp_y_0: + mov ecx,#1 << D_EXP_SHIFT + jmp y_unpacked + + .align ALIGNMENT +multiplication: + mov ebp,edx ! xu + xor ebp,ecx ! xu ^ yu + and ebp,#D_SIGN_MASK ! sign of result is difference of signs + + mov esi,edx ! free edx for multiplications + and esi,#D_FRAC_MASK ! discard sign and exponent + and edx,#D_EXP_MASK ! exponent(x) + jz exp_x_0 + or esi,#D_NORM_MASK ! normalize +x_unpacked: + + mov edi,ecx ! this mainly for consistent naming + and edi,#D_FRAC_MASK + and ecx,#D_EXP_MASK ! exponent(y) + jz exp_y_0 + or edi,#D_NORM_MASK +y_unpacked: + + add ecx,edx ! add exponents + +! exponent is in ecx, sign in ebp, operands in esi:eax and edi:ebx, edx is free +! product to go in esi:eax:ebp:ebx +! terminology: x * y = (xu,xl) * (yu,yl) +! = (xu * yu,0,0) + (0,xu * yl + xl * yu,0) + (0,0,xl * yl) + + push ecx + push ebp + mov ecx,eax + mul ebx ! xl * yl + mov ebp,edx ! (xl * yl).u in ebp + xchg ebx,eax ! (xl * yl).l in ebx (final), yl in eax + mul esi ! xu * yl + push eax ! (xu * yl).l on stack + push edx ! (xu * yl).u on stack + mov eax,esi ! xu + mul edi ! xu * yu + mov esi,edx ! (xu * yu).u in esi (final except carries) + xchg ecx,eax ! (xu * yu).l in ecx, xl in eax + mul edi ! xl * yu + + add ebp,eax ! (xl * yl).u + (xl * yu).l + pop eax ! (xu * yl).u + adc eax,edx ! (xu * yl).u + (xl * yu).u + adc esi,#0 + pop edx ! (xu * yl).l + add ebp,edx ! ((xl * yl).u + (xl * yu).l) + (xu * yl).l + adc eax,ecx ! ((xu * yl).u + (xl * yu).u) + (xu * yu).l + adc esi,#0 + pop edx ! sign + pop edi ! exponent + sub edi,#(D_EXP_BIAS+1-(D_EXP_BIT+2)) << D_EXP_SHIFT ! adjust +! cmp edi,#(D_EXP_INFINITE-1+(D_EXP_BIT+2)) << D_EXP_SHIFT +! jae outofbounds ! 0 will be caught as underflow by normalize2 +cmp edi,#(2*D_EXP_INFINITE-(D_EXP_BIAS+1)+(D_EXP_BIT+2)) << D_EXP_SHIFT +ja underflow + br normalize2 + + .align ALIGNMENT +overflow: + mov edx,ebp ! put sign in usual reg + call fpoverflow + mov eax,ecx ! XXX - wrong reg + ret + + .align ALIGNMENT +underflow: + mov edx,ebp ! put sign in usual reg + neg edi + shr edi,#D_EXP_SHIFT + inc edi + br fpunderflow |