summaryrefslogtreecommitdiff
path: root/libc/i386fp/fmul.x
blob: aa62b5c70b0b32db62da7e81a31fd14b4370b087 (plain)
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
149
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