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:
gdkchan 2019-01-24 23:59:53 -02:00 committed by GitHub
parent 72157e03eb
commit 36b9ab0e48
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 1274 additions and 495 deletions

View file

@ -19,20 +19,20 @@ namespace ChocolArm64.Decoders
_opActivators = new ConcurrentDictionary<Type, OpActivator>();
}
public static Block DecodeBasicBlock(CpuThreadState state, MemoryManager memory, long start)
public static Block DecodeBasicBlock(MemoryManager memory, long start, ExecutionMode mode)
{
Block block = new Block(start);
FillBlock(state, memory, block);
FillBlock(memory, mode, block);
return block;
}
public static Block DecodeSubroutine(
TranslatorCache cache,
CpuThreadState state,
MemoryManager memory,
long start)
long start,
ExecutionMode mode)
{
Dictionary<long, Block> visited = new Dictionary<long, Block>();
Dictionary<long, Block> visitedEnd = new Dictionary<long, Block>();
@ -59,7 +59,7 @@ namespace ChocolArm64.Decoders
{
Block current = blocks.Dequeue();
FillBlock(state, memory, current);
FillBlock(memory, mode, current);
//Set child blocks. "Branch" is the block the branch instruction
//points to (when taken), "Next" is the block at the next address,
@ -71,7 +71,7 @@ namespace ChocolArm64.Decoders
OpCode64 lastOp = current.GetLastOp();
if (lastOp is OpCodeBImm64 op)
if (lastOp is IOpCodeBImm op)
{
if (op.Emitter == InstEmit.Bl)
{
@ -83,8 +83,7 @@ namespace ChocolArm64.Decoders
}
}
if (!((lastOp is OpCodeBImmAl64) ||
(lastOp is OpCodeBReg64)) || hasCachedSub)
if (!IsUnconditionalBranch(lastOp) || hasCachedSub)
{
current.Next = Enqueue(current.EndPosition);
}
@ -121,7 +120,7 @@ namespace ChocolArm64.Decoders
return entry;
}
private static void FillBlock(CpuThreadState state, MemoryManager memory, Block block)
private static void FillBlock(MemoryManager memory, ExecutionMode mode, Block block)
{
long position = block.Position;
@ -129,13 +128,11 @@ namespace ChocolArm64.Decoders
do
{
//TODO: This needs to be changed to support both AArch32 and AArch64,
//once JIT support is introduced on AArch32 aswell.
opCode = DecodeOpCode(state, memory, position);
opCode = DecodeOpCode(memory, position, mode);
block.OpCodes.Add(opCode);
position += 4;
position += opCode.OpCodeSizeInBytes;
}
while (!(IsBranch(opCode) || IsException(opCode)));
@ -145,7 +142,35 @@ namespace ChocolArm64.Decoders
private static bool IsBranch(OpCode64 opCode)
{
return opCode is OpCodeBImm64 ||
opCode is OpCodeBReg64;
opCode is OpCodeBReg64 || IsAarch32Branch(opCode);
}
private static bool IsUnconditionalBranch(OpCode64 opCode)
{
return opCode is OpCodeBImmAl64 ||
opCode is OpCodeBReg64 || IsAarch32UnconditionalBranch(opCode);
}
private static bool IsAarch32UnconditionalBranch(OpCode64 opCode)
{
if (!(opCode is OpCode32 op))
{
return false;
}
//Note: On ARM32, most instructions have conditional execution,
//so there's no "Always" (unconditional) branch like on ARM64.
//We need to check if the condition is "Always" instead.
return IsAarch32Branch(op) && op.Cond >= Condition.Al;
}
private static bool IsAarch32Branch(OpCode64 opCode)
{
//Note: On ARM32, most ALU operations can write to R15 (PC),
//so we must consider such operations as a branch in potential aswell.
return opCode is IOpCodeBImm32 ||
opCode is IOpCodeBReg32 ||
(opCode is IOpCodeAlu32 op && op.Rd == RegisterAlias.Aarch32Pc);
}
private static bool IsException(OpCode64 opCode)
@ -155,20 +180,26 @@ namespace ChocolArm64.Decoders
opCode.Emitter == InstEmit.Und;
}
public static OpCode64 DecodeOpCode(CpuThreadState state, MemoryManager memory, long position)
public static OpCode64 DecodeOpCode(MemoryManager memory, long position, ExecutionMode mode)
{
int opCode = memory.ReadInt32(position);
Inst inst;
if (state.ExecutionMode == ExecutionMode.AArch64)
if (mode == ExecutionMode.Aarch64)
{
inst = OpCodeTable.GetInstA64(opCode);
}
else
{
//TODO: Thumb support.
inst = OpCodeTable.GetInstA32(opCode);
if (mode == ExecutionMode.Aarch32Arm)
{
inst = OpCodeTable.GetInstA32(opCode);
}
else /* if (mode == ExecutionMode.Aarch32Thumb) */
{
inst = OpCodeTable.GetInstT32(opCode);
}
}
OpCode64 decodedOpCode = new OpCode64(Inst.Undefined, position, opCode);