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