1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Linux/PA-RISC Project (http://www.parisc-linux.org/) 4 * 5 * Floating-point emulation code 6 * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> 7 */ 8 /* 9 * BEGIN_DESC 10 * 11 * File: 12 * @(#) pa/fp/fpudispatch.c $Revision: 1.1 $ 13 * 14 * Purpose: 15 * <<please update with a synopsis of the functionality provided by this file>> 16 * 17 * External Interfaces: 18 * <<the following list was autogenerated, please review>> 19 * emfpudispatch(ir, dummy1, dummy2, fpregs) 20 * fpudispatch(ir, excp_code, holder, fpregs) 21 * 22 * Internal Interfaces: 23 * <<the following list was autogenerated, please review>> 24 * static u_int decode_06(u_int, u_int *) 25 * static u_int decode_0c(u_int, u_int, u_int, u_int *) 26 * static u_int decode_0e(u_int, u_int, u_int, u_int *) 27 * static u_int decode_26(u_int, u_int *) 28 * static u_int decode_2e(u_int, u_int *) 29 * static void update_status_cbit(u_int *, u_int, u_int, u_int) 30 * 31 * Theory: 32 * <<please update with a overview of the operation of this file>> 33 * 34 * END_DESC 35 */ 36 37 #define FPUDEBUG 0 38 39 #include "float.h" 40 #include <linux/bug.h> 41 #include <linux/kernel.h> 42 #include <asm/processor.h> 43 /* #include <sys/debug.h> */ 44 /* #include <machine/sys/mdep_private.h> */ 45 46 #define COPR_INST 0x30000000 47 48 /* 49 * definition of extru macro. If pos and len are constants, the compiler 50 * will generate an extru instruction when optimized 51 */ 52 #define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1)) 53 /* definitions of bit field locations in the instruction */ 54 #define fpmajorpos 5 55 #define fpr1pos 10 56 #define fpr2pos 15 57 #define fptpos 31 58 #define fpsubpos 18 59 #define fpclass1subpos 16 60 #define fpclasspos 22 61 #define fpfmtpos 20 62 #define fpdfpos 18 63 #define fpnulpos 26 64 /* 65 * the following are the extra bits for the 0E major op 66 */ 67 #define fpxr1pos 24 68 #define fpxr2pos 19 69 #define fpxtpos 25 70 #define fpxpos 23 71 #define fp0efmtpos 20 72 /* 73 * the following are for the multi-ops 74 */ 75 #define fprm1pos 10 76 #define fprm2pos 15 77 #define fptmpos 31 78 #define fprapos 25 79 #define fptapos 20 80 #define fpmultifmt 26 81 /* 82 * the following are for the fused FP instructions 83 */ 84 /* fprm1pos 10 */ 85 /* fprm2pos 15 */ 86 #define fpraupos 18 87 #define fpxrm2pos 19 88 /* fpfmtpos 20 */ 89 #define fpralpos 23 90 #define fpxrm1pos 24 91 /* fpxtpos 25 */ 92 #define fpfusedsubop 26 93 /* fptpos 31 */ 94 95 /* 96 * offset to constant zero in the FP emulation registers 97 */ 98 #define fpzeroreg (32*sizeof(double)/sizeof(u_int)) 99 100 /* 101 * extract the major opcode from the instruction 102 */ 103 #define get_major(op) extru(op,fpmajorpos,6) 104 /* 105 * extract the two bit class field from the FP instruction. The class is at bit 106 * positions 21-22 107 */ 108 #define get_class(op) extru(op,fpclasspos,2) 109 /* 110 * extract the 3 bit subop field. For all but class 1 instructions, it is 111 * located at bit positions 16-18 112 */ 113 #define get_subop(op) extru(op,fpsubpos,3) 114 /* 115 * extract the 2 or 3 bit subop field from class 1 instructions. It is located 116 * at bit positions 15-16 (PA1.1) or 14-16 (PA2.0) 117 */ 118 #define get_subop1_PA1_1(op) extru(op,fpclass1subpos,2) /* PA89 (1.1) fmt */ 119 #define get_subop1_PA2_0(op) extru(op,fpclass1subpos,3) /* PA 2.0 fmt */ 120 121 /* definitions of unimplemented exceptions */ 122 #define MAJOR_0C_EXCP 0x09 123 #define MAJOR_0E_EXCP 0x0b 124 #define MAJOR_06_EXCP 0x03 125 #define MAJOR_26_EXCP 0x23 126 #define MAJOR_2E_EXCP 0x2b 127 #define PA83_UNIMP_EXCP 0x01 128 129 /* 130 * Special Defines for TIMEX specific code 131 */ 132 133 #define FPU_TYPE_FLAG_POS (EM_FPU_TYPE_OFFSET>>2) 134 #define TIMEX_ROLEX_FPU_MASK (TIMEX_EXTEN_FLAG|ROLEX_EXTEN_FLAG) 135 136 /* 137 * Static function definitions 138 */ 139 #define _PROTOTYPES 140 #if defined(_PROTOTYPES) || defined(_lint) 141 static u_int decode_0c(u_int, u_int, u_int, u_int *); 142 static u_int decode_0e(u_int, u_int, u_int, u_int *); 143 static u_int decode_06(u_int, u_int *); 144 static u_int decode_26(u_int, u_int *); 145 static u_int decode_2e(u_int, u_int *); 146 static void update_status_cbit(u_int *, u_int, u_int, u_int); 147 #else /* !_PROTOTYPES&&!_lint */ 148 static u_int decode_0c(); 149 static u_int decode_0e(); 150 static u_int decode_06(); 151 static u_int decode_26(); 152 static u_int decode_2e(); 153 static void update_status_cbit(); 154 #endif /* _PROTOTYPES&&!_lint */ 155 156 #define VASSERT(x) 157 158 static void parisc_linux_get_fpu_type(u_int fpregs[]) 159 { 160 /* on pa-linux the fpu type is not filled in by the 161 * caller; it is constructed here 162 */ 163 if (boot_cpu_data.cpu_type == pcxs) 164 fpregs[FPU_TYPE_FLAG_POS] = TIMEX_EXTEN_FLAG; 165 else if (boot_cpu_data.cpu_type == pcxt || 166 boot_cpu_data.cpu_type == pcxt_) 167 fpregs[FPU_TYPE_FLAG_POS] = ROLEX_EXTEN_FLAG; 168 else if (boot_cpu_data.cpu_type >= pcxu) 169 fpregs[FPU_TYPE_FLAG_POS] = PA2_0_FPU_FLAG; 170 } 171 172 /* 173 * this routine will decode the excepting floating point instruction and 174 * call the appropriate emulation routine. 175 * It is called by decode_fpu with the following parameters: 176 * fpudispatch(current_ir, unimplemented_code, 0, &Fpu_register) 177 * where current_ir is the instruction to be emulated, 178 * unimplemented_code is the exception_code that the hardware generated 179 * and &Fpu_register is the address of emulated FP reg 0. 180 */ 181 u_int 182 fpudispatch(u_int ir, u_int excp_code, u_int holder, u_int fpregs[]) 183 { 184 u_int class, subop; 185 u_int fpu_type_flags; 186 187 /* All FP emulation code assumes that ints are 4-bytes in length */ 188 VASSERT(sizeof(int) == 4); 189 190 parisc_linux_get_fpu_type(fpregs); 191 192 fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */ 193 194 class = get_class(ir); 195 if (class == 1) { 196 if (fpu_type_flags & PA2_0_FPU_FLAG) 197 subop = get_subop1_PA2_0(ir); 198 else 199 subop = get_subop1_PA1_1(ir); 200 } 201 else 202 subop = get_subop(ir); 203 204 if (FPUDEBUG) printk("class %d subop %d\n", class, subop); 205 206 switch (excp_code) { 207 case MAJOR_0C_EXCP: 208 case PA83_UNIMP_EXCP: 209 return(decode_0c(ir,class,subop,fpregs)); 210 case MAJOR_0E_EXCP: 211 return(decode_0e(ir,class,subop,fpregs)); 212 case MAJOR_06_EXCP: 213 return(decode_06(ir,fpregs)); 214 case MAJOR_26_EXCP: 215 return(decode_26(ir,fpregs)); 216 case MAJOR_2E_EXCP: 217 return(decode_2e(ir,fpregs)); 218 default: 219 /* "crashme Night Gallery painting nr 2. (asm_crash.s). 220 * This was fixed for multi-user kernels, but 221 * workstation kernels had a panic here. This allowed 222 * any arbitrary user to panic the kernel by executing 223 * setting the FP exception registers to strange values 224 * and generating an emulation trap. The emulation and 225 * exception code must never be able to panic the 226 * kernel. 227 */ 228 return(UNIMPLEMENTEDEXCEPTION); 229 } 230 } 231 232 /* 233 * this routine is called by $emulation_trap to emulate a coprocessor 234 * instruction if one doesn't exist 235 */ 236 u_int 237 emfpudispatch(u_int ir, u_int dummy1, u_int dummy2, u_int fpregs[]) 238 { 239 u_int class, subop, major; 240 u_int fpu_type_flags; 241 242 /* All FP emulation code assumes that ints are 4-bytes in length */ 243 VASSERT(sizeof(int) == 4); 244 245 fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */ 246 247 major = get_major(ir); 248 class = get_class(ir); 249 if (class == 1) { 250 if (fpu_type_flags & PA2_0_FPU_FLAG) 251 subop = get_subop1_PA2_0(ir); 252 else 253 subop = get_subop1_PA1_1(ir); 254 } 255 else 256 subop = get_subop(ir); 257 switch (major) { 258 case 0x0C: 259 return(decode_0c(ir,class,subop,fpregs)); 260 case 0x0E: 261 return(decode_0e(ir,class,subop,fpregs)); 262 case 0x06: 263 return(decode_06(ir,fpregs)); 264 case 0x26: 265 return(decode_26(ir,fpregs)); 266 case 0x2E: 267 return(decode_2e(ir,fpregs)); 268 default: 269 return(PA83_UNIMP_EXCP); 270 } 271 } 272 273 274 static u_int 275 decode_0c(u_int ir, u_int class, u_int subop, u_int fpregs[]) 276 { 277 u_int r1,r2,t; /* operand register offsets */ 278 u_int fmt; /* also sf for class 1 conversions */ 279 u_int df; /* for class 1 conversions */ 280 u_int *status; 281 u_int retval, local_status; 282 u_int fpu_type_flags; 283 284 if (ir == COPR_INST) { 285 fpregs[0] = EMULATION_VERSION << 11; 286 return(NOEXCEPTION); 287 } 288 status = &fpregs[0]; /* fp status register */ 289 local_status = fpregs[0]; /* and local copy */ 290 r1 = extru(ir,fpr1pos,5) * sizeof(double)/sizeof(u_int); 291 if (r1 == 0) /* map fr0 source to constant zero */ 292 r1 = fpzeroreg; 293 t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int); 294 if (t == 0 && class != 2) /* don't allow fr0 as a dest */ 295 return(MAJOR_0C_EXCP); 296 fmt = extru(ir,fpfmtpos,2); /* get fmt completer */ 297 298 switch (class) { 299 case 0: 300 switch (subop) { 301 case 0: /* COPR 0,0 emulated above*/ 302 case 1: 303 return(MAJOR_0C_EXCP); 304 case 2: /* FCPY */ 305 switch (fmt) { 306 case 2: /* illegal */ 307 return(MAJOR_0C_EXCP); 308 case 3: /* quad */ 309 t &= ~3; /* force to even reg #s */ 310 r1 &= ~3; 311 fpregs[t+3] = fpregs[r1+3]; 312 fpregs[t+2] = fpregs[r1+2]; 313 fallthrough; 314 case 1: /* double */ 315 fpregs[t+1] = fpregs[r1+1]; 316 fallthrough; 317 case 0: /* single */ 318 fpregs[t] = fpregs[r1]; 319 return(NOEXCEPTION); 320 } 321 BUG(); 322 case 3: /* FABS */ 323 switch (fmt) { 324 case 2: /* illegal */ 325 return(MAJOR_0C_EXCP); 326 case 3: /* quad */ 327 t &= ~3; /* force to even reg #s */ 328 r1 &= ~3; 329 fpregs[t+3] = fpregs[r1+3]; 330 fpregs[t+2] = fpregs[r1+2]; 331 fallthrough; 332 case 1: /* double */ 333 fpregs[t+1] = fpregs[r1+1]; 334 fallthrough; 335 case 0: /* single */ 336 /* copy and clear sign bit */ 337 fpregs[t] = fpregs[r1] & 0x7fffffff; 338 return(NOEXCEPTION); 339 } 340 BUG(); 341 case 6: /* FNEG */ 342 switch (fmt) { 343 case 2: /* illegal */ 344 return(MAJOR_0C_EXCP); 345 case 3: /* quad */ 346 t &= ~3; /* force to even reg #s */ 347 r1 &= ~3; 348 fpregs[t+3] = fpregs[r1+3]; 349 fpregs[t+2] = fpregs[r1+2]; 350 fallthrough; 351 case 1: /* double */ 352 fpregs[t+1] = fpregs[r1+1]; 353 fallthrough; 354 case 0: /* single */ 355 /* copy and invert sign bit */ 356 fpregs[t] = fpregs[r1] ^ 0x80000000; 357 return(NOEXCEPTION); 358 } 359 BUG(); 360 case 7: /* FNEGABS */ 361 switch (fmt) { 362 case 2: /* illegal */ 363 return(MAJOR_0C_EXCP); 364 case 3: /* quad */ 365 t &= ~3; /* force to even reg #s */ 366 r1 &= ~3; 367 fpregs[t+3] = fpregs[r1+3]; 368 fpregs[t+2] = fpregs[r1+2]; 369 fallthrough; 370 case 1: /* double */ 371 fpregs[t+1] = fpregs[r1+1]; 372 fallthrough; 373 case 0: /* single */ 374 /* copy and set sign bit */ 375 fpregs[t] = fpregs[r1] | 0x80000000; 376 return(NOEXCEPTION); 377 } 378 BUG(); 379 case 4: /* FSQRT */ 380 switch (fmt) { 381 case 0: 382 return(sgl_fsqrt(&fpregs[r1],0, 383 &fpregs[t],status)); 384 case 1: 385 return(dbl_fsqrt(&fpregs[r1],0, 386 &fpregs[t],status)); 387 case 2: 388 case 3: /* quad not implemented */ 389 return(MAJOR_0C_EXCP); 390 } 391 BUG(); 392 case 5: /* FRND */ 393 switch (fmt) { 394 case 0: 395 return(sgl_frnd(&fpregs[r1],0, 396 &fpregs[t],status)); 397 case 1: 398 return(dbl_frnd(&fpregs[r1],0, 399 &fpregs[t],status)); 400 case 2: 401 case 3: /* quad not implemented */ 402 return(MAJOR_0C_EXCP); 403 } 404 } /* end of switch (subop) */ 405 BUG(); 406 case 1: /* class 1 */ 407 df = extru(ir,fpdfpos,2); /* get dest format */ 408 if ((df & 2) || (fmt & 2)) { 409 /* 410 * fmt's 2 and 3 are illegal of not implemented 411 * quad conversions 412 */ 413 return(MAJOR_0C_EXCP); 414 } 415 /* 416 * encode source and dest formats into 2 bits. 417 * high bit is source, low bit is dest. 418 * bit = 1 --> double precision 419 */ 420 fmt = (fmt << 1) | df; 421 switch (subop) { 422 case 0: /* FCNVFF */ 423 switch(fmt) { 424 case 0: /* sgl/sgl */ 425 return(MAJOR_0C_EXCP); 426 case 1: /* sgl/dbl */ 427 return(sgl_to_dbl_fcnvff(&fpregs[r1],0, 428 &fpregs[t],status)); 429 case 2: /* dbl/sgl */ 430 return(dbl_to_sgl_fcnvff(&fpregs[r1],0, 431 &fpregs[t],status)); 432 case 3: /* dbl/dbl */ 433 return(MAJOR_0C_EXCP); 434 } 435 BUG(); 436 case 1: /* FCNVXF */ 437 switch(fmt) { 438 case 0: /* sgl/sgl */ 439 return(sgl_to_sgl_fcnvxf(&fpregs[r1],0, 440 &fpregs[t],status)); 441 case 1: /* sgl/dbl */ 442 return(sgl_to_dbl_fcnvxf(&fpregs[r1],0, 443 &fpregs[t],status)); 444 case 2: /* dbl/sgl */ 445 return(dbl_to_sgl_fcnvxf(&fpregs[r1],0, 446 &fpregs[t],status)); 447 case 3: /* dbl/dbl */ 448 return(dbl_to_dbl_fcnvxf(&fpregs[r1],0, 449 &fpregs[t],status)); 450 } 451 BUG(); 452 case 2: /* FCNVFX */ 453 switch(fmt) { 454 case 0: /* sgl/sgl */ 455 return(sgl_to_sgl_fcnvfx(&fpregs[r1],0, 456 &fpregs[t],status)); 457 case 1: /* sgl/dbl */ 458 return(sgl_to_dbl_fcnvfx(&fpregs[r1],0, 459 &fpregs[t],status)); 460 case 2: /* dbl/sgl */ 461 return(dbl_to_sgl_fcnvfx(&fpregs[r1],0, 462 &fpregs[t],status)); 463 case 3: /* dbl/dbl */ 464 return(dbl_to_dbl_fcnvfx(&fpregs[r1],0, 465 &fpregs[t],status)); 466 } 467 BUG(); 468 case 3: /* FCNVFXT */ 469 switch(fmt) { 470 case 0: /* sgl/sgl */ 471 return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0, 472 &fpregs[t],status)); 473 case 1: /* sgl/dbl */ 474 return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0, 475 &fpregs[t],status)); 476 case 2: /* dbl/sgl */ 477 return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0, 478 &fpregs[t],status)); 479 case 3: /* dbl/dbl */ 480 return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0, 481 &fpregs[t],status)); 482 } 483 BUG(); 484 case 5: /* FCNVUF (PA2.0 only) */ 485 switch(fmt) { 486 case 0: /* sgl/sgl */ 487 return(sgl_to_sgl_fcnvuf(&fpregs[r1],0, 488 &fpregs[t],status)); 489 case 1: /* sgl/dbl */ 490 return(sgl_to_dbl_fcnvuf(&fpregs[r1],0, 491 &fpregs[t],status)); 492 case 2: /* dbl/sgl */ 493 return(dbl_to_sgl_fcnvuf(&fpregs[r1],0, 494 &fpregs[t],status)); 495 case 3: /* dbl/dbl */ 496 return(dbl_to_dbl_fcnvuf(&fpregs[r1],0, 497 &fpregs[t],status)); 498 } 499 BUG(); 500 case 6: /* FCNVFU (PA2.0 only) */ 501 switch(fmt) { 502 case 0: /* sgl/sgl */ 503 return(sgl_to_sgl_fcnvfu(&fpregs[r1],0, 504 &fpregs[t],status)); 505 case 1: /* sgl/dbl */ 506 return(sgl_to_dbl_fcnvfu(&fpregs[r1],0, 507 &fpregs[t],status)); 508 case 2: /* dbl/sgl */ 509 return(dbl_to_sgl_fcnvfu(&fpregs[r1],0, 510 &fpregs[t],status)); 511 case 3: /* dbl/dbl */ 512 return(dbl_to_dbl_fcnvfu(&fpregs[r1],0, 513 &fpregs[t],status)); 514 } 515 BUG(); 516 case 7: /* FCNVFUT (PA2.0 only) */ 517 switch(fmt) { 518 case 0: /* sgl/sgl */ 519 return(sgl_to_sgl_fcnvfut(&fpregs[r1],0, 520 &fpregs[t],status)); 521 case 1: /* sgl/dbl */ 522 return(sgl_to_dbl_fcnvfut(&fpregs[r1],0, 523 &fpregs[t],status)); 524 case 2: /* dbl/sgl */ 525 return(dbl_to_sgl_fcnvfut(&fpregs[r1],0, 526 &fpregs[t],status)); 527 case 3: /* dbl/dbl */ 528 return(dbl_to_dbl_fcnvfut(&fpregs[r1],0, 529 &fpregs[t],status)); 530 } 531 BUG(); 532 case 4: /* undefined */ 533 return(MAJOR_0C_EXCP); 534 } /* end of switch subop */ 535 BUG(); 536 case 2: /* class 2 */ 537 fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; 538 r2 = extru(ir, fpr2pos, 5) * sizeof(double)/sizeof(u_int); 539 if (r2 == 0) 540 r2 = fpzeroreg; 541 if (fpu_type_flags & PA2_0_FPU_FLAG) { 542 /* FTEST if nullify bit set, otherwise FCMP */ 543 if (extru(ir, fpnulpos, 1)) { /* FTEST */ 544 switch (fmt) { 545 case 0: 546 /* 547 * arg0 is not used 548 * second param is the t field used for 549 * ftest,acc and ftest,rej 550 * third param is the subop (y-field) 551 */ 552 BUG(); 553 /* Unsupported 554 * return(ftest(0L,extru(ir,fptpos,5), 555 * &fpregs[0],subop)); 556 */ 557 case 1: 558 case 2: 559 case 3: 560 return(MAJOR_0C_EXCP); 561 } 562 } else { /* FCMP */ 563 switch (fmt) { 564 case 0: 565 retval = sgl_fcmp(&fpregs[r1], 566 &fpregs[r2],extru(ir,fptpos,5), 567 &local_status); 568 update_status_cbit(status,local_status, 569 fpu_type_flags, subop); 570 return(retval); 571 case 1: 572 retval = dbl_fcmp(&fpregs[r1], 573 &fpregs[r2],extru(ir,fptpos,5), 574 &local_status); 575 update_status_cbit(status,local_status, 576 fpu_type_flags, subop); 577 return(retval); 578 case 2: /* illegal */ 579 case 3: /* quad not implemented */ 580 return(MAJOR_0C_EXCP); 581 } 582 } 583 } /* end of if for PA2.0 */ 584 else { /* PA1.0 & PA1.1 */ 585 switch (subop) { 586 case 2: 587 case 3: 588 case 4: 589 case 5: 590 case 6: 591 case 7: 592 return(MAJOR_0C_EXCP); 593 case 0: /* FCMP */ 594 switch (fmt) { 595 case 0: 596 retval = sgl_fcmp(&fpregs[r1], 597 &fpregs[r2],extru(ir,fptpos,5), 598 &local_status); 599 update_status_cbit(status,local_status, 600 fpu_type_flags, subop); 601 return(retval); 602 case 1: 603 retval = dbl_fcmp(&fpregs[r1], 604 &fpregs[r2],extru(ir,fptpos,5), 605 &local_status); 606 update_status_cbit(status,local_status, 607 fpu_type_flags, subop); 608 return(retval); 609 case 2: /* illegal */ 610 case 3: /* quad not implemented */ 611 return(MAJOR_0C_EXCP); 612 } 613 BUG(); 614 case 1: /* FTEST */ 615 switch (fmt) { 616 case 0: 617 /* 618 * arg0 is not used 619 * second param is the t field used for 620 * ftest,acc and ftest,rej 621 * third param is the subop (y-field) 622 */ 623 BUG(); 624 /* unsupported 625 * return(ftest(0L,extru(ir,fptpos,5), 626 * &fpregs[0],subop)); 627 */ 628 case 1: 629 case 2: 630 case 3: 631 return(MAJOR_0C_EXCP); 632 } 633 BUG(); 634 } /* end of switch subop */ 635 } /* end of else for PA1.0 & PA1.1 */ 636 BUG(); 637 case 3: /* class 3 */ 638 r2 = extru(ir,fpr2pos,5) * sizeof(double)/sizeof(u_int); 639 if (r2 == 0) 640 r2 = fpzeroreg; 641 switch (subop) { 642 case 5: 643 case 6: 644 case 7: 645 return(MAJOR_0C_EXCP); 646 647 case 0: /* FADD */ 648 switch (fmt) { 649 case 0: 650 return(sgl_fadd(&fpregs[r1],&fpregs[r2], 651 &fpregs[t],status)); 652 case 1: 653 return(dbl_fadd(&fpregs[r1],&fpregs[r2], 654 &fpregs[t],status)); 655 case 2: /* illegal */ 656 case 3: /* quad not implemented */ 657 return(MAJOR_0C_EXCP); 658 } 659 BUG(); 660 case 1: /* FSUB */ 661 switch (fmt) { 662 case 0: 663 return(sgl_fsub(&fpregs[r1],&fpregs[r2], 664 &fpregs[t],status)); 665 case 1: 666 return(dbl_fsub(&fpregs[r1],&fpregs[r2], 667 &fpregs[t],status)); 668 case 2: /* illegal */ 669 case 3: /* quad not implemented */ 670 return(MAJOR_0C_EXCP); 671 } 672 BUG(); 673 case 2: /* FMPY */ 674 switch (fmt) { 675 case 0: 676 return(sgl_fmpy(&fpregs[r1],&fpregs[r2], 677 &fpregs[t],status)); 678 case 1: 679 return(dbl_fmpy(&fpregs[r1],&fpregs[r2], 680 &fpregs[t],status)); 681 case 2: /* illegal */ 682 case 3: /* quad not implemented */ 683 return(MAJOR_0C_EXCP); 684 } 685 BUG(); 686 case 3: /* FDIV */ 687 switch (fmt) { 688 case 0: 689 return(sgl_fdiv(&fpregs[r1],&fpregs[r2], 690 &fpregs[t],status)); 691 case 1: 692 return(dbl_fdiv(&fpregs[r1],&fpregs[r2], 693 &fpregs[t],status)); 694 case 2: /* illegal */ 695 case 3: /* quad not implemented */ 696 return(MAJOR_0C_EXCP); 697 } 698 BUG(); 699 case 4: /* FREM */ 700 switch (fmt) { 701 case 0: 702 return(sgl_frem(&fpregs[r1],&fpregs[r2], 703 &fpregs[t],status)); 704 case 1: 705 return(dbl_frem(&fpregs[r1],&fpregs[r2], 706 &fpregs[t],status)); 707 case 2: /* illegal */ 708 case 3: /* quad not implemented */ 709 return(MAJOR_0C_EXCP); 710 } 711 BUG(); 712 } /* end of class 3 switch */ 713 } /* end of switch(class) */ 714 715 /* If we get here, something is really wrong! */ 716 return(MAJOR_0C_EXCP); 717 } 718 719 static u_int 720 decode_0e(ir,class,subop,fpregs) 721 u_int ir,class,subop; 722 u_int fpregs[]; 723 { 724 u_int r1,r2,t; /* operand register offsets */ 725 u_int fmt; /* also sf for class 1 conversions */ 726 u_int df; /* dest format for class 1 conversions */ 727 u_int *status; 728 u_int retval, local_status; 729 u_int fpu_type_flags; 730 731 status = &fpregs[0]; 732 local_status = fpregs[0]; 733 r1 = ((extru(ir,fpr1pos,5)<<1)|(extru(ir,fpxr1pos,1))); 734 if (r1 == 0) 735 r1 = fpzeroreg; 736 t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1))); 737 if (t == 0 && class != 2) 738 return(MAJOR_0E_EXCP); 739 if (class < 2) /* class 0 or 1 has 2 bit fmt */ 740 fmt = extru(ir,fpfmtpos,2); 741 else /* class 2 and 3 have 1 bit fmt */ 742 fmt = extru(ir,fp0efmtpos,1); 743 /* 744 * An undefined combination, double precision accessing the 745 * right half of a FPR, can get us into trouble. 746 * Let's just force proper alignment on it. 747 */ 748 if (fmt == DBL) { 749 r1 &= ~1; 750 if (class != 1) 751 t &= ~1; 752 } 753 754 switch (class) { 755 case 0: 756 switch (subop) { 757 case 0: /* unimplemented */ 758 case 1: 759 return(MAJOR_0E_EXCP); 760 case 2: /* FCPY */ 761 switch (fmt) { 762 case 2: 763 case 3: 764 return(MAJOR_0E_EXCP); 765 case 1: /* double */ 766 fpregs[t+1] = fpregs[r1+1]; 767 fallthrough; 768 case 0: /* single */ 769 fpregs[t] = fpregs[r1]; 770 return(NOEXCEPTION); 771 } 772 BUG(); 773 case 3: /* FABS */ 774 switch (fmt) { 775 case 2: 776 case 3: 777 return(MAJOR_0E_EXCP); 778 case 1: /* double */ 779 fpregs[t+1] = fpregs[r1+1]; 780 fallthrough; 781 case 0: /* single */ 782 fpregs[t] = fpregs[r1] & 0x7fffffff; 783 return(NOEXCEPTION); 784 } 785 BUG(); 786 case 6: /* FNEG */ 787 switch (fmt) { 788 case 2: 789 case 3: 790 return(MAJOR_0E_EXCP); 791 case 1: /* double */ 792 fpregs[t+1] = fpregs[r1+1]; 793 fallthrough; 794 case 0: /* single */ 795 fpregs[t] = fpregs[r1] ^ 0x80000000; 796 return(NOEXCEPTION); 797 } 798 BUG(); 799 case 7: /* FNEGABS */ 800 switch (fmt) { 801 case 2: 802 case 3: 803 return(MAJOR_0E_EXCP); 804 case 1: /* double */ 805 fpregs[t+1] = fpregs[r1+1]; 806 fallthrough; 807 case 0: /* single */ 808 fpregs[t] = fpregs[r1] | 0x80000000; 809 return(NOEXCEPTION); 810 } 811 BUG(); 812 case 4: /* FSQRT */ 813 switch (fmt) { 814 case 0: 815 return(sgl_fsqrt(&fpregs[r1],0, 816 &fpregs[t], status)); 817 case 1: 818 return(dbl_fsqrt(&fpregs[r1],0, 819 &fpregs[t], status)); 820 case 2: 821 case 3: 822 return(MAJOR_0E_EXCP); 823 } 824 BUG(); 825 case 5: /* FRMD */ 826 switch (fmt) { 827 case 0: 828 return(sgl_frnd(&fpregs[r1],0, 829 &fpregs[t], status)); 830 case 1: 831 return(dbl_frnd(&fpregs[r1],0, 832 &fpregs[t], status)); 833 case 2: 834 case 3: 835 return(MAJOR_0E_EXCP); 836 } 837 } /* end of switch (subop */ 838 BUG(); 839 case 1: /* class 1 */ 840 df = extru(ir,fpdfpos,2); /* get dest format */ 841 /* 842 * Fix Crashme problem (writing to 31R in double precision) 843 * here too. 844 */ 845 if (df == DBL) { 846 t &= ~1; 847 } 848 if ((df & 2) || (fmt & 2)) 849 return(MAJOR_0E_EXCP); 850 851 fmt = (fmt << 1) | df; 852 switch (subop) { 853 case 0: /* FCNVFF */ 854 switch(fmt) { 855 case 0: /* sgl/sgl */ 856 return(MAJOR_0E_EXCP); 857 case 1: /* sgl/dbl */ 858 return(sgl_to_dbl_fcnvff(&fpregs[r1],0, 859 &fpregs[t],status)); 860 case 2: /* dbl/sgl */ 861 return(dbl_to_sgl_fcnvff(&fpregs[r1],0, 862 &fpregs[t],status)); 863 case 3: /* dbl/dbl */ 864 return(MAJOR_0E_EXCP); 865 } 866 BUG(); 867 case 1: /* FCNVXF */ 868 switch(fmt) { 869 case 0: /* sgl/sgl */ 870 return(sgl_to_sgl_fcnvxf(&fpregs[r1],0, 871 &fpregs[t],status)); 872 case 1: /* sgl/dbl */ 873 return(sgl_to_dbl_fcnvxf(&fpregs[r1],0, 874 &fpregs[t],status)); 875 case 2: /* dbl/sgl */ 876 return(dbl_to_sgl_fcnvxf(&fpregs[r1],0, 877 &fpregs[t],status)); 878 case 3: /* dbl/dbl */ 879 return(dbl_to_dbl_fcnvxf(&fpregs[r1],0, 880 &fpregs[t],status)); 881 } 882 BUG(); 883 case 2: /* FCNVFX */ 884 switch(fmt) { 885 case 0: /* sgl/sgl */ 886 return(sgl_to_sgl_fcnvfx(&fpregs[r1],0, 887 &fpregs[t],status)); 888 case 1: /* sgl/dbl */ 889 return(sgl_to_dbl_fcnvfx(&fpregs[r1],0, 890 &fpregs[t],status)); 891 case 2: /* dbl/sgl */ 892 return(dbl_to_sgl_fcnvfx(&fpregs[r1],0, 893 &fpregs[t],status)); 894 case 3: /* dbl/dbl */ 895 return(dbl_to_dbl_fcnvfx(&fpregs[r1],0, 896 &fpregs[t],status)); 897 } 898 BUG(); 899 case 3: /* FCNVFXT */ 900 switch(fmt) { 901 case 0: /* sgl/sgl */ 902 return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0, 903 &fpregs[t],status)); 904 case 1: /* sgl/dbl */ 905 return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0, 906 &fpregs[t],status)); 907 case 2: /* dbl/sgl */ 908 return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0, 909 &fpregs[t],status)); 910 case 3: /* dbl/dbl */ 911 return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0, 912 &fpregs[t],status)); 913 } 914 BUG(); 915 case 5: /* FCNVUF (PA2.0 only) */ 916 switch(fmt) { 917 case 0: /* sgl/sgl */ 918 return(sgl_to_sgl_fcnvuf(&fpregs[r1],0, 919 &fpregs[t],status)); 920 case 1: /* sgl/dbl */ 921 return(sgl_to_dbl_fcnvuf(&fpregs[r1],0, 922 &fpregs[t],status)); 923 case 2: /* dbl/sgl */ 924 return(dbl_to_sgl_fcnvuf(&fpregs[r1],0, 925 &fpregs[t],status)); 926 case 3: /* dbl/dbl */ 927 return(dbl_to_dbl_fcnvuf(&fpregs[r1],0, 928 &fpregs[t],status)); 929 } 930 BUG(); 931 case 6: /* FCNVFU (PA2.0 only) */ 932 switch(fmt) { 933 case 0: /* sgl/sgl */ 934 return(sgl_to_sgl_fcnvfu(&fpregs[r1],0, 935 &fpregs[t],status)); 936 case 1: /* sgl/dbl */ 937 return(sgl_to_dbl_fcnvfu(&fpregs[r1],0, 938 &fpregs[t],status)); 939 case 2: /* dbl/sgl */ 940 return(dbl_to_sgl_fcnvfu(&fpregs[r1],0, 941 &fpregs[t],status)); 942 case 3: /* dbl/dbl */ 943 return(dbl_to_dbl_fcnvfu(&fpregs[r1],0, 944 &fpregs[t],status)); 945 } 946 BUG(); 947 case 7: /* FCNVFUT (PA2.0 only) */ 948 switch(fmt) { 949 case 0: /* sgl/sgl */ 950 return(sgl_to_sgl_fcnvfut(&fpregs[r1],0, 951 &fpregs[t],status)); 952 case 1: /* sgl/dbl */ 953 return(sgl_to_dbl_fcnvfut(&fpregs[r1],0, 954 &fpregs[t],status)); 955 case 2: /* dbl/sgl */ 956 return(dbl_to_sgl_fcnvfut(&fpregs[r1],0, 957 &fpregs[t],status)); 958 case 3: /* dbl/dbl */ 959 return(dbl_to_dbl_fcnvfut(&fpregs[r1],0, 960 &fpregs[t],status)); 961 } 962 BUG(); 963 case 4: /* undefined */ 964 return(MAJOR_0C_EXCP); 965 } /* end of switch subop */ 966 BUG(); 967 case 2: /* class 2 */ 968 /* 969 * Be careful out there. 970 * Crashme can generate cases where FR31R is specified 971 * as the source or target of a double precision operation. 972 * Since we just pass the address of the floating-point 973 * register to the emulation routines, this can cause 974 * corruption of fpzeroreg. 975 */ 976 if (fmt == DBL) 977 r2 = (extru(ir,fpr2pos,5)<<1); 978 else 979 r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1))); 980 fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; 981 if (r2 == 0) 982 r2 = fpzeroreg; 983 if (fpu_type_flags & PA2_0_FPU_FLAG) { 984 /* FTEST if nullify bit set, otherwise FCMP */ 985 if (extru(ir, fpnulpos, 1)) { /* FTEST */ 986 /* not legal */ 987 return(MAJOR_0E_EXCP); 988 } else { /* FCMP */ 989 switch (fmt) { 990 /* 991 * fmt is only 1 bit long 992 */ 993 case 0: 994 retval = sgl_fcmp(&fpregs[r1], 995 &fpregs[r2],extru(ir,fptpos,5), 996 &local_status); 997 update_status_cbit(status,local_status, 998 fpu_type_flags, subop); 999 return(retval); 1000 case 1: 1001 retval = dbl_fcmp(&fpregs[r1], 1002 &fpregs[r2],extru(ir,fptpos,5), 1003 &local_status); 1004 update_status_cbit(status,local_status, 1005 fpu_type_flags, subop); 1006 return(retval); 1007 } 1008 } 1009 } /* end of if for PA2.0 */ 1010 else { /* PA1.0 & PA1.1 */ 1011 switch (subop) { 1012 case 1: 1013 case 2: 1014 case 3: 1015 case 4: 1016 case 5: 1017 case 6: 1018 case 7: 1019 return(MAJOR_0E_EXCP); 1020 case 0: /* FCMP */ 1021 switch (fmt) { 1022 /* 1023 * fmt is only 1 bit long 1024 */ 1025 case 0: 1026 retval = sgl_fcmp(&fpregs[r1], 1027 &fpregs[r2],extru(ir,fptpos,5), 1028 &local_status); 1029 update_status_cbit(status,local_status, 1030 fpu_type_flags, subop); 1031 return(retval); 1032 case 1: 1033 retval = dbl_fcmp(&fpregs[r1], 1034 &fpregs[r2],extru(ir,fptpos,5), 1035 &local_status); 1036 update_status_cbit(status,local_status, 1037 fpu_type_flags, subop); 1038 return(retval); 1039 } 1040 } /* end of switch subop */ 1041 } /* end of else for PA1.0 & PA1.1 */ 1042 BUG(); 1043 case 3: /* class 3 */ 1044 /* 1045 * Be careful out there. 1046 * Crashme can generate cases where FR31R is specified 1047 * as the source or target of a double precision operation. 1048 * Since we just pass the address of the floating-point 1049 * register to the emulation routines, this can cause 1050 * corruption of fpzeroreg. 1051 */ 1052 if (fmt == DBL) 1053 r2 = (extru(ir,fpr2pos,5)<<1); 1054 else 1055 r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1))); 1056 if (r2 == 0) 1057 r2 = fpzeroreg; 1058 switch (subop) { 1059 case 5: 1060 case 6: 1061 case 7: 1062 return(MAJOR_0E_EXCP); 1063 1064 /* 1065 * Note that fmt is only 1 bit for class 3 */ 1066 case 0: /* FADD */ 1067 switch (fmt) { 1068 case 0: 1069 return(sgl_fadd(&fpregs[r1],&fpregs[r2], 1070 &fpregs[t],status)); 1071 case 1: 1072 return(dbl_fadd(&fpregs[r1],&fpregs[r2], 1073 &fpregs[t],status)); 1074 } 1075 BUG(); 1076 case 1: /* FSUB */ 1077 switch (fmt) { 1078 case 0: 1079 return(sgl_fsub(&fpregs[r1],&fpregs[r2], 1080 &fpregs[t],status)); 1081 case 1: 1082 return(dbl_fsub(&fpregs[r1],&fpregs[r2], 1083 &fpregs[t],status)); 1084 } 1085 BUG(); 1086 case 2: /* FMPY or XMPYU */ 1087 /* 1088 * check for integer multiply (x bit set) 1089 */ 1090 if (extru(ir,fpxpos,1)) { 1091 /* 1092 * emulate XMPYU 1093 */ 1094 switch (fmt) { 1095 case 0: 1096 /* 1097 * bad instruction if t specifies 1098 * the right half of a register 1099 */ 1100 if (t & 1) 1101 return(MAJOR_0E_EXCP); 1102 BUG(); 1103 /* unsupported 1104 * impyu(&fpregs[r1],&fpregs[r2], 1105 * &fpregs[t]); 1106 */ 1107 return(NOEXCEPTION); 1108 case 1: 1109 return(MAJOR_0E_EXCP); 1110 } 1111 } 1112 else { /* FMPY */ 1113 switch (fmt) { 1114 case 0: 1115 return(sgl_fmpy(&fpregs[r1], 1116 &fpregs[r2],&fpregs[t],status)); 1117 case 1: 1118 return(dbl_fmpy(&fpregs[r1], 1119 &fpregs[r2],&fpregs[t],status)); 1120 } 1121 } 1122 BUG(); 1123 case 3: /* FDIV */ 1124 switch (fmt) { 1125 case 0: 1126 return(sgl_fdiv(&fpregs[r1],&fpregs[r2], 1127 &fpregs[t],status)); 1128 case 1: 1129 return(dbl_fdiv(&fpregs[r1],&fpregs[r2], 1130 &fpregs[t],status)); 1131 } 1132 BUG(); 1133 case 4: /* FREM */ 1134 switch (fmt) { 1135 case 0: 1136 return(sgl_frem(&fpregs[r1],&fpregs[r2], 1137 &fpregs[t],status)); 1138 case 1: 1139 return(dbl_frem(&fpregs[r1],&fpregs[r2], 1140 &fpregs[t],status)); 1141 } 1142 } /* end of class 3 switch */ 1143 } /* end of switch(class) */ 1144 1145 /* If we get here, something is really wrong! */ 1146 return(MAJOR_0E_EXCP); 1147 } 1148 1149 1150 /* 1151 * routine to decode the 06 (FMPYADD and FMPYCFXT) instruction 1152 */ 1153 static u_int 1154 decode_06(ir,fpregs) 1155 u_int ir; 1156 u_int fpregs[]; 1157 { 1158 u_int rm1, rm2, tm, ra, ta; /* operands */ 1159 u_int fmt; 1160 u_int error = 0; 1161 u_int status; 1162 u_int fpu_type_flags; 1163 union { 1164 double dbl; 1165 float flt; 1166 struct { u_int i1; u_int i2; } ints; 1167 } mtmp, atmp; 1168 1169 1170 status = fpregs[0]; /* use a local copy of status reg */ 1171 fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */ 1172 fmt = extru(ir, fpmultifmt, 1); /* get sgl/dbl flag */ 1173 if (fmt == 0) { /* DBL */ 1174 rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int); 1175 if (rm1 == 0) 1176 rm1 = fpzeroreg; 1177 rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int); 1178 if (rm2 == 0) 1179 rm2 = fpzeroreg; 1180 tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int); 1181 if (tm == 0) 1182 return(MAJOR_06_EXCP); 1183 ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int); 1184 ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int); 1185 if (ta == 0) 1186 return(MAJOR_06_EXCP); 1187 1188 if (fpu_type_flags & TIMEX_ROLEX_FPU_MASK) { 1189 1190 if (ra == 0) { 1191 /* special case FMPYCFXT, see sgl case below */ 1192 if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2], 1193 &mtmp.ints.i1,&status)) 1194 error = 1; 1195 if (dbl_to_sgl_fcnvfxt(&fpregs[ta], 1196 &atmp.ints.i1,&atmp.ints.i1,&status)) 1197 error = 1; 1198 } 1199 else { 1200 1201 if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1, 1202 &status)) 1203 error = 1; 1204 if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1, 1205 &status)) 1206 error = 1; 1207 } 1208 } 1209 1210 else 1211 1212 { 1213 if (ra == 0) 1214 ra = fpzeroreg; 1215 1216 if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1, 1217 &status)) 1218 error = 1; 1219 if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1, 1220 &status)) 1221 error = 1; 1222 1223 } 1224 1225 if (error) 1226 return(MAJOR_06_EXCP); 1227 else { 1228 /* copy results */ 1229 fpregs[tm] = mtmp.ints.i1; 1230 fpregs[tm+1] = mtmp.ints.i2; 1231 fpregs[ta] = atmp.ints.i1; 1232 fpregs[ta+1] = atmp.ints.i2; 1233 fpregs[0] = status; 1234 return(NOEXCEPTION); 1235 } 1236 } 1237 else { /* SGL */ 1238 /* 1239 * calculate offsets for single precision numbers 1240 * See table 6-14 in PA-89 architecture for mapping 1241 */ 1242 rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1; /* get offset */ 1243 rm1 |= extru(ir,fprm1pos-4,1); /* add right word offset */ 1244 1245 rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1; /* get offset */ 1246 rm2 |= extru(ir,fprm2pos-4,1); /* add right word offset */ 1247 1248 tm = (extru(ir,fptmpos,4) | 0x10 ) << 1; /* get offset */ 1249 tm |= extru(ir,fptmpos-4,1); /* add right word offset */ 1250 1251 ra = (extru(ir,fprapos,4) | 0x10 ) << 1; /* get offset */ 1252 ra |= extru(ir,fprapos-4,1); /* add right word offset */ 1253 1254 ta = (extru(ir,fptapos,4) | 0x10 ) << 1; /* get offset */ 1255 ta |= extru(ir,fptapos-4,1); /* add right word offset */ 1256 1257 if (ra == 0x20 &&(fpu_type_flags & TIMEX_ROLEX_FPU_MASK)) { 1258 /* special case FMPYCFXT (really 0) 1259 * This instruction is only present on the Timex and 1260 * Rolex fpu's in so if it is the special case and 1261 * one of these fpu's we run the FMPYCFXT instruction 1262 */ 1263 if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1, 1264 &status)) 1265 error = 1; 1266 if (sgl_to_sgl_fcnvfxt(&fpregs[ta],&atmp.ints.i1, 1267 &atmp.ints.i1,&status)) 1268 error = 1; 1269 } 1270 else { 1271 if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1, 1272 &status)) 1273 error = 1; 1274 if (sgl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1, 1275 &status)) 1276 error = 1; 1277 } 1278 if (error) 1279 return(MAJOR_06_EXCP); 1280 else { 1281 /* copy results */ 1282 fpregs[tm] = mtmp.ints.i1; 1283 fpregs[ta] = atmp.ints.i1; 1284 fpregs[0] = status; 1285 return(NOEXCEPTION); 1286 } 1287 } 1288 } 1289 1290 /* 1291 * routine to decode the 26 (FMPYSUB) instruction 1292 */ 1293 static u_int 1294 decode_26(ir,fpregs) 1295 u_int ir; 1296 u_int fpregs[]; 1297 { 1298 u_int rm1, rm2, tm, ra, ta; /* operands */ 1299 u_int fmt; 1300 u_int error = 0; 1301 u_int status; 1302 union { 1303 double dbl; 1304 float flt; 1305 struct { u_int i1; u_int i2; } ints; 1306 } mtmp, atmp; 1307 1308 1309 status = fpregs[0]; 1310 fmt = extru(ir, fpmultifmt, 1); /* get sgl/dbl flag */ 1311 if (fmt == 0) { /* DBL */ 1312 rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int); 1313 if (rm1 == 0) 1314 rm1 = fpzeroreg; 1315 rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int); 1316 if (rm2 == 0) 1317 rm2 = fpzeroreg; 1318 tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int); 1319 if (tm == 0) 1320 return(MAJOR_26_EXCP); 1321 ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int); 1322 if (ra == 0) 1323 return(MAJOR_26_EXCP); 1324 ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int); 1325 if (ta == 0) 1326 return(MAJOR_26_EXCP); 1327 1328 if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status)) 1329 error = 1; 1330 if (dbl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status)) 1331 error = 1; 1332 if (error) 1333 return(MAJOR_26_EXCP); 1334 else { 1335 /* copy results */ 1336 fpregs[tm] = mtmp.ints.i1; 1337 fpregs[tm+1] = mtmp.ints.i2; 1338 fpregs[ta] = atmp.ints.i1; 1339 fpregs[ta+1] = atmp.ints.i2; 1340 fpregs[0] = status; 1341 return(NOEXCEPTION); 1342 } 1343 } 1344 else { /* SGL */ 1345 /* 1346 * calculate offsets for single precision numbers 1347 * See table 6-14 in PA-89 architecture for mapping 1348 */ 1349 rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1; /* get offset */ 1350 rm1 |= extru(ir,fprm1pos-4,1); /* add right word offset */ 1351 1352 rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1; /* get offset */ 1353 rm2 |= extru(ir,fprm2pos-4,1); /* add right word offset */ 1354 1355 tm = (extru(ir,fptmpos,4) | 0x10 ) << 1; /* get offset */ 1356 tm |= extru(ir,fptmpos-4,1); /* add right word offset */ 1357 1358 ra = (extru(ir,fprapos,4) | 0x10 ) << 1; /* get offset */ 1359 ra |= extru(ir,fprapos-4,1); /* add right word offset */ 1360 1361 ta = (extru(ir,fptapos,4) | 0x10 ) << 1; /* get offset */ 1362 ta |= extru(ir,fptapos-4,1); /* add right word offset */ 1363 1364 if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status)) 1365 error = 1; 1366 if (sgl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status)) 1367 error = 1; 1368 if (error) 1369 return(MAJOR_26_EXCP); 1370 else { 1371 /* copy results */ 1372 fpregs[tm] = mtmp.ints.i1; 1373 fpregs[ta] = atmp.ints.i1; 1374 fpregs[0] = status; 1375 return(NOEXCEPTION); 1376 } 1377 } 1378 1379 } 1380 1381 /* 1382 * routine to decode the 2E (FMPYFADD,FMPYNFADD) instructions 1383 */ 1384 static u_int 1385 decode_2e(ir,fpregs) 1386 u_int ir; 1387 u_int fpregs[]; 1388 { 1389 u_int rm1, rm2, ra, t; /* operands */ 1390 u_int fmt; 1391 1392 fmt = extru(ir,fpfmtpos,1); /* get fmt completer */ 1393 if (fmt == DBL) { /* DBL */ 1394 rm1 = extru(ir,fprm1pos,5) * sizeof(double)/sizeof(u_int); 1395 if (rm1 == 0) 1396 rm1 = fpzeroreg; 1397 rm2 = extru(ir,fprm2pos,5) * sizeof(double)/sizeof(u_int); 1398 if (rm2 == 0) 1399 rm2 = fpzeroreg; 1400 ra = ((extru(ir,fpraupos,3)<<2)|(extru(ir,fpralpos,3)>>1)) * 1401 sizeof(double)/sizeof(u_int); 1402 if (ra == 0) 1403 ra = fpzeroreg; 1404 t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int); 1405 if (t == 0) 1406 return(MAJOR_2E_EXCP); 1407 1408 if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */ 1409 return(dbl_fmpynfadd(&fpregs[rm1], &fpregs[rm2], 1410 &fpregs[ra], &fpregs[0], &fpregs[t])); 1411 } else { 1412 return(dbl_fmpyfadd(&fpregs[rm1], &fpregs[rm2], 1413 &fpregs[ra], &fpregs[0], &fpregs[t])); 1414 } 1415 } /* end DBL */ 1416 else { /* SGL */ 1417 rm1 = (extru(ir,fprm1pos,5)<<1)|(extru(ir,fpxrm1pos,1)); 1418 if (rm1 == 0) 1419 rm1 = fpzeroreg; 1420 rm2 = (extru(ir,fprm2pos,5)<<1)|(extru(ir,fpxrm2pos,1)); 1421 if (rm2 == 0) 1422 rm2 = fpzeroreg; 1423 ra = (extru(ir,fpraupos,3)<<3)|extru(ir,fpralpos,3); 1424 if (ra == 0) 1425 ra = fpzeroreg; 1426 t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1))); 1427 if (t == 0) 1428 return(MAJOR_2E_EXCP); 1429 1430 if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */ 1431 return(sgl_fmpynfadd(&fpregs[rm1], &fpregs[rm2], 1432 &fpregs[ra], &fpregs[0], &fpregs[t])); 1433 } else { 1434 return(sgl_fmpyfadd(&fpregs[rm1], &fpregs[rm2], 1435 &fpregs[ra], &fpregs[0], &fpregs[t])); 1436 } 1437 } /* end SGL */ 1438 } 1439 1440 /* 1441 * update_status_cbit 1442 * 1443 * This routine returns the correct FP status register value in 1444 * *status, based on the C-bit & V-bit returned by the FCMP 1445 * emulation routine in new_status. The architecture type 1446 * (PA83, PA89 or PA2.0) is available in fpu_type. The y_field 1447 * and the architecture type are used to determine what flavor 1448 * of FCMP is being emulated. 1449 */ 1450 static void 1451 update_status_cbit(status, new_status, fpu_type, y_field) 1452 u_int *status, new_status; 1453 u_int fpu_type; 1454 u_int y_field; 1455 { 1456 /* 1457 * For PA89 FPU's which implement the Compare Queue and 1458 * for PA2.0 FPU's, update the Compare Queue if the y-field = 0, 1459 * otherwise update the specified bit in the Compare Array. 1460 * Note that the y-field will always be 0 for non-PA2.0 FPU's. 1461 */ 1462 if ((fpu_type & TIMEX_EXTEN_FLAG) || 1463 (fpu_type & ROLEX_EXTEN_FLAG) || 1464 (fpu_type & PA2_0_FPU_FLAG)) { 1465 if (y_field == 0) { 1466 *status = ((*status & 0x04000000) >> 5) | /* old Cbit */ 1467 ((*status & 0x003ff000) >> 1) | /* old CQ */ 1468 (new_status & 0xffc007ff); /* all other bits*/ 1469 } else { 1470 *status = (*status & 0x04000000) | /* old Cbit */ 1471 ((new_status & 0x04000000) >> (y_field+4)) | 1472 (new_status & ~0x04000000 & /* other bits */ 1473 ~(0x04000000 >> (y_field+4))); 1474 } 1475 } 1476 /* if PA83, just update the C-bit */ 1477 else { 1478 *status = new_status; 1479 } 1480 } 1481