예제 #1
0
void dec_DynamicSet(u32 regbase,u32 offs=0)
{
	if (offs==0)
		Emit(shop_jdyn,reg_pc_dyn,mk_reg((Sh4RegType)regbase));
	else
		Emit(shop_jdyn,reg_pc_dyn,mk_reg((Sh4RegType)regbase),mk_imm(offs));
}
예제 #2
0
/*
 *   Generate code to pop a register from the stack.
 */
static void g_pop P2 (REG, reg, DEEP, depth)
{
    ADDRESS *ap;

    /* check on stack underflow */
    if (stack_depth-- == EMPTY) {
        FATAL ((__FILE__, "g_pop", "register stack empty"));
    }
    /* check if the desired register really is on stack */
    if (reg_stack[stack_depth].depth != depth) {
        FATAL (
            (__FILE__, "g_pop", "register order (%d,%d)", (int) depth,
             (int) reg_stack[stack_depth].depth));
    }
    /* check if the register which is restored is really void */
    if (reg_in_use[reg] != UNUSED) {
        FATAL ((__FILE__, "g_pop", "register %d in use", (int) reg));
    }
    reg_in_use[reg] = depth;
    sync_stack ();
    ap = mk_reg (reg);
    switch (reg) {
    case D0:
    case D1:
    case D2:
    case D3:
    case D4:
    case D5:
    case D6:
    case D7:
    case A0:
    case A1:
    case A2:
    case A3:
    case A4:
    case A5:
    case A6:
    case A7:
        g_move (IL4, &apop, ap);
        break;
#ifdef FLOAT_IEEE
    case FP0:
    case FP1:
    case FP2:
    case FP3:
    case FP4:
    case FP5:
    case FP6:
    case FP7:
        g_fcode (op_fmove, IL12, &apop, ap);
        break;
#endif /* FLOAT_IEEE */
    default:
        CANNOT_REACH_HERE ();
    }

    /* clear the push_flag */
    reg_alloc[depth].pushed = FALSE;
}
예제 #3
0
static Exp *translate_get_reg_32( int offset )
{
    assert(offset >= 0);
    
    Temp *reg = mk_reg(reg_offset_to_name(offset), REG_32);
    
    return reg;
}
예제 #4
0
/*
 *   Allocate a temporary floating point register and return it's
 *   addressing mode.
 */
ADDRESS *float_register P0 (void)
{
    ADDRESS *ap = mk_reg (next_float);

    next_float = allocate_register (next_float, F_REG);
    ap->deep = reg_in_use[ap->preg];
    return ap;
}
예제 #5
0
/*
 *   Allocate a temporary addr register and return it's addressing mode.
 */
ADDRESS *address_register P0 (void)
{
    ADDRESS *ap = mk_reg (next_addr);

    next_addr = allocate_register (next_addr, A_REG);
    ap->deep = reg_in_use[ap->preg];
    return ap;
}
예제 #6
0
/*
 *   Allocate a temporary data register and return
 *   it's addressing mode.
 */
ADDRESS *data_register P0 (void)
{
    ADDRESS *ap = mk_reg (next_data);

    next_data = allocate_register (next_data, D_REG);
    ap->deep = reg_in_use[ap->preg];
    return ap;
}
예제 #7
0
static Stmt *translate_put_reg_32( int offset, Exp *data, IRSB *irbb )
{
    assert(data);
    
    Temp *reg = mk_reg(reg_offset_to_name(offset), REG_32);
    
    return new Move( reg, data );
}
예제 #8
0
static BOOL is_exchangable P2 (ADDRESS **, apptr, REG, reg)
{
    ADDRESS *ap = *apptr;

    switch (ap->mode) {
    case am_dreg:
    case am_freg:
	if ((ap->preg <= MAX_DATA) && (is_data_register (reg))
	    /* 
	     * to avoid endless exchanges do replaces only higher 
	     * registernumbers with lower registernumbers
	     */
	    && (reg < ap->preg)) {
	    /*
	     * replace only if temporary
	     */

	    *apptr = mk_reg (reg);
	    (*apptr)->mode = ap->mode;
	    DPRINTF ((DEBUG_FLOW, " and replaced\n"));
	    return TRUE;
	}
	break;
    case am_ireg:
    case am_sreg:
	break;
    case am_areg:
	if (((!is_address_register (reg)) || (ap->preg <= MAX_ADDR))
	    /* 
	     * to avoid endless exchanges do replaces only higher 
	     * registernumbers with lower registernumbers
	     */
	    && ((reg < ap->preg) || (is_index_register (reg)))) {
	    *apptr = mk_reg (reg);
	    DPRINTF ((DEBUG_FLOW, " and replaced\n"));
	    return TRUE;
	}
	break;
    default:
	*apptr = mk_reg (reg);
	DPRINTF ((DEBUG_FLOW, " and replaced\n"));
	return TRUE;
    }
    DPRINTF ((DEBUG_FLOW, " but not changed\n"));
    return FALSE;
}
예제 #9
0
파일: fs-up.c 프로젝트: dpc/rdup
/* make (or delete) an object in the filesystem */
gboolean
mk_obj(FILE * in, char *p, struct rdup * e, GHashTable * uidhash,
       GHashTable * gidhash)
{
	if (opt_verbose >= 1 && e->f_name) {
		if (S_ISLNK(e->f_mode) || e->f_lnk)
			fprintf(stderr, "%s -> %s\n", e->f_name, e->f_target);
		else
			fprintf(stderr, "%s\n", e->f_name);
	}
	if (opt_table)
		rdup_write_table(e, stdout);

	/* split here - or above - return when path is zero length
	 * for links check that the f_size is zero */
	switch (e->plusmin) {
	case MINUS:
		if (opt_dry || !e->f_name)
			return TRUE;

		return rm(e->f_name);
	case PLUS:
		/* opt_dry handled within the subfunctions */

		/* only files, no hardlinks! */
		if (S_ISREG(e->f_mode) && !e->f_lnk)
			return mk_reg(in, e, uidhash, gidhash);

		/* no name, we can exit here - for files this is handled
		 * in mk_reg, because we may need to suck in data */
		if (e->f_name == NULL)
			return TRUE;

		if (S_ISDIR(e->f_mode))
			return mk_dir(e, uidhash, gidhash);

		/* First sym and hardlinks and then regular files */
		if (S_ISLNK(e->f_mode) || e->f_lnk)
			return mk_link(e, p, uidhash, gidhash);

		if (S_ISBLK(e->f_mode) || S_ISCHR(e->f_mode))
			return mk_dev(e, uidhash, gidhash);

		// There's no way to restore a named socket
		if (S_ISSOCK(e->f_mode))
			return TRUE;

		if (S_ISFIFO(e->f_mode))
			return mk_sock(e, uidhash, gidhash);
	}
	/* only reached during the heat death of the universe */
	return TRUE;
}
예제 #10
0
/*
 *   This routine generates code to push a register onto the stack.
 */
static void g_push P2 (REG, reg, DEEP, depth)
{
    ADDRESS *ap;

    sync_stack ();
    ap = mk_reg (reg);
    switch (reg) {
    case D0:
    case D1:
    case D2:
    case D3:
    case D4:
    case D5:
    case D6:
    case D7:
    case A0:
    case A1:
    case A2:
    case A3:
    case A4:
    case A5:
    case A6:
    case A7:
        g_move (IL4, ap, &apush);
        break;
#ifdef FLOAT_IEEE
    case FP0:
    case FP1:
    case FP2:
    case FP3:
    case FP4:
    case FP5:
    case FP6:
    case FP7:
        g_fcode (op_fmove, IL12, ap, &apush);
        break;
#endif /* FLOAT_IEEE */
    default:
        CANNOT_REACH_HERE ();
    }
    reg_stack[stack_depth].reg = reg;
    reg_stack[stack_depth].depth = depth;

    if (reg_alloc[depth].pushed) {
        FATAL ((__FILE__, "g_push", "reg %d already pushed", (int) reg));
    }
    reg_alloc[depth].pushed = TRUE;

    /* check on stack overflow */
    if (++stack_depth > MAX_REG_STACK) {
        FATAL ((__FILE__, "g_push", "register stack overflow"));
    }
}
예제 #11
0
/*
 * this routine generates code to push a register onto the stack
 */
static void g_push P2 (REG, reg, DEEP, number)
{
    ADDRESS *ap;

    ap = mk_reg (reg);
    g_code (op_mov, cc_al, ap, NIL_ADDRESS, NIL_ADDRESS);
    reg_stack[reg_stack_ptr].reg = reg;
    reg_stack[reg_stack_ptr].depth = number;

    /* is already pushed */
    if (reg_alloc[number].pushed) {
	FATAL ((__FILE__, "g_push", "1"));
    }
    reg_alloc[number].pushed = TRUE;

    /* check on stack overflow */
    if (++reg_stack_ptr > MAX_REG_STACK) {
	FATAL ((__FILE__, "g_push", "2"));
    }
}
예제 #12
0
void dec_End(u32 dst,BlockEndType flags,bool delay)
{
	if (state.ngen.OnlyDynamicEnds && flags == BET_StaticJump)
	{
		Emit(shop_mov32,mk_reg(reg_nextpc),mk_imm(dst));
		dec_DynamicSet(reg_nextpc);
		dec_End(0xFFFFFFFF,BET_DynamicJump,delay);
		return;
	}

	if (state.ngen.OnlyDynamicEnds)
	{
		verify(flags == BET_DynamicJump);
	}

	state.BlockType=flags;
	state.NextOp=delay?NDO_Delayslot:NDO_End;
	state.DelayOp=NDO_End;
	state.JumpAddr=dst;
	state.NextAddr=state.cpu.rpc+2+(delay?2:0);
}
예제 #13
0
/*
 * generate code to pop a register from the stack.
 */
static void g_pop P2 (REG, reg, DEEP, number)
{
    ADDRESS *ap;

    /* check on stack underflow */
    if (reg_stack_ptr-- == EMPTY) {
	FATAL ((__FILE__, "g_pop", "1"));
    }
    /* check if the desired register really is on stack */
    if (reg_stack[reg_stack_ptr].depth != number) {
	FATAL ((__FILE__, "g_pop", "2"));
    }
    /* check if the register which is restored is really void */
    if (reg_in_use[reg] != UNUSED) {
	FATAL ((__FILE__, "g_pop", "3"));
    }
    reg_in_use[reg] = number;
    ap = mk_reg (reg);
    g_code (op_mov, cc_al, ap, NIL_ADDRESS, NIL_ADDRESS);

    /* clear the push_flag */
    reg_alloc[number].pushed = FALSE;
}
예제 #14
0
/*
 * allocate a register
 */
ADDRESS *data_register P0 (void)
{
    ADDRESS *ap;

    /*
     * if the register is in use, push it to the stack
     */
    if (reg_in_use[next_reg] != UNUSED) {
	g_push (next_reg, reg_in_use[next_reg]);
    }
    reg_in_use[next_reg] = reg_depth;
    ap = mk_reg (next_reg);
    ap->deep = reg_depth;
    reg_alloc[reg_depth].reg = next_reg;
    reg_alloc[reg_depth].pushed = FALSE;

    if (next_reg++ == max_reg) {
	next_reg = R0;		/* wrap around */
    }
    if (reg_depth++ == MAX_REG_STACK) {
	FATAL ((__FILE__, "data_register", ""));
    }
    return ap;
}
예제 #15
0
void dec_param(DecParam p,shil_param& r1,shil_param& r2, u32 op)
{
	switch(p)
	{
		//constants
	case PRM_PC_D8_x2:
		r1=mk_imm((state.cpu.rpc+4)+(GetImm8(op)<<1));
		break;

	case PRM_PC_D8_x4:
		r1=mk_imm(((state.cpu.rpc+4)&0xFFFFFFFC)+(GetImm8(op)<<2));
		break;
	
	case PRM_ZERO:
		r1= mk_imm(0);
		break;

	case PRM_ONE:
		r1= mk_imm(1);
		break;

	case PRM_TWO:
		r1= mk_imm(2);
		break;

	case PRM_TWO_INV:
		r1= mk_imm(~2);
		break;

	case PRM_ONE_F32:
		r1= mk_imm(0x3f800000);
		break;

	//imms
	case PRM_SIMM8:
		r1=mk_imm(GetSImm8(op));
		break;
	case PRM_UIMM8:
		r1=mk_imm(GetImm8(op));
		break;

	//direct registers
	case PRM_R0:
		r1=mk_reg(reg_r0);
		break;

	case PRM_RN:
		r1=mk_regi(reg_r0+GetN(op));
		break;

	case PRM_RM:
		r1=mk_regi(reg_r0+GetM(op));
		break;

	case PRM_FRN_SZ:
		if (state.cpu.FSZ64)
		{
			int rx=GetN(op)/2;
			if (GetN(op)&1)
				rx+=regv_xd_0;
			else
				rx+=regv_dr_0;

			r1=mk_regi(rx);
			break;
		}
	case PRM_FRN:
		r1=mk_regi(reg_fr_0+GetN(op));
		break;

	case PRM_FRM_SZ:
		if (state.cpu.FSZ64)
		{
			int rx=GetM(op)/2;
			if (GetM(op)&1)
				rx+=regv_xd_0;
			else
				rx+=regv_dr_0;

			r1=mk_regi(rx);
			break;
		}
	case PRM_FRM:
		r1=mk_regi(reg_fr_0+GetM(op));
		break;

	case PRM_FPUL:
		r1=mk_regi(reg_fpul);
		break;

	case PRM_FPN:	//float pair, 3 bits
		r1=mk_regi(regv_dr_0+GetN(op)/2);
		break;

	case PRM_FVN:	//float quad, 2 bits
		r1=mk_regi(regv_fv_0+GetN(op)/4);
		break;

	case PRM_FVM:	//float quad, 2 bits
		r1=mk_regi(regv_fv_0+(GetN(op)&0x3));
		break;

	case PRM_XMTRX:	//float matrix, 0 bits
		r1=mk_regi(regv_xmtrx);
		break;

	case PRM_FRM_FR0:
		r1=mk_regi(reg_fr_0+GetM(op));
		r2=mk_regi(reg_fr_0);
		break;

	case PRM_SR_T:
		r1=mk_regi(reg_sr_T);
		break;

	case PRM_SR_STATUS:
		r1=mk_regi(reg_sr_status);
		break;

	case PRM_SREG:	//FPUL/FPSCR/MACH/MACL/PR/DBR/SGR
		r1=mk_regi(SREGS[GetM(op)]);
		break;
	case PRM_CREG:	//SR/GBR/VBR/SSR/SPC/<RM_BANK>
		r1=mk_regi(CREGS[GetM(op)]);
		break;
	
	//reg/imm reg/reg
	case PRM_RN_D4_x1:
	case PRM_RN_D4_x2:
	case PRM_RN_D4_x4:
		{
			u32 shft=p-PRM_RN_D4_x1;
			r1=mk_regi(reg_r0+GetN(op));
			r2=mk_imm(GetImm4(op)<<shft);
		}
		break;

	case PRM_RN_R0:
		r1=mk_regi(reg_r0+GetN(op));
		r2=mk_regi(reg_r0);
		break;

	case PRM_RM_D4_x1:
	case PRM_RM_D4_x2:
	case PRM_RM_D4_x4:
		{
			u32 shft=p-PRM_RM_D4_x1;
			r1=mk_regi(reg_r0+GetM(op));
			r2=mk_imm(GetImm4(op)<<shft);
		}
		break;

	case PRM_RM_R0:
		r1=mk_regi(reg_r0+GetM(op));
		r2=mk_regi(reg_r0);
		break;

	case PRM_GBR_D8_x1:
	case PRM_GBR_D8_x2:
	case PRM_GBR_D8_x4:
		{
			u32 shft=p-PRM_GBR_D8_x1;
			r1=mk_regi(reg_gbr);
			r2=mk_imm(GetImm8(op)<<shft);
		}
		break;

	default:
		die("Non-supported parameter used");
	}
}
예제 #16
0
shil_param mk_regi(int reg)
{
	return mk_reg((Sh4RegType)reg);
}
예제 #17
0
void dec_write_sr(shil_param src)
{
	Emit(shop_and,mk_reg(reg_sr_status),src,mk_imm(SR_STATUS_MASK));
	Emit(shop_and,mk_reg(reg_sr_T),src,mk_imm(SR_T_MASK));
}
예제 #18
0
bool dec_generic(u32 op)
{
	DecMode mode;DecParam d;DecParam s;shilop natop;u32 e;
	if (OpDesc[op]->decode==0)
		return false;
	
	u64 inf=OpDesc[op]->decode;

	e=(u32)(inf>>32);
	mode=(DecMode)((inf>>24)&0xFF);
	d=(DecParam)((inf>>16)&0xFF);
	s=(DecParam)((inf>>8)&0xFF);
	natop=(shilop)((inf>>0)&0xFF);

	/*
	if ((op&0xF00F)==0x300E)
	{
		return false;
	}*/

	/*
	if (mode==DM_ADC)
		return false;
	*/

	bool transfer_64=false;
	if (op>=0xF000)
	{
		state.info.has_fpu=true;
		//return false;//FPU off for now
		if (state.cpu.FPR64 /*|| state.cpu.FSZ64*/)
			return false;

		if (state.cpu.FSZ64 && (d==PRM_FRN_SZ || d==PRM_FRM_SZ || s==PRM_FRN_SZ || s==PRM_FRM_SZ))
		{
			transfer_64=true;
		}
	}

	shil_param rs1,rs2,rs3,rd;

	dec_param(s,rs2,rs3,op);
	dec_param(d,rs1,rs3,op);

	switch(mode)
	{
	case DM_ReadSRF:
		Emit(shop_mov32,rs1,reg_sr_status);
		Emit(shop_or,rs1,rs1,reg_sr_T);
		break;

	case DM_WriteTOp:
		Emit(natop,reg_sr_T,rs1,rs2);
		break;

	case DM_DT:
		verify(natop==shop_sub);
		Emit(natop,rs1,rs1,rs2);
		Emit(shop_seteq,mk_reg(reg_sr_T),rs1,mk_imm(0));
		break;

	case DM_Shift:
		if (natop==shop_shl && e==1)
			Emit(shop_shr,mk_reg(reg_sr_T),rs1,mk_imm(31));
		else if (e==1)
			Emit(shop_and,mk_reg(reg_sr_T),rs1,mk_imm(1));

		Emit(natop,rs1,rs1,mk_imm(e));
		break;

	case DM_Rot:
		if (!(((s32)e>=0?e:-e)&0x1000))
		{
			if ((s32)e<0)
			{
				//left rotate
				Emit(shop_shr,mk_reg(reg_sr_T),rs2,mk_imm(31));
				e=-e;
			}
			else
			{
				//right rotate
				Emit(shop_and,mk_reg(reg_sr_T),rs2,mk_imm(1));
			}
		}
		e&=31;

		Emit(natop,rs1,rs2,mk_imm(e));
		break;

	case DM_BinaryOp://d=d op s
		if (e&1)
			Emit(natop,rs1,rs1,rs2,0,rs3);
		else
			Emit(natop,shil_param(),rs1,rs2,0,rs3);
		break;

	case DM_UnaryOp: //d= op s
		if (transfer_64 && natop==shop_mov32) 
			natop=shop_mov64;

		if (natop==shop_cvt_i2f_n && state.cpu.RoundToZero)
			natop=shop_cvt_i2f_z;

		if (e&1)
			Emit(natop,shil_param(),rs1);
		else
			Emit(natop,rs1,rs2);
		break;

	case DM_WriteM: //write(d,s)
		{
			//0 has no effect, so get rid of it
			if (rs3.is_imm() && rs3._imm==0)
				rs3=shil_param();

			state.info.has_writem=true;
			if (transfer_64) e=(s32)e*2;
			bool update_after=false;
			if ((s32)e<0)
			{
				if (rs1._reg!=rs2._reg) //reg shouldn't be updated if its written
				{
					Emit(shop_sub,rs1,rs1,mk_imm(-e));
				}
				else
				{
					verify(rs3.is_null());
					rs3=mk_imm(e);
					update_after=true;
				}
			}

			Emit(shop_writem,shil_param(),rs1,rs2,(s32)e<0?-e:e,rs3);

			if (update_after)
			{
				Emit(shop_sub,rs1,rs1,mk_imm(-e));
			}
		}
		break;

	case DM_ReadM:
		//0 has no effect, so get rid of it
		if (rs3.is_imm() && rs3._imm==0)
				rs3=shil_param();

		state.info.has_readm=true;
		if (transfer_64) e=(s32)e*2;

		Emit(shop_readm,rs1,rs2,shil_param(),(s32)e<0?-e:e,rs3);
		if ((s32)e<0)
		{
			if (rs1._reg!=rs2._reg)//the reg shouldn't be updated if it was just read.
				Emit(shop_add,rs2,rs2,mk_imm(-e));
		}
		break;

	case DM_fiprOp:
		{
			shil_param rdd=mk_regi(rs1._reg+3);
			Emit(natop,rdd,rs1,rs2);
		}
		break;

	case DM_EXTOP:
		{
			Emit(natop,rs1,rs2,mk_imm(e==1?0xFF:0xFFFF));
		}
		break;
	
	case DM_MUL:
		{
			shilop op;
			shil_param rd=mk_reg(reg_macl);
			shil_param rd2=shil_param();

			switch((s32)e)
			{
				case 16:  op=shop_mul_u16; break;
				case -16: op=shop_mul_s16; break;

				case -32: op=shop_mul_i32; break;

				case 64:  op=shop_mul_u64; rd2 = mk_reg(reg_mach); break;
				case -64: op=shop_mul_s64; rd2 = mk_reg(reg_mach); break;

				default:
					die("DM_MUL: Failed to classify opcode");
			}

			Emit(op,rd,rs1,rs2,0,shil_param(),rd2);
		}
		break;

	case DM_DIV0:
		{
			if (e==1)
			{
				if (MatchDiv32u(op,state.cpu.rpc))
				{
					verify(!state.cpu.is_delayslot);
					//div32u
					Emit(shop_div32u,mk_reg(div_som_reg1),mk_reg(div_som_reg1),mk_reg(div_som_reg2),0,shil_param(),mk_reg(div_som_reg3));
					
					Emit(shop_and,mk_reg(reg_sr_T),mk_reg(div_som_reg1),mk_imm(1));
					Emit(shop_shr,mk_reg(div_som_reg1),mk_reg(div_som_reg1),mk_imm(1));

					Emit(shop_div32p2,mk_reg(div_som_reg3),mk_reg(div_som_reg3),mk_reg(div_som_reg2),0,shil_param(reg_sr_T));
					
					//skip the aggregated opcodes
					state.cpu.rpc+=128;
					blk->guest_cycles+=CPU_RATIO*64;
				}
				else
				{
					//clear QM (bits 8,9)
					u32 qm=(1<<8)|(1<<9);
					Emit(shop_and,mk_reg(reg_sr_status),mk_reg(reg_sr_status),mk_imm(~qm));
					//clear T !
					Emit(shop_mov32,mk_reg(reg_sr_T),mk_imm(0));
				}
			}
			else
			{
				if (MatchDiv32s(op,state.cpu.rpc))
				{
					verify(!state.cpu.is_delayslot);
					//div32s
					Emit(shop_div32s,mk_reg(div_som_reg1),mk_reg(div_som_reg1),mk_reg(div_som_reg2),0,shil_param(),mk_reg(div_som_reg3));
					
					Emit(shop_and,mk_reg(reg_sr_T),mk_reg(div_som_reg1),mk_imm(1));
					Emit(shop_sar,mk_reg(div_som_reg1),mk_reg(div_som_reg1),mk_imm(1));

					Emit(shop_div32p2,mk_reg(div_som_reg3),mk_reg(div_som_reg3),mk_reg(div_som_reg2),0,shil_param(reg_sr_T));
					
					//skip the aggregated opcodes
					state.cpu.rpc+=128;
					blk->guest_cycles+=CPU_RATIO*64;
				}
				else
				{
					//sr.Q=r[n]>>31;
					//sr.M=r[m]>>31;
					//sr.T=sr.M^sr.Q;

					//This is nasty because there isn't a temp reg ..
					//VERY NASTY

					//Clear Q & M
					Emit(shop_and,mk_reg(reg_sr_status),mk_reg(reg_sr_status),mk_imm(~((1<<8)|(1<<9))));

					//sr.Q=r[n]>>31;
					Emit(shop_sar,mk_reg(reg_sr_T),rs1,mk_imm(31));
					Emit(shop_and,mk_reg(reg_sr_T),mk_reg(reg_sr_T),mk_imm(1<<8));
					Emit(shop_or,mk_reg(reg_sr_status),mk_reg(reg_sr_status),mk_reg(reg_sr_T));

					//sr.M=r[m]>>31;
					Emit(shop_sar,mk_reg(reg_sr_T),rs2,mk_imm(31));
					Emit(shop_and,mk_reg(reg_sr_T),mk_reg(reg_sr_T),mk_imm(1<<9));
					Emit(shop_or,mk_reg(reg_sr_status),mk_reg(reg_sr_status),mk_reg(reg_sr_T));

					//sr.T=sr.M^sr.Q;
					Emit(shop_xor,mk_reg(reg_sr_T),rs1,rs2);
					Emit(shop_shr,mk_reg(reg_sr_T),mk_reg(reg_sr_T),mk_imm(31));
				}
			}
		}
		break;

	case DM_ADC:
		{
			Emit(natop,rs1,rs1,rs2,0,mk_reg(reg_sr_T),mk_reg(reg_sr_T));
		}
		break;

	default:
		verify(false);
	}

	return true;
}