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