Home | History | Annotate | Line # | Download | only in spmath
fpudispatch.c revision 1.2
      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