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