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