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