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
This commit is contained in:
parent
72157e03eb
commit
36b9ab0e48
57 changed files with 1274 additions and 495 deletions
|
@ -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);
|
||||
}
|
||||
|
||||
public static void EmitDataLoadOpers(ILEmitterCtx context)
|
||||
{
|
||||
EmitDataLoadRn(context);
|
||||
EmitDataLoadOper2(context);
|
||||
}
|
||||
|
||||
public static void EmitDataLoadRn(ILEmitterCtx context)
|
||||
{
|
||||
IOpCodeAlu64 op = (IOpCodeAlu64)context.CurrOp;
|
||||
|
||||
if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs64)
|
||||
if (context.CurrOp is IOpCodeAluRs64 op)
|
||||
{
|
||||
context.EmitLdintzr(op.Rn);
|
||||
context.EmitLdintzr(op.Rm);
|
||||
}
|
||||
else if (context.CurrOp is OpCodeAluRsImm32 op32)
|
||||
{
|
||||
InstEmit32Helper.EmitLoadFromRegister(context, op32.Rm);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.EmitLdint(op.Rn);
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitDataLoadOper2(ILEmitterCtx context)
|
||||
public static void EmitAluLoadOpers(ILEmitterCtx context, bool setCarry = true)
|
||||
{
|
||||
EmitAluLoadRn(context);
|
||||
EmitAluLoadOper2(context, setCarry);
|
||||
}
|
||||
|
||||
public static void EmitAluLoadRn(ILEmitterCtx context)
|
||||
{
|
||||
if (context.CurrOp is IOpCodeAlu64 op)
|
||||
{
|
||||
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
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue