xref: /openbmc/linux/arch/parisc/math-emu/fpudispatch.c (revision 50af5ead3b44ccf8bd2b4d2a50c1b610f557c480)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * Linux/PA-RISC Project (http://www.parisc-linux.org/)
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Floating-point emulation code
51da177e4SLinus Torvalds  *  Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *    This program is free software; you can redistribute it and/or modify
81da177e4SLinus Torvalds  *    it under the terms of the GNU General Public License as published by
91da177e4SLinus Torvalds  *    the Free Software Foundation; either version 2, or (at your option)
101da177e4SLinus Torvalds  *    any later version.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *    This program is distributed in the hope that it will be useful,
131da177e4SLinus Torvalds  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4SLinus Torvalds  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151da177e4SLinus Torvalds  *    GNU General Public License for more details.
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  *    You should have received a copy of the GNU General Public License
181da177e4SLinus Torvalds  *    along with this program; if not, write to the Free Software
191da177e4SLinus Torvalds  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
201da177e4SLinus Torvalds  */
211da177e4SLinus Torvalds /*
221da177e4SLinus Torvalds  * BEGIN_DESC
231da177e4SLinus Torvalds  *
241da177e4SLinus Torvalds  *  File:
251da177e4SLinus Torvalds  *	@(#)	pa/fp/fpudispatch.c		$Revision: 1.1 $
261da177e4SLinus Torvalds  *
271da177e4SLinus Torvalds  *  Purpose:
281da177e4SLinus Torvalds  *	<<please update with a synopsis of the functionality provided by this file>>
291da177e4SLinus Torvalds  *
301da177e4SLinus Torvalds  *  External Interfaces:
311da177e4SLinus Torvalds  *	<<the following list was autogenerated, please review>>
321da177e4SLinus Torvalds  *	emfpudispatch(ir, dummy1, dummy2, fpregs)
331da177e4SLinus Torvalds  *	fpudispatch(ir, excp_code, holder, fpregs)
341da177e4SLinus Torvalds  *
351da177e4SLinus Torvalds  *  Internal Interfaces:
361da177e4SLinus Torvalds  *	<<the following list was autogenerated, please review>>
371da177e4SLinus Torvalds  *	static u_int decode_06(u_int, u_int *)
381da177e4SLinus Torvalds  *	static u_int decode_0c(u_int, u_int, u_int, u_int *)
391da177e4SLinus Torvalds  *	static u_int decode_0e(u_int, u_int, u_int, u_int *)
401da177e4SLinus Torvalds  *	static u_int decode_26(u_int, u_int *)
411da177e4SLinus Torvalds  *	static u_int decode_2e(u_int, u_int *)
421da177e4SLinus Torvalds  *	static void update_status_cbit(u_int *, u_int, u_int, u_int)
431da177e4SLinus Torvalds  *
441da177e4SLinus Torvalds  *  Theory:
451da177e4SLinus Torvalds  *	<<please update with a overview of the operation of this file>>
461da177e4SLinus Torvalds  *
471da177e4SLinus Torvalds  * END_DESC
481da177e4SLinus Torvalds */
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds #define FPUDEBUG 0
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds #include "float.h"
53*50af5eadSPaul Gortmaker #include <linux/bug.h>
541da177e4SLinus Torvalds #include <linux/kernel.h>
551da177e4SLinus Torvalds #include <asm/processor.h>
561da177e4SLinus Torvalds /* #include <sys/debug.h> */
571da177e4SLinus Torvalds /* #include <machine/sys/mdep_private.h> */
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds #define COPR_INST 0x30000000
601da177e4SLinus Torvalds 
611da177e4SLinus Torvalds /*
621da177e4SLinus Torvalds  * definition of extru macro.  If pos and len are constants, the compiler
631da177e4SLinus Torvalds  * will generate an extru instruction when optimized
641da177e4SLinus Torvalds  */
651da177e4SLinus Torvalds #define extru(r,pos,len)	(((r) >> (31-(pos))) & (( 1 << (len)) - 1))
661da177e4SLinus Torvalds /* definitions of bit field locations in the instruction */
671da177e4SLinus Torvalds #define fpmajorpos 5
681da177e4SLinus Torvalds #define fpr1pos	10
691da177e4SLinus Torvalds #define fpr2pos 15
701da177e4SLinus Torvalds #define fptpos	31
711da177e4SLinus Torvalds #define fpsubpos 18
721da177e4SLinus Torvalds #define fpclass1subpos 16
731da177e4SLinus Torvalds #define fpclasspos 22
741da177e4SLinus Torvalds #define fpfmtpos 20
751da177e4SLinus Torvalds #define fpdfpos 18
761da177e4SLinus Torvalds #define fpnulpos 26
771da177e4SLinus Torvalds /*
781da177e4SLinus Torvalds  * the following are the extra bits for the 0E major op
791da177e4SLinus Torvalds  */
801da177e4SLinus Torvalds #define fpxr1pos 24
811da177e4SLinus Torvalds #define fpxr2pos 19
821da177e4SLinus Torvalds #define fpxtpos 25
831da177e4SLinus Torvalds #define fpxpos 23
841da177e4SLinus Torvalds #define fp0efmtpos 20
851da177e4SLinus Torvalds /*
861da177e4SLinus Torvalds  * the following are for the multi-ops
871da177e4SLinus Torvalds  */
881da177e4SLinus Torvalds #define fprm1pos 10
891da177e4SLinus Torvalds #define fprm2pos 15
901da177e4SLinus Torvalds #define fptmpos 31
911da177e4SLinus Torvalds #define fprapos 25
921da177e4SLinus Torvalds #define fptapos 20
931da177e4SLinus Torvalds #define fpmultifmt 26
941da177e4SLinus Torvalds /*
951da177e4SLinus Torvalds  * the following are for the fused FP instructions
961da177e4SLinus Torvalds  */
971da177e4SLinus Torvalds      /* fprm1pos 10 */
981da177e4SLinus Torvalds      /* fprm2pos 15 */
991da177e4SLinus Torvalds #define fpraupos 18
1001da177e4SLinus Torvalds #define fpxrm2pos 19
1011da177e4SLinus Torvalds      /* fpfmtpos 20 */
1021da177e4SLinus Torvalds #define fpralpos 23
1031da177e4SLinus Torvalds #define fpxrm1pos 24
1041da177e4SLinus Torvalds      /* fpxtpos 25 */
1051da177e4SLinus Torvalds #define fpfusedsubop 26
1061da177e4SLinus Torvalds      /* fptpos	31 */
1071da177e4SLinus Torvalds 
1081da177e4SLinus Torvalds /*
1091da177e4SLinus Torvalds  * offset to constant zero in the FP emulation registers
1101da177e4SLinus Torvalds  */
1111da177e4SLinus Torvalds #define fpzeroreg (32*sizeof(double)/sizeof(u_int))
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds /*
1141da177e4SLinus Torvalds  * extract the major opcode from the instruction
1151da177e4SLinus Torvalds  */
1161da177e4SLinus Torvalds #define get_major(op) extru(op,fpmajorpos,6)
1171da177e4SLinus Torvalds /*
1181da177e4SLinus Torvalds  * extract the two bit class field from the FP instruction. The class is at bit
1191da177e4SLinus Torvalds  * positions 21-22
1201da177e4SLinus Torvalds  */
1211da177e4SLinus Torvalds #define get_class(op) extru(op,fpclasspos,2)
1221da177e4SLinus Torvalds /*
1231da177e4SLinus Torvalds  * extract the 3 bit subop field.  For all but class 1 instructions, it is
1241da177e4SLinus Torvalds  * located at bit positions 16-18
1251da177e4SLinus Torvalds  */
1261da177e4SLinus Torvalds #define get_subop(op) extru(op,fpsubpos,3)
1271da177e4SLinus Torvalds /*
1281da177e4SLinus Torvalds  * extract the 2 or 3 bit subop field from class 1 instructions.  It is located
1291da177e4SLinus Torvalds  * at bit positions 15-16 (PA1.1) or 14-16 (PA2.0)
1301da177e4SLinus Torvalds  */
1311da177e4SLinus Torvalds #define get_subop1_PA1_1(op) extru(op,fpclass1subpos,2)	/* PA89 (1.1) fmt */
1321da177e4SLinus Torvalds #define get_subop1_PA2_0(op) extru(op,fpclass1subpos,3)	/* PA 2.0 fmt */
1331da177e4SLinus Torvalds 
1341da177e4SLinus Torvalds /* definitions of unimplemented exceptions */
1351da177e4SLinus Torvalds #define MAJOR_0C_EXCP	0x09
1361da177e4SLinus Torvalds #define MAJOR_0E_EXCP	0x0b
1371da177e4SLinus Torvalds #define MAJOR_06_EXCP	0x03
1381da177e4SLinus Torvalds #define MAJOR_26_EXCP	0x23
1391da177e4SLinus Torvalds #define MAJOR_2E_EXCP	0x2b
1401da177e4SLinus Torvalds #define PA83_UNIMP_EXCP	0x01
1411da177e4SLinus Torvalds 
1421da177e4SLinus Torvalds /*
1431da177e4SLinus Torvalds  * Special Defines for TIMEX specific code
1441da177e4SLinus Torvalds  */
1451da177e4SLinus Torvalds 
1461da177e4SLinus Torvalds #define FPU_TYPE_FLAG_POS (EM_FPU_TYPE_OFFSET>>2)
1471da177e4SLinus Torvalds #define TIMEX_ROLEX_FPU_MASK (TIMEX_EXTEN_FLAG|ROLEX_EXTEN_FLAG)
1481da177e4SLinus Torvalds 
1491da177e4SLinus Torvalds /*
1501da177e4SLinus Torvalds  * Static function definitions
1511da177e4SLinus Torvalds  */
1521da177e4SLinus Torvalds #define _PROTOTYPES
1531da177e4SLinus Torvalds #if defined(_PROTOTYPES) || defined(_lint)
1541da177e4SLinus Torvalds static u_int decode_0c(u_int, u_int, u_int, u_int *);
1551da177e4SLinus Torvalds static u_int decode_0e(u_int, u_int, u_int, u_int *);
1561da177e4SLinus Torvalds static u_int decode_06(u_int, u_int *);
1571da177e4SLinus Torvalds static u_int decode_26(u_int, u_int *);
1581da177e4SLinus Torvalds static u_int decode_2e(u_int, u_int *);
1591da177e4SLinus Torvalds static void update_status_cbit(u_int *, u_int, u_int, u_int);
1601da177e4SLinus Torvalds #else /* !_PROTOTYPES&&!_lint */
1611da177e4SLinus Torvalds static u_int decode_0c();
1621da177e4SLinus Torvalds static u_int decode_0e();
1631da177e4SLinus Torvalds static u_int decode_06();
1641da177e4SLinus Torvalds static u_int decode_26();
1651da177e4SLinus Torvalds static u_int decode_2e();
1661da177e4SLinus Torvalds static void update_status_cbit();
1671da177e4SLinus Torvalds #endif /* _PROTOTYPES&&!_lint */
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds #define VASSERT(x)
1701da177e4SLinus Torvalds 
1711da177e4SLinus Torvalds static void parisc_linux_get_fpu_type(u_int fpregs[])
1721da177e4SLinus Torvalds {
1731da177e4SLinus Torvalds 	/* on pa-linux the fpu type is not filled in by the
1741da177e4SLinus Torvalds 	 * caller; it is constructed here
1751da177e4SLinus Torvalds 	 */
1761da177e4SLinus Torvalds 	if (boot_cpu_data.cpu_type == pcxs)
1771da177e4SLinus Torvalds 		fpregs[FPU_TYPE_FLAG_POS] = TIMEX_EXTEN_FLAG;
1781da177e4SLinus Torvalds 	else if (boot_cpu_data.cpu_type == pcxt ||
1791da177e4SLinus Torvalds 	         boot_cpu_data.cpu_type == pcxt_)
1801da177e4SLinus Torvalds 		fpregs[FPU_TYPE_FLAG_POS] = ROLEX_EXTEN_FLAG;
1811da177e4SLinus Torvalds 	else if (boot_cpu_data.cpu_type >= pcxu)
1821da177e4SLinus Torvalds 		fpregs[FPU_TYPE_FLAG_POS] = PA2_0_FPU_FLAG;
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds /*
1861da177e4SLinus Torvalds  * this routine will decode the excepting floating point instruction and
1871da177e4SLinus Torvalds  * call the approiate emulation routine.
1881da177e4SLinus Torvalds  * It is called by decode_fpu with the following parameters:
1891da177e4SLinus Torvalds  * fpudispatch(current_ir, unimplemented_code, 0, &Fpu_register)
1901da177e4SLinus Torvalds  * where current_ir is the instruction to be emulated,
1911da177e4SLinus Torvalds  * unimplemented_code is the exception_code that the hardware generated
1921da177e4SLinus Torvalds  * and &Fpu_register is the address of emulated FP reg 0.
1931da177e4SLinus Torvalds  */
1941da177e4SLinus Torvalds u_int
1951da177e4SLinus Torvalds fpudispatch(u_int ir, u_int excp_code, u_int holder, u_int fpregs[])
1961da177e4SLinus Torvalds {
1971da177e4SLinus Torvalds 	u_int class, subop;
1981da177e4SLinus Torvalds 	u_int fpu_type_flags;
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	/* All FP emulation code assumes that ints are 4-bytes in length */
2011da177e4SLinus Torvalds 	VASSERT(sizeof(int) == 4);
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	parisc_linux_get_fpu_type(fpregs);
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 	fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];  /* get fpu type flags */
2061da177e4SLinus Torvalds 
2071da177e4SLinus Torvalds 	class = get_class(ir);
2081da177e4SLinus Torvalds 	if (class == 1) {
2091da177e4SLinus Torvalds 		if  (fpu_type_flags & PA2_0_FPU_FLAG)
2101da177e4SLinus Torvalds 			subop = get_subop1_PA2_0(ir);
2111da177e4SLinus Torvalds 		else
2121da177e4SLinus Torvalds 			subop = get_subop1_PA1_1(ir);
2131da177e4SLinus Torvalds 	}
2141da177e4SLinus Torvalds 	else
2151da177e4SLinus Torvalds 		subop = get_subop(ir);
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	if (FPUDEBUG) printk("class %d subop %d\n", class, subop);
2181da177e4SLinus Torvalds 
2191da177e4SLinus Torvalds 	switch (excp_code) {
2201da177e4SLinus Torvalds 		case MAJOR_0C_EXCP:
2211da177e4SLinus Torvalds 		case PA83_UNIMP_EXCP:
2221da177e4SLinus Torvalds 			return(decode_0c(ir,class,subop,fpregs));
2231da177e4SLinus Torvalds 		case MAJOR_0E_EXCP:
2241da177e4SLinus Torvalds 			return(decode_0e(ir,class,subop,fpregs));
2251da177e4SLinus Torvalds 		case MAJOR_06_EXCP:
2261da177e4SLinus Torvalds 			return(decode_06(ir,fpregs));
2271da177e4SLinus Torvalds 		case MAJOR_26_EXCP:
2281da177e4SLinus Torvalds 			return(decode_26(ir,fpregs));
2291da177e4SLinus Torvalds 		case MAJOR_2E_EXCP:
2301da177e4SLinus Torvalds 			return(decode_2e(ir,fpregs));
2311da177e4SLinus Torvalds 		default:
2321da177e4SLinus Torvalds 			/* "crashme Night Gallery painting nr 2. (asm_crash.s).
2331da177e4SLinus Torvalds 			 * This was fixed for multi-user kernels, but
2341da177e4SLinus Torvalds 			 * workstation kernels had a panic here.  This allowed
2351da177e4SLinus Torvalds 			 * any arbitrary user to panic the kernel by executing
2361da177e4SLinus Torvalds 			 * setting the FP exception registers to strange values
2371da177e4SLinus Torvalds 			 * and generating an emulation trap.  The emulation and
2381da177e4SLinus Torvalds 			 * exception code must never be able to panic the
2391da177e4SLinus Torvalds 			 * kernel.
2401da177e4SLinus Torvalds 			 */
2411da177e4SLinus Torvalds 			return(UNIMPLEMENTEDEXCEPTION);
2421da177e4SLinus Torvalds 	}
2431da177e4SLinus Torvalds }
2441da177e4SLinus Torvalds 
2451da177e4SLinus Torvalds /*
2461da177e4SLinus Torvalds  * this routine is called by $emulation_trap to emulate a coprocessor
2471da177e4SLinus Torvalds  * instruction if one doesn't exist
2481da177e4SLinus Torvalds  */
2491da177e4SLinus Torvalds u_int
2501da177e4SLinus Torvalds emfpudispatch(u_int ir, u_int dummy1, u_int dummy2, u_int fpregs[])
2511da177e4SLinus Torvalds {
2521da177e4SLinus Torvalds 	u_int class, subop, major;
2531da177e4SLinus Torvalds 	u_int fpu_type_flags;
2541da177e4SLinus Torvalds 
2551da177e4SLinus Torvalds 	/* All FP emulation code assumes that ints are 4-bytes in length */
2561da177e4SLinus Torvalds 	VASSERT(sizeof(int) == 4);
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];  /* get fpu type flags */
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 	major = get_major(ir);
2611da177e4SLinus Torvalds 	class = get_class(ir);
2621da177e4SLinus Torvalds 	if (class == 1) {
2631da177e4SLinus Torvalds 		if  (fpu_type_flags & PA2_0_FPU_FLAG)
2641da177e4SLinus Torvalds 			subop = get_subop1_PA2_0(ir);
2651da177e4SLinus Torvalds 		else
2661da177e4SLinus Torvalds 			subop = get_subop1_PA1_1(ir);
2671da177e4SLinus Torvalds 	}
2681da177e4SLinus Torvalds 	else
2691da177e4SLinus Torvalds 		subop = get_subop(ir);
2701da177e4SLinus Torvalds 	switch (major) {
2711da177e4SLinus Torvalds 		case 0x0C:
2721da177e4SLinus Torvalds 			return(decode_0c(ir,class,subop,fpregs));
2731da177e4SLinus Torvalds 		case 0x0E:
2741da177e4SLinus Torvalds 			return(decode_0e(ir,class,subop,fpregs));
2751da177e4SLinus Torvalds 		case 0x06:
2761da177e4SLinus Torvalds 			return(decode_06(ir,fpregs));
2771da177e4SLinus Torvalds 		case 0x26:
2781da177e4SLinus Torvalds 			return(decode_26(ir,fpregs));
2791da177e4SLinus Torvalds 		case 0x2E:
2801da177e4SLinus Torvalds 			return(decode_2e(ir,fpregs));
2811da177e4SLinus Torvalds 		default:
2821da177e4SLinus Torvalds 			return(PA83_UNIMP_EXCP);
2831da177e4SLinus Torvalds 	}
2841da177e4SLinus Torvalds }
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds static u_int
2881da177e4SLinus Torvalds decode_0c(u_int ir, u_int class, u_int subop, u_int fpregs[])
2891da177e4SLinus Torvalds {
2901da177e4SLinus Torvalds 	u_int r1,r2,t;		/* operand register offsets */
2911da177e4SLinus Torvalds 	u_int fmt;		/* also sf for class 1 conversions */
2921da177e4SLinus Torvalds 	u_int  df;		/* for class 1 conversions */
2931da177e4SLinus Torvalds 	u_int *status;
2941da177e4SLinus Torvalds 	u_int retval, local_status;
2951da177e4SLinus Torvalds 	u_int fpu_type_flags;
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds 	if (ir == COPR_INST) {
2981da177e4SLinus Torvalds 		fpregs[0] = EMULATION_VERSION << 11;
2991da177e4SLinus Torvalds 		return(NOEXCEPTION);
3001da177e4SLinus Torvalds 	}
3011da177e4SLinus Torvalds 	status = &fpregs[0];	/* fp status register */
3021da177e4SLinus Torvalds 	local_status = fpregs[0]; /* and local copy */
3031da177e4SLinus Torvalds 	r1 = extru(ir,fpr1pos,5) * sizeof(double)/sizeof(u_int);
3041da177e4SLinus Torvalds 	if (r1 == 0)		/* map fr0 source to constant zero */
3051da177e4SLinus Torvalds 		r1 = fpzeroreg;
3061da177e4SLinus Torvalds 	t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int);
3071da177e4SLinus Torvalds 	if (t == 0 && class != 2)	/* don't allow fr0 as a dest */
3081da177e4SLinus Torvalds 		return(MAJOR_0C_EXCP);
3091da177e4SLinus Torvalds 	fmt = extru(ir,fpfmtpos,2);	/* get fmt completer */
3101da177e4SLinus Torvalds 
3111da177e4SLinus Torvalds 	switch (class) {
3121da177e4SLinus Torvalds 	    case 0:
3131da177e4SLinus Torvalds 		switch (subop) {
3141da177e4SLinus Torvalds 			case 0:	/* COPR 0,0 emulated above*/
3151da177e4SLinus Torvalds 			case 1:
3161da177e4SLinus Torvalds 				return(MAJOR_0C_EXCP);
3171da177e4SLinus Torvalds 			case 2:	/* FCPY */
3181da177e4SLinus Torvalds 				switch (fmt) {
3191da177e4SLinus Torvalds 				    case 2: /* illegal */
3201da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
3211da177e4SLinus Torvalds 				    case 3: /* quad */
3221da177e4SLinus Torvalds 					t &= ~3;  /* force to even reg #s */
3231da177e4SLinus Torvalds 					r1 &= ~3;
3241da177e4SLinus Torvalds 					fpregs[t+3] = fpregs[r1+3];
3251da177e4SLinus Torvalds 					fpregs[t+2] = fpregs[r1+2];
3261da177e4SLinus Torvalds 				    case 1: /* double */
3271da177e4SLinus Torvalds 					fpregs[t+1] = fpregs[r1+1];
3281da177e4SLinus Torvalds 				    case 0: /* single */
3291da177e4SLinus Torvalds 					fpregs[t] = fpregs[r1];
3301da177e4SLinus Torvalds 					return(NOEXCEPTION);
3311da177e4SLinus Torvalds 				}
3321da177e4SLinus Torvalds 			case 3: /* FABS */
3331da177e4SLinus Torvalds 				switch (fmt) {
3341da177e4SLinus Torvalds 				    case 2: /* illegal */
3351da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
3361da177e4SLinus Torvalds 				    case 3: /* quad */
3371da177e4SLinus Torvalds 					t &= ~3;  /* force to even reg #s */
3381da177e4SLinus Torvalds 					r1 &= ~3;
3391da177e4SLinus Torvalds 					fpregs[t+3] = fpregs[r1+3];
3401da177e4SLinus Torvalds 					fpregs[t+2] = fpregs[r1+2];
3411da177e4SLinus Torvalds 				    case 1: /* double */
3421da177e4SLinus Torvalds 					fpregs[t+1] = fpregs[r1+1];
3431da177e4SLinus Torvalds 				    case 0: /* single */
3441da177e4SLinus Torvalds 					/* copy and clear sign bit */
3451da177e4SLinus Torvalds 					fpregs[t] = fpregs[r1] & 0x7fffffff;
3461da177e4SLinus Torvalds 					return(NOEXCEPTION);
3471da177e4SLinus Torvalds 				}
3481da177e4SLinus Torvalds 			case 6: /* FNEG */
3491da177e4SLinus Torvalds 				switch (fmt) {
3501da177e4SLinus Torvalds 				    case 2: /* illegal */
3511da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
3521da177e4SLinus Torvalds 				    case 3: /* quad */
3531da177e4SLinus Torvalds 					t &= ~3;  /* force to even reg #s */
3541da177e4SLinus Torvalds 					r1 &= ~3;
3551da177e4SLinus Torvalds 					fpregs[t+3] = fpregs[r1+3];
3561da177e4SLinus Torvalds 					fpregs[t+2] = fpregs[r1+2];
3571da177e4SLinus Torvalds 				    case 1: /* double */
3581da177e4SLinus Torvalds 					fpregs[t+1] = fpregs[r1+1];
3591da177e4SLinus Torvalds 				    case 0: /* single */
3601da177e4SLinus Torvalds 					/* copy and invert sign bit */
3611da177e4SLinus Torvalds 					fpregs[t] = fpregs[r1] ^ 0x80000000;
3621da177e4SLinus Torvalds 					return(NOEXCEPTION);
3631da177e4SLinus Torvalds 				}
3641da177e4SLinus Torvalds 			case 7: /* FNEGABS */
3651da177e4SLinus Torvalds 				switch (fmt) {
3661da177e4SLinus Torvalds 				    case 2: /* illegal */
3671da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
3681da177e4SLinus Torvalds 				    case 3: /* quad */
3691da177e4SLinus Torvalds 					t &= ~3;  /* force to even reg #s */
3701da177e4SLinus Torvalds 					r1 &= ~3;
3711da177e4SLinus Torvalds 					fpregs[t+3] = fpregs[r1+3];
3721da177e4SLinus Torvalds 					fpregs[t+2] = fpregs[r1+2];
3731da177e4SLinus Torvalds 				    case 1: /* double */
3741da177e4SLinus Torvalds 					fpregs[t+1] = fpregs[r1+1];
3751da177e4SLinus Torvalds 				    case 0: /* single */
3761da177e4SLinus Torvalds 					/* copy and set sign bit */
3771da177e4SLinus Torvalds 					fpregs[t] = fpregs[r1] | 0x80000000;
3781da177e4SLinus Torvalds 					return(NOEXCEPTION);
3791da177e4SLinus Torvalds 				}
3801da177e4SLinus Torvalds 			case 4: /* FSQRT */
3811da177e4SLinus Torvalds 				switch (fmt) {
3821da177e4SLinus Torvalds 				    case 0:
3831da177e4SLinus Torvalds 					return(sgl_fsqrt(&fpregs[r1],0,
3841da177e4SLinus Torvalds 						&fpregs[t],status));
3851da177e4SLinus Torvalds 				    case 1:
3861da177e4SLinus Torvalds 					return(dbl_fsqrt(&fpregs[r1],0,
3871da177e4SLinus Torvalds 						&fpregs[t],status));
3881da177e4SLinus Torvalds 				    case 2:
3891da177e4SLinus Torvalds 				    case 3: /* quad not implemented */
3901da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
3911da177e4SLinus Torvalds 				}
3921da177e4SLinus Torvalds 			case 5: /* FRND */
3931da177e4SLinus Torvalds 				switch (fmt) {
3941da177e4SLinus Torvalds 				    case 0:
3951da177e4SLinus Torvalds 					return(sgl_frnd(&fpregs[r1],0,
3961da177e4SLinus Torvalds 						&fpregs[t],status));
3971da177e4SLinus Torvalds 				    case 1:
3981da177e4SLinus Torvalds 					return(dbl_frnd(&fpregs[r1],0,
3991da177e4SLinus Torvalds 						&fpregs[t],status));
4001da177e4SLinus Torvalds 				    case 2:
4011da177e4SLinus Torvalds 				    case 3: /* quad not implemented */
4021da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
4031da177e4SLinus Torvalds 				}
4041da177e4SLinus Torvalds 		} /* end of switch (subop) */
4051da177e4SLinus Torvalds 
4061da177e4SLinus Torvalds 	case 1: /* class 1 */
4071da177e4SLinus Torvalds 		df = extru(ir,fpdfpos,2); /* get dest format */
4081da177e4SLinus Torvalds 		if ((df & 2) || (fmt & 2)) {
4091da177e4SLinus Torvalds 			/*
4101da177e4SLinus Torvalds 			 * fmt's 2 and 3 are illegal of not implemented
4111da177e4SLinus Torvalds 			 * quad conversions
4121da177e4SLinus Torvalds 			 */
4131da177e4SLinus Torvalds 			return(MAJOR_0C_EXCP);
4141da177e4SLinus Torvalds 		}
4151da177e4SLinus Torvalds 		/*
4161da177e4SLinus Torvalds 		 * encode source and dest formats into 2 bits.
4171da177e4SLinus Torvalds 		 * high bit is source, low bit is dest.
4181da177e4SLinus Torvalds 		 * bit = 1 --> double precision
4191da177e4SLinus Torvalds 		 */
4201da177e4SLinus Torvalds 		fmt = (fmt << 1) | df;
4211da177e4SLinus Torvalds 		switch (subop) {
4221da177e4SLinus Torvalds 			case 0: /* FCNVFF */
4231da177e4SLinus Torvalds 				switch(fmt) {
4241da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
4251da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
4261da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
4271da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvff(&fpregs[r1],0,
4281da177e4SLinus Torvalds 						&fpregs[t],status));
4291da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
4301da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvff(&fpregs[r1],0,
4311da177e4SLinus Torvalds 						&fpregs[t],status));
4321da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
4331da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
4341da177e4SLinus Torvalds 				}
4351da177e4SLinus Torvalds 			case 1: /* FCNVXF */
4361da177e4SLinus Torvalds 				switch(fmt) {
4371da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
4381da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvxf(&fpregs[r1],0,
4391da177e4SLinus Torvalds 						&fpregs[t],status));
4401da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
4411da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvxf(&fpregs[r1],0,
4421da177e4SLinus Torvalds 						&fpregs[t],status));
4431da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
4441da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvxf(&fpregs[r1],0,
4451da177e4SLinus Torvalds 						&fpregs[t],status));
4461da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
4471da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,
4481da177e4SLinus Torvalds 						&fpregs[t],status));
4491da177e4SLinus Torvalds 				}
4501da177e4SLinus Torvalds 			case 2: /* FCNVFX */
4511da177e4SLinus Torvalds 				switch(fmt) {
4521da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
4531da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvfx(&fpregs[r1],0,
4541da177e4SLinus Torvalds 						&fpregs[t],status));
4551da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
4561da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvfx(&fpregs[r1],0,
4571da177e4SLinus Torvalds 						&fpregs[t],status));
4581da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
4591da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvfx(&fpregs[r1],0,
4601da177e4SLinus Torvalds 						&fpregs[t],status));
4611da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
4621da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,
4631da177e4SLinus Torvalds 						&fpregs[t],status));
4641da177e4SLinus Torvalds 				}
4651da177e4SLinus Torvalds 			case 3: /* FCNVFXT */
4661da177e4SLinus Torvalds 				switch(fmt) {
4671da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
4681da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0,
4691da177e4SLinus Torvalds 						&fpregs[t],status));
4701da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
4711da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0,
4721da177e4SLinus Torvalds 						&fpregs[t],status));
4731da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
4741da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0,
4751da177e4SLinus Torvalds 						&fpregs[t],status));
4761da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
4771da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,
4781da177e4SLinus Torvalds 						&fpregs[t],status));
4791da177e4SLinus Torvalds 				}
4801da177e4SLinus Torvalds 			case 5: /* FCNVUF (PA2.0 only) */
4811da177e4SLinus Torvalds 				switch(fmt) {
4821da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
4831da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvuf(&fpregs[r1],0,
4841da177e4SLinus Torvalds 						&fpregs[t],status));
4851da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
4861da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvuf(&fpregs[r1],0,
4871da177e4SLinus Torvalds 						&fpregs[t],status));
4881da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
4891da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvuf(&fpregs[r1],0,
4901da177e4SLinus Torvalds 						&fpregs[t],status));
4911da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
4921da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,
4931da177e4SLinus Torvalds 						&fpregs[t],status));
4941da177e4SLinus Torvalds 				}
4951da177e4SLinus Torvalds 			case 6: /* FCNVFU (PA2.0 only) */
4961da177e4SLinus Torvalds 				switch(fmt) {
4971da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
4981da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvfu(&fpregs[r1],0,
4991da177e4SLinus Torvalds 						&fpregs[t],status));
5001da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
5011da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvfu(&fpregs[r1],0,
5021da177e4SLinus Torvalds 						&fpregs[t],status));
5031da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
5041da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvfu(&fpregs[r1],0,
5051da177e4SLinus Torvalds 						&fpregs[t],status));
5061da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
5071da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,
5081da177e4SLinus Torvalds 						&fpregs[t],status));
5091da177e4SLinus Torvalds 				}
5101da177e4SLinus Torvalds 			case 7: /* FCNVFUT (PA2.0 only) */
5111da177e4SLinus Torvalds 				switch(fmt) {
5121da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
5131da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvfut(&fpregs[r1],0,
5141da177e4SLinus Torvalds 						&fpregs[t],status));
5151da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
5161da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvfut(&fpregs[r1],0,
5171da177e4SLinus Torvalds 						&fpregs[t],status));
5181da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
5191da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvfut(&fpregs[r1],0,
5201da177e4SLinus Torvalds 						&fpregs[t],status));
5211da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
5221da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,
5231da177e4SLinus Torvalds 						&fpregs[t],status));
5241da177e4SLinus Torvalds 				}
5251da177e4SLinus Torvalds 			case 4: /* undefined */
5261da177e4SLinus Torvalds 				return(MAJOR_0C_EXCP);
5271da177e4SLinus Torvalds 		} /* end of switch subop */
5281da177e4SLinus Torvalds 
5291da177e4SLinus Torvalds 	case 2: /* class 2 */
5301da177e4SLinus Torvalds 		fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];
5311da177e4SLinus Torvalds 		r2 = extru(ir, fpr2pos, 5) * sizeof(double)/sizeof(u_int);
5321da177e4SLinus Torvalds 		if (r2 == 0)
5331da177e4SLinus Torvalds 			r2 = fpzeroreg;
5341da177e4SLinus Torvalds 		if  (fpu_type_flags & PA2_0_FPU_FLAG) {
5351da177e4SLinus Torvalds 			/* FTEST if nullify bit set, otherwise FCMP */
5361da177e4SLinus Torvalds 			if (extru(ir, fpnulpos, 1)) {  /* FTEST */
5371da177e4SLinus Torvalds 				switch (fmt) {
5381da177e4SLinus Torvalds 				    case 0:
5391da177e4SLinus Torvalds 					/*
5401da177e4SLinus Torvalds 					 * arg0 is not used
5411da177e4SLinus Torvalds 					 * second param is the t field used for
5421da177e4SLinus Torvalds 					 * ftest,acc and ftest,rej
5431da177e4SLinus Torvalds 					 * third param is the subop (y-field)
5441da177e4SLinus Torvalds 					 */
5451da177e4SLinus Torvalds 					BUG();
5461da177e4SLinus Torvalds 					/* Unsupported
5471da177e4SLinus Torvalds 					 * return(ftest(0L,extru(ir,fptpos,5),
5481da177e4SLinus Torvalds 					 *	 &fpregs[0],subop));
5491da177e4SLinus Torvalds 					 */
5501da177e4SLinus Torvalds 				    case 1:
5511da177e4SLinus Torvalds 				    case 2:
5521da177e4SLinus Torvalds 				    case 3:
5531da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
5541da177e4SLinus Torvalds 				}
5551da177e4SLinus Torvalds 			} else {  /* FCMP */
5561da177e4SLinus Torvalds 				switch (fmt) {
5571da177e4SLinus Torvalds 				    case 0:
5581da177e4SLinus Torvalds 					retval = sgl_fcmp(&fpregs[r1],
5591da177e4SLinus Torvalds 						&fpregs[r2],extru(ir,fptpos,5),
5601da177e4SLinus Torvalds 						&local_status);
5611da177e4SLinus Torvalds 					update_status_cbit(status,local_status,
5621da177e4SLinus Torvalds 						fpu_type_flags, subop);
5631da177e4SLinus Torvalds 					return(retval);
5641da177e4SLinus Torvalds 				    case 1:
5651da177e4SLinus Torvalds 					retval = dbl_fcmp(&fpregs[r1],
5661da177e4SLinus Torvalds 						&fpregs[r2],extru(ir,fptpos,5),
5671da177e4SLinus Torvalds 						&local_status);
5681da177e4SLinus Torvalds 					update_status_cbit(status,local_status,
5691da177e4SLinus Torvalds 						fpu_type_flags, subop);
5701da177e4SLinus Torvalds 					return(retval);
5711da177e4SLinus Torvalds 				    case 2: /* illegal */
5721da177e4SLinus Torvalds 				    case 3: /* quad not implemented */
5731da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
5741da177e4SLinus Torvalds 				}
5751da177e4SLinus Torvalds 			}
5761da177e4SLinus Torvalds 		}  /* end of if for PA2.0 */
5771da177e4SLinus Torvalds 		else {	/* PA1.0 & PA1.1 */
5781da177e4SLinus Torvalds 		    switch (subop) {
5791da177e4SLinus Torvalds 			case 2:
5801da177e4SLinus Torvalds 			case 3:
5811da177e4SLinus Torvalds 			case 4:
5821da177e4SLinus Torvalds 			case 5:
5831da177e4SLinus Torvalds 			case 6:
5841da177e4SLinus Torvalds 			case 7:
5851da177e4SLinus Torvalds 				return(MAJOR_0C_EXCP);
5861da177e4SLinus Torvalds 			case 0: /* FCMP */
5871da177e4SLinus Torvalds 				switch (fmt) {
5881da177e4SLinus Torvalds 				    case 0:
5891da177e4SLinus Torvalds 					retval = sgl_fcmp(&fpregs[r1],
5901da177e4SLinus Torvalds 						&fpregs[r2],extru(ir,fptpos,5),
5911da177e4SLinus Torvalds 						&local_status);
5921da177e4SLinus Torvalds 					update_status_cbit(status,local_status,
5931da177e4SLinus Torvalds 						fpu_type_flags, subop);
5941da177e4SLinus Torvalds 					return(retval);
5951da177e4SLinus Torvalds 				    case 1:
5961da177e4SLinus Torvalds 					retval = dbl_fcmp(&fpregs[r1],
5971da177e4SLinus Torvalds 						&fpregs[r2],extru(ir,fptpos,5),
5981da177e4SLinus Torvalds 						&local_status);
5991da177e4SLinus Torvalds 					update_status_cbit(status,local_status,
6001da177e4SLinus Torvalds 						fpu_type_flags, subop);
6011da177e4SLinus Torvalds 					return(retval);
6021da177e4SLinus Torvalds 				    case 2: /* illegal */
6031da177e4SLinus Torvalds 				    case 3: /* quad not implemented */
6041da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
6051da177e4SLinus Torvalds 				}
6061da177e4SLinus Torvalds 			case 1: /* FTEST */
6071da177e4SLinus Torvalds 				switch (fmt) {
6081da177e4SLinus Torvalds 				    case 0:
6091da177e4SLinus Torvalds 					/*
6101da177e4SLinus Torvalds 					 * arg0 is not used
6111da177e4SLinus Torvalds 					 * second param is the t field used for
6121da177e4SLinus Torvalds 					 * ftest,acc and ftest,rej
6131da177e4SLinus Torvalds 					 * third param is the subop (y-field)
6141da177e4SLinus Torvalds 					 */
6151da177e4SLinus Torvalds 					BUG();
6161da177e4SLinus Torvalds 					/* unsupported
6171da177e4SLinus Torvalds 					 * return(ftest(0L,extru(ir,fptpos,5),
6181da177e4SLinus Torvalds 					 *     &fpregs[0],subop));
6191da177e4SLinus Torvalds 					 */
6201da177e4SLinus Torvalds 				    case 1:
6211da177e4SLinus Torvalds 				    case 2:
6221da177e4SLinus Torvalds 				    case 3:
6231da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
6241da177e4SLinus Torvalds 				}
6251da177e4SLinus Torvalds 		    } /* end of switch subop */
6261da177e4SLinus Torvalds 		} /* end of else for PA1.0 & PA1.1 */
6271da177e4SLinus Torvalds 	case 3: /* class 3 */
6281da177e4SLinus Torvalds 		r2 = extru(ir,fpr2pos,5) * sizeof(double)/sizeof(u_int);
6291da177e4SLinus Torvalds 		if (r2 == 0)
6301da177e4SLinus Torvalds 			r2 = fpzeroreg;
6311da177e4SLinus Torvalds 		switch (subop) {
6321da177e4SLinus Torvalds 			case 5:
6331da177e4SLinus Torvalds 			case 6:
6341da177e4SLinus Torvalds 			case 7:
6351da177e4SLinus Torvalds 				return(MAJOR_0C_EXCP);
6361da177e4SLinus Torvalds 
6371da177e4SLinus Torvalds 			case 0: /* FADD */
6381da177e4SLinus Torvalds 				switch (fmt) {
6391da177e4SLinus Torvalds 				    case 0:
6401da177e4SLinus Torvalds 					return(sgl_fadd(&fpregs[r1],&fpregs[r2],
6411da177e4SLinus Torvalds 						&fpregs[t],status));
6421da177e4SLinus Torvalds 				    case 1:
6431da177e4SLinus Torvalds 					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
6441da177e4SLinus Torvalds 						&fpregs[t],status));
6451da177e4SLinus Torvalds 				    case 2: /* illegal */
6461da177e4SLinus Torvalds 				    case 3: /* quad not implemented */
6471da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
6481da177e4SLinus Torvalds 				}
6491da177e4SLinus Torvalds 			case 1: /* FSUB */
6501da177e4SLinus Torvalds 				switch (fmt) {
6511da177e4SLinus Torvalds 				    case 0:
6521da177e4SLinus Torvalds 					return(sgl_fsub(&fpregs[r1],&fpregs[r2],
6531da177e4SLinus Torvalds 						&fpregs[t],status));
6541da177e4SLinus Torvalds 				    case 1:
6551da177e4SLinus Torvalds 					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
6561da177e4SLinus Torvalds 						&fpregs[t],status));
6571da177e4SLinus Torvalds 				    case 2: /* illegal */
6581da177e4SLinus Torvalds 				    case 3: /* quad not implemented */
6591da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
6601da177e4SLinus Torvalds 				}
6611da177e4SLinus Torvalds 			case 2: /* FMPY */
6621da177e4SLinus Torvalds 				switch (fmt) {
6631da177e4SLinus Torvalds 				    case 0:
6641da177e4SLinus Torvalds 					return(sgl_fmpy(&fpregs[r1],&fpregs[r2],
6651da177e4SLinus Torvalds 						&fpregs[t],status));
6661da177e4SLinus Torvalds 				    case 1:
6671da177e4SLinus Torvalds 					return(dbl_fmpy(&fpregs[r1],&fpregs[r2],
6681da177e4SLinus Torvalds 						&fpregs[t],status));
6691da177e4SLinus Torvalds 				    case 2: /* illegal */
6701da177e4SLinus Torvalds 				    case 3: /* quad not implemented */
6711da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
6721da177e4SLinus Torvalds 				}
6731da177e4SLinus Torvalds 			case 3: /* FDIV */
6741da177e4SLinus Torvalds 				switch (fmt) {
6751da177e4SLinus Torvalds 				    case 0:
6761da177e4SLinus Torvalds 					return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
6771da177e4SLinus Torvalds 						&fpregs[t],status));
6781da177e4SLinus Torvalds 				    case 1:
6791da177e4SLinus Torvalds 					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
6801da177e4SLinus Torvalds 						&fpregs[t],status));
6811da177e4SLinus Torvalds 				    case 2: /* illegal */
6821da177e4SLinus Torvalds 				    case 3: /* quad not implemented */
6831da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
6841da177e4SLinus Torvalds 				}
6851da177e4SLinus Torvalds 			case 4: /* FREM */
6861da177e4SLinus Torvalds 				switch (fmt) {
6871da177e4SLinus Torvalds 				    case 0:
6881da177e4SLinus Torvalds 					return(sgl_frem(&fpregs[r1],&fpregs[r2],
6891da177e4SLinus Torvalds 						&fpregs[t],status));
6901da177e4SLinus Torvalds 				    case 1:
6911da177e4SLinus Torvalds 					return(dbl_frem(&fpregs[r1],&fpregs[r2],
6921da177e4SLinus Torvalds 						&fpregs[t],status));
6931da177e4SLinus Torvalds 				    case 2: /* illegal */
6941da177e4SLinus Torvalds 				    case 3: /* quad not implemented */
6951da177e4SLinus Torvalds 					return(MAJOR_0C_EXCP);
6961da177e4SLinus Torvalds 				}
6971da177e4SLinus Torvalds 		} /* end of class 3 switch */
6981da177e4SLinus Torvalds 	} /* end of switch(class) */
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	/* If we get here, something is really wrong! */
7011da177e4SLinus Torvalds 	return(MAJOR_0C_EXCP);
7021da177e4SLinus Torvalds }
7031da177e4SLinus Torvalds 
7041da177e4SLinus Torvalds static u_int
7051da177e4SLinus Torvalds decode_0e(ir,class,subop,fpregs)
7061da177e4SLinus Torvalds u_int ir,class,subop;
7071da177e4SLinus Torvalds u_int fpregs[];
7081da177e4SLinus Torvalds {
7091da177e4SLinus Torvalds 	u_int r1,r2,t;		/* operand register offsets */
7101da177e4SLinus Torvalds 	u_int fmt;		/* also sf for class 1 conversions */
7111da177e4SLinus Torvalds 	u_int df;		/* dest format for class 1 conversions */
7121da177e4SLinus Torvalds 	u_int *status;
7131da177e4SLinus Torvalds 	u_int retval, local_status;
7141da177e4SLinus Torvalds 	u_int fpu_type_flags;
7151da177e4SLinus Torvalds 
7161da177e4SLinus Torvalds 	status = &fpregs[0];
7171da177e4SLinus Torvalds 	local_status = fpregs[0];
7181da177e4SLinus Torvalds 	r1 = ((extru(ir,fpr1pos,5)<<1)|(extru(ir,fpxr1pos,1)));
7191da177e4SLinus Torvalds 	if (r1 == 0)
7201da177e4SLinus Torvalds 		r1 = fpzeroreg;
7211da177e4SLinus Torvalds 	t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));
7221da177e4SLinus Torvalds 	if (t == 0 && class != 2)
7231da177e4SLinus Torvalds 		return(MAJOR_0E_EXCP);
7241da177e4SLinus Torvalds 	if (class < 2)		/* class 0 or 1 has 2 bit fmt */
7251da177e4SLinus Torvalds 		fmt = extru(ir,fpfmtpos,2);
7261da177e4SLinus Torvalds 	else 			/* class 2 and 3 have 1 bit fmt */
7271da177e4SLinus Torvalds 		fmt = extru(ir,fp0efmtpos,1);
7281da177e4SLinus Torvalds 	/*
7291da177e4SLinus Torvalds 	 * An undefined combination, double precision accessing the
7301da177e4SLinus Torvalds 	 * right half of a FPR, can get us into trouble.
7311da177e4SLinus Torvalds 	 * Let's just force proper alignment on it.
7321da177e4SLinus Torvalds 	 */
7331da177e4SLinus Torvalds 	if (fmt == DBL) {
7341da177e4SLinus Torvalds 		r1 &= ~1;
7351da177e4SLinus Torvalds 		if (class != 1)
7361da177e4SLinus Torvalds 			t &= ~1;
7371da177e4SLinus Torvalds 	}
7381da177e4SLinus Torvalds 
7391da177e4SLinus Torvalds 	switch (class) {
7401da177e4SLinus Torvalds 	    case 0:
7411da177e4SLinus Torvalds 		switch (subop) {
7421da177e4SLinus Torvalds 			case 0: /* unimplemented */
7431da177e4SLinus Torvalds 			case 1:
7441da177e4SLinus Torvalds 				return(MAJOR_0E_EXCP);
7451da177e4SLinus Torvalds 			case 2: /* FCPY */
7461da177e4SLinus Torvalds 				switch (fmt) {
7471da177e4SLinus Torvalds 				    case 2:
7481da177e4SLinus Torvalds 				    case 3:
7491da177e4SLinus Torvalds 					return(MAJOR_0E_EXCP);
7501da177e4SLinus Torvalds 				    case 1: /* double */
7511da177e4SLinus Torvalds 					fpregs[t+1] = fpregs[r1+1];
7521da177e4SLinus Torvalds 				    case 0: /* single */
7531da177e4SLinus Torvalds 					fpregs[t] = fpregs[r1];
7541da177e4SLinus Torvalds 					return(NOEXCEPTION);
7551da177e4SLinus Torvalds 				}
7561da177e4SLinus Torvalds 			case 3: /* FABS */
7571da177e4SLinus Torvalds 				switch (fmt) {
7581da177e4SLinus Torvalds 				    case 2:
7591da177e4SLinus Torvalds 				    case 3:
7601da177e4SLinus Torvalds 					return(MAJOR_0E_EXCP);
7611da177e4SLinus Torvalds 				    case 1: /* double */
7621da177e4SLinus Torvalds 					fpregs[t+1] = fpregs[r1+1];
7631da177e4SLinus Torvalds 				    case 0: /* single */
7641da177e4SLinus Torvalds 					fpregs[t] = fpregs[r1] & 0x7fffffff;
7651da177e4SLinus Torvalds 					return(NOEXCEPTION);
7661da177e4SLinus Torvalds 				}
7671da177e4SLinus Torvalds 			case 6: /* FNEG */
7681da177e4SLinus Torvalds 				switch (fmt) {
7691da177e4SLinus Torvalds 				    case 2:
7701da177e4SLinus Torvalds 				    case 3:
7711da177e4SLinus Torvalds 					return(MAJOR_0E_EXCP);
7721da177e4SLinus Torvalds 				    case 1: /* double */
7731da177e4SLinus Torvalds 					fpregs[t+1] = fpregs[r1+1];
7741da177e4SLinus Torvalds 				    case 0: /* single */
7751da177e4SLinus Torvalds 					fpregs[t] = fpregs[r1] ^ 0x80000000;
7761da177e4SLinus Torvalds 					return(NOEXCEPTION);
7771da177e4SLinus Torvalds 				}
7781da177e4SLinus Torvalds 			case 7: /* FNEGABS */
7791da177e4SLinus Torvalds 				switch (fmt) {
7801da177e4SLinus Torvalds 				    case 2:
7811da177e4SLinus Torvalds 				    case 3:
7821da177e4SLinus Torvalds 					return(MAJOR_0E_EXCP);
7831da177e4SLinus Torvalds 				    case 1: /* double */
7841da177e4SLinus Torvalds 					fpregs[t+1] = fpregs[r1+1];
7851da177e4SLinus Torvalds 				    case 0: /* single */
7861da177e4SLinus Torvalds 					fpregs[t] = fpregs[r1] | 0x80000000;
7871da177e4SLinus Torvalds 					return(NOEXCEPTION);
7881da177e4SLinus Torvalds 				}
7891da177e4SLinus Torvalds 			case 4: /* FSQRT */
7901da177e4SLinus Torvalds 				switch (fmt) {
7911da177e4SLinus Torvalds 				    case 0:
7921da177e4SLinus Torvalds 					return(sgl_fsqrt(&fpregs[r1],0,
7931da177e4SLinus Torvalds 						&fpregs[t], status));
7941da177e4SLinus Torvalds 				    case 1:
7951da177e4SLinus Torvalds 					return(dbl_fsqrt(&fpregs[r1],0,
7961da177e4SLinus Torvalds 						&fpregs[t], status));
7971da177e4SLinus Torvalds 				    case 2:
7981da177e4SLinus Torvalds 				    case 3:
7991da177e4SLinus Torvalds 					return(MAJOR_0E_EXCP);
8001da177e4SLinus Torvalds 				}
8011da177e4SLinus Torvalds 			case 5: /* FRMD */
8021da177e4SLinus Torvalds 				switch (fmt) {
8031da177e4SLinus Torvalds 				    case 0:
8041da177e4SLinus Torvalds 					return(sgl_frnd(&fpregs[r1],0,
8051da177e4SLinus Torvalds 						&fpregs[t], status));
8061da177e4SLinus Torvalds 				    case 1:
8071da177e4SLinus Torvalds 					return(dbl_frnd(&fpregs[r1],0,
8081da177e4SLinus Torvalds 						&fpregs[t], status));
8091da177e4SLinus Torvalds 				    case 2:
8101da177e4SLinus Torvalds 				    case 3:
8111da177e4SLinus Torvalds 					return(MAJOR_0E_EXCP);
8121da177e4SLinus Torvalds 				}
8131da177e4SLinus Torvalds 		} /* end of switch (subop */
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds 	case 1: /* class 1 */
8161da177e4SLinus Torvalds 		df = extru(ir,fpdfpos,2); /* get dest format */
8171da177e4SLinus Torvalds 		/*
8181da177e4SLinus Torvalds 		 * Fix Crashme problem (writing to 31R in double precision)
8191da177e4SLinus Torvalds 		 * here too.
8201da177e4SLinus Torvalds 		 */
8211da177e4SLinus Torvalds 		if (df == DBL) {
8221da177e4SLinus Torvalds 			t &= ~1;
8231da177e4SLinus Torvalds 		}
8241da177e4SLinus Torvalds 		if ((df & 2) || (fmt & 2))
8251da177e4SLinus Torvalds 			return(MAJOR_0E_EXCP);
8261da177e4SLinus Torvalds 
8271da177e4SLinus Torvalds 		fmt = (fmt << 1) | df;
8281da177e4SLinus Torvalds 		switch (subop) {
8291da177e4SLinus Torvalds 			case 0: /* FCNVFF */
8301da177e4SLinus Torvalds 				switch(fmt) {
8311da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
8321da177e4SLinus Torvalds 					return(MAJOR_0E_EXCP);
8331da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
8341da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvff(&fpregs[r1],0,
8351da177e4SLinus Torvalds 						&fpregs[t],status));
8361da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
8371da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvff(&fpregs[r1],0,
8381da177e4SLinus Torvalds 						&fpregs[t],status));
8391da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
8401da177e4SLinus Torvalds 					return(MAJOR_0E_EXCP);
8411da177e4SLinus Torvalds 				}
8421da177e4SLinus Torvalds 			case 1: /* FCNVXF */
8431da177e4SLinus Torvalds 				switch(fmt) {
8441da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
8451da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvxf(&fpregs[r1],0,
8461da177e4SLinus Torvalds 						&fpregs[t],status));
8471da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
8481da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvxf(&fpregs[r1],0,
8491da177e4SLinus Torvalds 						&fpregs[t],status));
8501da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
8511da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvxf(&fpregs[r1],0,
8521da177e4SLinus Torvalds 						&fpregs[t],status));
8531da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
8541da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,
8551da177e4SLinus Torvalds 						&fpregs[t],status));
8561da177e4SLinus Torvalds 				}
8571da177e4SLinus Torvalds 			case 2: /* FCNVFX */
8581da177e4SLinus Torvalds 				switch(fmt) {
8591da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
8601da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvfx(&fpregs[r1],0,
8611da177e4SLinus Torvalds 						&fpregs[t],status));
8621da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
8631da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvfx(&fpregs[r1],0,
8641da177e4SLinus Torvalds 						&fpregs[t],status));
8651da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
8661da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvfx(&fpregs[r1],0,
8671da177e4SLinus Torvalds 						&fpregs[t],status));
8681da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
8691da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,
8701da177e4SLinus Torvalds 						&fpregs[t],status));
8711da177e4SLinus Torvalds 				}
8721da177e4SLinus Torvalds 			case 3: /* FCNVFXT */
8731da177e4SLinus Torvalds 				switch(fmt) {
8741da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
8751da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0,
8761da177e4SLinus Torvalds 						&fpregs[t],status));
8771da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
8781da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0,
8791da177e4SLinus Torvalds 						&fpregs[t],status));
8801da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
8811da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0,
8821da177e4SLinus Torvalds 						&fpregs[t],status));
8831da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
8841da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,
8851da177e4SLinus Torvalds 						&fpregs[t],status));
8861da177e4SLinus Torvalds 				}
8871da177e4SLinus Torvalds 			case 5: /* FCNVUF (PA2.0 only) */
8881da177e4SLinus Torvalds 				switch(fmt) {
8891da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
8901da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvuf(&fpregs[r1],0,
8911da177e4SLinus Torvalds 						&fpregs[t],status));
8921da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
8931da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvuf(&fpregs[r1],0,
8941da177e4SLinus Torvalds 						&fpregs[t],status));
8951da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
8961da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvuf(&fpregs[r1],0,
8971da177e4SLinus Torvalds 						&fpregs[t],status));
8981da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
8991da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,
9001da177e4SLinus Torvalds 						&fpregs[t],status));
9011da177e4SLinus Torvalds 				}
9021da177e4SLinus Torvalds 			case 6: /* FCNVFU (PA2.0 only) */
9031da177e4SLinus Torvalds 				switch(fmt) {
9041da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
9051da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvfu(&fpregs[r1],0,
9061da177e4SLinus Torvalds 						&fpregs[t],status));
9071da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
9081da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvfu(&fpregs[r1],0,
9091da177e4SLinus Torvalds 						&fpregs[t],status));
9101da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
9111da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvfu(&fpregs[r1],0,
9121da177e4SLinus Torvalds 						&fpregs[t],status));
9131da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
9141da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,
9151da177e4SLinus Torvalds 						&fpregs[t],status));
9161da177e4SLinus Torvalds 				}
9171da177e4SLinus Torvalds 			case 7: /* FCNVFUT (PA2.0 only) */
9181da177e4SLinus Torvalds 				switch(fmt) {
9191da177e4SLinus Torvalds 				    case 0: /* sgl/sgl */
9201da177e4SLinus Torvalds 					return(sgl_to_sgl_fcnvfut(&fpregs[r1],0,
9211da177e4SLinus Torvalds 						&fpregs[t],status));
9221da177e4SLinus Torvalds 				    case 1: /* sgl/dbl */
9231da177e4SLinus Torvalds 					return(sgl_to_dbl_fcnvfut(&fpregs[r1],0,
9241da177e4SLinus Torvalds 						&fpregs[t],status));
9251da177e4SLinus Torvalds 				    case 2: /* dbl/sgl */
9261da177e4SLinus Torvalds 					return(dbl_to_sgl_fcnvfut(&fpregs[r1],0,
9271da177e4SLinus Torvalds 						&fpregs[t],status));
9281da177e4SLinus Torvalds 				    case 3: /* dbl/dbl */
9291da177e4SLinus Torvalds 					return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,
9301da177e4SLinus Torvalds 						&fpregs[t],status));
9311da177e4SLinus Torvalds 				}
9321da177e4SLinus Torvalds 			case 4: /* undefined */
9331da177e4SLinus Torvalds 				return(MAJOR_0C_EXCP);
9341da177e4SLinus Torvalds 		} /* end of switch subop */
9351da177e4SLinus Torvalds 	case 2: /* class 2 */
9361da177e4SLinus Torvalds 		/*
9371da177e4SLinus Torvalds 		 * Be careful out there.
9381da177e4SLinus Torvalds 		 * Crashme can generate cases where FR31R is specified
9391da177e4SLinus Torvalds 		 * as the source or target of a double precision operation.
9401da177e4SLinus Torvalds 		 * Since we just pass the address of the floating-point
9411da177e4SLinus Torvalds 		 * register to the emulation routines, this can cause
9421da177e4SLinus Torvalds 		 * corruption of fpzeroreg.
9431da177e4SLinus Torvalds 		 */
9441da177e4SLinus Torvalds 		if (fmt == DBL)
9451da177e4SLinus Torvalds 			r2 = (extru(ir,fpr2pos,5)<<1);
9461da177e4SLinus Torvalds 		else
9471da177e4SLinus Torvalds 			r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
9481da177e4SLinus Torvalds 		fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];
9491da177e4SLinus Torvalds 		if (r2 == 0)
9501da177e4SLinus Torvalds 			r2 = fpzeroreg;
9511da177e4SLinus Torvalds 		if  (fpu_type_flags & PA2_0_FPU_FLAG) {
9521da177e4SLinus Torvalds 			/* FTEST if nullify bit set, otherwise FCMP */
9531da177e4SLinus Torvalds 			if (extru(ir, fpnulpos, 1)) {  /* FTEST */
9541da177e4SLinus Torvalds 				/* not legal */
9551da177e4SLinus Torvalds 				return(MAJOR_0E_EXCP);
9561da177e4SLinus Torvalds 			} else {  /* FCMP */
9571da177e4SLinus Torvalds 			switch (fmt) {
9581da177e4SLinus Torvalds 				    /*
9591da177e4SLinus Torvalds 				     * fmt is only 1 bit long
9601da177e4SLinus Torvalds 				     */
9611da177e4SLinus Torvalds 				    case 0:
9621da177e4SLinus Torvalds 					retval = sgl_fcmp(&fpregs[r1],
9631da177e4SLinus Torvalds 						&fpregs[r2],extru(ir,fptpos,5),
9641da177e4SLinus Torvalds 						&local_status);
9651da177e4SLinus Torvalds 					update_status_cbit(status,local_status,
9661da177e4SLinus Torvalds 						fpu_type_flags, subop);
9671da177e4SLinus Torvalds 					return(retval);
9681da177e4SLinus Torvalds 				    case 1:
9691da177e4SLinus Torvalds 					retval = dbl_fcmp(&fpregs[r1],
9701da177e4SLinus Torvalds 						&fpregs[r2],extru(ir,fptpos,5),
9711da177e4SLinus Torvalds 						&local_status);
9721da177e4SLinus Torvalds 					update_status_cbit(status,local_status,
9731da177e4SLinus Torvalds 						fpu_type_flags, subop);
9741da177e4SLinus Torvalds 					return(retval);
9751da177e4SLinus Torvalds 				}
9761da177e4SLinus Torvalds 			}
9771da177e4SLinus Torvalds 		}  /* end of if for PA2.0 */
9781da177e4SLinus Torvalds 		else {  /* PA1.0 & PA1.1 */
9791da177e4SLinus Torvalds 		    switch (subop) {
9801da177e4SLinus Torvalds 			case 1:
9811da177e4SLinus Torvalds 			case 2:
9821da177e4SLinus Torvalds 			case 3:
9831da177e4SLinus Torvalds 			case 4:
9841da177e4SLinus Torvalds 			case 5:
9851da177e4SLinus Torvalds 			case 6:
9861da177e4SLinus Torvalds 			case 7:
9871da177e4SLinus Torvalds 				return(MAJOR_0E_EXCP);
9881da177e4SLinus Torvalds 			case 0: /* FCMP */
9891da177e4SLinus Torvalds 				switch (fmt) {
9901da177e4SLinus Torvalds 				    /*
9911da177e4SLinus Torvalds 				     * fmt is only 1 bit long
9921da177e4SLinus Torvalds 				     */
9931da177e4SLinus Torvalds 				    case 0:
9941da177e4SLinus Torvalds 					retval = sgl_fcmp(&fpregs[r1],
9951da177e4SLinus Torvalds 						&fpregs[r2],extru(ir,fptpos,5),
9961da177e4SLinus Torvalds 						&local_status);
9971da177e4SLinus Torvalds 					update_status_cbit(status,local_status,
9981da177e4SLinus Torvalds 						fpu_type_flags, subop);
9991da177e4SLinus Torvalds 					return(retval);
10001da177e4SLinus Torvalds 				    case 1:
10011da177e4SLinus Torvalds 					retval = dbl_fcmp(&fpregs[r1],
10021da177e4SLinus Torvalds 						&fpregs[r2],extru(ir,fptpos,5),
10031da177e4SLinus Torvalds 						&local_status);
10041da177e4SLinus Torvalds 					update_status_cbit(status,local_status,
10051da177e4SLinus Torvalds 						fpu_type_flags, subop);
10061da177e4SLinus Torvalds 					return(retval);
10071da177e4SLinus Torvalds 				}
10081da177e4SLinus Torvalds 		    } /* end of switch subop */
10091da177e4SLinus Torvalds 		} /* end of else for PA1.0 & PA1.1 */
10101da177e4SLinus Torvalds 	case 3: /* class 3 */
10111da177e4SLinus Torvalds 		/*
10121da177e4SLinus Torvalds 		 * Be careful out there.
10131da177e4SLinus Torvalds 		 * Crashme can generate cases where FR31R is specified
10141da177e4SLinus Torvalds 		 * as the source or target of a double precision operation.
10151da177e4SLinus Torvalds 		 * Since we just pass the address of the floating-point
10161da177e4SLinus Torvalds 		 * register to the emulation routines, this can cause
10171da177e4SLinus Torvalds 		 * corruption of fpzeroreg.
10181da177e4SLinus Torvalds 		 */
10191da177e4SLinus Torvalds 		if (fmt == DBL)
10201da177e4SLinus Torvalds 			r2 = (extru(ir,fpr2pos,5)<<1);
10211da177e4SLinus Torvalds 		else
10221da177e4SLinus Torvalds 			r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
10231da177e4SLinus Torvalds 		if (r2 == 0)
10241da177e4SLinus Torvalds 			r2 = fpzeroreg;
10251da177e4SLinus Torvalds 		switch (subop) {
10261da177e4SLinus Torvalds 			case 5:
10271da177e4SLinus Torvalds 			case 6:
10281da177e4SLinus Torvalds 			case 7:
10291da177e4SLinus Torvalds 				return(MAJOR_0E_EXCP);
10301da177e4SLinus Torvalds 
10311da177e4SLinus Torvalds 			/*
10321da177e4SLinus Torvalds 			 * Note that fmt is only 1 bit for class 3 */
10331da177e4SLinus Torvalds 			case 0: /* FADD */
10341da177e4SLinus Torvalds 				switch (fmt) {
10351da177e4SLinus Torvalds 				    case 0:
10361da177e4SLinus Torvalds 					return(sgl_fadd(&fpregs[r1],&fpregs[r2],
10371da177e4SLinus Torvalds 						&fpregs[t],status));
10381da177e4SLinus Torvalds 				    case 1:
10391da177e4SLinus Torvalds 					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
10401da177e4SLinus Torvalds 						&fpregs[t],status));
10411da177e4SLinus Torvalds 				}
10421da177e4SLinus Torvalds 			case 1: /* FSUB */
10431da177e4SLinus Torvalds 				switch (fmt) {
10441da177e4SLinus Torvalds 				    case 0:
10451da177e4SLinus Torvalds 					return(sgl_fsub(&fpregs[r1],&fpregs[r2],
10461da177e4SLinus Torvalds 						&fpregs[t],status));
10471da177e4SLinus Torvalds 				    case 1:
10481da177e4SLinus Torvalds 					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
10491da177e4SLinus Torvalds 						&fpregs[t],status));
10501da177e4SLinus Torvalds 				}
10511da177e4SLinus Torvalds 			case 2: /* FMPY or XMPYU */
10521da177e4SLinus Torvalds 				/*
10531da177e4SLinus Torvalds 				 * check for integer multiply (x bit set)
10541da177e4SLinus Torvalds 				 */
10551da177e4SLinus Torvalds 				if (extru(ir,fpxpos,1)) {
10561da177e4SLinus Torvalds 				    /*
10571da177e4SLinus Torvalds 				     * emulate XMPYU
10581da177e4SLinus Torvalds 				     */
10591da177e4SLinus Torvalds 				    switch (fmt) {
10601da177e4SLinus Torvalds 					case 0:
10611da177e4SLinus Torvalds 					    /*
10621da177e4SLinus Torvalds 					     * bad instruction if t specifies
10631da177e4SLinus Torvalds 					     * the right half of a register
10641da177e4SLinus Torvalds 					     */
10651da177e4SLinus Torvalds 					    if (t & 1)
10661da177e4SLinus Torvalds 						return(MAJOR_0E_EXCP);
10671da177e4SLinus Torvalds 					    BUG();
10681da177e4SLinus Torvalds 					    /* unsupported
10691da177e4SLinus Torvalds 					     * impyu(&fpregs[r1],&fpregs[r2],
10701da177e4SLinus Torvalds 						 * &fpregs[t]);
10711da177e4SLinus Torvalds 					     */
10721da177e4SLinus Torvalds 					    return(NOEXCEPTION);
10731da177e4SLinus Torvalds 					case 1:
10741da177e4SLinus Torvalds 						return(MAJOR_0E_EXCP);
10751da177e4SLinus Torvalds 				    }
10761da177e4SLinus Torvalds 				}
10771da177e4SLinus Torvalds 				else { /* FMPY */
10781da177e4SLinus Torvalds 				    switch (fmt) {
10791da177e4SLinus Torvalds 				        case 0:
10801da177e4SLinus Torvalds 					    return(sgl_fmpy(&fpregs[r1],
10811da177e4SLinus Torvalds 					       &fpregs[r2],&fpregs[t],status));
10821da177e4SLinus Torvalds 				        case 1:
10831da177e4SLinus Torvalds 					    return(dbl_fmpy(&fpregs[r1],
10841da177e4SLinus Torvalds 					       &fpregs[r2],&fpregs[t],status));
10851da177e4SLinus Torvalds 				    }
10861da177e4SLinus Torvalds 				}
10871da177e4SLinus Torvalds 			case 3: /* FDIV */
10881da177e4SLinus Torvalds 				switch (fmt) {
10891da177e4SLinus Torvalds 				    case 0:
10901da177e4SLinus Torvalds 					return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
10911da177e4SLinus Torvalds 						&fpregs[t],status));
10921da177e4SLinus Torvalds 				    case 1:
10931da177e4SLinus Torvalds 					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
10941da177e4SLinus Torvalds 						&fpregs[t],status));
10951da177e4SLinus Torvalds 				}
10961da177e4SLinus Torvalds 			case 4: /* FREM */
10971da177e4SLinus Torvalds 				switch (fmt) {
10981da177e4SLinus Torvalds 				    case 0:
10991da177e4SLinus Torvalds 					return(sgl_frem(&fpregs[r1],&fpregs[r2],
11001da177e4SLinus Torvalds 						&fpregs[t],status));
11011da177e4SLinus Torvalds 				    case 1:
11021da177e4SLinus Torvalds 					return(dbl_frem(&fpregs[r1],&fpregs[r2],
11031da177e4SLinus Torvalds 						&fpregs[t],status));
11041da177e4SLinus Torvalds 				}
11051da177e4SLinus Torvalds 		} /* end of class 3 switch */
11061da177e4SLinus Torvalds 	} /* end of switch(class) */
11071da177e4SLinus Torvalds 
11081da177e4SLinus Torvalds 	/* If we get here, something is really wrong! */
11091da177e4SLinus Torvalds 	return(MAJOR_0E_EXCP);
11101da177e4SLinus Torvalds }
11111da177e4SLinus Torvalds 
11121da177e4SLinus Torvalds 
11131da177e4SLinus Torvalds /*
11141da177e4SLinus Torvalds  * routine to decode the 06 (FMPYADD and FMPYCFXT) instruction
11151da177e4SLinus Torvalds  */
11161da177e4SLinus Torvalds static u_int
11171da177e4SLinus Torvalds decode_06(ir,fpregs)
11181da177e4SLinus Torvalds u_int ir;
11191da177e4SLinus Torvalds u_int fpregs[];
11201da177e4SLinus Torvalds {
11211da177e4SLinus Torvalds 	u_int rm1, rm2, tm, ra, ta; /* operands */
11221da177e4SLinus Torvalds 	u_int fmt;
11231da177e4SLinus Torvalds 	u_int error = 0;
11241da177e4SLinus Torvalds 	u_int status;
11251da177e4SLinus Torvalds 	u_int fpu_type_flags;
11261da177e4SLinus Torvalds 	union {
11271da177e4SLinus Torvalds 		double dbl;
11281da177e4SLinus Torvalds 		float flt;
11291da177e4SLinus Torvalds 		struct { u_int i1; u_int i2; } ints;
11301da177e4SLinus Torvalds 	} mtmp, atmp;
11311da177e4SLinus Torvalds 
11321da177e4SLinus Torvalds 
11331da177e4SLinus Torvalds 	status = fpregs[0];		/* use a local copy of status reg */
11341da177e4SLinus Torvalds 	fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];  /* get fpu type flags */
11351da177e4SLinus Torvalds 	fmt = extru(ir, fpmultifmt, 1);	/* get sgl/dbl flag */
11361da177e4SLinus Torvalds 	if (fmt == 0) { /* DBL */
11371da177e4SLinus Torvalds 		rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int);
11381da177e4SLinus Torvalds 		if (rm1 == 0)
11391da177e4SLinus Torvalds 			rm1 = fpzeroreg;
11401da177e4SLinus Torvalds 		rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int);
11411da177e4SLinus Torvalds 		if (rm2 == 0)
11421da177e4SLinus Torvalds 			rm2 = fpzeroreg;
11431da177e4SLinus Torvalds 		tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int);
11441da177e4SLinus Torvalds 		if (tm == 0)
11451da177e4SLinus Torvalds 			return(MAJOR_06_EXCP);
11461da177e4SLinus Torvalds 		ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int);
11471da177e4SLinus Torvalds 		ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int);
11481da177e4SLinus Torvalds 		if (ta == 0)
11491da177e4SLinus Torvalds 			return(MAJOR_06_EXCP);
11501da177e4SLinus Torvalds 
11511da177e4SLinus Torvalds 		if  (fpu_type_flags & TIMEX_ROLEX_FPU_MASK)  {
11521da177e4SLinus Torvalds 
11531da177e4SLinus Torvalds 			if (ra == 0) {
11541da177e4SLinus Torvalds 			 	/* special case FMPYCFXT, see sgl case below */
11551da177e4SLinus Torvalds 				if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],
11561da177e4SLinus Torvalds 					&mtmp.ints.i1,&status))
11571da177e4SLinus Torvalds 					error = 1;
11581da177e4SLinus Torvalds 				if (dbl_to_sgl_fcnvfxt(&fpregs[ta],
11591da177e4SLinus Torvalds 					&atmp.ints.i1,&atmp.ints.i1,&status))
11601da177e4SLinus Torvalds 					error = 1;
11611da177e4SLinus Torvalds 				}
11621da177e4SLinus Torvalds 			else {
11631da177e4SLinus Torvalds 
11641da177e4SLinus Torvalds 			if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
11651da177e4SLinus Torvalds 					&status))
11661da177e4SLinus Torvalds 				error = 1;
11671da177e4SLinus Torvalds 			if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
11681da177e4SLinus Torvalds 					&status))
11691da177e4SLinus Torvalds 				error = 1;
11701da177e4SLinus Torvalds 				}
11711da177e4SLinus Torvalds 			}
11721da177e4SLinus Torvalds 
11731da177e4SLinus Torvalds 		else
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds 			{
11761da177e4SLinus Torvalds 			if (ra == 0)
11771da177e4SLinus Torvalds 				ra = fpzeroreg;
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds 			if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
11801da177e4SLinus Torvalds 					&status))
11811da177e4SLinus Torvalds 				error = 1;
11821da177e4SLinus Torvalds 			if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
11831da177e4SLinus Torvalds 					&status))
11841da177e4SLinus Torvalds 				error = 1;
11851da177e4SLinus Torvalds 
11861da177e4SLinus Torvalds 			}
11871da177e4SLinus Torvalds 
11881da177e4SLinus Torvalds 		if (error)
11891da177e4SLinus Torvalds 			return(MAJOR_06_EXCP);
11901da177e4SLinus Torvalds 		else {
11911da177e4SLinus Torvalds 			/* copy results */
11921da177e4SLinus Torvalds 			fpregs[tm] = mtmp.ints.i1;
11931da177e4SLinus Torvalds 			fpregs[tm+1] = mtmp.ints.i2;
11941da177e4SLinus Torvalds 			fpregs[ta] = atmp.ints.i1;
11951da177e4SLinus Torvalds 			fpregs[ta+1] = atmp.ints.i2;
11961da177e4SLinus Torvalds 			fpregs[0] = status;
11971da177e4SLinus Torvalds 			return(NOEXCEPTION);
11981da177e4SLinus Torvalds 		}
11991da177e4SLinus Torvalds 	}
12001da177e4SLinus Torvalds 	else { /* SGL */
12011da177e4SLinus Torvalds 		/*
12021da177e4SLinus Torvalds 		 * calculate offsets for single precision numbers
12031da177e4SLinus Torvalds 		 * See table 6-14 in PA-89 architecture for mapping
12041da177e4SLinus Torvalds 		 */
12051da177e4SLinus Torvalds 		rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1;	/* get offset */
12061da177e4SLinus Torvalds 		rm1 |= extru(ir,fprm1pos-4,1);	/* add right word offset */
12071da177e4SLinus Torvalds 
12081da177e4SLinus Torvalds 		rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1;	/* get offset */
12091da177e4SLinus Torvalds 		rm2 |= extru(ir,fprm2pos-4,1);	/* add right word offset */
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds 		tm = (extru(ir,fptmpos,4) | 0x10 ) << 1;	/* get offset */
12121da177e4SLinus Torvalds 		tm |= extru(ir,fptmpos-4,1);	/* add right word offset */
12131da177e4SLinus Torvalds 
12141da177e4SLinus Torvalds 		ra = (extru(ir,fprapos,4) | 0x10 ) << 1;	/* get offset */
12151da177e4SLinus Torvalds 		ra |= extru(ir,fprapos-4,1);	/* add right word offset */
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds 		ta = (extru(ir,fptapos,4) | 0x10 ) << 1;	/* get offset */
12181da177e4SLinus Torvalds 		ta |= extru(ir,fptapos-4,1);	/* add right word offset */
12191da177e4SLinus Torvalds 
12201da177e4SLinus Torvalds 		if (ra == 0x20 &&(fpu_type_flags & TIMEX_ROLEX_FPU_MASK)) {
12211da177e4SLinus Torvalds 			/* special case FMPYCFXT (really 0)
12221da177e4SLinus Torvalds 			  * This instruction is only present on the Timex and
12231da177e4SLinus Torvalds 			  * Rolex fpu's in so if it is the special case and
12241da177e4SLinus Torvalds 			  * one of these fpu's we run the FMPYCFXT instruction
12251da177e4SLinus Torvalds 			  */
12261da177e4SLinus Torvalds 			if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
12271da177e4SLinus Torvalds 					&status))
12281da177e4SLinus Torvalds 				error = 1;
12291da177e4SLinus Torvalds 			if (sgl_to_sgl_fcnvfxt(&fpregs[ta],&atmp.ints.i1,
12301da177e4SLinus Torvalds 				&atmp.ints.i1,&status))
12311da177e4SLinus Torvalds 				error = 1;
12321da177e4SLinus Torvalds 		}
12331da177e4SLinus Torvalds 		else {
12341da177e4SLinus Torvalds 			if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
12351da177e4SLinus Torvalds 					&status))
12361da177e4SLinus Torvalds 				error = 1;
12371da177e4SLinus Torvalds 			if (sgl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
12381da177e4SLinus Torvalds 					&status))
12391da177e4SLinus Torvalds 				error = 1;
12401da177e4SLinus Torvalds 		}
12411da177e4SLinus Torvalds 		if (error)
12421da177e4SLinus Torvalds 			return(MAJOR_06_EXCP);
12431da177e4SLinus Torvalds 		else {
12441da177e4SLinus Torvalds 			/* copy results */
12451da177e4SLinus Torvalds 			fpregs[tm] = mtmp.ints.i1;
12461da177e4SLinus Torvalds 			fpregs[ta] = atmp.ints.i1;
12471da177e4SLinus Torvalds 			fpregs[0] = status;
12481da177e4SLinus Torvalds 			return(NOEXCEPTION);
12491da177e4SLinus Torvalds 		}
12501da177e4SLinus Torvalds 	}
12511da177e4SLinus Torvalds }
12521da177e4SLinus Torvalds 
12531da177e4SLinus Torvalds /*
12541da177e4SLinus Torvalds  * routine to decode the 26 (FMPYSUB) instruction
12551da177e4SLinus Torvalds  */
12561da177e4SLinus Torvalds static u_int
12571da177e4SLinus Torvalds decode_26(ir,fpregs)
12581da177e4SLinus Torvalds u_int ir;
12591da177e4SLinus Torvalds u_int fpregs[];
12601da177e4SLinus Torvalds {
12611da177e4SLinus Torvalds 	u_int rm1, rm2, tm, ra, ta; /* operands */
12621da177e4SLinus Torvalds 	u_int fmt;
12631da177e4SLinus Torvalds 	u_int error = 0;
12641da177e4SLinus Torvalds 	u_int status;
12651da177e4SLinus Torvalds 	union {
12661da177e4SLinus Torvalds 		double dbl;
12671da177e4SLinus Torvalds 		float flt;
12681da177e4SLinus Torvalds 		struct { u_int i1; u_int i2; } ints;
12691da177e4SLinus Torvalds 	} mtmp, atmp;
12701da177e4SLinus Torvalds 
12711da177e4SLinus Torvalds 
12721da177e4SLinus Torvalds 	status = fpregs[0];
12731da177e4SLinus Torvalds 	fmt = extru(ir, fpmultifmt, 1);	/* get sgl/dbl flag */
12741da177e4SLinus Torvalds 	if (fmt == 0) { /* DBL */
12751da177e4SLinus Torvalds 		rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int);
12761da177e4SLinus Torvalds 		if (rm1 == 0)
12771da177e4SLinus Torvalds 			rm1 = fpzeroreg;
12781da177e4SLinus Torvalds 		rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int);
12791da177e4SLinus Torvalds 		if (rm2 == 0)
12801da177e4SLinus Torvalds 			rm2 = fpzeroreg;
12811da177e4SLinus Torvalds 		tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int);
12821da177e4SLinus Torvalds 		if (tm == 0)
12831da177e4SLinus Torvalds 			return(MAJOR_26_EXCP);
12841da177e4SLinus Torvalds 		ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int);
12851da177e4SLinus Torvalds 		if (ra == 0)
12861da177e4SLinus Torvalds 			return(MAJOR_26_EXCP);
12871da177e4SLinus Torvalds 		ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int);
12881da177e4SLinus Torvalds 		if (ta == 0)
12891da177e4SLinus Torvalds 			return(MAJOR_26_EXCP);
12901da177e4SLinus Torvalds 
12911da177e4SLinus Torvalds 		if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status))
12921da177e4SLinus Torvalds 			error = 1;
12931da177e4SLinus Torvalds 		if (dbl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status))
12941da177e4SLinus Torvalds 			error = 1;
12951da177e4SLinus Torvalds 		if (error)
12961da177e4SLinus Torvalds 			return(MAJOR_26_EXCP);
12971da177e4SLinus Torvalds 		else {
12981da177e4SLinus Torvalds 			/* copy results */
12991da177e4SLinus Torvalds 			fpregs[tm] = mtmp.ints.i1;
13001da177e4SLinus Torvalds 			fpregs[tm+1] = mtmp.ints.i2;
13011da177e4SLinus Torvalds 			fpregs[ta] = atmp.ints.i1;
13021da177e4SLinus Torvalds 			fpregs[ta+1] = atmp.ints.i2;
13031da177e4SLinus Torvalds 			fpregs[0] = status;
13041da177e4SLinus Torvalds 			return(NOEXCEPTION);
13051da177e4SLinus Torvalds 		}
13061da177e4SLinus Torvalds 	}
13071da177e4SLinus Torvalds 	else { /* SGL */
13081da177e4SLinus Torvalds 		/*
13091da177e4SLinus Torvalds 		 * calculate offsets for single precision numbers
13101da177e4SLinus Torvalds 		 * See table 6-14 in PA-89 architecture for mapping
13111da177e4SLinus Torvalds 		 */
13121da177e4SLinus Torvalds 		rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1;	/* get offset */
13131da177e4SLinus Torvalds 		rm1 |= extru(ir,fprm1pos-4,1);	/* add right word offset */
13141da177e4SLinus Torvalds 
13151da177e4SLinus Torvalds 		rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1;	/* get offset */
13161da177e4SLinus Torvalds 		rm2 |= extru(ir,fprm2pos-4,1);	/* add right word offset */
13171da177e4SLinus Torvalds 
13181da177e4SLinus Torvalds 		tm = (extru(ir,fptmpos,4) | 0x10 ) << 1;	/* get offset */
13191da177e4SLinus Torvalds 		tm |= extru(ir,fptmpos-4,1);	/* add right word offset */
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds 		ra = (extru(ir,fprapos,4) | 0x10 ) << 1;	/* get offset */
13221da177e4SLinus Torvalds 		ra |= extru(ir,fprapos-4,1);	/* add right word offset */
13231da177e4SLinus Torvalds 
13241da177e4SLinus Torvalds 		ta = (extru(ir,fptapos,4) | 0x10 ) << 1;	/* get offset */
13251da177e4SLinus Torvalds 		ta |= extru(ir,fptapos-4,1);	/* add right word offset */
13261da177e4SLinus Torvalds 
13271da177e4SLinus Torvalds 		if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status))
13281da177e4SLinus Torvalds 			error = 1;
13291da177e4SLinus Torvalds 		if (sgl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status))
13301da177e4SLinus Torvalds 			error = 1;
13311da177e4SLinus Torvalds 		if (error)
13321da177e4SLinus Torvalds 			return(MAJOR_26_EXCP);
13331da177e4SLinus Torvalds 		else {
13341da177e4SLinus Torvalds 			/* copy results */
13351da177e4SLinus Torvalds 			fpregs[tm] = mtmp.ints.i1;
13361da177e4SLinus Torvalds 			fpregs[ta] = atmp.ints.i1;
13371da177e4SLinus Torvalds 			fpregs[0] = status;
13381da177e4SLinus Torvalds 			return(NOEXCEPTION);
13391da177e4SLinus Torvalds 		}
13401da177e4SLinus Torvalds 	}
13411da177e4SLinus Torvalds 
13421da177e4SLinus Torvalds }
13431da177e4SLinus Torvalds 
13441da177e4SLinus Torvalds /*
13451da177e4SLinus Torvalds  * routine to decode the 2E (FMPYFADD,FMPYNFADD) instructions
13461da177e4SLinus Torvalds  */
13471da177e4SLinus Torvalds static u_int
13481da177e4SLinus Torvalds decode_2e(ir,fpregs)
13491da177e4SLinus Torvalds u_int ir;
13501da177e4SLinus Torvalds u_int fpregs[];
13511da177e4SLinus Torvalds {
13521da177e4SLinus Torvalds 	u_int rm1, rm2, ra, t; /* operands */
13531da177e4SLinus Torvalds 	u_int fmt;
13541da177e4SLinus Torvalds 
13551da177e4SLinus Torvalds 	fmt = extru(ir,fpfmtpos,1);	/* get fmt completer */
13561da177e4SLinus Torvalds 	if (fmt == DBL) { /* DBL */
13571da177e4SLinus Torvalds 		rm1 = extru(ir,fprm1pos,5) * sizeof(double)/sizeof(u_int);
13581da177e4SLinus Torvalds 		if (rm1 == 0)
13591da177e4SLinus Torvalds 			rm1 = fpzeroreg;
13601da177e4SLinus Torvalds 		rm2 = extru(ir,fprm2pos,5) * sizeof(double)/sizeof(u_int);
13611da177e4SLinus Torvalds 		if (rm2 == 0)
13621da177e4SLinus Torvalds 			rm2 = fpzeroreg;
13631da177e4SLinus Torvalds 		ra = ((extru(ir,fpraupos,3)<<2)|(extru(ir,fpralpos,3)>>1)) *
13641da177e4SLinus Torvalds 		     sizeof(double)/sizeof(u_int);
13651da177e4SLinus Torvalds 		if (ra == 0)
13661da177e4SLinus Torvalds 			ra = fpzeroreg;
13671da177e4SLinus Torvalds 		t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int);
13681da177e4SLinus Torvalds 		if (t == 0)
13691da177e4SLinus Torvalds 			return(MAJOR_2E_EXCP);
13701da177e4SLinus Torvalds 
13711da177e4SLinus Torvalds 		if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */
13721da177e4SLinus Torvalds 			return(dbl_fmpynfadd(&fpregs[rm1], &fpregs[rm2],
13731da177e4SLinus Torvalds 					&fpregs[ra], &fpregs[0], &fpregs[t]));
13741da177e4SLinus Torvalds 		} else {
13751da177e4SLinus Torvalds 			return(dbl_fmpyfadd(&fpregs[rm1], &fpregs[rm2],
13761da177e4SLinus Torvalds 					&fpregs[ra], &fpregs[0], &fpregs[t]));
13771da177e4SLinus Torvalds 		}
13781da177e4SLinus Torvalds 	} /* end DBL */
13791da177e4SLinus Torvalds 	else { /* SGL */
13801da177e4SLinus Torvalds 		rm1 = (extru(ir,fprm1pos,5)<<1)|(extru(ir,fpxrm1pos,1));
13811da177e4SLinus Torvalds 		if (rm1 == 0)
13821da177e4SLinus Torvalds 			rm1 = fpzeroreg;
13831da177e4SLinus Torvalds 		rm2 = (extru(ir,fprm2pos,5)<<1)|(extru(ir,fpxrm2pos,1));
13841da177e4SLinus Torvalds 		if (rm2 == 0)
13851da177e4SLinus Torvalds 			rm2 = fpzeroreg;
13861da177e4SLinus Torvalds 		ra = (extru(ir,fpraupos,3)<<3)|extru(ir,fpralpos,3);
13871da177e4SLinus Torvalds 		if (ra == 0)
13881da177e4SLinus Torvalds 			ra = fpzeroreg;
13891da177e4SLinus Torvalds 		t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));
13901da177e4SLinus Torvalds 		if (t == 0)
13911da177e4SLinus Torvalds 			return(MAJOR_2E_EXCP);
13921da177e4SLinus Torvalds 
13931da177e4SLinus Torvalds 		if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */
13941da177e4SLinus Torvalds 			return(sgl_fmpynfadd(&fpregs[rm1], &fpregs[rm2],
13951da177e4SLinus Torvalds 					&fpregs[ra], &fpregs[0], &fpregs[t]));
13961da177e4SLinus Torvalds 		} else {
13971da177e4SLinus Torvalds 			return(sgl_fmpyfadd(&fpregs[rm1], &fpregs[rm2],
13981da177e4SLinus Torvalds 					&fpregs[ra], &fpregs[0], &fpregs[t]));
13991da177e4SLinus Torvalds 		}
14001da177e4SLinus Torvalds 	} /* end SGL */
14011da177e4SLinus Torvalds }
14021da177e4SLinus Torvalds 
14031da177e4SLinus Torvalds /*
14041da177e4SLinus Torvalds  * update_status_cbit
14051da177e4SLinus Torvalds  *
14061da177e4SLinus Torvalds  *	This routine returns the correct FP status register value in
14071da177e4SLinus Torvalds  *	*status, based on the C-bit & V-bit returned by the FCMP
14081da177e4SLinus Torvalds  *	emulation routine in new_status.  The architecture type
14091da177e4SLinus Torvalds  *	(PA83, PA89 or PA2.0) is available in fpu_type.  The y_field
14101da177e4SLinus Torvalds  *	and the architecture type are used to determine what flavor
14111da177e4SLinus Torvalds  *	of FCMP is being emulated.
14121da177e4SLinus Torvalds  */
14131da177e4SLinus Torvalds static void
14141da177e4SLinus Torvalds update_status_cbit(status, new_status, fpu_type, y_field)
14151da177e4SLinus Torvalds u_int *status, new_status;
14161da177e4SLinus Torvalds u_int fpu_type;
14171da177e4SLinus Torvalds u_int y_field;
14181da177e4SLinus Torvalds {
14191da177e4SLinus Torvalds 	/*
14201da177e4SLinus Torvalds 	 * For PA89 FPU's which implement the Compare Queue and
14211da177e4SLinus Torvalds 	 * for PA2.0 FPU's, update the Compare Queue if the y-field = 0,
14221da177e4SLinus Torvalds 	 * otherwise update the specified bit in the Compare Array.
14231da177e4SLinus Torvalds 	 * Note that the y-field will always be 0 for non-PA2.0 FPU's.
14241da177e4SLinus Torvalds 	 */
14251da177e4SLinus Torvalds 	if ((fpu_type & TIMEX_EXTEN_FLAG) ||
14261da177e4SLinus Torvalds 	    (fpu_type & ROLEX_EXTEN_FLAG) ||
14271da177e4SLinus Torvalds 	    (fpu_type & PA2_0_FPU_FLAG)) {
14281da177e4SLinus Torvalds 		if (y_field == 0) {
14291da177e4SLinus Torvalds 			*status = ((*status & 0x04000000) >> 5) | /* old Cbit */
14301da177e4SLinus Torvalds 				  ((*status & 0x003ff000) >> 1) | /* old CQ   */
14311da177e4SLinus Torvalds 				  (new_status & 0xffc007ff); /* all other bits*/
14321da177e4SLinus Torvalds 		} else {
14331da177e4SLinus Torvalds 			*status = (*status & 0x04000000) |     /* old Cbit */
14341da177e4SLinus Torvalds 				  ((new_status & 0x04000000) >> (y_field+4)) |
14351da177e4SLinus Torvalds 				  (new_status & ~0x04000000 &  /* other bits */
14361da177e4SLinus Torvalds 				   ~(0x04000000 >> (y_field+4)));
14371da177e4SLinus Torvalds 		}
14381da177e4SLinus Torvalds 	}
14391da177e4SLinus Torvalds 	/* if PA83, just update the C-bit */
14401da177e4SLinus Torvalds 	else {
14411da177e4SLinus Torvalds 		*status = new_status;
14421da177e4SLinus Torvalds 	}
14431da177e4SLinus Torvalds }
1444