diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2019-01-24 23:59:53 -0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-01-24 23:59:53 -0200 |
| commit | 36b9ab0e48b6893c057a954e1ef3181b452add1c (patch) | |
| tree | 16a4ae56019b55d0cb61f1aa105481933ada733e /ChocolArm64/Instructions | |
| parent | 72157e03eb09d4fb5d6d004efc2d13d3194e8c90 (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.cs | 14 | ||||
| -rw-r--r-- | ChocolArm64/Instructions/InstEmit32Helper.cs | 99 | ||||
| -rw-r--r-- | ChocolArm64/Instructions/InstEmitAlu.cs | 107 | ||||
| -rw-r--r-- | ChocolArm64/Instructions/InstEmitAlu32.cs | 123 | ||||
| -rw-r--r-- | ChocolArm64/Instructions/InstEmitAluHelper.cs | 317 | ||||
| -rw-r--r-- | ChocolArm64/Instructions/InstEmitCcmp.cs | 2 | ||||
| -rw-r--r-- | ChocolArm64/Instructions/InstEmitFlow.cs | 36 | ||||
| -rw-r--r-- | ChocolArm64/Instructions/InstEmitFlow32.cs | 99 | ||||
| -rw-r--r-- | ChocolArm64/Instructions/InstEmitFlowHelper.cs | 39 | ||||
| -rw-r--r-- | ChocolArm64/Instructions/InstEmitSimdMemory.cs | 2 | ||||
| -rw-r--r-- | ChocolArm64/Instructions/InstInterpreter.cs | 8 |
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 |
