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