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