aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/math-emu
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/s390/math-emu
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/s390/math-emu')
-rw-r--r--arch/s390/math-emu/Makefile8
-rw-r--r--arch/s390/math-emu/math.c2258
-rw-r--r--arch/s390/math-emu/qrnnd.S77
-rw-r--r--arch/s390/math-emu/sfp-util.h63
4 files changed, 2406 insertions, 0 deletions
diff --git a/arch/s390/math-emu/Makefile b/arch/s390/math-emu/Makefile
new file mode 100644
index 000000000000..c10df144f2ab
--- /dev/null
+++ b/arch/s390/math-emu/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for the FPU instruction emulation.
3#
4
5obj-$(CONFIG_MATHEMU) := math.o qrnnd.o
6
7EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
8EXTRA_AFLAGS := -traditional
diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c
new file mode 100644
index 000000000000..648df7140335
--- /dev/null
+++ b/arch/s390/math-emu/math.c
@@ -0,0 +1,2258 @@
1/*
2 * arch/s390/math-emu/math.c
3 *
4 * S390 version
5 * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7 *
8 * 'math.c' emulates IEEE instructions on a S390 processor
9 * that does not have the IEEE fpu (all processors before G5).
10 */
11
12#include <linux/config.h>
13#include <linux/types.h>
14#include <linux/sched.h>
15#include <linux/mm.h>
16#include <asm/uaccess.h>
17#include <asm/lowcore.h>
18
19#include "sfp-util.h"
20#include <math-emu/soft-fp.h>
21#include <math-emu/single.h>
22#include <math-emu/double.h>
23#include <math-emu/quad.h>
24
25/*
26 * I miss a macro to round a floating point number to the
27 * nearest integer in the same floating point format.
28 */
29#define _FP_TO_FPINT_ROUND(fs, wc, X) \
30 do { \
31 switch (X##_c) \
32 { \
33 case FP_CLS_NORMAL: \
34 if (X##_e > _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs) \
35 { /* floating point number has no bits after the dot. */ \
36 } \
37 else if (X##_e <= _FP_FRACBITS_##fs + _FP_EXPBIAS_##fs && \
38 X##_e > _FP_EXPBIAS_##fs) \
39 { /* some bits before the dot, some after it. */ \
40 _FP_FRAC_SRS_##wc(X, _FP_WFRACBITS_##fs, \
41 X##_e - _FP_EXPBIAS_##fs \
42 + _FP_FRACBITS_##fs); \
43 _FP_ROUND(wc, X); \
44 _FP_FRAC_SLL_##wc(X, X##_e - _FP_EXPBIAS_##fs \
45 + _FP_FRACBITS_##fs); \
46 } \
47 else \
48 { /* all bits after the dot. */ \
49 FP_SET_EXCEPTION(FP_EX_INEXACT); \
50 X##_c = FP_CLS_ZERO; \
51 } \
52 break; \
53 case FP_CLS_NAN: \
54 case FP_CLS_INF: \
55 case FP_CLS_ZERO: \
56 break; \
57 } \
58 } while (0)
59
60#define FP_TO_FPINT_ROUND_S(X) _FP_TO_FPINT_ROUND(S,1,X)
61#define FP_TO_FPINT_ROUND_D(X) _FP_TO_FPINT_ROUND(D,2,X)
62#define FP_TO_FPINT_ROUND_Q(X) _FP_TO_FPINT_ROUND(Q,4,X)
63
64typedef union {
65 long double ld;
66 struct {
67 __u64 high;
68 __u64 low;
69 } w;
70} mathemu_ldcv;
71
72#ifdef CONFIG_SYSCTL
73int sysctl_ieee_emulation_warnings=1;
74#endif
75
76#define mathemu_put_user(x, p) \
77 do { \
78 if (put_user((x),(p))) \
79 return SIGSEGV; \
80 } while (0)
81
82#define mathemu_get_user(x, p) \
83 do { \
84 if (get_user((x),(p))) \
85 return SIGSEGV; \
86 } while (0)
87
88#define mathemu_copy_from_user(d, s, n)\
89 do { \
90 if (copy_from_user((d),(s),(n)) != 0) \
91 return SIGSEGV; \
92 } while (0)
93
94#define mathemu_copy_to_user(d, s, n) \
95 do { \
96 if (copy_to_user((d),(s),(n)) != 0) \
97 return SIGSEGV; \
98 } while (0)
99
100static void display_emulation_not_implemented(struct pt_regs *regs, char *instr)
101{
102 __u16 *location;
103
104#ifdef CONFIG_SYSCTL
105 if(sysctl_ieee_emulation_warnings)
106#endif
107 {
108 location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
109 printk("%s ieee fpu instruction not emulated "
110 "process name: %s pid: %d \n",
111 instr, current->comm, current->pid);
112 printk("%s's PSW: %08lx %08lx\n", instr,
113 (unsigned long) regs->psw.mask,
114 (unsigned long) location);
115 }
116}
117
118static inline void emu_set_CC (struct pt_regs *regs, int cc)
119{
120 regs->psw.mask = (regs->psw.mask & 0xFFFFCFFF) | ((cc&3) << 12);
121}
122
123/*
124 * Set the condition code in the user psw.
125 * 0 : Result is zero
126 * 1 : Result is less than zero
127 * 2 : Result is greater than zero
128 * 3 : Result is NaN or INF
129 */
130static inline void emu_set_CC_cs(struct pt_regs *regs, int class, int sign)
131{
132 switch (class) {
133 case FP_CLS_NORMAL:
134 case FP_CLS_INF:
135 emu_set_CC(regs, sign ? 1 : 2);
136 break;
137 case FP_CLS_ZERO:
138 emu_set_CC(regs, 0);
139 break;
140 case FP_CLS_NAN:
141 emu_set_CC(regs, 3);
142 break;
143 }
144}
145
146/* Add long double */
147static int emu_axbr (struct pt_regs *regs, int rx, int ry) {
148 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
149 FP_DECL_EX;
150 mathemu_ldcv cvt;
151 int mode;
152
153 mode = current->thread.fp_regs.fpc & 3;
154 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
155 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
156 FP_UNPACK_QP(QA, &cvt.ld);
157 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
158 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
159 FP_UNPACK_QP(QB, &cvt.ld);
160 FP_ADD_Q(QR, QA, QB);
161 FP_PACK_QP(&cvt.ld, QR);
162 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
163 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
164 emu_set_CC_cs(regs, QR_c, QR_s);
165 return _fex;
166}
167
168/* Add double */
169static int emu_adbr (struct pt_regs *regs, int rx, int ry) {
170 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
171 FP_DECL_EX;
172 int mode;
173
174 mode = current->thread.fp_regs.fpc & 3;
175 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
176 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
177 FP_ADD_D(DR, DA, DB);
178 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
179 emu_set_CC_cs(regs, DR_c, DR_s);
180 return _fex;
181}
182
183/* Add double */
184static int emu_adb (struct pt_regs *regs, int rx, double *val) {
185 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
186 FP_DECL_EX;
187 int mode;
188
189 mode = current->thread.fp_regs.fpc & 3;
190 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
191 FP_UNPACK_DP(DB, val);
192 FP_ADD_D(DR, DA, DB);
193 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
194 emu_set_CC_cs(regs, DR_c, DR_s);
195 return _fex;
196}
197
198/* Add float */
199static int emu_aebr (struct pt_regs *regs, int rx, int ry) {
200 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
201 FP_DECL_EX;
202 int mode;
203
204 mode = current->thread.fp_regs.fpc & 3;
205 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
206 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
207 FP_ADD_S(SR, SA, SB);
208 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
209 emu_set_CC_cs(regs, SR_c, SR_s);
210 return _fex;
211}
212
213/* Add float */
214static int emu_aeb (struct pt_regs *regs, int rx, float *val) {
215 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
216 FP_DECL_EX;
217 int mode;
218
219 mode = current->thread.fp_regs.fpc & 3;
220 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
221 FP_UNPACK_SP(SB, val);
222 FP_ADD_S(SR, SA, SB);
223 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
224 emu_set_CC_cs(regs, SR_c, SR_s);
225 return _fex;
226}
227
228/* Compare long double */
229static int emu_cxbr (struct pt_regs *regs, int rx, int ry) {
230 FP_DECL_Q(QA); FP_DECL_Q(QB);
231 mathemu_ldcv cvt;
232 int IR;
233
234 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
235 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
236 FP_UNPACK_RAW_QP(QA, &cvt.ld);
237 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
238 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
239 FP_UNPACK_RAW_QP(QB, &cvt.ld);
240 FP_CMP_Q(IR, QA, QB, 3);
241 /*
242 * IR == -1 if DA < DB, IR == 0 if DA == DB,
243 * IR == 1 if DA > DB and IR == 3 if unorderded
244 */
245 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
246 return 0;
247}
248
249/* Compare double */
250static int emu_cdbr (struct pt_regs *regs, int rx, int ry) {
251 FP_DECL_D(DA); FP_DECL_D(DB);
252 int IR;
253
254 FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
255 FP_UNPACK_RAW_DP(DB, &current->thread.fp_regs.fprs[ry].d);
256 FP_CMP_D(IR, DA, DB, 3);
257 /*
258 * IR == -1 if DA < DB, IR == 0 if DA == DB,
259 * IR == 1 if DA > DB and IR == 3 if unorderded
260 */
261 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
262 return 0;
263}
264
265/* Compare double */
266static int emu_cdb (struct pt_regs *regs, int rx, double *val) {
267 FP_DECL_D(DA); FP_DECL_D(DB);
268 int IR;
269
270 FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
271 FP_UNPACK_RAW_DP(DB, val);
272 FP_CMP_D(IR, DA, DB, 3);
273 /*
274 * IR == -1 if DA < DB, IR == 0 if DA == DB,
275 * IR == 1 if DA > DB and IR == 3 if unorderded
276 */
277 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
278 return 0;
279}
280
281/* Compare float */
282static int emu_cebr (struct pt_regs *regs, int rx, int ry) {
283 FP_DECL_S(SA); FP_DECL_S(SB);
284 int IR;
285
286 FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
287 FP_UNPACK_RAW_SP(SB, &current->thread.fp_regs.fprs[ry].f);
288 FP_CMP_S(IR, SA, SB, 3);
289 /*
290 * IR == -1 if DA < DB, IR == 0 if DA == DB,
291 * IR == 1 if DA > DB and IR == 3 if unorderded
292 */
293 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
294 return 0;
295}
296
297/* Compare float */
298static int emu_ceb (struct pt_regs *regs, int rx, float *val) {
299 FP_DECL_S(SA); FP_DECL_S(SB);
300 int IR;
301
302 FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
303 FP_UNPACK_RAW_SP(SB, val);
304 FP_CMP_S(IR, SA, SB, 3);
305 /*
306 * IR == -1 if DA < DB, IR == 0 if DA == DB,
307 * IR == 1 if DA > DB and IR == 3 if unorderded
308 */
309 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
310 return 0;
311}
312
313/* Compare and signal long double */
314static int emu_kxbr (struct pt_regs *regs, int rx, int ry) {
315 FP_DECL_Q(QA); FP_DECL_Q(QB);
316 FP_DECL_EX;
317 mathemu_ldcv cvt;
318 int IR;
319
320 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
321 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
322 FP_UNPACK_RAW_QP(QA, &cvt.ld);
323 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
324 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
325 FP_UNPACK_QP(QB, &cvt.ld);
326 FP_CMP_Q(IR, QA, QB, 3);
327 /*
328 * IR == -1 if DA < DB, IR == 0 if DA == DB,
329 * IR == 1 if DA > DB and IR == 3 if unorderded
330 */
331 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
332 if (IR == 3)
333 FP_SET_EXCEPTION (FP_EX_INVALID);
334 return _fex;
335}
336
337/* Compare and signal double */
338static int emu_kdbr (struct pt_regs *regs, int rx, int ry) {
339 FP_DECL_D(DA); FP_DECL_D(DB);
340 FP_DECL_EX;
341 int IR;
342
343 FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
344 FP_UNPACK_RAW_DP(DB, &current->thread.fp_regs.fprs[ry].d);
345 FP_CMP_D(IR, DA, DB, 3);
346 /*
347 * IR == -1 if DA < DB, IR == 0 if DA == DB,
348 * IR == 1 if DA > DB and IR == 3 if unorderded
349 */
350 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
351 if (IR == 3)
352 FP_SET_EXCEPTION (FP_EX_INVALID);
353 return _fex;
354}
355
356/* Compare and signal double */
357static int emu_kdb (struct pt_regs *regs, int rx, double *val) {
358 FP_DECL_D(DA); FP_DECL_D(DB);
359 FP_DECL_EX;
360 int IR;
361
362 FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
363 FP_UNPACK_RAW_DP(DB, val);
364 FP_CMP_D(IR, DA, DB, 3);
365 /*
366 * IR == -1 if DA < DB, IR == 0 if DA == DB,
367 * IR == 1 if DA > DB and IR == 3 if unorderded
368 */
369 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
370 if (IR == 3)
371 FP_SET_EXCEPTION (FP_EX_INVALID);
372 return _fex;
373}
374
375/* Compare and signal float */
376static int emu_kebr (struct pt_regs *regs, int rx, int ry) {
377 FP_DECL_S(SA); FP_DECL_S(SB);
378 FP_DECL_EX;
379 int IR;
380
381 FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
382 FP_UNPACK_RAW_SP(SB, &current->thread.fp_regs.fprs[ry].f);
383 FP_CMP_S(IR, SA, SB, 3);
384 /*
385 * IR == -1 if DA < DB, IR == 0 if DA == DB,
386 * IR == 1 if DA > DB and IR == 3 if unorderded
387 */
388 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
389 if (IR == 3)
390 FP_SET_EXCEPTION (FP_EX_INVALID);
391 return _fex;
392}
393
394/* Compare and signal float */
395static int emu_keb (struct pt_regs *regs, int rx, float *val) {
396 FP_DECL_S(SA); FP_DECL_S(SB);
397 FP_DECL_EX;
398 int IR;
399
400 FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
401 FP_UNPACK_RAW_SP(SB, val);
402 FP_CMP_S(IR, SA, SB, 3);
403 /*
404 * IR == -1 if DA < DB, IR == 0 if DA == DB,
405 * IR == 1 if DA > DB and IR == 3 if unorderded
406 */
407 emu_set_CC(regs, (IR == -1) ? 1 : (IR == 1) ? 2 : IR);
408 if (IR == 3)
409 FP_SET_EXCEPTION (FP_EX_INVALID);
410 return _fex;
411}
412
413/* Convert from fixed long double */
414static int emu_cxfbr (struct pt_regs *regs, int rx, int ry) {
415 FP_DECL_Q(QR);
416 FP_DECL_EX;
417 mathemu_ldcv cvt;
418 __s32 si;
419 int mode;
420
421 mode = current->thread.fp_regs.fpc & 3;
422 si = regs->gprs[ry];
423 FP_FROM_INT_Q(QR, si, 32, int);
424 FP_PACK_QP(&cvt.ld, QR);
425 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
426 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
427 return _fex;
428}
429
430/* Convert from fixed double */
431static int emu_cdfbr (struct pt_regs *regs, int rx, int ry) {
432 FP_DECL_D(DR);
433 FP_DECL_EX;
434 __s32 si;
435 int mode;
436
437 mode = current->thread.fp_regs.fpc & 3;
438 si = regs->gprs[ry];
439 FP_FROM_INT_D(DR, si, 32, int);
440 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
441 return _fex;
442}
443
444/* Convert from fixed float */
445static int emu_cefbr (struct pt_regs *regs, int rx, int ry) {
446 FP_DECL_S(SR);
447 FP_DECL_EX;
448 __s32 si;
449 int mode;
450
451 mode = current->thread.fp_regs.fpc & 3;
452 si = regs->gprs[ry];
453 FP_FROM_INT_S(SR, si, 32, int);
454 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
455 return _fex;
456}
457
458/* Convert to fixed long double */
459static int emu_cfxbr (struct pt_regs *regs, int rx, int ry, int mask) {
460 FP_DECL_Q(QA);
461 FP_DECL_EX;
462 mathemu_ldcv cvt;
463 __s32 si;
464 int mode;
465
466 if (mask == 0)
467 mode = current->thread.fp_regs.fpc & 3;
468 else if (mask == 1)
469 mode = FP_RND_NEAREST;
470 else
471 mode = mask - 4;
472 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
473 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
474 FP_UNPACK_QP(QA, &cvt.ld);
475 FP_TO_INT_ROUND_Q(si, QA, 32, 1);
476 regs->gprs[rx] = si;
477 emu_set_CC_cs(regs, QA_c, QA_s);
478 return _fex;
479}
480
481/* Convert to fixed double */
482static int emu_cfdbr (struct pt_regs *regs, int rx, int ry, int mask) {
483 FP_DECL_D(DA);
484 FP_DECL_EX;
485 __s32 si;
486 int mode;
487
488 if (mask == 0)
489 mode = current->thread.fp_regs.fpc & 3;
490 else if (mask == 1)
491 mode = FP_RND_NEAREST;
492 else
493 mode = mask - 4;
494 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
495 FP_TO_INT_ROUND_D(si, DA, 32, 1);
496 regs->gprs[rx] = si;
497 emu_set_CC_cs(regs, DA_c, DA_s);
498 return _fex;
499}
500
501/* Convert to fixed float */
502static int emu_cfebr (struct pt_regs *regs, int rx, int ry, int mask) {
503 FP_DECL_S(SA);
504 FP_DECL_EX;
505 __s32 si;
506 int mode;
507
508 if (mask == 0)
509 mode = current->thread.fp_regs.fpc & 3;
510 else if (mask == 1)
511 mode = FP_RND_NEAREST;
512 else
513 mode = mask - 4;
514 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
515 FP_TO_INT_ROUND_S(si, SA, 32, 1);
516 regs->gprs[rx] = si;
517 emu_set_CC_cs(regs, SA_c, SA_s);
518 return _fex;
519}
520
521/* Divide long double */
522static int emu_dxbr (struct pt_regs *regs, int rx, int ry) {
523 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
524 FP_DECL_EX;
525 mathemu_ldcv cvt;
526 int mode;
527
528 mode = current->thread.fp_regs.fpc & 3;
529 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
530 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
531 FP_UNPACK_QP(QA, &cvt.ld);
532 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
533 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
534 FP_UNPACK_QP(QB, &cvt.ld);
535 FP_DIV_Q(QR, QA, QB);
536 FP_PACK_QP(&cvt.ld, QR);
537 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
538 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
539 return _fex;
540}
541
542/* Divide double */
543static int emu_ddbr (struct pt_regs *regs, int rx, int ry) {
544 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
545 FP_DECL_EX;
546 int mode;
547
548 mode = current->thread.fp_regs.fpc & 3;
549 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
550 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
551 FP_DIV_D(DR, DA, DB);
552 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
553 return _fex;
554}
555
556/* Divide double */
557static int emu_ddb (struct pt_regs *regs, int rx, double *val) {
558 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
559 FP_DECL_EX;
560 int mode;
561
562 mode = current->thread.fp_regs.fpc & 3;
563 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
564 FP_UNPACK_DP(DB, val);
565 FP_DIV_D(DR, DA, DB);
566 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
567 return _fex;
568}
569
570/* Divide float */
571static int emu_debr (struct pt_regs *regs, int rx, int ry) {
572 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
573 FP_DECL_EX;
574 int mode;
575
576 mode = current->thread.fp_regs.fpc & 3;
577 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
578 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
579 FP_DIV_S(SR, SA, SB);
580 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
581 return _fex;
582}
583
584/* Divide float */
585static int emu_deb (struct pt_regs *regs, int rx, float *val) {
586 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
587 FP_DECL_EX;
588 int mode;
589
590 mode = current->thread.fp_regs.fpc & 3;
591 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
592 FP_UNPACK_SP(SB, val);
593 FP_DIV_S(SR, SA, SB);
594 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
595 return _fex;
596}
597
598/* Divide to integer double */
599static int emu_didbr (struct pt_regs *regs, int rx, int ry, int mask) {
600 display_emulation_not_implemented(regs, "didbr");
601 return 0;
602}
603
604/* Divide to integer float */
605static int emu_diebr (struct pt_regs *regs, int rx, int ry, int mask) {
606 display_emulation_not_implemented(regs, "diebr");
607 return 0;
608}
609
610/* Extract fpc */
611static int emu_efpc (struct pt_regs *regs, int rx, int ry) {
612 regs->gprs[rx] = current->thread.fp_regs.fpc;
613 return 0;
614}
615
616/* Load and test long double */
617static int emu_ltxbr (struct pt_regs *regs, int rx, int ry) {
618 s390_fp_regs *fp_regs = &current->thread.fp_regs;
619 mathemu_ldcv cvt;
620 FP_DECL_Q(QA);
621 FP_DECL_EX;
622
623 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
624 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
625 FP_UNPACK_QP(QA, &cvt.ld);
626 fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
627 fp_regs->fprs[rx+2].ui = fp_regs->fprs[ry+2].ui;
628 emu_set_CC_cs(regs, QA_c, QA_s);
629 return _fex;
630}
631
632/* Load and test double */
633static int emu_ltdbr (struct pt_regs *regs, int rx, int ry) {
634 s390_fp_regs *fp_regs = &current->thread.fp_regs;
635 FP_DECL_D(DA);
636 FP_DECL_EX;
637
638 FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d);
639 fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
640 emu_set_CC_cs(regs, DA_c, DA_s);
641 return _fex;
642}
643
644/* Load and test double */
645static int emu_ltebr (struct pt_regs *regs, int rx, int ry) {
646 s390_fp_regs *fp_regs = &current->thread.fp_regs;
647 FP_DECL_S(SA);
648 FP_DECL_EX;
649
650 FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f);
651 fp_regs->fprs[rx].ui = fp_regs->fprs[ry].ui;
652 emu_set_CC_cs(regs, SA_c, SA_s);
653 return _fex;
654}
655
656/* Load complement long double */
657static int emu_lcxbr (struct pt_regs *regs, int rx, int ry) {
658 FP_DECL_Q(QA); FP_DECL_Q(QR);
659 FP_DECL_EX;
660 mathemu_ldcv cvt;
661 int mode;
662
663 mode = current->thread.fp_regs.fpc & 3;
664 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
665 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
666 FP_UNPACK_QP(QA, &cvt.ld);
667 FP_NEG_Q(QR, QA);
668 FP_PACK_QP(&cvt.ld, QR);
669 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
670 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
671 emu_set_CC_cs(regs, QR_c, QR_s);
672 return _fex;
673}
674
675/* Load complement double */
676static int emu_lcdbr (struct pt_regs *regs, int rx, int ry) {
677 FP_DECL_D(DA); FP_DECL_D(DR);
678 FP_DECL_EX;
679 int mode;
680
681 mode = current->thread.fp_regs.fpc & 3;
682 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
683 FP_NEG_D(DR, DA);
684 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
685 emu_set_CC_cs(regs, DR_c, DR_s);
686 return _fex;
687}
688
689/* Load complement float */
690static int emu_lcebr (struct pt_regs *regs, int rx, int ry) {
691 FP_DECL_S(SA); FP_DECL_S(SR);
692 FP_DECL_EX;
693 int mode;
694
695 mode = current->thread.fp_regs.fpc & 3;
696 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
697 FP_NEG_S(SR, SA);
698 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
699 emu_set_CC_cs(regs, SR_c, SR_s);
700 return _fex;
701}
702
703/* Load floating point integer long double */
704static int emu_fixbr (struct pt_regs *regs, int rx, int ry, int mask) {
705 s390_fp_regs *fp_regs = &current->thread.fp_regs;
706 FP_DECL_Q(QA);
707 FP_DECL_EX;
708 mathemu_ldcv cvt;
709 __s32 si;
710 int mode;
711
712 if (mask == 0)
713 mode = fp_regs->fpc & 3;
714 else if (mask == 1)
715 mode = FP_RND_NEAREST;
716 else
717 mode = mask - 4;
718 cvt.w.high = fp_regs->fprs[ry].ui;
719 cvt.w.low = fp_regs->fprs[ry+2].ui;
720 FP_UNPACK_QP(QA, &cvt.ld);
721 FP_TO_FPINT_ROUND_Q(QA);
722 FP_PACK_QP(&cvt.ld, QA);
723 fp_regs->fprs[rx].ui = cvt.w.high;
724 fp_regs->fprs[rx+2].ui = cvt.w.low;
725 return _fex;
726}
727
728/* Load floating point integer double */
729static int emu_fidbr (struct pt_regs *regs, int rx, int ry, int mask) {
730 /* FIXME: rounding mode !! */
731 s390_fp_regs *fp_regs = &current->thread.fp_regs;
732 FP_DECL_D(DA);
733 FP_DECL_EX;
734 __s32 si;
735 int mode;
736
737 if (mask == 0)
738 mode = fp_regs->fpc & 3;
739 else if (mask == 1)
740 mode = FP_RND_NEAREST;
741 else
742 mode = mask - 4;
743 FP_UNPACK_DP(DA, &fp_regs->fprs[ry].d);
744 FP_TO_FPINT_ROUND_D(DA);
745 FP_PACK_DP(&fp_regs->fprs[rx].d, DA);
746 return _fex;
747}
748
749/* Load floating point integer float */
750static int emu_fiebr (struct pt_regs *regs, int rx, int ry, int mask) {
751 s390_fp_regs *fp_regs = &current->thread.fp_regs;
752 FP_DECL_S(SA);
753 FP_DECL_EX;
754 __s32 si;
755 int mode;
756
757 if (mask == 0)
758 mode = fp_regs->fpc & 3;
759 else if (mask == 1)
760 mode = FP_RND_NEAREST;
761 else
762 mode = mask - 4;
763 FP_UNPACK_SP(SA, &fp_regs->fprs[ry].f);
764 FP_TO_FPINT_ROUND_S(SA);
765 FP_PACK_SP(&fp_regs->fprs[rx].f, SA);
766 return _fex;
767}
768
769/* Load lengthened double to long double */
770static int emu_lxdbr (struct pt_regs *regs, int rx, int ry) {
771 FP_DECL_D(DA); FP_DECL_Q(QR);
772 FP_DECL_EX;
773 mathemu_ldcv cvt;
774 int mode;
775
776 mode = current->thread.fp_regs.fpc & 3;
777 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
778 FP_CONV (Q, D, 4, 2, QR, DA);
779 FP_PACK_QP(&cvt.ld, QR);
780 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
781 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
782 return _fex;
783}
784
785/* Load lengthened double to long double */
786static int emu_lxdb (struct pt_regs *regs, int rx, double *val) {
787 FP_DECL_D(DA); FP_DECL_Q(QR);
788 FP_DECL_EX;
789 mathemu_ldcv cvt;
790 int mode;
791
792 mode = current->thread.fp_regs.fpc & 3;
793 FP_UNPACK_DP(DA, val);
794 FP_CONV (Q, D, 4, 2, QR, DA);
795 FP_PACK_QP(&cvt.ld, QR);
796 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
797 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
798 return _fex;
799}
800
801/* Load lengthened float to long double */
802static int emu_lxebr (struct pt_regs *regs, int rx, int ry) {
803 FP_DECL_S(SA); FP_DECL_Q(QR);
804 FP_DECL_EX;
805 mathemu_ldcv cvt;
806 int mode;
807
808 mode = current->thread.fp_regs.fpc & 3;
809 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
810 FP_CONV (Q, S, 4, 1, QR, SA);
811 FP_PACK_QP(&cvt.ld, QR);
812 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
813 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
814 return _fex;
815}
816
817/* Load lengthened float to long double */
818static int emu_lxeb (struct pt_regs *regs, int rx, float *val) {
819 FP_DECL_S(SA); FP_DECL_Q(QR);
820 FP_DECL_EX;
821 mathemu_ldcv cvt;
822 int mode;
823
824 mode = current->thread.fp_regs.fpc & 3;
825 FP_UNPACK_SP(SA, val);
826 FP_CONV (Q, S, 4, 1, QR, SA);
827 FP_PACK_QP(&cvt.ld, QR);
828 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
829 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
830 return _fex;
831}
832
833/* Load lengthened float to double */
834static int emu_ldebr (struct pt_regs *regs, int rx, int ry) {
835 FP_DECL_S(SA); FP_DECL_D(DR);
836 FP_DECL_EX;
837 int mode;
838
839 mode = current->thread.fp_regs.fpc & 3;
840 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
841 FP_CONV (D, S, 2, 1, DR, SA);
842 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
843 return _fex;
844}
845
846/* Load lengthened float to double */
847static int emu_ldeb (struct pt_regs *regs, int rx, float *val) {
848 FP_DECL_S(SA); FP_DECL_D(DR);
849 FP_DECL_EX;
850 int mode;
851
852 mode = current->thread.fp_regs.fpc & 3;
853 FP_UNPACK_SP(SA, val);
854 FP_CONV (D, S, 2, 1, DR, SA);
855 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
856 return _fex;
857}
858
859/* Load negative long double */
860static int emu_lnxbr (struct pt_regs *regs, int rx, int ry) {
861 FP_DECL_Q(QA); FP_DECL_Q(QR);
862 FP_DECL_EX;
863 mathemu_ldcv cvt;
864 int mode;
865
866 mode = current->thread.fp_regs.fpc & 3;
867 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
868 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
869 FP_UNPACK_QP(QA, &cvt.ld);
870 if (QA_s == 0) {
871 FP_NEG_Q(QR, QA);
872 FP_PACK_QP(&cvt.ld, QR);
873 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
874 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
875 } else {
876 current->thread.fp_regs.fprs[rx].ui =
877 current->thread.fp_regs.fprs[ry].ui;
878 current->thread.fp_regs.fprs[rx+2].ui =
879 current->thread.fp_regs.fprs[ry+2].ui;
880 }
881 emu_set_CC_cs(regs, QR_c, QR_s);
882 return _fex;
883}
884
885/* Load negative double */
886static int emu_lndbr (struct pt_regs *regs, int rx, int ry) {
887 FP_DECL_D(DA); FP_DECL_D(DR);
888 FP_DECL_EX;
889 int mode;
890
891 mode = current->thread.fp_regs.fpc & 3;
892 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
893 if (DA_s == 0) {
894 FP_NEG_D(DR, DA);
895 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
896 } else
897 current->thread.fp_regs.fprs[rx].ui =
898 current->thread.fp_regs.fprs[ry].ui;
899 emu_set_CC_cs(regs, DR_c, DR_s);
900 return _fex;
901}
902
903/* Load negative float */
904static int emu_lnebr (struct pt_regs *regs, int rx, int ry) {
905 FP_DECL_S(SA); FP_DECL_S(SR);
906 FP_DECL_EX;
907 int mode;
908
909 mode = current->thread.fp_regs.fpc & 3;
910 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
911 if (SA_s == 0) {
912 FP_NEG_S(SR, SA);
913 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
914 } else
915 current->thread.fp_regs.fprs[rx].ui =
916 current->thread.fp_regs.fprs[ry].ui;
917 emu_set_CC_cs(regs, SR_c, SR_s);
918 return _fex;
919}
920
921/* Load positive long double */
922static int emu_lpxbr (struct pt_regs *regs, int rx, int ry) {
923 FP_DECL_Q(QA); FP_DECL_Q(QR);
924 FP_DECL_EX;
925 mathemu_ldcv cvt;
926 int mode;
927
928 mode = current->thread.fp_regs.fpc & 3;
929 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
930 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
931 FP_UNPACK_QP(QA, &cvt.ld);
932 if (QA_s != 0) {
933 FP_NEG_Q(QR, QA);
934 FP_PACK_QP(&cvt.ld, QR);
935 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
936 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
937 } else{
938 current->thread.fp_regs.fprs[rx].ui =
939 current->thread.fp_regs.fprs[ry].ui;
940 current->thread.fp_regs.fprs[rx+2].ui =
941 current->thread.fp_regs.fprs[ry+2].ui;
942 }
943 emu_set_CC_cs(regs, QR_c, QR_s);
944 return _fex;
945}
946
947/* Load positive double */
948static int emu_lpdbr (struct pt_regs *regs, int rx, int ry) {
949 FP_DECL_D(DA); FP_DECL_D(DR);
950 FP_DECL_EX;
951 int mode;
952
953 mode = current->thread.fp_regs.fpc & 3;
954 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
955 if (DA_s != 0) {
956 FP_NEG_D(DR, DA);
957 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
958 } else
959 current->thread.fp_regs.fprs[rx].ui =
960 current->thread.fp_regs.fprs[ry].ui;
961 emu_set_CC_cs(regs, DR_c, DR_s);
962 return _fex;
963}
964
965/* Load positive float */
966static int emu_lpebr (struct pt_regs *regs, int rx, int ry) {
967 FP_DECL_S(SA); FP_DECL_S(SR);
968 FP_DECL_EX;
969 int mode;
970
971 mode = current->thread.fp_regs.fpc & 3;
972 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
973 if (SA_s != 0) {
974 FP_NEG_S(SR, SA);
975 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
976 } else
977 current->thread.fp_regs.fprs[rx].ui =
978 current->thread.fp_regs.fprs[ry].ui;
979 emu_set_CC_cs(regs, SR_c, SR_s);
980 return _fex;
981}
982
983/* Load rounded long double to double */
984static int emu_ldxbr (struct pt_regs *regs, int rx, int ry) {
985 FP_DECL_Q(QA); FP_DECL_D(DR);
986 FP_DECL_EX;
987 mathemu_ldcv cvt;
988 int mode;
989
990 mode = current->thread.fp_regs.fpc & 3;
991 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
992 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
993 FP_UNPACK_QP(QA, &cvt.ld);
994 FP_CONV (D, Q, 2, 4, DR, QA);
995 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].f, DR);
996 return _fex;
997}
998
999/* Load rounded long double to float */
1000static int emu_lexbr (struct pt_regs *regs, int rx, int ry) {
1001 FP_DECL_Q(QA); FP_DECL_S(SR);
1002 FP_DECL_EX;
1003 mathemu_ldcv cvt;
1004 int mode;
1005
1006 mode = current->thread.fp_regs.fpc & 3;
1007 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
1008 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
1009 FP_UNPACK_QP(QA, &cvt.ld);
1010 FP_CONV (S, Q, 1, 4, SR, QA);
1011 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1012 return _fex;
1013}
1014
1015/* Load rounded double to float */
1016static int emu_ledbr (struct pt_regs *regs, int rx, int ry) {
1017 FP_DECL_D(DA); FP_DECL_S(SR);
1018 FP_DECL_EX;
1019 int mode;
1020
1021 mode = current->thread.fp_regs.fpc & 3;
1022 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
1023 FP_CONV (S, D, 1, 2, SR, DA);
1024 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1025 return _fex;
1026}
1027
1028/* Multiply long double */
1029static int emu_mxbr (struct pt_regs *regs, int rx, int ry) {
1030 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
1031 FP_DECL_EX;
1032 mathemu_ldcv cvt;
1033 int mode;
1034
1035 mode = current->thread.fp_regs.fpc & 3;
1036 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
1037 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
1038 FP_UNPACK_QP(QA, &cvt.ld);
1039 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
1040 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
1041 FP_UNPACK_QP(QB, &cvt.ld);
1042 FP_MUL_Q(QR, QA, QB);
1043 FP_PACK_QP(&cvt.ld, QR);
1044 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
1045 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
1046 return _fex;
1047}
1048
1049/* Multiply double */
1050static int emu_mdbr (struct pt_regs *regs, int rx, int ry) {
1051 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1052 FP_DECL_EX;
1053 int mode;
1054
1055 mode = current->thread.fp_regs.fpc & 3;
1056 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1057 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
1058 FP_MUL_D(DR, DA, DB);
1059 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1060 return _fex;
1061}
1062
1063/* Multiply double */
1064static int emu_mdb (struct pt_regs *regs, int rx, double *val) {
1065 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1066 FP_DECL_EX;
1067 int mode;
1068
1069 mode = current->thread.fp_regs.fpc & 3;
1070 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1071 FP_UNPACK_DP(DB, val);
1072 FP_MUL_D(DR, DA, DB);
1073 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1074 return _fex;
1075}
1076
1077/* Multiply double to long double */
1078static int emu_mxdbr (struct pt_regs *regs, int rx, int ry) {
1079 FP_DECL_D(DA); FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
1080 FP_DECL_EX;
1081 mathemu_ldcv cvt;
1082 int mode;
1083
1084 mode = current->thread.fp_regs.fpc & 3;
1085 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1086 FP_CONV (Q, D, 4, 2, QA, DA);
1087 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
1088 FP_CONV (Q, D, 4, 2, QB, DA);
1089 FP_MUL_Q(QR, QA, QB);
1090 FP_PACK_QP(&cvt.ld, QR);
1091 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
1092 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
1093 return _fex;
1094}
1095
1096/* Multiply double to long double */
1097static int emu_mxdb (struct pt_regs *regs, int rx, long double *val) {
1098 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
1099 FP_DECL_EX;
1100 mathemu_ldcv cvt;
1101 int mode;
1102
1103 mode = current->thread.fp_regs.fpc & 3;
1104 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
1105 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
1106 FP_UNPACK_QP(QA, &cvt.ld);
1107 FP_UNPACK_QP(QB, val);
1108 FP_MUL_Q(QR, QA, QB);
1109 FP_PACK_QP(&cvt.ld, QR);
1110 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
1111 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
1112 return _fex;
1113}
1114
1115/* Multiply float */
1116static int emu_meebr (struct pt_regs *regs, int rx, int ry) {
1117 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
1118 FP_DECL_EX;
1119 int mode;
1120
1121 mode = current->thread.fp_regs.fpc & 3;
1122 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1123 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
1124 FP_MUL_S(SR, SA, SB);
1125 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1126 return _fex;
1127}
1128
1129/* Multiply float */
1130static int emu_meeb (struct pt_regs *regs, int rx, float *val) {
1131 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
1132 FP_DECL_EX;
1133 int mode;
1134
1135 mode = current->thread.fp_regs.fpc & 3;
1136 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1137 FP_UNPACK_SP(SB, val);
1138 FP_MUL_S(SR, SA, SB);
1139 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1140 return _fex;
1141}
1142
1143/* Multiply float to double */
1144static int emu_mdebr (struct pt_regs *regs, int rx, int ry) {
1145 FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1146 FP_DECL_EX;
1147 int mode;
1148
1149 mode = current->thread.fp_regs.fpc & 3;
1150 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1151 FP_CONV (D, S, 2, 1, DA, SA);
1152 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
1153 FP_CONV (D, S, 2, 1, DB, SA);
1154 FP_MUL_D(DR, DA, DB);
1155 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1156 return _fex;
1157}
1158
1159/* Multiply float to double */
1160static int emu_mdeb (struct pt_regs *regs, int rx, float *val) {
1161 FP_DECL_S(SA); FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1162 FP_DECL_EX;
1163 int mode;
1164
1165 mode = current->thread.fp_regs.fpc & 3;
1166 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1167 FP_CONV (D, S, 2, 1, DA, SA);
1168 FP_UNPACK_SP(SA, val);
1169 FP_CONV (D, S, 2, 1, DB, SA);
1170 FP_MUL_D(DR, DA, DB);
1171 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1172 return _fex;
1173}
1174
1175/* Multiply and add double */
1176static int emu_madbr (struct pt_regs *regs, int rx, int ry, int rz) {
1177 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
1178 FP_DECL_EX;
1179 int mode;
1180
1181 mode = current->thread.fp_regs.fpc & 3;
1182 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1183 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
1184 FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
1185 FP_MUL_D(DR, DA, DB);
1186 FP_ADD_D(DR, DR, DC);
1187 FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
1188 return _fex;
1189}
1190
1191/* Multiply and add double */
1192static int emu_madb (struct pt_regs *regs, int rx, double *val, int rz) {
1193 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
1194 FP_DECL_EX;
1195 int mode;
1196
1197 mode = current->thread.fp_regs.fpc & 3;
1198 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1199 FP_UNPACK_DP(DB, val);
1200 FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
1201 FP_MUL_D(DR, DA, DB);
1202 FP_ADD_D(DR, DR, DC);
1203 FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
1204 return _fex;
1205}
1206
1207/* Multiply and add float */
1208static int emu_maebr (struct pt_regs *regs, int rx, int ry, int rz) {
1209 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
1210 FP_DECL_EX;
1211 int mode;
1212
1213 mode = current->thread.fp_regs.fpc & 3;
1214 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1215 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
1216 FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
1217 FP_MUL_S(SR, SA, SB);
1218 FP_ADD_S(SR, SR, SC);
1219 FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
1220 return _fex;
1221}
1222
1223/* Multiply and add float */
1224static int emu_maeb (struct pt_regs *regs, int rx, float *val, int rz) {
1225 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
1226 FP_DECL_EX;
1227 int mode;
1228
1229 mode = current->thread.fp_regs.fpc & 3;
1230 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1231 FP_UNPACK_SP(SB, val);
1232 FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
1233 FP_MUL_S(SR, SA, SB);
1234 FP_ADD_S(SR, SR, SC);
1235 FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
1236 return _fex;
1237}
1238
1239/* Multiply and subtract double */
1240static int emu_msdbr (struct pt_regs *regs, int rx, int ry, int rz) {
1241 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
1242 FP_DECL_EX;
1243 int mode;
1244
1245 mode = current->thread.fp_regs.fpc & 3;
1246 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1247 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
1248 FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
1249 FP_MUL_D(DR, DA, DB);
1250 FP_SUB_D(DR, DR, DC);
1251 FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
1252 return _fex;
1253}
1254
1255/* Multiply and subtract double */
1256static int emu_msdb (struct pt_regs *regs, int rx, double *val, int rz) {
1257 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DC); FP_DECL_D(DR);
1258 FP_DECL_EX;
1259 int mode;
1260
1261 mode = current->thread.fp_regs.fpc & 3;
1262 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1263 FP_UNPACK_DP(DB, val);
1264 FP_UNPACK_DP(DC, &current->thread.fp_regs.fprs[rz].d);
1265 FP_MUL_D(DR, DA, DB);
1266 FP_SUB_D(DR, DR, DC);
1267 FP_PACK_DP(&current->thread.fp_regs.fprs[rz].d, DR);
1268 return _fex;
1269}
1270
1271/* Multiply and subtract float */
1272static int emu_msebr (struct pt_regs *regs, int rx, int ry, int rz) {
1273 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
1274 FP_DECL_EX;
1275 int mode;
1276
1277 mode = current->thread.fp_regs.fpc & 3;
1278 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1279 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
1280 FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
1281 FP_MUL_S(SR, SA, SB);
1282 FP_SUB_S(SR, SR, SC);
1283 FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
1284 return _fex;
1285}
1286
1287/* Multiply and subtract float */
1288static int emu_mseb (struct pt_regs *regs, int rx, float *val, int rz) {
1289 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SC); FP_DECL_S(SR);
1290 FP_DECL_EX;
1291 int mode;
1292
1293 mode = current->thread.fp_regs.fpc & 3;
1294 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1295 FP_UNPACK_SP(SB, val);
1296 FP_UNPACK_SP(SC, &current->thread.fp_regs.fprs[rz].f);
1297 FP_MUL_S(SR, SA, SB);
1298 FP_SUB_S(SR, SR, SC);
1299 FP_PACK_SP(&current->thread.fp_regs.fprs[rz].f, SR);
1300 return _fex;
1301}
1302
1303/* Set floating point control word */
1304static int emu_sfpc (struct pt_regs *regs, int rx, int ry) {
1305 __u32 temp;
1306
1307 temp = regs->gprs[rx];
1308 if ((temp & ~FPC_VALID_MASK) != 0)
1309 return SIGILL;
1310 current->thread.fp_regs.fpc = temp;
1311 return 0;
1312}
1313
1314/* Square root long double */
1315static int emu_sqxbr (struct pt_regs *regs, int rx, int ry) {
1316 FP_DECL_Q(QA); FP_DECL_Q(QR);
1317 FP_DECL_EX;
1318 mathemu_ldcv cvt;
1319 int mode;
1320
1321 mode = current->thread.fp_regs.fpc & 3;
1322 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
1323 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
1324 FP_UNPACK_QP(QA, &cvt.ld);
1325 FP_SQRT_Q(QR, QA);
1326 FP_PACK_QP(&cvt.ld, QR);
1327 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
1328 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
1329 emu_set_CC_cs(regs, QR_c, QR_s);
1330 return _fex;
1331}
1332
1333/* Square root double */
1334static int emu_sqdbr (struct pt_regs *regs, int rx, int ry) {
1335 FP_DECL_D(DA); FP_DECL_D(DR);
1336 FP_DECL_EX;
1337 int mode;
1338
1339 mode = current->thread.fp_regs.fpc & 3;
1340 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[ry].d);
1341 FP_SQRT_D(DR, DA);
1342 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1343 emu_set_CC_cs(regs, DR_c, DR_s);
1344 return _fex;
1345}
1346
1347/* Square root double */
1348static int emu_sqdb (struct pt_regs *regs, int rx, double *val) {
1349 FP_DECL_D(DA); FP_DECL_D(DR);
1350 FP_DECL_EX;
1351 int mode;
1352
1353 mode = current->thread.fp_regs.fpc & 3;
1354 FP_UNPACK_DP(DA, val);
1355 FP_SQRT_D(DR, DA);
1356 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1357 emu_set_CC_cs(regs, DR_c, DR_s);
1358 return _fex;
1359}
1360
1361/* Square root float */
1362static int emu_sqebr (struct pt_regs *regs, int rx, int ry) {
1363 FP_DECL_S(SA); FP_DECL_S(SR);
1364 FP_DECL_EX;
1365 int mode;
1366
1367 mode = current->thread.fp_regs.fpc & 3;
1368 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[ry].f);
1369 FP_SQRT_S(SR, SA);
1370 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1371 emu_set_CC_cs(regs, SR_c, SR_s);
1372 return _fex;
1373}
1374
1375/* Square root float */
1376static int emu_sqeb (struct pt_regs *regs, int rx, float *val) {
1377 FP_DECL_S(SA); FP_DECL_S(SR);
1378 FP_DECL_EX;
1379 int mode;
1380
1381 mode = current->thread.fp_regs.fpc & 3;
1382 FP_UNPACK_SP(SA, val);
1383 FP_SQRT_S(SR, SA);
1384 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1385 emu_set_CC_cs(regs, SR_c, SR_s);
1386 return _fex;
1387}
1388
1389/* Subtract long double */
1390static int emu_sxbr (struct pt_regs *regs, int rx, int ry) {
1391 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
1392 FP_DECL_EX;
1393 mathemu_ldcv cvt;
1394 int mode;
1395
1396 mode = current->thread.fp_regs.fpc & 3;
1397 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
1398 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
1399 FP_UNPACK_QP(QA, &cvt.ld);
1400 cvt.w.high = current->thread.fp_regs.fprs[ry].ui;
1401 cvt.w.low = current->thread.fp_regs.fprs[ry+2].ui;
1402 FP_UNPACK_QP(QB, &cvt.ld);
1403 FP_SUB_Q(QR, QA, QB);
1404 FP_PACK_QP(&cvt.ld, QR);
1405 current->thread.fp_regs.fprs[rx].ui = cvt.w.high;
1406 current->thread.fp_regs.fprs[rx+2].ui = cvt.w.low;
1407 emu_set_CC_cs(regs, QR_c, QR_s);
1408 return _fex;
1409}
1410
1411/* Subtract double */
1412static int emu_sdbr (struct pt_regs *regs, int rx, int ry) {
1413 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1414 FP_DECL_EX;
1415 int mode;
1416
1417 mode = current->thread.fp_regs.fpc & 3;
1418 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1419 FP_UNPACK_DP(DB, &current->thread.fp_regs.fprs[ry].d);
1420 FP_SUB_D(DR, DA, DB);
1421 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1422 emu_set_CC_cs(regs, DR_c, DR_s);
1423 return _fex;
1424}
1425
1426/* Subtract double */
1427static int emu_sdb (struct pt_regs *regs, int rx, double *val) {
1428 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
1429 FP_DECL_EX;
1430 int mode;
1431
1432 mode = current->thread.fp_regs.fpc & 3;
1433 FP_UNPACK_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1434 FP_UNPACK_DP(DB, val);
1435 FP_SUB_D(DR, DA, DB);
1436 FP_PACK_DP(&current->thread.fp_regs.fprs[rx].d, DR);
1437 emu_set_CC_cs(regs, DR_c, DR_s);
1438 return _fex;
1439}
1440
1441/* Subtract float */
1442static int emu_sebr (struct pt_regs *regs, int rx, int ry) {
1443 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
1444 FP_DECL_EX;
1445 int mode;
1446
1447 mode = current->thread.fp_regs.fpc & 3;
1448 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1449 FP_UNPACK_SP(SB, &current->thread.fp_regs.fprs[ry].f);
1450 FP_SUB_S(SR, SA, SB);
1451 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1452 emu_set_CC_cs(regs, SR_c, SR_s);
1453 return _fex;
1454}
1455
1456/* Subtract float */
1457static int emu_seb (struct pt_regs *regs, int rx, float *val) {
1458 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
1459 FP_DECL_EX;
1460 int mode;
1461
1462 mode = current->thread.fp_regs.fpc & 3;
1463 FP_UNPACK_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1464 FP_UNPACK_SP(SB, val);
1465 FP_SUB_S(SR, SA, SB);
1466 FP_PACK_SP(&current->thread.fp_regs.fprs[rx].f, SR);
1467 emu_set_CC_cs(regs, SR_c, SR_s);
1468 return _fex;
1469}
1470
1471/* Test data class long double */
1472static int emu_tcxb (struct pt_regs *regs, int rx, long val) {
1473 FP_DECL_Q(QA);
1474 mathemu_ldcv cvt;
1475 int bit;
1476
1477 cvt.w.high = current->thread.fp_regs.fprs[rx].ui;
1478 cvt.w.low = current->thread.fp_regs.fprs[rx+2].ui;
1479 FP_UNPACK_RAW_QP(QA, &cvt.ld);
1480 switch (QA_e) {
1481 default:
1482 bit = 8; /* normalized number */
1483 break;
1484 case 0:
1485 if (_FP_FRAC_ZEROP_4(QA))
1486 bit = 10; /* zero */
1487 else
1488 bit = 6; /* denormalized number */
1489 break;
1490 case _FP_EXPMAX_Q:
1491 if (_FP_FRAC_ZEROP_4(QA))
1492 bit = 4; /* infinity */
1493 else if (_FP_FRAC_HIGH_RAW_Q(QA) & _FP_QNANBIT_Q)
1494 bit = 2; /* quiet NAN */
1495 else
1496 bit = 0; /* signaling NAN */
1497 break;
1498 }
1499 if (!QA_s)
1500 bit++;
1501 emu_set_CC(regs, ((__u32) val >> bit) & 1);
1502 return 0;
1503}
1504
1505/* Test data class double */
1506static int emu_tcdb (struct pt_regs *regs, int rx, long val) {
1507 FP_DECL_D(DA);
1508 int bit;
1509
1510 FP_UNPACK_RAW_DP(DA, &current->thread.fp_regs.fprs[rx].d);
1511 switch (DA_e) {
1512 default:
1513 bit = 8; /* normalized number */
1514 break;
1515 case 0:
1516 if (_FP_FRAC_ZEROP_2(DA))
1517 bit = 10; /* zero */
1518 else
1519 bit = 6; /* denormalized number */
1520 break;
1521 case _FP_EXPMAX_D:
1522 if (_FP_FRAC_ZEROP_2(DA))
1523 bit = 4; /* infinity */
1524 else if (_FP_FRAC_HIGH_RAW_D(DA) & _FP_QNANBIT_D)
1525 bit = 2; /* quiet NAN */
1526 else
1527 bit = 0; /* signaling NAN */
1528 break;
1529 }
1530 if (!DA_s)
1531 bit++;
1532 emu_set_CC(regs, ((__u32) val >> bit) & 1);
1533 return 0;
1534}
1535
1536/* Test data class float */
1537static int emu_tceb (struct pt_regs *regs, int rx, long val) {
1538 FP_DECL_S(SA);
1539 int bit;
1540
1541 FP_UNPACK_RAW_SP(SA, &current->thread.fp_regs.fprs[rx].f);
1542 switch (SA_e) {
1543 default:
1544 bit = 8; /* normalized number */
1545 break;
1546 case 0:
1547 if (_FP_FRAC_ZEROP_1(SA))
1548 bit = 10; /* zero */
1549 else
1550 bit = 6; /* denormalized number */
1551 break;
1552 case _FP_EXPMAX_S:
1553 if (_FP_FRAC_ZEROP_1(SA))
1554 bit = 4; /* infinity */
1555 else if (_FP_FRAC_HIGH_RAW_S(SA) & _FP_QNANBIT_S)
1556 bit = 2; /* quiet NAN */
1557 else
1558 bit = 0; /* signaling NAN */
1559 break;
1560 }
1561 if (!SA_s)
1562 bit++;
1563 emu_set_CC(regs, ((__u32) val >> bit) & 1);
1564 return 0;
1565}
1566
1567static inline void emu_load_regd(int reg) {
1568 if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
1569 return;
1570 asm volatile ( /* load reg from fp_regs.fprs[reg] */
1571 " bras 1,0f\n"
1572 " ld 0,0(%1)\n"
1573 "0: ex %0,0(1)"
1574 : /* no output */
1575 : "a" (reg<<4),"a" (&current->thread.fp_regs.fprs[reg].d)
1576 : "1" );
1577}
1578
1579static inline void emu_load_rege(int reg) {
1580 if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
1581 return;
1582 asm volatile ( /* load reg from fp_regs.fprs[reg] */
1583 " bras 1,0f\n"
1584 " le 0,0(%1)\n"
1585 "0: ex %0,0(1)"
1586 : /* no output */
1587 : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
1588 : "1" );
1589}
1590
1591static inline void emu_store_regd(int reg) {
1592 if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
1593 return;
1594 asm volatile ( /* store reg to fp_regs.fprs[reg] */
1595 " bras 1,0f\n"
1596 " std 0,0(%1)\n"
1597 "0: ex %0,0(1)"
1598 : /* no output */
1599 : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
1600 : "1" );
1601}
1602
1603
1604static inline void emu_store_rege(int reg) {
1605 if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
1606 return;
1607 asm volatile ( /* store reg to fp_regs.fprs[reg] */
1608 " bras 1,0f\n"
1609 " ste 0,0(%1)\n"
1610 "0: ex %0,0(1)"
1611 : /* no output */
1612 : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
1613 : "1" );
1614}
1615
1616int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
1617 int _fex = 0;
1618 static const __u8 format_table[256] = {
1619 [0x00] = 0x03,[0x01] = 0x03,[0x02] = 0x03,[0x03] = 0x03,
1620 [0x04] = 0x0f,[0x05] = 0x0d,[0x06] = 0x0e,[0x07] = 0x0d,
1621 [0x08] = 0x03,[0x09] = 0x03,[0x0a] = 0x03,[0x0b] = 0x03,
1622 [0x0c] = 0x0f,[0x0d] = 0x03,[0x0e] = 0x06,[0x0f] = 0x06,
1623 [0x10] = 0x02,[0x11] = 0x02,[0x12] = 0x02,[0x13] = 0x02,
1624 [0x14] = 0x03,[0x15] = 0x02,[0x16] = 0x01,[0x17] = 0x03,
1625 [0x18] = 0x02,[0x19] = 0x02,[0x1a] = 0x02,[0x1b] = 0x02,
1626 [0x1c] = 0x02,[0x1d] = 0x02,[0x1e] = 0x05,[0x1f] = 0x05,
1627 [0x40] = 0x01,[0x41] = 0x01,[0x42] = 0x01,[0x43] = 0x01,
1628 [0x44] = 0x12,[0x45] = 0x0d,[0x46] = 0x11,[0x47] = 0x04,
1629 [0x48] = 0x01,[0x49] = 0x01,[0x4a] = 0x01,[0x4b] = 0x01,
1630 [0x4c] = 0x01,[0x4d] = 0x01,[0x53] = 0x06,[0x57] = 0x06,
1631 [0x5b] = 0x05,[0x5f] = 0x05,[0x84] = 0x13,[0x8c] = 0x13,
1632 [0x94] = 0x09,[0x95] = 0x08,[0x96] = 0x07,[0x98] = 0x0c,
1633 [0x99] = 0x0b,[0x9a] = 0x0a
1634 };
1635 static const void *jump_table[256]= {
1636 [0x00] = emu_lpebr,[0x01] = emu_lnebr,[0x02] = emu_ltebr,
1637 [0x03] = emu_lcebr,[0x04] = emu_ldebr,[0x05] = emu_lxdbr,
1638 [0x06] = emu_lxebr,[0x07] = emu_mxdbr,[0x08] = emu_kebr,
1639 [0x09] = emu_cebr, [0x0a] = emu_aebr, [0x0b] = emu_sebr,
1640 [0x0c] = emu_mdebr,[0x0d] = emu_debr, [0x0e] = emu_maebr,
1641 [0x0f] = emu_msebr,[0x10] = emu_lpdbr,[0x11] = emu_lndbr,
1642 [0x12] = emu_ltdbr,[0x13] = emu_lcdbr,[0x14] = emu_sqebr,
1643 [0x15] = emu_sqdbr,[0x16] = emu_sqxbr,[0x17] = emu_meebr,
1644 [0x18] = emu_kdbr, [0x19] = emu_cdbr, [0x1a] = emu_adbr,
1645 [0x1b] = emu_sdbr, [0x1c] = emu_mdbr, [0x1d] = emu_ddbr,
1646 [0x1e] = emu_madbr,[0x1f] = emu_msdbr,[0x40] = emu_lpxbr,
1647 [0x41] = emu_lnxbr,[0x42] = emu_ltxbr,[0x43] = emu_lcxbr,
1648 [0x44] = emu_ledbr,[0x45] = emu_ldxbr,[0x46] = emu_lexbr,
1649 [0x47] = emu_fixbr,[0x48] = emu_kxbr, [0x49] = emu_cxbr,
1650 [0x4a] = emu_axbr, [0x4b] = emu_sxbr, [0x4c] = emu_mxbr,
1651 [0x4d] = emu_dxbr, [0x53] = emu_diebr,[0x57] = emu_fiebr,
1652 [0x5b] = emu_didbr,[0x5f] = emu_fidbr,[0x84] = emu_sfpc,
1653 [0x8c] = emu_efpc, [0x94] = emu_cefbr,[0x95] = emu_cdfbr,
1654 [0x96] = emu_cxfbr,[0x98] = emu_cfebr,[0x99] = emu_cfdbr,
1655 [0x9a] = emu_cfxbr
1656 };
1657
1658 switch (format_table[opcode[1]]) {
1659 case 1: /* RRE format, long double operation */
1660 if (opcode[3] & 0x22)
1661 return SIGILL;
1662 emu_store_regd((opcode[3] >> 4) & 15);
1663 emu_store_regd(((opcode[3] >> 4) & 15) + 2);
1664 emu_store_regd(opcode[3] & 15);
1665 emu_store_regd((opcode[3] & 15) + 2);
1666 /* call the emulation function */
1667 _fex = ((int (*)(struct pt_regs *,int, int))
1668 jump_table[opcode[1]])
1669 (regs, opcode[3] >> 4, opcode[3] & 15);
1670 emu_load_regd((opcode[3] >> 4) & 15);
1671 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
1672 emu_load_regd(opcode[3] & 15);
1673 emu_load_regd((opcode[3] & 15) + 2);
1674 break;
1675 case 2: /* RRE format, double operation */
1676 emu_store_regd((opcode[3] >> 4) & 15);
1677 emu_store_regd(opcode[3] & 15);
1678 /* call the emulation function */
1679 _fex = ((int (*)(struct pt_regs *, int, int))
1680 jump_table[opcode[1]])
1681 (regs, opcode[3] >> 4, opcode[3] & 15);
1682 emu_load_regd((opcode[3] >> 4) & 15);
1683 emu_load_regd(opcode[3] & 15);
1684 break;
1685 case 3: /* RRE format, float operation */
1686 emu_store_rege((opcode[3] >> 4) & 15);
1687 emu_store_rege(opcode[3] & 15);
1688 /* call the emulation function */
1689 _fex = ((int (*)(struct pt_regs *, int, int))
1690 jump_table[opcode[1]])
1691 (regs, opcode[3] >> 4, opcode[3] & 15);
1692 emu_load_rege((opcode[3] >> 4) & 15);
1693 emu_load_rege(opcode[3] & 15);
1694 break;
1695 case 4: /* RRF format, long double operation */
1696 if (opcode[3] & 0x22)
1697 return SIGILL;
1698 emu_store_regd((opcode[3] >> 4) & 15);
1699 emu_store_regd(((opcode[3] >> 4) & 15) + 2);
1700 emu_store_regd(opcode[3] & 15);
1701 emu_store_regd((opcode[3] & 15) + 2);
1702 /* call the emulation function */
1703 _fex = ((int (*)(struct pt_regs *, int, int, int))
1704 jump_table[opcode[1]])
1705 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1706 emu_load_regd((opcode[3] >> 4) & 15);
1707 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
1708 emu_load_regd(opcode[3] & 15);
1709 emu_load_regd((opcode[3] & 15) + 2);
1710 break;
1711 case 5: /* RRF format, double operation */
1712 emu_store_regd((opcode[2] >> 4) & 15);
1713 emu_store_regd((opcode[3] >> 4) & 15);
1714 emu_store_regd(opcode[3] & 15);
1715 /* call the emulation function */
1716 _fex = ((int (*)(struct pt_regs *, int, int, int))
1717 jump_table[opcode[1]])
1718 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1719 emu_load_regd((opcode[2] >> 4) & 15);
1720 emu_load_regd((opcode[3] >> 4) & 15);
1721 emu_load_regd(opcode[3] & 15);
1722 break;
1723 case 6: /* RRF format, float operation */
1724 emu_store_rege((opcode[2] >> 4) & 15);
1725 emu_store_rege((opcode[3] >> 4) & 15);
1726 emu_store_rege(opcode[3] & 15);
1727 /* call the emulation function */
1728 _fex = ((int (*)(struct pt_regs *, int, int, int))
1729 jump_table[opcode[1]])
1730 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1731 emu_load_rege((opcode[2] >> 4) & 15);
1732 emu_load_rege((opcode[3] >> 4) & 15);
1733 emu_load_rege(opcode[3] & 15);
1734 break;
1735 case 7: /* RRE format, cxfbr instruction */
1736 /* call the emulation function */
1737 if (opcode[3] & 0x20)
1738 return SIGILL;
1739 _fex = ((int (*)(struct pt_regs *, int, int))
1740 jump_table[opcode[1]])
1741 (regs, opcode[3] >> 4, opcode[3] & 15);
1742 emu_load_regd((opcode[3] >> 4) & 15);
1743 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
1744 break;
1745 case 8: /* RRE format, cdfbr instruction */
1746 /* call the emulation function */
1747 _fex = ((int (*)(struct pt_regs *, int, int))
1748 jump_table[opcode[1]])
1749 (regs, opcode[3] >> 4, opcode[3] & 15);
1750 emu_load_regd((opcode[3] >> 4) & 15);
1751 break;
1752 case 9: /* RRE format, cefbr instruction */
1753 /* call the emulation function */
1754 _fex = ((int (*)(struct pt_regs *, int, int))
1755 jump_table[opcode[1]])
1756 (regs, opcode[3] >> 4, opcode[3] & 15);
1757 emu_load_rege((opcode[3] >> 4) & 15);
1758 break;
1759 case 10: /* RRF format, cfxbr instruction */
1760 if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
1761 /* mask of { 2,3,8-15 } is invalid */
1762 return SIGILL;
1763 if (opcode[3] & 2)
1764 return SIGILL;
1765 emu_store_regd(opcode[3] & 15);
1766 emu_store_regd((opcode[3] & 15) + 2);
1767 /* call the emulation function */
1768 _fex = ((int (*)(struct pt_regs *, int, int, int))
1769 jump_table[opcode[1]])
1770 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1771 break;
1772 case 11: /* RRF format, cfdbr instruction */
1773 if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
1774 /* mask of { 2,3,8-15 } is invalid */
1775 return SIGILL;
1776 emu_store_regd(opcode[3] & 15);
1777 /* call the emulation function */
1778 _fex = ((int (*)(struct pt_regs *, int, int, int))
1779 jump_table[opcode[1]])
1780 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1781 break;
1782 case 12: /* RRF format, cfebr instruction */
1783 if ((opcode[2] & 128) == 128 || (opcode[2] & 96) == 32)
1784 /* mask of { 2,3,8-15 } is invalid */
1785 return SIGILL;
1786 emu_store_rege(opcode[3] & 15);
1787 /* call the emulation function */
1788 _fex = ((int (*)(struct pt_regs *, int, int, int))
1789 jump_table[opcode[1]])
1790 (regs, opcode[3] >> 4, opcode[3] & 15, opcode[2] >> 4);
1791 break;
1792 case 13: /* RRE format, ldxbr & mdxbr instruction */
1793 /* double store but long double load */
1794 if (opcode[3] & 0x20)
1795 return SIGILL;
1796 emu_store_regd((opcode[3] >> 4) & 15);
1797 emu_store_regd(opcode[3] & 15);
1798 /* call the emulation function */
1799 _fex = ((int (*)(struct pt_regs *, int, int))
1800 jump_table[opcode[1]])
1801 (regs, opcode[3] >> 4, opcode[3] & 15);
1802 emu_load_regd((opcode[3] >> 4) & 15);
1803 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
1804 break;
1805 case 14: /* RRE format, ldxbr & mdxbr instruction */
1806 /* float store but long double load */
1807 if (opcode[3] & 0x20)
1808 return SIGILL;
1809 emu_store_rege((opcode[3] >> 4) & 15);
1810 emu_store_rege(opcode[3] & 15);
1811 /* call the emulation function */
1812 _fex = ((int (*)(struct pt_regs *, int, int))
1813 jump_table[opcode[1]])
1814 (regs, opcode[3] >> 4, opcode[3] & 15);
1815 emu_load_regd((opcode[3] >> 4) & 15);
1816 emu_load_regd(((opcode[3] >> 4) & 15) + 2);
1817 break;
1818 case 15: /* RRE format, ldebr & mdebr instruction */
1819 /* float store but double load */
1820 emu_store_rege((opcode[3] >> 4) & 15);
1821 emu_store_rege(opcode[3] & 15);
1822 /* call the emulation function */
1823 _fex = ((int (*)(struct pt_regs *, int, int))
1824 jump_table[opcode[1]])
1825 (regs, opcode[3] >> 4, opcode[3] & 15);
1826 emu_load_regd((opcode[3] >> 4) & 15);
1827 break;
1828 case 16: /* RRE format, ldxbr instruction */
1829 /* long double store but double load */
1830 if (opcode[3] & 2)
1831 return SIGILL;
1832 emu_store_regd(opcode[3] & 15);
1833 emu_store_regd((opcode[3] & 15) + 2);
1834 /* call the emulation function */
1835 _fex = ((int (*)(struct pt_regs *, int, int))
1836 jump_table[opcode[1]])
1837 (regs, opcode[3] >> 4, opcode[3] & 15);
1838 emu_load_regd((opcode[3] >> 4) & 15);
1839 break;
1840 case 17: /* RRE format, ldxbr instruction */
1841 /* long double store but float load */
1842 if (opcode[3] & 2)
1843 return SIGILL;
1844 emu_store_regd(opcode[3] & 15);
1845 emu_store_regd((opcode[3] & 15) + 2);
1846 /* call the emulation function */
1847 _fex = ((int (*)(struct pt_regs *, int, int))
1848 jump_table[opcode[1]])
1849 (regs, opcode[3] >> 4, opcode[3] & 15);
1850 emu_load_rege((opcode[3] >> 4) & 15);
1851 break;
1852 case 18: /* RRE format, ledbr instruction */
1853 /* double store but float load */
1854 emu_store_regd(opcode[3] & 15);
1855 /* call the emulation function */
1856 _fex = ((int (*)(struct pt_regs *, int, int))
1857 jump_table[opcode[1]])
1858 (regs, opcode[3] >> 4, opcode[3] & 15);
1859 emu_load_rege((opcode[3] >> 4) & 15);
1860 break;
1861 case 19: /* RRE format, efpc & sfpc instruction */
1862 /* call the emulation function */
1863 _fex = ((int (*)(struct pt_regs *, int, int))
1864 jump_table[opcode[1]])
1865 (regs, opcode[3] >> 4, opcode[3] & 15);
1866 break;
1867 default: /* invalid operation */
1868 return SIGILL;
1869 }
1870 if (_fex != 0) {
1871 current->thread.fp_regs.fpc |= _fex;
1872 if (current->thread.fp_regs.fpc & (_fex << 8))
1873 return SIGFPE;
1874 }
1875 return 0;
1876}
1877
1878static void* calc_addr(struct pt_regs *regs, int rx, int rb, int disp)
1879{
1880 addr_t addr;
1881
1882 rx &= 15;
1883 rb &= 15;
1884 addr = disp & 0xfff;
1885 addr += (rx != 0) ? regs->gprs[rx] : 0; /* + index */
1886 addr += (rb != 0) ? regs->gprs[rb] : 0; /* + base */
1887 return (void*) addr;
1888}
1889
1890int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
1891 int _fex = 0;
1892
1893 static const __u8 format_table[256] = {
1894 [0x04] = 0x06,[0x05] = 0x05,[0x06] = 0x07,[0x07] = 0x05,
1895 [0x08] = 0x02,[0x09] = 0x02,[0x0a] = 0x02,[0x0b] = 0x02,
1896 [0x0c] = 0x06,[0x0d] = 0x02,[0x0e] = 0x04,[0x0f] = 0x04,
1897 [0x10] = 0x08,[0x11] = 0x09,[0x12] = 0x0a,[0x14] = 0x02,
1898 [0x15] = 0x01,[0x17] = 0x02,[0x18] = 0x01,[0x19] = 0x01,
1899 [0x1a] = 0x01,[0x1b] = 0x01,[0x1c] = 0x01,[0x1d] = 0x01,
1900 [0x1e] = 0x03,[0x1f] = 0x03,
1901 };
1902 static const void *jump_table[]= {
1903 [0x04] = emu_ldeb,[0x05] = emu_lxdb,[0x06] = emu_lxeb,
1904 [0x07] = emu_mxdb,[0x08] = emu_keb, [0x09] = emu_ceb,
1905 [0x0a] = emu_aeb, [0x0b] = emu_seb, [0x0c] = emu_mdeb,
1906 [0x0d] = emu_deb, [0x0e] = emu_maeb,[0x0f] = emu_mseb,
1907 [0x10] = emu_tceb,[0x11] = emu_tcdb,[0x12] = emu_tcxb,
1908 [0x14] = emu_sqeb,[0x15] = emu_sqdb,[0x17] = emu_meeb,
1909 [0x18] = emu_kdb, [0x19] = emu_cdb, [0x1a] = emu_adb,
1910 [0x1b] = emu_sdb, [0x1c] = emu_mdb, [0x1d] = emu_ddb,
1911 [0x1e] = emu_madb,[0x1f] = emu_msdb
1912 };
1913
1914 switch (format_table[opcode[5]]) {
1915 case 1: /* RXE format, double constant */ {
1916 __u64 *dxb, temp;
1917 __u32 opc;
1918
1919 emu_store_regd((opcode[1] >> 4) & 15);
1920 opc = *((__u32 *) opcode);
1921 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
1922 mathemu_copy_from_user(&temp, dxb, 8);
1923 /* call the emulation function */
1924 _fex = ((int (*)(struct pt_regs *, int, double *))
1925 jump_table[opcode[5]])
1926 (regs, opcode[1] >> 4, (double *) &temp);
1927 emu_load_regd((opcode[1] >> 4) & 15);
1928 break;
1929 }
1930 case 2: /* RXE format, float constant */ {
1931 __u32 *dxb, temp;
1932 __u32 opc;
1933
1934 emu_store_rege((opcode[1] >> 4) & 15);
1935 opc = *((__u32 *) opcode);
1936 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
1937 mathemu_get_user(temp, dxb);
1938 /* call the emulation function */
1939 _fex = ((int (*)(struct pt_regs *, int, float *))
1940 jump_table[opcode[5]])
1941 (regs, opcode[1] >> 4, (float *) &temp);
1942 emu_load_rege((opcode[1] >> 4) & 15);
1943 break;
1944 }
1945 case 3: /* RXF format, double constant */ {
1946 __u64 *dxb, temp;
1947 __u32 opc;
1948
1949 emu_store_regd((opcode[1] >> 4) & 15);
1950 emu_store_regd((opcode[4] >> 4) & 15);
1951 opc = *((__u32 *) opcode);
1952 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
1953 mathemu_copy_from_user(&temp, dxb, 8);
1954 /* call the emulation function */
1955 _fex = ((int (*)(struct pt_regs *, int, double *, int))
1956 jump_table[opcode[5]])
1957 (regs, opcode[1] >> 4, (double *) &temp, opcode[4] >> 4);
1958 emu_load_regd((opcode[1] >> 4) & 15);
1959 break;
1960 }
1961 case 4: /* RXF format, float constant */ {
1962 __u32 *dxb, temp;
1963 __u32 opc;
1964
1965 emu_store_rege((opcode[1] >> 4) & 15);
1966 emu_store_rege((opcode[4] >> 4) & 15);
1967 opc = *((__u32 *) opcode);
1968 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
1969 mathemu_get_user(temp, dxb);
1970 /* call the emulation function */
1971 _fex = ((int (*)(struct pt_regs *, int, float *, int))
1972 jump_table[opcode[5]])
1973 (regs, opcode[1] >> 4, (float *) &temp, opcode[4] >> 4);
1974 emu_load_rege((opcode[4] >> 4) & 15);
1975 break;
1976 }
1977 case 5: /* RXE format, double constant */
1978 /* store double and load long double */
1979 {
1980 __u64 *dxb, temp;
1981 __u32 opc;
1982 if ((opcode[1] >> 4) & 0x20)
1983 return SIGILL;
1984 emu_store_regd((opcode[1] >> 4) & 15);
1985 opc = *((__u32 *) opcode);
1986 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
1987 mathemu_copy_from_user(&temp, dxb, 8);
1988 /* call the emulation function */
1989 _fex = ((int (*)(struct pt_regs *, int, double *))
1990 jump_table[opcode[5]])
1991 (regs, opcode[1] >> 4, (double *) &temp);
1992 emu_load_regd((opcode[1] >> 4) & 15);
1993 emu_load_regd(((opcode[1] >> 4) & 15) + 2);
1994 break;
1995 }
1996 case 6: /* RXE format, float constant */
1997 /* store float and load double */
1998 {
1999 __u32 *dxb, temp;
2000 __u32 opc;
2001 emu_store_rege((opcode[1] >> 4) & 15);
2002 opc = *((__u32 *) opcode);
2003 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2004 mathemu_get_user(temp, dxb);
2005 /* call the emulation function */
2006 _fex = ((int (*)(struct pt_regs *, int, float *))
2007 jump_table[opcode[5]])
2008 (regs, opcode[1] >> 4, (float *) &temp);
2009 emu_load_regd((opcode[1] >> 4) & 15);
2010 break;
2011 }
2012 case 7: /* RXE format, float constant */
2013 /* store float and load long double */
2014 {
2015 __u32 *dxb, temp;
2016 __u32 opc;
2017 if ((opcode[1] >> 4) & 0x20)
2018 return SIGILL;
2019 emu_store_rege((opcode[1] >> 4) & 15);
2020 opc = *((__u32 *) opcode);
2021 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2022 mathemu_get_user(temp, dxb);
2023 /* call the emulation function */
2024 _fex = ((int (*)(struct pt_regs *, int, float *))
2025 jump_table[opcode[5]])
2026 (regs, opcode[1] >> 4, (float *) &temp);
2027 emu_load_regd((opcode[1] >> 4) & 15);
2028 emu_load_regd(((opcode[1] >> 4) & 15) + 2);
2029 break;
2030 }
2031 case 8: /* RXE format, RX address used as int value */ {
2032 __u64 dxb;
2033 __u32 opc;
2034
2035 emu_store_rege((opcode[1] >> 4) & 15);
2036 opc = *((__u32 *) opcode);
2037 dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
2038 /* call the emulation function */
2039 _fex = ((int (*)(struct pt_regs *, int, long))
2040 jump_table[opcode[5]])
2041 (regs, opcode[1] >> 4, dxb);
2042 break;
2043 }
2044 case 9: /* RXE format, RX address used as int value */ {
2045 __u64 dxb;
2046 __u32 opc;
2047
2048 emu_store_regd((opcode[1] >> 4) & 15);
2049 opc = *((__u32 *) opcode);
2050 dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
2051 /* call the emulation function */
2052 _fex = ((int (*)(struct pt_regs *, int, long))
2053 jump_table[opcode[5]])
2054 (regs, opcode[1] >> 4, dxb);
2055 break;
2056 }
2057 case 10: /* RXE format, RX address used as int value */ {
2058 __u64 dxb;
2059 __u32 opc;
2060
2061 if ((opcode[1] >> 4) & 2)
2062 return SIGILL;
2063 emu_store_regd((opcode[1] >> 4) & 15);
2064 emu_store_regd(((opcode[1] >> 4) & 15) + 2);
2065 opc = *((__u32 *) opcode);
2066 dxb = (__u64) calc_addr(regs, opc >> 16, opc >> 12, opc);
2067 /* call the emulation function */
2068 _fex = ((int (*)(struct pt_regs *, int, long))
2069 jump_table[opcode[5]])
2070 (regs, opcode[1] >> 4, dxb);
2071 break;
2072 }
2073 default: /* invalid operation */
2074 return SIGILL;
2075 }
2076 if (_fex != 0) {
2077 current->thread.fp_regs.fpc |= _fex;
2078 if (current->thread.fp_regs.fpc & (_fex << 8))
2079 return SIGFPE;
2080 }
2081 return 0;
2082}
2083
2084/*
2085 * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
2086 */
2087int math_emu_ldr(__u8 *opcode) {
2088 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2089 __u16 opc = *((__u16 *) opcode);
2090
2091 if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
2092 /* we got an exception therfore ry can't be in {0,2,4,6} */
2093 __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */
2094 " bras 1,0f\n"
2095 " ld 0,0(%1)\n"
2096 "0: ex %0,0(1)"
2097 : /* no output */
2098 : "a" (opc & 0xf0),
2099 "a" (&fp_regs->fprs[opc & 0xf].d)
2100 : "1" );
2101 } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */
2102 __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */
2103 " bras 1,0f\n"
2104 " std 0,0(%1)\n"
2105 "0: ex %0,0(1)"
2106 : /* no output */
2107 : "a" ((opc & 0xf) << 4),
2108 "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d)
2109 : "1" );
2110 } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
2111 fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
2112 return 0;
2113}
2114
2115/*
2116 * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
2117 */
2118int math_emu_ler(__u8 *opcode) {
2119 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2120 __u16 opc = *((__u16 *) opcode);
2121
2122 if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
2123 /* we got an exception therfore ry can't be in {0,2,4,6} */
2124 __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */
2125 " bras 1,0f\n"
2126 " le 0,0(%1)\n"
2127 "0: ex %0,0(1)"
2128 : /* no output */
2129 : "a" (opc & 0xf0),
2130 "a" (&fp_regs->fprs[opc & 0xf].f)
2131 : "1" );
2132 } else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */
2133 __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */
2134 " bras 1,0f\n"
2135 " ste 0,0(%1)\n"
2136 "0: ex %0,0(1)"
2137 : /* no output */
2138 : "a" ((opc & 0xf) << 4),
2139 "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f)
2140 : "1" );
2141 } else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
2142 fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
2143 return 0;
2144}
2145
2146/*
2147 * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
2148 */
2149int math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
2150 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2151 __u32 opc = *((__u32 *) opcode);
2152 __u64 *dxb;
2153
2154 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2155 mathemu_copy_from_user(&fp_regs->fprs[(opc >> 20) & 0xf].d, dxb, 8);
2156 return 0;
2157}
2158
2159/*
2160 * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
2161 */
2162int math_emu_le(__u8 *opcode, struct pt_regs * regs) {
2163 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2164 __u32 opc = *((__u32 *) opcode);
2165 __u32 *mem, *dxb;
2166
2167 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2168 mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f);
2169 mathemu_get_user(mem[0], dxb);
2170 return 0;
2171}
2172
2173/*
2174 * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
2175 */
2176int math_emu_std(__u8 *opcode, struct pt_regs * regs) {
2177 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2178 __u32 opc = *((__u32 *) opcode);
2179 __u64 *dxb;
2180
2181 dxb = (__u64 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2182 mathemu_copy_to_user(dxb, &fp_regs->fprs[(opc >> 20) & 0xf].d, 8);
2183 return 0;
2184}
2185
2186/*
2187 * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
2188 */
2189int math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
2190 s390_fp_regs *fp_regs = &current->thread.fp_regs;
2191 __u32 opc = *((__u32 *) opcode);
2192 __u32 *mem, *dxb;
2193
2194 dxb = (__u32 *) calc_addr(regs, opc >> 16, opc >> 12, opc);
2195 mem = (__u32 *) (&fp_regs->fprs[(opc >> 20) & 0xf].f);
2196 mathemu_put_user(mem[0], dxb);
2197 return 0;
2198}
2199
2200/*
2201 * Emulate LFPC D(B)
2202 */
2203int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
2204 __u32 opc = *((__u32 *) opcode);
2205 __u32 *dxb, temp;
2206
2207 dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc);
2208 mathemu_get_user(temp, dxb);
2209 if ((temp & ~FPC_VALID_MASK) != 0)
2210 return SIGILL;
2211 current->thread.fp_regs.fpc = temp;
2212 return 0;
2213}
2214
2215/*
2216 * Emulate STFPC D(B)
2217 */
2218int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
2219 __u32 opc = *((__u32 *) opcode);
2220 __u32 *dxb;
2221
2222 dxb= (__u32 *) calc_addr(regs, 0, opc>>12, opc);
2223 mathemu_put_user(current->thread.fp_regs.fpc, dxb);
2224 return 0;
2225}
2226
2227/*
2228 * Emulate SRNM D(B)
2229 */
2230int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
2231 __u32 opc = *((__u32 *) opcode);
2232 __u32 temp;
2233
2234 temp = calc_addr(regs, 0, opc>>12, opc);
2235 current->thread.fp_regs.fpc &= ~3;
2236 current->thread.fp_regs.fpc |= (temp & 3);
2237 return 0;
2238}
2239
2240/* broken compiler ... */
2241long long
2242__negdi2 (long long u)
2243{
2244
2245 union lll {
2246 long long ll;
2247 long s[2];
2248 };
2249
2250 union lll w,uu;
2251
2252 uu.ll = u;
2253
2254 w.s[1] = -uu.s[1];
2255 w.s[0] = -uu.s[0] - ((int) w.s[1] != 0);
2256
2257 return w.ll;
2258}
diff --git a/arch/s390/math-emu/qrnnd.S b/arch/s390/math-emu/qrnnd.S
new file mode 100644
index 000000000000..b01c2b648e22
--- /dev/null
+++ b/arch/s390/math-emu/qrnnd.S
@@ -0,0 +1,77 @@
1# S/390 __udiv_qrnnd
2
3# r2 : &__r
4# r3 : upper half of 64 bit word n
5# r4 : lower half of 64 bit word n
6# r5 : divisor d
7# the reminder r of the division is to be stored to &__r and
8# the quotient q is to be returned
9
10 .text
11 .globl __udiv_qrnnd
12__udiv_qrnnd:
13 st %r2,24(%r15) # store pointer to reminder for later
14 lr %r0,%r3 # reload n
15 lr %r1,%r4
16 ltr %r2,%r5 # reload and test divisor
17 jp 5f
18 # divisor >= 0x80000000
19 srdl %r0,2 # n/4
20 srl %r2,1 # d/2
21 slr %r1,%r2 # special case if last bit of d is set
22 brc 3,0f # (n/4) div (n/2) can overflow by 1
23 ahi %r0,-1 # trick: subtract n/2, then divide
240: dr %r0,%r2 # signed division
25 ahi %r1,1 # trick part 2: add 1 to the quotient
26 # now (n >> 2) = (d >> 1) * %r1 + %r0
27 lhi %r3,1
28 nr %r3,%r1 # test last bit of q
29 jz 1f
30 alr %r0,%r2 # add (d>>1) to r
311: srl %r1,1 # q >>= 1
32 # now (n >> 2) = (d&-2) * %r1 + %r0
33 lhi %r3,1
34 nr %r3,%r5 # test last bit of d
35 jz 2f
36 slr %r0,%r1 # r -= q
37 brc 3,2f # borrow ?
38 alr %r0,%r5 # r += d
39 ahi %r1,-1
402: # now (n >> 2) = d * %r1 + %r0
41 alr %r1,%r1 # q <<= 1
42 alr %r0,%r0 # r <<= 1
43 brc 12,3f # overflow on r ?
44 slr %r0,%r5 # r -= d
45 ahi %r1,1 # q += 1
463: lhi %r3,2
47 nr %r3,%r4 # test next to last bit of n
48 jz 4f
49 ahi %r0,1 # r += 1
504: clr %r0,%r5 # r >= d ?
51 jl 6f
52 slr %r0,%r5 # r -= d
53 ahi %r1,1 # q += 1
54 # now (n >> 1) = d * %r1 + %r0
55 j 6f
565: # divisor < 0x80000000
57 srdl %r0,1
58 dr %r0,%r2 # signed division
59 # now (n >> 1) = d * %r1 + %r0
606: alr %r1,%r1 # q <<= 1
61 alr %r0,%r0 # r <<= 1
62 brc 12,7f # overflow on r ?
63 slr %r0,%r5 # r -= d
64 ahi %r1,1 # q += 1
657: lhi %r3,1
66 nr %r3,%r4 # isolate last bit of n
67 alr %r0,%r3 # r += (n & 1)
68 clr %r0,%r5 # r >= d ?
69 jl 8f
70 slr %r0,%r5 # r -= d
71 ahi %r1,1 # q += 1
728: # now n = d * %r1 + %r0
73 l %r2,24(%r15)
74 st %r0,0(%r2)
75 lr %r2,%r1
76 br %r14
77 .end __udiv_qrnnd
diff --git a/arch/s390/math-emu/sfp-util.h b/arch/s390/math-emu/sfp-util.h
new file mode 100644
index 000000000000..ab556b600f73
--- /dev/null
+++ b/arch/s390/math-emu/sfp-util.h
@@ -0,0 +1,63 @@
1#include <linux/kernel.h>
2#include <linux/sched.h>
3#include <linux/types.h>
4#include <asm/byteorder.h>
5
6#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({ \
7 unsigned int __sh = (ah); \
8 unsigned int __sl = (al); \
9 __asm__ (" alr %1,%3\n" \
10 " brc 12,0f\n" \
11 " ahi %0,1\n" \
12 "0: alr %0,%2" \
13 : "+&d" (__sh), "+d" (__sl) \
14 : "d" (bh), "d" (bl) : "cc" ); \
15 (sh) = __sh; \
16 (sl) = __sl; \
17})
18
19#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({ \
20 unsigned int __sh = (ah); \
21 unsigned int __sl = (al); \
22 __asm__ (" slr %1,%3\n" \
23 " brc 3,0f\n" \
24 " ahi %0,-1\n" \
25 "0: slr %0,%2" \
26 : "+&d" (__sh), "+d" (__sl) \
27 : "d" (bh), "d" (bl) : "cc" ); \
28 (sh) = __sh; \
29 (sl) = __sl; \
30})
31
32/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */
33#define umul_ppmm(wh, wl, u, v) ({ \
34 unsigned int __wh = u; \
35 unsigned int __wl = v; \
36 __asm__ (" ltr 1,%0\n" \
37 " mr 0,%1\n" \
38 " jnm 0f\n" \
39 " alr 0,%1\n" \
40 "0: ltr %1,%1\n" \
41 " jnm 1f\n" \
42 " alr 0,%0\n" \
43 "1: lr %0,0\n" \
44 " lr %1,1\n" \
45 : "+d" (__wh), "+d" (__wl) \
46 : : "0", "1", "cc" ); \
47 wh = __wh; \
48 wl = __wl; \
49})
50
51#define udiv_qrnnd(q, r, n1, n0, d) \
52 do { unsigned long __r; \
53 (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \
54 (r) = __r; \
55 } while (0)
56extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long,
57 unsigned long , unsigned long);
58
59#define UDIV_NEEDS_NORMALIZATION 0
60
61#define abort() return 0
62
63#define __BYTE_ORDER __BIG_ENDIAN