aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Instructions
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2019-01-24 23:59:53 -0200
committerGitHub <noreply@github.com>2019-01-24 23:59:53 -0200
commit36b9ab0e48b6893c057a954e1ef3181b452add1c (patch)
tree16a4ae56019b55d0cb61f1aa105481933ada733e /ChocolArm64/Instructions
parent72157e03eb09d4fb5d6d004efc2d13d3194e8c90 (diff)
Add ARM32 support on the translator (#561)
* Remove ARM32 interpreter and add ARM32 support on the translator * Nits. * Rename Cond -> Condition * Align code again * Rename Data to Alu * Enable ARM32 support and handle undefined instructions * Use the IsThumb method to check if its a thumb opcode * Remove another 32-bits check
Diffstat (limited to 'ChocolArm64/Instructions')
-rw-r--r--ChocolArm64/Instructions/Inst.cs14
-rw-r--r--ChocolArm64/Instructions/InstEmit32Helper.cs99
-rw-r--r--ChocolArm64/Instructions/InstEmitAlu.cs107
-rw-r--r--ChocolArm64/Instructions/InstEmitAlu32.cs123
-rw-r--r--ChocolArm64/Instructions/InstEmitAluHelper.cs317
-rw-r--r--ChocolArm64/Instructions/InstEmitCcmp.cs2
-rw-r--r--ChocolArm64/Instructions/InstEmitFlow.cs36
-rw-r--r--ChocolArm64/Instructions/InstEmitFlow32.cs99
-rw-r--r--ChocolArm64/Instructions/InstEmitFlowHelper.cs39
-rw-r--r--ChocolArm64/Instructions/InstEmitSimdMemory.cs2
-rw-r--r--ChocolArm64/Instructions/InstInterpreter.cs8
11 files changed, 714 insertions, 132 deletions
diff --git a/ChocolArm64/Instructions/Inst.cs b/ChocolArm64/Instructions/Inst.cs
index 5f6740ca..de9ec18b 100644
--- a/ChocolArm64/Instructions/Inst.cs
+++ b/ChocolArm64/Instructions/Inst.cs
@@ -4,17 +4,15 @@ namespace ChocolArm64.Instructions
{
struct Inst
{
- public InstInterpreter Interpreter { get; private set; }
- public InstEmitter Emitter { get; private set; }
- public Type Type { get; private set; }
+ public InstEmitter Emitter { get; }
+ public Type Type { get; }
- public static Inst Undefined => new Inst(null, InstEmit.Und, null);
+ public static Inst Undefined => new Inst(InstEmit.Und, null);
- public Inst(InstInterpreter interpreter, InstEmitter emitter, Type type)
+ public Inst(InstEmitter emitter, Type type)
{
- Interpreter = interpreter;
- Emitter = emitter;
- Type = type;
+ Emitter = emitter;
+ Type = type;
}
}
} \ No newline at end of file
diff --git a/ChocolArm64/Instructions/InstEmit32Helper.cs b/ChocolArm64/Instructions/InstEmit32Helper.cs
new file mode 100644
index 00000000..d3ff8138
--- /dev/null
+++ b/ChocolArm64/Instructions/InstEmit32Helper.cs
@@ -0,0 +1,99 @@
+using ChocolArm64.Decoders;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System;
+
+namespace ChocolArm64.Instructions
+{
+ static class InstEmit32Helper
+ {
+ public static bool IsThumb(OpCode64 op)
+ {
+ return op is OpCodeT16;
+ }
+
+ public static void EmitLoadFromRegister(ILEmitterCtx context, int register)
+ {
+ if (register == RegisterAlias.Aarch32Pc)
+ {
+ OpCode32 op = (OpCode32)context.CurrOp;
+
+ context.EmitLdc_I4((int)op.GetPc());
+ }
+ else
+ {
+ context.EmitLdint(InstEmit32Helper.GetRegisterAlias(context.Mode, register));
+ }
+ }
+
+ public static int GetRegisterAlias(Aarch32Mode mode, int register)
+ {
+ //Only registers >= 8 are banked, with registers in the range [8, 12] being
+ //banked for the FIQ mode, and registers 13 and 14 being banked for all modes.
+ if ((uint)register < 8)
+ {
+ return register;
+ }
+
+ return GetBankedRegisterAlias(mode, register);
+ }
+
+ public static int GetBankedRegisterAlias(Aarch32Mode mode, int register)
+ {
+ switch (register)
+ {
+ case 8: return mode == Aarch32Mode.Fiq
+ ? RegisterAlias.R8Fiq
+ : RegisterAlias.R8Usr;
+
+ case 9: return mode == Aarch32Mode.Fiq
+ ? RegisterAlias.R9Fiq
+ : RegisterAlias.R9Usr;
+
+ case 10: return mode == Aarch32Mode.Fiq
+ ? RegisterAlias.R10Fiq
+ : RegisterAlias.R10Usr;
+
+ case 11: return mode == Aarch32Mode.Fiq
+ ? RegisterAlias.R11Fiq
+ : RegisterAlias.R11Usr;
+
+ case 12: return mode == Aarch32Mode.Fiq
+ ? RegisterAlias.R12Fiq
+ : RegisterAlias.R12Usr;
+
+ case 13:
+ switch (mode)
+ {
+ case Aarch32Mode.User:
+ case Aarch32Mode.System: return RegisterAlias.SpUsr;
+ case Aarch32Mode.Fiq: return RegisterAlias.SpFiq;
+ case Aarch32Mode.Irq: return RegisterAlias.SpIrq;
+ case Aarch32Mode.Supervisor: return RegisterAlias.SpSvc;
+ case Aarch32Mode.Abort: return RegisterAlias.SpAbt;
+ case Aarch32Mode.Hypervisor: return RegisterAlias.SpHyp;
+ case Aarch32Mode.Undefined: return RegisterAlias.SpUnd;
+
+ default: throw new ArgumentException(nameof(mode));
+ }
+
+ case 14:
+ switch (mode)
+ {
+ case Aarch32Mode.User:
+ case Aarch32Mode.Hypervisor:
+ case Aarch32Mode.System: return RegisterAlias.LrUsr;
+ case Aarch32Mode.Fiq: return RegisterAlias.LrFiq;
+ case Aarch32Mode.Irq: return RegisterAlias.LrIrq;
+ case Aarch32Mode.Supervisor: return RegisterAlias.LrSvc;
+ case Aarch32Mode.Abort: return RegisterAlias.LrAbt;
+ case Aarch32Mode.Undefined: return RegisterAlias.LrUnd;
+
+ default: throw new ArgumentException(nameof(mode));
+ }
+
+ default: throw new ArgumentOutOfRangeException(nameof(register));
+ }
+ }
+ }
+}
diff --git a/ChocolArm64/Instructions/InstEmitAlu.cs b/ChocolArm64/Instructions/InstEmitAlu.cs
index c0258ed2..d5d9cd65 100644
--- a/ChocolArm64/Instructions/InstEmitAlu.cs
+++ b/ChocolArm64/Instructions/InstEmitAlu.cs
@@ -17,7 +17,7 @@ namespace ChocolArm64.Instructions
private static void EmitAdc(ILEmitterCtx context, bool setFlags)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Add);
@@ -44,14 +44,14 @@ namespace ChocolArm64.Instructions
EmitAddsVCheck(context);
}
- EmitDataStore(context);
+ EmitAluStore(context);
}
- public static void Add(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Add);
+ public static void Add(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Add);
public static void Adds(ILEmitterCtx context)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Add);
@@ -59,14 +59,14 @@ namespace ChocolArm64.Instructions
EmitAddsCCheck(context);
EmitAddsVCheck(context);
- EmitDataStoreS(context);
+ EmitAluStoreS(context);
}
- public static void And(ILEmitterCtx context) => EmitDataOp(context, OpCodes.And);
+ public static void And(ILEmitterCtx context) => EmitAluOp(context, OpCodes.And);
public static void Ands(ILEmitterCtx context)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.And);
@@ -74,17 +74,17 @@ namespace ChocolArm64.Instructions
context.EmitZnFlagCheck();
- EmitDataStoreS(context);
+ EmitAluStoreS(context);
}
- public static void Asrv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shr);
+ public static void Asrv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shr);
public static void Bic(ILEmitterCtx context) => EmitBic(context, false);
public static void Bics(ILEmitterCtx context) => EmitBic(context, true);
private static void EmitBic(ILEmitterCtx context, bool setFlags)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Not);
context.Emit(OpCodes.And);
@@ -96,7 +96,7 @@ namespace ChocolArm64.Instructions
context.EmitZnFlagCheck();
}
- EmitDataStore(context, setFlags);
+ EmitAluStore(context, setFlags);
}
public static void Cls(ILEmitterCtx context)
@@ -136,15 +136,15 @@ namespace ChocolArm64.Instructions
public static void Eon(ILEmitterCtx context)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Not);
context.Emit(OpCodes.Xor);
- EmitDataStore(context);
+ EmitAluStore(context);
}
- public static void Eor(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Xor);
+ public static void Eor(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Xor);
public static void Extr(ILEmitterCtx context)
{
@@ -166,18 +166,18 @@ namespace ChocolArm64.Instructions
context.Emit(OpCodes.Or);
}
- EmitDataStore(context);
+ EmitAluStore(context);
}
- public static void Lslv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shl);
- public static void Lsrv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shr_Un);
+ public static void Lslv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shl);
+ public static void Lsrv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shr_Un);
public static void Sbc(ILEmitterCtx context) => EmitSbc(context, false);
public static void Sbcs(ILEmitterCtx context) => EmitSbc(context, true);
private static void EmitSbc(ILEmitterCtx context, bool setFlags)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Sub);
@@ -208,16 +208,16 @@ namespace ChocolArm64.Instructions
EmitSubsVCheck(context);
}
- EmitDataStore(context);
+ EmitAluStore(context);
}
- public static void Sub(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Sub);
+ public static void Sub(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Sub);
public static void Subs(ILEmitterCtx context)
{
context.TryOptMarkCondWithoutCmp();
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Sub);
@@ -225,20 +225,20 @@ namespace ChocolArm64.Instructions
EmitSubsCCheck(context);
EmitSubsVCheck(context);
- EmitDataStoreS(context);
+ EmitAluStoreS(context);
}
public static void Orn(ILEmitterCtx context)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Not);
context.Emit(OpCodes.Or);
- EmitDataStore(context);
+ EmitAluStore(context);
}
- public static void Orr(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Or);
+ public static void Orr(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Or);
public static void Rbit(ILEmitterCtx context) => EmitFallback32_64(context,
nameof(SoftFallback.ReverseBits32),
@@ -283,22 +283,22 @@ namespace ChocolArm64.Instructions
public static void Rorv(ILEmitterCtx context)
{
- EmitDataLoadRn(context);
- EmitDataLoadShift(context);
+ EmitAluLoadRn(context);
+ EmitAluLoadShift(context);
context.Emit(OpCodes.Shr_Un);
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.EmitLdc_I4(context.CurrOp.GetBitsCount());
- EmitDataLoadShift(context);
+ EmitAluLoadShift(context);
context.Emit(OpCodes.Sub);
context.Emit(OpCodes.Shl);
context.Emit(OpCodes.Or);
- EmitDataStore(context);
+ EmitAluStore(context);
}
public static void Sdiv(ILEmitterCtx context) => EmitDiv(context, OpCodes.Div);
@@ -309,7 +309,7 @@ namespace ChocolArm64.Instructions
//If Rm == 0, Rd = 0 (division by zero).
context.EmitLdc_I(0);
- EmitDataLoadRm(context);
+ EmitAluLoadRm(context);
context.EmitLdc_I(0);
@@ -325,13 +325,13 @@ namespace ChocolArm64.Instructions
context.EmitLdc_I(intMin);
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.EmitLdc_I(intMin);
context.Emit(OpCodes.Ceq);
- EmitDataLoadRm(context);
+ EmitAluLoadRm(context);
context.EmitLdc_I(-1);
@@ -341,38 +341,38 @@ namespace ChocolArm64.Instructions
context.Emit(OpCodes.Pop);
}
- EmitDataLoadRn(context);
- EmitDataLoadRm(context);
+ EmitAluLoadRn(context);
+ EmitAluLoadRm(context);
context.Emit(ilOp);
context.MarkLabel(badDiv);
- EmitDataStore(context);
+ EmitAluStore(context);
}
- private static void EmitDataOp(ILEmitterCtx context, OpCode ilOp)
+ private static void EmitAluOp(ILEmitterCtx context, OpCode ilOp)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(ilOp);
- EmitDataStore(context);
+ EmitAluStore(context);
}
- private static void EmitDataOpShift(ILEmitterCtx context, OpCode ilOp)
+ private static void EmitAluOpShift(ILEmitterCtx context, OpCode ilOp)
{
- EmitDataLoadRn(context);
- EmitDataLoadShift(context);
+ EmitAluLoadRn(context);
+ EmitAluLoadShift(context);
context.Emit(ilOp);
- EmitDataStore(context);
+ EmitAluStore(context);
}
- private static void EmitDataLoadShift(ILEmitterCtx context)
+ private static void EmitAluLoadShift(ILEmitterCtx context)
{
- EmitDataLoadRm(context);
+ EmitAluLoadRm(context);
context.EmitLdc_I(context.CurrOp.GetBitsCount() - 1);
@@ -398,5 +398,22 @@ namespace ChocolArm64.Instructions
context.EmitStflg((int)PState.CBit);
}
+
+ public static void EmitAluStore(ILEmitterCtx context) => EmitAluStore(context, false);
+ public static void EmitAluStoreS(ILEmitterCtx context) => EmitAluStore(context, true);
+
+ public static void EmitAluStore(ILEmitterCtx context, bool setFlags)
+ {
+ IOpCodeAlu64 op = (IOpCodeAlu64)context.CurrOp;
+
+ if (setFlags || op is IOpCodeAluRs64)
+ {
+ context.EmitStintzr(op.Rd);
+ }
+ else
+ {
+ context.EmitStint(op.Rd);
+ }
+ }
}
}
diff --git a/ChocolArm64/Instructions/InstEmitAlu32.cs b/ChocolArm64/Instructions/InstEmitAlu32.cs
new file mode 100644
index 00000000..2ebb8073
--- /dev/null
+++ b/ChocolArm64/Instructions/InstEmitAlu32.cs
@@ -0,0 +1,123 @@
+using ChocolArm64.Decoders;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instructions.InstEmit32Helper;
+using static ChocolArm64.Instructions.InstEmitAluHelper;
+
+namespace ChocolArm64.Instructions
+{
+ static partial class InstEmit32
+ {
+ public static void Add(ILEmitterCtx context)
+ {
+ IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
+
+ EmitAluLoadOpers(context, setCarry: false);
+
+ context.Emit(OpCodes.Add);
+
+ if (op.SetFlags)
+ {
+ context.EmitZnFlagCheck();
+
+ EmitAddsCCheck(context);
+ EmitAddsVCheck(context);
+ }
+
+ EmitAluStore(context);
+ }
+
+ public static void Mov(ILEmitterCtx context)
+ {
+ IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
+
+ EmitAluLoadOper2(context);
+
+ if (op.SetFlags)
+ {
+ context.EmitZnFlagCheck();
+ }
+
+ EmitAluStore(context);
+ }
+
+ public static void Sub(ILEmitterCtx context)
+ {
+ IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
+
+ EmitAluLoadOpers(context, setCarry: false);
+
+ context.Emit(OpCodes.Sub);
+
+ if (op.SetFlags)
+ {
+ context.EmitZnFlagCheck();
+
+ EmitSubsCCheck(context);
+ EmitSubsVCheck(context);
+ }
+
+ EmitAluStore(context);
+ }
+
+ private static void EmitAluStore(ILEmitterCtx context)
+ {
+ IOpCodeAlu32 op = (IOpCodeAlu32)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));
+ }
+ }
+
+ private static void EmitAluWritePc(ILEmitterCtx context)
+ {
+ if (IsThumb(context.CurrOp))
+ {
+ context.EmitLdc_I4(~1);
+
+ context.Emit(OpCodes.And);
+ context.Emit(OpCodes.Conv_U8);
+ context.Emit(OpCodes.Ret);
+ }
+ else
+ {
+ EmitBxWritePc(context);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Instructions/InstEmitAluHelper.cs b/ChocolArm64/Instructions/InstEmitAluHelper.cs
index 97c50564..db8fd0e5 100644
--- a/ChocolArm64/Instructions/InstEmitAluHelper.cs
+++ b/ChocolArm64/Instructions/InstEmitAluHelper.cs
@@ -1,6 +1,7 @@
using ChocolArm64.Decoders;
using ChocolArm64.State;
using ChocolArm64.Translation;
+using System;
using System.Reflection.Emit;
namespace ChocolArm64.Instructions
@@ -14,7 +15,7 @@ namespace ChocolArm64.Instructions
context.EmitLdtmp();
context.EmitLdtmp();
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.Emit(OpCodes.Ceq);
@@ -24,7 +25,7 @@ namespace ChocolArm64.Instructions
context.EmitLdtmp();
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.Emit(OpCodes.Clt_Un);
context.Emit(OpCodes.Or);
@@ -37,7 +38,7 @@ namespace ChocolArm64.Instructions
//C = Rd < Rn
context.Emit(OpCodes.Dup);
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.Emit(OpCodes.Clt_Un);
@@ -49,11 +50,11 @@ namespace ChocolArm64.Instructions
//V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0
context.Emit(OpCodes.Dup);
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.Emit(OpCodes.Xor);
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Xor);
context.Emit(OpCodes.Not);
@@ -69,7 +70,7 @@ namespace ChocolArm64.Instructions
public static void EmitSbcsCCheck(ILEmitterCtx context)
{
//C = (Rn == Rm && CIn) || Rn > Rm
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Ceq);
@@ -77,7 +78,7 @@ namespace ChocolArm64.Instructions
context.Emit(OpCodes.And);
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Cgt_Un);
context.Emit(OpCodes.Or);
@@ -88,7 +89,7 @@ namespace ChocolArm64.Instructions
public static void EmitSubsCCheck(ILEmitterCtx context)
{
//C = Rn == Rm || Rn > Rm = !(Rn < Rm)
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Clt_Un);
@@ -104,11 +105,11 @@ namespace ChocolArm64.Instructions
//V = (Rd ^ Rn) & (Rn ^ Rm) < 0
context.Emit(OpCodes.Dup);
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.Emit(OpCodes.Xor);
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Xor);
context.Emit(OpCodes.And);
@@ -120,35 +121,76 @@ namespace ChocolArm64.Instructions
context.EmitStflg((int)PState.VBit);
}
- public static void EmitDataLoadRm(ILEmitterCtx context)
+ public static void EmitAluLoadRm(ILEmitterCtx context)
{
- context.EmitLdintzr(((IOpCodeAluRs64)context.CurrOp).Rm);
+ if (context.CurrOp is IOpCodeAluRs64 op)
+ {
+ context.EmitLdintzr(op.Rm);
+ }
+ else if (context.CurrOp is OpCodeAluRsImm32 op32)
+ {
+ InstEmit32Helper.EmitLoadFromRegister(context, op32.Rm);
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
}
- public static void EmitDataLoadOpers(ILEmitterCtx context)
+ public static void EmitAluLoadOpers(ILEmitterCtx context, bool setCarry = true)
{
- EmitDataLoadRn(context);
- EmitDataLoadOper2(context);
+ EmitAluLoadRn(context);
+ EmitAluLoadOper2(context, setCarry);
}
- public static void EmitDataLoadRn(ILEmitterCtx context)
+ public static void EmitAluLoadRn(ILEmitterCtx context)
{
- IOpCodeAlu64 op = (IOpCodeAlu64)context.CurrOp;
-
- if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs64)
+ if (context.CurrOp is IOpCodeAlu64 op)
{
- context.EmitLdintzr(op.Rn);
+ if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs64)
+ {
+ context.EmitLdintzr(op.Rn);
+ }
+ else
+ {
+ context.EmitLdint(op.Rn);
+ }
+ }
+ else if (context.CurrOp is IOpCodeAlu32 op32)
+ {
+ InstEmit32Helper.EmitLoadFromRegister(context, op32.Rn);
}
else
{
- context.EmitLdint(op.Rn);
+ throw new InvalidOperationException();
}
}
- public static void EmitDataLoadOper2(ILEmitterCtx context)
+ public static void EmitAluLoadOper2(ILEmitterCtx context, bool setCarry = true)
{
switch (context.CurrOp)
{
+ //ARM32.
+ case OpCodeAluImm32 op:
+ context.EmitLdc_I4(op.Imm);
+
+ if (op.SetFlags && op.IsRotated)
+ {
+ context.EmitLdc_I4((int)((uint)op.Imm >> 31));
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ break;
+
+ case OpCodeAluRsImm32 op:
+ EmitLoadRmShiftedByImmediate(context, op, setCarry);
+ break;
+
+ case OpCodeAluImm8T16 op:
+ context.EmitLdc_I4(op.Imm);
+ break;
+
+ //ARM64.
case IOpCodeAluImm64 op:
context.EmitLdc_I(op.Imm);
break;
@@ -170,23 +212,8 @@ namespace ChocolArm64.Instructions
context.EmitCast(op.IntType);
context.EmitLsl(op.Shift);
break;
- }
- }
- public static void EmitDataStore(ILEmitterCtx context) => EmitDataStore(context, false);
- public static void EmitDataStoreS(ILEmitterCtx context) => EmitDataStore(context, true);
-
- public static void EmitDataStore(ILEmitterCtx context, bool setFlags)
- {
- IOpCodeAlu64 op = (IOpCodeAlu64)context.CurrOp;
-
- if (setFlags || op is IOpCodeAluRs64)
- {
- context.EmitStintzr(op.Rd);
- }
- else
- {
- context.EmitStint(op.Rd);
+ default: throw new InvalidOperationException();
}
}
@@ -217,5 +244,219 @@ namespace ChocolArm64.Instructions
context.Emit(OpCodes.And);
context.EmitStflg((int)PState.NBit);
}
+
+ //ARM32 helpers.
+ private static void EmitLoadRmShiftedByImmediate(ILEmitterCtx context, OpCodeAluRsImm32 op, bool setCarry)
+ {
+ int shift = op.Imm;
+
+ if (shift == 0)
+ {
+ switch (op.ShiftType)
+ {
+ case ShiftType.Lsr: shift = 32; break;
+ case ShiftType.Asr: shift = 32; break;
+ case ShiftType.Ror: shift = 1; break;
+ }
+ }
+
+ context.EmitLdint(op.Rm);
+
+ if (shift != 0)
+ {
+ setCarry &= op.SetFlags;
+
+ switch (op.ShiftType)
+ {
+ case ShiftType.Lsl: EmitLslC(context, setCarry, shift); break;
+ case ShiftType.Lsr: EmitLsrC(context, setCarry, shift); break;
+ case ShiftType.Asr: EmitAsrC(context, setCarry, shift); break;
+ case ShiftType.Ror:
+ if (op.Imm != 0)
+ {
+ EmitRorC(context, setCarry, shift);
+ }
+ else
+ {
+ EmitRrxC(context, setCarry);
+ }
+ break;
+ }
+ }
+ }
+
+ private static void EmitLslC(ILEmitterCtx context, bool setCarry, int shift)
+ {
+ if ((uint)shift > 32)
+ {
+ EmitShiftByMoreThan32(context, setCarry);
+ }
+ else if (shift == 32)
+ {
+ if (setCarry)
+ {
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ else
+ {
+ context.Emit(OpCodes.Pop);
+ }
+
+ context.EmitLdc_I4(0);
+ }
+ else
+ {
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLsr(32 - shift);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+
+ context.EmitLsl(shift);
+ }
+ }
+
+ private static void EmitLsrC(ILEmitterCtx context, bool setCarry, int shift)
+ {
+ if ((uint)shift > 32)
+ {
+ EmitShiftByMoreThan32(context, setCarry);
+ }
+ else if (shift == 32)
+ {
+ if (setCarry)
+ {
+ context.EmitLsr(31);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ else
+ {
+ context.Emit(OpCodes.Pop);
+ }
+
+ context.EmitLdc_I4(0);
+ }
+ else
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLsr(shift - 1);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.CBit);
+
+ context.EmitLsr(shift);
+ }
+ }
+
+ private static void EmitShiftByMoreThan32(ILEmitterCtx context, bool setCarry)
+ {
+ context.Emit(OpCodes.Pop);
+
+ context.EmitLdc_I4(0);
+
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ }
+
+ private static void EmitAsrC(ILEmitterCtx context, bool setCarry, int shift)
+ {
+ if ((uint)shift >= 32)
+ {
+ context.EmitAsr(31);
+
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ }
+ else
+ {
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLsr(shift - 1);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+
+ context.EmitAsr(shift);
+ }
+ }
+
+ private static void EmitRorC(ILEmitterCtx context, bool setCarry, int shift)
+ {
+ shift &= 0x1f;
+
+ context.EmitRor(shift);
+
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLsr(31);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ }
+
+ 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);
+ }
+ }
}
}
diff --git a/ChocolArm64/Instructions/InstEmitCcmp.cs b/ChocolArm64/Instructions/InstEmitCcmp.cs
index b91104c9..714ae06a 100644
--- a/ChocolArm64/Instructions/InstEmitCcmp.cs
+++ b/ChocolArm64/Instructions/InstEmitCcmp.cs
@@ -48,7 +48,7 @@ namespace ChocolArm64.Instructions
context.MarkLabel(lblTrue);
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
if (cmpOp == CcmpOp.Cmp)
{
diff --git a/ChocolArm64/Instructions/InstEmitFlow.cs b/ChocolArm64/Instructions/InstEmitFlow.cs
index 758bf212..181c6a04 100644
--- a/ChocolArm64/Instructions/InstEmitFlow.cs
+++ b/ChocolArm64/Instructions/InstEmitFlow.cs
@@ -36,36 +36,10 @@ namespace ChocolArm64.Instructions
OpCodeBImmAl64 op = (OpCodeBImmAl64)context.CurrOp;
context.EmitLdc_I(op.Position + 4);
- context.EmitStint(CpuThreadState.LrIndex);
+ context.EmitStint(RegisterAlias.Lr);
context.EmitStoreState();
- if (context.TryOptEmitSubroutineCall())
- {
- //Note: the return value of the called method will be placed
- //at the Stack, the return value is always a Int64 with the
- //return address of the function. We check if the address is
- //correct, if it isn't we keep returning until we reach the dispatcher.
- context.Emit(OpCodes.Dup);
-
- context.EmitLdc_I8(op.Position + 4);
-
- ILLabel lblContinue = new ILLabel();
-
- context.Emit(OpCodes.Beq_S, lblContinue);
- context.Emit(OpCodes.Ret);
-
- context.MarkLabel(lblContinue);
-
- context.Emit(OpCodes.Pop);
-
- context.EmitLoadState();
- }
- else
- {
- context.EmitLdc_I8(op.Imm);
-
- context.Emit(OpCodes.Ret);
- }
+ InstEmitFlowHelper.EmitCall(context, op.Imm);
}
public static void Blr(ILEmitterCtx context)
@@ -74,7 +48,7 @@ namespace ChocolArm64.Instructions
context.EmitLdintzr(op.Rn);
context.EmitLdc_I(op.Position + 4);
- context.EmitStint(CpuThreadState.LrIndex);
+ context.EmitStint(RegisterAlias.Lr);
context.EmitStoreState();
context.Emit(OpCodes.Ret);
@@ -106,7 +80,7 @@ namespace ChocolArm64.Instructions
public static void Ret(ILEmitterCtx context)
{
context.EmitStoreState();
- context.EmitLdint(CpuThreadState.LrIndex);
+ context.EmitLdint(RegisterAlias.Lr);
context.Emit(OpCodes.Ret);
}
@@ -128,7 +102,7 @@ namespace ChocolArm64.Instructions
EmitBranch(context, ilOp);
}
- private static void EmitBranch(ILEmitterCtx context, Cond cond)
+ private static void EmitBranch(ILEmitterCtx context, Condition cond)
{
OpCodeBImm64 op = (OpCodeBImm64)context.CurrOp;
diff --git a/ChocolArm64/Instructions/InstEmitFlow32.cs b/ChocolArm64/Instructions/InstEmitFlow32.cs
new file mode 100644
index 00000000..03b39936
--- /dev/null
+++ b/ChocolArm64/Instructions/InstEmitFlow32.cs
@@ -0,0 +1,99 @@
+using ChocolArm64.Decoders;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instructions.InstEmit32Helper;
+
+namespace ChocolArm64.Instructions
+{
+ static partial class InstEmit32
+ {
+ public static void B(ILEmitterCtx context)
+ {
+ IOpCodeBImm32 op = (IOpCodeBImm32)context.CurrOp;
+
+ if (context.CurrBlock.Branch != null)
+ {
+ context.Emit(OpCodes.Br, context.GetLabel(op.Imm));
+ }
+ else
+ {
+ context.EmitStoreState();
+ context.EmitLdc_I8(op.Imm);
+
+ context.Emit(OpCodes.Ret);
+ }
+ }
+
+ public static void Bl(ILEmitterCtx context)
+ {
+ Blx(context, x: false);
+ }
+
+ public static void Blx(ILEmitterCtx context)
+ {
+ Blx(context, x: true);
+ }
+
+ public static void Bx(ILEmitterCtx context)
+ {
+ IOpCodeBReg32 op = (IOpCodeBReg32)context.CurrOp;
+
+ context.EmitStoreState();
+
+ EmitLoadFromRegister(context, op.Rm);
+
+ EmitBxWritePc(context);
+ }
+
+ private static void Blx(ILEmitterCtx context, bool x)
+ {
+ IOpCodeBImm32 op = (IOpCodeBImm32)context.CurrOp;
+
+ uint pc = op.GetPc();
+
+ bool isThumb = IsThumb(context.CurrOp);
+
+ if (!isThumb)
+ {
+ context.EmitLdc_I(op.GetPc() - 4);
+ }
+ else
+ {
+ context.EmitLdc_I(op.GetPc() | 1);
+ }
+
+ context.EmitStint(GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr));
+ context.EmitStoreState();
+
+ //If x is true, then this is a branch with link and exchange.
+ //In this case we need to swap the mode between Arm <-> Thumb.
+ if (x)
+ {
+ context.EmitLdc_I4(isThumb ? 0 : 1);
+
+ context.EmitStflg((int)PState.TBit);
+ }
+
+ InstEmitFlowHelper.EmitCall(context, op.Imm);
+ }
+
+ private static void EmitBxWritePc(ILEmitterCtx context)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.TBit);
+
+ context.EmitLdc_I4(~1);
+
+ context.Emit(OpCodes.And);
+ context.Emit(OpCodes.Conv_U8);
+ context.Emit(OpCodes.Ret);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Instructions/InstEmitFlowHelper.cs b/ChocolArm64/Instructions/InstEmitFlowHelper.cs
new file mode 100644
index 00000000..cf093bb3
--- /dev/null
+++ b/ChocolArm64/Instructions/InstEmitFlowHelper.cs
@@ -0,0 +1,39 @@
+using ChocolArm64.Translation;
+using System.Reflection.Emit;
+
+namespace ChocolArm64.Instructions
+{
+ static class InstEmitFlowHelper
+ {
+ public static void EmitCall(ILEmitterCtx context, long imm)
+ {
+ if (context.TryOptEmitSubroutineCall())
+ {
+ //Note: the return value of the called method will be placed
+ //at the Stack, the return value is always a Int64 with the
+ //return address of the function. We check if the address is
+ //correct, if it isn't we keep returning until we reach the dispatcher.
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLdc_I8(context.CurrOp.Position + 4);
+
+ ILLabel lblContinue = new ILLabel();
+
+ context.Emit(OpCodes.Beq_S, lblContinue);
+ context.Emit(OpCodes.Ret);
+
+ context.MarkLabel(lblContinue);
+
+ context.Emit(OpCodes.Pop);
+
+ context.EmitLoadState();
+ }
+ else
+ {
+ context.EmitLdc_I8(imm);
+
+ context.Emit(OpCodes.Ret);
+ }
+ }
+ }
+}
diff --git a/ChocolArm64/Instructions/InstEmitSimdMemory.cs b/ChocolArm64/Instructions/InstEmitSimdMemory.cs
index eb053257..9b84eb86 100644
--- a/ChocolArm64/Instructions/InstEmitSimdMemory.cs
+++ b/ChocolArm64/Instructions/InstEmitSimdMemory.cs
@@ -168,7 +168,7 @@ namespace ChocolArm64.Instructions
context.EmitLdint(op.Rn);
- if (op.Rm != CpuThreadState.ZrIndex)
+ if (op.Rm != RegisterAlias.Zr)
{
context.EmitLdint(op.Rm);
}
diff --git a/ChocolArm64/Instructions/InstInterpreter.cs b/ChocolArm64/Instructions/InstInterpreter.cs
deleted file mode 100644
index e6354fd5..00000000
--- a/ChocolArm64/Instructions/InstInterpreter.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using ChocolArm64.Decoders;
-using ChocolArm64.Memory;
-using ChocolArm64.State;
-
-namespace ChocolArm64.Instructions
-{
- delegate void InstInterpreter(CpuThreadState state, MemoryManager memory, OpCode64 opCode);
-} \ No newline at end of file