linux/arch/parisc/math-emu/fpudispatch.c
<<
>>
Prefs
   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)
 141static u_int decode_0c(u_int, u_int, u_int, u_int *);
 142static u_int decode_0e(u_int, u_int, u_int, u_int *);
 143static u_int decode_06(u_int, u_int *);
 144static u_int decode_26(u_int, u_int *);
 145static u_int decode_2e(u_int, u_int *);
 146static void update_status_cbit(u_int *, u_int, u_int, u_int);
 147#else /* !_PROTOTYPES&&!_lint */
 148static u_int decode_0c();
 149static u_int decode_0e();
 150static u_int decode_06();
 151static u_int decode_26();
 152static u_int decode_2e();
 153static void update_status_cbit();
 154#endif /* _PROTOTYPES&&!_lint */
 155
 156#define VASSERT(x)
 157
 158static 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 */
 181u_int
 182fpudispatch(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 */
 236u_int
 237emfpudispatch(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
 274static u_int
 275decode_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
 719static u_int
 720decode_0e(ir,class,subop,fpregs)
 721u_int ir,class,subop;
 722u_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 */
1153static u_int
1154decode_06(ir,fpregs)
1155u_int ir;
1156u_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 */
1293static u_int
1294decode_26(ir,fpregs)
1295u_int ir;
1296u_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 */
1384static u_int
1385decode_2e(ir,fpregs)
1386u_int ir;
1387u_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 */
1450static void
1451update_status_cbit(status, new_status, fpu_type, y_field)
1452u_int *status, new_status;
1453u_int fpu_type;
1454u_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