cp1emu.c revision 4a99d1e25b98c239d6e746af6f79679c413fb712
1/*
2 * cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator
3 *
4 * MIPS floating point support
5 * Copyright (C) 1994-2000 Algorithmics Ltd.
6 * http://www.algor.co.uk
7 *
8 * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
9 * Copyright (C) 2000  MIPS Technologies, Inc.
10 *
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.
14 *
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
18 *  for more details.
19 *
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.
23 *
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.
27 *
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.
33 *
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!
36 */
37#include <linux/sched.h>
38
39#include <asm/inst.h>
40#include <asm/bootinfo.h>
41#include <asm/cpu.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>
50
51#include "ieee754.h"
52#include "dsemul.h"
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. */
62
63static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *,
64	mips_instruction);
65
66#if __mips >= 4 && __mips != 32
67static int fpux_emu(struct pt_regs *,
68	struct mips_fpu_soft_struct *, mips_instruction);
69#endif
70
71/* Further private data for which no space exists in mips_fpu_soft_struct */
72
73struct mips_fpu_emulator_stats fpuemustats;
74
75/* Control registers */
76
77#define FPCREG_RID	0	/* $0  = revision id */
78#define FPCREG_CSR	31	/* $31 = csr */
79
80/* Convert Mips rounding mode (0..3) to IEEE library modes. */
81static const unsigned char ieee_rm[4] = {
82	[FPU_CSR_RN] = IEEE754_RN,
83	[FPU_CSR_RZ] = IEEE754_RZ,
84	[FPU_CSR_RU] = IEEE754_RU,
85	[FPU_CSR_RD] = IEEE754_RD,
86};
87/* Convert IEEE library modes to Mips rounding mode (0..3). */
88static const unsigned char mips_rm[4] = {
89	[IEEE754_RN] = FPU_CSR_RN,
90	[IEEE754_RZ] = FPU_CSR_RZ,
91	[IEEE754_RD] = FPU_CSR_RD,
92	[IEEE754_RU] = FPU_CSR_RU,
93};
94
95#if __mips >= 4
96/* convert condition code register number to csr bit */
97static const unsigned int fpucondbit[8] = {
98	FPU_CSR_COND0,
99	FPU_CSR_COND1,
100	FPU_CSR_COND2,
101	FPU_CSR_COND3,
102	FPU_CSR_COND4,
103	FPU_CSR_COND5,
104	FPU_CSR_COND6,
105	FPU_CSR_COND7
106};
107#endif
108
109
110/*
111 * Redundant with logic already in kernel/branch.c,
112 * embedded in compute_return_epc.  At some point,
113 * a single subroutine should be used across both
114 * modules.
115 */
116static int isBranchInstr(mips_instruction * i)
117{
118	switch (MIPSInst_OPCODE(*i)) {
119	case spec_op:
120		switch (MIPSInst_FUNC(*i)) {
121		case jalr_op:
122		case jr_op:
123			return 1;
124		}
125		break;
126
127	case bcond_op:
128		switch (MIPSInst_RT(*i)) {
129		case bltz_op:
130		case bgez_op:
131		case bltzl_op:
132		case bgezl_op:
133		case bltzal_op:
134		case bgezal_op:
135		case bltzall_op:
136		case bgezall_op:
137			return 1;
138		}
139		break;
140
141	case j_op:
142	case jal_op:
143	case jalx_op:
144	case beq_op:
145	case bne_op:
146	case blez_op:
147	case bgtz_op:
148	case beql_op:
149	case bnel_op:
150	case blezl_op:
151	case bgtzl_op:
152		return 1;
153
154	case cop0_op:
155	case cop1_op:
156	case cop2_op:
157	case cop1x_op:
158		if (MIPSInst_RS(*i) == bc_op)
159			return 1;
160		break;
161	}
162
163	return 0;
164}
165
166/*
167 * In the Linux kernel, we support selection of FPR format on the
168 * basis of the Status.FR bit.  This does imply that, if a full 32
169 * FPRs are desired, there needs to be a flip-flop that can be written
170 * to one at that bit position.  In any case, O32 MIPS ABI uses
171 * only the even FPRs (Status.FR = 0).
172 */
173
174#define CP0_STATUS_FR_SUPPORT
175
176#ifdef CP0_STATUS_FR_SUPPORT
177#define FR_BIT ST0_FR
178#else
179#define FR_BIT 0
180#endif
181
182#define SIFROMREG(si,x)	((si) = \
183			(xcp->cp0_status & FR_BIT) || !(x & 1) ? \
184			(int)ctx->fpr[x] : \
185			(int)(ctx->fpr[x & ~1] >> 32 ))
186#define SITOREG(si,x)	(ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] = \
187			(xcp->cp0_status & FR_BIT) || !(x & 1) ? \
188			ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \
189			ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32)
190
191#define DIFROMREG(di,x)	((di) = \
192			ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)])
193#define DITOREG(di,x)	(ctx->fpr[x & ~((xcp->cp0_status & FR_BIT) == 0)] \
194			= (di))
195
196#define SPFROMREG(sp,x)	SIFROMREG((sp).bits,x)
197#define SPTOREG(sp,x)	SITOREG((sp).bits,x)
198#define DPFROMREG(dp,x)	DIFROMREG((dp).bits,x)
199#define DPTOREG(dp,x)	DITOREG((dp).bits,x)
200
201/*
202 * Emulate the single floating point instruction pointed at by EPC.
203 * Two instructions if the instruction is in a branch delay slot.
204 */
205
206static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx)
207{
208	mips_instruction ir;
209	void * emulpc, *contpc;
210	unsigned int cond;
211
212	if (get_user(ir, (mips_instruction *) xcp->cp0_epc)) {
213		fpuemustats.errors++;
214		return SIGBUS;
215	}
216
217	/* XXX NEC Vr54xx bug workaround */
218	if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
219		xcp->cp0_cause &= ~CAUSEF_BD;
220
221	if (xcp->cp0_cause & CAUSEF_BD) {
222		/*
223		 * The instruction to be emulated is in a branch delay slot
224		 * which means that we have to  emulate the branch instruction
225		 * BEFORE we do the cop1 instruction.
226		 *
227		 * This branch could be a COP1 branch, but in that case we
228		 * would have had a trap for that instruction, and would not
229		 * come through this route.
230		 *
231		 * Linux MIPS branch emulator operates on context, updating the
232		 * cp0_epc.
233		 */
234		emulpc = (void *) (xcp->cp0_epc + 4);	/* Snapshot emulation target */
235
236		if (__compute_return_epc(xcp)) {
237#ifdef CP1DBG
238			printk("failed to emulate branch at %p\n",
239				(void *) (xcp->cp0_epc));
240#endif
241			return SIGILL;
242		}
243		if (get_user(ir, (mips_instruction *) emulpc)) {
244			fpuemustats.errors++;
245			return SIGBUS;
246		}
247		/* __compute_return_epc() will have updated cp0_epc */
248		contpc = (void *)  xcp->cp0_epc;
249		/* In order not to confuse ptrace() et al, tweak context */
250		xcp->cp0_epc = (unsigned long) emulpc - 4;
251	} else {
252		emulpc = (void *)  xcp->cp0_epc;
253		contpc = (void *) (xcp->cp0_epc + 4);
254	}
255
256      emul:
257	fpuemustats.emulated++;
258	switch (MIPSInst_OPCODE(ir)) {
259#ifndef SINGLE_ONLY_FPU
260	case ldc1_op:{
261		u64 *va = (void *) (xcp->regs[MIPSInst_RS(ir)] +
262			MIPSInst_SIMM(ir));
263		u64 val;
264
265		fpuemustats.loads++;
266		if (get_user(val, va)) {
267			fpuemustats.errors++;
268			return SIGBUS;
269		}
270		DITOREG(val, MIPSInst_RT(ir));
271		break;
272	}
273
274	case sdc1_op:{
275		u64 *va = (void *) (xcp->regs[MIPSInst_RS(ir)] +
276			MIPSInst_SIMM(ir));
277		u64 val;
278
279		fpuemustats.stores++;
280		DIFROMREG(val, MIPSInst_RT(ir));
281		if (put_user(val, va)) {
282			fpuemustats.errors++;
283			return SIGBUS;
284		}
285		break;
286	}
287#endif
288
289	case lwc1_op:{
290		u32 *va = (void *) (xcp->regs[MIPSInst_RS(ir)] +
291			MIPSInst_SIMM(ir));
292		u32 val;
293
294		fpuemustats.loads++;
295		if (get_user(val, va)) {
296			fpuemustats.errors++;
297			return SIGBUS;
298		}
299#ifdef SINGLE_ONLY_FPU
300		if (MIPSInst_RT(ir) & 1) {
301			/* illegal register in single-float mode */
302			return SIGILL;
303		}
304#endif
305		SITOREG(val, MIPSInst_RT(ir));
306		break;
307	}
308
309	case swc1_op:{
310		u32 *va = (void *) (xcp->regs[MIPSInst_RS(ir)] +
311			MIPSInst_SIMM(ir));
312		u32 val;
313
314		fpuemustats.stores++;
315#ifdef SINGLE_ONLY_FPU
316		if (MIPSInst_RT(ir) & 1) {
317			/* illegal register in single-float mode */
318			return SIGILL;
319		}
320#endif
321		SIFROMREG(val, MIPSInst_RT(ir));
322		if (put_user(val, va)) {
323			fpuemustats.errors++;
324			return SIGBUS;
325		}
326		break;
327	}
328
329	case cop1_op:
330		switch (MIPSInst_RS(ir)) {
331
332#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
333		case dmfc_op:
334			/* copregister fs -> gpr[rt] */
335			if (MIPSInst_RT(ir) != 0) {
336				DIFROMREG(xcp->regs[MIPSInst_RT(ir)],
337					MIPSInst_RD(ir));
338			}
339			break;
340
341		case dmtc_op:
342			/* copregister fs <- rt */
343			DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
344			break;
345#endif
346
347		case mfc_op:
348			/* copregister rd -> gpr[rt] */
349#ifdef SINGLE_ONLY_FPU
350			if (MIPSInst_RD(ir) & 1) {
351				/* illegal register in single-float mode */
352				return SIGILL;
353			}
354#endif
355			if (MIPSInst_RT(ir) != 0) {
356				SIFROMREG(xcp->regs[MIPSInst_RT(ir)],
357					MIPSInst_RD(ir));
358			}
359			break;
360
361		case mtc_op:
362			/* copregister rd <- rt */
363#ifdef SINGLE_ONLY_FPU
364			if (MIPSInst_RD(ir) & 1) {
365				/* illegal register in single-float mode */
366				return SIGILL;
367			}
368#endif
369			SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
370			break;
371
372		case cfc_op:{
373			/* cop control register rd -> gpr[rt] */
374			u32 value;
375
376			if (ir == CP1UNDEF) {
377				return do_dsemulret(xcp);
378			}
379			if (MIPSInst_RD(ir) == FPCREG_CSR) {
380				value = ctx->fcr31;
381				value = (value & ~0x3) | mips_rm[value & 0x3];
382#ifdef CSRTRACE
383				printk("%p gpr[%d]<-csr=%08x\n",
384					(void *) (xcp->cp0_epc),
385					MIPSInst_RT(ir), value);
386#endif
387			}
388			else if (MIPSInst_RD(ir) == FPCREG_RID)
389				value = 0;
390			else
391				value = 0;
392			if (MIPSInst_RT(ir))
393				xcp->regs[MIPSInst_RT(ir)] = value;
394			break;
395		}
396
397		case ctc_op:{
398			/* copregister rd <- rt */
399			u32 value;
400
401			if (MIPSInst_RT(ir) == 0)
402				value = 0;
403			else
404				value = xcp->regs[MIPSInst_RT(ir)];
405
406			/* we only have one writable control reg
407			 */
408			if (MIPSInst_RD(ir) == FPCREG_CSR) {
409#ifdef CSRTRACE
410				printk("%p gpr[%d]->csr=%08x\n",
411					(void *) (xcp->cp0_epc),
412					MIPSInst_RT(ir), value);
413#endif
414				value &= (FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03);
415				ctx->fcr31 &= ~(FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03);
416				/* convert to ieee library modes */
417				ctx->fcr31 |= (value & ~0x3) | ieee_rm[value & 0x3];
418			}
419			if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
420				return SIGFPE;
421			}
422			break;
423		}
424
425		case bc_op:{
426			int likely = 0;
427
428			if (xcp->cp0_cause & CAUSEF_BD)
429				return SIGILL;
430
431#if __mips >= 4
432			cond = ctx->fcr31 & fpucondbit[MIPSInst_RT(ir) >> 2];
433#else
434			cond = ctx->fcr31 & FPU_CSR_COND;
435#endif
436			switch (MIPSInst_RT(ir) & 3) {
437			case bcfl_op:
438				likely = 1;
439			case bcf_op:
440				cond = !cond;
441				break;
442			case bctl_op:
443				likely = 1;
444			case bct_op:
445				break;
446			default:
447				/* thats an illegal instruction */
448				return SIGILL;
449			}
450
451			xcp->cp0_cause |= CAUSEF_BD;
452			if (cond) {
453				/* branch taken: emulate dslot
454				 * instruction
455				 */
456				xcp->cp0_epc += 4;
457				contpc = (void *)
458					(xcp->cp0_epc +
459					(MIPSInst_SIMM(ir) << 2));
460
461				if (get_user(ir, (mips_instruction *)
462						(void *)  xcp->cp0_epc)) {
463					fpuemustats.errors++;
464					return SIGBUS;
465				}
466
467				switch (MIPSInst_OPCODE(ir)) {
468				case lwc1_op:
469				case swc1_op:
470#if (__mips >= 2 || __mips64) && !defined(SINGLE_ONLY_FPU)
471				case ldc1_op:
472				case sdc1_op:
473#endif
474				case cop1_op:
475#if __mips >= 4 && __mips != 32
476				case cop1x_op:
477#endif
478					/* its one of ours */
479					goto emul;
480#if __mips >= 4
481				case spec_op:
482					if (MIPSInst_FUNC(ir) == movc_op)
483						goto emul;
484					break;
485#endif
486				}
487
488				/*
489				 * Single step the non-cp1
490				 * instruction in the dslot
491				 */
492				return mips_dsemul(xcp, ir, (unsigned long) contpc);
493			}
494			else {
495				/* branch not taken */
496				if (likely) {
497					/*
498					 * branch likely nullifies
499					 * dslot if not taken
500					 */
501					xcp->cp0_epc += 4;
502					contpc += 4;
503					/*
504					 * else continue & execute
505					 * dslot as normal insn
506					 */
507				}
508			}
509			break;
510		}
511
512		default:
513			if (!(MIPSInst_RS(ir) & 0x10))
514				return SIGILL;
515			{
516				int sig;
517
518				/* a real fpu computation instruction */
519				if ((sig = fpu_emu(xcp, ctx, ir)))
520					return sig;
521			}
522		}
523		break;
524
525#if __mips >= 4 && __mips != 32
526	case cop1x_op:{
527		int sig;
528
529		if ((sig = fpux_emu(xcp, ctx, ir)))
530			return sig;
531		break;
532	}
533#endif
534
535#if __mips >= 4
536	case spec_op:
537		if (MIPSInst_FUNC(ir) != movc_op)
538			return SIGILL;
539		cond = fpucondbit[MIPSInst_RT(ir) >> 2];
540		if (((ctx->fcr31 & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0))
541			xcp->regs[MIPSInst_RD(ir)] =
542				xcp->regs[MIPSInst_RS(ir)];
543		break;
544#endif
545
546	default:
547		return SIGILL;
548	}
549
550	/* we did it !! */
551	xcp->cp0_epc = (unsigned long) contpc;
552	xcp->cp0_cause &= ~CAUSEF_BD;
553
554	return 0;
555}
556
557/*
558 * Conversion table from MIPS compare ops 48-63
559 * cond = ieee754dp_cmp(x,y,IEEE754_UN,sig);
560 */
561static const unsigned char cmptab[8] = {
562	0,			/* cmp_0 (sig) cmp_sf */
563	IEEE754_CUN,		/* cmp_un (sig) cmp_ngle */
564	IEEE754_CEQ,		/* cmp_eq (sig) cmp_seq */
565	IEEE754_CEQ | IEEE754_CUN,	/* cmp_ueq (sig) cmp_ngl  */
566	IEEE754_CLT,		/* cmp_olt (sig) cmp_lt */
567	IEEE754_CLT | IEEE754_CUN,	/* cmp_ult (sig) cmp_nge */
568	IEEE754_CLT | IEEE754_CEQ,	/* cmp_ole (sig) cmp_le */
569	IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN,	/* cmp_ule (sig) cmp_ngt */
570};
571
572
573#if __mips >= 4 && __mips != 32
574
575/*
576 * Additional MIPS4 instructions
577 */
578
579#define DEF3OP(name, p, f1, f2, f3) \
580static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \
581    ieee754##p t) \
582{ \
583	struct _ieee754_csr ieee754_csr_save; \
584	s = f1 (s, t); \
585	ieee754_csr_save = ieee754_csr; \
586	s = f2 (s, r); \
587	ieee754_csr_save.cx |= ieee754_csr.cx; \
588	ieee754_csr_save.sx |= ieee754_csr.sx; \
589	s = f3 (s); \
590	ieee754_csr.cx |= ieee754_csr_save.cx; \
591	ieee754_csr.sx |= ieee754_csr_save.sx; \
592	return s; \
593}
594
595static ieee754dp fpemu_dp_recip(ieee754dp d)
596{
597	return ieee754dp_div(ieee754dp_one(0), d);
598}
599
600static ieee754dp fpemu_dp_rsqrt(ieee754dp d)
601{
602	return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d));
603}
604
605static ieee754sp fpemu_sp_recip(ieee754sp s)
606{
607	return ieee754sp_div(ieee754sp_one(0), s);
608}
609
610static ieee754sp fpemu_sp_rsqrt(ieee754sp s)
611{
612	return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s));
613}
614
615DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add,);
616DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub,);
617DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg);
618DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg);
619DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add,);
620DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub,);
621DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
622DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
623
624static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
625	mips_instruction ir)
626{
627	unsigned rcsr = 0;	/* resulting csr */
628
629	fpuemustats.cp1xops++;
630
631	switch (MIPSInst_FMA_FFMT(ir)) {
632	case s_fmt:{		/* 0 */
633
634		ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
635		ieee754sp fd, fr, fs, ft;
636		u32 *va;
637		u32 val;
638
639		switch (MIPSInst_FUNC(ir)) {
640		case lwxc1_op:
641			va = (void *) (xcp->regs[MIPSInst_FR(ir)] +
642				xcp->regs[MIPSInst_FT(ir)]);
643
644			fpuemustats.loads++;
645			if (get_user(val, va)) {
646				fpuemustats.errors++;
647				return SIGBUS;
648			}
649#ifdef SINGLE_ONLY_FPU
650			if (MIPSInst_FD(ir) & 1) {
651				/* illegal register in single-float
652				 * mode
653				 */
654				return SIGILL;
655			}
656#endif
657			SITOREG(val, MIPSInst_FD(ir));
658			break;
659
660		case swxc1_op:
661			va = (void *) (xcp->regs[MIPSInst_FR(ir)] +
662				xcp->regs[MIPSInst_FT(ir)]);
663
664			fpuemustats.stores++;
665#ifdef SINGLE_ONLY_FPU
666			if (MIPSInst_FS(ir) & 1) {
667				/* illegal register in single-float
668				 * mode
669				 */
670				return SIGILL;
671			}
672#endif
673
674			SIFROMREG(val, MIPSInst_FS(ir));
675			if (put_user(val, va)) {
676				fpuemustats.errors++;
677				return SIGBUS;
678			}
679			break;
680
681		case madd_s_op:
682			handler = fpemu_sp_madd;
683			goto scoptop;
684		case msub_s_op:
685			handler = fpemu_sp_msub;
686			goto scoptop;
687		case nmadd_s_op:
688			handler = fpemu_sp_nmadd;
689			goto scoptop;
690		case nmsub_s_op:
691			handler = fpemu_sp_nmsub;
692			goto scoptop;
693
694		      scoptop:
695			SPFROMREG(fr, MIPSInst_FR(ir));
696			SPFROMREG(fs, MIPSInst_FS(ir));
697			SPFROMREG(ft, MIPSInst_FT(ir));
698			fd = (*handler) (fr, fs, ft);
699			SPTOREG(fd, MIPSInst_FD(ir));
700
701		      copcsr:
702			if (ieee754_cxtest(IEEE754_INEXACT))
703				rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
704			if (ieee754_cxtest(IEEE754_UNDERFLOW))
705				rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
706			if (ieee754_cxtest(IEEE754_OVERFLOW))
707				rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
708			if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
709				rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
710
711			ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
712			if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
713				/*printk ("SIGFPE: fpu csr = %08x\n",
714				   ctx->fcr31); */
715				return SIGFPE;
716			}
717
718			break;
719
720		default:
721			return SIGILL;
722		}
723		break;
724	}
725
726#ifndef SINGLE_ONLY_FPU
727	case d_fmt:{		/* 1 */
728		ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);
729		ieee754dp fd, fr, fs, ft;
730		u64 *va;
731		u64 val;
732
733		switch (MIPSInst_FUNC(ir)) {
734		case ldxc1_op:
735			va = (void *) (xcp->regs[MIPSInst_FR(ir)] +
736				xcp->regs[MIPSInst_FT(ir)]);
737
738			fpuemustats.loads++;
739			if (get_user(val, va)) {
740				fpuemustats.errors++;
741				return SIGBUS;
742			}
743			DITOREG(val, MIPSInst_FD(ir));
744			break;
745
746		case sdxc1_op:
747			va = (void *) (xcp->regs[MIPSInst_FR(ir)] +
748				xcp->regs[MIPSInst_FT(ir)]);
749
750			fpuemustats.stores++;
751			DIFROMREG(val, MIPSInst_FS(ir));
752			if (put_user(val, va)) {
753				fpuemustats.errors++;
754				return SIGBUS;
755			}
756			break;
757
758		case madd_d_op:
759			handler = fpemu_dp_madd;
760			goto dcoptop;
761		case msub_d_op:
762			handler = fpemu_dp_msub;
763			goto dcoptop;
764		case nmadd_d_op:
765			handler = fpemu_dp_nmadd;
766			goto dcoptop;
767		case nmsub_d_op:
768			handler = fpemu_dp_nmsub;
769			goto dcoptop;
770
771		      dcoptop:
772			DPFROMREG(fr, MIPSInst_FR(ir));
773			DPFROMREG(fs, MIPSInst_FS(ir));
774			DPFROMREG(ft, MIPSInst_FT(ir));
775			fd = (*handler) (fr, fs, ft);
776			DPTOREG(fd, MIPSInst_FD(ir));
777			goto copcsr;
778
779		default:
780			return SIGILL;
781		}
782		break;
783	}
784#endif
785
786	case 0x7:		/* 7 */
787		if (MIPSInst_FUNC(ir) != pfetch_op) {
788			return SIGILL;
789		}
790		/* ignore prefx operation */
791		break;
792
793	default:
794		return SIGILL;
795	}
796
797	return 0;
798}
799#endif
800
801
802
803/*
804 * Emulate a single COP1 arithmetic instruction.
805 */
806static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,
807	mips_instruction ir)
808{
809	int rfmt;		/* resulting format */
810	unsigned rcsr = 0;	/* resulting csr */
811	unsigned cond;
812	union {
813		ieee754dp d;
814		ieee754sp s;
815		int w;
816#ifdef __mips64
817		s64 l;
818#endif
819	} rv;			/* resulting value */
820
821	fpuemustats.cp1ops++;
822	switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
823	case s_fmt:{		/* 0 */
824		union {
825			ieee754sp(*b) (ieee754sp, ieee754sp);
826			ieee754sp(*u) (ieee754sp);
827		} handler;
828
829		switch (MIPSInst_FUNC(ir)) {
830			/* binary ops */
831		case fadd_op:
832			handler.b = ieee754sp_add;
833			goto scopbop;
834		case fsub_op:
835			handler.b = ieee754sp_sub;
836			goto scopbop;
837		case fmul_op:
838			handler.b = ieee754sp_mul;
839			goto scopbop;
840		case fdiv_op:
841			handler.b = ieee754sp_div;
842			goto scopbop;
843
844			/* unary  ops */
845#if __mips >= 2 || __mips64
846		case fsqrt_op:
847			handler.u = ieee754sp_sqrt;
848			goto scopuop;
849#endif
850#if __mips >= 4 && __mips != 32
851		case frsqrt_op:
852			handler.u = fpemu_sp_rsqrt;
853			goto scopuop;
854		case frecip_op:
855			handler.u = fpemu_sp_recip;
856			goto scopuop;
857#endif
858#if __mips >= 4
859		case fmovc_op:
860			cond = fpucondbit[MIPSInst_FT(ir) >> 2];
861			if (((ctx->fcr31 & cond) != 0) !=
862				((MIPSInst_FT(ir) & 1) != 0))
863				return 0;
864			SPFROMREG(rv.s, MIPSInst_FS(ir));
865			break;
866		case fmovz_op:
867			if (xcp->regs[MIPSInst_FT(ir)] != 0)
868				return 0;
869			SPFROMREG(rv.s, MIPSInst_FS(ir));
870			break;
871		case fmovn_op:
872			if (xcp->regs[MIPSInst_FT(ir)] == 0)
873				return 0;
874			SPFROMREG(rv.s, MIPSInst_FS(ir));
875			break;
876#endif
877		case fabs_op:
878			handler.u = ieee754sp_abs;
879			goto scopuop;
880		case fneg_op:
881			handler.u = ieee754sp_neg;
882			goto scopuop;
883		case fmov_op:
884			/* an easy one */
885			SPFROMREG(rv.s, MIPSInst_FS(ir));
886			goto copcsr;
887
888			/* binary op on handler */
889		      scopbop:
890			{
891				ieee754sp fs, ft;
892
893				SPFROMREG(fs, MIPSInst_FS(ir));
894				SPFROMREG(ft, MIPSInst_FT(ir));
895
896				rv.s = (*handler.b) (fs, ft);
897				goto copcsr;
898			}
899		      scopuop:
900			{
901				ieee754sp fs;
902
903				SPFROMREG(fs, MIPSInst_FS(ir));
904				rv.s = (*handler.u) (fs);
905				goto copcsr;
906			}
907		      copcsr:
908			if (ieee754_cxtest(IEEE754_INEXACT))
909				rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
910			if (ieee754_cxtest(IEEE754_UNDERFLOW))
911				rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
912			if (ieee754_cxtest(IEEE754_OVERFLOW))
913				rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
914			if (ieee754_cxtest(IEEE754_ZERO_DIVIDE))
915				rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S;
916			if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
917				rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
918			break;
919
920			/* unary conv ops */
921		case fcvts_op:
922			return SIGILL;	/* not defined */
923		case fcvtd_op:{
924#ifdef SINGLE_ONLY_FPU
925			return SIGILL;	/* not defined */
926#else
927			ieee754sp fs;
928
929			SPFROMREG(fs, MIPSInst_FS(ir));
930			rv.d = ieee754dp_fsp(fs);
931			rfmt = d_fmt;
932			goto copcsr;
933		}
934#endif
935		case fcvtw_op:{
936			ieee754sp fs;
937
938			SPFROMREG(fs, MIPSInst_FS(ir));
939			rv.w = ieee754sp_tint(fs);
940			rfmt = w_fmt;
941			goto copcsr;
942		}
943
944#if __mips >= 2 || __mips64
945		case fround_op:
946		case ftrunc_op:
947		case fceil_op:
948		case ffloor_op:{
949			unsigned int oldrm = ieee754_csr.rm;
950			ieee754sp fs;
951
952			SPFROMREG(fs, MIPSInst_FS(ir));
953			ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
954			rv.w = ieee754sp_tint(fs);
955			ieee754_csr.rm = oldrm;
956			rfmt = w_fmt;
957			goto copcsr;
958		}
959#endif /* __mips >= 2 */
960
961#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
962		case fcvtl_op:{
963			ieee754sp fs;
964
965			SPFROMREG(fs, MIPSInst_FS(ir));
966			rv.l = ieee754sp_tlong(fs);
967			rfmt = l_fmt;
968			goto copcsr;
969		}
970
971		case froundl_op:
972		case ftruncl_op:
973		case fceill_op:
974		case ffloorl_op:{
975			unsigned int oldrm = ieee754_csr.rm;
976			ieee754sp fs;
977
978			SPFROMREG(fs, MIPSInst_FS(ir));
979			ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
980			rv.l = ieee754sp_tlong(fs);
981			ieee754_csr.rm = oldrm;
982			rfmt = l_fmt;
983			goto copcsr;
984		}
985#endif /* __mips64 && !fpu(single) */
986
987		default:
988			if (MIPSInst_FUNC(ir) >= fcmp_op) {
989				unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
990				ieee754sp fs, ft;
991
992				SPFROMREG(fs, MIPSInst_FS(ir));
993				SPFROMREG(ft, MIPSInst_FT(ir));
994				rv.w = ieee754sp_cmp(fs, ft,
995					cmptab[cmpop & 0x7], cmpop & 0x8);
996				rfmt = -1;
997				if ((cmpop & 0x8) && ieee754_cxtest
998					(IEEE754_INVALID_OPERATION))
999					rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
1000				else
1001					goto copcsr;
1002
1003			}
1004			else {
1005				return SIGILL;
1006			}
1007			break;
1008		}
1009		break;
1010	}
1011
1012#ifndef SINGLE_ONLY_FPU
1013	case d_fmt:{
1014		union {
1015			ieee754dp(*b) (ieee754dp, ieee754dp);
1016			ieee754dp(*u) (ieee754dp);
1017		} handler;
1018
1019		switch (MIPSInst_FUNC(ir)) {
1020			/* binary ops */
1021		case fadd_op:
1022			handler.b = ieee754dp_add;
1023			goto dcopbop;
1024		case fsub_op:
1025			handler.b = ieee754dp_sub;
1026			goto dcopbop;
1027		case fmul_op:
1028			handler.b = ieee754dp_mul;
1029			goto dcopbop;
1030		case fdiv_op:
1031			handler.b = ieee754dp_div;
1032			goto dcopbop;
1033
1034			/* unary  ops */
1035#if __mips >= 2 || __mips64
1036		case fsqrt_op:
1037			handler.u = ieee754dp_sqrt;
1038			goto dcopuop;
1039#endif
1040#if __mips >= 4 && __mips != 32
1041		case frsqrt_op:
1042			handler.u = fpemu_dp_rsqrt;
1043			goto dcopuop;
1044		case frecip_op:
1045			handler.u = fpemu_dp_recip;
1046			goto dcopuop;
1047#endif
1048#if __mips >= 4
1049		case fmovc_op:
1050			cond = fpucondbit[MIPSInst_FT(ir) >> 2];
1051			if (((ctx->fcr31 & cond) != 0) !=
1052				((MIPSInst_FT(ir) & 1) != 0))
1053				return 0;
1054			DPFROMREG(rv.d, MIPSInst_FS(ir));
1055			break;
1056		case fmovz_op:
1057			if (xcp->regs[MIPSInst_FT(ir)] != 0)
1058				return 0;
1059			DPFROMREG(rv.d, MIPSInst_FS(ir));
1060			break;
1061		case fmovn_op:
1062			if (xcp->regs[MIPSInst_FT(ir)] == 0)
1063				return 0;
1064			DPFROMREG(rv.d, MIPSInst_FS(ir));
1065			break;
1066#endif
1067		case fabs_op:
1068			handler.u = ieee754dp_abs;
1069			goto dcopuop;
1070
1071		case fneg_op:
1072			handler.u = ieee754dp_neg;
1073			goto dcopuop;
1074
1075		case fmov_op:
1076			/* an easy one */
1077			DPFROMREG(rv.d, MIPSInst_FS(ir));
1078			goto copcsr;
1079
1080			/* binary op on handler */
1081		      dcopbop:{
1082				ieee754dp fs, ft;
1083
1084				DPFROMREG(fs, MIPSInst_FS(ir));
1085				DPFROMREG(ft, MIPSInst_FT(ir));
1086
1087				rv.d = (*handler.b) (fs, ft);
1088				goto copcsr;
1089			}
1090		      dcopuop:{
1091				ieee754dp fs;
1092
1093				DPFROMREG(fs, MIPSInst_FS(ir));
1094				rv.d = (*handler.u) (fs);
1095				goto copcsr;
1096			}
1097
1098			/* unary conv ops */
1099		case fcvts_op:{
1100			ieee754dp fs;
1101
1102			DPFROMREG(fs, MIPSInst_FS(ir));
1103			rv.s = ieee754sp_fdp(fs);
1104			rfmt = s_fmt;
1105			goto copcsr;
1106		}
1107		case fcvtd_op:
1108			return SIGILL;	/* not defined */
1109
1110		case fcvtw_op:{
1111			ieee754dp fs;
1112
1113			DPFROMREG(fs, MIPSInst_FS(ir));
1114			rv.w = ieee754dp_tint(fs);	/* wrong */
1115			rfmt = w_fmt;
1116			goto copcsr;
1117		}
1118
1119#if __mips >= 2 || __mips64
1120		case fround_op:
1121		case ftrunc_op:
1122		case fceil_op:
1123		case ffloor_op:{
1124			unsigned int oldrm = ieee754_csr.rm;
1125			ieee754dp fs;
1126
1127			DPFROMREG(fs, MIPSInst_FS(ir));
1128			ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
1129			rv.w = ieee754dp_tint(fs);
1130			ieee754_csr.rm = oldrm;
1131			rfmt = w_fmt;
1132			goto copcsr;
1133		}
1134#endif
1135
1136#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
1137		case fcvtl_op:{
1138			ieee754dp fs;
1139
1140			DPFROMREG(fs, MIPSInst_FS(ir));
1141			rv.l = ieee754dp_tlong(fs);
1142			rfmt = l_fmt;
1143			goto copcsr;
1144		}
1145
1146		case froundl_op:
1147		case ftruncl_op:
1148		case fceill_op:
1149		case ffloorl_op:{
1150			unsigned int oldrm = ieee754_csr.rm;
1151			ieee754dp fs;
1152
1153			DPFROMREG(fs, MIPSInst_FS(ir));
1154			ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];
1155			rv.l = ieee754dp_tlong(fs);
1156			ieee754_csr.rm = oldrm;
1157			rfmt = l_fmt;
1158			goto copcsr;
1159		}
1160#endif /* __mips >= 3 && !fpu(single) */
1161
1162		default:
1163			if (MIPSInst_FUNC(ir) >= fcmp_op) {
1164				unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
1165				ieee754dp fs, ft;
1166
1167				DPFROMREG(fs, MIPSInst_FS(ir));
1168				DPFROMREG(ft, MIPSInst_FT(ir));
1169				rv.w = ieee754dp_cmp(fs, ft,
1170					cmptab[cmpop & 0x7], cmpop & 0x8);
1171				rfmt = -1;
1172				if ((cmpop & 0x8)
1173					&&
1174					ieee754_cxtest
1175					(IEEE754_INVALID_OPERATION))
1176					rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
1177				else
1178					goto copcsr;
1179
1180			}
1181			else {
1182				return SIGILL;
1183			}
1184			break;
1185		}
1186		break;
1187	}
1188#endif /* ifndef SINGLE_ONLY_FPU */
1189
1190	case w_fmt:{
1191		ieee754sp fs;
1192
1193		switch (MIPSInst_FUNC(ir)) {
1194		case fcvts_op:
1195			/* convert word to single precision real */
1196			SPFROMREG(fs, MIPSInst_FS(ir));
1197			rv.s = ieee754sp_fint(fs.bits);
1198			rfmt = s_fmt;
1199			goto copcsr;
1200#ifndef SINGLE_ONLY_FPU
1201		case fcvtd_op:
1202			/* convert word to double precision real */
1203			SPFROMREG(fs, MIPSInst_FS(ir));
1204			rv.d = ieee754dp_fint(fs.bits);
1205			rfmt = d_fmt;
1206			goto copcsr;
1207#endif
1208		default:
1209			return SIGILL;
1210		}
1211		break;
1212	}
1213
1214#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
1215	case l_fmt:{
1216		switch (MIPSInst_FUNC(ir)) {
1217		case fcvts_op:
1218			/* convert long to single precision real */
1219			rv.s = ieee754sp_flong(ctx->fpr[MIPSInst_FS(ir)]);
1220			rfmt = s_fmt;
1221			goto copcsr;
1222		case fcvtd_op:
1223			/* convert long to double precision real */
1224			rv.d = ieee754dp_flong(ctx->fpr[MIPSInst_FS(ir)]);
1225			rfmt = d_fmt;
1226			goto copcsr;
1227		default:
1228			return SIGILL;
1229		}
1230		break;
1231	}
1232#endif
1233
1234	default:
1235		return SIGILL;
1236	}
1237
1238	/*
1239	 * Update the fpu CSR register for this operation.
1240	 * If an exception is required, generate a tidy SIGFPE exception,
1241	 * without updating the result register.
1242	 * Note: cause exception bits do not accumulate, they are rewritten
1243	 * for each op; only the flag/sticky bits accumulate.
1244	 */
1245	ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
1246	if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
1247		/*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */
1248		return SIGFPE;
1249	}
1250
1251	/*
1252	 * Now we can safely write the result back to the register file.
1253	 */
1254	switch (rfmt) {
1255	case -1:{
1256#if __mips >= 4
1257		cond = fpucondbit[MIPSInst_FD(ir) >> 2];
1258#else
1259		cond = FPU_CSR_COND;
1260#endif
1261		if (rv.w)
1262			ctx->fcr31 |= cond;
1263		else
1264			ctx->fcr31 &= ~cond;
1265		break;
1266	}
1267#ifndef SINGLE_ONLY_FPU
1268	case d_fmt:
1269		DPTOREG(rv.d, MIPSInst_FD(ir));
1270		break;
1271#endif
1272	case s_fmt:
1273		SPTOREG(rv.s, MIPSInst_FD(ir));
1274		break;
1275	case w_fmt:
1276		SITOREG(rv.w, MIPSInst_FD(ir));
1277		break;
1278#if defined(__mips64) && !defined(SINGLE_ONLY_FPU)
1279	case l_fmt:
1280		DITOREG(rv.l, MIPSInst_FD(ir));
1281		break;
1282#endif
1283	default:
1284		return SIGILL;
1285	}
1286
1287	return 0;
1288}
1289
1290int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp,
1291	struct mips_fpu_soft_struct *ctx)
1292{
1293	unsigned long oldepc, prevepc;
1294	mips_instruction insn;
1295	int sig = 0;
1296
1297	oldepc = xcp->cp0_epc;
1298	do {
1299		prevepc = xcp->cp0_epc;
1300
1301		if (get_user(insn, (mips_instruction *) xcp->cp0_epc)) {
1302			fpuemustats.errors++;
1303			return SIGBUS;
1304		}
1305		if (insn == 0)
1306			xcp->cp0_epc += 4;	/* skip nops */
1307		else {
1308			/*
1309			 * The 'ieee754_csr' is an alias of
1310			 * ctx->fcr31.  No need to copy ctx->fcr31 to
1311			 * ieee754_csr.  But ieee754_csr.rm is ieee
1312			 * library modes. (not mips rounding mode)
1313			 */
1314			/* convert to ieee library modes */
1315			ieee754_csr.rm = ieee_rm[ieee754_csr.rm];
1316			sig = cop1Emulate(xcp, ctx);
1317			/* revert to mips rounding mode */
1318			ieee754_csr.rm = mips_rm[ieee754_csr.rm];
1319		}
1320
1321		if (cpu_has_fpu)
1322			break;
1323		if (sig)
1324			break;
1325
1326		cond_resched();
1327	} while (xcp->cp0_epc > prevepc);
1328
1329	/* SIGILL indicates a non-fpu instruction */
1330	if (sig == SIGILL && xcp->cp0_epc != oldepc)
1331		/* but if epc has advanced, then ignore it */
1332		sig = 0;
1333
1334	return sig;
1335}
1336