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