This source file includes following definitions.
- alpha_read_fp_reg
- alpha_write_fp_reg
- alpha_fp_emul
- alpha_fp_emul_imprecise
1 #include <linux/types.h>
2
3 #include <linux/kernel.h>
4 #include <linux/sched.h>
5
6 #include <asm/segment.h>
7
8 #include "ieee-math.h"
9
10 #define OPC_PAL 0x00
11
12 #define OPC_INTA 0x10
13 #define OPC_INTL 0x11
14 #define OPC_INTS 0x12
15 #define OPC_INTM 0x13
16 #define OPC_FLTV 0x14
17 #define OPC_FLTI 0x15
18 #define OPC_FLTL 0x16
19
20 #define OPC_MISC 0x18
21
22 #define OPC_JSR 0x1a
23
24
25
26
27
28
29
30
31
32
33 #define FLTI_FUNC_ADDS 0x000
34 #define FLTI_FUNC_ADDT 0x020
35 #define FLTI_FUNC_CMPTEQ 0x025
36 #define FLTI_FUNC_CMPTLT 0x026
37 #define FLTI_FUNC_CMPTLE 0x027
38 #define FLTI_FUNC_CMPTUN 0x024
39 #define FLTI_FUNC_CVTTS_or_CVTST 0x02c
40 #define FLTI_FUNC_CVTTQ 0x02f
41 #define FLTI_FUNC_CVTQS 0x03c
42 #define FLTI_FUNC_CVTQT 0x03e
43 #define FLTI_FUNC_DIVS 0x003
44 #define FLTI_FUNC_DIVT 0x023
45 #define FLTI_FUNC_MULS 0x002
46 #define FLTI_FUNC_MULT 0x022
47 #define FLTI_FUNC_SUBS 0x001
48 #define FLTI_FUNC_SUBT 0x021
49
50 #define FLTI_FUNC_CVTQL 0x030
51
52 #define MISC_TRAPB 0x0000
53 #define MISC_EXCB 0x0400
54
55
56 extern unsigned long rdfpcr (void);
57 extern void wrfpcr (unsigned long);
58
59
60 unsigned long
61 alpha_read_fp_reg (unsigned long reg)
62 {
63 unsigned long r;
64
65 switch (reg) {
66 case 0: asm ("stt $f0,%0" : "m="(r)); break;
67 case 1: asm ("stt $f1,%0" : "m="(r)); break;
68 case 2: asm ("stt $f2,%0" : "m="(r)); break;
69 case 3: asm ("stt $f3,%0" : "m="(r)); break;
70 case 4: asm ("stt $f4,%0" : "m="(r)); break;
71 case 5: asm ("stt $f5,%0" : "m="(r)); break;
72 case 6: asm ("stt $f6,%0" : "m="(r)); break;
73 case 7: asm ("stt $f7,%0" : "m="(r)); break;
74 case 8: asm ("stt $f8,%0" : "m="(r)); break;
75 case 9: asm ("stt $f9,%0" : "m="(r)); break;
76 case 10: asm ("stt $f10,%0" : "m="(r)); break;
77 case 11: asm ("stt $f11,%0" : "m="(r)); break;
78 case 12: asm ("stt $f12,%0" : "m="(r)); break;
79 case 13: asm ("stt $f13,%0" : "m="(r)); break;
80 case 14: asm ("stt $f14,%0" : "m="(r)); break;
81 case 15: asm ("stt $f15,%0" : "m="(r)); break;
82 case 16: asm ("stt $f16,%0" : "m="(r)); break;
83 case 17: asm ("stt $f17,%0" : "m="(r)); break;
84 case 18: asm ("stt $f18,%0" : "m="(r)); break;
85 case 19: asm ("stt $f19,%0" : "m="(r)); break;
86 case 20: asm ("stt $f20,%0" : "m="(r)); break;
87 case 21: asm ("stt $f21,%0" : "m="(r)); break;
88 case 22: asm ("stt $f22,%0" : "m="(r)); break;
89 case 23: asm ("stt $f23,%0" : "m="(r)); break;
90 case 24: asm ("stt $f24,%0" : "m="(r)); break;
91 case 25: asm ("stt $f25,%0" : "m="(r)); break;
92 case 26: asm ("stt $f26,%0" : "m="(r)); break;
93 case 27: asm ("stt $f27,%0" : "m="(r)); break;
94 case 28: asm ("stt $f28,%0" : "m="(r)); break;
95 case 29: asm ("stt $f29,%0" : "m="(r)); break;
96 case 30: asm ("stt $f30,%0" : "m="(r)); break;
97 case 31: asm ("stt $f31,%0" : "m="(r)); break;
98 default:
99 break;
100 }
101 return r;
102 }
103
104
105 #if 0
106
107
108
109
110
111
112 # define LDT(reg,val) \
113 asm volatile ("ldt $f"#reg",%0" :: "m"(val));
114 #else
115 # define LDT(reg,val) \
116 asm volatile ("ldt $f"#reg",0(%0)" :: "r"(&val));
117 #endif
118
119 void
120 alpha_write_fp_reg (unsigned long reg, unsigned long val)
121 {
122 switch (reg) {
123 case 0: LDT( 0, val); break;
124 case 1: LDT( 1, val); break;
125 case 2: LDT( 2, val); break;
126 case 3: LDT( 3, val); break;
127 case 4: LDT( 4, val); break;
128 case 5: LDT( 5, val); break;
129 case 6: LDT( 6, val); break;
130 case 7: LDT( 7, val); break;
131 case 8: LDT( 8, val); break;
132 case 9: LDT( 9, val); break;
133 case 10: LDT(10, val); break;
134 case 11: LDT(11, val); break;
135 case 12: LDT(12, val); break;
136 case 13: LDT(13, val); break;
137 case 14: LDT(14, val); break;
138 case 15: LDT(15, val); break;
139 case 16: LDT(16, val); break;
140 case 17: LDT(17, val); break;
141 case 18: LDT(18, val); break;
142 case 19: LDT(19, val); break;
143 case 20: LDT(20, val); break;
144 case 21: LDT(21, val); break;
145 case 22: LDT(22, val); break;
146 case 23: LDT(23, val); break;
147 case 24: LDT(24, val); break;
148 case 25: LDT(25, val); break;
149 case 26: LDT(26, val); break;
150 case 27: LDT(27, val); break;
151 case 28: LDT(28, val); break;
152 case 29: LDT(29, val); break;
153 case 30: LDT(30, val); break;
154 case 31: LDT(31, val); break;
155 default:
156 break;
157 }
158 }
159
160
161
162
163
164
165
166
167
168 long
169 alpha_fp_emul (unsigned long pc)
170 {
171 unsigned long opcode, fa, fb, fc, func, mode;
172 unsigned long fpcw = current->tss.flags;
173 unsigned long va, vb, vc, res, fpcr;
174 __u32 insn;
175
176 insn = get_user((__u32*)pc);
177 fc = (insn >> 0) & 0x1f;
178 func = (insn >> 5) & 0x7ff;
179 fb = (insn >> 16) & 0x1f;
180 fa = (insn >> 21) & 0x1f;
181 opcode = insn >> 26;
182
183 va = alpha_read_fp_reg(fa);
184 vb = alpha_read_fp_reg(fb);
185
186 fpcr = rdfpcr();
187
188
189
190
191 mode = func & 0xc0;
192 if (mode == 0xc0) {
193
194 mode = ((fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT) << ROUND_SHIFT;
195 }
196 mode |= (fpcw & IEEE_TRAP_ENABLE_MASK);
197
198 if ((IEEE_TRAP_ENABLE_MASK & 0xc0)) {
199 extern int something_is_wrong (void);
200 something_is_wrong();
201 }
202
203
204 switch (func & 0x3f) {
205 case FLTI_FUNC_CMPTEQ:
206 res = ieee_CMPTEQ(va, vb, &vc);
207 break;
208
209 case FLTI_FUNC_CMPTLT:
210 res = ieee_CMPTLT(va, vb, &vc);
211 break;
212
213 case FLTI_FUNC_CMPTLE:
214 res = ieee_CMPTLE(va, vb, &vc);
215 break;
216
217 case FLTI_FUNC_CMPTUN:
218 res = ieee_CMPTUN(va, vb, &vc);
219 break;
220
221 case FLTI_FUNC_CVTQL:
222
223
224
225
226
227
228 vc = ((vb & 0xc0000000) << 32 |
229 (vb & 0x3fffffff) << 29);
230 res = FPCR_INV;
231 break;
232
233 case FLTI_FUNC_CVTQS:
234 res = ieee_CVTQS(mode, vb, &vc);
235 break;
236
237 case FLTI_FUNC_CVTQT:
238 res = ieee_CVTQT(mode, vb, &vc);
239 break;
240
241 case FLTI_FUNC_CVTTS_or_CVTST:
242 if (func == 0x6ac) {
243
244
245
246
247
248 res = ieee_CVTST(mode, vb, &vc);
249 } else {
250 res = ieee_CVTTS(mode, vb, &vc);
251 }
252 break;
253
254 case FLTI_FUNC_DIVS:
255 res = ieee_DIVS(mode, va, vb, &vc);
256 break;
257
258 case FLTI_FUNC_DIVT:
259 res = ieee_DIVT(mode, va, vb, &vc);
260 break;
261
262 case FLTI_FUNC_MULS:
263 res = ieee_MULS(mode, va, vb, &vc);
264 break;
265
266 case FLTI_FUNC_MULT:
267 res = ieee_MULT(mode, va, vb, &vc);
268 break;
269
270 case FLTI_FUNC_SUBS:
271 res = ieee_SUBS(mode, va, vb, &vc);
272 break;
273
274 case FLTI_FUNC_SUBT:
275 res = ieee_SUBT(mode, va, vb, &vc);
276 break;
277
278 case FLTI_FUNC_ADDS:
279 res = ieee_ADDS(mode, va, vb, &vc);
280 break;
281
282 case FLTI_FUNC_ADDT:
283 res = ieee_ADDT(mode, va, vb, &vc);
284 break;
285
286 case FLTI_FUNC_CVTTQ:
287 res = ieee_CVTTQ(mode, vb, &vc);
288 break;
289
290 default:
291 printk("alpha_fp_emul: unexpected function code %#lx at %#lx\n",
292 func & 0x3f, pc);
293 return 0;
294 }
295
296
297
298
299
300
301
302
303
304 if (res) {
305 fpcr |= FPCR_SUM | res;
306 wrfpcr(fpcr);
307 if (((res & FPCR_INV) && (fpcw & IEEE_TRAP_ENABLE_INV)) ||
308 ((res & FPCR_DZE) && (fpcw & IEEE_TRAP_ENABLE_DZE)) ||
309 ((res & FPCR_OVF) && (fpcw & IEEE_TRAP_ENABLE_OVF)) ||
310 ((res & FPCR_UNF) && (fpcw & IEEE_TRAP_ENABLE_UNF)) ||
311 ((res & FPCR_INE) && (fpcw & IEEE_TRAP_ENABLE_INE)))
312 return 0;
313 }
314
315
316
317
318
319 alpha_write_fp_reg(fc, vc);
320 return 1;
321 }
322
323
324 long
325 alpha_fp_emul_imprecise (struct pt_regs *regs, unsigned long write_mask)
326 {
327 unsigned long trigger_pc = regs->pc - 4;
328 unsigned long insn, opcode, rc;
329
330
331
332
333
334
335
336
337
338
339
340 while (write_mask) {
341 insn = get_user((__u32*)(trigger_pc));
342 opcode = insn >> 26;
343 rc = insn & 0x1f;
344
345 switch (opcode) {
346 case OPC_PAL:
347 case OPC_JSR:
348 case 0x30 ... 0x3f:
349 return 0;
350
351 case OPC_MISC:
352 switch (insn & 0xffff) {
353 case MISC_TRAPB:
354 case MISC_EXCB:
355 return 0;
356
357 default:
358 break;
359 }
360 break;
361
362 case OPC_INTA:
363 case OPC_INTL:
364 case OPC_INTS:
365 case OPC_INTM:
366 write_mask &= ~(1UL << rc);
367 break;
368
369 case OPC_FLTV:
370 case OPC_FLTI:
371 case OPC_FLTL:
372 write_mask &= ~(1UL << (rc + 32));
373 break;
374 }
375 if (!write_mask) {
376 if ((opcode == OPC_FLTI || opcode == OPC_FLTL)
377 && alpha_fp_emul(trigger_pc))
378 {
379
380 regs->pc = trigger_pc + 4;
381 return 1;
382 }
383 break;
384 }
385 trigger_pc -= 4;
386 }
387 return 0;
388 }