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