aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/sh4/fpu.c
diff options
context:
space:
mode:
authorStuart Menefy <stuart.menefy@st.com>2007-11-30 04:42:27 -0500
committerPaul Mundt <lethal@linux-sh.org>2008-01-27 23:18:59 -0500
commitc8c0a1aba9fa8f816dc8fb477ff816a5b700f0ea (patch)
tree54329f0b6497be088fc573c67e5541863041fdde /arch/sh/kernel/cpu/sh4/fpu.c
parent453ec9c1c3808b051347edbbf637f997add7b85b (diff)
sh: Support denormalization on SH-4 FPU.
Signed-off-by: Stuart Menefy <stuart.menefy@st.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel/cpu/sh4/fpu.c')
-rw-r--r--arch/sh/kernel/cpu/sh4/fpu.c514
1 files changed, 334 insertions, 180 deletions
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
index e624180b4467..817f9939cda6 100644
--- a/arch/sh/kernel/cpu/sh4/fpu.c
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -1,7 +1,4 @@
1/* $Id: fpu.c,v 1.4 2004/01/13 05:52:11 kkojima Exp $ 1/*
2 *
3 * linux/arch/sh/kernel/fpu.c
4 *
5 * Save/restore floating point context for signal handlers. 2 * Save/restore floating point context for signal handlers.
6 * 3 *
7 * This file is subject to the terms and conditions of the GNU General Public 4 * This file is subject to the terms and conditions of the GNU General Public
@@ -9,15 +6,16 @@
9 * for more details. 6 * for more details.
10 * 7 *
11 * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka 8 * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka
9 * Copyright (C) 2006 ST Microelectronics Ltd. (denorm support)
12 * 10 *
13 * FIXME! These routines can be optimized in big endian case. 11 * FIXME! These routines have not been tested for big endian case.
14 */ 12 */
15
16#include <linux/sched.h> 13#include <linux/sched.h>
17#include <linux/signal.h> 14#include <linux/signal.h>
15#include <linux/io.h>
16#include <asm/cpu/fpu.h>
18#include <asm/processor.h> 17#include <asm/processor.h>
19#include <asm/system.h> 18#include <asm/system.h>
20#include <asm/io.h>
21 19
22/* The PR (precision) bit in the FP Status Register must be clear when 20/* The PR (precision) bit in the FP Status Register must be clear when
23 * an frchg instruction is executed, otherwise the instruction is undefined. 21 * an frchg instruction is executed, otherwise the instruction is undefined.
@@ -25,113 +23,122 @@
25 */ 23 */
26 24
27#define FPSCR_RCHG 0x00000000 25#define FPSCR_RCHG 0x00000000
26extern unsigned long long float64_div(unsigned long long a,
27 unsigned long long b);
28extern unsigned long int float32_div(unsigned long int a, unsigned long int b);
29extern unsigned long long float64_mul(unsigned long long a,
30 unsigned long long b);
31extern unsigned long int float32_mul(unsigned long int a, unsigned long int b);
32extern unsigned long long float64_add(unsigned long long a,
33 unsigned long long b);
34extern unsigned long int float32_add(unsigned long int a, unsigned long int b);
35extern unsigned long long float64_sub(unsigned long long a,
36 unsigned long long b);
37extern unsigned long int float32_sub(unsigned long int a, unsigned long int b);
28 38
39static unsigned int fpu_exception_flags;
29 40
30/* 41/*
31 * Save FPU registers onto task structure. 42 * Save FPU registers onto task structure.
32 * Assume called with FPU enabled (SR.FD=0). 43 * Assume called with FPU enabled (SR.FD=0).
33 */ 44 */
34void 45void save_fpu(struct task_struct *tsk, struct pt_regs *regs)
35save_fpu(struct task_struct *tsk, struct pt_regs *regs)
36{ 46{
37 unsigned long dummy; 47 unsigned long dummy;
38 48
39 clear_tsk_thread_flag(tsk, TIF_USEDFPU); 49 clear_tsk_thread_flag(tsk, TIF_USEDFPU);
40 enable_fpu(); 50 enable_fpu();
41 asm volatile("sts.l fpul, @-%0\n\t" 51 asm volatile ("sts.l fpul, @-%0\n\t"
42 "sts.l fpscr, @-%0\n\t" 52 "sts.l fpscr, @-%0\n\t"
43 "lds %2, fpscr\n\t" 53 "lds %2, fpscr\n\t"
44 "frchg\n\t" 54 "frchg\n\t"
45 "fmov.s fr15, @-%0\n\t" 55 "fmov.s fr15, @-%0\n\t"
46 "fmov.s fr14, @-%0\n\t" 56 "fmov.s fr14, @-%0\n\t"
47 "fmov.s fr13, @-%0\n\t" 57 "fmov.s fr13, @-%0\n\t"
48 "fmov.s fr12, @-%0\n\t" 58 "fmov.s fr12, @-%0\n\t"
49 "fmov.s fr11, @-%0\n\t" 59 "fmov.s fr11, @-%0\n\t"
50 "fmov.s fr10, @-%0\n\t" 60 "fmov.s fr10, @-%0\n\t"
51 "fmov.s fr9, @-%0\n\t" 61 "fmov.s fr9, @-%0\n\t"
52 "fmov.s fr8, @-%0\n\t" 62 "fmov.s fr8, @-%0\n\t"
53 "fmov.s fr7, @-%0\n\t" 63 "fmov.s fr7, @-%0\n\t"
54 "fmov.s fr6, @-%0\n\t" 64 "fmov.s fr6, @-%0\n\t"
55 "fmov.s fr5, @-%0\n\t" 65 "fmov.s fr5, @-%0\n\t"
56 "fmov.s fr4, @-%0\n\t" 66 "fmov.s fr4, @-%0\n\t"
57 "fmov.s fr3, @-%0\n\t" 67 "fmov.s fr3, @-%0\n\t"
58 "fmov.s fr2, @-%0\n\t" 68 "fmov.s fr2, @-%0\n\t"
59 "fmov.s fr1, @-%0\n\t" 69 "fmov.s fr1, @-%0\n\t"
60 "fmov.s fr0, @-%0\n\t" 70 "fmov.s fr0, @-%0\n\t"
61 "frchg\n\t" 71 "frchg\n\t"
62 "fmov.s fr15, @-%0\n\t" 72 "fmov.s fr15, @-%0\n\t"
63 "fmov.s fr14, @-%0\n\t" 73 "fmov.s fr14, @-%0\n\t"
64 "fmov.s fr13, @-%0\n\t" 74 "fmov.s fr13, @-%0\n\t"
65 "fmov.s fr12, @-%0\n\t" 75 "fmov.s fr12, @-%0\n\t"
66 "fmov.s fr11, @-%0\n\t" 76 "fmov.s fr11, @-%0\n\t"
67 "fmov.s fr10, @-%0\n\t" 77 "fmov.s fr10, @-%0\n\t"
68 "fmov.s fr9, @-%0\n\t" 78 "fmov.s fr9, @-%0\n\t"
69 "fmov.s fr8, @-%0\n\t" 79 "fmov.s fr8, @-%0\n\t"
70 "fmov.s fr7, @-%0\n\t" 80 "fmov.s fr7, @-%0\n\t"
71 "fmov.s fr6, @-%0\n\t" 81 "fmov.s fr6, @-%0\n\t"
72 "fmov.s fr5, @-%0\n\t" 82 "fmov.s fr5, @-%0\n\t"
73 "fmov.s fr4, @-%0\n\t" 83 "fmov.s fr4, @-%0\n\t"
74 "fmov.s fr3, @-%0\n\t" 84 "fmov.s fr3, @-%0\n\t"
75 "fmov.s fr2, @-%0\n\t" 85 "fmov.s fr2, @-%0\n\t"
76 "fmov.s fr1, @-%0\n\t" 86 "fmov.s fr1, @-%0\n\t"
77 "fmov.s fr0, @-%0\n\t" 87 "fmov.s fr0, @-%0\n\t"
78 "lds %3, fpscr\n\t" 88 "lds %3, fpscr\n\t":"=r" (dummy)
79 : "=r" (dummy) 89 :"0"((char *)(&tsk->thread.fpu.hard.status)),
80 : "0" ((char *)(&tsk->thread.fpu.hard.status)), 90 "r"(FPSCR_RCHG), "r"(FPSCR_INIT)
81 "r" (FPSCR_RCHG), 91 :"memory");
82 "r" (FPSCR_INIT)
83 : "memory");
84 92
85 disable_fpu(); 93 disable_fpu();
86 release_fpu(regs); 94 release_fpu(regs);
87} 95}
88 96
89static void 97static void restore_fpu(struct task_struct *tsk)
90restore_fpu(struct task_struct *tsk)
91{ 98{
92 unsigned long dummy; 99 unsigned long dummy;
93 100
94 enable_fpu(); 101 enable_fpu();
95 asm volatile("lds %2, fpscr\n\t" 102 asm volatile ("lds %2, fpscr\n\t"
96 "fmov.s @%0+, fr0\n\t" 103 "fmov.s @%0+, fr0\n\t"
97 "fmov.s @%0+, fr1\n\t" 104 "fmov.s @%0+, fr1\n\t"
98 "fmov.s @%0+, fr2\n\t" 105 "fmov.s @%0+, fr2\n\t"
99 "fmov.s @%0+, fr3\n\t" 106 "fmov.s @%0+, fr3\n\t"
100 "fmov.s @%0+, fr4\n\t" 107 "fmov.s @%0+, fr4\n\t"
101 "fmov.s @%0+, fr5\n\t" 108 "fmov.s @%0+, fr5\n\t"
102 "fmov.s @%0+, fr6\n\t" 109 "fmov.s @%0+, fr6\n\t"
103 "fmov.s @%0+, fr7\n\t" 110 "fmov.s @%0+, fr7\n\t"
104 "fmov.s @%0+, fr8\n\t" 111 "fmov.s @%0+, fr8\n\t"
105 "fmov.s @%0+, fr9\n\t" 112 "fmov.s @%0+, fr9\n\t"
106 "fmov.s @%0+, fr10\n\t" 113 "fmov.s @%0+, fr10\n\t"
107 "fmov.s @%0+, fr11\n\t" 114 "fmov.s @%0+, fr11\n\t"
108 "fmov.s @%0+, fr12\n\t" 115 "fmov.s @%0+, fr12\n\t"
109 "fmov.s @%0+, fr13\n\t" 116 "fmov.s @%0+, fr13\n\t"
110 "fmov.s @%0+, fr14\n\t" 117 "fmov.s @%0+, fr14\n\t"
111 "fmov.s @%0+, fr15\n\t" 118 "fmov.s @%0+, fr15\n\t"
112 "frchg\n\t" 119 "frchg\n\t"
113 "fmov.s @%0+, fr0\n\t" 120 "fmov.s @%0+, fr0\n\t"
114 "fmov.s @%0+, fr1\n\t" 121 "fmov.s @%0+, fr1\n\t"
115 "fmov.s @%0+, fr2\n\t" 122 "fmov.s @%0+, fr2\n\t"
116 "fmov.s @%0+, fr3\n\t" 123 "fmov.s @%0+, fr3\n\t"
117 "fmov.s @%0+, fr4\n\t" 124 "fmov.s @%0+, fr4\n\t"
118 "fmov.s @%0+, fr5\n\t" 125 "fmov.s @%0+, fr5\n\t"
119 "fmov.s @%0+, fr6\n\t" 126 "fmov.s @%0+, fr6\n\t"
120 "fmov.s @%0+, fr7\n\t" 127 "fmov.s @%0+, fr7\n\t"
121 "fmov.s @%0+, fr8\n\t" 128 "fmov.s @%0+, fr8\n\t"
122 "fmov.s @%0+, fr9\n\t" 129 "fmov.s @%0+, fr9\n\t"
123 "fmov.s @%0+, fr10\n\t" 130 "fmov.s @%0+, fr10\n\t"
124 "fmov.s @%0+, fr11\n\t" 131 "fmov.s @%0+, fr11\n\t"
125 "fmov.s @%0+, fr12\n\t" 132 "fmov.s @%0+, fr12\n\t"
126 "fmov.s @%0+, fr13\n\t" 133 "fmov.s @%0+, fr13\n\t"
127 "fmov.s @%0+, fr14\n\t" 134 "fmov.s @%0+, fr14\n\t"
128 "fmov.s @%0+, fr15\n\t" 135 "fmov.s @%0+, fr15\n\t"
129 "frchg\n\t" 136 "frchg\n\t"
130 "lds.l @%0+, fpscr\n\t" 137 "lds.l @%0+, fpscr\n\t"
131 "lds.l @%0+, fpul\n\t" 138 "lds.l @%0+, fpul\n\t"
132 : "=r" (dummy) 139 :"=r" (dummy)
133 : "0" (&tsk->thread.fpu), "r" (FPSCR_RCHG) 140 :"0"(&tsk->thread.fpu), "r"(FPSCR_RCHG)
134 : "memory"); 141 :"memory");
135 disable_fpu(); 142 disable_fpu();
136} 143}
137 144
@@ -141,61 +148,59 @@ restore_fpu(struct task_struct *tsk)
141 * double precision represents signaling NANS. 148 * double precision represents signaling NANS.
142 */ 149 */
143 150
144static void 151static void fpu_init(void)
145fpu_init(void)
146{ 152{
147 enable_fpu(); 153 enable_fpu();
148 asm volatile("lds %0, fpul\n\t" 154 asm volatile ( "lds %0, fpul\n\t"
149 "lds %1, fpscr\n\t" 155 "lds %1, fpscr\n\t"
150 "fsts fpul, fr0\n\t" 156 "fsts fpul, fr0\n\t"
151 "fsts fpul, fr1\n\t" 157 "fsts fpul, fr1\n\t"
152 "fsts fpul, fr2\n\t" 158 "fsts fpul, fr2\n\t"
153 "fsts fpul, fr3\n\t" 159 "fsts fpul, fr3\n\t"
154 "fsts fpul, fr4\n\t" 160 "fsts fpul, fr4\n\t"
155 "fsts fpul, fr5\n\t" 161 "fsts fpul, fr5\n\t"
156 "fsts fpul, fr6\n\t" 162 "fsts fpul, fr6\n\t"
157 "fsts fpul, fr7\n\t" 163 "fsts fpul, fr7\n\t"
158 "fsts fpul, fr8\n\t" 164 "fsts fpul, fr8\n\t"
159 "fsts fpul, fr9\n\t" 165 "fsts fpul, fr9\n\t"
160 "fsts fpul, fr10\n\t" 166 "fsts fpul, fr10\n\t"
161 "fsts fpul, fr11\n\t" 167 "fsts fpul, fr11\n\t"
162 "fsts fpul, fr12\n\t" 168 "fsts fpul, fr12\n\t"
163 "fsts fpul, fr13\n\t" 169 "fsts fpul, fr13\n\t"
164 "fsts fpul, fr14\n\t" 170 "fsts fpul, fr14\n\t"
165 "fsts fpul, fr15\n\t" 171 "fsts fpul, fr15\n\t"
166 "frchg\n\t" 172 "frchg\n\t"
167 "fsts fpul, fr0\n\t" 173 "fsts fpul, fr0\n\t"
168 "fsts fpul, fr1\n\t" 174 "fsts fpul, fr1\n\t"
169 "fsts fpul, fr2\n\t" 175 "fsts fpul, fr2\n\t"
170 "fsts fpul, fr3\n\t" 176 "fsts fpul, fr3\n\t"
171 "fsts fpul, fr4\n\t" 177 "fsts fpul, fr4\n\t"
172 "fsts fpul, fr5\n\t" 178 "fsts fpul, fr5\n\t"
173 "fsts fpul, fr6\n\t" 179 "fsts fpul, fr6\n\t"
174 "fsts fpul, fr7\n\t" 180 "fsts fpul, fr7\n\t"
175 "fsts fpul, fr8\n\t" 181 "fsts fpul, fr8\n\t"
176 "fsts fpul, fr9\n\t" 182 "fsts fpul, fr9\n\t"
177 "fsts fpul, fr10\n\t" 183 "fsts fpul, fr10\n\t"
178 "fsts fpul, fr11\n\t" 184 "fsts fpul, fr11\n\t"
179 "fsts fpul, fr12\n\t" 185 "fsts fpul, fr12\n\t"
180 "fsts fpul, fr13\n\t" 186 "fsts fpul, fr13\n\t"
181 "fsts fpul, fr14\n\t" 187 "fsts fpul, fr14\n\t"
182 "fsts fpul, fr15\n\t" 188 "fsts fpul, fr15\n\t"
183 "frchg\n\t" 189 "frchg\n\t"
184 "lds %2, fpscr\n\t" 190 "lds %2, fpscr\n\t"
185 : /* no output */ 191 : /* no output */
186 : "r" (0), "r" (FPSCR_RCHG), "r" (FPSCR_INIT)); 192 :"r" (0), "r"(FPSCR_RCHG), "r"(FPSCR_INIT));
187 disable_fpu(); 193 disable_fpu();
188} 194}
189 195
190/** 196/**
191 * denormal_to_double - Given denormalized float number, 197 * denormal_to_double - Given denormalized float number,
192 * store double float 198 * store double float
193 * 199 *
194 * @fpu: Pointer to sh_fpu_hard structure 200 * @fpu: Pointer to sh_fpu_hard structure
195 * @n: Index to FP register 201 * @n: Index to FP register
196 */ 202 */
197static void 203static void denormal_to_double(struct sh_fpu_hard_struct *fpu, int n)
198denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
199{ 204{
200 unsigned long du, dl; 205 unsigned long du, dl;
201 unsigned long x = fpu->fpul; 206 unsigned long x = fpu->fpul;
@@ -212,7 +217,7 @@ denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
212 dl = x << 29; 217 dl = x << 29;
213 218
214 fpu->fp_regs[n] = du; 219 fpu->fp_regs[n] = du;
215 fpu->fp_regs[n+1] = dl; 220 fpu->fp_regs[n + 1] = dl;
216 } 221 }
217} 222}
218 223
@@ -223,67 +228,191 @@ denormal_to_double (struct sh_fpu_hard_struct *fpu, int n)
223 * 228 *
224 * Returns 1 when it's handled (should not cause exception). 229 * Returns 1 when it's handled (should not cause exception).
225 */ 230 */
226static int 231static int ieee_fpe_handler(struct pt_regs *regs)
227ieee_fpe_handler (struct pt_regs *regs)
228{ 232{
229 unsigned short insn = *(unsigned short *) regs->pc; 233 unsigned short insn = *(unsigned short *)regs->pc;
230 unsigned short finsn; 234 unsigned short finsn;
231 unsigned long nextpc; 235 unsigned long nextpc;
232 int nib[4] = { 236 int nib[4] = {
233 (insn >> 12) & 0xf, 237 (insn >> 12) & 0xf,
234 (insn >> 8) & 0xf, 238 (insn >> 8) & 0xf,
235 (insn >> 4) & 0xf, 239 (insn >> 4) & 0xf,
236 insn & 0xf}; 240 insn & 0xf
237 241 };
238 if (nib[0] == 0xb || 242
239 (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */ 243 if (nib[0] == 0xb || (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb))
240 regs->pr = regs->pc + 4; 244 regs->pr = regs->pc + 4; /* bsr & jsr */
241 if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */ 245
242 nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3); 246 if (nib[0] == 0xa || nib[0] == 0xb) {
243 finsn = *(unsigned short *) (regs->pc + 2); 247 /* bra & bsr */
244 } else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */ 248 nextpc = regs->pc + 4 + ((short)((insn & 0xfff) << 4) >> 3);
249 finsn = *(unsigned short *)(regs->pc + 2);
250 } else if (nib[0] == 0x8 && nib[1] == 0xd) {
251 /* bt/s */
245 if (regs->sr & 1) 252 if (regs->sr & 1)
246 nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); 253 nextpc = regs->pc + 4 + ((char)(insn & 0xff) << 1);
247 else 254 else
248 nextpc = regs->pc + 4; 255 nextpc = regs->pc + 4;
249 finsn = *(unsigned short *) (regs->pc + 2); 256 finsn = *(unsigned short *)(regs->pc + 2);
250 } else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */ 257 } else if (nib[0] == 0x8 && nib[1] == 0xf) {
258 /* bf/s */
251 if (regs->sr & 1) 259 if (regs->sr & 1)
252 nextpc = regs->pc + 4; 260 nextpc = regs->pc + 4;
253 else 261 else
254 nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1); 262 nextpc = regs->pc + 4 + ((char)(insn & 0xff) << 1);
255 finsn = *(unsigned short *) (regs->pc + 2); 263 finsn = *(unsigned short *)(regs->pc + 2);
256 } else if (nib[0] == 0x4 && nib[3] == 0xb && 264 } else if (nib[0] == 0x4 && nib[3] == 0xb &&
257 (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */ 265 (nib[2] == 0x0 || nib[2] == 0x2)) {
266 /* jmp & jsr */
258 nextpc = regs->regs[nib[1]]; 267 nextpc = regs->regs[nib[1]];
259 finsn = *(unsigned short *) (regs->pc + 2); 268 finsn = *(unsigned short *)(regs->pc + 2);
260 } else if (nib[0] == 0x0 && nib[3] == 0x3 && 269 } else if (nib[0] == 0x0 && nib[3] == 0x3 &&
261 (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */ 270 (nib[2] == 0x0 || nib[2] == 0x2)) {
271 /* braf & bsrf */
262 nextpc = regs->pc + 4 + regs->regs[nib[1]]; 272 nextpc = regs->pc + 4 + regs->regs[nib[1]];
263 finsn = *(unsigned short *) (regs->pc + 2); 273 finsn = *(unsigned short *)(regs->pc + 2);
264 } else if (insn == 0x000b) { /* rts */ 274 } else if (insn == 0x000b) {
275 /* rts */
265 nextpc = regs->pr; 276 nextpc = regs->pr;
266 finsn = *(unsigned short *) (regs->pc + 2); 277 finsn = *(unsigned short *)(regs->pc + 2);
267 } else { 278 } else {
268 nextpc = regs->pc + instruction_size(insn); 279 nextpc = regs->pc + instruction_size(insn);
269 finsn = insn; 280 finsn = insn;
270 } 281 }
271 282
272 if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */ 283 if ((finsn & 0xf1ff) == 0xf0ad) {
284 /* fcnvsd */
273 struct task_struct *tsk = current; 285 struct task_struct *tsk = current;
274 286
275 save_fpu(tsk, regs); 287 save_fpu(tsk, regs);
276 if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) { 288 if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR))
277 /* FPU error */ 289 /* FPU error */
278 denormal_to_double (&tsk->thread.fpu.hard, 290 denormal_to_double(&tsk->thread.fpu.hard,
279 (finsn >> 8) & 0xf); 291 (finsn >> 8) & 0xf);
280 tsk->thread.fpu.hard.fpscr &= 292 else
281 ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); 293 return 0;
282 grab_fpu(regs); 294
283 restore_fpu(tsk); 295 regs->pc = nextpc;
284 set_tsk_thread_flag(tsk, TIF_USEDFPU); 296 return 1;
297 } else if ((finsn & 0xf00f) == 0xf002) {
298 /* fmul */
299 struct task_struct *tsk = current;
300 int fpscr;
301 int n, m, prec;
302 unsigned int hx, hy;
303
304 n = (finsn >> 8) & 0xf;
305 m = (finsn >> 4) & 0xf;
306 hx = tsk->thread.fpu.hard.fp_regs[n];
307 hy = tsk->thread.fpu.hard.fp_regs[m];
308 fpscr = tsk->thread.fpu.hard.fpscr;
309 prec = fpscr & FPSCR_DBL_PRECISION;
310
311 if ((fpscr & FPSCR_CAUSE_ERROR)
312 && (prec && ((hx & 0x7fffffff) < 0x00100000
313 || (hy & 0x7fffffff) < 0x00100000))) {
314 long long llx, lly;
315
316 /* FPU error because of denormal (doubles) */
317 llx = ((long long)hx << 32)
318 | tsk->thread.fpu.hard.fp_regs[n + 1];
319 lly = ((long long)hy << 32)
320 | tsk->thread.fpu.hard.fp_regs[m + 1];
321 llx = float64_mul(llx, lly);
322 tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
323 tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
324 } else if ((fpscr & FPSCR_CAUSE_ERROR)
325 && (!prec && ((hx & 0x7fffffff) < 0x00800000
326 || (hy & 0x7fffffff) < 0x00800000))) {
327 /* FPU error because of denormal (floats) */
328 hx = float32_mul(hx, hy);
329 tsk->thread.fpu.hard.fp_regs[n] = hx;
330 } else
331 return 0;
332
333 regs->pc = nextpc;
334 return 1;
335 } else if ((finsn & 0xf00e) == 0xf000) {
336 /* fadd, fsub */
337 struct task_struct *tsk = current;
338 int fpscr;
339 int n, m, prec;
340 unsigned int hx, hy;
341
342 n = (finsn >> 8) & 0xf;
343 m = (finsn >> 4) & 0xf;
344 hx = tsk->thread.fpu.hard.fp_regs[n];
345 hy = tsk->thread.fpu.hard.fp_regs[m];
346 fpscr = tsk->thread.fpu.hard.fpscr;
347 prec = fpscr & FPSCR_DBL_PRECISION;
348
349 if ((fpscr & FPSCR_CAUSE_ERROR)
350 && (prec && ((hx & 0x7fffffff) < 0x00100000
351 || (hy & 0x7fffffff) < 0x00100000))) {
352 long long llx, lly;
353
354 /* FPU error because of denormal (doubles) */
355 llx = ((long long)hx << 32)
356 | tsk->thread.fpu.hard.fp_regs[n + 1];
357 lly = ((long long)hy << 32)
358 | tsk->thread.fpu.hard.fp_regs[m + 1];
359 if ((finsn & 0xf00f) == 0xf000)
360 llx = float64_add(llx, lly);
361 else
362 llx = float64_sub(llx, lly);
363 tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
364 tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
365 } else if ((fpscr & FPSCR_CAUSE_ERROR)
366 && (!prec && ((hx & 0x7fffffff) < 0x00800000
367 || (hy & 0x7fffffff) < 0x00800000))) {
368 /* FPU error because of denormal (floats) */
369 if ((finsn & 0xf00f) == 0xf000)
370 hx = float32_add(hx, hy);
371 else
372 hx = float32_sub(hx, hy);
373 tsk->thread.fpu.hard.fp_regs[n] = hx;
374 } else
375 return 0;
376
377 regs->pc = nextpc;
378 return 1;
379 } else if ((finsn & 0xf003) == 0xf003) {
380 /* fdiv */
381 struct task_struct *tsk = current;
382 int fpscr;
383 int n, m, prec;
384 unsigned int hx, hy;
385
386 n = (finsn >> 8) & 0xf;
387 m = (finsn >> 4) & 0xf;
388 hx = tsk->thread.fpu.hard.fp_regs[n];
389 hy = tsk->thread.fpu.hard.fp_regs[m];
390 fpscr = tsk->thread.fpu.hard.fpscr;
391 prec = fpscr & FPSCR_DBL_PRECISION;
392
393 if ((fpscr & FPSCR_CAUSE_ERROR)
394 && (prec && ((hx & 0x7fffffff) < 0x00100000
395 || (hy & 0x7fffffff) < 0x00100000))) {
396 long long llx, lly;
397
398 /* FPU error because of denormal (doubles) */
399 llx = ((long long)hx << 32)
400 | tsk->thread.fpu.hard.fp_regs[n + 1];
401 lly = ((long long)hy << 32)
402 | tsk->thread.fpu.hard.fp_regs[m + 1];
403
404 llx = float64_div(llx, lly);
405
406 tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
407 tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
408 } else if ((fpscr & FPSCR_CAUSE_ERROR)
409 && (!prec && ((hx & 0x7fffffff) < 0x00800000
410 || (hy & 0x7fffffff) < 0x00800000))) {
411 /* FPU error because of denormal (floats) */
412 hx = float32_div(hx, hy);
413 tsk->thread.fpu.hard.fp_regs[n] = hx;
285 } else 414 } else
286 force_sig(SIGFPE, tsk); 415 return 0;
287 416
288 regs->pc = nextpc; 417 regs->pc = nextpc;
289 return 1; 418 return 1;
@@ -292,16 +421,41 @@ ieee_fpe_handler (struct pt_regs *regs)
292 return 0; 421 return 0;
293} 422}
294 423
424void float_raise(unsigned int flags)
425{
426 fpu_exception_flags |= flags;
427}
428
429int float_rounding_mode(void)
430{
431 struct task_struct *tsk = current;
432 int roundingMode = FPSCR_ROUNDING_MODE(tsk->thread.fpu.hard.fpscr);
433 return roundingMode;
434}
435
295BUILD_TRAP_HANDLER(fpu_error) 436BUILD_TRAP_HANDLER(fpu_error)
296{ 437{
297 struct task_struct *tsk = current; 438 struct task_struct *tsk = current;
298 TRAP_HANDLER_DECL; 439 TRAP_HANDLER_DECL;
299 440
300 if (ieee_fpe_handler(regs))
301 return;
302
303 regs->pc += 2;
304 save_fpu(tsk, regs); 441 save_fpu(tsk, regs);
442 fpu_exception_flags = 0;
443 if (ieee_fpe_handler(regs)) {
444 tsk->thread.fpu.hard.fpscr &=
445 ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
446 tsk->thread.fpu.hard.fpscr |= fpu_exception_flags;
447 /* Set the FPSCR flag as well as cause bits - simply
448 * replicate the cause */
449 tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10);
450 grab_fpu(regs);
451 restore_fpu(tsk);
452 set_tsk_thread_flag(tsk, TIF_USEDFPU);
453 if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) &
454 (fpu_exception_flags >> 2)) == 0) {
455 return;
456 }
457 }
458
305 force_sig(SIGFPE, tsk); 459 force_sig(SIGFPE, tsk);
306} 460}
307 461
@@ -319,7 +473,7 @@ BUILD_TRAP_HANDLER(fpu_state_restore)
319 if (used_math()) { 473 if (used_math()) {
320 /* Using the FPU again. */ 474 /* Using the FPU again. */
321 restore_fpu(tsk); 475 restore_fpu(tsk);
322 } else { 476 } else {
323 /* First time FPU user. */ 477 /* First time FPU user. */
324 fpu_init(); 478 fpu_init();
325 set_used_math(); 479 set_used_math();