1 /* 2 * Linux/PA-RISC Project (http://www.parisc-linux.org/) 3 * 4 * Floating-point emulation code 5 * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 /* 22 * linux/arch/math-emu/driver.c.c 23 * 24 * decodes and dispatches unimplemented FPU instructions 25 * 26 * Copyright (C) 1999, 2000 Philipp Rumpf <prumpf@tux.org> 27 * Copyright (C) 2001 Hewlett-Packard <bame@debian.org> 28 */ 29 30 #include <linux/sched.h> 31 #include "float.h" 32 #include "math-emu.h" 33 34 35 #define fptpos 31 36 #define fpr1pos 10 37 #define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1)) 38 39 #define FPUDEBUG 0 40 41 /* Format of the floating-point exception registers. */ 42 struct exc_reg { 43 unsigned int exception : 6; 44 unsigned int ei : 26; 45 }; 46 47 /* Macros for grabbing bits of the instruction format from the 'ei' 48 field above. */ 49 /* Major opcode 0c and 0e */ 50 #define FP0CE_UID(i) (((i) >> 6) & 3) 51 #define FP0CE_CLASS(i) (((i) >> 9) & 3) 52 #define FP0CE_SUBOP(i) (((i) >> 13) & 7) 53 #define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */ 54 #define FP0C_FORMAT(i) (((i) >> 11) & 3) 55 #define FP0E_FORMAT(i) (((i) >> 11) & 1) 56 57 /* Major opcode 0c, uid 2 (performance monitoring) */ 58 #define FPPM_SUBOP(i) (((i) >> 9) & 0x1f) 59 60 /* Major opcode 2e (fused operations). */ 61 #define FP2E_SUBOP(i) (((i) >> 5) & 1) 62 #define FP2E_FORMAT(i) (((i) >> 11) & 1) 63 64 /* Major opcode 26 (FMPYSUB) */ 65 /* Major opcode 06 (FMPYADD) */ 66 #define FPx6_FORMAT(i) ((i) & 0x1f) 67 68 /* Flags and enable bits of the status word. */ 69 #define FPSW_FLAGS(w) ((w) >> 27) 70 #define FPSW_ENABLE(w) ((w) & 0x1f) 71 #define FPSW_V (1<<4) 72 #define FPSW_Z (1<<3) 73 #define FPSW_O (1<<2) 74 #define FPSW_U (1<<1) 75 #define FPSW_I (1<<0) 76 77 /* Handle a floating point exception. Return zero if the faulting 78 instruction can be completed successfully. */ 79 int 80 handle_fpe(struct pt_regs *regs) 81 { 82 extern void printbinary(unsigned long x, int nbits); 83 struct siginfo si; 84 unsigned int orig_sw, sw; 85 int signalcode; 86 /* need an intermediate copy of float regs because FPU emulation 87 * code expects an artificial last entry which contains zero 88 * 89 * also, the passed in fr registers contain one word that defines 90 * the fpu type. the fpu type information is constructed 91 * inside the emulation code 92 */ 93 __u64 frcopy[36]; 94 95 memcpy(frcopy, regs->fr, sizeof regs->fr); 96 frcopy[32] = 0; 97 98 memcpy(&orig_sw, frcopy, sizeof(orig_sw)); 99 100 if (FPUDEBUG) { 101 printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n "); 102 printbinary(orig_sw, 32); 103 printk(KERN_DEBUG "\n"); 104 } 105 106 signalcode = decode_fpu(frcopy, 0x666); 107 108 /* Status word = FR0L. */ 109 memcpy(&sw, frcopy, sizeof(sw)); 110 if (FPUDEBUG) { 111 printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n", 112 signalcode >> 24, signalcode & 0xffffff); 113 printbinary(sw, 32); 114 printk(KERN_DEBUG "\n"); 115 } 116 117 memcpy(regs->fr, frcopy, sizeof regs->fr); 118 if (signalcode != 0) { 119 si.si_signo = signalcode >> 24; 120 si.si_errno = 0; 121 si.si_code = signalcode & 0xffffff; 122 si.si_addr = (void __user *) regs->iaoq[0]; 123 force_sig_info(si.si_signo, &si, current); 124 return -1; 125 } 126 127 return signalcode ? -1 : 0; 128 } 129