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