File: /usr/src/linux/arch/mips64/math-emu/cp1emu.c
1 /*
2 * MIPS floating point support
3 *
4 * This program is free software; you can distribute it and/or modify it
5 * under the terms of the GNU General Public License (Version 2) as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
16 *
17 * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator
18 *
19 * A complete emulator for MIPS coprocessor 1 instructions. This is
20 * required for #float(switch) or #float(trap), where it catches all
21 * COP1 instructions via the "CoProcessor Unusable" exception.
22 *
23 * More surprisingly it is also required for #float(ieee), to help out
24 * the hardware fpu at the boundaries of the IEEE-754 representation
25 * (denormalised values, infinities, underflow, etc). It is made
26 * quite nasty because emulation of some non-COP1 instructions is
27 * required, e.g. in branch delay slots.
28 *
29 * Notes:
30 * 1) the IEEE754 library (-le) performs the actual arithmetic;
31 * 2) if you know that you won't have an fpu, then you'll get much
32 * better performance by compiling with -msoft-float! */
33 *
34 * Nov 7, 2000
35 * Massive changes to integrate with Linux kernel.
36 *
37 * Replace use of kernel data area with use of user stack
38 * for execution of instructions in branch delay slots.
39 *
40 * Replace use of static kernel variables with thread_struct elements.
41 *
42 * Copyright (C) 1994-2000 Algorithmics Ltd. All rights reserved.
43 * http://www.algor.co.uk
44 *
45 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
46 * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
47 */
48 #include <linux/config.h>
49 #include <linux/mm.h>
50 #include <linux/signal.h>
51 #include <linux/smp.h>
52 #include <linux/smp_lock.h>
53
54 #include <asm/asm.h>
55 #include <asm/branch.h>
56 #include <asm/bootinfo.h>
57 #include <asm/byteorder.h>
58 #include <asm/cpu.h>
59 #include <asm/inst.h>
60 #include <asm/uaccess.h>
61 #include <asm/processor.h>
62 #include <asm/mipsregs.h>
63 #include <asm/system.h>
64 #include <asm/pgtable.h>
65
66 #include <asm/fpu_emulator.h>
67
68 #include "ieee754.h"
69
70 /* Strap kernel emulator for full MIPS IV emulation */
71
72 #ifdef __mips
73 #undef __mips
74 #endif
75 #define __mips 4
76
77 typedef void *vaddr_t;
78
79 /* Function which emulates the instruction in a branch delay slot. */
80
81 static int mips_dsemul(struct pt_regs *, mips_instruction, vaddr_t);
82
83 /* Function which emulates a floating point instruction. */
84
85 static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *,
86 mips_instruction);
87
88 #if __mips >= 4 && __mips != 32
89 static int fpux_emu(struct pt_regs *,
90 struct mips_fpu_soft_struct *, mips_instruction);
91 #endif
92
93 /* Further private data for which no space exists in mips_fpu_soft_struct */
94
95 struct mips_fpu_emulator_private fpuemuprivate;
96
97 /* Control registers */
98
99 #define FPCREG_RID 0 /* $0 = revision id */
100 #define FPCREG_CSR 31 /* $31 = csr */
101
102 /* Convert Mips rounding mode (0..3) to IEEE library modes. */
103 static const unsigned char ieee_rm[4] = {
104 IEEE754_RN, IEEE754_RZ, IEEE754_RU, IEEE754_RD
105 };
106
107 #if __mips >= 4
108 /* convert condition code register number to csr bit */
109 static const unsigned int fpucondbit[8] = {
110 FPU_CSR_COND0,
111 FPU_CSR_COND1,
112 FPU_CSR_COND2,
113 FPU_CSR_COND3,
114 FPU_CSR_COND4,
115 FPU_CSR_COND5,
116 FPU_CSR_COND6,
117 FPU_CSR_COND7
118 };
119 #endif
120
121
122
123 /*
124 * Redundant with logic already in kernel/branch.c,
125 * embedded in compute_return_epc. At some point,
126 * a single subroutine should be used across both
127 * modules.
128 */
129 static int isBranchInstr(mips_instruction * i)
130 {
131 switch (MIPSInst_OPCODE(*i)) {
132 case spec_op:
133 switch (MIPSInst_FUNC(*i)) {
134 case jalr_op:
135 case jr_op:
136 return 1;
137 }
138 break;
139
140 case bcond_op:
141 switch (MIPSInst_RT(*i)) {
142 case bltz_op:
143 case bgez_op:
144 case bltzl_op:
145 case bgezl_op:
146 case bltzal_op:
147 case bgezal_op:
148 case bltzall_op:
149 case bgezall_op:
150 return 1;
151 }
152 break;
153
154 case j_op:
155 case jal_op:
156 case jalx_op:
157 case beq_op:
158 case bne_op:
159 case blez_op:
160 case bgtz_op:
161 case beql_op:
162 case bnel_op:
163 case blezl_op:
164 case bgtzl_op:
165 return 1;
166
167 case cop0_op:
168 case cop1_op:
169 case cop2_op:
170 case cop1x_op:
171 if (MIPSInst_RS(*i) == bc_op)
172 return 1;
173 break;
174 }
175
176 return 0;
177 }
178
179 #define REG_TO_VA (vaddr_t)
180 #define VA_TO_REG (unsigned long)
181
182 static unsigned long
183 mips_get_word(struct pt_regs *xcp, void *va, int *perr)
184 {
185 unsigned long temp;
186
187 if (!user_mode(xcp)) {
188 *perr = 0;
189 return (*(unsigned long *) va);
190 } else {
191 /* Use kernel get_user() macro */
192 *perr = (int) get_user(temp, (unsigned long *) va);
193 return temp;
194 }
195 }
196
197 static unsigned long long
198 mips_get_dword(struct pt_regs *xcp, void *va, int *perr)
199 {
200 unsigned long long temp;
201
202 if (!user_mode(xcp)) {
203 *perr = 0;
204 return (*(unsigned long long *) va);
205 } else {
206 /* Use kernel get_user() macro */
207 *perr = (int) get_user(temp, (unsigned long long *) va);
208 return temp;
209 }
210 }
211
212 static int mips_put_word(struct pt_regs *xcp, void *va, unsigned long val)
213 {
214 if (!user_mode(xcp)) {
215 *(unsigned long *) va = val;
216 return 0;
217 } else {
218 /* Use kernel get_user() macro */
219 return (int) put_user(val, (unsigned long *) va);
220 }
221 }
222
223 static int mips_put_dword(struct pt_regs *xcp, void *va, long long val)
224 {
225 if (!user_mode(xcp)) {
226 *(unsigned long long *) va = val;
227 return 0;
228 } else {
229 /* Use kernel get_user() macro */
230 return (int) put_user(val, (unsigned long long *) va);
231 }
232 }
233
234
235 /*
236 * In the Linux kernel, we support selection of FPR format on the
237 * basis of the Status.FR bit. This does imply that, if a full 32
238 * FPRs are desired, there needs to be a flip-flop that can be written
239 * to one at that bit position. In any case, normal MIPS ABI uses
240 * only the even FPRs (Status.FR = 0).
241 */
242
243 #define CP0_STATUS_FR_SUPPORT
244
245 /*
246 * Emulate the single floating point instruction pointed at by EPC.
247 * Two instructions if the instruction is in a branch delay slot.
248 */
249
250 static int
251 cop1Emulate(int xcptno, struct pt_regs *xcp,
252 struct mips_fpu_soft_struct *ctx)
253 {
254 mips_instruction ir;
255 vaddr_t emulpc;
256 vaddr_t contpc;
257 unsigned int cond;
258 int err = 0;
259
260
261 ir = mips_get_word(xcp, REG_TO_VA xcp->cp0_epc, &err);
262 if (err) {
263 fpuemuprivate.stats.errors++;
264 return SIGBUS;
265 }
266
267 /* XXX NEC Vr54xx bug workaround */
268 if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
269 xcp->cp0_cause &= ~CAUSEF_BD;
270
271 if (xcp->cp0_cause & CAUSEF_BD) {
272 /*
273 * The instruction to be emulated is in a branch delay slot
274 * which means that we have to emulate the branch instruction
275 * BEFORE we do the cop1 instruction.
276 *
277 * This branch could be a COP1 branch, but in that case we
278 * would have had a trap for that instruction, and would not
279 * come through this route.
280 *
281 * Linux MIPS branch emulator operates on context, updating the
282 * cp0_epc.
283 */
284 emulpc = REG_TO_VA(xcp->cp0_epc + 4); /* Snapshot emulation target */
285
286 if (__compute_return_epc(xcp)) {
287 #ifdef CP1DBG
288 printk("failed to emulate branch at %p\n",
289 REG_TO_VA(xcp->cp0_epc));
290 #endif
291 return SIGILL;;
292 }
293 ir = mips_get_word(xcp, emulpc, &err);
294 if (err) {
295 fpuemuprivate.stats.errors++;
296 return SIGBUS;
297 }
298 contpc = REG_TO_VA xcp->cp0_epc;
299 } else {
300 emulpc = REG_TO_VA xcp->cp0_epc;
301 contpc = REG_TO_VA xcp->cp0_epc + 4;
302 }
303
304 emul:
305 fpuemuprivate.stats.emulated++;
306 switch (MIPSInst_OPCODE(ir)) {
307 #ifdef CP0_STATUS_FR_SUPPORT
308 /* R4000+ 64-bit fpu registers */
309 #ifndef SINGLE_ONLY_FPU
310 case ldc1_op:
311 {
312 void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
313 + MIPSInst_SIMM(ir);
314 int ft = MIPSInst_RT(ir);
315 if (!(xcp->cp0_status & ST0_FR))
316 ft &= ~1;
317 ctx->regs[ft] = mips_get_dword(xcp, va, &err);
318 fpuemuprivate.stats.loads++;
319 if (err) {
320 fpuemuprivate.stats.errors++;
321 return SIGBUS;
322 }
323 }
324 break;
325
326 case sdc1_op:
327 {
328 void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
329 + MIPSInst_SIMM(ir);
330 int ft = MIPSInst_RT(ir);
331 if (!(xcp->cp0_status & ST0_FR))
332 ft &= ~1;
333 fpuemuprivate.stats.stores++;
334 if (mips_put_dword(xcp, va, ctx->regs[ft])) {
335 fpuemuprivate.stats.errors++;
336 return SIGBUS;
337 }
338 }
339 break;
340 #endif
341
342 case lwc1_op:
343 {
344 void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
345 + MIPSInst_SIMM(ir);
346 fpureg_t val;
347 int ft = MIPSInst_RT(ir);
348 fpuemuprivate.stats.loads++;
349 val = mips_get_word(xcp, va, &err);
350 if (err) {
351 fpuemuprivate.stats.errors++;
352 return SIGBUS;
353 }
354 if (xcp->cp0_status & ST0_FR) {
355 /* load whole register */
356 ctx->regs[ft] = val;
357 } else if (ft & 1) {
358 /* load to m.s. 32 bits */
359 #ifdef SINGLE_ONLY_FPU
360 /* illegal register in single-float mode */
361 return SIGILL;
362 #else
363 ctx->regs[(ft & ~1)] &= 0xffffffff;
364 ctx->regs[(ft & ~1)] |= val << 32;
365 #endif
366 } else {
367 /* load to l.s. 32 bits */
368 ctx->regs[ft] &= ~0xffffffffLL;
369 ctx->regs[ft] |= val;
370 }
371 }
372 break;
373
374 case swc1_op:
375 {
376 void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
377 + MIPSInst_SIMM(ir);
378 unsigned int val;
379 int ft = MIPSInst_RT(ir);
380 fpuemuprivate.stats.stores++;
381 if (xcp->cp0_status & ST0_FR) {
382 /* store whole register */
383 val = ctx->regs[ft];
384 } else if (ft & 1) {
385 #ifdef SINGLE_ONLY_FPU
386 /* illegal register in single-float mode */
387 return SIGILL;
388 #else
389 /* store from m.s. 32 bits */
390 val = ctx->regs[(ft & ~1)] >> 32;
391 #endif
392 } else {
393 /* store from l.s. 32 bits */
394 val = ctx->regs[ft];
395 }
396 if (mips_put_word(xcp, va, val)) {
397 fpuemuprivate.stats.errors++;
398 return SIGBUS;
399 }
400 }
401 break;
402 #else /* old 32-bit fpu registers */
403 case lwc1_op:
404 {
405 void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
406 + MIPSInst_SIMM(ir);
407 ctx->regs[MIPSInst_RT(ir)] =
408 mips_get_word(xcp, va, &err);
409 fpuemuprivate.stats.loads++;
410 if (err) {
411 fpuemuprivate.stats.errors++;
412 return SIGBUS;
413 }
414 }
415 break;
416
417 case swc1_op:
418 {
419 void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
420 + MIPSInst_SIMM(ir);
421 fpuemuprivate.stats.stores++;
422 if (mips_put_word
423 (xcp, va, ctx->regs[MIPSInst_RT(ir)])) {
424 fpuemuprivate.stats.errors++;
425 return SIGBUS;
426 }
427 }
428 break;
429 case ldc1_op:
430 {
431 void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
432 + MIPSInst_SIMM(ir);
433 unsigned int rt = MIPSInst_RT(ir) & ~1;
434 int errs = 0;
435 fpuemuprivate.stats.loads++;
436 #if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
437 ctx->regs[rt + 1] =
438 mips_get_word(xcp, va + 0, &err);
439 errs += err;
440 ctx->regs[rt + 0] =
441 mips_get_word(xcp, va + 4, &err);
442 errs += err;
443 #else
444 ctx->regs[rt + 0] =
445 mips_get_word(xcp, va + 0, &err);
446 errs += err;
447 ctx->regs[rt + 1] =
448 mips_get_word(xcp, va + 4, &err);
449 errs += err;
450 #endif
451 if (err)
452 return SIGBUS;
453 }
454 break;
455
456 case sdc1_op:
457 {
458 void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
459 + MIPSInst_SIMM(ir);
460 unsigned int rt = MIPSInst_RT(ir) & ~1;
461 fpuemuprivate.stats.stores++;
462 #if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
463 if (mips_put_word(xcp, va + 0, ctx->regs[rt + 1]))
464 return SIGBUS;
465 if (mips_put_word(xcp, va + 4, ctx->regs[rt + 0]))
466 return SIGBUS;
467 #else
468 if (mips_put_word(xcp, va + 0, ctx->regs[rt + 0]))
469 return SIGBUS;
470 if (mips_put_word(xcp, va + 4, ctx->regs[rt + 1]))
471 return SIGBUS;
472 #endif
473 }
474 break;
475 #endif
476
477 case cop1_op:
478 switch (MIPSInst_RS(ir)) {
479
480 #ifdef CP0_STATUS_FR_SUPPORT
481 #if __mips64 && !defined(SINGLE_ONLY_FPU)
482 case dmfc_op:
483 /* copregister fs -> gpr[rt] */
484 if (MIPSInst_RT(ir) != 0) {
485 int fs = MIPSInst_RD(ir);
486 if (!(xcp->cp0_status & ST0_FR))
487 fs &= ~1;
488 xcp->regs[MIPSInst_RT(ir)] = ctx->regs[fs];
489 }
490 break;
491
492 case dmtc_op:
493 /* copregister fs <- rt */
494 {
495 fpureg_t value;
496 int fs = MIPSInst_RD(ir);
497 if (!(xcp->cp0_status & ST0_FR))
498 fs &= ~1;
499 value =
500 (MIPSInst_RT(ir) ==
501 0) ? 0 : xcp->regs[MIPSInst_RT(ir)];
502 ctx->regs[fs] = value;
503 }
504 break;
505 #endif
506
507 case mfc_op:
508 /* copregister rd -> gpr[rt] */
509 if (MIPSInst_RT(ir) != 0) {
510 /* default value from l.s. 32 bits */
511 int value = ctx->regs[MIPSInst_RD(ir)];
512 if (MIPSInst_RD(ir) & 1) {
513 #ifdef SINGLE_ONLY_FPU
514 /* illegal register in single-float mode */
515 return SIGILL;
516 #else
517 if (!(xcp->cp0_status & ST0_FR)) {
518 /* move from m.s. 32 bits */
519 value =
520 ctx->
521 regs[MIPSInst_RD(ir) &
522 ~1] >> 32;
523 }
524 #endif
525 }
526 xcp->regs[MIPSInst_RT(ir)] = value;
527 }
528 break;
529
530 case mtc_op:
531 /* copregister rd <- rt */
532 {
533 fpureg_t value;
534 if (MIPSInst_RT(ir) == 0)
535 value = 0;
536 else
537 value =
538 (unsigned int) xcp->
539 regs[MIPSInst_RT(ir)];
540 if (MIPSInst_RD(ir) & 1) {
541 #ifdef SINGLE_ONLY_FPU
542 /* illegal register in single-float mode */
543 return SIGILL;
544 #else
545 if (!(xcp->cp0_status & ST0_FR)) {
546 /* move to m.s. 32 bits */
547 ctx->
548 regs[
549 (MIPSInst_RD(ir) &
550 ~1)] &=
551 0xffffffff;
552 ctx->
553 regs[
554 (MIPSInst_RD(ir) &
555 ~1)] |=
556 value << 32;
557 break;
558 }
559 #endif
560 }
561 /* move to l.s. 32 bits */
562 ctx->regs[MIPSInst_RD(ir)] &=
563 ~0xffffffffLL;
564 ctx->regs[MIPSInst_RD(ir)] |= value;
565 }
566 break;
567 #else
568
569 case mfc_op:
570 /* copregister rd -> gpr[rt] */
571 if (MIPSInst_RT(ir) != 0) {
572 unsigned value =
573 ctx->regs[MIPSInst_RD(ir)];
574 xcp->regs[MIPSInst_RT(ir)] = value;
575 }
576 break;
577
578 case mtc_op:
579 /* copregister rd <- rt */
580 {
581 unsigned value;
582 value =
583 (MIPSInst_RT(ir) ==
584 0) ? 0 : xcp->regs[MIPSInst_RT(ir)];
585 ctx->regs[MIPSInst_RD(ir)] = value;
586 }
587 break;
588 #endif
589
590 case cfc_op:
591 /* cop control register rd -> gpr[rt] */
592 {
593 unsigned value;
594
595 if (MIPSInst_RD(ir) == FPCREG_CSR) {
596 value = ctx->sr;
597 #ifdef CSRTRACE
598 printk
599 ("%p gpr[%d]<-csr=%08x\n",
600 REG_TO_VA(xcp->cp0_epc),
601 MIPSInst_RT(ir), value);
602 #endif
603 } else if (MIPSInst_RD(ir) == FPCREG_RID)
604 value = 0;
605 else
606 value = 0;
607 if (MIPSInst_RT(ir))
608 xcp->regs[MIPSInst_RT(ir)] = value;
609 }
610 break;
611
612 case ctc_op:
613 /* copregister rd <- rt */
614 {
615 unsigned value;
616
617 if (MIPSInst_RT(ir) == 0)
618 value = 0;
619 else
620 value = xcp->regs[MIPSInst_RT(ir)];
621
622 /* we only have one writable control reg
623 */
624 if (MIPSInst_RD(ir) == FPCREG_CSR) {
625 #ifdef CSRTRACE
626 printk
627 ("%p gpr[%d]->csr=%08x\n",
628 REG_TO_VA(xcp->cp0_epc),
629 MIPSInst_RT(ir), value);
630 #endif
631 ctx->sr = value;
632 /* copy new rounding mode to ieee library state! */
633 ieee754_csr.rm =
634 ieee_rm[value & 0x3];
635 }
636 }
637 break;
638
639 case bc_op:
640 if (xcp->cp0_cause & CAUSEF_BD) {
641 return SIGILL;
642 }
643 {
644 int likely = 0;
645
646 #if __mips >= 4
647 cond =
648 ctx->
649 sr & fpucondbit[MIPSInst_RT(ir) >> 2];
650 #else
651 cond = ctx->sr & FPU_CSR_COND;
652 #endif
653 switch (MIPSInst_RT(ir) & 3) {
654 case bcfl_op:
655 likely = 1;
656 case bcf_op:
657 cond = !cond;
658 break;
659 case bctl_op:
660 likely = 1;
661 case bct_op:
662 break;
663 default:
664 /* thats an illegal instruction */
665 return SIGILL;
666 }
667
668 xcp->cp0_cause |= CAUSEF_BD;
669 if (cond) {
670 /* branch taken: emulate dslot instruction */
671 xcp->cp0_epc += 4;
672 contpc =
673 REG_TO_VA xcp->cp0_epc +
674 (MIPSInst_SIMM(ir) << 2);
675
676 ir =
677 mips_get_word(xcp,
678 REG_TO_VA(xcp->
679 cp0_epc),
680 &err);
681 if (err) {
682 fpuemuprivate.stats.
683 errors++;
684 return SIGBUS;
685 }
686
687 switch (MIPSInst_OPCODE(ir)) {
688 case lwc1_op:
689 case swc1_op:
690 #if (__mips >= 2 || __mips64) && !defined(SINGLE_ONLY_FPU)
691 case ldc1_op:
692 case sdc1_op:
693 #endif
694 case cop1_op:
695 #if __mips >= 4 && __mips != 32
696 case cop1x_op:
697 #endif
698 /* its one of ours */
699 goto emul;
700 #if __mips >= 4
701 case spec_op:
702 if (MIPSInst_FUNC(ir) ==
703 movc_op) goto emul;
704 break;
705 #endif
706 }
707
708 /* single step the non-cp1 instruction in the dslot */
709 return mips_dsemul(xcp, ir, contpc);
710 } else {
711 /* branch not taken */
712 if (likely)
713 /* branch likely nullifies dslot if not taken */
714 xcp->cp0_epc += 4;
715 /* else continue & execute dslot as normal insn */
716 }
717 }
718 break;
719
720 default:
721 if (!(MIPSInst_RS(ir) & 0x10)) {
722 return SIGILL;
723 }
724 /* a real fpu computation instruction */
725 {
726 int sig;
727 if ((sig = fpu_emu(xcp, ctx, ir)))
728 return sig;
729 }
730 }
731 break;
732
733 #if __mips >= 4 && __mips != 32
734 case cop1x_op:
735 {
736 int sig;
737 if ((sig = fpux_emu(xcp, ctx, ir)))
738 return sig;
739 }
740 break;
741 #endif
742
743 #if __mips >= 4
744 case spec_op:
745 if (MIPSInst_FUNC(ir) != movc_op)
746 return SIGILL;
747 cond = fpucondbit[MIPSInst_RT(ir) >> 2];
748 if (((ctx->sr & cond) != 0) !=
749 ((MIPSInst_RT(ir) & 1) != 0)) return 0;
750 xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)];
751 break;
752 #endif
753
754 default:
755 return SIGILL;
756 }
757
758 /* we did it !! */
759 xcp->cp0_epc = VA_TO_REG(contpc);
760 xcp->cp0_cause &= ~CAUSEF_BD;
761 return 0;
762 }
763
764 /*
765 * Emulate the arbritrary instruction ir at xcp->cp0_epc. Required when
766 * we have to emulate the instruction in a COP1 branch delay slot. Do
767 * not change cp0_epc due to the instruction
768 *
769 * According to the spec:
770 * 1) it shouldnt be a branch :-)
771 * 2) it can be a COP instruction :-(
772 * 3) if we are tring to run a protected memory space we must take
773 * special care on memory access instructions :-(
774 */
775
776 /*
777 * "Trampoline" return routine to catch exception following
778 * execution of delay-slot instruction execution.
779 */
780
781 int do_dsemulret(struct pt_regs *xcp)
782 {
783 #ifdef DSEMUL_TRACE
784 printk("desemulret\n");
785 #endif
786 /* Set EPC to return to post-branch instruction */
787 xcp->cp0_epc = current->thread.dsemul_epc;
788 /*
789 * Clear the state that got us here.
790 */
791 current->thread.dsemul_aerpc = (unsigned long) 0;
792
793 return 0;
794 }
795
796
797 #define AdELOAD 0x8c000001 /* lw $0,1($0) */
798
799 static int
800 mips_dsemul(struct pt_regs *xcp, mips_instruction ir, vaddr_t cpc)
801 {
802 mips_instruction *dsemul_insns;
803 mips_instruction forcetrap;
804 extern asmlinkage void handle_dsemulret(void);
805
806 if (ir == 0) { /* a nop is easy */
807 xcp->cp0_epc = VA_TO_REG(cpc);
808 return 0;
809 }
810 #ifdef DSEMUL_TRACE
811 printk("desemul %p %p\n", REG_TO_VA(xcp->cp0_epc), cpc);
812 #endif
813
814 /*
815 * The strategy is to push the instruction onto the user stack
816 * and put a trap after it which we can catch and jump to
817 * the required address any alternative apart from full
818 * instruction emulation!!.
819 */
820 dsemul_insns = (mips_instruction *) (xcp->regs[29] & ~3);
821 dsemul_insns -= 3; /* Two instructions, plus one for luck ;-) */
822 /* Verify that the stack pointer is not competely insane */
823 if (verify_area
824 (VERIFY_WRITE, dsemul_insns, sizeof(mips_instruction) * 2))
825 return SIGBUS;
826
827 if (mips_put_word(xcp, &dsemul_insns[0], ir)) {
828 fpuemuprivate.stats.errors++;
829 return (SIGBUS);
830 }
831
832 /*
833 * Algorithmics used a system call instruction, and
834 * borrowed that vector. MIPS/Linux version is a bit
835 * more heavyweight in the interests of portability and
836 * multiprocessor support. We flag the thread for special
837 * handling in the unaligned access handler and force an
838 * address error excpetion.
839 */
840
841 /* If one is *really* paranoid, one tests for a bad stack pointer */
842 if ((xcp->regs[29] & 0x3) == 0x3)
843 forcetrap = AdELOAD - 1;
844 else
845 forcetrap = AdELOAD;
846
847 if (mips_put_word(xcp, &dsemul_insns[1], forcetrap)) {
848 fpuemuprivate.stats.errors++;
849 return (SIGBUS);
850 }
851
852 /* Set thread state to catch and handle the exception */
853 current->thread.dsemul_epc = (unsigned long) cpc;
854 current->thread.dsemul_aerpc = (unsigned long) &dsemul_insns[1];
855 xcp->cp0_epc = VA_TO_REG & dsemul_insns[0];
856 flush_cache_sigtramp((unsigned long) dsemul_insns);
857
858 return SIGILL; /* force out of emulation loop */
859 }
860
861 /*
862 * Conversion table from MIPS compare ops 48-63
863 * cond = ieee754dp_cmp(x,y,IEEE754_UN);
864 */
865 static const unsigned char cmptab[8] = {
866 0, /* cmp_0 (sig) cmp_sf */
867 IEEE754_CUN, /* cmp_un (sig) cmp_ngle */
868 IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */
869 IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */
870 IEEE754_CLT, /* cmp_olt (sig) cmp_lt */
871 IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */
872 IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */
873 IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */
874 };
875
876 #define SIFROMREG(si,x) ((si) = ctx->regs[x])
877 #define SITOREG(si,x) (ctx->regs[x] = (int)(si))
878
879 #if __mips64 && !defined(SINGLE_ONLY_FPU)
880 #define DIFROMREG(di,x) ((di) = ctx->regs[x])
881 #define DITOREG(di,x) (ctx->regs[x] = (di))
882 #endif
883
884 #define SPFROMREG(sp,x) ((sp).bits = ctx->regs[x])
885 #define SPTOREG(sp,x) (ctx->regs[x] = (sp).bits)
886
887 #ifdef CP0_STATUS_FR_SUPPORT
888 #define DPFROMREG(dp,x) ((dp).bits = \
889 ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)])
890 #define DPTOREG(dp,x) (ctx->regs[(xcp->cp0_status & ST0_FR) ? x : (x & ~1)]\
891 = (dp).bits)
892 #else
893 /* Beware: MIPS COP1 doubles are always little_word endian in registers */
894 #define DPFROMREG(dp,x) \
895 ((dp).bits = ((unsigned long long)ctx->regs[(x)+1] << 32) | ctx->regs[x])
896 #define DPTOREG(dp,x) \
897 (ctx->regs[x] = (dp).bits, ctx->regs[(x)+1] = (dp).bits >> 32)
898 #endif
899
900 #if __mips >= 4 && __mips != 32
901
902 /*
903 * Additional MIPS4 instructions
904 */
905
906 static ieee754dp fpemu_dp_recip(ieee754dp d)
907 {
908 return ieee754dp_div(ieee754dp_one(0), d);
909 }
910
911 static ieee754dp fpemu_dp_rsqrt(ieee754dp d)
912 {
913 return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d));
914 }
915
916 static ieee754sp fpemu_sp_recip(ieee754sp s)
917 {
918 return ieee754sp_div(ieee754sp_one(0), s);
919 }
920
921 static ieee754sp fpemu_sp_rsqrt(ieee754sp s)
922 {
923 return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s));
924 }
925
926
927 static ieee754dp fpemu_dp_madd(ieee754dp r, ieee754dp s, ieee754dp t)
928 {
929 return ieee754dp_add(ieee754dp_mul(s, t), r);
930 }
931
932 static ieee754dp fpemu_dp_msub(ieee754dp r, ieee754dp s, ieee754dp t)
933 {
934 return ieee754dp_sub(ieee754dp_mul(s, t), r);
935 }
936
937 static ieee754dp fpemu_dp_nmadd(ieee754dp r, ieee754dp s, ieee754dp t)
938 {
939 return ieee754dp_neg(ieee754dp_add(ieee754dp_mul(s, t), r));
940 }
941
942 static ieee754dp fpemu_dp_nmsub(ieee754dp r, ieee754dp s, ieee754dp t)
943 {
944 return ieee754dp_neg(ieee754dp_sub(ieee754dp_mul(s, t), r));
945 }
946
947
948 static ieee754sp fpemu_sp_madd(ieee754sp r, ieee754sp s, ieee754sp t)
949 {
950 return ieee754sp_add(ieee754sp_mul(s, t), r);
951 }
952
953 static ieee754sp fpemu_sp_msub(ieee754sp r, ieee754sp s, ieee754sp t)
954 {
955 return ieee754sp_sub(ieee754sp_mul(s, t), r);
956 }
957
958 static ieee754sp fpemu_sp_nmadd(ieee754sp r, ieee754sp s, ieee754sp t)
959 {
960 return ieee754sp_neg(ieee754sp_add(ieee754sp_mul(s, t), r));
961 }
962
963 static ieee754sp fpemu_sp_nmsub(ieee754sp r, ieee754sp s, ieee754sp t)
964 {
965 return ieee754sp_neg(ieee754sp_sub(ieee754sp_mul(s, t), r));
966 }
967
968 static int
969 fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
970 mips_instruction ir)
971 {
972 unsigned rcsr = 0; /* resulting csr */
973
974 fpuemuprivate.stats.cp1xops++;
975
976 switch (MIPSInst_FMA_FFMT(ir)) {
977 case s_fmt: /* 0 */
978 {
979 ieee754sp(*handler) (ieee754sp, ieee754sp,
980 ieee754sp);
981 ieee754sp fd, fr, fs, ft;
982
983 switch (MIPSInst_FUNC(ir)) {
984 case lwxc1_op:
985 {
986 void *va =
987 REG_TO_VA(xcp->
988 regs[MIPSInst_FR(ir)]
989 +
990 xcp->
991 regs[MIPSInst_FT
992 (ir)]);
993 fpureg_t val;
994 int err = 0;
995 val = mips_get_word(xcp, va, &err);
996 if (err) {
997 fpuemuprivate.stats.
998 errors++;
999 return SIGBUS;
1000 }
1001 if (xcp->cp0_status & ST0_FR) {
1002 /* load whole register */
1003 ctx->
1004 regs[MIPSInst_FD(ir)] =
1005 val;
1006 } else if (MIPSInst_FD(ir) & 1) {
1007 /* load to m.s. 32 bits */
1008 #if defined(SINGLE_ONLY_FPU)
1009 /* illegal register in single-float mode */
1010 return SIGILL;
1011 #else
1012 ctx->
1013 regs[
1014 (MIPSInst_FD(ir) &
1015 ~1)] &=
1016 0xffffffff;
1017 ctx->
1018 regs[
1019 (MIPSInst_FD(ir) &
1020 ~1)] |=
1021 val << 32;
1022 #endif
1023 } else {
1024 /* load to l.s. 32 bits */
1025 ctx->
1026 regs[MIPSInst_FD(ir)]
1027 &= ~0xffffffffLL;
1028 ctx->
1029 regs[MIPSInst_FD(ir)]
1030 |= val;
1031 }
1032 }
1033 break;
1034
1035 case swxc1_op:
1036 {
1037 void *va =
1038 REG_TO_VA(xcp->
1039 regs[MIPSInst_FR(ir)]
1040 +
1041 xcp->
1042 regs[MIPSInst_FT
1043 (ir)]);
1044 unsigned int val;
1045 if (xcp->cp0_status & ST0_FR) {
1046 /* store whole register */
1047 val =
1048 ctx->
1049 regs[MIPSInst_FS(ir)];
1050 } else if (MIPSInst_FS(ir) & 1) {
1051 #if defined(SINGLE_ONLY_FPU)
1052 /* illegal register in single-float mode */
1053 return SIGILL;
1054 #else
1055 /* store from m.s. 32 bits */
1056 val =
1057 ctx->
1058 regs[
1059 (MIPSInst_FS(ir) &
1060 ~1)] >> 32;
1061 #endif
1062 } else {
1063 /* store from l.s. 32 bits */
1064 val =
1065 ctx->
1066 regs[MIPSInst_FS(ir)];
1067 }
1068 if (mips_put_word(xcp, va, val)) {
1069 fpuemuprivate.stats.
1070 errors++;
1071 return SIGBUS;
1072 }
1073 }
1074 break;
1075
1076 case madd_s_op:
1077 handler = fpemu_sp_madd;
1078 goto scoptop;
1079 case msub_s_op:
1080 handler = fpemu_sp_msub;
1081 goto scoptop;
1082 case nmadd_s_op:
1083 handler = fpemu_sp_nmadd;
1084 goto scoptop;
1085 case nmsub_s_op:
1086 handler = fpemu_sp_nmsub;
1087 goto scoptop;
1088
1089 scoptop:
1090 SPFROMREG(fr, MIPSInst_FR(ir));
1091 SPFROMREG(fs, MIPSInst_FS(ir));
1092 SPFROMREG(ft, MIPSInst_FT(ir));
1093 fd = (*handler) (fr, fs, ft);
1094 SPTOREG(fd, MIPSInst_FD(ir));
1095
1096 copcsr:
1097 if (ieee754_cxtest(IEEE754_INEXACT))
1098 rcsr |=
1099 FPU_CSR_INE_X | FPU_CSR_INE_S;
1100 if (ieee754_cxtest(IEEE754_UNDERFLOW))
1101 rcsr |=
1102 FPU_CSR_UDF_X | FPU_CSR_UDF_S;
1103 if (ieee754_cxtest(IEEE754_OVERFLOW))
1104 rcsr |=
1105 FPU_CSR_OVF_X | FPU_CSR_OVF_S;
1106 if (ieee754_cxtest
1107 (IEEE754_INVALID_OPERATION)) rcsr |=
1108 FPU_CSR_INV_X | FPU_CSR_INV_S;
1109
1110 ctx->sr =
1111 (ctx->sr & ~FPU_CSR_ALL_X) | rcsr;
1112 if ((ctx->sr >> 5) & ctx->
1113 sr & FPU_CSR_ALL_E) {
1114 /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */
1115 return SIGFPE;
1116 }
1117
1118 break;
1119
1120 default:
1121 return SIGILL;
1122 }
1123 }
1124 break;
1125
1126 #if !defined(SINGLE_ONLY_FPU)
1127 case d_fmt: /* 1 */
1128 {
1129 ieee754dp(*handler) (ieee754dp, ieee754dp,
1130 ieee754dp);
1131 ieee754dp fd, fr, fs, ft;
1132
1133 switch (MIPSInst_FUNC(ir)) {
1134 case ldxc1_op:
1135 {
1136 void *va =
1137 REG_TO_VA(xcp->
1138 regs[MIPSInst_FR(ir)]
1139 +
1140 xcp->
1141 regs[MIPSInst_FT
1142 (ir)]);
1143 int err = 0;
1144 ctx->regs[MIPSInst_FD(ir)] =
1145 mips_get_dword(xcp, va, &err);
1146 if (err) {
1147 fpuemuprivate.stats.
1148 errors++;
1149 return SIGBUS;
1150 }
1151 }
1152 break;
1153
1154 case sdxc1_op:
1155 {
1156 void *va =
1157 REG_TO_VA(xcp->
1158 regs[MIPSInst_FR(ir)]
1159 +
1160 xcp->
1161 regs[MIPSInst_FT
1162 (ir)]);
1163 if (mips_put_dword
1164 (xcp, va,
1165 ctx->regs[MIPSInst_FS(ir)])) {
1166 fpuemuprivate.stats.
1167 errors++;
1168 return SIGBUS;
1169 }
1170 }
1171 break;
1172
1173 case madd_d_op:
1174 handler = fpemu_dp_madd;
1175 goto dcoptop;
1176 case msub_d_op:
1177 handler = fpemu_dp_msub;
1178 goto dcoptop;
1179 case nmadd_d_op:
1180 handler = fpemu_dp_nmadd;
1181 goto dcoptop;
1182 case nmsub_d_op:
1183 handler = fpemu_dp_nmsub;
1184 goto dcoptop;
1185
1186 dcoptop:
1187 DPFROMREG(fr, MIPSInst_FR(ir));
1188 DPFROMREG(fs, MIPSInst_FS(ir));
1189 DPFROMREG(ft, MIPSInst_FT(ir));
1190 fd = (*handler) (fr, fs, ft);
1191 DPTOREG(fd, MIPSInst_FD(ir));
1192 goto copcsr;
1193
1194 default:
1195 return SIGILL;
1196 }
1197 }
1198 break;
1199 #endif
1200
1201 case 0x7: /* 7 */
1202 {
1203 if (MIPSInst_FUNC(ir) != pfetch_op) {
1204 return SIGILL;
1205 }
1206 /* ignore prefx operation */
1207 }
1208 break;
1209
1210 default:
1211 return SIGILL;
1212 }
1213
1214 return 0;
1215 }
1216 #endif
1217
1218
1219
1220 /*
1221 * Emulate a single COP1 arithmetic instruction.
1222 */
1223 static int
1224 fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
1225 mips_instruction ir)
1226 {
1227 int rfmt; /* resulting format */
1228 unsigned rcsr = 0; /* resulting csr */
1229 unsigned cond;
1230 union {
1231 ieee754dp d;
1232 ieee754sp s;
1233 int w;
1234 #if __mips64
1235 long long l;
1236 #endif
1237 } rv; /* resulting value */
1238
1239 fpuemuprivate.stats.cp1ops++;
1240 switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
1241
1242 case s_fmt:{ /* 0 */
1243 ieee754sp(*handler) ();
1244
1245 switch (MIPSInst_FUNC(ir)) {
1246 /* binary ops */
1247 case fadd_op:
1248 handler = ieee754sp_add;
1249 goto scopbop;
1250 case fsub_op:
1251 handler = ieee754sp_sub;
1252 goto scopbop;
1253 case fmul_op:
1254 handler = ieee754sp_mul;
1255 goto scopbop;
1256 case fdiv_op:
1257 handler = ieee754sp_div;
1258 goto scopbop;
1259
1260 /* unary ops */
1261 #if __mips >= 2 || __mips64
1262 case fsqrt_op:
1263 handler = ieee754sp_sqrt;
1264 goto scopuop;
1265 #endif
1266 #if __mips >= 4 && __mips != 32
1267 case frsqrt_op:
1268 handler = fpemu_sp_rsqrt;
1269 goto scopuop;
1270 case frecip_op:
1271 handler = fpemu_sp_recip;
1272 goto scopuop;
1273 #endif
1274 #if __mips >= 4
1275 case fmovc_op:
1276 cond = fpucondbit[MIPSInst_FT(ir) >> 2];
1277 if (((ctx->sr & cond) != 0) !=
1278 ((MIPSInst_FT(ir) & 1) != 0))
1279 return 0;
1280 SPFROMREG(rv.s, MIPSInst_FS(ir));
1281 break;
1282 case fmovz_op:
1283 if (xcp->regs[MIPSInst_FT(ir)] != 0)
1284 return 0;
1285 SPFROMREG(rv.s, MIPSInst_FS(ir));
1286 break;
1287 case fmovn_op:
1288 if (xcp->regs[MIPSInst_FT(ir)] == 0)
1289 return 0;
1290 SPFROMREG(rv.s, MIPSInst_FS(ir));
1291 break;
1292 #endif
1293 case fabs_op:
1294 handler = ieee754sp_abs;
1295 goto scopuop;
1296 case fneg_op:
1297 handler = ieee754sp_neg;
1298 goto scopuop;
1299 case fmov_op:
1300 /* an easy one */
1301 SPFROMREG(rv.s, MIPSInst_FS(ir));
1302 break;
1303 /* binary op on handler */
1304 scopbop:
1305 {
1306 ieee754sp fs, ft;
1307
1308 SPFROMREG(fs, MIPSInst_FS(ir));
1309 SPFROMREG(ft, MIPSInst_FT(ir));
1310
1311 rv.s = (*handler) (fs, ft);
1312 goto copcsr;
1313 }
1314 scopuop:
1315 {
1316 ieee754sp fs;
1317
1318 SPFROMREG(fs, MIPSInst_FS(ir));
1319 rv.s = (*handler) (fs);
1320 goto copcsr;
1321 }
1322 copcsr:
1323 if (ieee754_cxtest(IEEE754_INEXACT))
1324 rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
1325 if (ieee754_cxtest(IEEE754_UNDERFLOW))
1326 rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
1327 if (ieee754_cxtest(IEEE754_OVERFLOW))
1328 rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
1329 if (ieee754_cxtest(IEEE754_ZERO_DIVIDE))
1330 rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S;
1331 if (ieee754_cxtest
1332 (IEEE754_INVALID_OPERATION)) rcsr |=
1333 FPU_CSR_INV_X | FPU_CSR_INV_S;
1334 break;
1335
1336 /* unary conv ops */
1337 case fcvts_op:
1338 return SIGILL; /* not defined */
1339 case fcvtd_op:
1340 #if defined(SINGLE_ONLY_FPU)
1341 return SIGILL; /* not defined */
1342 #else
1343 {
1344 ieee754sp fs;
1345
1346 SPFROMREG(fs, MIPSInst_FS(ir));
1347 rv.d = ieee754dp_fsp(fs);
1348 rfmt = d_fmt;
1349 goto copcsr;
1350 }
1351 #endif
1352 case fcvtw_op:
1353 {
1354 ieee754sp fs;
1355
1356 SPFROMREG(fs, MIPSInst_FS(ir));
1357 rv.w = ieee754sp_tint(fs);
1358 rfmt = w_fmt;
1359 goto copcsr;
1360 }
1361
1362 #if __mips >= 2 || __mips64
1363 case fround_op:
1364 case ftrunc_op:
1365 case fceil_op:
1366 case ffloor_op:
1367 {
1368 unsigned int oldrm = ieee754_csr.rm;
1369 ieee754sp fs;
1370
1371 SPFROMREG(fs, MIPSInst_FS(ir));
1372 ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
1373 rv.w = ieee754sp_tint(fs);
1374 ieee754_csr.rm = oldrm;
1375 rfmt = w_fmt;
1376 goto copcsr;
1377 }
1378 #endif /* __mips >= 2 */
1379
1380 #if __mips64 && !defined(SINGLE_ONLY_FPU)
1381 case fcvtl_op:
1382 {
1383 ieee754sp fs;
1384
1385 SPFROMREG(fs, MIPSInst_FS(ir));
1386 rv.l = ieee754sp_tlong(fs);
1387 rfmt = l_fmt;
1388 goto copcsr;
1389 }
1390
1391 case froundl_op:
1392 case ftruncl_op:
1393 case fceill_op:
1394 case ffloorl_op:
1395 {
1396 unsigned int oldrm = ieee754_csr.rm;
1397 ieee754sp fs;
1398
1399 SPFROMREG(fs, MIPSInst_FS(ir));
1400 ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
1401 rv.l = ieee754sp_tlong(fs);
1402 ieee754_csr.rm = oldrm;
1403 rfmt = l_fmt;
1404 goto copcsr;
1405 }
1406 #endif /* __mips64 && !fpu(single) */
1407
1408 default:
1409 if (MIPSInst_FUNC(ir) >= fcmp_op) {
1410 unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
1411 ieee754sp fs, ft;
1412
1413 SPFROMREG(fs, MIPSInst_FS(ir));
1414 SPFROMREG(ft, MIPSInst_FT(ir));
1415 rv.w = ieee754sp_cmp(fs, ft, cmptab[cmpop & 0x7]);
1416 rfmt = -1;
1417 if ((cmpop & 0x8) && ieee754_cxtest(IEEE754_INVALID_OPERATION))
1418 rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
1419 } else {
1420 return SIGILL;
1421 }
1422 break;
1423 }
1424 break;
1425 }
1426
1427 #if !defined(SINGLE_ONLY_FPU)
1428 case d_fmt: {
1429 ieee754dp(*handler) ();
1430
1431 switch (MIPSInst_FUNC(ir)) {
1432 /* binary ops */
1433 case fadd_op:
1434 handler = ieee754dp_add;
1435 goto dcopbop;
1436 case fsub_op:
1437 handler = ieee754dp_sub;
1438 goto dcopbop;
1439 case fmul_op:
1440 handler = ieee754dp_mul;
1441 goto dcopbop;
1442 case fdiv_op:
1443 handler = ieee754dp_div;
1444 goto dcopbop;
1445
1446 /* unary ops */
1447 #if __mips >= 2 || __mips64
1448 case fsqrt_op:
1449 handler = ieee754dp_sqrt;
1450 goto dcopuop;
1451 #endif
1452 #if __mips >= 4 && __mips != 32
1453 case frsqrt_op:
1454 handler = fpemu_dp_rsqrt;
1455 goto dcopuop;
1456 case frecip_op:
1457 handler = fpemu_dp_recip;
1458 goto dcopuop;
1459 #endif
1460 #if __mips >= 4
1461 case fmovc_op:
1462 cond = fpucondbit[MIPSInst_FT(ir) >> 2];
1463 if (((ctx->sr & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0))
1464 return 0;
1465 DPFROMREG(rv.d, MIPSInst_FS(ir));
1466 break;
1467 case fmovz_op:
1468 if (xcp->regs[MIPSInst_FT(ir)] != 0)
1469 return 0;
1470 DPFROMREG(rv.d, MIPSInst_FS(ir));
1471 break;
1472 case fmovn_op:
1473 if (xcp->regs[MIPSInst_FT(ir)] == 0)
1474 return 0;
1475 DPFROMREG(rv.d, MIPSInst_FS(ir));
1476 break;
1477 #endif
1478 case fabs_op:
1479 handler = ieee754dp_abs;
1480 goto dcopuop;
1481 case fneg_op:
1482 handler = ieee754dp_neg;
1483 goto dcopuop;
1484 case fmov_op:
1485 /* an easy one */
1486 DPFROMREG(rv.d, MIPSInst_FS(ir));
1487 break;
1488
1489 /* binary op on handler */
1490 dcopbop:
1491 {
1492 ieee754dp fs, ft;
1493
1494 DPFROMREG(fs, MIPSInst_FS(ir));
1495 DPFROMREG(ft, MIPSInst_FT(ir));
1496
1497 rv.d = (*handler) (fs, ft);
1498 goto copcsr;
1499 }
1500 dcopuop:
1501 {
1502 ieee754dp fs;
1503
1504 DPFROMREG(fs, MIPSInst_FS(ir));
1505 rv.d = (*handler) (fs);
1506 goto copcsr;
1507 }
1508
1509 /* unary conv ops */
1510 case fcvts_op:
1511 {
1512 ieee754dp fs;
1513
1514 DPFROMREG(fs, MIPSInst_FS(ir));
1515 rv.s = ieee754sp_fdp(fs);
1516 rfmt = s_fmt;
1517 goto copcsr;
1518 }
1519 case fcvtd_op:
1520 return SIGILL; /* not defined */
1521 case fcvtw_op:
1522 {
1523 ieee754dp fs;
1524
1525 DPFROMREG(fs, MIPSInst_FS(ir));
1526 rv.w = ieee754dp_tint(fs); /* wrong */
1527 rfmt = w_fmt;
1528 goto copcsr;
1529 }
1530
1531 #if __mips >= 2 || __mips64
1532 case fround_op:
1533 case ftrunc_op:
1534 case fceil_op:
1535 case ffloor_op:
1536 {
1537 unsigned int oldrm = ieee754_csr.rm;
1538 ieee754dp fs;
1539
1540 DPFROMREG(fs, MIPSInst_FS(ir));
1541 ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
1542 rv.w = ieee754dp_tint(fs);
1543 ieee754_csr.rm = oldrm;
1544 rfmt = w_fmt;
1545 goto copcsr;
1546 }
1547 #endif
1548
1549 #if __mips64 && !defined(SINGLE_ONLY_FPU)
1550 case fcvtl_op:
1551 {
1552 ieee754dp fs;
1553
1554 DPFROMREG(fs, MIPSInst_FS(ir));
1555 rv.l = ieee754dp_tlong(fs);
1556 rfmt = l_fmt;
1557 goto copcsr;
1558 }
1559
1560 case froundl_op:
1561 case ftruncl_op:
1562 case fceill_op:
1563 case ffloorl_op:
1564 {
1565 unsigned int oldrm = ieee754_csr.rm;
1566 ieee754dp fs;
1567
1568 DPFROMREG(fs, MIPSInst_FS(ir));
1569 ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
1570 rv.l = ieee754dp_tlong(fs);
1571 ieee754_csr.rm = oldrm;
1572 rfmt = l_fmt;
1573 goto copcsr;
1574 }
1575 #endif /* __mips >= 3 && !fpu(single) */
1576
1577 default:
1578 if (MIPSInst_FUNC(ir) >= fcmp_op) {
1579 unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
1580 ieee754dp fs, ft;
1581
1582 DPFROMREG(fs, MIPSInst_FS(ir));
1583 DPFROMREG(ft, MIPSInst_FT(ir));
1584 rv.w = ieee754dp_cmp(fs, ft, cmptab[cmpop & 0x7]);
1585 rfmt = -1;
1586 if ((cmpop & 0x8) && ieee754_cxtest (IEEE754_INVALID_OPERATION))
1587 rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
1588 } else {
1589 return SIGILL;
1590 }
1591 break;
1592 }
1593 break;
1594 }
1595 #endif /* !defined(SINGLE_ONLY_FPU) */
1596
1597 case w_fmt: {
1598 switch (MIPSInst_FUNC(ir)) {
1599 case fcvts_op:
1600 /* convert word to single precision real */
1601 rv.s = ieee754sp_fint(ctx-> regs[MIPSInst_FS(ir)]);
1602 rfmt = s_fmt;
1603 goto copcsr;
1604 #if !defined(SINGLE_ONLY_FPU)
1605 case fcvtd_op:
1606 /* convert word to double precision real */
1607 rv.d = ieee754dp_fint(ctx-> regs[MIPSInst_FS(ir)]);
1608 rfmt = d_fmt;
1609 goto copcsr;
1610 #endif
1611 default:
1612 return SIGILL;
1613 }
1614 break;
1615 }
1616
1617 #if __mips64 && !defined(SINGLE_ONLY_FPU)
1618 case l_fmt: {
1619 switch (MIPSInst_FUNC(ir)) {
1620 case fcvts_op:
1621 /* convert long to single precision real */
1622 rv.s = ieee754sp_flong(ctx-> regs[MIPSInst_FS(ir)]);
1623 rfmt = s_fmt;
1624 goto copcsr;
1625 case fcvtd_op:
1626 /* convert long to double precision real */
1627 rv.d = ieee754dp_flong(ctx-> regs[MIPSInst_FS(ir)]);
1628 rfmt = d_fmt;
1629 goto copcsr;
1630 default:
1631 return SIGILL;
1632 }
1633 break;
1634 }
1635 #endif
1636
1637 default:
1638 return SIGILL;
1639 }
1640
1641 /*
1642 * Update the fpu CSR register for this operation.
1643 * If an exception is required, generate a tidy SIGFPE exception,
1644 * without updating the result register.
1645 * Note: cause exception bits do not accumulate, they are rewritten
1646 * for each op; only the flag/sticky bits accumulate.
1647 */
1648 ctx->sr = (ctx->sr & ~FPU_CSR_ALL_X) | rcsr;
1649 if ((ctx->sr >> 5) & ctx->sr & FPU_CSR_ALL_E) {
1650 /*printk ("SIGFPE: fpu csr = %08x\n",ctx->sr); */
1651 return SIGFPE;
1652 }
1653
1654 /*
1655 * Now we can safely write the result back to the register file.
1656 */
1657 switch (rfmt) {
1658 case -1: {
1659 #if __mips >= 4
1660 cond = fpucondbit[MIPSInst_FD(ir) >> 2];
1661 #else
1662 cond = FPU_CSR_COND;
1663 #endif
1664 if (rv.w)
1665 ctx->sr |= cond;
1666 else
1667 ctx->sr &= ~cond;
1668 break;
1669 }
1670 #if !defined(SINGLE_ONLY_FPU)
1671 case d_fmt:
1672 DPTOREG(rv.d, MIPSInst_FD(ir));
1673 break;
1674 #endif
1675 case s_fmt:
1676 SPTOREG(rv.s, MIPSInst_FD(ir));
1677 break;
1678 case w_fmt:
1679 SITOREG(rv.w, MIPSInst_FD(ir));
1680 break;
1681 #if __mips64 && !defined(SINGLE_ONLY_FPU)
1682 case l_fmt:
1683 DITOREG(rv.l, MIPSInst_FD(ir));
1684 break;
1685 #endif
1686 default:
1687 return SIGILL;
1688 }
1689
1690 return 0;
1691 }
1692
1693
1694 /*
1695 * Emulate the floating point instruction at EPC, and continue
1696 * to run until we hit a non-fp instruction, or a backward
1697 * branch. This cuts down dramatically on the per instruction
1698 * exception overhead.
1699 */
1700 int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp)
1701 {
1702 struct mips_fpu_soft_struct *ctx = ¤t->thread.fpu.soft;
1703 unsigned long oldepc, prevepc;
1704 unsigned int insn;
1705 int sig = 0;
1706 int err = 0;
1707
1708 oldepc = xcp->cp0_epc;
1709 do {
1710 if (current->need_resched)
1711 schedule();
1712
1713 prevepc = xcp->cp0_epc;
1714 insn = mips_get_word(xcp, REG_TO_VA(xcp->cp0_epc), &err);
1715 if (err) {
1716 fpuemuprivate.stats.errors++;
1717 return SIGBUS;
1718 }
1719 if (insn != 0)
1720 sig = cop1Emulate(xcptno, xcp, ctx);
1721 else
1722 xcp->cp0_epc += 4; /* skip nops */
1723
1724 if (mips_cpu.options & MIPS_CPU_FPU)
1725 break;
1726 } while (xcp->cp0_epc > prevepc && sig == 0);
1727
1728 /* SIGILL indicates a non-fpu instruction */
1729 if (sig == SIGILL && xcp->cp0_epc != oldepc)
1730 /* but if epc has advanced, then ignore it */
1731 sig = 0;
1732
1733 return sig;
1734 }
1735
1736
1737 #ifdef NOTDEF
1738 /*
1739 * Patch up the hardware fpu state when an f.p. exception occurs.
1740 */
1741 static int cop1Patcher(int xcptno, struct pt_regs *xcp)
1742 {
1743 struct mips_fpu_soft_struct *ctx = ¤t->thread.fpu.soft;
1744 unsigned sr;
1745 int sig;
1746
1747 /* reenable Cp1, else fpe_save() will get nested exception */
1748 sr = mips_bissr(ST0_CU1);
1749
1750 /* get fpu registers and status, then clear pending exceptions */
1751 fpe_save(ctx);
1752 fpe_setsr(ctx->sr &= ~FPU_CSR_ALL_X);
1753
1754 /* get current rounding mode for IEEE library, and emulate insn */
1755 ieee754_csr.rm = ieee_rm[ctx->sr & 0x3];
1756 sig = cop1Emulate(xcptno, xcp, ctx);
1757
1758 /* don't return with f.p. exceptions pending */
1759 ctx->sr &= ~FPU_CSR_ALL_X;
1760 fpe_restore(ctx);
1761
1762 mips_setsr(sr);
1763 return sig;
1764 }
1765
1766 void _cop1_init(int emulate)
1767 {
1768 extern int _nofpu;
1769
1770 if (emulate) {
1771 /*
1772 * Install cop1 emulator to handle "coprocessor unusable" exception
1773 */
1774 xcption(XCPTCPU, cop1Handler);
1775 fpuemuactive = 1; /* tell dbg.c that we are in charge */
1776 _nofpu = 0; /* tell setjmp() it "has" an fpu */
1777 } else {
1778 /*
1779 * Install cop1 emulator for floating point exceptions only,
1780 * i.e. denormalised results, underflow, overflow etc, which
1781 * must be emulated in s/w.
1782 */
1783 #ifdef 1
1784 /* r4000 or above use dedicate exception */
1785 xcption(XCPTFPE, cop1Patcher);
1786 #else
1787 /* r3000 et al use interrupt */
1788 extern int _sbd_getfpuintr(void);
1789 int intno = _sbd_getfpuintr();
1790 intrupt(intno, cop1Patcher, 0);
1791 mips_bissr(SR_IM0 << intno);
1792 #endif
1793
1794 #if (#cpu(r4640) || #cpu(r4650)) && !defined(SINGLE_ONLY_FPU)
1795 /* For R4640/R4650 compiled *without* the -msingle-float flag,
1796 then we share responsibility: the h/w handles the single
1797 precision operations, and the trap emulator handles the
1798 double precision. We set fpuemuactive so that dbg.c first
1799 fetches the s/w state before saving the h/w state. */
1800 fpuemuactive = 1;
1801 {
1802 int i;
1803 /* initialise the unused d.p high order words to be NaN */
1804 for (i = 0; i < 32; i++)
1805 current->thread.fpu.soft.regs[i] =
1806 0x7ff80bad00000000LL;
1807 }
1808 #endif /* (r4640 || r4650) && !fpu(single) */
1809 }
1810 }
1811 #endif
1812
1813