aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Instruction/AInstEmitAluHelper.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ChocolArm64/Instruction/AInstEmitAluHelper.cs')
-rw-r--r--ChocolArm64/Instruction/AInstEmitAluHelper.cs168
1 files changed, 168 insertions, 0 deletions
diff --git a/ChocolArm64/Instruction/AInstEmitAluHelper.cs b/ChocolArm64/Instruction/AInstEmitAluHelper.cs
new file mode 100644
index 00000000..e848742d
--- /dev/null
+++ b/ChocolArm64/Instruction/AInstEmitAluHelper.cs
@@ -0,0 +1,168 @@
+using ChocolArm64.Decoder;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System.Reflection.Emit;
+
+namespace ChocolArm64.Instruction
+{
+ static class AInstEmitAluHelper
+ {
+ public static void EmitAddsCCheck(AILEmitterCtx Context)
+ {
+ //C = Rd < Rn
+ Context.Emit(OpCodes.Dup);
+
+ EmitDataLoadRn(Context);
+
+ Context.Emit(OpCodes.Clt_Un);
+
+ Context.EmitStflg((int)APState.CBit);
+ }
+
+ public static void EmitAddsVCheck(AILEmitterCtx Context)
+ {
+ //V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0
+ Context.Emit(OpCodes.Dup);
+
+ EmitDataLoadRn(Context);
+
+ Context.Emit(OpCodes.Xor);
+
+ EmitDataLoadOpers(Context);
+
+ Context.Emit(OpCodes.Xor);
+ Context.Emit(OpCodes.Not);
+ Context.Emit(OpCodes.And);
+
+ Context.EmitLdc_I(0);
+
+ Context.Emit(OpCodes.Clt);
+
+ Context.EmitStflg((int)APState.VBit);
+ }
+
+ public static void EmitSubsCCheck(AILEmitterCtx Context)
+ {
+ //C = Rn == Rm || Rn > Rm = !(Rn < Rm)
+ EmitDataLoadOpers(Context);
+
+ Context.Emit(OpCodes.Clt_Un);
+
+ Context.EmitLdc_I4(1);
+
+ Context.Emit(OpCodes.Xor);
+
+ Context.EmitStflg((int)APState.CBit);
+ }
+
+ public static void EmitSubsVCheck(AILEmitterCtx Context)
+ {
+ //V = (Rd ^ Rn) & (Rn ^ Rm) < 0
+ Context.Emit(OpCodes.Dup);
+
+ EmitDataLoadRn(Context);
+
+ Context.Emit(OpCodes.Xor);
+
+ EmitDataLoadOpers(Context);
+
+ Context.Emit(OpCodes.Xor);
+ Context.Emit(OpCodes.And);
+
+ Context.EmitLdc_I(0);
+
+ Context.Emit(OpCodes.Clt);
+
+ Context.EmitStflg((int)APState.VBit);
+ }
+
+ public static void EmitDataLoadRm(AILEmitterCtx Context)
+ {
+ Context.EmitLdintzr(((IAOpCodeAluRs)Context.CurrOp).Rm);
+ }
+
+ public static void EmitDataLoadOpers(AILEmitterCtx Context)
+ {
+ EmitDataLoadRn(Context);
+ EmitDataLoadOper2(Context);
+ }
+
+ public static void EmitDataLoadRn(AILEmitterCtx Context)
+ {
+ IAOpCodeAlu Op = (IAOpCodeAlu)Context.CurrOp;
+
+ if (Op.DataOp == ADataOp.Logical || Op is IAOpCodeAluRs)
+ {
+ Context.EmitLdintzr(Op.Rn);
+ }
+ else
+ {
+ Context.EmitLdint(Op.Rn);
+ }
+ }
+
+ public static void EmitDataLoadOper2(AILEmitterCtx Context)
+ {
+ switch (Context.CurrOp)
+ {
+ case IAOpCodeAluImm Op:
+ Context.EmitLdc_I(Op.Imm);
+ break;
+
+ case IAOpCodeAluRs Op:
+ Context.EmitLdintzr(Op.Rm);
+
+ switch (Op.ShiftType)
+ {
+ case AShiftType.Lsl: Context.EmitLsl(Op.Shift); break;
+ case AShiftType.Lsr: Context.EmitLsr(Op.Shift); break;
+ case AShiftType.Asr: Context.EmitAsr(Op.Shift); break;
+ case AShiftType.Ror: Context.EmitRor(Op.Shift); break;
+ }
+ break;
+
+ case IAOpCodeAluRx Op:
+ Context.EmitLdintzr(Op.Rm);
+ Context.EmitCast(Op.IntType);
+ Context.EmitLsl(Op.Shift);
+ break;
+ }
+ }
+
+ public static void EmitDataStore(AILEmitterCtx Context) => EmitDataStore(Context, false);
+ public static void EmitDataStoreS(AILEmitterCtx Context) => EmitDataStore(Context, true);
+
+ public static void EmitDataStore(AILEmitterCtx Context, bool SetFlags)
+ {
+ IAOpCodeAlu Op = (IAOpCodeAlu)Context.CurrOp;
+
+ if (SetFlags || Op is IAOpCodeAluRs)
+ {
+ Context.EmitStintzr(Op.Rd);
+ }
+ else
+ {
+ Context.EmitStint(Op.Rd);
+ }
+ }
+
+ public static void EmitSetNZCV(AILEmitterCtx Context, int NZCV)
+ {
+ Context.EmitLdc_I4((NZCV >> 0) & 1);
+
+ Context.EmitStflg((int)APState.VBit);
+
+ Context.EmitLdc_I4((NZCV >> 1) & 1);
+
+ Context.EmitStflg((int)APState.CBit);
+
+ Context.EmitLdc_I4((NZCV >> 2) & 1);
+
+ Context.EmitStflg((int)APState.ZBit);
+
+ Context.EmitLdc_I4((NZCV >> 3) & 1);
+
+ Context.EmitStflg((int)APState.NBit);
+ }
+ }
+} \ No newline at end of file