2 * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator
4 * MIPS floating point support
5 * Copyright (C) 1994-2000 Algorithmics Ltd.
6 * http://www.algor.co.uk
8 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
9 * Copyright (C) 2000 MIPS Technologies, Inc.
11 * This program is free software; you can distribute it and/or modify it
12 * under the terms of the GNU General Public License (Version 2) as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
24 * A complete emulator for MIPS coprocessor 1 instructions. This is
25 * required for #float(switch) or #float(trap), where it catches all
26 * COP1 instructions via the "CoProcessor Unusable" exception.
28 * More surprisingly it is also required for #float(ieee), to help out
29 * the hardware fpu at the boundaries of the IEEE-754 representation
30 * (denormalised values, infinities, underflow, etc). It is made
31 * quite nasty because emulation of some non-COP1 instructions is
32 * required, e.g. in branch delay slots.
34 * Note if you know that you won't have an fpu, then you'll get much
35 * better performance by compiling with -msoft-float!
37 #include <linux/sched.h>
40 #include <asm/bootinfo.h>
42 #include <asm/cpu-features.h>
43 #include <asm/processor.h>
44 #include <asm/ptrace.h>
45 #include <asm/signal.h>
46 #include <asm/mipsregs.h>
47 #include <asm/fpu_emulator.h>
48 #include <asm/uaccess.h>
49 #include <asm/branch.h>
54 /* Strap kernel emulator for full MIPS IV emulation */
61 /* Function which emulates a floating point instruction. */
63 static int fpu_emu(struct pt_regs
*, struct mips_fpu_soft_struct
*,
66 #if __mips >= 4 && __mips != 32
67 static int fpux_emu(struct pt_regs
*,
68 struct mips_fpu_soft_struct
*, mips_instruction
);
71 /* Further private data for which no space exists in mips_fpu_soft_struct */
73 struct mips_fpu_emulator_private fpuemuprivate
;
75 /* Control registers */
77 #define FPCREG_RID 0 /* $0 = revision id */
78 #define FPCREG_CSR 31 /* $31 = csr */
80 /* Convert Mips rounding mode (0..3) to IEEE library modes. */
81 static const unsigned char ieee_rm
[4] = {
82 IEEE754_RN
, IEEE754_RZ
, IEEE754_RU
, IEEE754_RD
86 /* convert condition code register number to csr bit */
87 static const unsigned int fpucondbit
[8] = {
101 * Redundant with logic already in kernel/branch.c,
102 * embedded in compute_return_epc. At some point,
103 * a single subroutine should be used across both
106 static int isBranchInstr(mips_instruction
* i
)
108 switch (MIPSInst_OPCODE(*i
)) {
110 switch (MIPSInst_FUNC(*i
)) {
118 switch (MIPSInst_RT(*i
)) {
148 if (MIPSInst_RS(*i
) == bc_op
)
157 * In the Linux kernel, we support selection of FPR format on the
158 * basis of the Status.FR bit. This does imply that, if a full 32
159 * FPRs are desired, there needs to be a flip-flop that can be written
160 * to one at that bit position. In any case, O32 MIPS ABI uses
161 * only the even FPRs (Status.FR = 0).
164 #define CP0_STATUS_FR_SUPPORT
166 #ifdef CP0_STATUS_FR_SUPPORT
167 #define FR_BIT ST0_FR
172 #define SIFROMREG(si,x) ((si) = \
173 (xcp->cp0_status & FR_BIT) || !(x & 1) ? \
175 (int)(ctx->fpr[x & ~1] >> 32 ))
176 #define SITOREG(si,x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] = \
177 (xcp->cp0_status & FR_BIT) || !(x & 1) ? \
178 ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \
179 ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32)
181 #define DIFROMREG(di,x) ((di) = \
182 ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)])
183 #define DITOREG(di,x) (ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] \
186 #define SPFROMREG(sp,x) SIFROMREG((sp).bits,x)
187 #define SPTOREG(sp,x) SITOREG((sp).bits,x)
188 #define DPFROMREG(dp,x) DIFROMREG((dp).bits,x)
189 #define DPTOREG(dp,x) DITOREG((dp).bits,x)
192 * Emulate the single floating point instruction pointed at by EPC.
193 * Two instructions if the instruction is in a branch delay slot.
196 static int cop1Emulate(struct pt_regs
*xcp
, struct mips_fpu_soft_struct
*ctx
)
199 vaddr_t emulpc
, contpc
;
202 if (get_user(ir
, (mips_instruction
*) xcp
->cp0_epc
)) {
203 fpuemuprivate
.stats
.errors
++;
207 /* XXX NEC Vr54xx bug workaround */
208 if ((xcp
->cp0_cause
& CAUSEF_BD
) && !isBranchInstr(&ir
))
209 xcp
->cp0_cause
&= ~CAUSEF_BD
;
211 if (xcp
->cp0_cause
& CAUSEF_BD
) {
213 * The instruction to be emulated is in a branch delay slot
214 * which means that we have to emulate the branch instruction
215 * BEFORE we do the cop1 instruction.
217 * This branch could be a COP1 branch, but in that case we
218 * would have had a trap for that instruction, and would not
219 * come through this route.
221 * Linux MIPS branch emulator operates on context, updating the
224 emulpc
= REG_TO_VA(xcp
->cp0_epc
+ 4); /* Snapshot emulation target */
226 if (__compute_return_epc(xcp
)) {
228 printk("failed to emulate branch at %p\n",
229 REG_TO_VA(xcp
->cp0_epc
));
233 if (get_user(ir
, (mips_instruction
*) emulpc
)) {
234 fpuemuprivate
.stats
.errors
++;
237 /* __compute_return_epc() will have updated cp0_epc */
238 contpc
= REG_TO_VA xcp
->cp0_epc
;
239 /* In order not to confuse ptrace() et al, tweak context */
240 xcp
->cp0_epc
= VA_TO_REG emulpc
- 4;
243 emulpc
= REG_TO_VA xcp
->cp0_epc
;
244 contpc
= REG_TO_VA(xcp
->cp0_epc
+ 4);
248 fpuemuprivate
.stats
.emulated
++;
249 switch (MIPSInst_OPCODE(ir
)) {
250 #ifndef SINGLE_ONLY_FPU
252 u64
*va
= REG_TO_VA(xcp
->regs
[MIPSInst_RS(ir
)] +
256 fpuemuprivate
.stats
.loads
++;
257 if (get_user(val
, va
)) {
258 fpuemuprivate
.stats
.errors
++;
261 DITOREG(val
, MIPSInst_RT(ir
));
266 u64
*va
= REG_TO_VA(xcp
->regs
[MIPSInst_RS(ir
)] +
270 fpuemuprivate
.stats
.stores
++;
271 DIFROMREG(val
, MIPSInst_RT(ir
));
272 if (put_user(val
, va
)) {
273 fpuemuprivate
.stats
.errors
++;
281 u32
*va
= REG_TO_VA(xcp
->regs
[MIPSInst_RS(ir
)] +
285 fpuemuprivate
.stats
.loads
++;
286 if (get_user(val
, va
)) {
287 fpuemuprivate
.stats
.errors
++;
290 #ifdef SINGLE_ONLY_FPU
291 if (MIPSInst_RT(ir
) & 1) {
292 /* illegal register in single-float mode */
296 SITOREG(val
, MIPSInst_RT(ir
));
301 u32
*va
= REG_TO_VA(xcp
->regs
[MIPSInst_RS(ir
)] +
305 fpuemuprivate
.stats
.stores
++;
306 #ifdef SINGLE_ONLY_FPU
307 if (MIPSInst_RT(ir
) & 1) {
308 /* illegal register in single-float mode */
312 SIFROMREG(val
, MIPSInst_RT(ir
));
313 if (put_user(val
, va
)) {
314 fpuemuprivate
.stats
.errors
++;
321 switch (MIPSInst_RS(ir
)) {
323 #if __mips64 && !defined(SINGLE_ONLY_FPU)
325 /* copregister fs -> gpr[rt] */
326 if (MIPSInst_RT(ir
) != 0) {
327 DIFROMREG(xcp
->regs
[MIPSInst_RT(ir
)],
333 /* copregister fs <- rt */
334 DITOREG(xcp
->regs
[MIPSInst_RT(ir
)], MIPSInst_RD(ir
));
339 /* copregister rd -> gpr[rt] */
340 #ifdef SINGLE_ONLY_FPU
341 if (MIPSInst_RD(ir
) & 1) {
342 /* illegal register in single-float mode */
346 if (MIPSInst_RT(ir
) != 0) {
347 SIFROMREG(xcp
->regs
[MIPSInst_RT(ir
)],
353 /* copregister rd <- rt */
354 #ifdef SINGLE_ONLY_FPU
355 if (MIPSInst_RD(ir
) & 1) {
356 /* illegal register in single-float mode */
360 SITOREG(xcp
->regs
[MIPSInst_RT(ir
)], MIPSInst_RD(ir
));
364 /* cop control register rd -> gpr[rt] */
367 if (ir
== CP1UNDEF
) {
368 return do_dsemulret(xcp
);
370 if (MIPSInst_RD(ir
) == FPCREG_CSR
) {
373 printk("%p gpr[%d]<-csr=%08x\n",
374 REG_TO_VA(xcp
->cp0_epc
),
375 MIPSInst_RT(ir
), value
);
378 else if (MIPSInst_RD(ir
) == FPCREG_RID
)
383 xcp
->regs
[MIPSInst_RT(ir
)] = value
;
388 /* copregister rd <- rt */
391 if (MIPSInst_RT(ir
) == 0)
394 value
= xcp
->regs
[MIPSInst_RT(ir
)];
396 /* we only have one writable control reg
398 if (MIPSInst_RD(ir
) == FPCREG_CSR
) {
400 printk("%p gpr[%d]->csr=%08x\n",
401 REG_TO_VA(xcp
->cp0_epc
),
402 MIPSInst_RT(ir
), value
);
405 /* copy new rounding mode and
406 flush bit to ieee library state! */
407 ieee754_csr
.nod
= (ctx
->fcr31
& 0x1000000) != 0;
408 ieee754_csr
.rm
= ieee_rm
[value
& 0x3];
410 if ((ctx
->fcr31
>> 5) & ctx
->fcr31
& FPU_CSR_ALL_E
) {
419 if (xcp
->cp0_cause
& CAUSEF_BD
)
423 cond
= ctx
->fcr31
& fpucondbit
[MIPSInst_RT(ir
) >> 2];
425 cond
= ctx
->fcr31
& FPU_CSR_COND
;
427 switch (MIPSInst_RT(ir
) & 3) {
438 /* thats an illegal instruction */
442 xcp
->cp0_cause
|= CAUSEF_BD
;
444 /* branch taken: emulate dslot
450 (MIPSInst_SIMM(ir
) << 2));
452 if (get_user(ir
, (mips_instruction
*)
453 REG_TO_VA xcp
->cp0_epc
)) {
454 fpuemuprivate
.stats
.errors
++;
458 switch (MIPSInst_OPCODE(ir
)) {
461 #if (__mips >= 2 || __mips64) && !defined(SINGLE_ONLY_FPU)
466 #if __mips >= 4 && __mips != 32
469 /* its one of ours */
473 if (MIPSInst_FUNC(ir
) == movc_op
)
480 * Single step the non-cp1
481 * instruction in the dslot
483 return mips_dsemul(xcp
, ir
, VA_TO_REG contpc
);
486 /* branch not taken */
489 * branch likely nullifies
495 * else continue & execute
496 * dslot as normal insn
504 if (!(MIPSInst_RS(ir
) & 0x10))
509 /* a real fpu computation instruction */
510 if ((sig
= fpu_emu(xcp
, ctx
, ir
)))
516 #if __mips >= 4 && __mips != 32
520 if ((sig
= fpux_emu(xcp
, ctx
, ir
)))
528 if (MIPSInst_FUNC(ir
) != movc_op
)
530 cond
= fpucondbit
[MIPSInst_RT(ir
) >> 2];
531 if (((ctx
->fcr31
& cond
) != 0) == ((MIPSInst_RT(ir
) & 1) != 0))
532 xcp
->regs
[MIPSInst_RD(ir
)] =
533 xcp
->regs
[MIPSInst_RS(ir
)];
542 xcp
->cp0_epc
= VA_TO_REG(contpc
);
543 xcp
->cp0_cause
&= ~CAUSEF_BD
;
548 * Conversion table from MIPS compare ops 48-63
549 * cond = ieee754dp_cmp(x,y,IEEE754_UN,sig);
551 static const unsigned char cmptab
[8] = {
552 0, /* cmp_0 (sig) cmp_sf */
553 IEEE754_CUN
, /* cmp_un (sig) cmp_ngle */
554 IEEE754_CEQ
, /* cmp_eq (sig) cmp_seq */
555 IEEE754_CEQ
| IEEE754_CUN
, /* cmp_ueq (sig) cmp_ngl */
556 IEEE754_CLT
, /* cmp_olt (sig) cmp_lt */
557 IEEE754_CLT
| IEEE754_CUN
, /* cmp_ult (sig) cmp_nge */
558 IEEE754_CLT
| IEEE754_CEQ
, /* cmp_ole (sig) cmp_le */
559 IEEE754_CLT
| IEEE754_CEQ
| IEEE754_CUN
, /* cmp_ule (sig) cmp_ngt */
563 #if __mips >= 4 && __mips != 32
566 * Additional MIPS4 instructions
569 #define DEF3OP(name, p, f1, f2, f3) \
570 static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \
573 struct ieee754_csr ieee754_csr_save; \
575 ieee754_csr_save = ieee754_csr; \
577 ieee754_csr_save.cx |= ieee754_csr.cx; \
578 ieee754_csr_save.sx |= ieee754_csr.sx; \
580 ieee754_csr.cx |= ieee754_csr_save.cx; \
581 ieee754_csr.sx |= ieee754_csr_save.sx; \
585 static ieee754dp
fpemu_dp_recip(ieee754dp d
)
587 return ieee754dp_div(ieee754dp_one(0), d
);
590 static ieee754dp
fpemu_dp_rsqrt(ieee754dp d
)
592 return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d
));
595 static ieee754sp
fpemu_sp_recip(ieee754sp s
)
597 return ieee754sp_div(ieee754sp_one(0), s
);
600 static ieee754sp
fpemu_sp_rsqrt(ieee754sp s
)
602 return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s
));
605 DEF3OP(madd
, sp
, ieee754sp_mul
, ieee754sp_add
,);
606 DEF3OP(msub
, sp
, ieee754sp_mul
, ieee754sp_sub
,);
607 DEF3OP(nmadd
, sp
, ieee754sp_mul
, ieee754sp_add
, ieee754sp_neg
);
608 DEF3OP(nmsub
, sp
, ieee754sp_mul
, ieee754sp_sub
, ieee754sp_neg
);
609 DEF3OP(madd
, dp
, ieee754dp_mul
, ieee754dp_add
,);
610 DEF3OP(msub
, dp
, ieee754dp_mul
, ieee754dp_sub
,);
611 DEF3OP(nmadd
, dp
, ieee754dp_mul
, ieee754dp_add
, ieee754dp_neg
);
612 DEF3OP(nmsub
, dp
, ieee754dp_mul
, ieee754dp_sub
, ieee754dp_neg
);
614 static int fpux_emu(struct pt_regs
*xcp
, struct mips_fpu_soft_struct
*ctx
,
617 unsigned rcsr
= 0; /* resulting csr */
619 fpuemuprivate
.stats
.cp1xops
++;
621 switch (MIPSInst_FMA_FFMT(ir
)) {
624 ieee754sp(*handler
) (ieee754sp
, ieee754sp
, ieee754sp
);
625 ieee754sp fd
, fr
, fs
, ft
;
629 switch (MIPSInst_FUNC(ir
)) {
631 va
= REG_TO_VA(xcp
->regs
[MIPSInst_FR(ir
)] +
632 xcp
->regs
[MIPSInst_FT(ir
)]);
634 fpuemuprivate
.stats
.loads
++;
635 if (get_user(val
, va
)) {
636 fpuemuprivate
.stats
.errors
++;
639 #ifdef SINGLE_ONLY_FPU
640 if (MIPSInst_FD(ir
) & 1) {
641 /* illegal register in single-float
647 SITOREG(val
, MIPSInst_FD(ir
));
651 va
= REG_TO_VA(xcp
->regs
[MIPSInst_FR(ir
)] +
652 xcp
->regs
[MIPSInst_FT(ir
)]);
654 fpuemuprivate
.stats
.stores
++;
655 #ifdef SINGLE_ONLY_FPU
656 if (MIPSInst_FS(ir
) & 1) {
657 /* illegal register in single-float
664 SIFROMREG(val
, MIPSInst_FS(ir
));
665 if (put_user(val
, va
)) {
666 fpuemuprivate
.stats
.errors
++;
672 handler
= fpemu_sp_madd
;
675 handler
= fpemu_sp_msub
;
678 handler
= fpemu_sp_nmadd
;
681 handler
= fpemu_sp_nmsub
;
685 SPFROMREG(fr
, MIPSInst_FR(ir
));
686 SPFROMREG(fs
, MIPSInst_FS(ir
));
687 SPFROMREG(ft
, MIPSInst_FT(ir
));
688 fd
= (*handler
) (fr
, fs
, ft
);
689 SPTOREG(fd
, MIPSInst_FD(ir
));
692 if (ieee754_cxtest(IEEE754_INEXACT
))
693 rcsr
|= FPU_CSR_INE_X
| FPU_CSR_INE_S
;
694 if (ieee754_cxtest(IEEE754_UNDERFLOW
))
695 rcsr
|= FPU_CSR_UDF_X
| FPU_CSR_UDF_S
;
696 if (ieee754_cxtest(IEEE754_OVERFLOW
))
697 rcsr
|= FPU_CSR_OVF_X
| FPU_CSR_OVF_S
;
698 if (ieee754_cxtest(IEEE754_INVALID_OPERATION
))
699 rcsr
|= FPU_CSR_INV_X
| FPU_CSR_INV_S
;
701 ctx
->fcr31
= (ctx
->fcr31
& ~FPU_CSR_ALL_X
) | rcsr
;
703 ctx
->fcr31
|= 0x1000000;
704 if ((ctx
->fcr31
>> 5) & ctx
->fcr31
& FPU_CSR_ALL_E
) {
705 /*printk ("SIGFPE: fpu csr = %08x\n",
718 #ifndef SINGLE_ONLY_FPU
720 ieee754dp(*handler
) (ieee754dp
, ieee754dp
, ieee754dp
);
721 ieee754dp fd
, fr
, fs
, ft
;
725 switch (MIPSInst_FUNC(ir
)) {
727 va
= REG_TO_VA(xcp
->regs
[MIPSInst_FR(ir
)] +
728 xcp
->regs
[MIPSInst_FT(ir
)]);
730 fpuemuprivate
.stats
.loads
++;
731 if (get_user(val
, va
)) {
732 fpuemuprivate
.stats
.errors
++;
735 DITOREG(val
, MIPSInst_FD(ir
));
739 va
= REG_TO_VA(xcp
->regs
[MIPSInst_FR(ir
)] +
740 xcp
->regs
[MIPSInst_FT(ir
)]);
742 fpuemuprivate
.stats
.stores
++;
743 DIFROMREG(val
, MIPSInst_FS(ir
));
744 if (put_user(val
, va
)) {
745 fpuemuprivate
.stats
.errors
++;
751 handler
= fpemu_dp_madd
;
754 handler
= fpemu_dp_msub
;
757 handler
= fpemu_dp_nmadd
;
760 handler
= fpemu_dp_nmsub
;
764 DPFROMREG(fr
, MIPSInst_FR(ir
));
765 DPFROMREG(fs
, MIPSInst_FS(ir
));
766 DPFROMREG(ft
, MIPSInst_FT(ir
));
767 fd
= (*handler
) (fr
, fs
, ft
);
768 DPTOREG(fd
, MIPSInst_FD(ir
));
779 if (MIPSInst_FUNC(ir
) != pfetch_op
) {
782 /* ignore prefx operation */
796 * Emulate a single COP1 arithmetic instruction.
798 static int fpu_emu(struct pt_regs
*xcp
, struct mips_fpu_soft_struct
*ctx
,
801 int rfmt
; /* resulting format */
802 unsigned rcsr
= 0; /* resulting csr */
811 } rv
; /* resulting value */
813 fpuemuprivate
.stats
.cp1ops
++;
814 switch (rfmt
= (MIPSInst_FFMT(ir
) & 0xf)) {
817 ieee754sp(*b
) (ieee754sp
, ieee754sp
);
818 ieee754sp(*u
) (ieee754sp
);
821 switch (MIPSInst_FUNC(ir
)) {
824 handler
.b
= ieee754sp_add
;
827 handler
.b
= ieee754sp_sub
;
830 handler
.b
= ieee754sp_mul
;
833 handler
.b
= ieee754sp_div
;
837 #if __mips >= 2 || __mips64
839 handler
.u
= ieee754sp_sqrt
;
842 #if __mips >= 4 && __mips != 32
844 handler
.u
= fpemu_sp_rsqrt
;
847 handler
.u
= fpemu_sp_recip
;
852 cond
= fpucondbit
[MIPSInst_FT(ir
) >> 2];
853 if (((ctx
->fcr31
& cond
) != 0) !=
854 ((MIPSInst_FT(ir
) & 1) != 0))
856 SPFROMREG(rv
.s
, MIPSInst_FS(ir
));
859 if (xcp
->regs
[MIPSInst_FT(ir
)] != 0)
861 SPFROMREG(rv
.s
, MIPSInst_FS(ir
));
864 if (xcp
->regs
[MIPSInst_FT(ir
)] == 0)
866 SPFROMREG(rv
.s
, MIPSInst_FS(ir
));
870 handler
.u
= ieee754sp_abs
;
873 handler
.u
= ieee754sp_neg
;
877 SPFROMREG(rv
.s
, MIPSInst_FS(ir
));
880 /* binary op on handler */
885 SPFROMREG(fs
, MIPSInst_FS(ir
));
886 SPFROMREG(ft
, MIPSInst_FT(ir
));
888 rv
.s
= (*handler
.b
) (fs
, ft
);
895 SPFROMREG(fs
, MIPSInst_FS(ir
));
896 rv
.s
= (*handler
.u
) (fs
);
900 if (ieee754_cxtest(IEEE754_INEXACT
))
901 rcsr
|= FPU_CSR_INE_X
| FPU_CSR_INE_S
;
902 if (ieee754_cxtest(IEEE754_UNDERFLOW
))
903 rcsr
|= FPU_CSR_UDF_X
| FPU_CSR_UDF_S
;
904 if (ieee754_cxtest(IEEE754_OVERFLOW
))
905 rcsr
|= FPU_CSR_OVF_X
| FPU_CSR_OVF_S
;
906 if (ieee754_cxtest(IEEE754_ZERO_DIVIDE
))
907 rcsr
|= FPU_CSR_DIV_X
| FPU_CSR_DIV_S
;
908 if (ieee754_cxtest(IEEE754_INVALID_OPERATION
))
909 rcsr
|= FPU_CSR_INV_X
| FPU_CSR_INV_S
;
914 return SIGILL
; /* not defined */
916 #ifdef SINGLE_ONLY_FPU
917 return SIGILL
; /* not defined */
921 SPFROMREG(fs
, MIPSInst_FS(ir
));
922 rv
.d
= ieee754dp_fsp(fs
);
930 SPFROMREG(fs
, MIPSInst_FS(ir
));
931 rv
.w
= ieee754sp_tint(fs
);
936 #if __mips >= 2 || __mips64
941 unsigned int oldrm
= ieee754_csr
.rm
;
944 SPFROMREG(fs
, MIPSInst_FS(ir
));
945 ieee754_csr
.rm
= ieee_rm
[MIPSInst_FUNC(ir
) & 0x3];
946 rv
.w
= ieee754sp_tint(fs
);
947 ieee754_csr
.rm
= oldrm
;
951 #endif /* __mips >= 2 */
953 #if __mips64 && !defined(SINGLE_ONLY_FPU)
957 SPFROMREG(fs
, MIPSInst_FS(ir
));
958 rv
.l
= ieee754sp_tlong(fs
);
967 unsigned int oldrm
= ieee754_csr
.rm
;
970 SPFROMREG(fs
, MIPSInst_FS(ir
));
971 ieee754_csr
.rm
= ieee_rm
[MIPSInst_FUNC(ir
) & 0x3];
972 rv
.l
= ieee754sp_tlong(fs
);
973 ieee754_csr
.rm
= oldrm
;
977 #endif /* __mips64 && !fpu(single) */
980 if (MIPSInst_FUNC(ir
) >= fcmp_op
) {
981 unsigned cmpop
= MIPSInst_FUNC(ir
) - fcmp_op
;
984 SPFROMREG(fs
, MIPSInst_FS(ir
));
985 SPFROMREG(ft
, MIPSInst_FT(ir
));
986 rv
.w
= ieee754sp_cmp(fs
, ft
,
987 cmptab
[cmpop
& 0x7], cmpop
& 0x8);
989 if ((cmpop
& 0x8) && ieee754_cxtest
990 (IEEE754_INVALID_OPERATION
))
991 rcsr
= FPU_CSR_INV_X
| FPU_CSR_INV_S
;
1004 #ifndef SINGLE_ONLY_FPU
1007 ieee754dp(*b
) (ieee754dp
, ieee754dp
);
1008 ieee754dp(*u
) (ieee754dp
);
1011 switch (MIPSInst_FUNC(ir
)) {
1014 handler
.b
= ieee754dp_add
;
1017 handler
.b
= ieee754dp_sub
;
1020 handler
.b
= ieee754dp_mul
;
1023 handler
.b
= ieee754dp_div
;
1027 #if __mips >= 2 || __mips64
1029 handler
.u
= ieee754dp_sqrt
;
1032 #if __mips >= 4 && __mips != 32
1034 handler
.u
= fpemu_dp_rsqrt
;
1037 handler
.u
= fpemu_dp_recip
;
1042 cond
= fpucondbit
[MIPSInst_FT(ir
) >> 2];
1043 if (((ctx
->fcr31
& cond
) != 0) !=
1044 ((MIPSInst_FT(ir
) & 1) != 0))
1046 DPFROMREG(rv
.d
, MIPSInst_FS(ir
));
1049 if (xcp
->regs
[MIPSInst_FT(ir
)] != 0)
1051 DPFROMREG(rv
.d
, MIPSInst_FS(ir
));
1054 if (xcp
->regs
[MIPSInst_FT(ir
)] == 0)
1056 DPFROMREG(rv
.d
, MIPSInst_FS(ir
));
1060 handler
.u
= ieee754dp_abs
;
1064 handler
.u
= ieee754dp_neg
;
1069 DPFROMREG(rv
.d
, MIPSInst_FS(ir
));
1072 /* binary op on handler */
1076 DPFROMREG(fs
, MIPSInst_FS(ir
));
1077 DPFROMREG(ft
, MIPSInst_FT(ir
));
1079 rv
.d
= (*handler
.b
) (fs
, ft
);
1085 DPFROMREG(fs
, MIPSInst_FS(ir
));
1086 rv
.d
= (*handler
.u
) (fs
);
1090 /* unary conv ops */
1094 DPFROMREG(fs
, MIPSInst_FS(ir
));
1095 rv
.s
= ieee754sp_fdp(fs
);
1100 return SIGILL
; /* not defined */
1105 DPFROMREG(fs
, MIPSInst_FS(ir
));
1106 rv
.w
= ieee754dp_tint(fs
); /* wrong */
1111 #if __mips >= 2 || __mips64
1116 unsigned int oldrm
= ieee754_csr
.rm
;
1119 DPFROMREG(fs
, MIPSInst_FS(ir
));
1120 ieee754_csr
.rm
= ieee_rm
[MIPSInst_FUNC(ir
) & 0x3];
1121 rv
.w
= ieee754dp_tint(fs
);
1122 ieee754_csr
.rm
= oldrm
;
1128 #if __mips64 && !defined(SINGLE_ONLY_FPU)
1132 DPFROMREG(fs
, MIPSInst_FS(ir
));
1133 rv
.l
= ieee754dp_tlong(fs
);
1142 unsigned int oldrm
= ieee754_csr
.rm
;
1145 DPFROMREG(fs
, MIPSInst_FS(ir
));
1146 ieee754_csr
.rm
= ieee_rm
[MIPSInst_FUNC(ir
) & 0x3];
1147 rv
.l
= ieee754dp_tlong(fs
);
1148 ieee754_csr
.rm
= oldrm
;
1152 #endif /* __mips >= 3 && !fpu(single) */
1155 if (MIPSInst_FUNC(ir
) >= fcmp_op
) {
1156 unsigned cmpop
= MIPSInst_FUNC(ir
) - fcmp_op
;
1159 DPFROMREG(fs
, MIPSInst_FS(ir
));
1160 DPFROMREG(ft
, MIPSInst_FT(ir
));
1161 rv
.w
= ieee754dp_cmp(fs
, ft
,
1162 cmptab
[cmpop
& 0x7], cmpop
& 0x8);
1167 (IEEE754_INVALID_OPERATION
))
1168 rcsr
= FPU_CSR_INV_X
| FPU_CSR_INV_S
;
1180 #endif /* ifndef SINGLE_ONLY_FPU */
1185 switch (MIPSInst_FUNC(ir
)) {
1187 /* convert word to single precision real */
1188 SPFROMREG(fs
, MIPSInst_FS(ir
));
1189 rv
.s
= ieee754sp_fint(fs
.bits
);
1192 #ifndef SINGLE_ONLY_FPU
1194 /* convert word to double precision real */
1195 SPFROMREG(fs
, MIPSInst_FS(ir
));
1196 rv
.d
= ieee754dp_fint(fs
.bits
);
1206 #if __mips64 && !defined(SINGLE_ONLY_FPU)
1208 switch (MIPSInst_FUNC(ir
)) {
1210 /* convert long to single precision real */
1211 rv
.s
= ieee754sp_flong(ctx
->fpr
[MIPSInst_FS(ir
)]);
1215 /* convert long to double precision real */
1216 rv
.d
= ieee754dp_flong(ctx
->fpr
[MIPSInst_FS(ir
)]);
1231 * Update the fpu CSR register for this operation.
1232 * If an exception is required, generate a tidy SIGFPE exception,
1233 * without updating the result register.
1234 * Note: cause exception bits do not accumulate, they are rewritten
1235 * for each op; only the flag/sticky bits accumulate.
1237 ctx
->fcr31
= (ctx
->fcr31
& ~FPU_CSR_ALL_X
) | rcsr
;
1238 if ((ctx
->fcr31
>> 5) & ctx
->fcr31
& FPU_CSR_ALL_E
) {
1239 /*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */
1244 * Now we can safely write the result back to the register file.
1249 cond
= fpucondbit
[MIPSInst_FD(ir
) >> 2];
1251 cond
= FPU_CSR_COND
;
1256 ctx
->fcr31
&= ~cond
;
1259 #ifndef SINGLE_ONLY_FPU
1261 DPTOREG(rv
.d
, MIPSInst_FD(ir
));
1265 SPTOREG(rv
.s
, MIPSInst_FD(ir
));
1268 SITOREG(rv
.w
, MIPSInst_FD(ir
));
1270 #if __mips64 && !defined(SINGLE_ONLY_FPU)
1272 DITOREG(rv
.l
, MIPSInst_FD(ir
));
1282 int fpu_emulator_cop1Handler(int xcptno
, struct pt_regs
*xcp
,
1283 struct mips_fpu_soft_struct
*ctx
)
1285 gpreg_t oldepc
, prevepc
;
1286 mips_instruction insn
;
1289 oldepc
= xcp
->cp0_epc
;
1291 prevepc
= xcp
->cp0_epc
;
1293 if (get_user(insn
, (mips_instruction
*) xcp
->cp0_epc
)) {
1294 fpuemuprivate
.stats
.errors
++;
1298 xcp
->cp0_epc
+= 4; /* skip nops */
1300 /* Update ieee754_csr. Only relevant if we have a
1302 ieee754_csr
.nod
= (ctx
->fcr31
& 0x1000000) != 0;
1303 ieee754_csr
.rm
= ieee_rm
[ctx
->fcr31
& 0x3];
1304 ieee754_csr
.cx
= (ctx
->fcr31
>> 12) & 0x1f;
1305 sig
= cop1Emulate(xcp
, ctx
);
1314 } while (xcp
->cp0_epc
> prevepc
);
1316 /* SIGILL indicates a non-fpu instruction */
1317 if (sig
== SIGILL
&& xcp
->cp0_epc
!= oldepc
)
1318 /* but if epc has advanced, then ignore it */