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