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