Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/math-emu/reg_u_mul.S
26451 views
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 [email protected] |
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
SYM_FUNC_START(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
SYM_FUNC_END(FPU_u_mul)
151
152