1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43#include <linux/kernel.h>
44#include "float.h"
45#include "sgl_float.h"
46#include "dbl_float.h"
47#include "cnv_float.h"
48
49#include <asm/signal.h>
50#include <asm/siginfo.h>
51
52
53#undef Fpustatus_register
54#define Fpustatus_register Fpu_register[0]
55
56
57#define DOESTRAP 1
58#define NOTRAP 0
59#define SIGNALCODE(signal, code) ((signal) << 24 | (code))
60#define copropbit 1<<31-2
61#define opclass 9
62#define fmt 11
63#define df 13
64#define twobits 3
65#define fivebits 31
66#define MAX_EXCP_REG 7
67
68
69#define Excp_type(index) Exceptiontype(Fpu_register[index])
70#define Excp_instr(index) Instructionfield(Fpu_register[index])
71#define Clear_excp_register(index) Allexception(Fpu_register[index]) = 0
72#define Excp_format() \
73 (current_ir >> ((current_ir>>opclass & twobits)==1 ? df : fmt) & twobits)
74
75
76#define Fpu_sgl(index) Fpu_register[index*2]
77
78#define Fpu_dblp1(index) Fpu_register[index*2]
79#define Fpu_dblp2(index) Fpu_register[(index*2)+1]
80
81#define Fpu_quadp1(index) Fpu_register[index*2]
82#define Fpu_quadp2(index) Fpu_register[(index*2)+1]
83#define Fpu_quadp3(index) Fpu_register[(index*2)+2]
84#define Fpu_quadp4(index) Fpu_register[(index*2)+3]
85
86
87#ifndef Sgl_decrement
88# define Sgl_decrement(sgl_value) Sall(sgl_value)--
89#endif
90
91
92#ifndef Dbl_decrement
93# define Dbl_decrement(dbl_valuep1,dbl_valuep2) \
94 if ((Dallp2(dbl_valuep2)--) == 0) Dallp1(dbl_valuep1)--
95#endif
96
97
98#define update_trap_counts(Fpu_register, aflags, bflags, trap_counts) { \
99 aflags=(Fpu_register[0])>>27; \
100 Fpu_register[0] |= bflags; \
101}
102
103u_int
104decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])
105{
106 unsigned int current_ir, excp;
107 int target, exception_index = 1;
108 boolean inexact;
109 unsigned int aflags;
110 unsigned int bflags;
111 unsigned int excptype;
112
113
114
115
116
117
118
119
120 bflags=(Fpu_register[0] & 0xf8000000);
121 Fpu_register[0] &= 0x07ffffff;
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138 if (!Is_tbit_set()) {
139 update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
140 return SIGNALCODE(SIGILL, ILL_COPROC);
141 }
142
143
144
145
146
147
148 for (exception_index=1; exception_index<=MAX_EXCP_REG; exception_index++) {
149 current_ir = Excp_instr(exception_index);
150
151
152
153
154
155 excptype = Excp_type(exception_index);
156 if (excptype & UNIMPLEMENTEDEXCEPTION) {
157
158
159
160
161
162 Clear_tbit();
163 Clear_excp_register(exception_index);
164
165
166
167
168 excp = fpudispatch(current_ir,excptype,0,Fpu_register);
169
170 if (excp) {
171
172
173
174
175
176
177
178
179
180 Set_tbit();
181
182
183 Set_exceptiontype_and_instr_field(excp,current_ir,
184 Fpu_register[exception_index]);
185 if (excp == UNIMPLEMENTEDEXCEPTION) {
186
187
188
189
190 excp = excptype;
191 update_trap_counts(Fpu_register, aflags, bflags,
192 trap_counts);
193 return SIGNALCODE(SIGILL, ILL_COPROC);
194 }
195
196
197 excptype = excp;
198 }
199
200
201 if (excp == NOEXCEPTION)
202
203 break;
204 }
205
206
207
208
209
210
211
212 if (excptype & UNDERFLOWEXCEPTION) {
213
214 if (Is_underflowtrap_enabled()) {
215 update_trap_counts(Fpu_register, aflags, bflags,
216 trap_counts);
217 return SIGNALCODE(SIGFPE, FPE_FLTUND);
218 } else {
219
220
221
222
223 target = current_ir & fivebits;
224#ifndef lint
225 if (Ibit(Fpu_register[exception_index])) inexact = TRUE;
226 else inexact = FALSE;
227#endif
228 switch (Excp_format()) {
229 case SGL:
230
231
232
233
234
235 if (Rabit(Fpu_register[exception_index]))
236 Sgl_decrement(Fpu_sgl(target));
237
238
239 sgl_denormalize(&Fpu_sgl(target),&inexact,Rounding_mode());
240 break;
241 case DBL:
242
243
244
245
246
247 if (Rabit(Fpu_register[exception_index]))
248 Dbl_decrement(Fpu_dblp1(target),Fpu_dblp2(target));
249
250
251 dbl_denormalize(&Fpu_dblp1(target),&Fpu_dblp2(target),
252 &inexact,Rounding_mode());
253 break;
254 }
255 if (inexact) Set_underflowflag();
256
257
258
259
260
261
262 if (inexact && Is_inexacttrap_enabled()) {
263
264
265
266
267
268 Set_exceptiontype(Fpu_register[exception_index],
269 INEXACTEXCEPTION);
270 Set_parmfield(Fpu_register[exception_index],0);
271 update_trap_counts(Fpu_register, aflags, bflags,
272 trap_counts);
273 return SIGNALCODE(SIGFPE, FPE_FLTRES);
274 }
275 else {
276
277
278
279
280 Clear_excp_register(exception_index);
281 if (inexact) Set_inexactflag();
282 }
283 }
284 continue;
285 }
286 switch(Excp_type(exception_index)) {
287 case OVERFLOWEXCEPTION:
288 case OVERFLOWEXCEPTION | INEXACTEXCEPTION:
289
290 update_trap_counts(Fpu_register, aflags, bflags,
291 trap_counts);
292 if (Is_overflowtrap_enabled()) {
293 update_trap_counts(Fpu_register, aflags, bflags,
294 trap_counts);
295 return SIGNALCODE(SIGFPE, FPE_FLTOVF);
296 } else {
297
298
299
300
301 target = current_ir & fivebits;
302 switch (Excp_format()) {
303 case SGL:
304 Sgl_setoverflow(Fpu_sgl(target));
305 break;
306 case DBL:
307 Dbl_setoverflow(Fpu_dblp1(target),Fpu_dblp2(target));
308 break;
309 }
310 Set_overflowflag();
311
312
313
314
315
316
317 if (Is_inexacttrap_enabled()) {
318
319
320
321
322
323 Set_exceptiontype(Fpu_register[exception_index],
324 INEXACTEXCEPTION);
325 update_trap_counts(Fpu_register, aflags, bflags,
326 trap_counts);
327 return SIGNALCODE(SIGFPE, FPE_FLTRES);
328 }
329 else {
330
331
332
333
334 Clear_excp_register(exception_index);
335 Set_inexactflag();
336 }
337 }
338 break;
339 case INVALIDEXCEPTION:
340 case OPC_2E_INVALIDEXCEPTION:
341 update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
342 return SIGNALCODE(SIGFPE, FPE_FLTINV);
343 case DIVISIONBYZEROEXCEPTION:
344 update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
345 Clear_excp_register(exception_index);
346 return SIGNALCODE(SIGFPE, FPE_FLTDIV);
347 case INEXACTEXCEPTION:
348 update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
349 return SIGNALCODE(SIGFPE, FPE_FLTRES);
350 default:
351 update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
352 printk("%s(%d) Unknown FPU exception 0x%x\n", __FILE__,
353 __LINE__, Excp_type(exception_index));
354 return SIGNALCODE(SIGILL, ILL_COPROC);
355 case NOEXCEPTION:
356
357
358
359
360 Clear_excp_register(exception_index);
361 break;
362 }
363 }
364
365
366
367 Clear_tbit();
368 update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
369 return(NOTRAP);
370}
371