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