diff options
Diffstat (limited to 'arch/sh/kernel/cpu/sh5/fpu.c')
-rw-r--r-- | arch/sh/kernel/cpu/sh5/fpu.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/arch/sh/kernel/cpu/sh5/fpu.c b/arch/sh/kernel/cpu/sh5/fpu.c new file mode 100644 index 000000000000..30b76a94abf2 --- /dev/null +++ b/arch/sh/kernel/cpu/sh5/fpu.c | |||
@@ -0,0 +1,166 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh5/fpu.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Manuela Cirronis, Paolo Alberelli | ||
5 | * Copyright (C) 2002 STMicroelectronics Limited | ||
6 | * Author : Stuart Menefy | ||
7 | * | ||
8 | * Started from SH4 version: | ||
9 | * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | */ | ||
15 | #include <linux/sched.h> | ||
16 | #include <linux/signal.h> | ||
17 | #include <asm/processor.h> | ||
18 | #include <asm/user.h> | ||
19 | #include <asm/io.h> | ||
20 | |||
21 | /* | ||
22 | * Initially load the FPU with signalling NANS. This bit pattern | ||
23 | * has the property that no matter whether considered as single or as | ||
24 | * double precision, it still represents a signalling NAN. | ||
25 | */ | ||
26 | #define sNAN64 0xFFFFFFFFFFFFFFFFULL | ||
27 | #define sNAN32 0xFFFFFFFFUL | ||
28 | |||
29 | static union sh_fpu_union init_fpuregs = { | ||
30 | .hard = { | ||
31 | .fp_regs = { [0 ... 63] = sNAN32 }, | ||
32 | .fpscr = FPSCR_INIT | ||
33 | } | ||
34 | }; | ||
35 | |||
36 | void save_fpu(struct task_struct *tsk, struct pt_regs *regs) | ||
37 | { | ||
38 | asm volatile("fst.p %0, (0*8), fp0\n\t" | ||
39 | "fst.p %0, (1*8), fp2\n\t" | ||
40 | "fst.p %0, (2*8), fp4\n\t" | ||
41 | "fst.p %0, (3*8), fp6\n\t" | ||
42 | "fst.p %0, (4*8), fp8\n\t" | ||
43 | "fst.p %0, (5*8), fp10\n\t" | ||
44 | "fst.p %0, (6*8), fp12\n\t" | ||
45 | "fst.p %0, (7*8), fp14\n\t" | ||
46 | "fst.p %0, (8*8), fp16\n\t" | ||
47 | "fst.p %0, (9*8), fp18\n\t" | ||
48 | "fst.p %0, (10*8), fp20\n\t" | ||
49 | "fst.p %0, (11*8), fp22\n\t" | ||
50 | "fst.p %0, (12*8), fp24\n\t" | ||
51 | "fst.p %0, (13*8), fp26\n\t" | ||
52 | "fst.p %0, (14*8), fp28\n\t" | ||
53 | "fst.p %0, (15*8), fp30\n\t" | ||
54 | "fst.p %0, (16*8), fp32\n\t" | ||
55 | "fst.p %0, (17*8), fp34\n\t" | ||
56 | "fst.p %0, (18*8), fp36\n\t" | ||
57 | "fst.p %0, (19*8), fp38\n\t" | ||
58 | "fst.p %0, (20*8), fp40\n\t" | ||
59 | "fst.p %0, (21*8), fp42\n\t" | ||
60 | "fst.p %0, (22*8), fp44\n\t" | ||
61 | "fst.p %0, (23*8), fp46\n\t" | ||
62 | "fst.p %0, (24*8), fp48\n\t" | ||
63 | "fst.p %0, (25*8), fp50\n\t" | ||
64 | "fst.p %0, (26*8), fp52\n\t" | ||
65 | "fst.p %0, (27*8), fp54\n\t" | ||
66 | "fst.p %0, (28*8), fp56\n\t" | ||
67 | "fst.p %0, (29*8), fp58\n\t" | ||
68 | "fst.p %0, (30*8), fp60\n\t" | ||
69 | "fst.p %0, (31*8), fp62\n\t" | ||
70 | |||
71 | "fgetscr fr63\n\t" | ||
72 | "fst.s %0, (32*8), fr63\n\t" | ||
73 | : /* no output */ | ||
74 | : "r" (&tsk->thread.fpu.hard) | ||
75 | : "memory"); | ||
76 | } | ||
77 | |||
78 | static inline void | ||
79 | fpload(struct sh_fpu_hard_struct *fpregs) | ||
80 | { | ||
81 | asm volatile("fld.p %0, (0*8), fp0\n\t" | ||
82 | "fld.p %0, (1*8), fp2\n\t" | ||
83 | "fld.p %0, (2*8), fp4\n\t" | ||
84 | "fld.p %0, (3*8), fp6\n\t" | ||
85 | "fld.p %0, (4*8), fp8\n\t" | ||
86 | "fld.p %0, (5*8), fp10\n\t" | ||
87 | "fld.p %0, (6*8), fp12\n\t" | ||
88 | "fld.p %0, (7*8), fp14\n\t" | ||
89 | "fld.p %0, (8*8), fp16\n\t" | ||
90 | "fld.p %0, (9*8), fp18\n\t" | ||
91 | "fld.p %0, (10*8), fp20\n\t" | ||
92 | "fld.p %0, (11*8), fp22\n\t" | ||
93 | "fld.p %0, (12*8), fp24\n\t" | ||
94 | "fld.p %0, (13*8), fp26\n\t" | ||
95 | "fld.p %0, (14*8), fp28\n\t" | ||
96 | "fld.p %0, (15*8), fp30\n\t" | ||
97 | "fld.p %0, (16*8), fp32\n\t" | ||
98 | "fld.p %0, (17*8), fp34\n\t" | ||
99 | "fld.p %0, (18*8), fp36\n\t" | ||
100 | "fld.p %0, (19*8), fp38\n\t" | ||
101 | "fld.p %0, (20*8), fp40\n\t" | ||
102 | "fld.p %0, (21*8), fp42\n\t" | ||
103 | "fld.p %0, (22*8), fp44\n\t" | ||
104 | "fld.p %0, (23*8), fp46\n\t" | ||
105 | "fld.p %0, (24*8), fp48\n\t" | ||
106 | "fld.p %0, (25*8), fp50\n\t" | ||
107 | "fld.p %0, (26*8), fp52\n\t" | ||
108 | "fld.p %0, (27*8), fp54\n\t" | ||
109 | "fld.p %0, (28*8), fp56\n\t" | ||
110 | "fld.p %0, (29*8), fp58\n\t" | ||
111 | "fld.p %0, (30*8), fp60\n\t" | ||
112 | |||
113 | "fld.s %0, (32*8), fr63\n\t" | ||
114 | "fputscr fr63\n\t" | ||
115 | |||
116 | "fld.p %0, (31*8), fp62\n\t" | ||
117 | : /* no output */ | ||
118 | : "r" (fpregs) ); | ||
119 | } | ||
120 | |||
121 | void fpinit(struct sh_fpu_hard_struct *fpregs) | ||
122 | { | ||
123 | *fpregs = init_fpuregs.hard; | ||
124 | } | ||
125 | |||
126 | asmlinkage void | ||
127 | do_fpu_error(unsigned long ex, struct pt_regs *regs) | ||
128 | { | ||
129 | struct task_struct *tsk = current; | ||
130 | |||
131 | regs->pc += 4; | ||
132 | |||
133 | tsk->thread.trap_no = 11; | ||
134 | tsk->thread.error_code = 0; | ||
135 | force_sig(SIGFPE, tsk); | ||
136 | } | ||
137 | |||
138 | |||
139 | asmlinkage void | ||
140 | do_fpu_state_restore(unsigned long ex, struct pt_regs *regs) | ||
141 | { | ||
142 | void die(const char *str, struct pt_regs *regs, long err); | ||
143 | |||
144 | if (! user_mode(regs)) | ||
145 | die("FPU used in kernel", regs, ex); | ||
146 | |||
147 | regs->sr &= ~SR_FD; | ||
148 | |||
149 | if (last_task_used_math == current) | ||
150 | return; | ||
151 | |||
152 | enable_fpu(); | ||
153 | if (last_task_used_math != NULL) | ||
154 | /* Other processes fpu state, save away */ | ||
155 | save_fpu(last_task_used_math, regs); | ||
156 | |||
157 | last_task_used_math = current; | ||
158 | if (used_math()) { | ||
159 | fpload(¤t->thread.fpu.hard); | ||
160 | } else { | ||
161 | /* First time FPU user. */ | ||
162 | fpload(&init_fpuregs.hard); | ||
163 | set_used_math(); | ||
164 | } | ||
165 | disable_fpu(); | ||
166 | } | ||