linux/arch/sparc/kernel/visemul.c
<<
>>
Prefs
   1/* visemul.c: Emulation of VIS instructions.
   2 *
   3 * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
   4 */
   5#include <linux/kernel.h>
   6#include <linux/errno.h>
   7#include <linux/thread_info.h>
   8#include <linux/perf_event.h>
   9
  10#include <asm/ptrace.h>
  11#include <asm/pstate.h>
  12#include <asm/system.h>
  13#include <asm/fpumacro.h>
  14#include <asm/uaccess.h>
  15
  16/* OPF field of various VIS instructions.  */
  17
  18/* 000111011 - four 16-bit packs  */
  19#define FPACK16_OPF     0x03b
  20
  21/* 000111010 - two 32-bit packs  */
  22#define FPACK32_OPF     0x03a
  23
  24/* 000111101 - four 16-bit packs  */
  25#define FPACKFIX_OPF    0x03d
  26
  27/* 001001101 - four 16-bit expands  */
  28#define FEXPAND_OPF     0x04d
  29
  30/* 001001011 - two 32-bit merges */
  31#define FPMERGE_OPF     0x04b
  32
  33/* 000110001 - 8-by-16-bit partitoned product  */
  34#define FMUL8x16_OPF    0x031
  35
  36/* 000110011 - 8-by-16-bit upper alpha partitioned product  */
  37#define FMUL8x16AU_OPF  0x033
  38
  39/* 000110101 - 8-by-16-bit lower alpha partitioned product  */
  40#define FMUL8x16AL_OPF  0x035
  41
  42/* 000110110 - upper 8-by-16-bit partitioned product  */
  43#define FMUL8SUx16_OPF  0x036
  44
  45/* 000110111 - lower 8-by-16-bit partitioned product  */
  46#define FMUL8ULx16_OPF  0x037
  47
  48/* 000111000 - upper 8-by-16-bit partitioned product  */
  49#define FMULD8SUx16_OPF 0x038
  50
  51/* 000111001 - lower unsigned 8-by-16-bit partitioned product  */
  52#define FMULD8ULx16_OPF 0x039
  53
  54/* 000101000 - four 16-bit compare; set rd if src1 > src2  */
  55#define FCMPGT16_OPF    0x028
  56
  57/* 000101100 - two 32-bit compare; set rd if src1 > src2  */
  58#define FCMPGT32_OPF    0x02c
  59
  60/* 000100000 - four 16-bit compare; set rd if src1 <= src2  */
  61#define FCMPLE16_OPF    0x020
  62
  63/* 000100100 - two 32-bit compare; set rd if src1 <= src2  */
  64#define FCMPLE32_OPF    0x024
  65
  66/* 000100010 - four 16-bit compare; set rd if src1 != src2  */
  67#define FCMPNE16_OPF    0x022
  68
  69/* 000100110 - two 32-bit compare; set rd if src1 != src2  */
  70#define FCMPNE32_OPF    0x026
  71
  72/* 000101010 - four 16-bit compare; set rd if src1 == src2  */
  73#define FCMPEQ16_OPF    0x02a
  74
  75/* 000101110 - two 32-bit compare; set rd if src1 == src2  */
  76#define FCMPEQ32_OPF    0x02e
  77
  78/* 000000000 - Eight 8-bit edge boundary processing  */
  79#define EDGE8_OPF       0x000
  80
  81/* 000000001 - Eight 8-bit edge boundary processing, no CC */
  82#define EDGE8N_OPF      0x001
  83
  84/* 000000010 - Eight 8-bit edge boundary processing, little-endian  */
  85#define EDGE8L_OPF      0x002
  86
  87/* 000000011 - Eight 8-bit edge boundary processing, little-endian, no CC  */
  88#define EDGE8LN_OPF     0x003
  89
  90/* 000000100 - Four 16-bit edge boundary processing  */
  91#define EDGE16_OPF      0x004
  92
  93/* 000000101 - Four 16-bit edge boundary processing, no CC  */
  94#define EDGE16N_OPF     0x005
  95
  96/* 000000110 - Four 16-bit edge boundary processing, little-endian  */
  97#define EDGE16L_OPF     0x006
  98
  99/* 000000111 - Four 16-bit edge boundary processing, little-endian, no CC  */
 100#define EDGE16LN_OPF    0x007
 101
 102/* 000001000 - Two 32-bit edge boundary processing  */
 103#define EDGE32_OPF      0x008
 104
 105/* 000001001 - Two 32-bit edge boundary processing, no CC  */
 106#define EDGE32N_OPF     0x009
 107
 108/* 000001010 - Two 32-bit edge boundary processing, little-endian  */
 109#define EDGE32L_OPF     0x00a
 110
 111/* 000001011 - Two 32-bit edge boundary processing, little-endian, no CC  */
 112#define EDGE32LN_OPF    0x00b
 113
 114/* 000111110 - distance between 8 8-bit components  */
 115#define PDIST_OPF       0x03e
 116
 117/* 000010000 - convert 8-bit 3-D address to blocked byte address  */
 118#define ARRAY8_OPF      0x010
 119
 120/* 000010010 - convert 16-bit 3-D address to blocked byte address  */
 121#define ARRAY16_OPF     0x012
 122
 123/* 000010100 - convert 32-bit 3-D address to blocked byte address  */
 124#define ARRAY32_OPF     0x014
 125
 126/* 000011001 - Set the GSR.MASK field in preparation for a BSHUFFLE  */
 127#define BMASK_OPF       0x019
 128
 129/* 001001100 - Permute bytes as specified by GSR.MASK  */
 130#define BSHUFFLE_OPF    0x04c
 131
 132#define VIS_OPF_SHIFT   5
 133#define VIS_OPF_MASK    (0x1ff << VIS_OPF_SHIFT)
 134
 135#define RS1(INSN)       (((INSN) >> 14) & 0x1f)
 136#define RS2(INSN)       (((INSN) >>  0) & 0x1f)
 137#define RD(INSN)        (((INSN) >> 25) & 0x1f)
 138
 139static inline void maybe_flush_windows(unsigned int rs1, unsigned int rs2,
 140                                       unsigned int rd, int from_kernel)
 141{
 142        if (rs2 >= 16 || rs1 >= 16 || rd >= 16) {
 143                if (from_kernel != 0)
 144                        __asm__ __volatile__("flushw");
 145                else
 146                        flushw_user();
 147        }
 148}
 149
 150static unsigned long fetch_reg(unsigned int reg, struct pt_regs *regs)
 151{
 152        unsigned long value;
 153        
 154        if (reg < 16)
 155                return (!reg ? 0 : regs->u_regs[reg]);
 156        if (regs->tstate & TSTATE_PRIV) {
 157                struct reg_window *win;
 158                win = (struct reg_window *)(regs->u_regs[UREG_FP] + STACK_BIAS);
 159                value = win->locals[reg - 16];
 160        } else if (test_thread_flag(TIF_32BIT)) {
 161                struct reg_window32 __user *win32;
 162                win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
 163                get_user(value, &win32->locals[reg - 16]);
 164        } else {
 165                struct reg_window __user *win;
 166                win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
 167                get_user(value, &win->locals[reg - 16]);
 168        }
 169        return value;
 170}
 171
 172static inline unsigned long __user *__fetch_reg_addr_user(unsigned int reg,
 173                                                          struct pt_regs *regs)
 174{
 175        BUG_ON(reg < 16);
 176        BUG_ON(regs->tstate & TSTATE_PRIV);
 177
 178        if (test_thread_flag(TIF_32BIT)) {
 179                struct reg_window32 __user *win32;
 180                win32 = (struct reg_window32 __user *)((unsigned long)((u32)regs->u_regs[UREG_FP]));
 181                return (unsigned long __user *)&win32->locals[reg - 16];
 182        } else {
 183                struct reg_window __user *win;
 184                win = (struct reg_window __user *)(regs->u_regs[UREG_FP] + STACK_BIAS);
 185                return &win->locals[reg - 16];
 186        }
 187}
 188
 189static inline unsigned long *__fetch_reg_addr_kern(unsigned int reg,
 190                                                   struct pt_regs *regs)
 191{
 192        BUG_ON(reg >= 16);
 193        BUG_ON(regs->tstate & TSTATE_PRIV);
 194
 195        return &regs->u_regs[reg];
 196}
 197
 198static void store_reg(struct pt_regs *regs, unsigned long val, unsigned long rd)
 199{
 200        if (rd < 16) {
 201                unsigned long *rd_kern = __fetch_reg_addr_kern(rd, regs);
 202
 203                *rd_kern = val;
 204        } else {
 205                unsigned long __user *rd_user = __fetch_reg_addr_user(rd, regs);
 206
 207                if (test_thread_flag(TIF_32BIT))
 208                        __put_user((u32)val, (u32 __user *)rd_user);
 209                else
 210                        __put_user(val, rd_user);
 211        }
 212}
 213
 214static inline unsigned long fpd_regval(struct fpustate *f,
 215                                       unsigned int insn_regnum)
 216{
 217        insn_regnum = (((insn_regnum & 1) << 5) |
 218                       (insn_regnum & 0x1e));
 219
 220        return *(unsigned long *) &f->regs[insn_regnum];
 221}
 222
 223static inline unsigned long *fpd_regaddr(struct fpustate *f,
 224                                         unsigned int insn_regnum)
 225{
 226        insn_regnum = (((insn_regnum & 1) << 5) |
 227                       (insn_regnum & 0x1e));
 228
 229        return (unsigned long *) &f->regs[insn_regnum];
 230}
 231
 232static inline unsigned int fps_regval(struct fpustate *f,
 233                                      unsigned int insn_regnum)
 234{
 235        return f->regs[insn_regnum];
 236}
 237
 238static inline unsigned int *fps_regaddr(struct fpustate *f,
 239                                        unsigned int insn_regnum)
 240{
 241        return &f->regs[insn_regnum];
 242}
 243
 244struct edge_tab {
 245        u16 left, right;
 246};
 247static struct edge_tab edge8_tab[8] = {
 248        { 0xff, 0x80 },
 249        { 0x7f, 0xc0 },
 250        { 0x3f, 0xe0 },
 251        { 0x1f, 0xf0 },
 252        { 0x0f, 0xf8 },
 253        { 0x07, 0xfc },
 254        { 0x03, 0xfe },
 255        { 0x01, 0xff },
 256};
 257static struct edge_tab edge8_tab_l[8] = {
 258        { 0xff, 0x01 },
 259        { 0xfe, 0x03 },
 260        { 0xfc, 0x07 },
 261        { 0xf8, 0x0f },
 262        { 0xf0, 0x1f },
 263        { 0xe0, 0x3f },
 264        { 0xc0, 0x7f },
 265        { 0x80, 0xff },
 266};
 267static struct edge_tab edge16_tab[4] = {
 268        { 0xf, 0x8 },
 269        { 0x7, 0xc },
 270        { 0x3, 0xe },
 271        { 0x1, 0xf },
 272};
 273static struct edge_tab edge16_tab_l[4] = {
 274        { 0xf, 0x1 },
 275        { 0xe, 0x3 },
 276        { 0xc, 0x7 },
 277        { 0x8, 0xf },
 278};
 279static struct edge_tab edge32_tab[2] = {
 280        { 0x3, 0x2 },
 281        { 0x1, 0x3 },
 282};
 283static struct edge_tab edge32_tab_l[2] = {
 284        { 0x3, 0x1 },
 285        { 0x2, 0x3 },
 286};
 287
 288static void edge(struct pt_regs *regs, unsigned int insn, unsigned int opf)
 289{
 290        unsigned long orig_rs1, rs1, orig_rs2, rs2, rd_val;
 291        u16 left, right;
 292
 293        maybe_flush_windows(RS1(insn), RS2(insn), RD(insn), 0);
 294        orig_rs1 = rs1 = fetch_reg(RS1(insn), regs);
 295        orig_rs2 = rs2 = fetch_reg(RS2(insn), regs);
 296
 297        if (test_thread_flag(TIF_32BIT)) {
 298                rs1 = rs1 & 0xffffffff;
 299                rs2 = rs2 & 0xffffffff;
 300        }
 301        switch (opf) {
 302        default:
 303        case EDGE8_OPF:
 304        case EDGE8N_OPF:
 305                left = edge8_tab[rs1 & 0x7].left;
 306                right = edge8_tab[rs2 & 0x7].right;
 307                break;
 308        case EDGE8L_OPF:
 309        case EDGE8LN_OPF:
 310                left = edge8_tab_l[rs1 & 0x7].left;
 311                right = edge8_tab_l[rs2 & 0x7].right;
 312                break;
 313
 314        case EDGE16_OPF:
 315        case EDGE16N_OPF:
 316                left = edge16_tab[(rs1 >> 1) & 0x3].left;
 317                right = edge16_tab[(rs2 >> 1) & 0x3].right;
 318                break;
 319
 320        case EDGE16L_OPF:
 321        case EDGE16LN_OPF:
 322                left = edge16_tab_l[(rs1 >> 1) & 0x3].left;
 323                right = edge16_tab_l[(rs2 >> 1) & 0x3].right;
 324                break;
 325
 326        case EDGE32_OPF:
 327        case EDGE32N_OPF:
 328                left = edge32_tab[(rs1 >> 2) & 0x1].left;
 329                right = edge32_tab[(rs2 >> 2) & 0x1].right;
 330                break;
 331
 332        case EDGE32L_OPF:
 333        case EDGE32LN_OPF:
 334                left = edge32_tab_l[(rs1 >> 2) & 0x1].left;
 335                right = edge32_tab_l[(rs2 >> 2) & 0x1].right;
 336                break;
 337        }
 338
 339        if ((rs1 & ~0x7UL) == (rs2 & ~0x7UL))
 340                rd_val = right & left;
 341        else
 342                rd_val = left;
 343
 344        store_reg(regs, rd_val, RD(insn));
 345
 346        switch (opf) {
 347        case EDGE8_OPF:
 348        case EDGE8L_OPF:
 349        case EDGE16_OPF:
 350        case EDGE16L_OPF:
 351        case EDGE32_OPF:
 352        case EDGE32L_OPF: {
 353                unsigned long ccr, tstate;
 354
 355                __asm__ __volatile__("subcc     %1, %2, %%g0\n\t"
 356                                     "rd        %%ccr, %0"
 357                                     : "=r" (ccr)
 358                                     : "r" (orig_rs1), "r" (orig_rs2)
 359                                     : "cc");
 360                tstate = regs->tstate & ~(TSTATE_XCC | TSTATE_ICC);
 361                regs->tstate = tstate | (ccr << 32UL);
 362        }
 363        }
 364}
 365
 366static void array(struct pt_regs *regs, unsigned int insn, unsigned int opf)
 367{
 368        unsigned long rs1, rs2, rd_val;
 369        unsigned int bits, bits_mask;
 370
 371        maybe_flush_windows(RS1(insn), RS2(insn), RD(insn), 0);
 372        rs1 = fetch_reg(RS1(insn), regs);
 373        rs2 = fetch_reg(RS2(insn), regs);
 374
 375        bits = (rs2 > 5 ? 5 : rs2);
 376        bits_mask = (1UL << bits) - 1UL;
 377
 378        rd_val = ((((rs1 >> 11) & 0x3) <<  0) |
 379                  (((rs1 >> 33) & 0x3) <<  2) |
 380                  (((rs1 >> 55) & 0x1) <<  4) |
 381                  (((rs1 >> 13) & 0xf) <<  5) |
 382                  (((rs1 >> 35) & 0xf) <<  9) |
 383                  (((rs1 >> 56) & 0xf) << 13) |
 384                  (((rs1 >> 17) & bits_mask) << 17) |
 385                  (((rs1 >> 39) & bits_mask) << (17 + bits)) |
 386                  (((rs1 >> 60) & 0xf)       << (17 + (2*bits))));
 387
 388        switch (opf) {
 389        case ARRAY16_OPF:
 390                rd_val <<= 1;
 391                break;
 392
 393        case ARRAY32_OPF:
 394                rd_val <<= 2;
 395        }
 396
 397        store_reg(regs, rd_val, RD(insn));
 398}
 399
 400static void bmask(struct pt_regs *regs, unsigned int insn)
 401{
 402        unsigned long rs1, rs2, rd_val, gsr;
 403
 404        maybe_flush_windows(RS1(insn), RS2(insn), RD(insn), 0);
 405        rs1 = fetch_reg(RS1(insn), regs);
 406        rs2 = fetch_reg(RS2(insn), regs);
 407        rd_val = rs1 + rs2;
 408
 409        store_reg(regs, rd_val, RD(insn));
 410
 411        gsr = current_thread_info()->gsr[0] & 0xffffffff;
 412        gsr |= rd_val << 32UL;
 413        current_thread_info()->gsr[0] = gsr;
 414}
 415
 416static void bshuffle(struct pt_regs *regs, unsigned int insn)
 417{
 418        struct fpustate *f = FPUSTATE;
 419        unsigned long rs1, rs2, rd_val;
 420        unsigned long bmask, i;
 421
 422        bmask = current_thread_info()->gsr[0] >> 32UL;
 423
 424        rs1 = fpd_regval(f, RS1(insn));
 425        rs2 = fpd_regval(f, RS2(insn));
 426
 427        rd_val = 0UL;
 428        for (i = 0; i < 8; i++) {
 429                unsigned long which = (bmask >> (i * 4)) & 0xf;
 430                unsigned long byte;
 431
 432                if (which < 8)
 433                        byte = (rs1 >> (which * 8)) & 0xff;
 434                else
 435                        byte = (rs2 >> ((which-8)*8)) & 0xff;
 436                rd_val |= (byte << (i * 8));
 437        }
 438
 439        *fpd_regaddr(f, RD(insn)) = rd_val;
 440}
 441
 442static void pdist(struct pt_regs *regs, unsigned int insn)
 443{
 444        struct fpustate *f = FPUSTATE;
 445        unsigned long rs1, rs2, *rd, rd_val;
 446        unsigned long i;
 447
 448        rs1 = fpd_regval(f, RS1(insn));
 449        rs2 = fpd_regval(f, RS2(insn));
 450        rd = fpd_regaddr(f, RD(insn));
 451
 452        rd_val = *rd;
 453
 454        for (i = 0; i < 8; i++) {
 455                s16 s1, s2;
 456
 457                s1 = (rs1 >> (56 - (i * 8))) & 0xff;
 458                s2 = (rs2 >> (56 - (i * 8))) & 0xff;
 459
 460                /* Absolute value of difference. */
 461                s1 -= s2;
 462                if (s1 < 0)
 463                        s1 = ~s1 + 1;
 464
 465                rd_val += s1;
 466        }
 467
 468        *rd = rd_val;
 469}
 470
 471static void pformat(struct pt_regs *regs, unsigned int insn, unsigned int opf)
 472{
 473        struct fpustate *f = FPUSTATE;
 474        unsigned long rs1, rs2, gsr, scale, rd_val;
 475
 476        gsr = current_thread_info()->gsr[0];
 477        scale = (gsr >> 3) & (opf == FPACK16_OPF ? 0xf : 0x1f);
 478        switch (opf) {
 479        case FPACK16_OPF: {
 480                unsigned long byte;
 481
 482                rs2 = fpd_regval(f, RS2(insn));
 483                rd_val = 0;
 484                for (byte = 0; byte < 4; byte++) {
 485                        unsigned int val;
 486                        s16 src = (rs2 >> (byte * 16UL)) & 0xffffUL;
 487                        int scaled = src << scale;
 488                        int from_fixed = scaled >> 7;
 489
 490                        val = ((from_fixed < 0) ?
 491                               0 :
 492                               (from_fixed > 255) ?
 493                               255 : from_fixed);
 494
 495                        rd_val |= (val << (8 * byte));
 496                }
 497                *fps_regaddr(f, RD(insn)) = rd_val;
 498                break;
 499        }
 500
 501        case FPACK32_OPF: {
 502                unsigned long word;
 503
 504                rs1 = fpd_regval(f, RS1(insn));
 505                rs2 = fpd_regval(f, RS2(insn));
 506                rd_val = (rs1 << 8) & ~(0x000000ff000000ffUL);
 507                for (word = 0; word < 2; word++) {
 508                        unsigned long val;
 509                        s32 src = (rs2 >> (word * 32UL));
 510                        s64 scaled = src << scale;
 511                        s64 from_fixed = scaled >> 23;
 512
 513                        val = ((from_fixed < 0) ?
 514                               0 :
 515                               (from_fixed > 255) ?
 516                               255 : from_fixed);
 517
 518                        rd_val |= (val << (32 * word));
 519                }
 520                *fpd_regaddr(f, RD(insn)) = rd_val;
 521                break;
 522        }
 523
 524        case FPACKFIX_OPF: {
 525                unsigned long word;
 526
 527                rs2 = fpd_regval(f, RS2(insn));
 528
 529                rd_val = 0;
 530                for (word = 0; word < 2; word++) {
 531                        long val;
 532                        s32 src = (rs2 >> (word * 32UL));
 533                        s64 scaled = src << scale;
 534                        s64 from_fixed = scaled >> 16;
 535
 536                        val = ((from_fixed < -32768) ?
 537                               -32768 :
 538                               (from_fixed > 32767) ?
 539                               32767 : from_fixed);
 540
 541                        rd_val |= ((val & 0xffff) << (word * 16));
 542                }
 543                *fps_regaddr(f, RD(insn)) = rd_val;
 544                break;
 545        }
 546
 547        case FEXPAND_OPF: {
 548                unsigned long byte;
 549
 550                rs2 = fps_regval(f, RS2(insn));
 551
 552                rd_val = 0;
 553                for (byte = 0; byte < 4; byte++) {
 554                        unsigned long val;
 555                        u8 src = (rs2 >> (byte * 8)) & 0xff;
 556
 557                        val = src << 4;
 558
 559                        rd_val |= (val << (byte * 16));
 560                }
 561                *fpd_regaddr(f, RD(insn)) = rd_val;
 562                break;
 563        }
 564
 565        case FPMERGE_OPF: {
 566                rs1 = fps_regval(f, RS1(insn));
 567                rs2 = fps_regval(f, RS2(insn));
 568
 569                rd_val = (((rs2 & 0x000000ff) <<  0) |
 570                          ((rs1 & 0x000000ff) <<  8) |
 571                          ((rs2 & 0x0000ff00) <<  8) |
 572                          ((rs1 & 0x0000ff00) << 16) |
 573                          ((rs2 & 0x00ff0000) << 16) |
 574                          ((rs1 & 0x00ff0000) << 24) |
 575                          ((rs2 & 0xff000000) << 24) |
 576                          ((rs1 & 0xff000000) << 32));
 577                *fpd_regaddr(f, RD(insn)) = rd_val;
 578                break;
 579        }
 580        }
 581}
 582
 583static void pmul(struct pt_regs *regs, unsigned int insn, unsigned int opf)
 584{
 585        struct fpustate *f = FPUSTATE;
 586        unsigned long rs1, rs2, rd_val;
 587
 588        switch (opf) {
 589        case FMUL8x16_OPF: {
 590                unsigned long byte;
 591
 592                rs1 = fps_regval(f, RS1(insn));
 593                rs2 = fpd_regval(f, RS2(insn));
 594
 595                rd_val = 0;
 596                for (byte = 0; byte < 4; byte++) {
 597                        u16 src1 = (rs1 >> (byte *  8)) & 0x00ff;
 598                        s16 src2 = (rs2 >> (byte * 16)) & 0xffff;
 599                        u32 prod = src1 * src2;
 600                        u16 scaled = ((prod & 0x00ffff00) >> 8);
 601
 602                        /* Round up.  */
 603                        if (prod & 0x80)
 604                                scaled++;
 605                        rd_val |= ((scaled & 0xffffUL) << (byte * 16UL));
 606                }
 607
 608                *fpd_regaddr(f, RD(insn)) = rd_val;
 609                break;
 610        }
 611
 612        case FMUL8x16AU_OPF:
 613        case FMUL8x16AL_OPF: {
 614                unsigned long byte;
 615                s16 src2;
 616
 617                rs1 = fps_regval(f, RS1(insn));
 618                rs2 = fps_regval(f, RS2(insn));
 619
 620                rd_val = 0;
 621                src2 = rs2 >> (opf == FMUL8x16AU_OPF ? 16 : 0);
 622                for (byte = 0; byte < 4; byte++) {
 623                        u16 src1 = (rs1 >> (byte * 8)) & 0x00ff;
 624                        u32 prod = src1 * src2;
 625                        u16 scaled = ((prod & 0x00ffff00) >> 8);
 626
 627                        /* Round up.  */
 628                        if (prod & 0x80)
 629                                scaled++;
 630                        rd_val |= ((scaled & 0xffffUL) << (byte * 16UL));
 631                }
 632
 633                *fpd_regaddr(f, RD(insn)) = rd_val;
 634                break;
 635        }
 636
 637        case FMUL8SUx16_OPF:
 638        case FMUL8ULx16_OPF: {
 639                unsigned long byte, ushift;
 640
 641                rs1 = fpd_regval(f, RS1(insn));
 642                rs2 = fpd_regval(f, RS2(insn));
 643
 644                rd_val = 0;
 645                ushift = (opf == FMUL8SUx16_OPF) ? 8 : 0;
 646                for (byte = 0; byte < 4; byte++) {
 647                        u16 src1;
 648                        s16 src2;
 649                        u32 prod;
 650                        u16 scaled;
 651
 652                        src1 = ((rs1 >> ((16 * byte) + ushift)) & 0x00ff);
 653                        src2 = ((rs2 >> (16 * byte)) & 0xffff);
 654                        prod = src1 * src2;
 655                        scaled = ((prod & 0x00ffff00) >> 8);
 656
 657                        /* Round up.  */
 658                        if (prod & 0x80)
 659                                scaled++;
 660                        rd_val |= ((scaled & 0xffffUL) << (byte * 16UL));
 661                }
 662
 663                *fpd_regaddr(f, RD(insn)) = rd_val;
 664                break;
 665        }
 666
 667        case FMULD8SUx16_OPF:
 668        case FMULD8ULx16_OPF: {
 669                unsigned long byte, ushift;
 670
 671                rs1 = fps_regval(f, RS1(insn));
 672                rs2 = fps_regval(f, RS2(insn));
 673
 674                rd_val = 0;
 675                ushift = (opf == FMULD8SUx16_OPF) ? 8 : 0;
 676                for (byte = 0; byte < 2; byte++) {
 677                        u16 src1;
 678                        s16 src2;
 679                        u32 prod;
 680                        u16 scaled;
 681
 682                        src1 = ((rs1 >> ((16 * byte) + ushift)) & 0x00ff);
 683                        src2 = ((rs2 >> (16 * byte)) & 0xffff);
 684                        prod = src1 * src2;
 685                        scaled = ((prod & 0x00ffff00) >> 8);
 686
 687                        /* Round up.  */
 688                        if (prod & 0x80)
 689                                scaled++;
 690                        rd_val |= ((scaled & 0xffffUL) <<
 691                                   ((byte * 32UL) + 7UL));
 692                }
 693                *fpd_regaddr(f, RD(insn)) = rd_val;
 694                break;
 695        }
 696        }
 697}
 698
 699static void pcmp(struct pt_regs *regs, unsigned int insn, unsigned int opf)
 700{
 701        struct fpustate *f = FPUSTATE;
 702        unsigned long rs1, rs2, rd_val, i;
 703
 704        rs1 = fpd_regval(f, RS1(insn));
 705        rs2 = fpd_regval(f, RS2(insn));
 706
 707        rd_val = 0;
 708
 709        switch (opf) {
 710        case FCMPGT16_OPF:
 711                for (i = 0; i < 4; i++) {
 712                        s16 a = (rs1 >> (i * 16)) & 0xffff;
 713                        s16 b = (rs2 >> (i * 16)) & 0xffff;
 714
 715                        if (a > b)
 716                                rd_val |= 8 >> i;
 717                }
 718                break;
 719
 720        case FCMPGT32_OPF:
 721                for (i = 0; i < 2; i++) {
 722                        s32 a = (rs1 >> (i * 32)) & 0xffffffff;
 723                        s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 724
 725                        if (a > b)
 726                                rd_val |= 2 >> i;
 727                }
 728                break;
 729
 730        case FCMPLE16_OPF:
 731                for (i = 0; i < 4; i++) {
 732                        s16 a = (rs1 >> (i * 16)) & 0xffff;
 733                        s16 b = (rs2 >> (i * 16)) & 0xffff;
 734
 735                        if (a <= b)
 736                                rd_val |= 8 >> i;
 737                }
 738                break;
 739
 740        case FCMPLE32_OPF:
 741                for (i = 0; i < 2; i++) {
 742                        s32 a = (rs1 >> (i * 32)) & 0xffffffff;
 743                        s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 744
 745                        if (a <= b)
 746                                rd_val |= 2 >> i;
 747                }
 748                break;
 749
 750        case FCMPNE16_OPF:
 751                for (i = 0; i < 4; i++) {
 752                        s16 a = (rs1 >> (i * 16)) & 0xffff;
 753                        s16 b = (rs2 >> (i * 16)) & 0xffff;
 754
 755                        if (a != b)
 756                                rd_val |= 8 >> i;
 757                }
 758                break;
 759
 760        case FCMPNE32_OPF:
 761                for (i = 0; i < 2; i++) {
 762                        s32 a = (rs1 >> (i * 32)) & 0xffffffff;
 763                        s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 764
 765                        if (a != b)
 766                                rd_val |= 2 >> i;
 767                }
 768                break;
 769
 770        case FCMPEQ16_OPF:
 771                for (i = 0; i < 4; i++) {
 772                        s16 a = (rs1 >> (i * 16)) & 0xffff;
 773                        s16 b = (rs2 >> (i * 16)) & 0xffff;
 774
 775                        if (a == b)
 776                                rd_val |= 8 >> i;
 777                }
 778                break;
 779
 780        case FCMPEQ32_OPF:
 781                for (i = 0; i < 2; i++) {
 782                        s32 a = (rs1 >> (i * 32)) & 0xffffffff;
 783                        s32 b = (rs2 >> (i * 32)) & 0xffffffff;
 784
 785                        if (a == b)
 786                                rd_val |= 2 >> i;
 787                }
 788                break;
 789        }
 790
 791        maybe_flush_windows(0, 0, RD(insn), 0);
 792        store_reg(regs, rd_val, RD(insn));
 793}
 794
 795/* Emulate the VIS instructions which are not implemented in
 796 * hardware on Niagara.
 797 */
 798int vis_emul(struct pt_regs *regs, unsigned int insn)
 799{
 800        unsigned long pc = regs->tpc;
 801        unsigned int opf;
 802
 803        BUG_ON(regs->tstate & TSTATE_PRIV);
 804
 805        perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
 806
 807        if (test_thread_flag(TIF_32BIT))
 808                pc = (u32)pc;
 809
 810        if (get_user(insn, (u32 __user *) pc))
 811                return -EFAULT;
 812
 813        save_and_clear_fpu();
 814
 815        opf = (insn & VIS_OPF_MASK) >> VIS_OPF_SHIFT;
 816        switch (opf) {
 817        default:
 818                return -EINVAL;
 819
 820        /* Pixel Formatting Instructions.  */
 821        case FPACK16_OPF:
 822        case FPACK32_OPF:
 823        case FPACKFIX_OPF:
 824        case FEXPAND_OPF:
 825        case FPMERGE_OPF:
 826                pformat(regs, insn, opf);
 827                break;
 828
 829        /* Partitioned Multiply Instructions  */
 830        case FMUL8x16_OPF:
 831        case FMUL8x16AU_OPF:
 832        case FMUL8x16AL_OPF:
 833        case FMUL8SUx16_OPF:
 834        case FMUL8ULx16_OPF:
 835        case FMULD8SUx16_OPF:
 836        case FMULD8ULx16_OPF:
 837                pmul(regs, insn, opf);
 838                break;
 839
 840        /* Pixel Compare Instructions  */
 841        case FCMPGT16_OPF:
 842        case FCMPGT32_OPF:
 843        case FCMPLE16_OPF:
 844        case FCMPLE32_OPF:
 845        case FCMPNE16_OPF:
 846        case FCMPNE32_OPF:
 847        case FCMPEQ16_OPF:
 848        case FCMPEQ32_OPF:
 849                pcmp(regs, insn, opf);
 850                break;
 851
 852        /* Edge Handling Instructions  */
 853        case EDGE8_OPF:
 854        case EDGE8N_OPF:
 855        case EDGE8L_OPF:
 856        case EDGE8LN_OPF:
 857        case EDGE16_OPF:
 858        case EDGE16N_OPF:
 859        case EDGE16L_OPF:
 860        case EDGE16LN_OPF:
 861        case EDGE32_OPF:
 862        case EDGE32N_OPF:
 863        case EDGE32L_OPF:
 864        case EDGE32LN_OPF:
 865                edge(regs, insn, opf);
 866                break;
 867
 868        /* Pixel Component Distance  */
 869        case PDIST_OPF:
 870                pdist(regs, insn);
 871                break;
 872
 873        /* Three-Dimensional Array Addressing Instructions  */
 874        case ARRAY8_OPF:
 875        case ARRAY16_OPF:
 876        case ARRAY32_OPF:
 877                array(regs, insn, opf);
 878                break;
 879
 880        /* Byte Mask and Shuffle Instructions  */
 881        case BMASK_OPF:
 882                bmask(regs, insn);
 883                break;
 884
 885        case BSHUFFLE_OPF:
 886                bshuffle(regs, insn);
 887                break;
 888        }
 889
 890        regs->tpc = regs->tnpc;
 891        regs->tnpc += 4;
 892        return 0;
 893}
 894