Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | |
34 | ENTRY(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 | ||
58 | L_arg1_larger: | |
59 | /* num1 has larger or equal exponent */ | |
60 | movl SIGL(%edi),%ebx | |
61 | movl SIGH(%edi),%eax | |
62 | ||
63 | L_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 | ||
87 | L_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 | ||
101 | L_more_31_no_low: | |
102 | movl %eax,%ebx | |
103 | xorl %eax,%eax | |
104 | jmp L_shift_done | |
105 | ||
106 | L_exactly_32: | |
107 | movl %ebx,%edx | |
108 | movl %eax,%ebx | |
109 | xorl %eax,%eax | |
110 | jmp L_shift_done | |
111 | ||
112 | L_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 | ||
123 | L_more_than_64: | |
124 | movl $1,%edx /* The shifted nr always at least one '1' */ | |
125 | ||
126 | L_more_63_no_low: | |
127 | xorl %ebx,%ebx | |
128 | xorl %eax,%eax | |
129 | ||
130 | L_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 | ||
144 | L_no_bit_lost: | |
145 | incw EXP(%edi) | |
146 | ||
147 | L_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! */ | |
154 | L_bugged: | |
155 | pushl EX_INTERNAL|0x201 | |
156 | call EXCEPTION | |
157 | pop %ebx | |
158 | movl $-1,%eax | |
159 | jmp L_exit | |
160 | ||
161 | L_exit: | |
162 | popl %ebx | |
163 | popl %edi | |
164 | popl %esi | |
165 | leave | |
166 | ret | |
167 | #endif /* PARANOID */ |