diff options
Diffstat (limited to 'arch/mips/math-emu/cp1emu.c')
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 934 |
1 files changed, 340 insertions, 594 deletions
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 7b3c9acae689..736c17a226e9 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator | 2 | * cp1emu.c: a MIPS coprocessor 1 (FPU) instruction emulator |
3 | * | 3 | * |
4 | * MIPS floating point support | 4 | * MIPS floating point support |
5 | * Copyright (C) 1994-2000 Algorithmics Ltd. | 5 | * Copyright (C) 1994-2000 Algorithmics Ltd. |
@@ -18,61 +18,46 @@ | |||
18 | * | 18 | * |
19 | * You should have received a copy of the GNU General Public License along | 19 | * You should have received a copy of the GNU General Public License along |
20 | * with this program; if not, write to the Free Software Foundation, Inc., | 20 | * with this program; if not, write to the Free Software Foundation, Inc., |
21 | * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. | 21 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
22 | * | 22 | * |
23 | * A complete emulator for MIPS coprocessor 1 instructions. This is | 23 | * A complete emulator for MIPS coprocessor 1 instructions. This is |
24 | * required for #float(switch) or #float(trap), where it catches all | 24 | * required for #float(switch) or #float(trap), where it catches all |
25 | * COP1 instructions via the "CoProcessor Unusable" exception. | 25 | * COP1 instructions via the "CoProcessor Unusable" exception. |
26 | * | 26 | * |
27 | * More surprisingly it is also required for #float(ieee), to help out | 27 | * More surprisingly it is also required for #float(ieee), to help out |
28 | * the hardware fpu at the boundaries of the IEEE-754 representation | 28 | * the hardware FPU at the boundaries of the IEEE-754 representation |
29 | * (denormalised values, infinities, underflow, etc). It is made | 29 | * (denormalised values, infinities, underflow, etc). It is made |
30 | * quite nasty because emulation of some non-COP1 instructions is | 30 | * quite nasty because emulation of some non-COP1 instructions is |
31 | * required, e.g. in branch delay slots. | 31 | * required, e.g. in branch delay slots. |
32 | * | 32 | * |
33 | * Note if you know that you won't have an fpu, then you'll get much | 33 | * Note if you know that you won't have an FPU, then you'll get much |
34 | * better performance by compiling with -msoft-float! | 34 | * better performance by compiling with -msoft-float! |
35 | */ | 35 | */ |
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <linux/module.h> | ||
38 | #include <linux/debugfs.h> | 37 | #include <linux/debugfs.h> |
38 | #include <linux/kconfig.h> | ||
39 | #include <linux/percpu-defs.h> | ||
39 | #include <linux/perf_event.h> | 40 | #include <linux/perf_event.h> |
40 | 41 | ||
42 | #include <asm/branch.h> | ||
41 | #include <asm/inst.h> | 43 | #include <asm/inst.h> |
42 | #include <asm/bootinfo.h> | ||
43 | #include <asm/processor.h> | ||
44 | #include <asm/ptrace.h> | 44 | #include <asm/ptrace.h> |
45 | #include <asm/signal.h> | 45 | #include <asm/signal.h> |
46 | #include <asm/mipsregs.h> | 46 | #include <asm/uaccess.h> |
47 | |||
48 | #include <asm/processor.h> | ||
47 | #include <asm/fpu_emulator.h> | 49 | #include <asm/fpu_emulator.h> |
48 | #include <asm/fpu.h> | 50 | #include <asm/fpu.h> |
49 | #include <asm/uaccess.h> | ||
50 | #include <asm/branch.h> | ||
51 | 51 | ||
52 | #include "ieee754.h" | 52 | #include "ieee754.h" |
53 | 53 | ||
54 | /* Strap kernel emulator for full MIPS IV emulation */ | ||
55 | |||
56 | #ifdef __mips | ||
57 | #undef __mips | ||
58 | #endif | ||
59 | #define __mips 4 | ||
60 | |||
61 | /* Function which emulates a floating point instruction. */ | 54 | /* Function which emulates a floating point instruction. */ |
62 | 55 | ||
63 | static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, | 56 | static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, |
64 | mips_instruction); | 57 | mips_instruction); |
65 | 58 | ||
66 | #if __mips >= 4 && __mips != 32 | ||
67 | static int fpux_emu(struct pt_regs *, | 59 | static int fpux_emu(struct pt_regs *, |
68 | struct mips_fpu_struct *, mips_instruction, void *__user *); | 60 | struct mips_fpu_struct *, mips_instruction, void *__user *); |
69 | #endif | ||
70 | |||
71 | /* Further private data for which no space exists in mips_fpu_struct */ | ||
72 | |||
73 | #ifdef CONFIG_DEBUG_FS | ||
74 | DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); | ||
75 | #endif | ||
76 | 61 | ||
77 | /* Control registers */ | 62 | /* Control registers */ |
78 | 63 | ||
@@ -82,27 +67,6 @@ DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats); | |||
82 | /* Determine rounding mode from the RM bits of the FCSR */ | 67 | /* Determine rounding mode from the RM bits of the FCSR */ |
83 | #define modeindex(v) ((v) & FPU_CSR_RM) | 68 | #define modeindex(v) ((v) & FPU_CSR_RM) |
84 | 69 | ||
85 | /* microMIPS bitfields */ | ||
86 | #define MM_POOL32A_MINOR_MASK 0x3f | ||
87 | #define MM_POOL32A_MINOR_SHIFT 0x6 | ||
88 | #define MM_MIPS32_COND_FC 0x30 | ||
89 | |||
90 | /* Convert Mips rounding mode (0..3) to IEEE library modes. */ | ||
91 | static const unsigned char ieee_rm[4] = { | ||
92 | [FPU_CSR_RN] = IEEE754_RN, | ||
93 | [FPU_CSR_RZ] = IEEE754_RZ, | ||
94 | [FPU_CSR_RU] = IEEE754_RU, | ||
95 | [FPU_CSR_RD] = IEEE754_RD, | ||
96 | }; | ||
97 | /* Convert IEEE library modes to Mips rounding mode (0..3). */ | ||
98 | static const unsigned char mips_rm[4] = { | ||
99 | [IEEE754_RN] = FPU_CSR_RN, | ||
100 | [IEEE754_RZ] = FPU_CSR_RZ, | ||
101 | [IEEE754_RD] = FPU_CSR_RD, | ||
102 | [IEEE754_RU] = FPU_CSR_RU, | ||
103 | }; | ||
104 | |||
105 | #if __mips >= 4 | ||
106 | /* convert condition code register number to csr bit */ | 70 | /* convert condition code register number to csr bit */ |
107 | static const unsigned int fpucondbit[8] = { | 71 | static const unsigned int fpucondbit[8] = { |
108 | FPU_CSR_COND0, | 72 | FPU_CSR_COND0, |
@@ -114,10 +78,6 @@ static const unsigned int fpucondbit[8] = { | |||
114 | FPU_CSR_COND6, | 78 | FPU_CSR_COND6, |
115 | FPU_CSR_COND7 | 79 | FPU_CSR_COND7 |
116 | }; | 80 | }; |
117 | #endif | ||
118 | |||
119 | /* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */ | ||
120 | static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7}; | ||
121 | 81 | ||
122 | /* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ | 82 | /* (microMIPS) Convert certain microMIPS instructions to MIPS32 format. */ |
123 | static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; | 83 | static const int sd_format[] = {16, 17, 0, 0, 0, 0, 0, 0}; |
@@ -466,199 +426,6 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) | |||
466 | return 0; | 426 | return 0; |
467 | } | 427 | } |
468 | 428 | ||
469 | int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | ||
470 | unsigned long *contpc) | ||
471 | { | ||
472 | union mips_instruction insn = (union mips_instruction)dec_insn.insn; | ||
473 | int bc_false = 0; | ||
474 | unsigned int fcr31; | ||
475 | unsigned int bit; | ||
476 | |||
477 | if (!cpu_has_mmips) | ||
478 | return 0; | ||
479 | |||
480 | switch (insn.mm_i_format.opcode) { | ||
481 | case mm_pool32a_op: | ||
482 | if ((insn.mm_i_format.simmediate & MM_POOL32A_MINOR_MASK) == | ||
483 | mm_pool32axf_op) { | ||
484 | switch (insn.mm_i_format.simmediate >> | ||
485 | MM_POOL32A_MINOR_SHIFT) { | ||
486 | case mm_jalr_op: | ||
487 | case mm_jalrhb_op: | ||
488 | case mm_jalrs_op: | ||
489 | case mm_jalrshb_op: | ||
490 | if (insn.mm_i_format.rt != 0) /* Not mm_jr */ | ||
491 | regs->regs[insn.mm_i_format.rt] = | ||
492 | regs->cp0_epc + | ||
493 | dec_insn.pc_inc + | ||
494 | dec_insn.next_pc_inc; | ||
495 | *contpc = regs->regs[insn.mm_i_format.rs]; | ||
496 | return 1; | ||
497 | } | ||
498 | } | ||
499 | break; | ||
500 | case mm_pool32i_op: | ||
501 | switch (insn.mm_i_format.rt) { | ||
502 | case mm_bltzals_op: | ||
503 | case mm_bltzal_op: | ||
504 | regs->regs[31] = regs->cp0_epc + | ||
505 | dec_insn.pc_inc + | ||
506 | dec_insn.next_pc_inc; | ||
507 | /* Fall through */ | ||
508 | case mm_bltz_op: | ||
509 | if ((long)regs->regs[insn.mm_i_format.rs] < 0) | ||
510 | *contpc = regs->cp0_epc + | ||
511 | dec_insn.pc_inc + | ||
512 | (insn.mm_i_format.simmediate << 1); | ||
513 | else | ||
514 | *contpc = regs->cp0_epc + | ||
515 | dec_insn.pc_inc + | ||
516 | dec_insn.next_pc_inc; | ||
517 | return 1; | ||
518 | case mm_bgezals_op: | ||
519 | case mm_bgezal_op: | ||
520 | regs->regs[31] = regs->cp0_epc + | ||
521 | dec_insn.pc_inc + | ||
522 | dec_insn.next_pc_inc; | ||
523 | /* Fall through */ | ||
524 | case mm_bgez_op: | ||
525 | if ((long)regs->regs[insn.mm_i_format.rs] >= 0) | ||
526 | *contpc = regs->cp0_epc + | ||
527 | dec_insn.pc_inc + | ||
528 | (insn.mm_i_format.simmediate << 1); | ||
529 | else | ||
530 | *contpc = regs->cp0_epc + | ||
531 | dec_insn.pc_inc + | ||
532 | dec_insn.next_pc_inc; | ||
533 | return 1; | ||
534 | case mm_blez_op: | ||
535 | if ((long)regs->regs[insn.mm_i_format.rs] <= 0) | ||
536 | *contpc = regs->cp0_epc + | ||
537 | dec_insn.pc_inc + | ||
538 | (insn.mm_i_format.simmediate << 1); | ||
539 | else | ||
540 | *contpc = regs->cp0_epc + | ||
541 | dec_insn.pc_inc + | ||
542 | dec_insn.next_pc_inc; | ||
543 | return 1; | ||
544 | case mm_bgtz_op: | ||
545 | if ((long)regs->regs[insn.mm_i_format.rs] <= 0) | ||
546 | *contpc = regs->cp0_epc + | ||
547 | dec_insn.pc_inc + | ||
548 | (insn.mm_i_format.simmediate << 1); | ||
549 | else | ||
550 | *contpc = regs->cp0_epc + | ||
551 | dec_insn.pc_inc + | ||
552 | dec_insn.next_pc_inc; | ||
553 | return 1; | ||
554 | case mm_bc2f_op: | ||
555 | case mm_bc1f_op: | ||
556 | bc_false = 1; | ||
557 | /* Fall through */ | ||
558 | case mm_bc2t_op: | ||
559 | case mm_bc1t_op: | ||
560 | preempt_disable(); | ||
561 | if (is_fpu_owner()) | ||
562 | asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); | ||
563 | else | ||
564 | fcr31 = current->thread.fpu.fcr31; | ||
565 | preempt_enable(); | ||
566 | |||
567 | if (bc_false) | ||
568 | fcr31 = ~fcr31; | ||
569 | |||
570 | bit = (insn.mm_i_format.rs >> 2); | ||
571 | bit += (bit != 0); | ||
572 | bit += 23; | ||
573 | if (fcr31 & (1 << bit)) | ||
574 | *contpc = regs->cp0_epc + | ||
575 | dec_insn.pc_inc + | ||
576 | (insn.mm_i_format.simmediate << 1); | ||
577 | else | ||
578 | *contpc = regs->cp0_epc + | ||
579 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
580 | return 1; | ||
581 | } | ||
582 | break; | ||
583 | case mm_pool16c_op: | ||
584 | switch (insn.mm_i_format.rt) { | ||
585 | case mm_jalr16_op: | ||
586 | case mm_jalrs16_op: | ||
587 | regs->regs[31] = regs->cp0_epc + | ||
588 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
589 | /* Fall through */ | ||
590 | case mm_jr16_op: | ||
591 | *contpc = regs->regs[insn.mm_i_format.rs]; | ||
592 | return 1; | ||
593 | } | ||
594 | break; | ||
595 | case mm_beqz16_op: | ||
596 | if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] == 0) | ||
597 | *contpc = regs->cp0_epc + | ||
598 | dec_insn.pc_inc + | ||
599 | (insn.mm_b1_format.simmediate << 1); | ||
600 | else | ||
601 | *contpc = regs->cp0_epc + | ||
602 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
603 | return 1; | ||
604 | case mm_bnez16_op: | ||
605 | if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0) | ||
606 | *contpc = regs->cp0_epc + | ||
607 | dec_insn.pc_inc + | ||
608 | (insn.mm_b1_format.simmediate << 1); | ||
609 | else | ||
610 | *contpc = regs->cp0_epc + | ||
611 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
612 | return 1; | ||
613 | case mm_b16_op: | ||
614 | *contpc = regs->cp0_epc + dec_insn.pc_inc + | ||
615 | (insn.mm_b0_format.simmediate << 1); | ||
616 | return 1; | ||
617 | case mm_beq32_op: | ||
618 | if (regs->regs[insn.mm_i_format.rs] == | ||
619 | regs->regs[insn.mm_i_format.rt]) | ||
620 | *contpc = regs->cp0_epc + | ||
621 | dec_insn.pc_inc + | ||
622 | (insn.mm_i_format.simmediate << 1); | ||
623 | else | ||
624 | *contpc = regs->cp0_epc + | ||
625 | dec_insn.pc_inc + | ||
626 | dec_insn.next_pc_inc; | ||
627 | return 1; | ||
628 | case mm_bne32_op: | ||
629 | if (regs->regs[insn.mm_i_format.rs] != | ||
630 | regs->regs[insn.mm_i_format.rt]) | ||
631 | *contpc = regs->cp0_epc + | ||
632 | dec_insn.pc_inc + | ||
633 | (insn.mm_i_format.simmediate << 1); | ||
634 | else | ||
635 | *contpc = regs->cp0_epc + | ||
636 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
637 | return 1; | ||
638 | case mm_jalx32_op: | ||
639 | regs->regs[31] = regs->cp0_epc + | ||
640 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
641 | *contpc = regs->cp0_epc + dec_insn.pc_inc; | ||
642 | *contpc >>= 28; | ||
643 | *contpc <<= 28; | ||
644 | *contpc |= (insn.j_format.target << 2); | ||
645 | return 1; | ||
646 | case mm_jals32_op: | ||
647 | case mm_jal32_op: | ||
648 | regs->regs[31] = regs->cp0_epc + | ||
649 | dec_insn.pc_inc + dec_insn.next_pc_inc; | ||
650 | /* Fall through */ | ||
651 | case mm_j32_op: | ||
652 | *contpc = regs->cp0_epc + dec_insn.pc_inc; | ||
653 | *contpc >>= 27; | ||
654 | *contpc <<= 27; | ||
655 | *contpc |= (insn.j_format.target << 1); | ||
656 | set_isa16_mode(*contpc); | ||
657 | return 1; | ||
658 | } | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | /* | 429 | /* |
663 | * Redundant with logic already in kernel/branch.c, | 430 | * Redundant with logic already in kernel/branch.c, |
664 | * embedded in compute_return_epc. At some point, | 431 | * embedded in compute_return_epc. At some point, |
@@ -817,7 +584,11 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
817 | if (insn.i_format.rs == bc_op) { | 584 | if (insn.i_format.rs == bc_op) { |
818 | preempt_disable(); | 585 | preempt_disable(); |
819 | if (is_fpu_owner()) | 586 | if (is_fpu_owner()) |
820 | asm volatile("cfc1\t%0,$31" : "=r" (fcr31)); | 587 | asm volatile( |
588 | ".set push\n" | ||
589 | "\t.set mips1\n" | ||
590 | "\tcfc1\t%0,$31\n" | ||
591 | "\t.set pop" : "=r" (fcr31)); | ||
821 | else | 592 | else |
822 | fcr31 = current->thread.fpu.fcr31; | 593 | fcr31 = current->thread.fpu.fcr31; |
823 | preempt_enable(); | 594 | preempt_enable(); |
@@ -867,23 +638,25 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, | |||
867 | */ | 638 | */ |
868 | static inline int cop1_64bit(struct pt_regs *xcp) | 639 | static inline int cop1_64bit(struct pt_regs *xcp) |
869 | { | 640 | { |
870 | #if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32) | 641 | if (config_enabled(CONFIG_64BIT) && !config_enabled(CONFIG_MIPS32_O32)) |
871 | return 1; | 642 | return 1; |
872 | #elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT) | 643 | else if (config_enabled(CONFIG_32BIT) && |
873 | return 0; | 644 | !config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) |
874 | #else | 645 | return 0; |
646 | |||
875 | return !test_thread_flag(TIF_32BIT_FPREGS); | 647 | return !test_thread_flag(TIF_32BIT_FPREGS); |
876 | #endif | ||
877 | } | 648 | } |
878 | 649 | ||
879 | #define SIFROMREG(si, x) do { \ | 650 | #define SIFROMREG(si, x) \ |
651 | do { \ | ||
880 | if (cop1_64bit(xcp)) \ | 652 | if (cop1_64bit(xcp)) \ |
881 | (si) = get_fpr32(&ctx->fpr[x], 0); \ | 653 | (si) = get_fpr32(&ctx->fpr[x], 0); \ |
882 | else \ | 654 | else \ |
883 | (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ | 655 | (si) = get_fpr32(&ctx->fpr[(x) & ~1], (x) & 1); \ |
884 | } while (0) | 656 | } while (0) |
885 | 657 | ||
886 | #define SITOREG(si, x) do { \ | 658 | #define SITOREG(si, x) \ |
659 | do { \ | ||
887 | if (cop1_64bit(xcp)) { \ | 660 | if (cop1_64bit(xcp)) { \ |
888 | unsigned i; \ | 661 | unsigned i; \ |
889 | set_fpr32(&ctx->fpr[x], 0, si); \ | 662 | set_fpr32(&ctx->fpr[x], 0, si); \ |
@@ -896,17 +669,19 @@ static inline int cop1_64bit(struct pt_regs *xcp) | |||
896 | 669 | ||
897 | #define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1)) | 670 | #define SIFROMHREG(si, x) ((si) = get_fpr32(&ctx->fpr[x], 1)) |
898 | 671 | ||
899 | #define SITOHREG(si, x) do { \ | 672 | #define SITOHREG(si, x) \ |
673 | do { \ | ||
900 | unsigned i; \ | 674 | unsigned i; \ |
901 | set_fpr32(&ctx->fpr[x], 1, si); \ | 675 | set_fpr32(&ctx->fpr[x], 1, si); \ |
902 | for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ | 676 | for (i = 2; i < ARRAY_SIZE(ctx->fpr[x].val32); i++) \ |
903 | set_fpr32(&ctx->fpr[x], i, 0); \ | 677 | set_fpr32(&ctx->fpr[x], i, 0); \ |
904 | } while (0) | 678 | } while (0) |
905 | 679 | ||
906 | #define DIFROMREG(di, x) \ | 680 | #define DIFROMREG(di, x) \ |
907 | ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0)) | 681 | ((di) = get_fpr64(&ctx->fpr[(x) & ~(cop1_64bit(xcp) == 0)], 0)) |
908 | 682 | ||
909 | #define DITOREG(di, x) do { \ | 683 | #define DITOREG(di, x) \ |
684 | do { \ | ||
910 | unsigned fpr, i; \ | 685 | unsigned fpr, i; \ |
911 | fpr = (x) & ~(cop1_64bit(xcp) == 0); \ | 686 | fpr = (x) & ~(cop1_64bit(xcp) == 0); \ |
912 | set_fpr64(&ctx->fpr[fpr], 0, di); \ | 687 | set_fpr64(&ctx->fpr[fpr], 0, di); \ |
@@ -927,23 +702,36 @@ static inline int cop1_64bit(struct pt_regs *xcp) | |||
927 | static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | 702 | static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, |
928 | struct mm_decoded_insn dec_insn, void *__user *fault_addr) | 703 | struct mm_decoded_insn dec_insn, void *__user *fault_addr) |
929 | { | 704 | { |
930 | mips_instruction ir; | ||
931 | unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; | 705 | unsigned long contpc = xcp->cp0_epc + dec_insn.pc_inc; |
932 | unsigned int cond; | 706 | unsigned int cond, cbit; |
933 | int pc_inc; | 707 | mips_instruction ir; |
708 | int likely, pc_inc; | ||
709 | u32 __user *wva; | ||
710 | u64 __user *dva; | ||
711 | u32 value; | ||
712 | u32 wval; | ||
713 | u64 dval; | ||
714 | int sig; | ||
715 | |||
716 | /* | ||
717 | * These are giving gcc a gentle hint about what to expect in | ||
718 | * dec_inst in order to do better optimization. | ||
719 | */ | ||
720 | if (!cpu_has_mmips && dec_insn.micro_mips_mode) | ||
721 | unreachable(); | ||
934 | 722 | ||
935 | /* XXX NEC Vr54xx bug workaround */ | 723 | /* XXX NEC Vr54xx bug workaround */ |
936 | if (xcp->cp0_cause & CAUSEF_BD) { | 724 | if (delay_slot(xcp)) { |
937 | if (dec_insn.micro_mips_mode) { | 725 | if (dec_insn.micro_mips_mode) { |
938 | if (!mm_isBranchInstr(xcp, dec_insn, &contpc)) | 726 | if (!mm_isBranchInstr(xcp, dec_insn, &contpc)) |
939 | xcp->cp0_cause &= ~CAUSEF_BD; | 727 | clear_delay_slot(xcp); |
940 | } else { | 728 | } else { |
941 | if (!isBranchInstr(xcp, dec_insn, &contpc)) | 729 | if (!isBranchInstr(xcp, dec_insn, &contpc)) |
942 | xcp->cp0_cause &= ~CAUSEF_BD; | 730 | clear_delay_slot(xcp); |
943 | } | 731 | } |
944 | } | 732 | } |
945 | 733 | ||
946 | if (xcp->cp0_cause & CAUSEF_BD) { | 734 | if (delay_slot(xcp)) { |
947 | /* | 735 | /* |
948 | * The instruction to be emulated is in a branch delay slot | 736 | * The instruction to be emulated is in a branch delay slot |
949 | * which means that we have to emulate the branch instruction | 737 | * which means that we have to emulate the branch instruction |
@@ -985,96 +773,85 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
985 | return SIGILL; | 773 | return SIGILL; |
986 | } | 774 | } |
987 | 775 | ||
988 | emul: | 776 | emul: |
989 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0); | 777 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, xcp, 0); |
990 | MIPS_FPU_EMU_INC_STATS(emulated); | 778 | MIPS_FPU_EMU_INC_STATS(emulated); |
991 | switch (MIPSInst_OPCODE(ir)) { | 779 | switch (MIPSInst_OPCODE(ir)) { |
992 | case ldc1_op:{ | 780 | case ldc1_op: |
993 | u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + | 781 | dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + |
994 | MIPSInst_SIMM(ir)); | 782 | MIPSInst_SIMM(ir)); |
995 | u64 val; | ||
996 | |||
997 | MIPS_FPU_EMU_INC_STATS(loads); | 783 | MIPS_FPU_EMU_INC_STATS(loads); |
998 | 784 | ||
999 | if (!access_ok(VERIFY_READ, va, sizeof(u64))) { | 785 | if (!access_ok(VERIFY_READ, dva, sizeof(u64))) { |
1000 | MIPS_FPU_EMU_INC_STATS(errors); | 786 | MIPS_FPU_EMU_INC_STATS(errors); |
1001 | *fault_addr = va; | 787 | *fault_addr = dva; |
1002 | return SIGBUS; | 788 | return SIGBUS; |
1003 | } | 789 | } |
1004 | if (__get_user(val, va)) { | 790 | if (__get_user(dval, dva)) { |
1005 | MIPS_FPU_EMU_INC_STATS(errors); | 791 | MIPS_FPU_EMU_INC_STATS(errors); |
1006 | *fault_addr = va; | 792 | *fault_addr = dva; |
1007 | return SIGSEGV; | 793 | return SIGSEGV; |
1008 | } | 794 | } |
1009 | DITOREG(val, MIPSInst_RT(ir)); | 795 | DITOREG(dval, MIPSInst_RT(ir)); |
1010 | break; | 796 | break; |
1011 | } | ||
1012 | |||
1013 | case sdc1_op:{ | ||
1014 | u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
1015 | MIPSInst_SIMM(ir)); | ||
1016 | u64 val; | ||
1017 | 797 | ||
798 | case sdc1_op: | ||
799 | dva = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
800 | MIPSInst_SIMM(ir)); | ||
1018 | MIPS_FPU_EMU_INC_STATS(stores); | 801 | MIPS_FPU_EMU_INC_STATS(stores); |
1019 | DIFROMREG(val, MIPSInst_RT(ir)); | 802 | DIFROMREG(dval, MIPSInst_RT(ir)); |
1020 | if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) { | 803 | if (!access_ok(VERIFY_WRITE, dva, sizeof(u64))) { |
1021 | MIPS_FPU_EMU_INC_STATS(errors); | 804 | MIPS_FPU_EMU_INC_STATS(errors); |
1022 | *fault_addr = va; | 805 | *fault_addr = dva; |
1023 | return SIGBUS; | 806 | return SIGBUS; |
1024 | } | 807 | } |
1025 | if (__put_user(val, va)) { | 808 | if (__put_user(dval, dva)) { |
1026 | MIPS_FPU_EMU_INC_STATS(errors); | 809 | MIPS_FPU_EMU_INC_STATS(errors); |
1027 | *fault_addr = va; | 810 | *fault_addr = dva; |
1028 | return SIGSEGV; | 811 | return SIGSEGV; |
1029 | } | 812 | } |
1030 | break; | 813 | break; |
1031 | } | ||
1032 | |||
1033 | case lwc1_op:{ | ||
1034 | u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
1035 | MIPSInst_SIMM(ir)); | ||
1036 | u32 val; | ||
1037 | 814 | ||
815 | case lwc1_op: | ||
816 | wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
817 | MIPSInst_SIMM(ir)); | ||
1038 | MIPS_FPU_EMU_INC_STATS(loads); | 818 | MIPS_FPU_EMU_INC_STATS(loads); |
1039 | if (!access_ok(VERIFY_READ, va, sizeof(u32))) { | 819 | if (!access_ok(VERIFY_READ, wva, sizeof(u32))) { |
1040 | MIPS_FPU_EMU_INC_STATS(errors); | 820 | MIPS_FPU_EMU_INC_STATS(errors); |
1041 | *fault_addr = va; | 821 | *fault_addr = wva; |
1042 | return SIGBUS; | 822 | return SIGBUS; |
1043 | } | 823 | } |
1044 | if (__get_user(val, va)) { | 824 | if (__get_user(wval, wva)) { |
1045 | MIPS_FPU_EMU_INC_STATS(errors); | 825 | MIPS_FPU_EMU_INC_STATS(errors); |
1046 | *fault_addr = va; | 826 | *fault_addr = wva; |
1047 | return SIGSEGV; | 827 | return SIGSEGV; |
1048 | } | 828 | } |
1049 | SITOREG(val, MIPSInst_RT(ir)); | 829 | SITOREG(wval, MIPSInst_RT(ir)); |
1050 | break; | 830 | break; |
1051 | } | ||
1052 | |||
1053 | case swc1_op:{ | ||
1054 | u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
1055 | MIPSInst_SIMM(ir)); | ||
1056 | u32 val; | ||
1057 | 831 | ||
832 | case swc1_op: | ||
833 | wva = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] + | ||
834 | MIPSInst_SIMM(ir)); | ||
1058 | MIPS_FPU_EMU_INC_STATS(stores); | 835 | MIPS_FPU_EMU_INC_STATS(stores); |
1059 | SIFROMREG(val, MIPSInst_RT(ir)); | 836 | SIFROMREG(wval, MIPSInst_RT(ir)); |
1060 | if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) { | 837 | if (!access_ok(VERIFY_WRITE, wva, sizeof(u32))) { |
1061 | MIPS_FPU_EMU_INC_STATS(errors); | 838 | MIPS_FPU_EMU_INC_STATS(errors); |
1062 | *fault_addr = va; | 839 | *fault_addr = wva; |
1063 | return SIGBUS; | 840 | return SIGBUS; |
1064 | } | 841 | } |
1065 | if (__put_user(val, va)) { | 842 | if (__put_user(wval, wva)) { |
1066 | MIPS_FPU_EMU_INC_STATS(errors); | 843 | MIPS_FPU_EMU_INC_STATS(errors); |
1067 | *fault_addr = va; | 844 | *fault_addr = wva; |
1068 | return SIGSEGV; | 845 | return SIGSEGV; |
1069 | } | 846 | } |
1070 | break; | 847 | break; |
1071 | } | ||
1072 | 848 | ||
1073 | case cop1_op: | 849 | case cop1_op: |
1074 | switch (MIPSInst_RS(ir)) { | 850 | switch (MIPSInst_RS(ir)) { |
1075 | |||
1076 | #if defined(__mips64) | ||
1077 | case dmfc_op: | 851 | case dmfc_op: |
852 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | ||
853 | return SIGILL; | ||
854 | |||
1078 | /* copregister fs -> gpr[rt] */ | 855 | /* copregister fs -> gpr[rt] */ |
1079 | if (MIPSInst_RT(ir) != 0) { | 856 | if (MIPSInst_RT(ir) != 0) { |
1080 | DIFROMREG(xcp->regs[MIPSInst_RT(ir)], | 857 | DIFROMREG(xcp->regs[MIPSInst_RT(ir)], |
@@ -1083,10 +860,12 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1083 | break; | 860 | break; |
1084 | 861 | ||
1085 | case dmtc_op: | 862 | case dmtc_op: |
863 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | ||
864 | return SIGILL; | ||
865 | |||
1086 | /* copregister fs <- rt */ | 866 | /* copregister fs <- rt */ |
1087 | DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); | 867 | DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); |
1088 | break; | 868 | break; |
1089 | #endif | ||
1090 | 869 | ||
1091 | case mfhc_op: | 870 | case mfhc_op: |
1092 | if (!cpu_has_mips_r2) | 871 | if (!cpu_has_mips_r2) |
@@ -1120,19 +899,14 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1120 | SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); | 899 | SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); |
1121 | break; | 900 | break; |
1122 | 901 | ||
1123 | case cfc_op:{ | 902 | case cfc_op: |
1124 | /* cop control register rd -> gpr[rt] */ | 903 | /* cop control register rd -> gpr[rt] */ |
1125 | u32 value; | ||
1126 | |||
1127 | if (MIPSInst_RD(ir) == FPCREG_CSR) { | 904 | if (MIPSInst_RD(ir) == FPCREG_CSR) { |
1128 | value = ctx->fcr31; | 905 | value = ctx->fcr31; |
1129 | value = (value & ~FPU_CSR_RM) | | 906 | value = (value & ~FPU_CSR_RM) | modeindex(value); |
1130 | mips_rm[modeindex(value)]; | 907 | pr_debug("%p gpr[%d]<-csr=%08x\n", |
1131 | #ifdef CSRTRACE | 908 | (void *) (xcp->cp0_epc), |
1132 | printk("%p gpr[%d]<-csr=%08x\n", | 909 | MIPSInst_RT(ir), value); |
1133 | (void *) (xcp->cp0_epc), | ||
1134 | MIPSInst_RT(ir), value); | ||
1135 | #endif | ||
1136 | } | 910 | } |
1137 | else if (MIPSInst_RD(ir) == FPCREG_RID) | 911 | else if (MIPSInst_RD(ir) == FPCREG_RID) |
1138 | value = 0; | 912 | value = 0; |
@@ -1141,12 +915,9 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1141 | if (MIPSInst_RT(ir)) | 915 | if (MIPSInst_RT(ir)) |
1142 | xcp->regs[MIPSInst_RT(ir)] = value; | 916 | xcp->regs[MIPSInst_RT(ir)] = value; |
1143 | break; | 917 | break; |
1144 | } | ||
1145 | 918 | ||
1146 | case ctc_op:{ | 919 | case ctc_op: |
1147 | /* copregister rd <- rt */ | 920 | /* copregister rd <- rt */ |
1148 | u32 value; | ||
1149 | |||
1150 | if (MIPSInst_RT(ir) == 0) | 921 | if (MIPSInst_RT(ir) == 0) |
1151 | value = 0; | 922 | value = 0; |
1152 | else | 923 | else |
@@ -1155,37 +926,33 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1155 | /* we only have one writable control reg | 926 | /* we only have one writable control reg |
1156 | */ | 927 | */ |
1157 | if (MIPSInst_RD(ir) == FPCREG_CSR) { | 928 | if (MIPSInst_RD(ir) == FPCREG_CSR) { |
1158 | #ifdef CSRTRACE | 929 | pr_debug("%p gpr[%d]->csr=%08x\n", |
1159 | printk("%p gpr[%d]->csr=%08x\n", | 930 | (void *) (xcp->cp0_epc), |
1160 | (void *) (xcp->cp0_epc), | 931 | MIPSInst_RT(ir), value); |
1161 | MIPSInst_RT(ir), value); | ||
1162 | #endif | ||
1163 | 932 | ||
1164 | /* | 933 | /* |
1165 | * Don't write reserved bits, | 934 | * Don't write reserved bits, |
1166 | * and convert to ieee library modes | 935 | * and convert to ieee library modes |
1167 | */ | 936 | */ |
1168 | ctx->fcr31 = (value & | 937 | ctx->fcr31 = (value & ~(FPU_CSR_RSVD | FPU_CSR_RM)) | |
1169 | ~(FPU_CSR_RSVD | FPU_CSR_RM)) | | 938 | modeindex(value); |
1170 | ieee_rm[modeindex(value)]; | ||
1171 | } | 939 | } |
1172 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { | 940 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { |
1173 | return SIGFPE; | 941 | return SIGFPE; |
1174 | } | 942 | } |
1175 | break; | 943 | break; |
1176 | } | ||
1177 | 944 | ||
1178 | case bc_op:{ | 945 | case bc_op: |
1179 | int likely = 0; | 946 | if (delay_slot(xcp)) |
1180 | |||
1181 | if (xcp->cp0_cause & CAUSEF_BD) | ||
1182 | return SIGILL; | 947 | return SIGILL; |
1183 | 948 | ||
1184 | #if __mips >= 4 | 949 | if (cpu_has_mips_4_5_r) |
1185 | cond = ctx->fcr31 & fpucondbit[MIPSInst_RT(ir) >> 2]; | 950 | cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; |
1186 | #else | 951 | else |
1187 | cond = ctx->fcr31 & FPU_CSR_COND; | 952 | cbit = FPU_CSR_COND; |
1188 | #endif | 953 | cond = ctx->fcr31 & cbit; |
954 | |||
955 | likely = 0; | ||
1189 | switch (MIPSInst_RT(ir) & 3) { | 956 | switch (MIPSInst_RT(ir) & 3) { |
1190 | case bcfl_op: | 957 | case bcfl_op: |
1191 | likely = 1; | 958 | likely = 1; |
@@ -1201,10 +968,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1201 | return SIGILL; | 968 | return SIGILL; |
1202 | } | 969 | } |
1203 | 970 | ||
1204 | xcp->cp0_cause |= CAUSEF_BD; | 971 | set_delay_slot(xcp); |
1205 | if (cond) { | 972 | if (cond) { |
1206 | /* branch taken: emulate dslot | 973 | /* |
1207 | * instruction | 974 | * Branch taken: emulate dslot instruction |
1208 | */ | 975 | */ |
1209 | xcp->cp0_epc += dec_insn.pc_inc; | 976 | xcp->cp0_epc += dec_insn.pc_inc; |
1210 | 977 | ||
@@ -1238,23 +1005,37 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1238 | 1005 | ||
1239 | switch (MIPSInst_OPCODE(ir)) { | 1006 | switch (MIPSInst_OPCODE(ir)) { |
1240 | case lwc1_op: | 1007 | case lwc1_op: |
1008 | goto emul; | ||
1009 | |||
1241 | case swc1_op: | 1010 | case swc1_op: |
1242 | #if (__mips >= 2 || defined(__mips64)) | 1011 | goto emul; |
1012 | |||
1243 | case ldc1_op: | 1013 | case ldc1_op: |
1244 | case sdc1_op: | 1014 | case sdc1_op: |
1245 | #endif | 1015 | if (cpu_has_mips_2_3_4_5 || |
1016 | cpu_has_mips64) | ||
1017 | goto emul; | ||
1018 | |||
1019 | return SIGILL; | ||
1020 | goto emul; | ||
1021 | |||
1246 | case cop1_op: | 1022 | case cop1_op: |
1247 | #if __mips >= 4 && __mips != 32 | ||
1248 | case cop1x_op: | ||
1249 | #endif | ||
1250 | /* its one of ours */ | ||
1251 | goto emul; | 1023 | goto emul; |
1252 | #if __mips >= 4 | 1024 | |
1025 | case cop1x_op: | ||
1026 | if (cpu_has_mips_4_5 || cpu_has_mips64) | ||
1027 | /* its one of ours */ | ||
1028 | goto emul; | ||
1029 | |||
1030 | return SIGILL; | ||
1031 | |||
1253 | case spec_op: | 1032 | case spec_op: |
1033 | if (!cpu_has_mips_4_5_r) | ||
1034 | return SIGILL; | ||
1035 | |||
1254 | if (MIPSInst_FUNC(ir) == movc_op) | 1036 | if (MIPSInst_FUNC(ir) == movc_op) |
1255 | goto emul; | 1037 | goto emul; |
1256 | break; | 1038 | break; |
1257 | #endif | ||
1258 | } | 1039 | } |
1259 | 1040 | ||
1260 | /* | 1041 | /* |
@@ -1262,10 +1043,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1262 | * instruction in the dslot | 1043 | * instruction in the dslot |
1263 | */ | 1044 | */ |
1264 | return mips_dsemul(xcp, ir, contpc); | 1045 | return mips_dsemul(xcp, ir, contpc); |
1265 | } | 1046 | } else if (likely) { /* branch not taken */ |
1266 | else { | ||
1267 | /* branch not taken */ | ||
1268 | if (likely) { | ||
1269 | /* | 1047 | /* |
1270 | * branch likely nullifies | 1048 | * branch likely nullifies |
1271 | * dslot if not taken | 1049 | * dslot if not taken |
@@ -1277,34 +1055,31 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1277 | * dslot as normal insn | 1055 | * dslot as normal insn |
1278 | */ | 1056 | */ |
1279 | } | 1057 | } |
1280 | } | ||
1281 | break; | 1058 | break; |
1282 | } | ||
1283 | 1059 | ||
1284 | default: | 1060 | default: |
1285 | if (!(MIPSInst_RS(ir) & 0x10)) | 1061 | if (!(MIPSInst_RS(ir) & 0x10)) |
1286 | return SIGILL; | 1062 | return SIGILL; |
1287 | { | ||
1288 | int sig; | ||
1289 | 1063 | ||
1290 | /* a real fpu computation instruction */ | 1064 | /* a real fpu computation instruction */ |
1291 | if ((sig = fpu_emu(xcp, ctx, ir))) | 1065 | if ((sig = fpu_emu(xcp, ctx, ir))) |
1292 | return sig; | 1066 | return sig; |
1293 | } | ||
1294 | } | 1067 | } |
1295 | break; | 1068 | break; |
1296 | 1069 | ||
1297 | #if __mips >= 4 && __mips != 32 | 1070 | case cop1x_op: |
1298 | case cop1x_op:{ | 1071 | if (!cpu_has_mips_4_5 && !cpu_has_mips64) |
1299 | int sig = fpux_emu(xcp, ctx, ir, fault_addr); | 1072 | return SIGILL; |
1073 | |||
1074 | sig = fpux_emu(xcp, ctx, ir, fault_addr); | ||
1300 | if (sig) | 1075 | if (sig) |
1301 | return sig; | 1076 | return sig; |
1302 | break; | 1077 | break; |
1303 | } | ||
1304 | #endif | ||
1305 | 1078 | ||
1306 | #if __mips >= 4 | ||
1307 | case spec_op: | 1079 | case spec_op: |
1080 | if (!cpu_has_mips_4_5_r) | ||
1081 | return SIGILL; | ||
1082 | |||
1308 | if (MIPSInst_FUNC(ir) != movc_op) | 1083 | if (MIPSInst_FUNC(ir) != movc_op) |
1309 | return SIGILL; | 1084 | return SIGILL; |
1310 | cond = fpucondbit[MIPSInst_RT(ir) >> 2]; | 1085 | cond = fpucondbit[MIPSInst_RT(ir) >> 2]; |
@@ -1312,8 +1087,6 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1312 | xcp->regs[MIPSInst_RD(ir)] = | 1087 | xcp->regs[MIPSInst_RD(ir)] = |
1313 | xcp->regs[MIPSInst_RS(ir)]; | 1088 | xcp->regs[MIPSInst_RS(ir)]; |
1314 | break; | 1089 | break; |
1315 | #endif | ||
1316 | |||
1317 | default: | 1090 | default: |
1318 | sigill: | 1091 | sigill: |
1319 | return SIGILL; | 1092 | return SIGILL; |
@@ -1321,7 +1094,7 @@ sigill: | |||
1321 | 1094 | ||
1322 | /* we did it !! */ | 1095 | /* we did it !! */ |
1323 | xcp->cp0_epc = contpc; | 1096 | xcp->cp0_epc = contpc; |
1324 | xcp->cp0_cause &= ~CAUSEF_BD; | 1097 | clear_delay_slot(xcp); |
1325 | 1098 | ||
1326 | return 0; | 1099 | return 0; |
1327 | } | 1100 | } |
@@ -1342,44 +1115,42 @@ static const unsigned char cmptab[8] = { | |||
1342 | }; | 1115 | }; |
1343 | 1116 | ||
1344 | 1117 | ||
1345 | #if __mips >= 4 && __mips != 32 | ||
1346 | |||
1347 | /* | 1118 | /* |
1348 | * Additional MIPS4 instructions | 1119 | * Additional MIPS4 instructions |
1349 | */ | 1120 | */ |
1350 | 1121 | ||
1351 | #define DEF3OP(name, p, f1, f2, f3) \ | 1122 | #define DEF3OP(name, p, f1, f2, f3) \ |
1352 | static ieee754##p fpemu_##p##_##name(ieee754##p r, ieee754##p s, \ | 1123 | static union ieee754##p fpemu_##p##_##name(union ieee754##p r, \ |
1353 | ieee754##p t) \ | 1124 | union ieee754##p s, union ieee754##p t) \ |
1354 | { \ | 1125 | { \ |
1355 | struct _ieee754_csr ieee754_csr_save; \ | 1126 | struct _ieee754_csr ieee754_csr_save; \ |
1356 | s = f1(s, t); \ | 1127 | s = f1(s, t); \ |
1357 | ieee754_csr_save = ieee754_csr; \ | 1128 | ieee754_csr_save = ieee754_csr; \ |
1358 | s = f2(s, r); \ | 1129 | s = f2(s, r); \ |
1359 | ieee754_csr_save.cx |= ieee754_csr.cx; \ | 1130 | ieee754_csr_save.cx |= ieee754_csr.cx; \ |
1360 | ieee754_csr_save.sx |= ieee754_csr.sx; \ | 1131 | ieee754_csr_save.sx |= ieee754_csr.sx; \ |
1361 | s = f3(s); \ | 1132 | s = f3(s); \ |
1362 | ieee754_csr.cx |= ieee754_csr_save.cx; \ | 1133 | ieee754_csr.cx |= ieee754_csr_save.cx; \ |
1363 | ieee754_csr.sx |= ieee754_csr_save.sx; \ | 1134 | ieee754_csr.sx |= ieee754_csr_save.sx; \ |
1364 | return s; \ | 1135 | return s; \ |
1365 | } | 1136 | } |
1366 | 1137 | ||
1367 | static ieee754dp fpemu_dp_recip(ieee754dp d) | 1138 | static union ieee754dp fpemu_dp_recip(union ieee754dp d) |
1368 | { | 1139 | { |
1369 | return ieee754dp_div(ieee754dp_one(0), d); | 1140 | return ieee754dp_div(ieee754dp_one(0), d); |
1370 | } | 1141 | } |
1371 | 1142 | ||
1372 | static ieee754dp fpemu_dp_rsqrt(ieee754dp d) | 1143 | static union ieee754dp fpemu_dp_rsqrt(union ieee754dp d) |
1373 | { | 1144 | { |
1374 | return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); | 1145 | return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d)); |
1375 | } | 1146 | } |
1376 | 1147 | ||
1377 | static ieee754sp fpemu_sp_recip(ieee754sp s) | 1148 | static union ieee754sp fpemu_sp_recip(union ieee754sp s) |
1378 | { | 1149 | { |
1379 | return ieee754sp_div(ieee754sp_one(0), s); | 1150 | return ieee754sp_div(ieee754sp_one(0), s); |
1380 | } | 1151 | } |
1381 | 1152 | ||
1382 | static ieee754sp fpemu_sp_rsqrt(ieee754sp s) | 1153 | static union ieee754sp fpemu_sp_rsqrt(union ieee754sp s) |
1383 | { | 1154 | { |
1384 | return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); | 1155 | return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s)); |
1385 | } | 1156 | } |
@@ -1403,8 +1174,8 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1403 | switch (MIPSInst_FMA_FFMT(ir)) { | 1174 | switch (MIPSInst_FMA_FFMT(ir)) { |
1404 | case s_fmt:{ /* 0 */ | 1175 | case s_fmt:{ /* 0 */ |
1405 | 1176 | ||
1406 | ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp); | 1177 | union ieee754sp(*handler) (union ieee754sp, union ieee754sp, union ieee754sp); |
1407 | ieee754sp fd, fr, fs, ft; | 1178 | union ieee754sp fd, fr, fs, ft; |
1408 | u32 __user *va; | 1179 | u32 __user *va; |
1409 | u32 val; | 1180 | u32 val; |
1410 | 1181 | ||
@@ -1467,18 +1238,26 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1467 | SPTOREG(fd, MIPSInst_FD(ir)); | 1238 | SPTOREG(fd, MIPSInst_FD(ir)); |
1468 | 1239 | ||
1469 | copcsr: | 1240 | copcsr: |
1470 | if (ieee754_cxtest(IEEE754_INEXACT)) | 1241 | if (ieee754_cxtest(IEEE754_INEXACT)) { |
1242 | MIPS_FPU_EMU_INC_STATS(ieee754_inexact); | ||
1471 | rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; | 1243 | rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; |
1472 | if (ieee754_cxtest(IEEE754_UNDERFLOW)) | 1244 | } |
1245 | if (ieee754_cxtest(IEEE754_UNDERFLOW)) { | ||
1246 | MIPS_FPU_EMU_INC_STATS(ieee754_underflow); | ||
1473 | rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; | 1247 | rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; |
1474 | if (ieee754_cxtest(IEEE754_OVERFLOW)) | 1248 | } |
1249 | if (ieee754_cxtest(IEEE754_OVERFLOW)) { | ||
1250 | MIPS_FPU_EMU_INC_STATS(ieee754_overflow); | ||
1475 | rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; | 1251 | rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; |
1476 | if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) | 1252 | } |
1253 | if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) { | ||
1254 | MIPS_FPU_EMU_INC_STATS(ieee754_invalidop); | ||
1477 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; | 1255 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; |
1256 | } | ||
1478 | 1257 | ||
1479 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; | 1258 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; |
1480 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { | 1259 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { |
1481 | /*printk ("SIGFPE: fpu csr = %08x\n", | 1260 | /*printk ("SIGFPE: FPU csr = %08x\n", |
1482 | ctx->fcr31); */ | 1261 | ctx->fcr31); */ |
1483 | return SIGFPE; | 1262 | return SIGFPE; |
1484 | } | 1263 | } |
@@ -1492,8 +1271,8 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1492 | } | 1271 | } |
1493 | 1272 | ||
1494 | case d_fmt:{ /* 1 */ | 1273 | case d_fmt:{ /* 1 */ |
1495 | ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp); | 1274 | union ieee754dp(*handler) (union ieee754dp, union ieee754dp, union ieee754dp); |
1496 | ieee754dp fd, fr, fs, ft; | 1275 | union ieee754dp fd, fr, fs, ft; |
1497 | u64 __user *va; | 1276 | u64 __user *va; |
1498 | u64 val; | 1277 | u64 val; |
1499 | 1278 | ||
@@ -1574,7 +1353,6 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1574 | 1353 | ||
1575 | return 0; | 1354 | return 0; |
1576 | } | 1355 | } |
1577 | #endif | ||
1578 | 1356 | ||
1579 | 1357 | ||
1580 | 1358 | ||
@@ -1586,23 +1364,25 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1586 | { | 1364 | { |
1587 | int rfmt; /* resulting format */ | 1365 | int rfmt; /* resulting format */ |
1588 | unsigned rcsr = 0; /* resulting csr */ | 1366 | unsigned rcsr = 0; /* resulting csr */ |
1367 | unsigned int oldrm; | ||
1368 | unsigned int cbit; | ||
1589 | unsigned cond; | 1369 | unsigned cond; |
1590 | union { | 1370 | union { |
1591 | ieee754dp d; | 1371 | union ieee754dp d; |
1592 | ieee754sp s; | 1372 | union ieee754sp s; |
1593 | int w; | 1373 | int w; |
1594 | #ifdef __mips64 | ||
1595 | s64 l; | 1374 | s64 l; |
1596 | #endif | ||
1597 | } rv; /* resulting value */ | 1375 | } rv; /* resulting value */ |
1376 | u64 bits; | ||
1598 | 1377 | ||
1599 | MIPS_FPU_EMU_INC_STATS(cp1ops); | 1378 | MIPS_FPU_EMU_INC_STATS(cp1ops); |
1600 | switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { | 1379 | switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) { |
1601 | case s_fmt:{ /* 0 */ | 1380 | case s_fmt: { /* 0 */ |
1602 | union { | 1381 | union { |
1603 | ieee754sp(*b) (ieee754sp, ieee754sp); | 1382 | union ieee754sp(*b) (union ieee754sp, union ieee754sp); |
1604 | ieee754sp(*u) (ieee754sp); | 1383 | union ieee754sp(*u) (union ieee754sp); |
1605 | } handler; | 1384 | } handler; |
1385 | union ieee754sp fs, ft; | ||
1606 | 1386 | ||
1607 | switch (MIPSInst_FUNC(ir)) { | 1387 | switch (MIPSInst_FUNC(ir)) { |
1608 | /* binary ops */ | 1388 | /* binary ops */ |
@@ -1620,148 +1400,167 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1620 | goto scopbop; | 1400 | goto scopbop; |
1621 | 1401 | ||
1622 | /* unary ops */ | 1402 | /* unary ops */ |
1623 | #if __mips >= 2 || defined(__mips64) | ||
1624 | case fsqrt_op: | 1403 | case fsqrt_op: |
1404 | if (!cpu_has_mips_4_5_r) | ||
1405 | return SIGILL; | ||
1406 | |||
1625 | handler.u = ieee754sp_sqrt; | 1407 | handler.u = ieee754sp_sqrt; |
1626 | goto scopuop; | 1408 | goto scopuop; |
1627 | #endif | 1409 | |
1628 | #if __mips >= 4 && __mips != 32 | 1410 | /* |
1411 | * Note that on some MIPS IV implementations such as the | ||
1412 | * R5000 and R8000 the FSQRT and FRECIP instructions do not | ||
1413 | * achieve full IEEE-754 accuracy - however this emulator does. | ||
1414 | */ | ||
1629 | case frsqrt_op: | 1415 | case frsqrt_op: |
1416 | if (!cpu_has_mips_4_5_r2) | ||
1417 | return SIGILL; | ||
1418 | |||
1630 | handler.u = fpemu_sp_rsqrt; | 1419 | handler.u = fpemu_sp_rsqrt; |
1631 | goto scopuop; | 1420 | goto scopuop; |
1421 | |||
1632 | case frecip_op: | 1422 | case frecip_op: |
1423 | if (!cpu_has_mips_4_5_r2) | ||
1424 | return SIGILL; | ||
1425 | |||
1633 | handler.u = fpemu_sp_recip; | 1426 | handler.u = fpemu_sp_recip; |
1634 | goto scopuop; | 1427 | goto scopuop; |
1635 | #endif | 1428 | |
1636 | #if __mips >= 4 | ||
1637 | case fmovc_op: | 1429 | case fmovc_op: |
1430 | if (!cpu_has_mips_4_5_r) | ||
1431 | return SIGILL; | ||
1432 | |||
1638 | cond = fpucondbit[MIPSInst_FT(ir) >> 2]; | 1433 | cond = fpucondbit[MIPSInst_FT(ir) >> 2]; |
1639 | if (((ctx->fcr31 & cond) != 0) != | 1434 | if (((ctx->fcr31 & cond) != 0) != |
1640 | ((MIPSInst_FT(ir) & 1) != 0)) | 1435 | ((MIPSInst_FT(ir) & 1) != 0)) |
1641 | return 0; | 1436 | return 0; |
1642 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | 1437 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
1643 | break; | 1438 | break; |
1439 | |||
1644 | case fmovz_op: | 1440 | case fmovz_op: |
1441 | if (!cpu_has_mips_4_5_r) | ||
1442 | return SIGILL; | ||
1443 | |||
1645 | if (xcp->regs[MIPSInst_FT(ir)] != 0) | 1444 | if (xcp->regs[MIPSInst_FT(ir)] != 0) |
1646 | return 0; | 1445 | return 0; |
1647 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | 1446 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
1648 | break; | 1447 | break; |
1448 | |||
1649 | case fmovn_op: | 1449 | case fmovn_op: |
1450 | if (!cpu_has_mips_4_5_r) | ||
1451 | return SIGILL; | ||
1452 | |||
1650 | if (xcp->regs[MIPSInst_FT(ir)] == 0) | 1453 | if (xcp->regs[MIPSInst_FT(ir)] == 0) |
1651 | return 0; | 1454 | return 0; |
1652 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | 1455 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
1653 | break; | 1456 | break; |
1654 | #endif | 1457 | |
1655 | case fabs_op: | 1458 | case fabs_op: |
1656 | handler.u = ieee754sp_abs; | 1459 | handler.u = ieee754sp_abs; |
1657 | goto scopuop; | 1460 | goto scopuop; |
1461 | |||
1658 | case fneg_op: | 1462 | case fneg_op: |
1659 | handler.u = ieee754sp_neg; | 1463 | handler.u = ieee754sp_neg; |
1660 | goto scopuop; | 1464 | goto scopuop; |
1465 | |||
1661 | case fmov_op: | 1466 | case fmov_op: |
1662 | /* an easy one */ | 1467 | /* an easy one */ |
1663 | SPFROMREG(rv.s, MIPSInst_FS(ir)); | 1468 | SPFROMREG(rv.s, MIPSInst_FS(ir)); |
1664 | goto copcsr; | 1469 | goto copcsr; |
1665 | 1470 | ||
1666 | /* binary op on handler */ | 1471 | /* binary op on handler */ |
1667 | scopbop: | 1472 | scopbop: |
1668 | { | 1473 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1669 | ieee754sp fs, ft; | 1474 | SPFROMREG(ft, MIPSInst_FT(ir)); |
1670 | |||
1671 | SPFROMREG(fs, MIPSInst_FS(ir)); | ||
1672 | SPFROMREG(ft, MIPSInst_FT(ir)); | ||
1673 | |||
1674 | rv.s = (*handler.b) (fs, ft); | ||
1675 | goto copcsr; | ||
1676 | } | ||
1677 | scopuop: | ||
1678 | { | ||
1679 | ieee754sp fs; | ||
1680 | 1475 | ||
1681 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1476 | rv.s = (*handler.b) (fs, ft); |
1682 | rv.s = (*handler.u) (fs); | 1477 | goto copcsr; |
1683 | goto copcsr; | 1478 | scopuop: |
1684 | } | 1479 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1685 | copcsr: | 1480 | rv.s = (*handler.u) (fs); |
1686 | if (ieee754_cxtest(IEEE754_INEXACT)) | 1481 | goto copcsr; |
1482 | copcsr: | ||
1483 | if (ieee754_cxtest(IEEE754_INEXACT)) { | ||
1484 | MIPS_FPU_EMU_INC_STATS(ieee754_inexact); | ||
1687 | rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; | 1485 | rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S; |
1688 | if (ieee754_cxtest(IEEE754_UNDERFLOW)) | 1486 | } |
1487 | if (ieee754_cxtest(IEEE754_UNDERFLOW)) { | ||
1488 | MIPS_FPU_EMU_INC_STATS(ieee754_underflow); | ||
1689 | rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; | 1489 | rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S; |
1690 | if (ieee754_cxtest(IEEE754_OVERFLOW)) | 1490 | } |
1491 | if (ieee754_cxtest(IEEE754_OVERFLOW)) { | ||
1492 | MIPS_FPU_EMU_INC_STATS(ieee754_overflow); | ||
1691 | rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; | 1493 | rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S; |
1692 | if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) | 1494 | } |
1495 | if (ieee754_cxtest(IEEE754_ZERO_DIVIDE)) { | ||
1496 | MIPS_FPU_EMU_INC_STATS(ieee754_zerodiv); | ||
1693 | rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; | 1497 | rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S; |
1694 | if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) | 1498 | } |
1499 | if (ieee754_cxtest(IEEE754_INVALID_OPERATION)) { | ||
1500 | MIPS_FPU_EMU_INC_STATS(ieee754_invalidop); | ||
1695 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; | 1501 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; |
1502 | } | ||
1696 | break; | 1503 | break; |
1697 | 1504 | ||
1698 | /* unary conv ops */ | 1505 | /* unary conv ops */ |
1699 | case fcvts_op: | 1506 | case fcvts_op: |
1700 | return SIGILL; /* not defined */ | 1507 | return SIGILL; /* not defined */ |
1701 | case fcvtd_op:{ | ||
1702 | ieee754sp fs; | ||
1703 | 1508 | ||
1509 | case fcvtd_op: | ||
1704 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1510 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1705 | rv.d = ieee754dp_fsp(fs); | 1511 | rv.d = ieee754dp_fsp(fs); |
1706 | rfmt = d_fmt; | 1512 | rfmt = d_fmt; |
1707 | goto copcsr; | 1513 | goto copcsr; |
1708 | } | ||
1709 | case fcvtw_op:{ | ||
1710 | ieee754sp fs; | ||
1711 | 1514 | ||
1515 | case fcvtw_op: | ||
1712 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1516 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1713 | rv.w = ieee754sp_tint(fs); | 1517 | rv.w = ieee754sp_tint(fs); |
1714 | rfmt = w_fmt; | 1518 | rfmt = w_fmt; |
1715 | goto copcsr; | 1519 | goto copcsr; |
1716 | } | ||
1717 | 1520 | ||
1718 | #if __mips >= 2 || defined(__mips64) | ||
1719 | case fround_op: | 1521 | case fround_op: |
1720 | case ftrunc_op: | 1522 | case ftrunc_op: |
1721 | case fceil_op: | 1523 | case fceil_op: |
1722 | case ffloor_op:{ | 1524 | case ffloor_op: |
1723 | unsigned int oldrm = ieee754_csr.rm; | 1525 | if (!cpu_has_mips_2_3_4_5 && !cpu_has_mips64) |
1724 | ieee754sp fs; | 1526 | return SIGILL; |
1725 | 1527 | ||
1528 | oldrm = ieee754_csr.rm; | ||
1726 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1529 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1727 | ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; | 1530 | ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); |
1728 | rv.w = ieee754sp_tint(fs); | 1531 | rv.w = ieee754sp_tint(fs); |
1729 | ieee754_csr.rm = oldrm; | 1532 | ieee754_csr.rm = oldrm; |
1730 | rfmt = w_fmt; | 1533 | rfmt = w_fmt; |
1731 | goto copcsr; | 1534 | goto copcsr; |
1732 | } | ||
1733 | #endif /* __mips >= 2 */ | ||
1734 | 1535 | ||
1735 | #if defined(__mips64) | 1536 | case fcvtl_op: |
1736 | case fcvtl_op:{ | 1537 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) |
1737 | ieee754sp fs; | 1538 | return SIGILL; |
1738 | 1539 | ||
1739 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1540 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1740 | rv.l = ieee754sp_tlong(fs); | 1541 | rv.l = ieee754sp_tlong(fs); |
1741 | rfmt = l_fmt; | 1542 | rfmt = l_fmt; |
1742 | goto copcsr; | 1543 | goto copcsr; |
1743 | } | ||
1744 | 1544 | ||
1745 | case froundl_op: | 1545 | case froundl_op: |
1746 | case ftruncl_op: | 1546 | case ftruncl_op: |
1747 | case fceill_op: | 1547 | case fceill_op: |
1748 | case ffloorl_op:{ | 1548 | case ffloorl_op: |
1749 | unsigned int oldrm = ieee754_csr.rm; | 1549 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) |
1750 | ieee754sp fs; | 1550 | return SIGILL; |
1751 | 1551 | ||
1552 | oldrm = ieee754_csr.rm; | ||
1752 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1553 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1753 | ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; | 1554 | ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); |
1754 | rv.l = ieee754sp_tlong(fs); | 1555 | rv.l = ieee754sp_tlong(fs); |
1755 | ieee754_csr.rm = oldrm; | 1556 | ieee754_csr.rm = oldrm; |
1756 | rfmt = l_fmt; | 1557 | rfmt = l_fmt; |
1757 | goto copcsr; | 1558 | goto copcsr; |
1758 | } | ||
1759 | #endif /* defined(__mips64) */ | ||
1760 | 1559 | ||
1761 | default: | 1560 | default: |
1762 | if (MIPSInst_FUNC(ir) >= fcmp_op) { | 1561 | if (MIPSInst_FUNC(ir) >= fcmp_op) { |
1763 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; | 1562 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; |
1764 | ieee754sp fs, ft; | 1563 | union ieee754sp fs, ft; |
1765 | 1564 | ||
1766 | SPFROMREG(fs, MIPSInst_FS(ir)); | 1565 | SPFROMREG(fs, MIPSInst_FS(ir)); |
1767 | SPFROMREG(ft, MIPSInst_FT(ir)); | 1566 | SPFROMREG(ft, MIPSInst_FT(ir)); |
@@ -1774,19 +1573,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1774 | else | 1573 | else |
1775 | goto copcsr; | 1574 | goto copcsr; |
1776 | 1575 | ||
1777 | } | 1576 | } else |
1778 | else { | ||
1779 | return SIGILL; | 1577 | return SIGILL; |
1780 | } | ||
1781 | break; | 1578 | break; |
1782 | } | 1579 | } |
1783 | break; | 1580 | break; |
1784 | } | 1581 | } |
1785 | 1582 | ||
1786 | case d_fmt:{ | 1583 | case d_fmt: { |
1584 | union ieee754dp fs, ft; | ||
1787 | union { | 1585 | union { |
1788 | ieee754dp(*b) (ieee754dp, ieee754dp); | 1586 | union ieee754dp(*b) (union ieee754dp, union ieee754dp); |
1789 | ieee754dp(*u) (ieee754dp); | 1587 | union ieee754dp(*u) (union ieee754dp); |
1790 | } handler; | 1588 | } handler; |
1791 | 1589 | ||
1792 | switch (MIPSInst_FUNC(ir)) { | 1590 | switch (MIPSInst_FUNC(ir)) { |
@@ -1805,21 +1603,33 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1805 | goto dcopbop; | 1603 | goto dcopbop; |
1806 | 1604 | ||
1807 | /* unary ops */ | 1605 | /* unary ops */ |
1808 | #if __mips >= 2 || defined(__mips64) | ||
1809 | case fsqrt_op: | 1606 | case fsqrt_op: |
1607 | if (!cpu_has_mips_2_3_4_5_r) | ||
1608 | return SIGILL; | ||
1609 | |||
1810 | handler.u = ieee754dp_sqrt; | 1610 | handler.u = ieee754dp_sqrt; |
1811 | goto dcopuop; | 1611 | goto dcopuop; |
1812 | #endif | 1612 | /* |
1813 | #if __mips >= 4 && __mips != 32 | 1613 | * Note that on some MIPS IV implementations such as the |
1614 | * R5000 and R8000 the FSQRT and FRECIP instructions do not | ||
1615 | * achieve full IEEE-754 accuracy - however this emulator does. | ||
1616 | */ | ||
1814 | case frsqrt_op: | 1617 | case frsqrt_op: |
1618 | if (!cpu_has_mips_4_5_r2) | ||
1619 | return SIGILL; | ||
1620 | |||
1815 | handler.u = fpemu_dp_rsqrt; | 1621 | handler.u = fpemu_dp_rsqrt; |
1816 | goto dcopuop; | 1622 | goto dcopuop; |
1817 | case frecip_op: | 1623 | case frecip_op: |
1624 | if (!cpu_has_mips_4_5_r2) | ||
1625 | return SIGILL; | ||
1626 | |||
1818 | handler.u = fpemu_dp_recip; | 1627 | handler.u = fpemu_dp_recip; |
1819 | goto dcopuop; | 1628 | goto dcopuop; |
1820 | #endif | ||
1821 | #if __mips >= 4 | ||
1822 | case fmovc_op: | 1629 | case fmovc_op: |
1630 | if (!cpu_has_mips_4_5_r) | ||
1631 | return SIGILL; | ||
1632 | |||
1823 | cond = fpucondbit[MIPSInst_FT(ir) >> 2]; | 1633 | cond = fpucondbit[MIPSInst_FT(ir) >> 2]; |
1824 | if (((ctx->fcr31 & cond) != 0) != | 1634 | if (((ctx->fcr31 & cond) != 0) != |
1825 | ((MIPSInst_FT(ir) & 1) != 0)) | 1635 | ((MIPSInst_FT(ir) & 1) != 0)) |
@@ -1827,16 +1637,21 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1827 | DPFROMREG(rv.d, MIPSInst_FS(ir)); | 1637 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
1828 | break; | 1638 | break; |
1829 | case fmovz_op: | 1639 | case fmovz_op: |
1640 | if (!cpu_has_mips_4_5_r) | ||
1641 | return SIGILL; | ||
1642 | |||
1830 | if (xcp->regs[MIPSInst_FT(ir)] != 0) | 1643 | if (xcp->regs[MIPSInst_FT(ir)] != 0) |
1831 | return 0; | 1644 | return 0; |
1832 | DPFROMREG(rv.d, MIPSInst_FS(ir)); | 1645 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
1833 | break; | 1646 | break; |
1834 | case fmovn_op: | 1647 | case fmovn_op: |
1648 | if (!cpu_has_mips_4_5_r) | ||
1649 | return SIGILL; | ||
1650 | |||
1835 | if (xcp->regs[MIPSInst_FT(ir)] == 0) | 1651 | if (xcp->regs[MIPSInst_FT(ir)] == 0) |
1836 | return 0; | 1652 | return 0; |
1837 | DPFROMREG(rv.d, MIPSInst_FS(ir)); | 1653 | DPFROMREG(rv.d, MIPSInst_FS(ir)); |
1838 | break; | 1654 | break; |
1839 | #endif | ||
1840 | case fabs_op: | 1655 | case fabs_op: |
1841 | handler.u = ieee754dp_abs; | 1656 | handler.u = ieee754dp_abs; |
1842 | goto dcopuop; | 1657 | goto dcopuop; |
@@ -1851,91 +1666,78 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1851 | goto copcsr; | 1666 | goto copcsr; |
1852 | 1667 | ||
1853 | /* binary op on handler */ | 1668 | /* binary op on handler */ |
1854 | dcopbop:{ | 1669 | dcopbop: |
1855 | ieee754dp fs, ft; | 1670 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1856 | 1671 | DPFROMREG(ft, MIPSInst_FT(ir)); | |
1857 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
1858 | DPFROMREG(ft, MIPSInst_FT(ir)); | ||
1859 | |||
1860 | rv.d = (*handler.b) (fs, ft); | ||
1861 | goto copcsr; | ||
1862 | } | ||
1863 | dcopuop:{ | ||
1864 | ieee754dp fs; | ||
1865 | |||
1866 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
1867 | rv.d = (*handler.u) (fs); | ||
1868 | goto copcsr; | ||
1869 | } | ||
1870 | 1672 | ||
1871 | /* unary conv ops */ | 1673 | rv.d = (*handler.b) (fs, ft); |
1872 | case fcvts_op:{ | 1674 | goto copcsr; |
1873 | ieee754dp fs; | 1675 | dcopuop: |
1676 | DPFROMREG(fs, MIPSInst_FS(ir)); | ||
1677 | rv.d = (*handler.u) (fs); | ||
1678 | goto copcsr; | ||
1874 | 1679 | ||
1680 | /* | ||
1681 | * unary conv ops | ||
1682 | */ | ||
1683 | case fcvts_op: | ||
1875 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1684 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1876 | rv.s = ieee754sp_fdp(fs); | 1685 | rv.s = ieee754sp_fdp(fs); |
1877 | rfmt = s_fmt; | 1686 | rfmt = s_fmt; |
1878 | goto copcsr; | 1687 | goto copcsr; |
1879 | } | 1688 | |
1880 | case fcvtd_op: | 1689 | case fcvtd_op: |
1881 | return SIGILL; /* not defined */ | 1690 | return SIGILL; /* not defined */ |
1882 | 1691 | ||
1883 | case fcvtw_op:{ | 1692 | case fcvtw_op: |
1884 | ieee754dp fs; | ||
1885 | |||
1886 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1693 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1887 | rv.w = ieee754dp_tint(fs); /* wrong */ | 1694 | rv.w = ieee754dp_tint(fs); /* wrong */ |
1888 | rfmt = w_fmt; | 1695 | rfmt = w_fmt; |
1889 | goto copcsr; | 1696 | goto copcsr; |
1890 | } | ||
1891 | 1697 | ||
1892 | #if __mips >= 2 || defined(__mips64) | ||
1893 | case fround_op: | 1698 | case fround_op: |
1894 | case ftrunc_op: | 1699 | case ftrunc_op: |
1895 | case fceil_op: | 1700 | case fceil_op: |
1896 | case ffloor_op:{ | 1701 | case ffloor_op: |
1897 | unsigned int oldrm = ieee754_csr.rm; | 1702 | if (!cpu_has_mips_2_3_4_5_r) |
1898 | ieee754dp fs; | 1703 | return SIGILL; |
1899 | 1704 | ||
1705 | oldrm = ieee754_csr.rm; | ||
1900 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1706 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1901 | ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; | 1707 | ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); |
1902 | rv.w = ieee754dp_tint(fs); | 1708 | rv.w = ieee754dp_tint(fs); |
1903 | ieee754_csr.rm = oldrm; | 1709 | ieee754_csr.rm = oldrm; |
1904 | rfmt = w_fmt; | 1710 | rfmt = w_fmt; |
1905 | goto copcsr; | 1711 | goto copcsr; |
1906 | } | ||
1907 | #endif | ||
1908 | 1712 | ||
1909 | #if defined(__mips64) | 1713 | case fcvtl_op: |
1910 | case fcvtl_op:{ | 1714 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) |
1911 | ieee754dp fs; | 1715 | return SIGILL; |
1912 | 1716 | ||
1913 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1717 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1914 | rv.l = ieee754dp_tlong(fs); | 1718 | rv.l = ieee754dp_tlong(fs); |
1915 | rfmt = l_fmt; | 1719 | rfmt = l_fmt; |
1916 | goto copcsr; | 1720 | goto copcsr; |
1917 | } | ||
1918 | 1721 | ||
1919 | case froundl_op: | 1722 | case froundl_op: |
1920 | case ftruncl_op: | 1723 | case ftruncl_op: |
1921 | case fceill_op: | 1724 | case fceill_op: |
1922 | case ffloorl_op:{ | 1725 | case ffloorl_op: |
1923 | unsigned int oldrm = ieee754_csr.rm; | 1726 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) |
1924 | ieee754dp fs; | 1727 | return SIGILL; |
1925 | 1728 | ||
1729 | oldrm = ieee754_csr.rm; | ||
1926 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1730 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1927 | ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; | 1731 | ieee754_csr.rm = modeindex(MIPSInst_FUNC(ir)); |
1928 | rv.l = ieee754dp_tlong(fs); | 1732 | rv.l = ieee754dp_tlong(fs); |
1929 | ieee754_csr.rm = oldrm; | 1733 | ieee754_csr.rm = oldrm; |
1930 | rfmt = l_fmt; | 1734 | rfmt = l_fmt; |
1931 | goto copcsr; | 1735 | goto copcsr; |
1932 | } | ||
1933 | #endif /* __mips >= 3 */ | ||
1934 | 1736 | ||
1935 | default: | 1737 | default: |
1936 | if (MIPSInst_FUNC(ir) >= fcmp_op) { | 1738 | if (MIPSInst_FUNC(ir) >= fcmp_op) { |
1937 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; | 1739 | unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; |
1938 | ieee754dp fs, ft; | 1740 | union ieee754dp fs, ft; |
1939 | 1741 | ||
1940 | DPFROMREG(fs, MIPSInst_FS(ir)); | 1742 | DPFROMREG(fs, MIPSInst_FS(ir)); |
1941 | DPFROMREG(ft, MIPSInst_FT(ir)); | 1743 | DPFROMREG(ft, MIPSInst_FT(ir)); |
@@ -1957,11 +1759,8 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1957 | break; | 1759 | break; |
1958 | } | 1760 | } |
1959 | break; | 1761 | break; |
1960 | } | ||
1961 | |||
1962 | case w_fmt:{ | ||
1963 | ieee754sp fs; | ||
1964 | 1762 | ||
1763 | case w_fmt: | ||
1965 | switch (MIPSInst_FUNC(ir)) { | 1764 | switch (MIPSInst_FUNC(ir)) { |
1966 | case fcvts_op: | 1765 | case fcvts_op: |
1967 | /* convert word to single precision real */ | 1766 | /* convert word to single precision real */ |
@@ -1981,9 +1780,11 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
1981 | break; | 1780 | break; |
1982 | } | 1781 | } |
1983 | 1782 | ||
1984 | #if defined(__mips64) | 1783 | case l_fmt: |
1985 | case l_fmt:{ | 1784 | |
1986 | u64 bits; | 1785 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) |
1786 | return SIGILL; | ||
1787 | |||
1987 | DIFROMREG(bits, MIPSInst_FS(ir)); | 1788 | DIFROMREG(bits, MIPSInst_FS(ir)); |
1988 | 1789 | ||
1989 | switch (MIPSInst_FUNC(ir)) { | 1790 | switch (MIPSInst_FUNC(ir)) { |
@@ -2001,8 +1802,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2001 | return SIGILL; | 1802 | return SIGILL; |
2002 | } | 1803 | } |
2003 | break; | 1804 | break; |
2004 | } | ||
2005 | #endif | ||
2006 | 1805 | ||
2007 | default: | 1806 | default: |
2008 | return SIGILL; | 1807 | return SIGILL; |
@@ -2017,7 +1816,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2017 | */ | 1816 | */ |
2018 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; | 1817 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; |
2019 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { | 1818 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { |
2020 | /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */ | 1819 | /*printk ("SIGFPE: FPU csr = %08x\n",ctx->fcr31); */ |
2021 | return SIGFPE; | 1820 | return SIGFPE; |
2022 | } | 1821 | } |
2023 | 1822 | ||
@@ -2025,18 +1824,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2025 | * Now we can safely write the result back to the register file. | 1824 | * Now we can safely write the result back to the register file. |
2026 | */ | 1825 | */ |
2027 | switch (rfmt) { | 1826 | switch (rfmt) { |
2028 | case -1:{ | 1827 | case -1: |
2029 | #if __mips >= 4 | 1828 | |
2030 | cond = fpucondbit[MIPSInst_FD(ir) >> 2]; | 1829 | if (cpu_has_mips_4_5_r) |
2031 | #else | 1830 | cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; |
2032 | cond = FPU_CSR_COND; | 1831 | else |
2033 | #endif | 1832 | cbit = FPU_CSR_COND; |
2034 | if (rv.w) | 1833 | if (rv.w) |
2035 | ctx->fcr31 |= cond; | 1834 | ctx->fcr31 |= cbit; |
2036 | else | 1835 | else |
2037 | ctx->fcr31 &= ~cond; | 1836 | ctx->fcr31 &= ~cbit; |
2038 | break; | 1837 | break; |
2039 | } | 1838 | |
2040 | case d_fmt: | 1839 | case d_fmt: |
2041 | DPTOREG(rv.d, MIPSInst_FD(ir)); | 1840 | DPTOREG(rv.d, MIPSInst_FD(ir)); |
2042 | break; | 1841 | break; |
@@ -2046,11 +1845,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2046 | case w_fmt: | 1845 | case w_fmt: |
2047 | SITOREG(rv.w, MIPSInst_FD(ir)); | 1846 | SITOREG(rv.w, MIPSInst_FD(ir)); |
2048 | break; | 1847 | break; |
2049 | #if defined(__mips64) | ||
2050 | case l_fmt: | 1848 | case l_fmt: |
1849 | if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) | ||
1850 | return SIGILL; | ||
1851 | |||
2051 | DITOREG(rv.l, MIPSInst_FD(ir)); | 1852 | DITOREG(rv.l, MIPSInst_FD(ir)); |
2052 | break; | 1853 | break; |
2053 | #endif | ||
2054 | default: | 1854 | default: |
2055 | return SIGILL; | 1855 | return SIGILL; |
2056 | } | 1856 | } |
@@ -2138,11 +1938,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2138 | * ieee754_csr. But ieee754_csr.rm is ieee | 1938 | * ieee754_csr. But ieee754_csr.rm is ieee |
2139 | * library modes. (not mips rounding mode) | 1939 | * library modes. (not mips rounding mode) |
2140 | */ | 1940 | */ |
2141 | /* convert to ieee library modes */ | ||
2142 | ieee754_csr.rm = ieee_rm[ieee754_csr.rm]; | ||
2143 | sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr); | 1941 | sig = cop1Emulate(xcp, ctx, dec_insn, fault_addr); |
2144 | /* revert to mips rounding mode */ | ||
2145 | ieee754_csr.rm = mips_rm[ieee754_csr.rm]; | ||
2146 | } | 1942 | } |
2147 | 1943 | ||
2148 | if (has_fpu) | 1944 | if (has_fpu) |
@@ -2155,58 +1951,8 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx, | |||
2155 | 1951 | ||
2156 | /* SIGILL indicates a non-fpu instruction */ | 1952 | /* SIGILL indicates a non-fpu instruction */ |
2157 | if (sig == SIGILL && xcp->cp0_epc != oldepc) | 1953 | if (sig == SIGILL && xcp->cp0_epc != oldepc) |
2158 | /* but if epc has advanced, then ignore it */ | 1954 | /* but if EPC has advanced, then ignore it */ |
2159 | sig = 0; | 1955 | sig = 0; |
2160 | 1956 | ||
2161 | return sig; | 1957 | return sig; |
2162 | } | 1958 | } |
2163 | |||
2164 | #ifdef CONFIG_DEBUG_FS | ||
2165 | |||
2166 | static int fpuemu_stat_get(void *data, u64 *val) | ||
2167 | { | ||
2168 | int cpu; | ||
2169 | unsigned long sum = 0; | ||
2170 | for_each_online_cpu(cpu) { | ||
2171 | struct mips_fpu_emulator_stats *ps; | ||
2172 | local_t *pv; | ||
2173 | ps = &per_cpu(fpuemustats, cpu); | ||
2174 | pv = (void *)ps + (unsigned long)data; | ||
2175 | sum += local_read(pv); | ||
2176 | } | ||
2177 | *val = sum; | ||
2178 | return 0; | ||
2179 | } | ||
2180 | DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n"); | ||
2181 | |||
2182 | extern struct dentry *mips_debugfs_dir; | ||
2183 | static int __init debugfs_fpuemu(void) | ||
2184 | { | ||
2185 | struct dentry *d, *dir; | ||
2186 | |||
2187 | if (!mips_debugfs_dir) | ||
2188 | return -ENODEV; | ||
2189 | dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir); | ||
2190 | if (!dir) | ||
2191 | return -ENOMEM; | ||
2192 | |||
2193 | #define FPU_STAT_CREATE(M) \ | ||
2194 | do { \ | ||
2195 | d = debugfs_create_file(#M , S_IRUGO, dir, \ | ||
2196 | (void *)offsetof(struct mips_fpu_emulator_stats, M), \ | ||
2197 | &fops_fpuemu_stat); \ | ||
2198 | if (!d) \ | ||
2199 | return -ENOMEM; \ | ||
2200 | } while (0) | ||
2201 | |||
2202 | FPU_STAT_CREATE(emulated); | ||
2203 | FPU_STAT_CREATE(loads); | ||
2204 | FPU_STAT_CREATE(stores); | ||
2205 | FPU_STAT_CREATE(cp1ops); | ||
2206 | FPU_STAT_CREATE(cp1xops); | ||
2207 | FPU_STAT_CREATE(errors); | ||
2208 | |||
2209 | return 0; | ||
2210 | } | ||
2211 | __initcall(debugfs_fpuemu); | ||
2212 | #endif | ||