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