Merge git://git.linux-nfs.org/pub/linux/nfs-2.6
[linux-2.6] / arch / x86 / math-emu / reg_u_mul.S
1         .file   "reg_u_mul.S"
2 /*---------------------------------------------------------------------------+
3  |  reg_u_mul.S                                                              |
4  |                                                                           |
5  | Core multiplication routine                                               |
6  |                                                                           |
7  | Copyright (C) 1992,1993,1995,1997                                         |
8  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
9  |                  E-mail   billm@suburbia.net                              |
10  |                                                                           |
11  |                                                                           |
12  +---------------------------------------------------------------------------*/
13
14 /*---------------------------------------------------------------------------+
15  |   Basic multiplication routine.                                           |
16  |   Does not check the resulting exponent for overflow/underflow            |
17  |                                                                           |
18  |   FPU_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw);         |
19  |                                                                           |
20  |   Internal working is at approx 128 bits.                                 |
21  |   Result is rounded to nearest 53 or 64 bits, using "nearest or even".    |
22  +---------------------------------------------------------------------------*/
23
24 #include "exception.h"
25 #include "fpu_emu.h"
26 #include "control_w.h"
27
28
29
30 #ifndef NON_REENTRANT_FPU
31 /*  Local storage on the stack: */
32 #define FPU_accum_0     -4(%ebp)        /* ms word */
33 #define FPU_accum_1     -8(%ebp)
34
35 #else
36 /*  Local storage in a static area: */
37 .data
38         .align 4,0
39 FPU_accum_0:
40         .long   0
41 FPU_accum_1:
42         .long   0
43 #endif /* NON_REENTRANT_FPU */
44
45
46 .text
47 ENTRY(FPU_u_mul)
48         pushl   %ebp
49         movl    %esp,%ebp
50 #ifndef NON_REENTRANT_FPU
51         subl    $8,%esp
52 #endif /* NON_REENTRANT_FPU */ 
53
54         pushl   %esi
55         pushl   %edi
56         pushl   %ebx
57
58         movl    PARAM1,%esi
59         movl    PARAM2,%edi
60
61 #ifdef PARANOID
62         testl   $0x80000000,SIGH(%esi)
63         jz      L_bugged
64         testl   $0x80000000,SIGH(%edi)
65         jz      L_bugged
66 #endif /* PARANOID */
67
68         xorl    %ecx,%ecx
69         xorl    %ebx,%ebx
70
71         movl    SIGL(%esi),%eax
72         mull    SIGL(%edi)
73         movl    %eax,FPU_accum_0
74         movl    %edx,FPU_accum_1
75
76         movl    SIGL(%esi),%eax
77         mull    SIGH(%edi)
78         addl    %eax,FPU_accum_1
79         adcl    %edx,%ebx
80 /*      adcl    $0,%ecx         // overflow here is not possible */
81
82         movl    SIGH(%esi),%eax
83         mull    SIGL(%edi)
84         addl    %eax,FPU_accum_1
85         adcl    %edx,%ebx
86         adcl    $0,%ecx
87
88         movl    SIGH(%esi),%eax
89         mull    SIGH(%edi)
90         addl    %eax,%ebx
91         adcl    %edx,%ecx
92
93         /* Get the sum of the exponents. */
94         movl    PARAM6,%eax
95         subl    EXP_BIAS-1,%eax
96
97         /* Two denormals can cause an exponent underflow */
98         cmpl    EXP_WAY_UNDER,%eax
99         jg      Exp_not_underflow
100
101         /* Set to a really low value allow correct handling */
102         movl    EXP_WAY_UNDER,%eax
103
104 Exp_not_underflow:
105
106 /*  Have now finished with the sources */
107         movl    PARAM3,%edi     /* Point to the destination */
108         movw    %ax,EXP(%edi)
109
110 /*  Now make sure that the result is normalized */
111         testl   $0x80000000,%ecx
112         jnz     LResult_Normalised
113
114         /* Normalize by shifting left one bit */
115         shll    $1,FPU_accum_0
116         rcll    $1,FPU_accum_1
117         rcll    $1,%ebx
118         rcll    $1,%ecx
119         decw    EXP(%edi)
120
121 LResult_Normalised:
122         movl    FPU_accum_0,%eax
123         movl    FPU_accum_1,%edx
124         orl     %eax,%eax
125         jz      L_extent_zero
126
127         orl     $1,%edx
128
129 L_extent_zero:
130         movl    %ecx,%eax
131         jmp     fpu_reg_round
132
133
134 #ifdef PARANOID
135 L_bugged:
136         pushl   EX_INTERNAL|0x205
137         call    EXCEPTION
138         pop     %ebx
139         jmp     L_exit
140
141 L_exit:
142         popl    %ebx
143         popl    %edi
144         popl    %esi
145         leave
146         ret
147 #endif /* PARANOID */ 
148