⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cp1emu.c

📁 LINUX 2.6.17.4的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		case msub_s_op:			handler = fpemu_sp_msub;			goto scoptop;		case nmadd_s_op:			handler = fpemu_sp_nmadd;			goto scoptop;		case nmsub_s_op:			handler = fpemu_sp_nmsub;			goto scoptop;		      scoptop:			SPFROMREG(fr, MIPSInst_FR(ir));			SPFROMREG(fs, MIPSInst_FS(ir));			SPFROMREG(ft, MIPSInst_FT(ir));			fd = (*handler) (fr, fs, ft);			SPTOREG(fd, MIPSInst_FD(ir));		      copcsr:			if (ieee754_cxtest(IEEE754_INEXACT))				rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;			if (ieee754_cxtest(IEEE754_UNDERFLOW))				rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;			if (ieee754_cxtest(IEEE754_OVERFLOW))				rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;			if (ieee754_cxtest(IEEE754_INVALID_OPERATION))				rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;			ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;			if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {				/*printk ("SIGFPE: fpu csr = %08x\n",				   ctx->fcr31); */				return SIGFPE;			}			break;		default:			return SIGILL;		}		break;	}	case d_fmt:{		/* 1 */		ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);		ieee754dp fd, fr, fs, ft;		u64 __user *va;		u64 val;		switch (MIPSInst_FUNC(ir)) {		case ldxc1_op:			va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] +				xcp->regs[MIPSInst_FT(ir)]);			fpuemustats.loads++;			if (get_user(val, va)) {				fpuemustats.errors++;				return SIGBUS;			}			DITOREG(val, MIPSInst_FD(ir));			break;		case sdxc1_op:			va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] +				xcp->regs[MIPSInst_FT(ir)]);			fpuemustats.stores++;			DIFROMREG(val, MIPSInst_FS(ir));			if (put_user(val, va)) {				fpuemustats.errors++;				return SIGBUS;			}			break;		case madd_d_op:			handler = fpemu_dp_madd;			goto dcoptop;		case msub_d_op:			handler = fpemu_dp_msub;			goto dcoptop;		case nmadd_d_op:			handler = fpemu_dp_nmadd;			goto dcoptop;		case nmsub_d_op:			handler = fpemu_dp_nmsub;			goto dcoptop;		      dcoptop:			DPFROMREG(fr, MIPSInst_FR(ir));			DPFROMREG(fs, MIPSInst_FS(ir));			DPFROMREG(ft, MIPSInst_FT(ir));			fd = (*handler) (fr, fs, ft);			DPTOREG(fd, MIPSInst_FD(ir));			goto copcsr;		default:			return SIGILL;		}		break;	}	case 0x7:		/* 7 */		if (MIPSInst_FUNC(ir) != pfetch_op) {			return SIGILL;		}		/* ignore prefx operation */		break;	default:		return SIGILL;	}	return 0;}#endif/* * Emulate a single COP1 arithmetic instruction. */static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx,	mips_instruction ir){	int rfmt;		/* resulting format */	unsigned rcsr = 0;	/* resulting csr */	unsigned cond;	union {		ieee754dp d;		ieee754sp s;		int w;#ifdef __mips64		s64 l;#endif	} rv;			/* resulting value */	fpuemustats.cp1ops++;	switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {	case s_fmt:{		/* 0 */		union {			ieee754sp(*b) (ieee754sp, ieee754sp);			ieee754sp(*u) (ieee754sp);		} handler;		switch (MIPSInst_FUNC(ir)) {			/* binary ops */		case fadd_op:			handler.b = ieee754sp_add;			goto scopbop;		case fsub_op:			handler.b = ieee754sp_sub;			goto scopbop;		case fmul_op:			handler.b = ieee754sp_mul;			goto scopbop;		case fdiv_op:			handler.b = ieee754sp_div;			goto scopbop;			/* unary  ops */#if __mips >= 2 || defined(__mips64)		case fsqrt_op:			handler.u = ieee754sp_sqrt;			goto scopuop;#endif#if __mips >= 4 && __mips != 32		case frsqrt_op:			handler.u = fpemu_sp_rsqrt;			goto scopuop;		case frecip_op:			handler.u = fpemu_sp_recip;			goto scopuop;#endif#if __mips >= 4		case fmovc_op:			cond = fpucondbit[MIPSInst_FT(ir) >> 2];			if (((ctx->fcr31 & cond) != 0) !=				((MIPSInst_FT(ir) & 1) != 0))				return 0;			SPFROMREG(rv.s, MIPSInst_FS(ir));			break;		case fmovz_op:			if (xcp->regs[MIPSInst_FT(ir)] != 0)				return 0;			SPFROMREG(rv.s, MIPSInst_FS(ir));			break;		case fmovn_op:			if (xcp->regs[MIPSInst_FT(ir)] == 0)				return 0;			SPFROMREG(rv.s, MIPSInst_FS(ir));			break;#endif		case fabs_op:			handler.u = ieee754sp_abs;			goto scopuop;		case fneg_op:			handler.u = ieee754sp_neg;			goto scopuop;		case fmov_op:			/* an easy one */			SPFROMREG(rv.s, MIPSInst_FS(ir));			goto copcsr;			/* binary op on handler */		      scopbop:			{				ieee754sp fs, ft;				SPFROMREG(fs, MIPSInst_FS(ir));				SPFROMREG(ft, MIPSInst_FT(ir));				rv.s = (*handler.b) (fs, ft);				goto copcsr;			}		      scopuop:			{				ieee754sp fs;				SPFROMREG(fs, MIPSInst_FS(ir));				rv.s = (*handler.u) (fs);				goto copcsr;			}		      copcsr:			if (ieee754_cxtest(IEEE754_INEXACT))				rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;			if (ieee754_cxtest(IEEE754_UNDERFLOW))				rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;			if (ieee754_cxtest(IEEE754_OVERFLOW))				rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;			if (ieee754_cxtest(IEEE754_ZERO_DIVIDE))				rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S;			if (ieee754_cxtest(IEEE754_INVALID_OPERATION))				rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;			break;			/* unary conv ops */		case fcvts_op:			return SIGILL;	/* not defined */		case fcvtd_op:{			ieee754sp fs;			SPFROMREG(fs, MIPSInst_FS(ir));			rv.d = ieee754dp_fsp(fs);			rfmt = d_fmt;			goto copcsr;		}		case fcvtw_op:{			ieee754sp fs;			SPFROMREG(fs, MIPSInst_FS(ir));			rv.w = ieee754sp_tint(fs);			rfmt = w_fmt;			goto copcsr;		}#if __mips >= 2 || defined(__mips64)		case fround_op:		case ftrunc_op:		case fceil_op:		case ffloor_op:{			unsigned int oldrm = ieee754_csr.rm;			ieee754sp fs;			SPFROMREG(fs, MIPSInst_FS(ir));			ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];			rv.w = ieee754sp_tint(fs);			ieee754_csr.rm = oldrm;			rfmt = w_fmt;			goto copcsr;		}#endif /* __mips >= 2 */#if defined(__mips64)		case fcvtl_op:{			ieee754sp fs;			SPFROMREG(fs, MIPSInst_FS(ir));			rv.l = ieee754sp_tlong(fs);			rfmt = l_fmt;			goto copcsr;		}		case froundl_op:		case ftruncl_op:		case fceill_op:		case ffloorl_op:{			unsigned int oldrm = ieee754_csr.rm;			ieee754sp fs;			SPFROMREG(fs, MIPSInst_FS(ir));			ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];			rv.l = ieee754sp_tlong(fs);			ieee754_csr.rm = oldrm;			rfmt = l_fmt;			goto copcsr;		}#endif /* defined(__mips64) */		default:			if (MIPSInst_FUNC(ir) >= fcmp_op) {				unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;				ieee754sp fs, ft;				SPFROMREG(fs, MIPSInst_FS(ir));				SPFROMREG(ft, MIPSInst_FT(ir));				rv.w = ieee754sp_cmp(fs, ft,					cmptab[cmpop & 0x7], cmpop & 0x8);				rfmt = -1;				if ((cmpop & 0x8) && ieee754_cxtest					(IEEE754_INVALID_OPERATION))					rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;				else					goto copcsr;			}			else {				return SIGILL;			}			break;		}		break;	}	case d_fmt:{		union {			ieee754dp(*b) (ieee754dp, ieee754dp);			ieee754dp(*u) (ieee754dp);		} handler;		switch (MIPSInst_FUNC(ir)) {			/* binary ops */		case fadd_op:			handler.b = ieee754dp_add;			goto dcopbop;		case fsub_op:			handler.b = ieee754dp_sub;			goto dcopbop;		case fmul_op:			handler.b = ieee754dp_mul;			goto dcopbop;		case fdiv_op:			handler.b = ieee754dp_div;			goto dcopbop;			/* unary  ops */#if __mips >= 2 || defined(__mips64)		case fsqrt_op:			handler.u = ieee754dp_sqrt;			goto dcopuop;#endif#if __mips >= 4 && __mips != 32		case frsqrt_op:			handler.u = fpemu_dp_rsqrt;			goto dcopuop;		case frecip_op:			handler.u = fpemu_dp_recip;			goto dcopuop;#endif#if __mips >= 4		case fmovc_op:			cond = fpucondbit[MIPSInst_FT(ir) >> 2];			if (((ctx->fcr31 & cond) != 0) !=				((MIPSInst_FT(ir) & 1) != 0))				return 0;			DPFROMREG(rv.d, MIPSInst_FS(ir));			break;		case fmovz_op:			if (xcp->regs[MIPSInst_FT(ir)] != 0)				return 0;			DPFROMREG(rv.d, MIPSInst_FS(ir));			break;		case fmovn_op:			if (xcp->regs[MIPSInst_FT(ir)] == 0)				return 0;			DPFROMREG(rv.d, MIPSInst_FS(ir));			break;#endif		case fabs_op:			handler.u = ieee754dp_abs;			goto dcopuop;		case fneg_op:			handler.u = ieee754dp_neg;			goto dcopuop;		case fmov_op:			/* an easy one */			DPFROMREG(rv.d, MIPSInst_FS(ir));			goto copcsr;			/* binary op on handler */		      dcopbop:{				ieee754dp fs, ft;				DPFROMREG(fs, MIPSInst_FS(ir));				DPFROMREG(ft, MIPSInst_FT(ir));				rv.d = (*handler.b) (fs, ft);				goto copcsr;			}		      dcopuop:{				ieee754dp fs;				DPFROMREG(fs, MIPSInst_FS(ir));				rv.d = (*handler.u) (fs);				goto copcsr;			}			/* unary conv ops */		case fcvts_op:{			ieee754dp fs;			DPFROMREG(fs, MIPSInst_FS(ir));			rv.s = ieee754sp_fdp(fs);			rfmt = s_fmt;			goto copcsr;		}		case fcvtd_op:			return SIGILL;	/* not defined */		case fcvtw_op:{			ieee754dp fs;			DPFROMREG(fs, MIPSInst_FS(ir));			rv.w = ieee754dp_tint(fs);	/* wrong */			rfmt = w_fmt;			goto copcsr;		}#if __mips >= 2 || defined(__mips64)		case fround_op:		case ftrunc_op:		case fceil_op:		case ffloor_op:{			unsigned int oldrm = ieee754_csr.rm;			ieee754dp fs;			DPFROMREG(fs, MIPSInst_FS(ir));			ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];			rv.w = ieee754dp_tint(fs);			ieee754_csr.rm = oldrm;			rfmt = w_fmt;			goto copcsr;		}#endif#if defined(__mips64)		case fcvtl_op:{			ieee754dp fs;			DPFROMREG(fs, MIPSInst_FS(ir));			rv.l = ieee754dp_tlong(fs);			rfmt = l_fmt;			goto copcsr;		}		case froundl_op:		case ftruncl_op:		case fceill_op:		case ffloorl_op:{			unsigned int oldrm = ieee754_csr.rm;			ieee754dp fs;			DPFROMREG(fs, MIPSInst_FS(ir));			ieee754_csr.rm = ieee_rm[MIPSInst_FUNC(ir) & 0x3];			rv.l = ieee754dp_tlong(fs);			ieee754_csr.rm = oldrm;			rfmt = l_fmt;			goto copcsr;		}#endif /* __mips >= 3 */		default:			if (MIPSInst_FUNC(ir) >= fcmp_op) {				unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;				ieee754dp fs, ft;				DPFROMREG(fs, MIPSInst_FS(ir));				DPFROMREG(ft, MIPSInst_FT(ir));				rv.w = ieee754dp_cmp(fs, ft,					cmptab[cmpop & 0x7], cmpop & 0x8);				rfmt = -1;				if ((cmpop & 0x8)					&&					ieee754_cxtest					(IEEE754_INVALID_OPERATION))					rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;				else					goto copcsr;			}			else {				return SIGILL;			}			break;		}		break;	}	case w_fmt:{		ieee754sp fs;		switch (MIPSInst_FUNC(ir)) {		case fcvts_op:			/* convert word to single precision real */			SPFROMREG(fs, MIPSInst_FS(ir));			rv.s = ieee754sp_fint(fs.bits);			rfmt = s_fmt;			goto copcsr;		case fcvtd_op:			/* convert word to double precision real */			SPFROMREG(fs, MIPSInst_FS(ir));			rv.d = ieee754dp_fint(fs.bits);			rfmt = d_fmt;			goto copcsr;		default:			return SIGILL;		}		break;	}#if defined(__mips64)	case l_fmt:{		switch (MIPSInst_FUNC(ir)) {		case fcvts_op:			/* convert long to single precision real */			rv.s = ieee754sp_flong(ctx->fpr[MIPSInst_FS(ir)]);			rfmt = s_fmt;			goto copcsr;		case fcvtd_op:			/* convert long to double precision real */			rv.d = ieee754dp_flong(ctx->fpr[MIPSInst_FS(ir)]);			rfmt = d_fmt;			goto copcsr;		default:			return SIGILL;		}		break;	}#endif	default:		return SIGILL;	}	/*	 * Update the fpu CSR register for this operation.	 * If an exception is required, generate a tidy SIGFPE exception,	 * without updating the result register.	 * Note: cause exception bits do not accumulate, they are rewritten	 * for each op; only the flag/sticky bits accumulate.	 */	ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;	if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {		/*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */		return SIGFPE;	}	/*	 * Now we can safely write the result back to the register file.	 */	switch (rfmt) {	case -1:{#if __mips >= 4		cond = fpucondbit[MIPSInst_FD(ir) >> 2];#else		cond = FPU_CSR_COND;#endif		if (rv.w)			ctx->fcr31 |= cond;		else			ctx->fcr31 &= ~cond;		break;	}	case d_fmt:		DPTOREG(rv.d, MIPSInst_FD(ir));		break;	case s_fmt:		SPTOREG(rv.s, MIPSInst_FD(ir));		break;	case w_fmt:		SITOREG(rv.w, MIPSInst_FD(ir));		break;#if defined(__mips64)	case l_fmt:		DITOREG(rv.l, MIPSInst_FD(ir));		break;#endif	default:		return SIGILL;	}	return 0;}int fpu_emulator_cop1Handler(struct pt_regs *xcp,	struct mips_fpu_soft_struct *ctx){	unsigned long oldepc, prevepc;	mips_instruction insn;	int sig = 0;	oldepc = xcp->cp0_epc;	do {		prevepc = xcp->cp0_epc;		if (get_user(insn, (mips_instruction __user *) xcp->cp0_epc)) {			fpuemustats.errors++;			return SIGBUS;		}		if (insn == 0)			xcp->cp0_epc += 4;	/* skip nops */		else {			/*			 * The 'ieee754_csr' is an alias of			 * ctx->fcr31.  No need to copy ctx->fcr31 to			 * ieee754_csr.  But ieee754_csr.rm is ieee			 * library modes. (not mips rounding mode)			 */			/* convert to ieee library modes */			ieee754_csr.rm = ieee_rm[ieee754_csr.rm];			sig = cop1Emulate(xcp, ctx);			/* revert to mips rounding mode */			ieee754_csr.rm = mips_rm[ieee754_csr.rm];		}		if (cpu_has_fpu)			break;		if (sig)			break;		cond_resched();	} while (xcp->cp0_epc > prevepc);	/* SIGILL indicates a non-fpu instruction */	if (sig == SIGILL && xcp->cp0_epc != oldepc)		/* but if epc has advanced, then ignore it */		sig = 0;	return sig;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -