summaryrefslogtreecommitdiff
path: root/libc/i386fp/fmul.x
diff options
context:
space:
mode:
Diffstat (limited to 'libc/i386fp/fmul.x')
-rw-r--r--libc/i386fp/fmul.x150
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