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