private static void EmitSbc(ILEmitterCtx context, bool setFlags) { EmitAluLoadOpers(context); context.Emit(OpCodes.Sub); context.EmitLdflg((int)PState.CBit); Type[] mthdTypes = new Type[] { typeof(bool) }; MethodInfo mthdInfo = typeof(Convert).GetMethod(nameof(Convert.ToInt32), mthdTypes); context.EmitCall(mthdInfo); context.EmitLdc_I4(1); context.Emit(OpCodes.Xor); if (context.CurrOp.RegisterSize != RegisterSize.Int32) { context.Emit(OpCodes.Conv_U8); } context.Emit(OpCodes.Sub); if (setFlags) { context.EmitZnFlagCheck(); EmitSbcsCCheck(context); EmitSubsVCheck(context); } EmitAluStore(context); }
private static void EmitRrxC(ILEmitterCtx context, bool setCarry) { // Rotate right by 1 with carry. if (setCarry) { context.Emit(OpCodes.Dup); context.EmitLdc_I4(1); context.Emit(OpCodes.And); context.EmitSttmp(); } context.EmitLsr(1); context.EmitLdflg((int)PState.CBit); context.EmitLsl(31); context.Emit(OpCodes.Or); if (setCarry) { context.EmitLdtmp(); context.EmitStflg((int)PState.CBit); } }
public static void EmitSbcsCCheck(ILEmitterCtx context) { // C = (Rn == Rm && CIn) || Rn > Rm EmitAluLoadOpers(context); context.Emit(OpCodes.Ceq); context.EmitLdflg((int)PState.CBit); context.Emit(OpCodes.And); EmitAluLoadOpers(context); context.Emit(OpCodes.Cgt_Un); context.Emit(OpCodes.Or); context.EmitStflg((int)PState.CBit); }
private static void EmitAluStore(ILEmitterCtx context) { IOpCode32Alu op = (IOpCode32Alu)context.CurrOp; if (op.Rd == RegisterAlias.Aarch32Pc) { if (op.SetFlags) { // TODO: Load SPSR etc. context.EmitLdflg((int)PState.TBit); ILLabel lblThumb = new ILLabel(); ILLabel lblEnd = new ILLabel(); context.Emit(OpCodes.Brtrue_S, lblThumb); context.EmitLdc_I4(~3); context.Emit(OpCodes.Br_S, lblEnd); context.MarkLabel(lblThumb); context.EmitLdc_I4(~1); context.MarkLabel(lblEnd); context.Emit(OpCodes.And); context.Emit(OpCodes.Conv_U8); context.Emit(OpCodes.Ret); } else { EmitAluWritePc(context); } } else { context.EmitStint(GetRegisterAlias(context.Mode, op.Rd)); } }
public static void EmitAdcsCCheck(ILEmitterCtx context) { // C = (Rd == Rn && CIn) || Rd < Rn context.EmitSttmp(); context.EmitLdtmp(); context.EmitLdtmp(); EmitAluLoadRn(context); context.Emit(OpCodes.Ceq); context.EmitLdflg((int)PState.CBit); context.Emit(OpCodes.And); context.EmitLdtmp(); EmitAluLoadRn(context); context.Emit(OpCodes.Clt_Un); context.Emit(OpCodes.Or); context.EmitStflg((int)PState.CBit); }
private static void EmitLoadOrStore(ILEmitterCtx context, int size, AccessType accType) { OpCode32Mem op = (OpCode32Mem)context.CurrOp; if (op.Index || op.WBack) { EmitLoadFromRegister(context, op.Rn); context.EmitLdc_I4(op.Imm); context.Emit(op.Add ? OpCodes.Add : OpCodes.Sub); context.EmitSttmp(); } if (op.Index) { context.EmitLdtmp(); } else { EmitLoadFromRegister(context, op.Rn); } if ((accType & AccessType.Load) != 0) { if ((accType & AccessType.Signed) != 0) { EmitReadSx32Call(context, size); } else { EmitReadZxCall(context, size); } if (op.WBack) { context.EmitLdtmp(); EmitStoreToRegister(context, op.Rn); } if (size == DWordSizeLog2) { context.Emit(OpCodes.Dup); context.EmitLdflg((int)PState.EBit); ILLabel lblBigEndian = new ILLabel(); ILLabel lblEnd = new ILLabel(); context.Emit(OpCodes.Brtrue_S, lblBigEndian); //Little endian mode. context.Emit(OpCodes.Conv_U4); EmitStoreToRegister(context, op.Rt); context.EmitLsr(32); context.Emit(OpCodes.Conv_U4); EmitStoreToRegister(context, op.Rt | 1); context.Emit(OpCodes.Br_S, lblEnd); //Big endian mode. context.MarkLabel(lblBigEndian); context.EmitLsr(32); context.Emit(OpCodes.Conv_U4); EmitStoreToRegister(context, op.Rt); context.Emit(OpCodes.Conv_U4); EmitStoreToRegister(context, op.Rt | 1); context.MarkLabel(lblEnd); } else { EmitStoreToRegister(context, op.Rt); } } else { if (op.WBack) { context.EmitLdtmp(); EmitStoreToRegister(context, op.Rn); } EmitLoadFromRegister(context, op.Rt); if (size == DWordSizeLog2) { context.Emit(OpCodes.Conv_U8); context.EmitLdflg((int)PState.EBit); ILLabel lblBigEndian = new ILLabel(); ILLabel lblEnd = new ILLabel(); context.Emit(OpCodes.Brtrue_S, lblBigEndian); //Little endian mode. EmitLoadFromRegister(context, op.Rt | 1); context.Emit(OpCodes.Conv_U8); context.EmitLsl(32); context.Emit(OpCodes.Or); context.Emit(OpCodes.Br_S, lblEnd); //Big endian mode. context.MarkLabel(lblBigEndian); context.EmitLsl(32); EmitLoadFromRegister(context, op.Rt | 1); context.Emit(OpCodes.Conv_U8); context.Emit(OpCodes.Or); context.MarkLabel(lblEnd); } EmitWriteCall(context, size); } }