/*
 * Redundant with logic already in kernel/branch.c,
 * embedded in compute_return_epc.  At some point,
 * a single subroutine should be used across both
 * modules.
 */
static int isBranchInstr(mips_instruction * i)
{
	switch (MIPSInst_OPCODE(*i)) {
	case spec_op:
		switch (MIPSInst_FUNC(*i)) {
		case jalr_op:
		case jr_op:
			return 1;
		}
		break;

	case bcond_op:
		switch (MIPSInst_RT(*i)) {
		case bltz_op:
		case bgez_op:
		case bltzl_op:
		case bgezl_op:
		case bltzal_op:
		case bgezal_op:
		case bltzall_op:
		case bgezall_op:
			return 1;
		}
		break;

	case j_op:
	case jal_op:
	case jalx_op:
	case beq_op:
	case bne_op:
	case blez_op:
	case bgtz_op:
	case beql_op:
	case bnel_op:
	case blezl_op:
	case bgtzl_op:
		return 1;

	case cop0_op:
	case cop1_op:
	case cop2_op:
	case cop1x_op:
		if (MIPSInst_RS(*i) == bc_op)
			return 1;
		break;
	}

	return 0;
}
示例#2
0
static int emu_div(struct pt_regs *regs,mips_instruction ir)
{
	int x,y;
	int flag = 0;
	int quotient = 0,remainder = 0;
	unsigned int absx,absy,absquotient = 0,absremainder = 0,bm = 1;
	/*the "ir" is the instruction causing the exception*/
	x = regs->regs[MIPSInst_RS(ir)];
	y = regs->regs[MIPSInst_RT(ir)];
	
#ifdef __test_ri__
	//printf("now in function:emu_div().\r\n");
#endif

	if( y == 0 ) {/*overflow*/
		return SIGABRT;
	}
	/*x and y ·ûºÅÊÇ·ñ²»Í¬*/
	flag = (x&0x80000000)^(y&0x80000000);
	
	/*get the abs(x)*/
	if(x<0){
		absx = (unsigned int)-x;
	}else {
		absx = (unsigned int)x;
	}
	
	/*get the abs(y)*/
	if(y<0){
		absy = (unsigned int) -y;
	}else {
		absy = (unsigned int)y;
	}
	
	/*caculate the absx/absy*/		
	if(absx<absy) {/*don't need to calculate*/
		absquotient = 0;
		absremainder = absx;
		goto end;
	}
       
	while(!(absy&0x80000000))
	{	absy<<=1;
		if(absx<absy){
			absy>>= 1;
			break;
		}
		bm<<=1;
	}
示例#3
0
static int
cop1Emulate(int xcptno, struct pt_regs *xcp,
	    struct mips_fpu_soft_struct *ctx)
{
	mips_instruction ir;
	vaddr_t emulpc;
	vaddr_t contpc;
	unsigned int cond;
	int err = 0;


	ir = mips_get_word(xcp, REG_TO_VA xcp->cp0_epc, &err);
	if (err) {
		fpuemuprivate.stats.errors++;
		return SIGBUS;
	}

	/* XXX NEC Vr54xx bug workaround */
	if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
		xcp->cp0_cause &= ~CAUSEF_BD;

	if (xcp->cp0_cause & CAUSEF_BD) {
		/*
		 * The instruction to be emulated is in a branch delay slot
		 * which means that we have to  emulate the branch instruction
		 * BEFORE we do the cop1 instruction. 
		 *
		 * This branch could be a COP1 branch, but in that case we
		 * would have had a trap for that instruction, and would not
		 * come through this route.
		 *
		 * Linux MIPS branch emulator operates on context, updating the
		 * cp0_epc.
		 */
		emulpc = REG_TO_VA(xcp->cp0_epc + 4);	/* Snapshot emulation target */

		if (__compute_return_epc(xcp)) {
#ifdef CP1DBG
			printk("failed to emulate branch at %p\n",
				    REG_TO_VA(xcp->cp0_epc));
#endif
			return SIGILL;;
		}
		ir = mips_get_word(xcp, emulpc, &err);
		if (err) {
			fpuemuprivate.stats.errors++;
			return SIGBUS;
		}
		contpc = REG_TO_VA xcp->cp0_epc;
	} else {
		emulpc = REG_TO_VA xcp->cp0_epc;
		contpc = REG_TO_VA xcp->cp0_epc + 4;
	}

      emul:
	fpuemuprivate.stats.emulated++;
	switch (MIPSInst_OPCODE(ir)) {
#ifdef CP0_STATUS_FR_SUPPORT
		/* R4000+ 64-bit fpu registers */
#ifndef SINGLE_ONLY_FPU
	case ldc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			int ft = MIPSInst_RT(ir);
			if (!(xcp->cp0_status & ST0_FR))
				ft &= ~1;
			ctx->regs[ft] = mips_get_dword(xcp, va, &err);
			fpuemuprivate.stats.loads++;
			if (err) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
		}
		break;

	case sdc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			int ft = MIPSInst_RT(ir);
			if (!(xcp->cp0_status & ST0_FR))
				ft &= ~1;
			fpuemuprivate.stats.stores++;
			if (mips_put_dword(xcp, va, ctx->regs[ft])) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
		}
		break;
#endif

	case lwc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			fpureg_t val;
			int ft = MIPSInst_RT(ir);
			fpuemuprivate.stats.loads++;
			val = mips_get_word(xcp, va, &err);
			if (err) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
			if (xcp->cp0_status & ST0_FR) {
				/* load whole register */
				ctx->regs[ft] = val;
			} else if (ft & 1) {
				/* load to m.s. 32 bits */
#ifdef SINGLE_ONLY_FPU
				/* illegal register in single-float mode */
				return SIGILL;
#else
				ctx->regs[(ft & ~1)] &= 0xffffffff;
				ctx->regs[(ft & ~1)] |= val << 32;
#endif
			} else {
				/* load to l.s. 32 bits */
				ctx->regs[ft] &= ~0xffffffffLL;
				ctx->regs[ft] |= val;
			}
		}
		break;

	case swc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			unsigned int val;
			int ft = MIPSInst_RT(ir);
			fpuemuprivate.stats.stores++;
			if (xcp->cp0_status & ST0_FR) {
				/* store whole register */
				val = ctx->regs[ft];
			} else if (ft & 1) {
#ifdef SINGLE_ONLY_FPU
				/* illegal register in single-float mode */
				return SIGILL;
#else
				/* store from m.s. 32 bits */
				val = ctx->regs[(ft & ~1)] >> 32;
#endif
			} else {
				/* store from l.s. 32 bits */
				val = ctx->regs[ft];
			}
			if (mips_put_word(xcp, va, val)) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
		}
		break;
#else				/* old 32-bit fpu registers */
	case lwc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			ctx->regs[MIPSInst_RT(ir)] =
			    mips_get_word(xcp, va, &err);
			fpuemuprivate.stats.loads++;
			if (err) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
		}
		break;

	case swc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			fpuemuprivate.stats.stores++;
			if (mips_put_word
			    (xcp, va, ctx->regs[MIPSInst_RT(ir)])) {
				fpuemuprivate.stats.errors++;
				return SIGBUS;
			}
		}
		break;
	case ldc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			unsigned int rt = MIPSInst_RT(ir) & ~1;
			int errs = 0;
			fpuemuprivate.stats.loads++;
#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
			ctx->regs[rt + 1] =
			    mips_get_word(xcp, va + 0, &err);
			errs += err;
			ctx->regs[rt + 0] =
			    mips_get_word(xcp, va + 4, &err);
			errs += err;
#else
			ctx->regs[rt + 0] =
			    mips_get_word(xcp, va + 0, &err);
			errs += err;
			ctx->regs[rt + 1] =
			    mips_get_word(xcp, va + 4, &err);
			errs += err;
#endif
			if (err)
				return SIGBUS;
		}
		break;

	case sdc1_op:
		{
			void *va = REG_TO_VA(xcp->regs[MIPSInst_RS(ir)])
			    + MIPSInst_SIMM(ir);
			unsigned int rt = MIPSInst_RT(ir) & ~1;
			fpuemuprivate.stats.stores++;
#if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__)
			if (mips_put_word(xcp, va + 0, ctx->regs[rt + 1]))
				return SIGBUS;
			if (mips_put_word(xcp, va + 4, ctx->regs[rt + 0]))
				return SIGBUS;
#else
			if (mips_put_word(xcp, va + 0, ctx->regs[rt + 0]))
				return SIGBUS;
			if (mips_put_word(xcp, va + 4, ctx->regs[rt + 1]))
				return SIGBUS;
#endif
		}
		break;
#endif

	case cop1_op:
		switch (MIPSInst_RS(ir)) {

#ifdef CP0_STATUS_FR_SUPPORT
#if __mips64 && !defined(SINGLE_ONLY_FPU)
		case dmfc_op:
			/* copregister fs -> gpr[rt] */
			if (MIPSInst_RT(ir) != 0) {
				int fs = MIPSInst_RD(ir);
				if (!(xcp->cp0_status & ST0_FR))
					fs &= ~1;
				xcp->regs[MIPSInst_RT(ir)] = ctx->regs[fs];
			}
			break;

		case dmtc_op:
			/* copregister fs <- rt */
			{
				fpureg_t value;
				int fs = MIPSInst_RD(ir);
				if (!(xcp->cp0_status & ST0_FR))
					fs &= ~1;
				value =
				    (MIPSInst_RT(ir) ==
				     0) ? 0 : xcp->regs[MIPSInst_RT(ir)];
				ctx->regs[fs] = value;
			}
			break;
#endif

		case mfc_op:
			/* copregister rd -> gpr[rt] */
			if (MIPSInst_RT(ir) != 0) {
				/* default value from l.s. 32 bits */
				int value = ctx->regs[MIPSInst_RD(ir)];
				if (MIPSInst_RD(ir) & 1) {
#ifdef SINGLE_ONLY_FPU
					/* illegal register in single-float mode */
					return SIGILL;
#else
					if (!(xcp->cp0_status & ST0_FR)) {
						/* move from m.s. 32 bits */
						value =
						    ctx->
						    regs[MIPSInst_RD(ir) &
							 ~1] >> 32;
					}
#endif
				}
				xcp->regs[MIPSInst_RT(ir)] = value;
			}
示例#4
0
static int emu_lwl(struct pt_regs * regs,mips_instruction ir,vaddr_t_l emulpc)
{ 	int err = 0;
	/*the "ir" is the instruction causing the exception*/
	/*get the real address,perhaps the address is not word aligned*/
	void *va = REG_TO_VA_l (regs->regs[MIPSInst_RS(ir)])+ MIPSInst_SIMM(ir);
	
	unsigned long addr = 0;
	unsigned long emul_pc = (unsigned long)emulpc;
	
	unsigned long little_three_bits;
	unsigned long value,value_tmp;

//	printf("emu_lwl\r\n");

	/*compute the correct position in the RT*/
	/*note !!!!: we have supposed the CPU is little_Endianness and status regiester's RE bit =0 */
	/*little Endianness*/
	little_three_bits = (unsigned long)va&(0x7);
	value_tmp = regs->regs[MIPSInst_RT(ir)];
	switch(little_three_bits) {
		case 0:
		case 4:
		 /*must check lwl valid*/
		 addr = (unsigned long) va;
		 check_axs(emul_pc,addr,4);
		 value = mips_get_word_l(regs,va,&err);
		 if(err){
			 return SIGBUS;
		 }
		 value<<=24;
		 value_tmp &= 0xffffff;
	         regs->regs[MIPSInst_RT(ir)] =value_tmp|value;
			break;
			
		case 1:
		case 5:
		addr = (unsigned long)va -1;
		check_axs(emul_pc,addr,4);
		value = mips_get_word_l(regs,(void *)((unsigned long) va-1),&err);
		if(err){
			return SIGBUS;
		}
		value<<=16;
		value_tmp&=0xffff;
		regs->regs[MIPSInst_RT(ir)] =value_tmp|value;
			break;

		case 2:
		case 6:
		addr = (unsigned long)va - 2;
		check_axs(emul_pc,addr,4);
		value = mips_get_word_l(regs,(void *)((unsigned long)va-2),&err);
		if(err){
			return SIGBUS;

		}
		value<<=8;
		value_tmp &= 0xff;
		regs->regs[MIPSInst_RT(ir)] =value_tmp|value;
			break;
			
		case 3:
		case 7:
		addr = (unsigned long)va - 3;
		check_axs(emul_pc,addr,4);
		value = mips_get_word_l(regs,(void *)((unsigned long)va-3),&err);
		if(err){
			return SIGBUS;
		};
		regs->regs[MIPSInst_RT(ir)] = value;
			break;
	} /*swith ended*/
	return 0;

}