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