diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/parisc/math-emu/fpudispatch.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/parisc/math-emu/fpudispatch.c')
-rw-r--r-- | arch/parisc/math-emu/fpudispatch.c | 1442 |
1 files changed, 1442 insertions, 0 deletions
diff --git a/arch/parisc/math-emu/fpudispatch.c b/arch/parisc/math-emu/fpudispatch.c new file mode 100644 index 000000000000..6e28f9f4c620 --- /dev/null +++ b/arch/parisc/math-emu/fpudispatch.c | |||
@@ -0,0 +1,1442 @@ | |||
1 | /* | ||
2 | * Linux/PA-RISC Project (http://www.parisc-linux.org/) | ||
3 | * | ||
4 | * Floating-point emulation code | ||
5 | * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2, or (at your option) | ||
10 | * any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | /* | ||
22 | * BEGIN_DESC | ||
23 | * | ||
24 | * File: | ||
25 | * @(#) pa/fp/fpudispatch.c $Revision: 1.1 $ | ||
26 | * | ||
27 | * Purpose: | ||
28 | * <<please update with a synopsis of the functionality provided by this file>> | ||
29 | * | ||
30 | * External Interfaces: | ||
31 | * <<the following list was autogenerated, please review>> | ||
32 | * emfpudispatch(ir, dummy1, dummy2, fpregs) | ||
33 | * fpudispatch(ir, excp_code, holder, fpregs) | ||
34 | * | ||
35 | * Internal Interfaces: | ||
36 | * <<the following list was autogenerated, please review>> | ||
37 | * static u_int decode_06(u_int, u_int *) | ||
38 | * static u_int decode_0c(u_int, u_int, u_int, u_int *) | ||
39 | * static u_int decode_0e(u_int, u_int, u_int, u_int *) | ||
40 | * static u_int decode_26(u_int, u_int *) | ||
41 | * static u_int decode_2e(u_int, u_int *) | ||
42 | * static void update_status_cbit(u_int *, u_int, u_int, u_int) | ||
43 | * | ||
44 | * Theory: | ||
45 | * <<please update with a overview of the operation of this file>> | ||
46 | * | ||
47 | * END_DESC | ||
48 | */ | ||
49 | |||
50 | #define FPUDEBUG 0 | ||
51 | |||
52 | #include "float.h" | ||
53 | #include <linux/kernel.h> | ||
54 | #include <asm/processor.h> | ||
55 | /* #include <sys/debug.h> */ | ||
56 | /* #include <machine/sys/mdep_private.h> */ | ||
57 | |||
58 | #define COPR_INST 0x30000000 | ||
59 | |||
60 | /* | ||
61 | * definition of extru macro. If pos and len are constants, the compiler | ||
62 | * will generate an extru instruction when optimized | ||
63 | */ | ||
64 | #define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1)) | ||
65 | /* definitions of bit field locations in the instruction */ | ||
66 | #define fpmajorpos 5 | ||
67 | #define fpr1pos 10 | ||
68 | #define fpr2pos 15 | ||
69 | #define fptpos 31 | ||
70 | #define fpsubpos 18 | ||
71 | #define fpclass1subpos 16 | ||
72 | #define fpclasspos 22 | ||
73 | #define fpfmtpos 20 | ||
74 | #define fpdfpos 18 | ||
75 | #define fpnulpos 26 | ||
76 | /* | ||
77 | * the following are the extra bits for the 0E major op | ||
78 | */ | ||
79 | #define fpxr1pos 24 | ||
80 | #define fpxr2pos 19 | ||
81 | #define fpxtpos 25 | ||
82 | #define fpxpos 23 | ||
83 | #define fp0efmtpos 20 | ||
84 | /* | ||
85 | * the following are for the multi-ops | ||
86 | */ | ||
87 | #define fprm1pos 10 | ||
88 | #define fprm2pos 15 | ||
89 | #define fptmpos 31 | ||
90 | #define fprapos 25 | ||
91 | #define fptapos 20 | ||
92 | #define fpmultifmt 26 | ||
93 | /* | ||
94 | * the following are for the fused FP instructions | ||
95 | */ | ||
96 | /* fprm1pos 10 */ | ||
97 | /* fprm2pos 15 */ | ||
98 | #define fpraupos 18 | ||
99 | #define fpxrm2pos 19 | ||
100 | /* fpfmtpos 20 */ | ||
101 | #define fpralpos 23 | ||
102 | #define fpxrm1pos 24 | ||
103 | /* fpxtpos 25 */ | ||
104 | #define fpfusedsubop 26 | ||
105 | /* fptpos 31 */ | ||
106 | |||
107 | /* | ||
108 | * offset to constant zero in the FP emulation registers | ||
109 | */ | ||
110 | #define fpzeroreg (32*sizeof(double)/sizeof(u_int)) | ||
111 | |||
112 | /* | ||
113 | * extract the major opcode from the instruction | ||
114 | */ | ||
115 | #define get_major(op) extru(op,fpmajorpos,6) | ||
116 | /* | ||
117 | * extract the two bit class field from the FP instruction. The class is at bit | ||
118 | * positions 21-22 | ||
119 | */ | ||
120 | #define get_class(op) extru(op,fpclasspos,2) | ||
121 | /* | ||
122 | * extract the 3 bit subop field. For all but class 1 instructions, it is | ||
123 | * located at bit positions 16-18 | ||
124 | */ | ||
125 | #define get_subop(op) extru(op,fpsubpos,3) | ||
126 | /* | ||
127 | * extract the 2 or 3 bit subop field from class 1 instructions. It is located | ||
128 | * at bit positions 15-16 (PA1.1) or 14-16 (PA2.0) | ||
129 | */ | ||
130 | #define get_subop1_PA1_1(op) extru(op,fpclass1subpos,2) /* PA89 (1.1) fmt */ | ||
131 | #define get_subop1_PA2_0(op) extru(op,fpclass1subpos,3) /* PA 2.0 fmt */ | ||
132 | |||
133 | /* definitions of unimplemented exceptions */ | ||
134 | #define MAJOR_0C_EXCP 0x09 | ||
135 | #define MAJOR_0E_EXCP 0x0b | ||
136 | #define MAJOR_06_EXCP 0x03 | ||
137 | #define MAJOR_26_EXCP 0x23 | ||
138 | #define MAJOR_2E_EXCP 0x2b | ||
139 | #define PA83_UNIMP_EXCP 0x01 | ||
140 | |||
141 | /* | ||
142 | * Special Defines for TIMEX specific code | ||
143 | */ | ||
144 | |||
145 | #define FPU_TYPE_FLAG_POS (EM_FPU_TYPE_OFFSET>>2) | ||
146 | #define TIMEX_ROLEX_FPU_MASK (TIMEX_EXTEN_FLAG|ROLEX_EXTEN_FLAG) | ||
147 | |||
148 | /* | ||
149 | * Static function definitions | ||
150 | */ | ||
151 | #define _PROTOTYPES | ||
152 | #if defined(_PROTOTYPES) || defined(_lint) | ||
153 | static u_int decode_0c(u_int, u_int, u_int, u_int *); | ||
154 | static u_int decode_0e(u_int, u_int, u_int, u_int *); | ||
155 | static u_int decode_06(u_int, u_int *); | ||
156 | static u_int decode_26(u_int, u_int *); | ||
157 | static u_int decode_2e(u_int, u_int *); | ||
158 | static void update_status_cbit(u_int *, u_int, u_int, u_int); | ||
159 | #else /* !_PROTOTYPES&&!_lint */ | ||
160 | static u_int decode_0c(); | ||
161 | static u_int decode_0e(); | ||
162 | static u_int decode_06(); | ||
163 | static u_int decode_26(); | ||
164 | static u_int decode_2e(); | ||
165 | static void update_status_cbit(); | ||
166 | #endif /* _PROTOTYPES&&!_lint */ | ||
167 | |||
168 | #define VASSERT(x) | ||
169 | |||
170 | static void parisc_linux_get_fpu_type(u_int fpregs[]) | ||
171 | { | ||
172 | /* on pa-linux the fpu type is not filled in by the | ||
173 | * caller; it is constructed here | ||
174 | */ | ||
175 | if (boot_cpu_data.cpu_type == pcxs) | ||
176 | fpregs[FPU_TYPE_FLAG_POS] = TIMEX_EXTEN_FLAG; | ||
177 | else if (boot_cpu_data.cpu_type == pcxt || | ||
178 | boot_cpu_data.cpu_type == pcxt_) | ||
179 | fpregs[FPU_TYPE_FLAG_POS] = ROLEX_EXTEN_FLAG; | ||
180 | else if (boot_cpu_data.cpu_type >= pcxu) | ||
181 | fpregs[FPU_TYPE_FLAG_POS] = PA2_0_FPU_FLAG; | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | * this routine will decode the excepting floating point instruction and | ||
186 | * call the approiate emulation routine. | ||
187 | * It is called by decode_fpu with the following parameters: | ||
188 | * fpudispatch(current_ir, unimplemented_code, 0, &Fpu_register) | ||
189 | * where current_ir is the instruction to be emulated, | ||
190 | * unimplemented_code is the exception_code that the hardware generated | ||
191 | * and &Fpu_register is the address of emulated FP reg 0. | ||
192 | */ | ||
193 | u_int | ||
194 | fpudispatch(u_int ir, u_int excp_code, u_int holder, u_int fpregs[]) | ||
195 | { | ||
196 | u_int class, subop; | ||
197 | u_int fpu_type_flags; | ||
198 | |||
199 | /* All FP emulation code assumes that ints are 4-bytes in length */ | ||
200 | VASSERT(sizeof(int) == 4); | ||
201 | |||
202 | parisc_linux_get_fpu_type(fpregs); | ||
203 | |||
204 | fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */ | ||
205 | |||
206 | class = get_class(ir); | ||
207 | if (class == 1) { | ||
208 | if (fpu_type_flags & PA2_0_FPU_FLAG) | ||
209 | subop = get_subop1_PA2_0(ir); | ||
210 | else | ||
211 | subop = get_subop1_PA1_1(ir); | ||
212 | } | ||
213 | else | ||
214 | subop = get_subop(ir); | ||
215 | |||
216 | if (FPUDEBUG) printk("class %d subop %d\n", class, subop); | ||
217 | |||
218 | switch (excp_code) { | ||
219 | case MAJOR_0C_EXCP: | ||
220 | case PA83_UNIMP_EXCP: | ||
221 | return(decode_0c(ir,class,subop,fpregs)); | ||
222 | case MAJOR_0E_EXCP: | ||
223 | return(decode_0e(ir,class,subop,fpregs)); | ||
224 | case MAJOR_06_EXCP: | ||
225 | return(decode_06(ir,fpregs)); | ||
226 | case MAJOR_26_EXCP: | ||
227 | return(decode_26(ir,fpregs)); | ||
228 | case MAJOR_2E_EXCP: | ||
229 | return(decode_2e(ir,fpregs)); | ||
230 | default: | ||
231 | /* "crashme Night Gallery painting nr 2. (asm_crash.s). | ||
232 | * This was fixed for multi-user kernels, but | ||
233 | * workstation kernels had a panic here. This allowed | ||
234 | * any arbitrary user to panic the kernel by executing | ||
235 | * setting the FP exception registers to strange values | ||
236 | * and generating an emulation trap. The emulation and | ||
237 | * exception code must never be able to panic the | ||
238 | * kernel. | ||
239 | */ | ||
240 | return(UNIMPLEMENTEDEXCEPTION); | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /* | ||
245 | * this routine is called by $emulation_trap to emulate a coprocessor | ||
246 | * instruction if one doesn't exist | ||
247 | */ | ||
248 | u_int | ||
249 | emfpudispatch(u_int ir, u_int dummy1, u_int dummy2, u_int fpregs[]) | ||
250 | { | ||
251 | u_int class, subop, major; | ||
252 | u_int fpu_type_flags; | ||
253 | |||
254 | /* All FP emulation code assumes that ints are 4-bytes in length */ | ||
255 | VASSERT(sizeof(int) == 4); | ||
256 | |||
257 | fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */ | ||
258 | |||
259 | major = get_major(ir); | ||
260 | class = get_class(ir); | ||
261 | if (class == 1) { | ||
262 | if (fpu_type_flags & PA2_0_FPU_FLAG) | ||
263 | subop = get_subop1_PA2_0(ir); | ||
264 | else | ||
265 | subop = get_subop1_PA1_1(ir); | ||
266 | } | ||
267 | else | ||
268 | subop = get_subop(ir); | ||
269 | switch (major) { | ||
270 | case 0x0C: | ||
271 | return(decode_0c(ir,class,subop,fpregs)); | ||
272 | case 0x0E: | ||
273 | return(decode_0e(ir,class,subop,fpregs)); | ||
274 | case 0x06: | ||
275 | return(decode_06(ir,fpregs)); | ||
276 | case 0x26: | ||
277 | return(decode_26(ir,fpregs)); | ||
278 | case 0x2E: | ||
279 | return(decode_2e(ir,fpregs)); | ||
280 | default: | ||
281 | return(PA83_UNIMP_EXCP); | ||
282 | } | ||
283 | } | ||
284 | |||
285 | |||
286 | static u_int | ||
287 | decode_0c(u_int ir, u_int class, u_int subop, u_int fpregs[]) | ||
288 | { | ||
289 | u_int r1,r2,t; /* operand register offsets */ | ||
290 | u_int fmt; /* also sf for class 1 conversions */ | ||
291 | u_int df; /* for class 1 conversions */ | ||
292 | u_int *status; | ||
293 | u_int retval, local_status; | ||
294 | u_int fpu_type_flags; | ||
295 | |||
296 | if (ir == COPR_INST) { | ||
297 | fpregs[0] = EMULATION_VERSION << 11; | ||
298 | return(NOEXCEPTION); | ||
299 | } | ||
300 | status = &fpregs[0]; /* fp status register */ | ||
301 | local_status = fpregs[0]; /* and local copy */ | ||
302 | r1 = extru(ir,fpr1pos,5) * sizeof(double)/sizeof(u_int); | ||
303 | if (r1 == 0) /* map fr0 source to constant zero */ | ||
304 | r1 = fpzeroreg; | ||
305 | t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int); | ||
306 | if (t == 0 && class != 2) /* don't allow fr0 as a dest */ | ||
307 | return(MAJOR_0C_EXCP); | ||
308 | fmt = extru(ir,fpfmtpos,2); /* get fmt completer */ | ||
309 | |||
310 | switch (class) { | ||
311 | case 0: | ||
312 | switch (subop) { | ||
313 | case 0: /* COPR 0,0 emulated above*/ | ||
314 | case 1: | ||
315 | return(MAJOR_0C_EXCP); | ||
316 | case 2: /* FCPY */ | ||
317 | switch (fmt) { | ||
318 | case 2: /* illegal */ | ||
319 | return(MAJOR_0C_EXCP); | ||
320 | case 3: /* quad */ | ||
321 | t &= ~3; /* force to even reg #s */ | ||
322 | r1 &= ~3; | ||
323 | fpregs[t+3] = fpregs[r1+3]; | ||
324 | fpregs[t+2] = fpregs[r1+2]; | ||
325 | case 1: /* double */ | ||
326 | fpregs[t+1] = fpregs[r1+1]; | ||
327 | case 0: /* single */ | ||
328 | fpregs[t] = fpregs[r1]; | ||
329 | return(NOEXCEPTION); | ||
330 | } | ||
331 | case 3: /* FABS */ | ||
332 | switch (fmt) { | ||
333 | case 2: /* illegal */ | ||
334 | return(MAJOR_0C_EXCP); | ||
335 | case 3: /* quad */ | ||
336 | t &= ~3; /* force to even reg #s */ | ||
337 | r1 &= ~3; | ||
338 | fpregs[t+3] = fpregs[r1+3]; | ||
339 | fpregs[t+2] = fpregs[r1+2]; | ||
340 | case 1: /* double */ | ||
341 | fpregs[t+1] = fpregs[r1+1]; | ||
342 | case 0: /* single */ | ||
343 | /* copy and clear sign bit */ | ||
344 | fpregs[t] = fpregs[r1] & 0x7fffffff; | ||
345 | return(NOEXCEPTION); | ||
346 | } | ||
347 | case 6: /* FNEG */ | ||
348 | switch (fmt) { | ||
349 | case 2: /* illegal */ | ||
350 | return(MAJOR_0C_EXCP); | ||
351 | case 3: /* quad */ | ||
352 | t &= ~3; /* force to even reg #s */ | ||
353 | r1 &= ~3; | ||
354 | fpregs[t+3] = fpregs[r1+3]; | ||
355 | fpregs[t+2] = fpregs[r1+2]; | ||
356 | case 1: /* double */ | ||
357 | fpregs[t+1] = fpregs[r1+1]; | ||
358 | case 0: /* single */ | ||
359 | /* copy and invert sign bit */ | ||
360 | fpregs[t] = fpregs[r1] ^ 0x80000000; | ||
361 | return(NOEXCEPTION); | ||
362 | } | ||
363 | case 7: /* FNEGABS */ | ||
364 | switch (fmt) { | ||
365 | case 2: /* illegal */ | ||
366 | return(MAJOR_0C_EXCP); | ||
367 | case 3: /* quad */ | ||
368 | t &= ~3; /* force to even reg #s */ | ||
369 | r1 &= ~3; | ||
370 | fpregs[t+3] = fpregs[r1+3]; | ||
371 | fpregs[t+2] = fpregs[r1+2]; | ||
372 | case 1: /* double */ | ||
373 | fpregs[t+1] = fpregs[r1+1]; | ||
374 | case 0: /* single */ | ||
375 | /* copy and set sign bit */ | ||
376 | fpregs[t] = fpregs[r1] | 0x80000000; | ||
377 | return(NOEXCEPTION); | ||
378 | } | ||
379 | case 4: /* FSQRT */ | ||
380 | switch (fmt) { | ||
381 | case 0: | ||
382 | return(sgl_fsqrt(&fpregs[r1],0, | ||
383 | &fpregs[t],status)); | ||
384 | case 1: | ||
385 | return(dbl_fsqrt(&fpregs[r1],0, | ||
386 | &fpregs[t],status)); | ||
387 | case 2: | ||
388 | case 3: /* quad not implemented */ | ||
389 | return(MAJOR_0C_EXCP); | ||
390 | } | ||
391 | case 5: /* FRND */ | ||
392 | switch (fmt) { | ||
393 | case 0: | ||
394 | return(sgl_frnd(&fpregs[r1],0, | ||
395 | &fpregs[t],status)); | ||
396 | case 1: | ||
397 | return(dbl_frnd(&fpregs[r1],0, | ||
398 | &fpregs[t],status)); | ||
399 | case 2: | ||
400 | case 3: /* quad not implemented */ | ||
401 | return(MAJOR_0C_EXCP); | ||
402 | } | ||
403 | } /* end of switch (subop) */ | ||
404 | |||
405 | case 1: /* class 1 */ | ||
406 | df = extru(ir,fpdfpos,2); /* get dest format */ | ||
407 | if ((df & 2) || (fmt & 2)) { | ||
408 | /* | ||
409 | * fmt's 2 and 3 are illegal of not implemented | ||
410 | * quad conversions | ||
411 | */ | ||
412 | return(MAJOR_0C_EXCP); | ||
413 | } | ||
414 | /* | ||
415 | * encode source and dest formats into 2 bits. | ||
416 | * high bit is source, low bit is dest. | ||
417 | * bit = 1 --> double precision | ||
418 | */ | ||
419 | fmt = (fmt << 1) | df; | ||
420 | switch (subop) { | ||
421 | case 0: /* FCNVFF */ | ||
422 | switch(fmt) { | ||
423 | case 0: /* sgl/sgl */ | ||
424 | return(MAJOR_0C_EXCP); | ||
425 | case 1: /* sgl/dbl */ | ||
426 | return(sgl_to_dbl_fcnvff(&fpregs[r1],0, | ||
427 | &fpregs[t],status)); | ||
428 | case 2: /* dbl/sgl */ | ||
429 | return(dbl_to_sgl_fcnvff(&fpregs[r1],0, | ||
430 | &fpregs[t],status)); | ||
431 | case 3: /* dbl/dbl */ | ||
432 | return(MAJOR_0C_EXCP); | ||
433 | } | ||
434 | case 1: /* FCNVXF */ | ||
435 | switch(fmt) { | ||
436 | case 0: /* sgl/sgl */ | ||
437 | return(sgl_to_sgl_fcnvxf(&fpregs[r1],0, | ||
438 | &fpregs[t],status)); | ||
439 | case 1: /* sgl/dbl */ | ||
440 | return(sgl_to_dbl_fcnvxf(&fpregs[r1],0, | ||
441 | &fpregs[t],status)); | ||
442 | case 2: /* dbl/sgl */ | ||
443 | return(dbl_to_sgl_fcnvxf(&fpregs[r1],0, | ||
444 | &fpregs[t],status)); | ||
445 | case 3: /* dbl/dbl */ | ||
446 | return(dbl_to_dbl_fcnvxf(&fpregs[r1],0, | ||
447 | &fpregs[t],status)); | ||
448 | } | ||
449 | case 2: /* FCNVFX */ | ||
450 | switch(fmt) { | ||
451 | case 0: /* sgl/sgl */ | ||
452 | return(sgl_to_sgl_fcnvfx(&fpregs[r1],0, | ||
453 | &fpregs[t],status)); | ||
454 | case 1: /* sgl/dbl */ | ||
455 | return(sgl_to_dbl_fcnvfx(&fpregs[r1],0, | ||
456 | &fpregs[t],status)); | ||
457 | case 2: /* dbl/sgl */ | ||
458 | return(dbl_to_sgl_fcnvfx(&fpregs[r1],0, | ||
459 | &fpregs[t],status)); | ||
460 | case 3: /* dbl/dbl */ | ||
461 | return(dbl_to_dbl_fcnvfx(&fpregs[r1],0, | ||
462 | &fpregs[t],status)); | ||
463 | } | ||
464 | case 3: /* FCNVFXT */ | ||
465 | switch(fmt) { | ||
466 | case 0: /* sgl/sgl */ | ||
467 | return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0, | ||
468 | &fpregs[t],status)); | ||
469 | case 1: /* sgl/dbl */ | ||
470 | return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0, | ||
471 | &fpregs[t],status)); | ||
472 | case 2: /* dbl/sgl */ | ||
473 | return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0, | ||
474 | &fpregs[t],status)); | ||
475 | case 3: /* dbl/dbl */ | ||
476 | return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0, | ||
477 | &fpregs[t],status)); | ||
478 | } | ||
479 | case 5: /* FCNVUF (PA2.0 only) */ | ||
480 | switch(fmt) { | ||
481 | case 0: /* sgl/sgl */ | ||
482 | return(sgl_to_sgl_fcnvuf(&fpregs[r1],0, | ||
483 | &fpregs[t],status)); | ||
484 | case 1: /* sgl/dbl */ | ||
485 | return(sgl_to_dbl_fcnvuf(&fpregs[r1],0, | ||
486 | &fpregs[t],status)); | ||
487 | case 2: /* dbl/sgl */ | ||
488 | return(dbl_to_sgl_fcnvuf(&fpregs[r1],0, | ||
489 | &fpregs[t],status)); | ||
490 | case 3: /* dbl/dbl */ | ||
491 | return(dbl_to_dbl_fcnvuf(&fpregs[r1],0, | ||
492 | &fpregs[t],status)); | ||
493 | } | ||
494 | case 6: /* FCNVFU (PA2.0 only) */ | ||
495 | switch(fmt) { | ||
496 | case 0: /* sgl/sgl */ | ||
497 | return(sgl_to_sgl_fcnvfu(&fpregs[r1],0, | ||
498 | &fpregs[t],status)); | ||
499 | case 1: /* sgl/dbl */ | ||
500 | return(sgl_to_dbl_fcnvfu(&fpregs[r1],0, | ||
501 | &fpregs[t],status)); | ||
502 | case 2: /* dbl/sgl */ | ||
503 | return(dbl_to_sgl_fcnvfu(&fpregs[r1],0, | ||
504 | &fpregs[t],status)); | ||
505 | case 3: /* dbl/dbl */ | ||
506 | return(dbl_to_dbl_fcnvfu(&fpregs[r1],0, | ||
507 | &fpregs[t],status)); | ||
508 | } | ||
509 | case 7: /* FCNVFUT (PA2.0 only) */ | ||
510 | switch(fmt) { | ||
511 | case 0: /* sgl/sgl */ | ||
512 | return(sgl_to_sgl_fcnvfut(&fpregs[r1],0, | ||
513 | &fpregs[t],status)); | ||
514 | case 1: /* sgl/dbl */ | ||
515 | return(sgl_to_dbl_fcnvfut(&fpregs[r1],0, | ||
516 | &fpregs[t],status)); | ||
517 | case 2: /* dbl/sgl */ | ||
518 | return(dbl_to_sgl_fcnvfut(&fpregs[r1],0, | ||
519 | &fpregs[t],status)); | ||
520 | case 3: /* dbl/dbl */ | ||
521 | return(dbl_to_dbl_fcnvfut(&fpregs[r1],0, | ||
522 | &fpregs[t],status)); | ||
523 | } | ||
524 | case 4: /* undefined */ | ||
525 | return(MAJOR_0C_EXCP); | ||
526 | } /* end of switch subop */ | ||
527 | |||
528 | case 2: /* class 2 */ | ||
529 | fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; | ||
530 | r2 = extru(ir, fpr2pos, 5) * sizeof(double)/sizeof(u_int); | ||
531 | if (r2 == 0) | ||
532 | r2 = fpzeroreg; | ||
533 | if (fpu_type_flags & PA2_0_FPU_FLAG) { | ||
534 | /* FTEST if nullify bit set, otherwise FCMP */ | ||
535 | if (extru(ir, fpnulpos, 1)) { /* FTEST */ | ||
536 | switch (fmt) { | ||
537 | case 0: | ||
538 | /* | ||
539 | * arg0 is not used | ||
540 | * second param is the t field used for | ||
541 | * ftest,acc and ftest,rej | ||
542 | * third param is the subop (y-field) | ||
543 | */ | ||
544 | BUG(); | ||
545 | /* Unsupported | ||
546 | * return(ftest(0L,extru(ir,fptpos,5), | ||
547 | * &fpregs[0],subop)); | ||
548 | */ | ||
549 | case 1: | ||
550 | case 2: | ||
551 | case 3: | ||
552 | return(MAJOR_0C_EXCP); | ||
553 | } | ||
554 | } else { /* FCMP */ | ||
555 | switch (fmt) { | ||
556 | case 0: | ||
557 | retval = sgl_fcmp(&fpregs[r1], | ||
558 | &fpregs[r2],extru(ir,fptpos,5), | ||
559 | &local_status); | ||
560 | update_status_cbit(status,local_status, | ||
561 | fpu_type_flags, subop); | ||
562 | return(retval); | ||
563 | case 1: | ||
564 | retval = dbl_fcmp(&fpregs[r1], | ||
565 | &fpregs[r2],extru(ir,fptpos,5), | ||
566 | &local_status); | ||
567 | update_status_cbit(status,local_status, | ||
568 | fpu_type_flags, subop); | ||
569 | return(retval); | ||
570 | case 2: /* illegal */ | ||
571 | case 3: /* quad not implemented */ | ||
572 | return(MAJOR_0C_EXCP); | ||
573 | } | ||
574 | } | ||
575 | } /* end of if for PA2.0 */ | ||
576 | else { /* PA1.0 & PA1.1 */ | ||
577 | switch (subop) { | ||
578 | case 2: | ||
579 | case 3: | ||
580 | case 4: | ||
581 | case 5: | ||
582 | case 6: | ||
583 | case 7: | ||
584 | return(MAJOR_0C_EXCP); | ||
585 | case 0: /* FCMP */ | ||
586 | switch (fmt) { | ||
587 | case 0: | ||
588 | retval = sgl_fcmp(&fpregs[r1], | ||
589 | &fpregs[r2],extru(ir,fptpos,5), | ||
590 | &local_status); | ||
591 | update_status_cbit(status,local_status, | ||
592 | fpu_type_flags, subop); | ||
593 | return(retval); | ||
594 | case 1: | ||
595 | retval = dbl_fcmp(&fpregs[r1], | ||
596 | &fpregs[r2],extru(ir,fptpos,5), | ||
597 | &local_status); | ||
598 | update_status_cbit(status,local_status, | ||
599 | fpu_type_flags, subop); | ||
600 | return(retval); | ||
601 | case 2: /* illegal */ | ||
602 | case 3: /* quad not implemented */ | ||
603 | return(MAJOR_0C_EXCP); | ||
604 | } | ||
605 | case 1: /* FTEST */ | ||
606 | switch (fmt) { | ||
607 | case 0: | ||
608 | /* | ||
609 | * arg0 is not used | ||
610 | * second param is the t field used for | ||
611 | * ftest,acc and ftest,rej | ||
612 | * third param is the subop (y-field) | ||
613 | */ | ||
614 | BUG(); | ||
615 | /* unsupported | ||
616 | * return(ftest(0L,extru(ir,fptpos,5), | ||
617 | * &fpregs[0],subop)); | ||
618 | */ | ||
619 | case 1: | ||
620 | case 2: | ||
621 | case 3: | ||
622 | return(MAJOR_0C_EXCP); | ||
623 | } | ||
624 | } /* end of switch subop */ | ||
625 | } /* end of else for PA1.0 & PA1.1 */ | ||
626 | case 3: /* class 3 */ | ||
627 | r2 = extru(ir,fpr2pos,5) * sizeof(double)/sizeof(u_int); | ||
628 | if (r2 == 0) | ||
629 | r2 = fpzeroreg; | ||
630 | switch (subop) { | ||
631 | case 5: | ||
632 | case 6: | ||
633 | case 7: | ||
634 | return(MAJOR_0C_EXCP); | ||
635 | |||
636 | case 0: /* FADD */ | ||
637 | switch (fmt) { | ||
638 | case 0: | ||
639 | return(sgl_fadd(&fpregs[r1],&fpregs[r2], | ||
640 | &fpregs[t],status)); | ||
641 | case 1: | ||
642 | return(dbl_fadd(&fpregs[r1],&fpregs[r2], | ||
643 | &fpregs[t],status)); | ||
644 | case 2: /* illegal */ | ||
645 | case 3: /* quad not implemented */ | ||
646 | return(MAJOR_0C_EXCP); | ||
647 | } | ||
648 | case 1: /* FSUB */ | ||
649 | switch (fmt) { | ||
650 | case 0: | ||
651 | return(sgl_fsub(&fpregs[r1],&fpregs[r2], | ||
652 | &fpregs[t],status)); | ||
653 | case 1: | ||
654 | return(dbl_fsub(&fpregs[r1],&fpregs[r2], | ||
655 | &fpregs[t],status)); | ||
656 | case 2: /* illegal */ | ||
657 | case 3: /* quad not implemented */ | ||
658 | return(MAJOR_0C_EXCP); | ||
659 | } | ||
660 | case 2: /* FMPY */ | ||
661 | switch (fmt) { | ||
662 | case 0: | ||
663 | return(sgl_fmpy(&fpregs[r1],&fpregs[r2], | ||
664 | &fpregs[t],status)); | ||
665 | case 1: | ||
666 | return(dbl_fmpy(&fpregs[r1],&fpregs[r2], | ||
667 | &fpregs[t],status)); | ||
668 | case 2: /* illegal */ | ||
669 | case 3: /* quad not implemented */ | ||
670 | return(MAJOR_0C_EXCP); | ||
671 | } | ||
672 | case 3: /* FDIV */ | ||
673 | switch (fmt) { | ||
674 | case 0: | ||
675 | return(sgl_fdiv(&fpregs[r1],&fpregs[r2], | ||
676 | &fpregs[t],status)); | ||
677 | case 1: | ||
678 | return(dbl_fdiv(&fpregs[r1],&fpregs[r2], | ||
679 | &fpregs[t],status)); | ||
680 | case 2: /* illegal */ | ||
681 | case 3: /* quad not implemented */ | ||
682 | return(MAJOR_0C_EXCP); | ||
683 | } | ||
684 | case 4: /* FREM */ | ||
685 | switch (fmt) { | ||
686 | case 0: | ||
687 | return(sgl_frem(&fpregs[r1],&fpregs[r2], | ||
688 | &fpregs[t],status)); | ||
689 | case 1: | ||
690 | return(dbl_frem(&fpregs[r1],&fpregs[r2], | ||
691 | &fpregs[t],status)); | ||
692 | case 2: /* illegal */ | ||
693 | case 3: /* quad not implemented */ | ||
694 | return(MAJOR_0C_EXCP); | ||
695 | } | ||
696 | } /* end of class 3 switch */ | ||
697 | } /* end of switch(class) */ | ||
698 | |||
699 | /* If we get here, something is really wrong! */ | ||
700 | return(MAJOR_0C_EXCP); | ||
701 | } | ||
702 | |||
703 | static u_int | ||
704 | decode_0e(ir,class,subop,fpregs) | ||
705 | u_int ir,class,subop; | ||
706 | u_int fpregs[]; | ||
707 | { | ||
708 | u_int r1,r2,t; /* operand register offsets */ | ||
709 | u_int fmt; /* also sf for class 1 conversions */ | ||
710 | u_int df; /* dest format for class 1 conversions */ | ||
711 | u_int *status; | ||
712 | u_int retval, local_status; | ||
713 | u_int fpu_type_flags; | ||
714 | |||
715 | status = &fpregs[0]; | ||
716 | local_status = fpregs[0]; | ||
717 | r1 = ((extru(ir,fpr1pos,5)<<1)|(extru(ir,fpxr1pos,1))); | ||
718 | if (r1 == 0) | ||
719 | r1 = fpzeroreg; | ||
720 | t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1))); | ||
721 | if (t == 0 && class != 2) | ||
722 | return(MAJOR_0E_EXCP); | ||
723 | if (class < 2) /* class 0 or 1 has 2 bit fmt */ | ||
724 | fmt = extru(ir,fpfmtpos,2); | ||
725 | else /* class 2 and 3 have 1 bit fmt */ | ||
726 | fmt = extru(ir,fp0efmtpos,1); | ||
727 | /* | ||
728 | * An undefined combination, double precision accessing the | ||
729 | * right half of a FPR, can get us into trouble. | ||
730 | * Let's just force proper alignment on it. | ||
731 | */ | ||
732 | if (fmt == DBL) { | ||
733 | r1 &= ~1; | ||
734 | if (class != 1) | ||
735 | t &= ~1; | ||
736 | } | ||
737 | |||
738 | switch (class) { | ||
739 | case 0: | ||
740 | switch (subop) { | ||
741 | case 0: /* unimplemented */ | ||
742 | case 1: | ||
743 | return(MAJOR_0E_EXCP); | ||
744 | case 2: /* FCPY */ | ||
745 | switch (fmt) { | ||
746 | case 2: | ||
747 | case 3: | ||
748 | return(MAJOR_0E_EXCP); | ||
749 | case 1: /* double */ | ||
750 | fpregs[t+1] = fpregs[r1+1]; | ||
751 | case 0: /* single */ | ||
752 | fpregs[t] = fpregs[r1]; | ||
753 | return(NOEXCEPTION); | ||
754 | } | ||
755 | case 3: /* FABS */ | ||
756 | switch (fmt) { | ||
757 | case 2: | ||
758 | case 3: | ||
759 | return(MAJOR_0E_EXCP); | ||
760 | case 1: /* double */ | ||
761 | fpregs[t+1] = fpregs[r1+1]; | ||
762 | case 0: /* single */ | ||
763 | fpregs[t] = fpregs[r1] & 0x7fffffff; | ||
764 | return(NOEXCEPTION); | ||
765 | } | ||
766 | case 6: /* FNEG */ | ||
767 | switch (fmt) { | ||
768 | case 2: | ||
769 | case 3: | ||
770 | return(MAJOR_0E_EXCP); | ||
771 | case 1: /* double */ | ||
772 | fpregs[t+1] = fpregs[r1+1]; | ||
773 | case 0: /* single */ | ||
774 | fpregs[t] = fpregs[r1] ^ 0x80000000; | ||
775 | return(NOEXCEPTION); | ||
776 | } | ||
777 | case 7: /* FNEGABS */ | ||
778 | switch (fmt) { | ||
779 | case 2: | ||
780 | case 3: | ||
781 | return(MAJOR_0E_EXCP); | ||
782 | case 1: /* double */ | ||
783 | fpregs[t+1] = fpregs[r1+1]; | ||
784 | case 0: /* single */ | ||
785 | fpregs[t] = fpregs[r1] | 0x80000000; | ||
786 | return(NOEXCEPTION); | ||
787 | } | ||
788 | case 4: /* FSQRT */ | ||
789 | switch (fmt) { | ||
790 | case 0: | ||
791 | return(sgl_fsqrt(&fpregs[r1],0, | ||
792 | &fpregs[t], status)); | ||
793 | case 1: | ||
794 | return(dbl_fsqrt(&fpregs[r1],0, | ||
795 | &fpregs[t], status)); | ||
796 | case 2: | ||
797 | case 3: | ||
798 | return(MAJOR_0E_EXCP); | ||
799 | } | ||
800 | case 5: /* FRMD */ | ||
801 | switch (fmt) { | ||
802 | case 0: | ||
803 | return(sgl_frnd(&fpregs[r1],0, | ||
804 | &fpregs[t], status)); | ||
805 | case 1: | ||
806 | return(dbl_frnd(&fpregs[r1],0, | ||
807 | &fpregs[t], status)); | ||
808 | case 2: | ||
809 | case 3: | ||
810 | return(MAJOR_0E_EXCP); | ||
811 | } | ||
812 | } /* end of switch (subop */ | ||
813 | |||
814 | case 1: /* class 1 */ | ||
815 | df = extru(ir,fpdfpos,2); /* get dest format */ | ||
816 | /* | ||
817 | * Fix Crashme problem (writing to 31R in double precision) | ||
818 | * here too. | ||
819 | */ | ||
820 | if (df == DBL) { | ||
821 | t &= ~1; | ||
822 | } | ||
823 | if ((df & 2) || (fmt & 2)) | ||
824 | return(MAJOR_0E_EXCP); | ||
825 | |||
826 | fmt = (fmt << 1) | df; | ||
827 | switch (subop) { | ||
828 | case 0: /* FCNVFF */ | ||
829 | switch(fmt) { | ||
830 | case 0: /* sgl/sgl */ | ||
831 | return(MAJOR_0E_EXCP); | ||
832 | case 1: /* sgl/dbl */ | ||
833 | return(sgl_to_dbl_fcnvff(&fpregs[r1],0, | ||
834 | &fpregs[t],status)); | ||
835 | case 2: /* dbl/sgl */ | ||
836 | return(dbl_to_sgl_fcnvff(&fpregs[r1],0, | ||
837 | &fpregs[t],status)); | ||
838 | case 3: /* dbl/dbl */ | ||
839 | return(MAJOR_0E_EXCP); | ||
840 | } | ||
841 | case 1: /* FCNVXF */ | ||
842 | switch(fmt) { | ||
843 | case 0: /* sgl/sgl */ | ||
844 | return(sgl_to_sgl_fcnvxf(&fpregs[r1],0, | ||
845 | &fpregs[t],status)); | ||
846 | case 1: /* sgl/dbl */ | ||
847 | return(sgl_to_dbl_fcnvxf(&fpregs[r1],0, | ||
848 | &fpregs[t],status)); | ||
849 | case 2: /* dbl/sgl */ | ||
850 | return(dbl_to_sgl_fcnvxf(&fpregs[r1],0, | ||
851 | &fpregs[t],status)); | ||
852 | case 3: /* dbl/dbl */ | ||
853 | return(dbl_to_dbl_fcnvxf(&fpregs[r1],0, | ||
854 | &fpregs[t],status)); | ||
855 | } | ||
856 | case 2: /* FCNVFX */ | ||
857 | switch(fmt) { | ||
858 | case 0: /* sgl/sgl */ | ||
859 | return(sgl_to_sgl_fcnvfx(&fpregs[r1],0, | ||
860 | &fpregs[t],status)); | ||
861 | case 1: /* sgl/dbl */ | ||
862 | return(sgl_to_dbl_fcnvfx(&fpregs[r1],0, | ||
863 | &fpregs[t],status)); | ||
864 | case 2: /* dbl/sgl */ | ||
865 | return(dbl_to_sgl_fcnvfx(&fpregs[r1],0, | ||
866 | &fpregs[t],status)); | ||
867 | case 3: /* dbl/dbl */ | ||
868 | return(dbl_to_dbl_fcnvfx(&fpregs[r1],0, | ||
869 | &fpregs[t],status)); | ||
870 | } | ||
871 | case 3: /* FCNVFXT */ | ||
872 | switch(fmt) { | ||
873 | case 0: /* sgl/sgl */ | ||
874 | return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0, | ||
875 | &fpregs[t],status)); | ||
876 | case 1: /* sgl/dbl */ | ||
877 | return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0, | ||
878 | &fpregs[t],status)); | ||
879 | case 2: /* dbl/sgl */ | ||
880 | return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0, | ||
881 | &fpregs[t],status)); | ||
882 | case 3: /* dbl/dbl */ | ||
883 | return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0, | ||
884 | &fpregs[t],status)); | ||
885 | } | ||
886 | case 5: /* FCNVUF (PA2.0 only) */ | ||
887 | switch(fmt) { | ||
888 | case 0: /* sgl/sgl */ | ||
889 | return(sgl_to_sgl_fcnvuf(&fpregs[r1],0, | ||
890 | &fpregs[t],status)); | ||
891 | case 1: /* sgl/dbl */ | ||
892 | return(sgl_to_dbl_fcnvuf(&fpregs[r1],0, | ||
893 | &fpregs[t],status)); | ||
894 | case 2: /* dbl/sgl */ | ||
895 | return(dbl_to_sgl_fcnvuf(&fpregs[r1],0, | ||
896 | &fpregs[t],status)); | ||
897 | case 3: /* dbl/dbl */ | ||
898 | return(dbl_to_dbl_fcnvuf(&fpregs[r1],0, | ||
899 | &fpregs[t],status)); | ||
900 | } | ||
901 | case 6: /* FCNVFU (PA2.0 only) */ | ||
902 | switch(fmt) { | ||
903 | case 0: /* sgl/sgl */ | ||
904 | return(sgl_to_sgl_fcnvfu(&fpregs[r1],0, | ||
905 | &fpregs[t],status)); | ||
906 | case 1: /* sgl/dbl */ | ||
907 | return(sgl_to_dbl_fcnvfu(&fpregs[r1],0, | ||
908 | &fpregs[t],status)); | ||
909 | case 2: /* dbl/sgl */ | ||
910 | return(dbl_to_sgl_fcnvfu(&fpregs[r1],0, | ||
911 | &fpregs[t],status)); | ||
912 | case 3: /* dbl/dbl */ | ||
913 | return(dbl_to_dbl_fcnvfu(&fpregs[r1],0, | ||
914 | &fpregs[t],status)); | ||
915 | } | ||
916 | case 7: /* FCNVFUT (PA2.0 only) */ | ||
917 | switch(fmt) { | ||
918 | case 0: /* sgl/sgl */ | ||
919 | return(sgl_to_sgl_fcnvfut(&fpregs[r1],0, | ||
920 | &fpregs[t],status)); | ||
921 | case 1: /* sgl/dbl */ | ||
922 | return(sgl_to_dbl_fcnvfut(&fpregs[r1],0, | ||
923 | &fpregs[t],status)); | ||
924 | case 2: /* dbl/sgl */ | ||
925 | return(dbl_to_sgl_fcnvfut(&fpregs[r1],0, | ||
926 | &fpregs[t],status)); | ||
927 | case 3: /* dbl/dbl */ | ||
928 | return(dbl_to_dbl_fcnvfut(&fpregs[r1],0, | ||
929 | &fpregs[t],status)); | ||
930 | } | ||
931 | case 4: /* undefined */ | ||
932 | return(MAJOR_0C_EXCP); | ||
933 | } /* end of switch subop */ | ||
934 | case 2: /* class 2 */ | ||
935 | /* | ||
936 | * Be careful out there. | ||
937 | * Crashme can generate cases where FR31R is specified | ||
938 | * as the source or target of a double precision operation. | ||
939 | * Since we just pass the address of the floating-point | ||
940 | * register to the emulation routines, this can cause | ||
941 | * corruption of fpzeroreg. | ||
942 | */ | ||
943 | if (fmt == DBL) | ||
944 | r2 = (extru(ir,fpr2pos,5)<<1); | ||
945 | else | ||
946 | r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1))); | ||
947 | fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; | ||
948 | if (r2 == 0) | ||
949 | r2 = fpzeroreg; | ||
950 | if (fpu_type_flags & PA2_0_FPU_FLAG) { | ||
951 | /* FTEST if nullify bit set, otherwise FCMP */ | ||
952 | if (extru(ir, fpnulpos, 1)) { /* FTEST */ | ||
953 | /* not legal */ | ||
954 | return(MAJOR_0E_EXCP); | ||
955 | } else { /* FCMP */ | ||
956 | switch (fmt) { | ||
957 | /* | ||
958 | * fmt is only 1 bit long | ||
959 | */ | ||
960 | case 0: | ||
961 | retval = sgl_fcmp(&fpregs[r1], | ||
962 | &fpregs[r2],extru(ir,fptpos,5), | ||
963 | &local_status); | ||
964 | update_status_cbit(status,local_status, | ||
965 | fpu_type_flags, subop); | ||
966 | return(retval); | ||
967 | case 1: | ||
968 | retval = dbl_fcmp(&fpregs[r1], | ||
969 | &fpregs[r2],extru(ir,fptpos,5), | ||
970 | &local_status); | ||
971 | update_status_cbit(status,local_status, | ||
972 | fpu_type_flags, subop); | ||
973 | return(retval); | ||
974 | } | ||
975 | } | ||
976 | } /* end of if for PA2.0 */ | ||
977 | else { /* PA1.0 & PA1.1 */ | ||
978 | switch (subop) { | ||
979 | case 1: | ||
980 | case 2: | ||
981 | case 3: | ||
982 | case 4: | ||
983 | case 5: | ||
984 | case 6: | ||
985 | case 7: | ||
986 | return(MAJOR_0E_EXCP); | ||
987 | case 0: /* FCMP */ | ||
988 | switch (fmt) { | ||
989 | /* | ||
990 | * fmt is only 1 bit long | ||
991 | */ | ||
992 | case 0: | ||
993 | retval = sgl_fcmp(&fpregs[r1], | ||
994 | &fpregs[r2],extru(ir,fptpos,5), | ||
995 | &local_status); | ||
996 | update_status_cbit(status,local_status, | ||
997 | fpu_type_flags, subop); | ||
998 | return(retval); | ||
999 | case 1: | ||
1000 | retval = dbl_fcmp(&fpregs[r1], | ||
1001 | &fpregs[r2],extru(ir,fptpos,5), | ||
1002 | &local_status); | ||
1003 | update_status_cbit(status,local_status, | ||
1004 | fpu_type_flags, subop); | ||
1005 | return(retval); | ||
1006 | } | ||
1007 | } /* end of switch subop */ | ||
1008 | } /* end of else for PA1.0 & PA1.1 */ | ||
1009 | case 3: /* class 3 */ | ||
1010 | /* | ||
1011 | * Be careful out there. | ||
1012 | * Crashme can generate cases where FR31R is specified | ||
1013 | * as the source or target of a double precision operation. | ||
1014 | * Since we just pass the address of the floating-point | ||
1015 | * register to the emulation routines, this can cause | ||
1016 | * corruption of fpzeroreg. | ||
1017 | */ | ||
1018 | if (fmt == DBL) | ||
1019 | r2 = (extru(ir,fpr2pos,5)<<1); | ||
1020 | else | ||
1021 | r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1))); | ||
1022 | if (r2 == 0) | ||
1023 | r2 = fpzeroreg; | ||
1024 | switch (subop) { | ||
1025 | case 5: | ||
1026 | case 6: | ||
1027 | case 7: | ||
1028 | return(MAJOR_0E_EXCP); | ||
1029 | |||
1030 | /* | ||
1031 | * Note that fmt is only 1 bit for class 3 */ | ||
1032 | case 0: /* FADD */ | ||
1033 | switch (fmt) { | ||
1034 | case 0: | ||
1035 | return(sgl_fadd(&fpregs[r1],&fpregs[r2], | ||
1036 | &fpregs[t],status)); | ||
1037 | case 1: | ||
1038 | return(dbl_fadd(&fpregs[r1],&fpregs[r2], | ||
1039 | &fpregs[t],status)); | ||
1040 | } | ||
1041 | case 1: /* FSUB */ | ||
1042 | switch (fmt) { | ||
1043 | case 0: | ||
1044 | return(sgl_fsub(&fpregs[r1],&fpregs[r2], | ||
1045 | &fpregs[t],status)); | ||
1046 | case 1: | ||
1047 | return(dbl_fsub(&fpregs[r1],&fpregs[r2], | ||
1048 | &fpregs[t],status)); | ||
1049 | } | ||
1050 | case 2: /* FMPY or XMPYU */ | ||
1051 | /* | ||
1052 | * check for integer multiply (x bit set) | ||
1053 | */ | ||
1054 | if (extru(ir,fpxpos,1)) { | ||
1055 | /* | ||
1056 | * emulate XMPYU | ||
1057 | */ | ||
1058 | switch (fmt) { | ||
1059 | case 0: | ||
1060 | /* | ||
1061 | * bad instruction if t specifies | ||
1062 | * the right half of a register | ||
1063 | */ | ||
1064 | if (t & 1) | ||
1065 | return(MAJOR_0E_EXCP); | ||
1066 | BUG(); | ||
1067 | /* unsupported | ||
1068 | * impyu(&fpregs[r1],&fpregs[r2], | ||
1069 | * &fpregs[t]); | ||
1070 | */ | ||
1071 | return(NOEXCEPTION); | ||
1072 | case 1: | ||
1073 | return(MAJOR_0E_EXCP); | ||
1074 | } | ||
1075 | } | ||
1076 | else { /* FMPY */ | ||
1077 | switch (fmt) { | ||
1078 | case 0: | ||
1079 | return(sgl_fmpy(&fpregs[r1], | ||
1080 | &fpregs[r2],&fpregs[t],status)); | ||
1081 | case 1: | ||
1082 | return(dbl_fmpy(&fpregs[r1], | ||
1083 | &fpregs[r2],&fpregs[t],status)); | ||
1084 | } | ||
1085 | } | ||
1086 | case 3: /* FDIV */ | ||
1087 | switch (fmt) { | ||
1088 | case 0: | ||
1089 | return(sgl_fdiv(&fpregs[r1],&fpregs[r2], | ||
1090 | &fpregs[t],status)); | ||
1091 | case 1: | ||
1092 | return(dbl_fdiv(&fpregs[r1],&fpregs[r2], | ||
1093 | &fpregs[t],status)); | ||
1094 | } | ||
1095 | case 4: /* FREM */ | ||
1096 | switch (fmt) { | ||
1097 | case 0: | ||
1098 | return(sgl_frem(&fpregs[r1],&fpregs[r2], | ||
1099 | &fpregs[t],status)); | ||
1100 | case 1: | ||
1101 | return(dbl_frem(&fpregs[r1],&fpregs[r2], | ||
1102 | &fpregs[t],status)); | ||
1103 | } | ||
1104 | } /* end of class 3 switch */ | ||
1105 | } /* end of switch(class) */ | ||
1106 | |||
1107 | /* If we get here, something is really wrong! */ | ||
1108 | return(MAJOR_0E_EXCP); | ||
1109 | } | ||
1110 | |||
1111 | |||
1112 | /* | ||
1113 | * routine to decode the 06 (FMPYADD and FMPYCFXT) instruction | ||
1114 | */ | ||
1115 | static u_int | ||
1116 | decode_06(ir,fpregs) | ||
1117 | u_int ir; | ||
1118 | u_int fpregs[]; | ||
1119 | { | ||
1120 | u_int rm1, rm2, tm, ra, ta; /* operands */ | ||
1121 | u_int fmt; | ||
1122 | u_int error = 0; | ||
1123 | u_int status; | ||
1124 | u_int fpu_type_flags; | ||
1125 | union { | ||
1126 | double dbl; | ||
1127 | float flt; | ||
1128 | struct { u_int i1; u_int i2; } ints; | ||
1129 | } mtmp, atmp; | ||
1130 | |||
1131 | |||
1132 | status = fpregs[0]; /* use a local copy of status reg */ | ||
1133 | fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */ | ||
1134 | fmt = extru(ir, fpmultifmt, 1); /* get sgl/dbl flag */ | ||
1135 | if (fmt == 0) { /* DBL */ | ||
1136 | rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int); | ||
1137 | if (rm1 == 0) | ||
1138 | rm1 = fpzeroreg; | ||
1139 | rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int); | ||
1140 | if (rm2 == 0) | ||
1141 | rm2 = fpzeroreg; | ||
1142 | tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int); | ||
1143 | if (tm == 0) | ||
1144 | return(MAJOR_06_EXCP); | ||
1145 | ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int); | ||
1146 | ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int); | ||
1147 | if (ta == 0) | ||
1148 | return(MAJOR_06_EXCP); | ||
1149 | |||
1150 | if (fpu_type_flags & TIMEX_ROLEX_FPU_MASK) { | ||
1151 | |||
1152 | if (ra == 0) { | ||
1153 | /* special case FMPYCFXT, see sgl case below */ | ||
1154 | if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2], | ||
1155 | &mtmp.ints.i1,&status)) | ||
1156 | error = 1; | ||
1157 | if (dbl_to_sgl_fcnvfxt(&fpregs[ta], | ||
1158 | &atmp.ints.i1,&atmp.ints.i1,&status)) | ||
1159 | error = 1; | ||
1160 | } | ||
1161 | else { | ||
1162 | |||
1163 | if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1, | ||
1164 | &status)) | ||
1165 | error = 1; | ||
1166 | if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1, | ||
1167 | &status)) | ||
1168 | error = 1; | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | else | ||
1173 | |||
1174 | { | ||
1175 | if (ra == 0) | ||
1176 | ra = fpzeroreg; | ||
1177 | |||
1178 | if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1, | ||
1179 | &status)) | ||
1180 | error = 1; | ||
1181 | if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1, | ||
1182 | &status)) | ||
1183 | error = 1; | ||
1184 | |||
1185 | } | ||
1186 | |||
1187 | if (error) | ||
1188 | return(MAJOR_06_EXCP); | ||
1189 | else { | ||
1190 | /* copy results */ | ||
1191 | fpregs[tm] = mtmp.ints.i1; | ||
1192 | fpregs[tm+1] = mtmp.ints.i2; | ||
1193 | fpregs[ta] = atmp.ints.i1; | ||
1194 | fpregs[ta+1] = atmp.ints.i2; | ||
1195 | fpregs[0] = status; | ||
1196 | return(NOEXCEPTION); | ||
1197 | } | ||
1198 | } | ||
1199 | else { /* SGL */ | ||
1200 | /* | ||
1201 | * calculate offsets for single precision numbers | ||
1202 | * See table 6-14 in PA-89 architecture for mapping | ||
1203 | */ | ||
1204 | rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1; /* get offset */ | ||
1205 | rm1 |= extru(ir,fprm1pos-4,1); /* add right word offset */ | ||
1206 | |||
1207 | rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1; /* get offset */ | ||
1208 | rm2 |= extru(ir,fprm2pos-4,1); /* add right word offset */ | ||
1209 | |||
1210 | tm = (extru(ir,fptmpos,4) | 0x10 ) << 1; /* get offset */ | ||
1211 | tm |= extru(ir,fptmpos-4,1); /* add right word offset */ | ||
1212 | |||
1213 | ra = (extru(ir,fprapos,4) | 0x10 ) << 1; /* get offset */ | ||
1214 | ra |= extru(ir,fprapos-4,1); /* add right word offset */ | ||
1215 | |||
1216 | ta = (extru(ir,fptapos,4) | 0x10 ) << 1; /* get offset */ | ||
1217 | ta |= extru(ir,fptapos-4,1); /* add right word offset */ | ||
1218 | |||
1219 | if (ra == 0x20 &&(fpu_type_flags & TIMEX_ROLEX_FPU_MASK)) { | ||
1220 | /* special case FMPYCFXT (really 0) | ||
1221 | * This instruction is only present on the Timex and | ||
1222 | * Rolex fpu's in so if it is the special case and | ||
1223 | * one of these fpu's we run the FMPYCFXT instruction | ||
1224 | */ | ||
1225 | if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1, | ||
1226 | &status)) | ||
1227 | error = 1; | ||
1228 | if (sgl_to_sgl_fcnvfxt(&fpregs[ta],&atmp.ints.i1, | ||
1229 | &atmp.ints.i1,&status)) | ||
1230 | error = 1; | ||
1231 | } | ||
1232 | else { | ||
1233 | if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1, | ||
1234 | &status)) | ||
1235 | error = 1; | ||
1236 | if (sgl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1, | ||
1237 | &status)) | ||
1238 | error = 1; | ||
1239 | } | ||
1240 | if (error) | ||
1241 | return(MAJOR_06_EXCP); | ||
1242 | else { | ||
1243 | /* copy results */ | ||
1244 | fpregs[tm] = mtmp.ints.i1; | ||
1245 | fpregs[ta] = atmp.ints.i1; | ||
1246 | fpregs[0] = status; | ||
1247 | return(NOEXCEPTION); | ||
1248 | } | ||
1249 | } | ||
1250 | } | ||
1251 | |||
1252 | /* | ||
1253 | * routine to decode the 26 (FMPYSUB) instruction | ||
1254 | */ | ||
1255 | static u_int | ||
1256 | decode_26(ir,fpregs) | ||
1257 | u_int ir; | ||
1258 | u_int fpregs[]; | ||
1259 | { | ||
1260 | u_int rm1, rm2, tm, ra, ta; /* operands */ | ||
1261 | u_int fmt; | ||
1262 | u_int error = 0; | ||
1263 | u_int status; | ||
1264 | union { | ||
1265 | double dbl; | ||
1266 | float flt; | ||
1267 | struct { u_int i1; u_int i2; } ints; | ||
1268 | } mtmp, atmp; | ||
1269 | |||
1270 | |||
1271 | status = fpregs[0]; | ||
1272 | fmt = extru(ir, fpmultifmt, 1); /* get sgl/dbl flag */ | ||
1273 | if (fmt == 0) { /* DBL */ | ||
1274 | rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int); | ||
1275 | if (rm1 == 0) | ||
1276 | rm1 = fpzeroreg; | ||
1277 | rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int); | ||
1278 | if (rm2 == 0) | ||
1279 | rm2 = fpzeroreg; | ||
1280 | tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int); | ||
1281 | if (tm == 0) | ||
1282 | return(MAJOR_26_EXCP); | ||
1283 | ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int); | ||
1284 | if (ra == 0) | ||
1285 | return(MAJOR_26_EXCP); | ||
1286 | ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int); | ||
1287 | if (ta == 0) | ||
1288 | return(MAJOR_26_EXCP); | ||
1289 | |||
1290 | if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status)) | ||
1291 | error = 1; | ||
1292 | if (dbl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status)) | ||
1293 | error = 1; | ||
1294 | if (error) | ||
1295 | return(MAJOR_26_EXCP); | ||
1296 | else { | ||
1297 | /* copy results */ | ||
1298 | fpregs[tm] = mtmp.ints.i1; | ||
1299 | fpregs[tm+1] = mtmp.ints.i2; | ||
1300 | fpregs[ta] = atmp.ints.i1; | ||
1301 | fpregs[ta+1] = atmp.ints.i2; | ||
1302 | fpregs[0] = status; | ||
1303 | return(NOEXCEPTION); | ||
1304 | } | ||
1305 | } | ||
1306 | else { /* SGL */ | ||
1307 | /* | ||
1308 | * calculate offsets for single precision numbers | ||
1309 | * See table 6-14 in PA-89 architecture for mapping | ||
1310 | */ | ||
1311 | rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1; /* get offset */ | ||
1312 | rm1 |= extru(ir,fprm1pos-4,1); /* add right word offset */ | ||
1313 | |||
1314 | rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1; /* get offset */ | ||
1315 | rm2 |= extru(ir,fprm2pos-4,1); /* add right word offset */ | ||
1316 | |||
1317 | tm = (extru(ir,fptmpos,4) | 0x10 ) << 1; /* get offset */ | ||
1318 | tm |= extru(ir,fptmpos-4,1); /* add right word offset */ | ||
1319 | |||
1320 | ra = (extru(ir,fprapos,4) | 0x10 ) << 1; /* get offset */ | ||
1321 | ra |= extru(ir,fprapos-4,1); /* add right word offset */ | ||
1322 | |||
1323 | ta = (extru(ir,fptapos,4) | 0x10 ) << 1; /* get offset */ | ||
1324 | ta |= extru(ir,fptapos-4,1); /* add right word offset */ | ||
1325 | |||
1326 | if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status)) | ||
1327 | error = 1; | ||
1328 | if (sgl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status)) | ||
1329 | error = 1; | ||
1330 | if (error) | ||
1331 | return(MAJOR_26_EXCP); | ||
1332 | else { | ||
1333 | /* copy results */ | ||
1334 | fpregs[tm] = mtmp.ints.i1; | ||
1335 | fpregs[ta] = atmp.ints.i1; | ||
1336 | fpregs[0] = status; | ||
1337 | return(NOEXCEPTION); | ||
1338 | } | ||
1339 | } | ||
1340 | |||
1341 | } | ||
1342 | |||
1343 | /* | ||
1344 | * routine to decode the 2E (FMPYFADD,FMPYNFADD) instructions | ||
1345 | */ | ||
1346 | static u_int | ||
1347 | decode_2e(ir,fpregs) | ||
1348 | u_int ir; | ||
1349 | u_int fpregs[]; | ||
1350 | { | ||
1351 | u_int rm1, rm2, ra, t; /* operands */ | ||
1352 | u_int fmt; | ||
1353 | |||
1354 | fmt = extru(ir,fpfmtpos,1); /* get fmt completer */ | ||
1355 | if (fmt == DBL) { /* DBL */ | ||
1356 | rm1 = extru(ir,fprm1pos,5) * sizeof(double)/sizeof(u_int); | ||
1357 | if (rm1 == 0) | ||
1358 | rm1 = fpzeroreg; | ||
1359 | rm2 = extru(ir,fprm2pos,5) * sizeof(double)/sizeof(u_int); | ||
1360 | if (rm2 == 0) | ||
1361 | rm2 = fpzeroreg; | ||
1362 | ra = ((extru(ir,fpraupos,3)<<2)|(extru(ir,fpralpos,3)>>1)) * | ||
1363 | sizeof(double)/sizeof(u_int); | ||
1364 | if (ra == 0) | ||
1365 | ra = fpzeroreg; | ||
1366 | t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int); | ||
1367 | if (t == 0) | ||
1368 | return(MAJOR_2E_EXCP); | ||
1369 | |||
1370 | if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */ | ||
1371 | return(dbl_fmpynfadd(&fpregs[rm1], &fpregs[rm2], | ||
1372 | &fpregs[ra], &fpregs[0], &fpregs[t])); | ||
1373 | } else { | ||
1374 | return(dbl_fmpyfadd(&fpregs[rm1], &fpregs[rm2], | ||
1375 | &fpregs[ra], &fpregs[0], &fpregs[t])); | ||
1376 | } | ||
1377 | } /* end DBL */ | ||
1378 | else { /* SGL */ | ||
1379 | rm1 = (extru(ir,fprm1pos,5)<<1)|(extru(ir,fpxrm1pos,1)); | ||
1380 | if (rm1 == 0) | ||
1381 | rm1 = fpzeroreg; | ||
1382 | rm2 = (extru(ir,fprm2pos,5)<<1)|(extru(ir,fpxrm2pos,1)); | ||
1383 | if (rm2 == 0) | ||
1384 | rm2 = fpzeroreg; | ||
1385 | ra = (extru(ir,fpraupos,3)<<3)|extru(ir,fpralpos,3); | ||
1386 | if (ra == 0) | ||
1387 | ra = fpzeroreg; | ||
1388 | t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1))); | ||
1389 | if (t == 0) | ||
1390 | return(MAJOR_2E_EXCP); | ||
1391 | |||
1392 | if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */ | ||
1393 | return(sgl_fmpynfadd(&fpregs[rm1], &fpregs[rm2], | ||
1394 | &fpregs[ra], &fpregs[0], &fpregs[t])); | ||
1395 | } else { | ||
1396 | return(sgl_fmpyfadd(&fpregs[rm1], &fpregs[rm2], | ||
1397 | &fpregs[ra], &fpregs[0], &fpregs[t])); | ||
1398 | } | ||
1399 | } /* end SGL */ | ||
1400 | } | ||
1401 | |||
1402 | /* | ||
1403 | * update_status_cbit | ||
1404 | * | ||
1405 | * This routine returns the correct FP status register value in | ||
1406 | * *status, based on the C-bit & V-bit returned by the FCMP | ||
1407 | * emulation routine in new_status. The architecture type | ||
1408 | * (PA83, PA89 or PA2.0) is available in fpu_type. The y_field | ||
1409 | * and the architecture type are used to determine what flavor | ||
1410 | * of FCMP is being emulated. | ||
1411 | */ | ||
1412 | static void | ||
1413 | update_status_cbit(status, new_status, fpu_type, y_field) | ||
1414 | u_int *status, new_status; | ||
1415 | u_int fpu_type; | ||
1416 | u_int y_field; | ||
1417 | { | ||
1418 | /* | ||
1419 | * For PA89 FPU's which implement the Compare Queue and | ||
1420 | * for PA2.0 FPU's, update the Compare Queue if the y-field = 0, | ||
1421 | * otherwise update the specified bit in the Compare Array. | ||
1422 | * Note that the y-field will always be 0 for non-PA2.0 FPU's. | ||
1423 | */ | ||
1424 | if ((fpu_type & TIMEX_EXTEN_FLAG) || | ||
1425 | (fpu_type & ROLEX_EXTEN_FLAG) || | ||
1426 | (fpu_type & PA2_0_FPU_FLAG)) { | ||
1427 | if (y_field == 0) { | ||
1428 | *status = ((*status & 0x04000000) >> 5) | /* old Cbit */ | ||
1429 | ((*status & 0x003ff000) >> 1) | /* old CQ */ | ||
1430 | (new_status & 0xffc007ff); /* all other bits*/ | ||
1431 | } else { | ||
1432 | *status = (*status & 0x04000000) | /* old Cbit */ | ||
1433 | ((new_status & 0x04000000) >> (y_field+4)) | | ||
1434 | (new_status & ~0x04000000 & /* other bits */ | ||
1435 | ~(0x04000000 >> (y_field+4))); | ||
1436 | } | ||
1437 | } | ||
1438 | /* if PA83, just update the C-bit */ | ||
1439 | else { | ||
1440 | *status = new_status; | ||
1441 | } | ||
1442 | } | ||