xref: /netbsd-src/sys/arch/hppa/spmath/fpudispatch.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: fpudispatch.c,v 1.2 2003/07/15 02:29:42 lukem Exp $	 */
2 
3 /*
4  *  (c) Copyright 1991 HEWLETT-PACKARD COMPANY
5  *
6  *  To anyone who acknowledges that this file is provided "AS IS"
7  *  without any express or implied warranty:
8  *      permission to use, copy, modify, and distribute this file
9  *  for any purpose is hereby granted without fee, provided that
10  *  the above copyright notice and this notice appears in all
11  *  copies, and that the name of Hewlett-Packard Company not be
12  *  used in advertising or publicity pertaining to distribution
13  *  of the software without specific, written prior permission.
14  *  Hewlett-Packard Company makes no representations about the
15  *  suitability of this software for any purpose.
16  */
17 
18 /* Source: /n/schirf/u/baford/CVS/mach4-parisc/kernel/parisc/fpudispatch.c,v
19  * Revision: 1.4 	Author: mike
20  * State: Exp    	Locker:
21  * Date: 1994/07/21 17:36:35
22  */
23 
24 #include <sys/cdefs.h>
25 __KERNEL_RCSID(0, "$NetBSD: fpudispatch.c,v 1.2 2003/07/15 02:29:42 lukem Exp $");
26 
27 #include <sys/types.h>
28 #include <sys/systm.h>
29 
30 #include "../spmath/float.h"
31 /*
32  * XXX fredette - hack to glue the bulk of
33  * the spmath library to this dispatcher.
34  */
35 #define	dbl_integer		unsigned
36 #define	sgl_floating_point	unsigned
37 #define	dbl_floating_point	unsigned
38 #include "../spmath/sgl_float.h"
39 #include "../spmath/dbl_float.h"
40 #include "../spmath/cnv_float.h"
41 #include "../spmath/md.h"
42 #include "../spmath/fpudispatch.h"
43 
44 /*
45  * version of EMULATION software for COPR,0,0 instruction
46  */
47 #define EMULATION_VERSION 3
48 #define COPR_INST 0x30000000
49 
50 /*
51  * definition of extru macro.  If pos and len are constants, the compiler
52  * will generate an extru instruction when optimized
53  */
54 #define extru(r,pos,len)	(((r) >> (31-(pos))) & (( 1 << (len)) - 1))
55 /* definitions of bit field locations in the instruction */
56 #define fpmajorpos 5
57 #define fpr1pos	10
58 #define fpr2pos 15
59 #define fptpos	31
60 #define fpsubpos 18
61 #define fpclass1subpos 16
62 #define fpclasspos 22
63 #define fpfmtpos 20
64 #define fpdfpos 18
65 /*
66  * the following are the extra bits for the 0E major op
67  */
68 #define fpxr1pos 24
69 #define fpxr2pos 19
70 #define fpxtpos 25
71 #define fpxpos 23
72 #define fp0efmtpos 20
73 /*
74  * the following are for the multi-ops
75  */
76 #define fprm1pos 10
77 #define fprm2pos 15
78 #define fptmpos 31
79 #define fprapos 25
80 #define fptapos 20
81 #define fpmultifmt 26
82 
83 /*
84  * offset to constant zero in the FP emulation registers
85  */
86 #define fpzeroreg (32*sizeof(double)/sizeof(unsigned))
87 
88 /*
89  * extract the major opcode from the instruction
90  */
91 #define get_major(op) extru(op,fpmajorpos,6)
92 /*
93  * extract the two bit class field from the FP instruction. The class is at bit
94  * positions 21-22
95  */
96 #define get_class(op) extru(op,fpclasspos,2)
97 /*
98  * extract the 3 bit subop field.  For all but class 1 instructions, it is
99  * located at bit positions 16-18
100  */
101 #define get_subop(op) extru(op,fpsubpos,3)
102 /*
103  * extract the 2 bit subop field from class 1 instructions.  It is located
104  * at bit positions 15-16
105  */
106 #define get_subop1(op) extru(op,fpclass1subpos,2)
107 
108 /* definitions of unimplemented exceptions */
109 #define MAJOR_0C_EXCP	UNIMPLEMENTEDEXCEPTION
110 #define MAJOR_0E_EXCP	UNIMPLEMENTEDEXCEPTION
111 #define MAJOR_06_EXCP	UNIMPLEMENTEDEXCEPTION
112 #define MAJOR_26_EXCP	UNIMPLEMENTEDEXCEPTION
113 #define PA83_UNIMP_EXCP	UNIMPLEMENTEDEXCEPTION
114 
115 int
116 decode_0c(ir,class,subop,fpregs)
117 unsigned ir,class,subop;
118 unsigned fpregs[];
119 {
120 	unsigned r1,r2,t;	/* operand register offsets */
121 	unsigned fmt;		/* also sf for class 1 conversions */
122 	unsigned  df;		/* for class 1 conversions */
123 	unsigned *status;
124 
125 	if (ir == COPR_INST) {
126 		fpregs[0] = EMULATION_VERSION << 11;
127 		return(NOEXCEPTION);
128 	}
129 	status = &fpregs[0];	/* fp status register */
130 	r1 = extru(ir,fpr1pos,5) * sizeof(double)/sizeof(unsigned);
131 	if (r1 == 0)		/* map fr0 source to constant zero */
132 		r1 = fpzeroreg;
133 	t = extru(ir,fptpos,5) * sizeof(double)/sizeof(unsigned);
134 	if (t == 0 && class != 2)	/* don't allow fr0 as a dest */
135 		return(MAJOR_0C_EXCP);
136 	fmt = extru(ir,fpfmtpos,2);	/* get fmt completer */
137 
138 	switch (class) {
139 	    case 0:
140 		switch (subop) {
141 			case 0:	/* COPR 0,0 emulated above*/
142 			case 1:
143 			case 6:
144 			case 7:
145 				return(MAJOR_0C_EXCP);
146 			case 2:	/* FCPY */
147 				switch (fmt) {
148 				    case 2: /* illegal */
149 					return(MAJOR_0C_EXCP);
150 				    case 3: /* quad */
151 					fpregs[t+3] = fpregs[r1+3];
152 					fpregs[t+2] = fpregs[r1+2];
153 				    case 1: /* double */
154 					fpregs[t+1] = fpregs[r1+1];
155 				    case 0: /* single */
156 					fpregs[t] = fpregs[r1];
157 					return(NOEXCEPTION);
158 				}
159 			case 3: /* FABS */
160 				switch (fmt) {
161 				    case 2: /* illegal */
162 					return(MAJOR_0C_EXCP);
163 				    case 3: /* quad */
164 					fpregs[t+3] = fpregs[r1+3];
165 					fpregs[t+2] = fpregs[r1+2];
166 				    case 1: /* double */
167 					fpregs[t+1] = fpregs[r1+1];
168 				    case 0: /* single */
169 					/* copy and clear sign bit */
170 					fpregs[t] = fpregs[r1] & 0x7fffffff;
171 					return(NOEXCEPTION);
172 				}
173 			case 4: /* FSQRT */
174 				switch (fmt) {
175 				    case 0:
176 					return(sgl_fsqrt(&fpregs[r1],
177 						&fpregs[t],status));
178 				    case 1:
179 					return(dbl_fsqrt(&fpregs[r1],
180 						&fpregs[t],status));
181 				    case 2:
182 				    case 3: /* quad not implemented */
183 					return(MAJOR_0C_EXCP);
184 				}
185 			case 5: /* FRND */
186 				switch (fmt) {
187 				    case 0:
188 					return(sgl_frnd(&fpregs[r1],
189 						&fpregs[t],status));
190 				    case 1:
191 					return(dbl_frnd(&fpregs[r1],
192 						&fpregs[t],status));
193 				    case 2:
194 				    case 3: /* quad not implemented */
195 					return(MAJOR_0C_EXCP);
196 				}
197 		} /* end of switch (subop) */
198 
199 	case 1: /* class 1 */
200 		df = extru(ir,fpdfpos,2); /* get dest format */
201 		if ((df & 2) || (fmt & 2)) {
202 			/*
203 			 * fmt's 2 and 3 are illegal of not implemented
204 			 * quad conversions
205 			 */
206 			return(MAJOR_0C_EXCP);
207 		}
208 		/*
209 		 * encode source and dest formats into 2 bits.
210 		 * high bit is source, low bit is dest.
211 		 * bit = 1 --> double precision
212 		 */
213 		fmt = (fmt << 1) | df;
214 		switch (subop) {
215 			case 0: /* FCNVFF */
216 				switch(fmt) {
217 				    case 0: /* sgl/sgl */
218 					return(MAJOR_0C_EXCP);
219 				    case 1: /* sgl/dbl */
220 					return(sgl_to_dbl_fcnvff(&fpregs[r1],
221 						&fpregs[t],status));
222 				    case 2: /* dbl/sgl */
223 					return(dbl_to_sgl_fcnvff(&fpregs[r1],
224 						&fpregs[t],status));
225 				    case 3: /* dbl/dbl */
226 					return(MAJOR_0C_EXCP);
227 				}
228 			case 1: /* FCNVXF */
229 				switch(fmt) {
230 				    case 0: /* sgl/sgl */
231 					return(sgl_to_sgl_fcnvxf(&fpregs[r1],
232 						&fpregs[t],status));
233 				    case 1: /* sgl/dbl */
234 					return(sgl_to_dbl_fcnvxf(&fpregs[r1],
235 						&fpregs[t],status));
236 				    case 2: /* dbl/sgl */
237 					return(dbl_to_sgl_fcnvxf(&fpregs[r1],
238 						&fpregs[t],status));
239 				    case 3: /* dbl/dbl */
240 					return(dbl_to_dbl_fcnvxf(&fpregs[r1],
241 						&fpregs[t],status));
242 				}
243 			case 2: /* FCNVFX */
244 				switch(fmt) {
245 				    case 0: /* sgl/sgl */
246 					return(sgl_to_sgl_fcnvfx(&fpregs[r1],
247 						&fpregs[t],status));
248 				    case 1: /* sgl/dbl */
249 					return(sgl_to_dbl_fcnvfx(&fpregs[r1],
250 						&fpregs[t],status));
251 				    case 2: /* dbl/sgl */
252 					return(dbl_to_sgl_fcnvfx(&fpregs[r1],
253 						&fpregs[t],status));
254 				    case 3: /* dbl/dbl */
255 					return(dbl_to_dbl_fcnvfx(&fpregs[r1],
256 						&fpregs[t],status));
257 				}
258 			case 3: /* FCNVFXT */
259 				switch(fmt) {
260 				    case 0: /* sgl/sgl */
261 					return(sgl_to_sgl_fcnvfxt(&fpregs[r1],
262 						&fpregs[t],status));
263 				    case 1: /* sgl/dbl */
264 					return(sgl_to_dbl_fcnvfxt(&fpregs[r1],
265 						&fpregs[t],status));
266 				    case 2: /* dbl/sgl */
267 					return(dbl_to_sgl_fcnvfxt(&fpregs[r1],
268 						&fpregs[t],status));
269 				    case 3: /* dbl/dbl */
270 					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],
271 						&fpregs[t],status));
272 				}
273 		} /* end of switch subop */
274 
275 	case 2: /* class 2 */
276 		r2 = extru(ir, fpr2pos, 5) * sizeof(double)/sizeof(unsigned);
277 		if (r2 == 0)
278 			r2 = fpzeroreg;
279 		switch (subop) {
280 			case 2:
281 			case 3:
282 			case 4:
283 			case 5:
284 			case 6:
285 			case 7:
286 				return(MAJOR_0C_EXCP);
287 			case 0: /* FCMP */
288 				switch (fmt) {
289 				    case 0:
290 					return(sgl_fcmp(&fpregs[r1],&fpregs[r2],
291 						extru(ir,fptpos,5),status));
292 				    case 1:
293 					return(dbl_fcmp(&fpregs[r1],&fpregs[r2],
294 						extru(ir,fptpos,5),status));
295 				    case 2: /* illegal */
296 				    case 3: /* quad not implemented */
297 					return(MAJOR_0C_EXCP);
298 				}
299 			case 1: /* FTEST */
300 				switch (fmt) {
301 				    case 0:
302 					/*
303 					 * arg0 is not used
304 					 * second param is the t field used for
305 					 * ftest,acc and ftest,rej
306 					 */
307 					/* XXX fredette - broken */
308 #if 0
309 					return(ftest(0,extru(ir,fptpos,5),
310 						&fpregs[0]));
311 #else
312 					panic("ftest");
313 #endif
314 				    case 1:
315 				    case 2:
316 				    case 3:
317 					return(MAJOR_0C_EXCP);
318 				}
319 		} /* end if switch for class 2*/
320 	case 3: /* class 3 */
321 		r2 = extru(ir,fpr2pos,5) * sizeof(double)/sizeof(unsigned);
322 		if (r2 == 0)
323 			r2 = fpzeroreg;
324 		switch (subop) {
325 			case 5:
326 			case 6:
327 			case 7:
328 				return(MAJOR_0C_EXCP);
329 
330 			case 0: /* FADD */
331 				switch (fmt) {
332 				    case 0:
333 					return(sgl_fadd(&fpregs[r1],&fpregs[r2],
334 						&fpregs[t],status));
335 				    case 1:
336 					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
337 						&fpregs[t],status));
338 				    case 2: /* illegal */
339 				    case 3: /* quad not implemented */
340 					return(MAJOR_0C_EXCP);
341 				}
342 			case 1: /* FSUB */
343 				switch (fmt) {
344 				    case 0:
345 					return(sgl_fsub(&fpregs[r1],&fpregs[r2],
346 						&fpregs[t],status));
347 				    case 1:
348 					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
349 						&fpregs[t],status));
350 				    case 2: /* illegal */
351 				    case 3: /* quad not implemented */
352 					return(MAJOR_0C_EXCP);
353 				}
354 			case 2: /* FMPY */
355 				switch (fmt) {
356 				    case 0:
357 					return(sgl_fmpy(&fpregs[r1],&fpregs[r2],
358 						&fpregs[t],status));
359 				    case 1:
360 					return(dbl_fmpy(&fpregs[r1],&fpregs[r2],
361 						&fpregs[t],status));
362 				    case 2: /* illegal */
363 				    case 3: /* quad not implemented */
364 					return(MAJOR_0C_EXCP);
365 				}
366 			case 3: /* FDIV */
367 				switch (fmt) {
368 				    case 0:
369 					return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
370 						&fpregs[t],status));
371 				    case 1:
372 					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
373 						&fpregs[t],status));
374 				    case 2: /* illegal */
375 				    case 3: /* quad not implemented */
376 					return(MAJOR_0C_EXCP);
377 				}
378 			case 4: /* FREM */
379 				switch (fmt) {
380 				    case 0:
381 					return(sgl_frem(&fpregs[r1],&fpregs[r2],
382 						&fpregs[t],status));
383 				    case 1:
384 					return(dbl_frem(&fpregs[r1],&fpregs[r2],
385 						&fpregs[t],status));
386 				    case 2: /* illegal */
387 				    case 3: /* quad not implemented */
388 					return(MAJOR_0C_EXCP);
389 				}
390 		} /* end of class 3 switch */
391 	} /* end of switch(class) */
392 	panic("decode_0c");
393 }
394 
395 int
396 decode_0e(ir,class,subop,fpregs)
397 unsigned ir,class,subop;
398 unsigned fpregs[];
399 {
400 	unsigned r1,r2,t;	/* operand register offsets */
401 	unsigned fmt;		/* also sf for class 1 conversions */
402 	unsigned df;		/* dest format for class 1 conversions */
403 	unsigned *status;
404 
405 	status = &fpregs[0];
406 	r1 = ((extru(ir,fpr1pos,5)<<1)|(extru(ir,fpxr1pos,1)));
407 	if (r1 == 0)
408 		r1 = fpzeroreg;
409 	t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));
410 	if (t == 0 && class != 2)
411 		return(MAJOR_0E_EXCP);
412 	if (class < 2)		/* class 0 or 1 has 2 bit fmt */
413 		fmt = extru(ir,fpfmtpos,2);
414 	else			/* class 2 and 3 have 1 bit fmt */
415 		fmt = extru(ir,fp0efmtpos,1);
416 
417 	switch (class) {
418 	    case 0:
419 		switch (subop) {
420 			case 0: /* unimplemented */
421 			case 1:
422 			case 6:
423 			case 7:
424 				return(MAJOR_0E_EXCP);
425 			case 2: /* FCPY */
426 				switch (fmt) {
427 				    case 2:
428 				    case 3:
429 					return(MAJOR_0E_EXCP);
430 				    case 1: /* double */
431 					fpregs[t+1] = fpregs[r1+1];
432 				    case 0: /* single */
433 					fpregs[t] = fpregs[r1];
434 					return(NOEXCEPTION);
435 				}
436 			case 3: /* FABS */
437 				switch (fmt) {
438 				    case 2:
439 				    case 3:
440 					return(MAJOR_0E_EXCP);
441 				    case 1: /* double */
442 					fpregs[t+1] = fpregs[r1+1];
443 				    case 0: /* single */
444 					fpregs[t] = fpregs[r1] & 0x7fffffff;
445 					return(NOEXCEPTION);
446 				}
447 			case 4: /* FSQRT */
448 				switch (fmt) {
449 				    case 0:
450 					return(sgl_fsqrt(&fpregs[r1],
451 						&fpregs[t], status));
452 				    case 1:
453 					return(dbl_fsqrt(&fpregs[r1],
454 						&fpregs[t], status));
455 				    case 2:
456 				    case 3:
457 					return(MAJOR_0E_EXCP);
458 				}
459 			case 5: /* FRMD */
460 				switch (fmt) {
461 				    case 0:
462 					return(sgl_frnd(&fpregs[r1],
463 						&fpregs[t], status));
464 				    case 1:
465 					return(dbl_frnd(&fpregs[r1],
466 						&fpregs[t], status));
467 				    case 2:
468 				    case 3:
469 					return(MAJOR_0E_EXCP);
470 				}
471 		} /* end of switch (subop */
472 
473 	case 1: /* class 1 */
474 		df = extru(ir,fpdfpos,2); /* get dest format */
475 		if ((df & 2) || (fmt & 2))
476 			return(MAJOR_0E_EXCP);
477 
478 		fmt = (fmt << 1) | df;
479 		switch (subop) {
480 			case 0: /* FCNVFF */
481 				switch(fmt) {
482 				    case 0: /* sgl/sgl */
483 					return(MAJOR_0E_EXCP);
484 				    case 1: /* sgl/dbl */
485 					return(sgl_to_dbl_fcnvff(&fpregs[r1],
486 						&fpregs[t],status));
487 				    case 2: /* dbl/sgl */
488 					return(dbl_to_sgl_fcnvff(&fpregs[r1],
489 						&fpregs[t],status));
490 				    case 3: /* dbl/dbl */
491 					return(MAJOR_0E_EXCP);
492 				}
493 			case 1: /* FCNVXF */
494 				switch(fmt) {
495 				    case 0: /* sgl/sgl */
496 					return(sgl_to_sgl_fcnvxf(&fpregs[r1],
497 						&fpregs[t],status));
498 				    case 1: /* sgl/dbl */
499 					return(sgl_to_dbl_fcnvxf(&fpregs[r1],
500 						&fpregs[t],status));
501 				    case 2: /* dbl/sgl */
502 					return(dbl_to_sgl_fcnvxf(&fpregs[r1],
503 						&fpregs[t],status));
504 				    case 3: /* dbl/dbl */
505 					return(dbl_to_dbl_fcnvxf(&fpregs[r1],
506 						&fpregs[t],status));
507 				}
508 			case 2: /* FCNVFX */
509 				switch(fmt) {
510 				    case 0: /* sgl/sgl */
511 					return(sgl_to_sgl_fcnvfx(&fpregs[r1],
512 						&fpregs[t],status));
513 				    case 1: /* sgl/dbl */
514 					return(sgl_to_dbl_fcnvfx(&fpregs[r1],
515 						&fpregs[t],status));
516 				    case 2: /* dbl/sgl */
517 					return(dbl_to_sgl_fcnvfx(&fpregs[r1],
518 						&fpregs[t],status));
519 				    case 3: /* dbl/dbl */
520 					return(dbl_to_dbl_fcnvfx(&fpregs[r1],
521 						&fpregs[t],status));
522 				}
523 			case 3: /* FCNVFXT */
524 				switch(fmt) {
525 				    case 0: /* sgl/sgl */
526 					return(sgl_to_sgl_fcnvfxt(&fpregs[r1],
527 						&fpregs[t],status));
528 				    case 1: /* sgl/dbl */
529 					return(sgl_to_dbl_fcnvfxt(&fpregs[r1],
530 						&fpregs[t],status));
531 				    case 2: /* dbl/sgl */
532 					return(dbl_to_sgl_fcnvfxt(&fpregs[r1],
533 						&fpregs[t],status));
534 				    case 3: /* dbl/dbl */
535 					return(dbl_to_dbl_fcnvfxt(&fpregs[r1],
536 						&fpregs[t],status));
537 				}
538 		} /* end of switch subop */
539 	case 2: /* class 2 */
540 		r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
541 		if (r2 == 0)
542 			r2 = fpzeroreg;
543 		switch (subop) {
544 			case 1:
545 			case 2:
546 			case 3:
547 			case 4:
548 			case 5:
549 			case 6:
550 			case 7:
551 				return(MAJOR_0E_EXCP);
552 			case 0: /* FCMP */
553 				switch (fmt) {
554 				    /*
555 				     * fmt is only 1 bit long
556 				     */
557 				    case 0:
558 					return(sgl_fcmp(&fpregs[r1],&fpregs[r2],
559 						extru(ir,fptpos,5),status));
560 				    case 1:
561 					return(dbl_fcmp(&fpregs[r1],&fpregs[r2],
562 						extru(ir,fptpos,5),status));
563 				}
564 		} /* end of switch for class 2 */
565 	case 3: /* class 3 */
566 		r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
567 		if (r2 == 0)
568 			r2 = fpzeroreg;
569 		switch (subop) {
570 			case 5:
571 			case 6:
572 			case 7:
573 				return(MAJOR_0E_EXCP);
574 
575 			/*
576 			 * Note that fmt is only 1 bit for class 3 */
577 			case 0: /* FADD */
578 				switch (fmt) {
579 				    case 0:
580 					return(sgl_fadd(&fpregs[r1],&fpregs[r2],
581 						&fpregs[t],status));
582 				    case 1:
583 					return(dbl_fadd(&fpregs[r1],&fpregs[r2],
584 						&fpregs[t],status));
585 				}
586 			case 1: /* FSUB */
587 				switch (fmt) {
588 				    case 0:
589 					return(sgl_fsub(&fpregs[r1],&fpregs[r2],
590 						&fpregs[t],status));
591 				    case 1:
592 					return(dbl_fsub(&fpregs[r1],&fpregs[r2],
593 						&fpregs[t],status));
594 				}
595 			case 2: /* FMPY or XMPYU */
596 				/*
597 				 * check for integer multiply (x bit set)
598 				 */
599 				if (extru(ir,fpxpos,1)) {
600 				    /*
601 				     * emulate XMPYU
602 				     */
603 				    switch (fmt) {
604 					case 0:
605 					    /*
606 					     * bad instruction if t specifies
607 					     * the right half of a register
608 					     */
609 					    if (t & 1)
610 						return(MAJOR_0E_EXCP);
611 					    /* XXX fredette - broken. */
612 #if 0
613 					    impyu(&fpregs[r1],&fpregs[r2],
614 						&fpregs[t]);
615 					    return(NOEXCEPTION);
616 #else
617 					    panic("impyu");
618 #endif
619 					case 1:
620 						return(MAJOR_0E_EXCP);
621 				    }
622 				}
623 				else { /* FMPY */
624 				    switch (fmt) {
625 				        case 0:
626 					    return(sgl_fmpy(&fpregs[r1],
627 					       &fpregs[r2],&fpregs[t],status));
628 				        case 1:
629 					    return(dbl_fmpy(&fpregs[r1],
630 					       &fpregs[r2],&fpregs[t],status));
631 				    }
632 				}
633 			case 3: /* FDIV */
634 				switch (fmt) {
635 				    case 0:
636 					return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
637 						&fpregs[t],status));
638 				    case 1:
639 					return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
640 						&fpregs[t],status));
641 				}
642 			case 4: /* FREM */
643 				switch (fmt) {
644 				    case 0:
645 					return(sgl_frem(&fpregs[r1],&fpregs[r2],
646 						&fpregs[t],status));
647 				    case 1:
648 					return(dbl_frem(&fpregs[r1],&fpregs[r2],
649 						&fpregs[t],status));
650 				}
651 		} /* end of class 3 switch */
652 	} /* end of switch(class) */
653 	panic("decode_0e");
654 }
655 
656 
657 /*
658  * routine to decode the 06 (FMPYADD and FMPYCFXT) instruction
659  */
660 int
661 decode_06(ir,fpregs)
662 unsigned ir;
663 unsigned fpregs[];
664 {
665 	unsigned rm1, rm2, tm, ra, ta; /* operands */
666 	unsigned fmt;
667 	unsigned error = 0;
668 	unsigned status;
669 	union {
670 		double dbl;
671 		float flt;
672 		struct { unsigned i1; unsigned i2; } ints;
673 	} mtmp, atmp;
674 
675 
676 	status = fpregs[0];		/* use a local copy of status reg */
677 	fmt = extru(ir, fpmultifmt, 1);	/* get sgl/dbl flag */
678 	if (fmt == 0) { /* DBL */
679 		rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(unsigned);
680 		if (rm1 == 0)
681 			rm1 = fpzeroreg;
682 		rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(unsigned);
683 		if (rm2 == 0)
684 			rm2 = fpzeroreg;
685 		tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(unsigned);
686 		if (tm == 0)
687 			return(MAJOR_06_EXCP);
688 		ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(unsigned);
689 		ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(unsigned);
690 		if (ta == 0)
691 			return(MAJOR_06_EXCP);
692 
693 #ifdef TIMEX
694 		if (ra == 0) {
695 			 /* special case FMPYCFXT */
696 			if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
697 					&status))
698 				error = 1;
699 			if (dbl_to_sgl_fcnvfxt(&fpregs[ta],(unsigned *) &atmp,
700 				(unsigned *) &atmp,&status))
701 				error = 1;
702 		}
703 		else {
704 #else
705 		if (ra == 0)
706 			ra = fpzeroreg;
707 #endif
708 
709 			if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
710 					&status))
711 				error = 1;
712 			if (dbl_fadd(&fpregs[ta], &fpregs[ra], (unsigned *) &atmp,
713 					&status))
714 				error = 1;
715 #ifdef TIMEX
716 		}
717 #endif
718 		if (error)
719 			return(MAJOR_06_EXCP);
720 		else {
721 			/* copy results */
722 			fpregs[tm] = mtmp.ints.i1;
723 			fpregs[tm+1] = mtmp.ints.i2;
724 			fpregs[ta] = atmp.ints.i1;
725 			fpregs[ta+1] = atmp.ints.i2;
726 			fpregs[0] = status;
727 			return(NOEXCEPTION);
728 		}
729 	}
730 	else { /* SGL */
731 		/*
732 		 * calculate offsets for single precision numbers
733 		 * See table 6-14 in PA-89 architecture for mapping
734 		 */
735 		rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1;	/* get offset */
736 		rm1 |= extru(ir,fprm1pos-4,1);	/* add right word offset */
737 
738 		rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1;	/* get offset */
739 		rm2 |= extru(ir,fprm2pos-4,1);	/* add right word offset */
740 
741 		tm = (extru(ir,fptmpos,4) | 0x10 ) << 1;	/* get offset */
742 		tm |= extru(ir,fptmpos-4,1);	/* add right word offset */
743 
744 		ra = (extru(ir,fprapos,4) | 0x10 ) << 1;	/* get offset */
745 		ra |= extru(ir,fprapos-4,1);	/* add right word offset */
746 
747 		ta = (extru(ir,fptapos,4) | 0x10 ) << 1;	/* get offset */
748 		ta |= extru(ir,fptapos-4,1);	/* add right word offset */
749 
750 		if (ra == 0x20) { /* special case FMPYCFXT (really 0) */
751 			if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
752 					&status))
753 				error = 1;
754 			/* XXX fredette - this is broken */
755 #if 0
756 			if (sgl_to_sgl_fcnvfxt(&fpregs[ta],(unsigned *) &atmp,
757 				(unsigned *) &atmp,&status))
758 				error = 1;
759 #else
760 				panic("FMPYADD");
761 #endif
762 		}
763 		else {
764 			if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
765 					&status))
766 				error = 1;
767 			if (sgl_fadd(&fpregs[ta], &fpregs[ra], (unsigned *) &atmp,
768 					&status))
769 				error = 1;
770 		}
771 		if (error)
772 			return(MAJOR_06_EXCP);
773 		else {
774 			/* copy results */
775 			fpregs[tm] = mtmp.ints.i1;
776 			fpregs[ta] = atmp.ints.i1;
777 			fpregs[0] = status;
778 			return(NOEXCEPTION);
779 		}
780 	}
781 }
782 
783 /*
784  * routine to decode the 26 (FMPYSUB) instruction
785  */
786 int
787 decode_26(ir,fpregs)
788 unsigned ir;
789 unsigned fpregs[];
790 {
791 	unsigned rm1, rm2, tm, ra, ta; /* operands */
792 	unsigned fmt;
793 	unsigned error = 0;
794 	unsigned status;
795 	union {
796 		double dbl;
797 		float flt;
798 		struct { unsigned i1; unsigned i2; } ints;
799 	} mtmp, atmp;
800 
801 
802 	status = fpregs[0];
803 	fmt = extru(ir, fpmultifmt, 1);	/* get sgl/dbl flag */
804 	if (fmt == 0) { /* DBL */
805 		rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(unsigned);
806 		if (rm1 == 0)
807 			rm1 = fpzeroreg;
808 		rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(unsigned);
809 		if (rm2 == 0)
810 			rm2 = fpzeroreg;
811 		tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(unsigned);
812 		if (tm == 0)
813 			return(MAJOR_26_EXCP);
814 		ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(unsigned);
815 		if (ra == 0)
816 			return(MAJOR_26_EXCP);
817 		ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(unsigned);
818 		if (ta == 0)
819 			return(MAJOR_26_EXCP);
820 
821 		if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
822 				&status))
823 			error = 1;
824 		if (dbl_fsub(&fpregs[ta], &fpregs[ra], (unsigned *) &atmp,
825 				&status))
826 			error = 1;
827 		if (error)
828 			return(MAJOR_26_EXCP);
829 		else {
830 			/* copy results */
831 			fpregs[tm] = mtmp.ints.i1;
832 			fpregs[tm+1] = mtmp.ints.i2;
833 			fpregs[ta] = atmp.ints.i1;
834 			fpregs[ta+1] = atmp.ints.i2;
835 			fpregs[0] = status;
836 			return(NOEXCEPTION);
837 		}
838 	}
839 	else { /* SGL */
840 		/*
841 		 * calculate offsets for single precision numbers
842 		 * See table 6-14 in PA-89 architecture for mapping
843 		 */
844 		rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1;	/* get offset */
845 		rm1 |= extru(ir,fprm1pos-4,1);	/* add right word offset */
846 
847 		rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1;	/* get offset */
848 		rm2 |= extru(ir,fprm2pos-4,1);	/* add right word offset */
849 
850 		tm = (extru(ir,fptmpos,4) | 0x10 ) << 1;	/* get offset */
851 		tm |= extru(ir,fptmpos-4,1);	/* add right word offset */
852 
853 		ra = (extru(ir,fprapos,4) | 0x10 ) << 1;	/* get offset */
854 		ra |= extru(ir,fprapos-4,1);	/* add right word offset */
855 
856 		ta = (extru(ir,fptapos,4) | 0x10 ) << 1;	/* get offset */
857 		ta |= extru(ir,fptapos-4,1);	/* add right word offset */
858 
859 		if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],(unsigned *) &mtmp,
860 				&status))
861 			error = 1;
862 		if (sgl_fsub(&fpregs[ta], &fpregs[ra], (unsigned *) &atmp,
863 				&status))
864 			error = 1;
865 		if (error)
866 			return(MAJOR_26_EXCP);
867 		else {
868 			/* copy results */
869 			fpregs[tm] = mtmp.ints.i1;
870 			fpregs[ta] = atmp.ints.i1;
871 			fpregs[0] = status;
872 			return(NOEXCEPTION);
873 		}
874 	}
875 
876 }
877