summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/math-emu/reg_u_add.S')
-rw-r--r--arch/i386/math-emu/reg_u_add.S167
1 files changed, 167 insertions, 0 deletions
diff --git a/arch/i386/math-emu/reg_u_add.S b/arch/i386/math-emu/reg_u_add.S
new file mode 100644
index 000000000000..47c4c2434d85
--- /dev/null
+++ b/arch/i386/math-emu/reg_u_add.S
@@ -0,0 +1,167 @@
1 .file "reg_u_add.S"
2/*---------------------------------------------------------------------------+
3 | reg_u_add.S |
4 | |
5 | Add two valid (TAG_Valid) FPU_REG numbers, of the same sign, and put the |
6 | result in a destination FPU_REG. |
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 | Call from C as: |
13 | int FPU_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
14 | int control_w) |
15 | Return value is the tag of the answer, or-ed with FPU_Exception if |
16 | one was raised, or -1 on internal error. |
17 | |
18 +---------------------------------------------------------------------------*/
19
20/*
21 | Kernel addition routine FPU_u_add(reg *arg1, reg *arg2, reg *answ).
22 | Takes two valid reg f.p. numbers (TAG_Valid), which are
23 | treated as unsigned numbers,
24 | and returns their sum as a TAG_Valid or TAG_Special f.p. number.
25 | The returned number is normalized.
26 | Basic checks are performed if PARANOID is defined.
27 */
28
29#include "exception.h"
30#include "fpu_emu.h"
31#include "control_w.h"
32
33.text
34ENTRY(FPU_u_add)
35 pushl %ebp
36 movl %esp,%ebp
37 pushl %esi
38 pushl %edi
39 pushl %ebx
40
41 movl PARAM1,%esi /* source 1 */
42 movl PARAM2,%edi /* source 2 */
43
44 movl PARAM6,%ecx
45 movl %ecx,%edx
46 subl PARAM7,%ecx /* exp1 - exp2 */
47 jge L_arg1_larger
48
49 /* num1 is smaller */
50 movl SIGL(%esi),%ebx
51 movl SIGH(%esi),%eax
52
53 movl %edi,%esi
54 movl PARAM7,%edx
55 negw %cx
56 jmp L_accum_loaded
57
58L_arg1_larger:
59 /* num1 has larger or equal exponent */
60 movl SIGL(%edi),%ebx
61 movl SIGH(%edi),%eax
62
63L_accum_loaded:
64 movl PARAM3,%edi /* destination */
65 movw %dx,EXP(%edi) /* Copy exponent to destination */
66
67 xorl %edx,%edx /* clear the extension */
68
69#ifdef PARANOID
70 testl $0x80000000,%eax
71 je L_bugged
72
73 testl $0x80000000,SIGH(%esi)
74 je L_bugged
75#endif /* PARANOID */
76
77/* The number to be shifted is in %eax:%ebx:%edx */
78 cmpw $32,%cx /* shrd only works for 0..31 bits */
79 jnc L_more_than_31
80
81/* less than 32 bits */
82 shrd %cl,%ebx,%edx
83 shrd %cl,%eax,%ebx
84 shr %cl,%eax
85 jmp L_shift_done
86
87L_more_than_31:
88 cmpw $64,%cx
89 jnc L_more_than_63
90
91 subb $32,%cl
92 jz L_exactly_32
93
94 shrd %cl,%eax,%edx
95 shr %cl,%eax
96 orl %ebx,%ebx
97 jz L_more_31_no_low /* none of the lowest bits is set */
98
99 orl $1,%edx /* record the fact in the extension */
100
101L_more_31_no_low:
102 movl %eax,%ebx
103 xorl %eax,%eax
104 jmp L_shift_done
105
106L_exactly_32:
107 movl %ebx,%edx
108 movl %eax,%ebx
109 xorl %eax,%eax
110 jmp L_shift_done
111
112L_more_than_63:
113 cmpw $65,%cx
114 jnc L_more_than_64
115
116 movl %eax,%edx
117 orl %ebx,%ebx
118 jz L_more_63_no_low
119
120 orl $1,%edx
121 jmp L_more_63_no_low
122
123L_more_than_64:
124 movl $1,%edx /* The shifted nr always at least one '1' */
125
126L_more_63_no_low:
127 xorl %ebx,%ebx
128 xorl %eax,%eax
129
130L_shift_done:
131 /* Now do the addition */
132 addl SIGL(%esi),%ebx
133 adcl SIGH(%esi),%eax
134 jnc L_round_the_result
135
136 /* Overflow, adjust the result */
137 rcrl $1,%eax
138 rcrl $1,%ebx
139 rcrl $1,%edx
140 jnc L_no_bit_lost
141
142 orl $1,%edx
143
144L_no_bit_lost:
145 incw EXP(%edi)
146
147L_round_the_result:
148 jmp fpu_reg_round /* Round the result */
149
150
151
152#ifdef PARANOID
153/* If we ever get here then we have problems! */
154L_bugged:
155 pushl EX_INTERNAL|0x201
156 call EXCEPTION
157 pop %ebx
158 movl $-1,%eax
159 jmp L_exit
160
161L_exit:
162 popl %ebx
163 popl %edi
164 popl %esi
165 leave
166 ret
167#endif /* PARANOID */