xref: /linux/arch/mips/math-emu/cp1emu.c (revision 587cb98f368de7ea4382a6ca99847113fbbeea91)
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 
63 static int fpu_emu(struct pt_regs *, struct mips_fpu_soft_struct *,
64 	mips_instruction);
65 
66 #if __mips >= 4 && __mips != 32
67 static 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 
73 struct 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. */
81 static 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). */
88 static 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 */
97 static 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  */
116 static 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 
206 static 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 || defined(__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  */
561 static 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) \
580 static 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 
595 static ieee754dp fpemu_dp_recip(ieee754dp d)
596 {
597 	return ieee754dp_div(ieee754dp_one(0), d);
598 }
599 
600 static ieee754dp fpemu_dp_rsqrt(ieee754dp d)
601 {
602 	return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d));
603 }
604 
605 static ieee754sp fpemu_sp_recip(ieee754sp s)
606 {
607 	return ieee754sp_div(ieee754sp_one(0), s);
608 }
609 
610 static ieee754sp fpemu_sp_rsqrt(ieee754sp s)
611 {
612 	return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s));
613 }
614 
615 DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add,);
616 DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub,);
617 DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg);
618 DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg);
619 DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add,);
620 DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub,);
621 DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
622 DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
623 
624 static 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  */
806 static 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 || defined(__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 || defined(__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 /* defined(__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 || defined(__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 || defined(__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 
1290 int 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