linux/arch/powerpc/math-emu/math_efp.c
<<
>>
Prefs
   1/*
   2 * arch/powerpc/math-emu/math_efp.c
   3 *
   4 * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved.
   5 *
   6 * Author: Ebony Zhu,   <ebony.zhu@freescale.com>
   7 *         Yu Liu,      <yu.liu@freescale.com>
   8 *
   9 * Derived from arch/alpha/math-emu/math.c
  10 *              arch/powerpc/math-emu/math.c
  11 *
  12 * Description:
  13 * This file is the exception handler to make E500 SPE instructions
  14 * fully comply with IEEE-754 floating point standard.
  15 *
  16 * This program is free software; you can redistribute it and/or
  17 * modify it under the terms of the GNU General Public License
  18 * as published by the Free Software Foundation; either version
  19 * 2 of the License, or (at your option) any later version.
  20 */
  21
  22#include <linux/types.h>
  23
  24#include <asm/uaccess.h>
  25#include <asm/reg.h>
  26
  27#define FP_EX_BOOKE_E500_SPE
  28#include <asm/sfp-machine.h>
  29
  30#include <math-emu/soft-fp.h>
  31#include <math-emu/single.h>
  32#include <math-emu/double.h>
  33
  34#define EFAPU           0x4
  35
  36#define VCT             0x4
  37#define SPFP            0x6
  38#define DPFP            0x7
  39
  40#define EFSADD          0x2c0
  41#define EFSSUB          0x2c1
  42#define EFSABS          0x2c4
  43#define EFSNABS         0x2c5
  44#define EFSNEG          0x2c6
  45#define EFSMUL          0x2c8
  46#define EFSDIV          0x2c9
  47#define EFSCMPGT        0x2cc
  48#define EFSCMPLT        0x2cd
  49#define EFSCMPEQ        0x2ce
  50#define EFSCFD          0x2cf
  51#define EFSCFSI         0x2d1
  52#define EFSCTUI         0x2d4
  53#define EFSCTSI         0x2d5
  54#define EFSCTUF         0x2d6
  55#define EFSCTSF         0x2d7
  56#define EFSCTUIZ        0x2d8
  57#define EFSCTSIZ        0x2da
  58
  59#define EVFSADD         0x280
  60#define EVFSSUB         0x281
  61#define EVFSABS         0x284
  62#define EVFSNABS        0x285
  63#define EVFSNEG         0x286
  64#define EVFSMUL         0x288
  65#define EVFSDIV         0x289
  66#define EVFSCMPGT       0x28c
  67#define EVFSCMPLT       0x28d
  68#define EVFSCMPEQ       0x28e
  69#define EVFSCTUI        0x294
  70#define EVFSCTSI        0x295
  71#define EVFSCTUF        0x296
  72#define EVFSCTSF        0x297
  73#define EVFSCTUIZ       0x298
  74#define EVFSCTSIZ       0x29a
  75
  76#define EFDADD          0x2e0
  77#define EFDSUB          0x2e1
  78#define EFDABS          0x2e4
  79#define EFDNABS         0x2e5
  80#define EFDNEG          0x2e6
  81#define EFDMUL          0x2e8
  82#define EFDDIV          0x2e9
  83#define EFDCTUIDZ       0x2ea
  84#define EFDCTSIDZ       0x2eb
  85#define EFDCMPGT        0x2ec
  86#define EFDCMPLT        0x2ed
  87#define EFDCMPEQ        0x2ee
  88#define EFDCFS          0x2ef
  89#define EFDCTUI         0x2f4
  90#define EFDCTSI         0x2f5
  91#define EFDCTUF         0x2f6
  92#define EFDCTSF         0x2f7
  93#define EFDCTUIZ        0x2f8
  94#define EFDCTSIZ        0x2fa
  95
  96#define AB      2
  97#define XA      3
  98#define XB      4
  99#define XCR     5
 100#define NOTYPE  0
 101
 102#define SIGN_BIT_S      (1UL << 31)
 103#define SIGN_BIT_D      (1ULL << 63)
 104#define FP_EX_MASK      (FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \
 105                        FP_EX_UNDERFLOW | FP_EX_OVERFLOW)
 106
 107union dw_union {
 108        u64 dp[1];
 109        u32 wp[2];
 110};
 111
 112static unsigned long insn_type(unsigned long speinsn)
 113{
 114        unsigned long ret = NOTYPE;
 115
 116        switch (speinsn & 0x7ff) {
 117        case EFSABS:    ret = XA;       break;
 118        case EFSADD:    ret = AB;       break;
 119        case EFSCFD:    ret = XB;       break;
 120        case EFSCMPEQ:  ret = XCR;      break;
 121        case EFSCMPGT:  ret = XCR;      break;
 122        case EFSCMPLT:  ret = XCR;      break;
 123        case EFSCTSF:   ret = XB;       break;
 124        case EFSCTSI:   ret = XB;       break;
 125        case EFSCTSIZ:  ret = XB;       break;
 126        case EFSCTUF:   ret = XB;       break;
 127        case EFSCTUI:   ret = XB;       break;
 128        case EFSCTUIZ:  ret = XB;       break;
 129        case EFSDIV:    ret = AB;       break;
 130        case EFSMUL:    ret = AB;       break;
 131        case EFSNABS:   ret = XA;       break;
 132        case EFSNEG:    ret = XA;       break;
 133        case EFSSUB:    ret = AB;       break;
 134        case EFSCFSI:   ret = XB;       break;
 135
 136        case EVFSABS:   ret = XA;       break;
 137        case EVFSADD:   ret = AB;       break;
 138        case EVFSCMPEQ: ret = XCR;      break;
 139        case EVFSCMPGT: ret = XCR;      break;
 140        case EVFSCMPLT: ret = XCR;      break;
 141        case EVFSCTSF:  ret = XB;       break;
 142        case EVFSCTSI:  ret = XB;       break;
 143        case EVFSCTSIZ: ret = XB;       break;
 144        case EVFSCTUF:  ret = XB;       break;
 145        case EVFSCTUI:  ret = XB;       break;
 146        case EVFSCTUIZ: ret = XB;       break;
 147        case EVFSDIV:   ret = AB;       break;
 148        case EVFSMUL:   ret = AB;       break;
 149        case EVFSNABS:  ret = XA;       break;
 150        case EVFSNEG:   ret = XA;       break;
 151        case EVFSSUB:   ret = AB;       break;
 152
 153        case EFDABS:    ret = XA;       break;
 154        case EFDADD:    ret = AB;       break;
 155        case EFDCFS:    ret = XB;       break;
 156        case EFDCMPEQ:  ret = XCR;      break;
 157        case EFDCMPGT:  ret = XCR;      break;
 158        case EFDCMPLT:  ret = XCR;      break;
 159        case EFDCTSF:   ret = XB;       break;
 160        case EFDCTSI:   ret = XB;       break;
 161        case EFDCTSIDZ: ret = XB;       break;
 162        case EFDCTSIZ:  ret = XB;       break;
 163        case EFDCTUF:   ret = XB;       break;
 164        case EFDCTUI:   ret = XB;       break;
 165        case EFDCTUIDZ: ret = XB;       break;
 166        case EFDCTUIZ:  ret = XB;       break;
 167        case EFDDIV:    ret = AB;       break;
 168        case EFDMUL:    ret = AB;       break;
 169        case EFDNABS:   ret = XA;       break;
 170        case EFDNEG:    ret = XA;       break;
 171        case EFDSUB:    ret = AB;       break;
 172
 173        default:
 174                printk(KERN_ERR "\nOoops! SPE instruction no type found.");
 175                printk(KERN_ERR "\ninst code: %08lx\n", speinsn);
 176        }
 177
 178        return ret;
 179}
 180
 181int do_spe_mathemu(struct pt_regs *regs)
 182{
 183        FP_DECL_EX;
 184        int IR, cmp;
 185
 186        unsigned long type, func, fc, fa, fb, src, speinsn;
 187        union dw_union vc, va, vb;
 188
 189        if (get_user(speinsn, (unsigned int __user *) regs->nip))
 190                return -EFAULT;
 191        if ((speinsn >> 26) != EFAPU)
 192                return -EINVAL;         /* not an spe instruction */
 193
 194        type = insn_type(speinsn);
 195        if (type == NOTYPE)
 196                return -ENOSYS;
 197
 198        func = speinsn & 0x7ff;
 199        fc = (speinsn >> 21) & 0x1f;
 200        fa = (speinsn >> 16) & 0x1f;
 201        fb = (speinsn >> 11) & 0x1f;
 202        src = (speinsn >> 5) & 0x7;
 203
 204        vc.wp[0] = current->thread.evr[fc];
 205        vc.wp[1] = regs->gpr[fc];
 206        va.wp[0] = current->thread.evr[fa];
 207        va.wp[1] = regs->gpr[fa];
 208        vb.wp[0] = current->thread.evr[fb];
 209        vb.wp[1] = regs->gpr[fb];
 210
 211        __FPU_FPSCR = mfspr(SPRN_SPEFSCR);
 212
 213#ifdef DEBUG
 214        printk("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR);
 215        printk("vc: %08x  %08x\n", vc.wp[0], vc.wp[1]);
 216        printk("va: %08x  %08x\n", va.wp[0], va.wp[1]);
 217        printk("vb: %08x  %08x\n", vb.wp[0], vb.wp[1]);
 218#endif
 219
 220        switch (src) {
 221        case SPFP: {
 222                FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
 223
 224                switch (type) {
 225                case AB:
 226                case XCR:
 227                        FP_UNPACK_SP(SA, va.wp + 1);
 228                case XB:
 229                        FP_UNPACK_SP(SB, vb.wp + 1);
 230                        break;
 231                case XA:
 232                        FP_UNPACK_SP(SA, va.wp + 1);
 233                        break;
 234                }
 235
 236#ifdef DEBUG
 237                printk("SA: %ld %08lx %ld (%ld)\n", SA_s, SA_f, SA_e, SA_c);
 238                printk("SB: %ld %08lx %ld (%ld)\n", SB_s, SB_f, SB_e, SB_c);
 239#endif
 240
 241                switch (func) {
 242                case EFSABS:
 243                        vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;
 244                        goto update_regs;
 245
 246                case EFSNABS:
 247                        vc.wp[1] = va.wp[1] | SIGN_BIT_S;
 248                        goto update_regs;
 249
 250                case EFSNEG:
 251                        vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;
 252                        goto update_regs;
 253
 254                case EFSADD:
 255                        FP_ADD_S(SR, SA, SB);
 256                        goto pack_s;
 257
 258                case EFSSUB:
 259                        FP_SUB_S(SR, SA, SB);
 260                        goto pack_s;
 261
 262                case EFSMUL:
 263                        FP_MUL_S(SR, SA, SB);
 264                        goto pack_s;
 265
 266                case EFSDIV:
 267                        FP_DIV_S(SR, SA, SB);
 268                        goto pack_s;
 269
 270                case EFSCMPEQ:
 271                        cmp = 0;
 272                        goto cmp_s;
 273
 274                case EFSCMPGT:
 275                        cmp = 1;
 276                        goto cmp_s;
 277
 278                case EFSCMPLT:
 279                        cmp = -1;
 280                        goto cmp_s;
 281
 282                case EFSCTSF:
 283                case EFSCTUF:
 284                        if (!((vb.wp[1] >> 23) == 0xff && ((vb.wp[1] & 0x7fffff) > 0))) {
 285                                /* NaN */
 286                                if (((vb.wp[1] >> 23) & 0xff) == 0) {
 287                                        /* denorm */
 288                                        vc.wp[1] = 0x0;
 289                                } else if ((vb.wp[1] >> 31) == 0) {
 290                                        /* positive normal */
 291                                        vc.wp[1] = (func == EFSCTSF) ?
 292                                                0x7fffffff : 0xffffffff;
 293                                } else { /* negative normal */
 294                                        vc.wp[1] = (func == EFSCTSF) ?
 295                                                0x80000000 : 0x0;
 296                                }
 297                        } else { /* rB is NaN */
 298                                vc.wp[1] = 0x0;
 299                        }
 300                        goto update_regs;
 301
 302                case EFSCFD: {
 303                        FP_DECL_D(DB);
 304                        FP_CLEAR_EXCEPTIONS;
 305                        FP_UNPACK_DP(DB, vb.dp);
 306#ifdef DEBUG
 307                        printk("DB: %ld %08lx %08lx %ld (%ld)\n",
 308                                        DB_s, DB_f1, DB_f0, DB_e, DB_c);
 309#endif
 310                        FP_CONV(S, D, 1, 2, SR, DB);
 311                        goto pack_s;
 312                }
 313
 314                case EFSCTSI:
 315                case EFSCTSIZ:
 316                case EFSCTUI:
 317                case EFSCTUIZ:
 318                        if (func & 0x4) {
 319                                _FP_ROUND(1, SB);
 320                        } else {
 321                                _FP_ROUND_ZERO(1, SB);
 322                        }
 323                        FP_TO_INT_S(vc.wp[1], SB, 32, ((func & 0x3) != 0));
 324                        goto update_regs;
 325
 326                default:
 327                        goto illegal;
 328                }
 329                break;
 330
 331pack_s:
 332#ifdef DEBUG
 333                printk("SR: %ld %08lx %ld (%ld)\n", SR_s, SR_f, SR_e, SR_c);
 334#endif
 335                FP_PACK_SP(vc.wp + 1, SR);
 336                goto update_regs;
 337
 338cmp_s:
 339                FP_CMP_S(IR, SA, SB, 3);
 340                if (IR == 3 && (FP_ISSIGNAN_S(SA) || FP_ISSIGNAN_S(SB)))
 341                        FP_SET_EXCEPTION(FP_EX_INVALID);
 342                if (IR == cmp) {
 343                        IR = 0x4;
 344                } else {
 345                        IR = 0;
 346                }
 347                goto update_ccr;
 348        }
 349
 350        case DPFP: {
 351                FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
 352
 353                switch (type) {
 354                case AB:
 355                case XCR:
 356                        FP_UNPACK_DP(DA, va.dp);
 357                case XB:
 358                        FP_UNPACK_DP(DB, vb.dp);
 359                        break;
 360                case XA:
 361                        FP_UNPACK_DP(DA, va.dp);
 362                        break;
 363                }
 364
 365#ifdef DEBUG
 366                printk("DA: %ld %08lx %08lx %ld (%ld)\n",
 367                                DA_s, DA_f1, DA_f0, DA_e, DA_c);
 368                printk("DB: %ld %08lx %08lx %ld (%ld)\n",
 369                                DB_s, DB_f1, DB_f0, DB_e, DB_c);
 370#endif
 371
 372                switch (func) {
 373                case EFDABS:
 374                        vc.dp[0] = va.dp[0] & ~SIGN_BIT_D;
 375                        goto update_regs;
 376
 377                case EFDNABS:
 378                        vc.dp[0] = va.dp[0] | SIGN_BIT_D;
 379                        goto update_regs;
 380
 381                case EFDNEG:
 382                        vc.dp[0] = va.dp[0] ^ SIGN_BIT_D;
 383                        goto update_regs;
 384
 385                case EFDADD:
 386                        FP_ADD_D(DR, DA, DB);
 387                        goto pack_d;
 388
 389                case EFDSUB:
 390                        FP_SUB_D(DR, DA, DB);
 391                        goto pack_d;
 392
 393                case EFDMUL:
 394                        FP_MUL_D(DR, DA, DB);
 395                        goto pack_d;
 396
 397                case EFDDIV:
 398                        FP_DIV_D(DR, DA, DB);
 399                        goto pack_d;
 400
 401                case EFDCMPEQ:
 402                        cmp = 0;
 403                        goto cmp_d;
 404
 405                case EFDCMPGT:
 406                        cmp = 1;
 407                        goto cmp_d;
 408
 409                case EFDCMPLT:
 410                        cmp = -1;
 411                        goto cmp_d;
 412
 413                case EFDCTSF:
 414                case EFDCTUF:
 415                        if (!((vb.wp[0] >> 20) == 0x7ff &&
 416                           ((vb.wp[0] & 0xfffff) > 0 || (vb.wp[1] > 0)))) {
 417                                /* not a NaN */
 418                                if (((vb.wp[0] >> 20) & 0x7ff) == 0) {
 419                                        /* denorm */
 420                                        vc.wp[1] = 0x0;
 421                                } else if ((vb.wp[0] >> 31) == 0) {
 422                                        /* positive normal */
 423                                        vc.wp[1] = (func == EFDCTSF) ?
 424                                                0x7fffffff : 0xffffffff;
 425                                } else { /* negative normal */
 426                                        vc.wp[1] = (func == EFDCTSF) ?
 427                                                0x80000000 : 0x0;
 428                                }
 429                        } else { /* NaN */
 430                                vc.wp[1] = 0x0;
 431                        }
 432                        goto update_regs;
 433
 434                case EFDCFS: {
 435                        FP_DECL_S(SB);
 436                        FP_CLEAR_EXCEPTIONS;
 437                        FP_UNPACK_SP(SB, vb.wp + 1);
 438#ifdef DEBUG
 439                        printk("SB: %ld %08lx %ld (%ld)\n",
 440                                        SB_s, SB_f, SB_e, SB_c);
 441#endif
 442                        FP_CONV(D, S, 2, 1, DR, SB);
 443                        goto pack_d;
 444                }
 445
 446                case EFDCTUIDZ:
 447                case EFDCTSIDZ:
 448                        _FP_ROUND_ZERO(2, DB);
 449                        FP_TO_INT_D(vc.dp[0], DB, 64, ((func & 0x1) == 0));
 450                        goto update_regs;
 451
 452                case EFDCTUI:
 453                case EFDCTSI:
 454                case EFDCTUIZ:
 455                case EFDCTSIZ:
 456                        if (func & 0x4) {
 457                                _FP_ROUND(2, DB);
 458                        } else {
 459                                _FP_ROUND_ZERO(2, DB);
 460                        }
 461                        FP_TO_INT_D(vc.wp[1], DB, 32, ((func & 0x3) != 0));
 462                        goto update_regs;
 463
 464                default:
 465                        goto illegal;
 466                }
 467                break;
 468
 469pack_d:
 470#ifdef DEBUG
 471                printk("DR: %ld %08lx %08lx %ld (%ld)\n",
 472                                DR_s, DR_f1, DR_f0, DR_e, DR_c);
 473#endif
 474                FP_PACK_DP(vc.dp, DR);
 475                goto update_regs;
 476
 477cmp_d:
 478                FP_CMP_D(IR, DA, DB, 3);
 479                if (IR == 3 && (FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB)))
 480                        FP_SET_EXCEPTION(FP_EX_INVALID);
 481                if (IR == cmp) {
 482                        IR = 0x4;
 483                } else {
 484                        IR = 0;
 485                }
 486                goto update_ccr;
 487
 488        }
 489
 490        case VCT: {
 491                FP_DECL_S(SA0); FP_DECL_S(SB0); FP_DECL_S(SR0);
 492                FP_DECL_S(SA1); FP_DECL_S(SB1); FP_DECL_S(SR1);
 493                int IR0, IR1;
 494
 495                switch (type) {
 496                case AB:
 497                case XCR:
 498                        FP_UNPACK_SP(SA0, va.wp);
 499                        FP_UNPACK_SP(SA1, va.wp + 1);
 500                case XB:
 501                        FP_UNPACK_SP(SB0, vb.wp);
 502                        FP_UNPACK_SP(SB1, vb.wp + 1);
 503                        break;
 504                case XA:
 505                        FP_UNPACK_SP(SA0, va.wp);
 506                        FP_UNPACK_SP(SA1, va.wp + 1);
 507                        break;
 508                }
 509
 510#ifdef DEBUG
 511                printk("SA0: %ld %08lx %ld (%ld)\n", SA0_s, SA0_f, SA0_e, SA0_c);
 512                printk("SA1: %ld %08lx %ld (%ld)\n", SA1_s, SA1_f, SA1_e, SA1_c);
 513                printk("SB0: %ld %08lx %ld (%ld)\n", SB0_s, SB0_f, SB0_e, SB0_c);
 514                printk("SB1: %ld %08lx %ld (%ld)\n", SB1_s, SB1_f, SB1_e, SB1_c);
 515#endif
 516
 517                switch (func) {
 518                case EVFSABS:
 519                        vc.wp[0] = va.wp[0] & ~SIGN_BIT_S;
 520                        vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;
 521                        goto update_regs;
 522
 523                case EVFSNABS:
 524                        vc.wp[0] = va.wp[0] | SIGN_BIT_S;
 525                        vc.wp[1] = va.wp[1] | SIGN_BIT_S;
 526                        goto update_regs;
 527
 528                case EVFSNEG:
 529                        vc.wp[0] = va.wp[0] ^ SIGN_BIT_S;
 530                        vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;
 531                        goto update_regs;
 532
 533                case EVFSADD:
 534                        FP_ADD_S(SR0, SA0, SB0);
 535                        FP_ADD_S(SR1, SA1, SB1);
 536                        goto pack_vs;
 537
 538                case EVFSSUB:
 539                        FP_SUB_S(SR0, SA0, SB0);
 540                        FP_SUB_S(SR1, SA1, SB1);
 541                        goto pack_vs;
 542
 543                case EVFSMUL:
 544                        FP_MUL_S(SR0, SA0, SB0);
 545                        FP_MUL_S(SR1, SA1, SB1);
 546                        goto pack_vs;
 547
 548                case EVFSDIV:
 549                        FP_DIV_S(SR0, SA0, SB0);
 550                        FP_DIV_S(SR1, SA1, SB1);
 551                        goto pack_vs;
 552
 553                case EVFSCMPEQ:
 554                        cmp = 0;
 555                        goto cmp_vs;
 556
 557                case EVFSCMPGT:
 558                        cmp = 1;
 559                        goto cmp_vs;
 560
 561                case EVFSCMPLT:
 562                        cmp = -1;
 563                        goto cmp_vs;
 564
 565                case EVFSCTSF:
 566                        __asm__ __volatile__ ("mtspr 512, %4\n"
 567                                "efsctsf %0, %2\n"
 568                                "efsctsf %1, %3\n"
 569                                : "=r" (vc.wp[0]), "=r" (vc.wp[1])
 570                                : "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0));
 571                        goto update_regs;
 572
 573                case EVFSCTUF:
 574                        __asm__ __volatile__ ("mtspr 512, %4\n"
 575                                "efsctuf %0, %2\n"
 576                                "efsctuf %1, %3\n"
 577                                : "=r" (vc.wp[0]), "=r" (vc.wp[1])
 578                                : "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0));
 579                        goto update_regs;
 580
 581                case EVFSCTUI:
 582                case EVFSCTSI:
 583                case EVFSCTUIZ:
 584                case EVFSCTSIZ:
 585                        if (func & 0x4) {
 586                                _FP_ROUND(1, SB0);
 587                                _FP_ROUND(1, SB1);
 588                        } else {
 589                                _FP_ROUND_ZERO(1, SB0);
 590                                _FP_ROUND_ZERO(1, SB1);
 591                        }
 592                        FP_TO_INT_S(vc.wp[0], SB0, 32, ((func & 0x3) != 0));
 593                        FP_TO_INT_S(vc.wp[1], SB1, 32, ((func & 0x3) != 0));
 594                        goto update_regs;
 595
 596                default:
 597                        goto illegal;
 598                }
 599                break;
 600
 601pack_vs:
 602#ifdef DEBUG
 603                printk("SR0: %ld %08lx %ld (%ld)\n", SR0_s, SR0_f, SR0_e, SR0_c);
 604                printk("SR1: %ld %08lx %ld (%ld)\n", SR1_s, SR1_f, SR1_e, SR1_c);
 605#endif
 606                FP_PACK_SP(vc.wp, SR0);
 607                FP_PACK_SP(vc.wp + 1, SR1);
 608                goto update_regs;
 609
 610cmp_vs:
 611                {
 612                        int ch, cl;
 613
 614                        FP_CMP_S(IR0, SA0, SB0, 3);
 615                        FP_CMP_S(IR1, SA1, SB1, 3);
 616                        if (IR0 == 3 && (FP_ISSIGNAN_S(SA0) || FP_ISSIGNAN_S(SB0)))
 617                                FP_SET_EXCEPTION(FP_EX_INVALID);
 618                        if (IR1 == 3 && (FP_ISSIGNAN_S(SA1) || FP_ISSIGNAN_S(SB1)))
 619                                FP_SET_EXCEPTION(FP_EX_INVALID);
 620                        ch = (IR0 == cmp) ? 1 : 0;
 621                        cl = (IR1 == cmp) ? 1 : 0;
 622                        IR = (ch << 3) | (cl << 2) | ((ch | cl) << 1) |
 623                                ((ch & cl) << 0);
 624                        goto update_ccr;
 625                }
 626        }
 627        default:
 628                return -EINVAL;
 629        }
 630
 631update_ccr:
 632        regs->ccr &= ~(15 << ((7 - ((speinsn >> 23) & 0x7)) << 2));
 633        regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2));
 634
 635update_regs:
 636        __FPU_FPSCR &= ~FP_EX_MASK;
 637        __FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK);
 638        mtspr(SPRN_SPEFSCR, __FPU_FPSCR);
 639
 640        current->thread.evr[fc] = vc.wp[0];
 641        regs->gpr[fc] = vc.wp[1];
 642
 643#ifdef DEBUG
 644        printk("ccr = %08lx\n", regs->ccr);
 645        printk("cur exceptions = %08x spefscr = %08lx\n",
 646                        FP_CUR_EXCEPTIONS, __FPU_FPSCR);
 647        printk("vc: %08x  %08x\n", vc.wp[0], vc.wp[1]);
 648        printk("va: %08x  %08x\n", va.wp[0], va.wp[1]);
 649        printk("vb: %08x  %08x\n", vb.wp[0], vb.wp[1]);
 650#endif
 651
 652        return 0;
 653
 654illegal:
 655        printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn);
 656        return -ENOSYS;
 657}
 658
 659int speround_handler(struct pt_regs *regs)
 660{
 661        union dw_union fgpr;
 662        int s_lo, s_hi;
 663        unsigned long speinsn, type, fc;
 664
 665        if (get_user(speinsn, (unsigned int __user *) regs->nip))
 666                return -EFAULT;
 667        if ((speinsn >> 26) != 4)
 668                return -EINVAL;         /* not an spe instruction */
 669
 670        type = insn_type(speinsn & 0x7ff);
 671        if (type == XCR) return -ENOSYS;
 672
 673        fc = (speinsn >> 21) & 0x1f;
 674        s_lo = regs->gpr[fc] & SIGN_BIT_S;
 675        s_hi = current->thread.evr[fc] & SIGN_BIT_S;
 676        fgpr.wp[0] = current->thread.evr[fc];
 677        fgpr.wp[1] = regs->gpr[fc];
 678
 679        __FPU_FPSCR = mfspr(SPRN_SPEFSCR);
 680
 681        switch ((speinsn >> 5) & 0x7) {
 682        /* Since SPE instructions on E500 core can handle round to nearest
 683         * and round toward zero with IEEE-754 complied, we just need
 684         * to handle round toward +Inf and round toward -Inf by software.
 685         */
 686        case SPFP:
 687                if ((FP_ROUNDMODE) == FP_RND_PINF) {
 688                        if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */
 689                } else { /* round to -Inf */
 690                        if (s_lo) fgpr.wp[1]++; /* Z < 0, choose Z2 */
 691                }
 692                break;
 693
 694        case DPFP:
 695                if (FP_ROUNDMODE == FP_RND_PINF) {
 696                        if (!s_hi) fgpr.dp[0]++; /* Z > 0, choose Z1 */
 697                } else { /* round to -Inf */
 698                        if (s_hi) fgpr.dp[0]++; /* Z < 0, choose Z2 */
 699                }
 700                break;
 701
 702        case VCT:
 703                if (FP_ROUNDMODE == FP_RND_PINF) {
 704                        if (!s_lo) fgpr.wp[1]++; /* Z_low > 0, choose Z1 */
 705                        if (!s_hi) fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */
 706                } else { /* round to -Inf */
 707                        if (s_lo) fgpr.wp[1]++; /* Z_low < 0, choose Z2 */
 708                        if (s_hi) fgpr.wp[0]++; /* Z_high < 0, choose Z2 */
 709                }
 710                break;
 711
 712        default:
 713                return -EINVAL;
 714        }
 715
 716        current->thread.evr[fc] = fgpr.wp[0];
 717        regs->gpr[fc] = fgpr.wp[1];
 718
 719        return 0;
 720}
 721