forked from Mirror/Ryujinx
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
|
@ -25,8 +25,6 @@ namespace ChocolArm64
|
||||||
|
|
||||||
ThreadState = new CpuThreadState();
|
ThreadState = new CpuThreadState();
|
||||||
|
|
||||||
ThreadState.ExecutionMode = ExecutionMode.AArch64;
|
|
||||||
|
|
||||||
ThreadState.Running = true;
|
ThreadState.Running = true;
|
||||||
|
|
||||||
Work = new Thread(delegate()
|
Work = new Thread(delegate()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace ChocolArm64
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
static class BitUtils
|
static class BitUtils
|
||||||
{
|
{
|
||||||
|
@ -36,6 +36,16 @@ namespace ChocolArm64
|
||||||
return bits == 64 ? -1L : (1L << bits) - 1;
|
return bits == 64 ? -1L : (1L << bits) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int RotateRight(int bits, int shift, int size)
|
||||||
|
{
|
||||||
|
return (int)RotateRight((uint)bits, shift, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint RotateRight(uint bits, int shift, int size)
|
||||||
|
{
|
||||||
|
return (bits >> shift) | (bits << (size - shift));
|
||||||
|
}
|
||||||
|
|
||||||
public static long RotateRight(long bits, int shift, int size)
|
public static long RotateRight(long bits, int shift, int size)
|
||||||
{
|
{
|
||||||
return (long)RotateRight((ulong)bits, shift, size);
|
return (long)RotateRight((ulong)bits, shift, size);
|
|
@ -1,6 +1,6 @@
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
enum Cond
|
enum Condition
|
||||||
{
|
{
|
||||||
Eq = 0,
|
Eq = 0,
|
||||||
Ne = 1,
|
Ne = 1,
|
|
@ -19,20 +19,20 @@ namespace ChocolArm64.Decoders
|
||||||
_opActivators = new ConcurrentDictionary<Type, OpActivator>();
|
_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);
|
Block block = new Block(start);
|
||||||
|
|
||||||
FillBlock(state, memory, block);
|
FillBlock(memory, mode, block);
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Block DecodeSubroutine(
|
public static Block DecodeSubroutine(
|
||||||
TranslatorCache cache,
|
TranslatorCache cache,
|
||||||
CpuThreadState state,
|
|
||||||
MemoryManager memory,
|
MemoryManager memory,
|
||||||
long start)
|
long start,
|
||||||
|
ExecutionMode mode)
|
||||||
{
|
{
|
||||||
Dictionary<long, Block> visited = new Dictionary<long, Block>();
|
Dictionary<long, Block> visited = new Dictionary<long, Block>();
|
||||||
Dictionary<long, Block> visitedEnd = new Dictionary<long, Block>();
|
Dictionary<long, Block> visitedEnd = new Dictionary<long, Block>();
|
||||||
|
@ -59,7 +59,7 @@ namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
Block current = blocks.Dequeue();
|
Block current = blocks.Dequeue();
|
||||||
|
|
||||||
FillBlock(state, memory, current);
|
FillBlock(memory, mode, current);
|
||||||
|
|
||||||
//Set child blocks. "Branch" is the block the branch instruction
|
//Set child blocks. "Branch" is the block the branch instruction
|
||||||
//points to (when taken), "Next" is the block at the next address,
|
//points to (when taken), "Next" is the block at the next address,
|
||||||
|
@ -71,7 +71,7 @@ namespace ChocolArm64.Decoders
|
||||||
|
|
||||||
OpCode64 lastOp = current.GetLastOp();
|
OpCode64 lastOp = current.GetLastOp();
|
||||||
|
|
||||||
if (lastOp is OpCodeBImm64 op)
|
if (lastOp is IOpCodeBImm op)
|
||||||
{
|
{
|
||||||
if (op.Emitter == InstEmit.Bl)
|
if (op.Emitter == InstEmit.Bl)
|
||||||
{
|
{
|
||||||
|
@ -83,8 +83,7 @@ namespace ChocolArm64.Decoders
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((lastOp is OpCodeBImmAl64) ||
|
if (!IsUnconditionalBranch(lastOp) || hasCachedSub)
|
||||||
(lastOp is OpCodeBReg64)) || hasCachedSub)
|
|
||||||
{
|
{
|
||||||
current.Next = Enqueue(current.EndPosition);
|
current.Next = Enqueue(current.EndPosition);
|
||||||
}
|
}
|
||||||
|
@ -121,7 +120,7 @@ namespace ChocolArm64.Decoders
|
||||||
return entry;
|
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;
|
long position = block.Position;
|
||||||
|
|
||||||
|
@ -129,13 +128,11 @@ namespace ChocolArm64.Decoders
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
//TODO: This needs to be changed to support both AArch32 and AArch64,
|
opCode = DecodeOpCode(memory, position, mode);
|
||||||
//once JIT support is introduced on AArch32 aswell.
|
|
||||||
opCode = DecodeOpCode(state, memory, position);
|
|
||||||
|
|
||||||
block.OpCodes.Add(opCode);
|
block.OpCodes.Add(opCode);
|
||||||
|
|
||||||
position += 4;
|
position += opCode.OpCodeSizeInBytes;
|
||||||
}
|
}
|
||||||
while (!(IsBranch(opCode) || IsException(opCode)));
|
while (!(IsBranch(opCode) || IsException(opCode)));
|
||||||
|
|
||||||
|
@ -145,7 +142,35 @@ namespace ChocolArm64.Decoders
|
||||||
private static bool IsBranch(OpCode64 opCode)
|
private static bool IsBranch(OpCode64 opCode)
|
||||||
{
|
{
|
||||||
return opCode is OpCodeBImm64 ||
|
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)
|
private static bool IsException(OpCode64 opCode)
|
||||||
|
@ -155,20 +180,26 @@ namespace ChocolArm64.Decoders
|
||||||
opCode.Emitter == InstEmit.Und;
|
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);
|
int opCode = memory.ReadInt32(position);
|
||||||
|
|
||||||
Inst inst;
|
Inst inst;
|
||||||
|
|
||||||
if (state.ExecutionMode == ExecutionMode.AArch64)
|
if (mode == ExecutionMode.Aarch64)
|
||||||
{
|
{
|
||||||
inst = OpCodeTable.GetInstA64(opCode);
|
inst = OpCodeTable.GetInstA64(opCode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//TODO: Thumb support.
|
if (mode == ExecutionMode.Aarch32Arm)
|
||||||
inst = OpCodeTable.GetInstA32(opCode);
|
{
|
||||||
|
inst = OpCodeTable.GetInstA32(opCode);
|
||||||
|
}
|
||||||
|
else /* if (mode == ExecutionMode.Aarch32Thumb) */
|
||||||
|
{
|
||||||
|
inst = OpCodeTable.GetInstT32(opCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OpCode64 decodedOpCode = new OpCode64(Inst.Undefined, position, opCode);
|
OpCode64 decodedOpCode = new OpCode64(Inst.Undefined, position, opCode);
|
||||||
|
|
|
@ -89,6 +89,11 @@ namespace ChocolArm64.Decoders
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long DecodeImm24_2(int opCode)
|
||||||
|
{
|
||||||
|
return ((long)opCode << 40) >> 38;
|
||||||
|
}
|
||||||
|
|
||||||
public static long DecodeImm26_2(int opCode)
|
public static long DecodeImm26_2(int opCode)
|
||||||
{
|
{
|
||||||
return ((long)opCode << 38) >> 36;
|
return ((long)opCode << 38) >> 36;
|
||||||
|
|
9
ChocolArm64/Decoders/IOpCode32.cs
Normal file
9
ChocolArm64/Decoders/IOpCode32.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32 : IOpCode64
|
||||||
|
{
|
||||||
|
Condition Cond { get; }
|
||||||
|
|
||||||
|
uint GetPc();
|
||||||
|
}
|
||||||
|
}
|
10
ChocolArm64/Decoders/IOpCodeAlu32.cs
Normal file
10
ChocolArm64/Decoders/IOpCodeAlu32.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCodeAlu32 : IOpCode32
|
||||||
|
{
|
||||||
|
int Rd { get; }
|
||||||
|
int Rn { get; }
|
||||||
|
|
||||||
|
bool SetFlags { get; }
|
||||||
|
}
|
||||||
|
}
|
7
ChocolArm64/Decoders/IOpCodeBImm.cs
Normal file
7
ChocolArm64/Decoders/IOpCodeBImm.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCodeBImm : IOpCode64
|
||||||
|
{
|
||||||
|
long Imm { get; }
|
||||||
|
}
|
||||||
|
}
|
4
ChocolArm64/Decoders/IOpCodeBImm32.cs
Normal file
4
ChocolArm64/Decoders/IOpCodeBImm32.cs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCodeBImm32 : IOpCode32, IOpCodeBImm { }
|
||||||
|
}
|
7
ChocolArm64/Decoders/IOpCodeBReg32.cs
Normal file
7
ChocolArm64/Decoders/IOpCodeBReg32.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCodeBReg32 : IOpCode32
|
||||||
|
{
|
||||||
|
int Rm { get; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,6 @@ namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
interface IOpCodeCond64 : IOpCode64
|
interface IOpCodeCond64 : IOpCode64
|
||||||
{
|
{
|
||||||
Cond Cond { get; }
|
Condition Cond { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
24
ChocolArm64/Decoders/OpCode32.cs
Normal file
24
ChocolArm64/Decoders/OpCode32.cs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
using ChocolArm64.State;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32 : OpCode64
|
||||||
|
{
|
||||||
|
public Condition Cond { get; protected set; }
|
||||||
|
|
||||||
|
public OpCode32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
RegisterSize = RegisterSize.Int32;
|
||||||
|
|
||||||
|
Cond = (Condition)((uint)opCode >> 28);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetPc()
|
||||||
|
{
|
||||||
|
//Due to backwards compatibility and legacy behavior of ARMv4 CPUs pipeline,
|
||||||
|
//the PC actually points 2 instructions ahead.
|
||||||
|
return (uint)Position + (uint)OpCodeSizeInBytes * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,9 +9,10 @@ namespace ChocolArm64.Decoders
|
||||||
public long Position { get; private set; }
|
public long Position { get; private set; }
|
||||||
public int RawOpCode { get; private set; }
|
public int RawOpCode { get; private set; }
|
||||||
|
|
||||||
public InstEmitter Emitter { get; protected set; }
|
public int OpCodeSizeInBytes { get; protected set; } = 4;
|
||||||
public InstInterpreter Interpreter { get; protected set; }
|
|
||||||
public RegisterSize RegisterSize { get; protected set; }
|
public InstEmitter Emitter { get; protected set; }
|
||||||
|
public RegisterSize RegisterSize { get; protected set; }
|
||||||
|
|
||||||
public OpCode64(Inst inst, long position, int opCode)
|
public OpCode64(Inst inst, long position, int opCode)
|
||||||
{
|
{
|
||||||
|
@ -20,8 +21,7 @@ namespace ChocolArm64.Decoders
|
||||||
|
|
||||||
RegisterSize = RegisterSize.Int64;
|
RegisterSize = RegisterSize.Int64;
|
||||||
|
|
||||||
Emitter = inst.Emitter;
|
Emitter = inst.Emitter;
|
||||||
Interpreter = inst.Interpreter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetBitsCount()
|
public int GetBitsCount()
|
||||||
|
|
20
ChocolArm64/Decoders/OpCodeAlu32.cs
Normal file
20
ChocolArm64/Decoders/OpCodeAlu32.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeAlu32 : OpCode32, IOpCodeAlu32
|
||||||
|
{
|
||||||
|
public int Rd { get; private set; }
|
||||||
|
public int Rn { get; private set; }
|
||||||
|
|
||||||
|
public bool SetFlags { get; private set; }
|
||||||
|
|
||||||
|
public OpCodeAlu32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 12) & 0xf;
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
SetFlags = ((opCode >> 20) & 1) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
ChocolArm64/Decoders/OpCodeAluImm32.cs
Normal file
21
ChocolArm64/Decoders/OpCodeAluImm32.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeAluImm32 : OpCodeAlu32
|
||||||
|
{
|
||||||
|
public int Imm { get; private set; }
|
||||||
|
|
||||||
|
public bool IsRotated { get; private set; }
|
||||||
|
|
||||||
|
public OpCodeAluImm32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
int value = (opCode >> 0) & 0xff;
|
||||||
|
int shift = (opCode >> 8) & 0xf;
|
||||||
|
|
||||||
|
Imm = BitUtils.RotateRight(value, shift * 2, 32);
|
||||||
|
|
||||||
|
IsRotated = shift != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
ChocolArm64/Decoders/OpCodeAluImm8T16.cs
Normal file
22
ChocolArm64/Decoders/OpCodeAluImm8T16.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeAluImm8T16 : OpCodeT16, IOpCodeAlu32
|
||||||
|
{
|
||||||
|
private int _rdn;
|
||||||
|
|
||||||
|
public int Rd => _rdn;
|
||||||
|
public int Rn => _rdn;
|
||||||
|
|
||||||
|
public bool SetFlags => false;
|
||||||
|
|
||||||
|
public int Imm { get; private set; }
|
||||||
|
|
||||||
|
public OpCodeAluImm8T16(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
Imm = (opCode >> 0) & 0xff;
|
||||||
|
_rdn = (opCode >> 8) & 0x7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ChocolArm64/Decoders/OpCodeAluRsImm32.cs
Normal file
20
ChocolArm64/Decoders/OpCodeAluRsImm32.cs
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeAluRsImm32 : OpCodeAlu32
|
||||||
|
{
|
||||||
|
public int Rm { get; private set; }
|
||||||
|
public int Imm { get; private set; }
|
||||||
|
|
||||||
|
public ShiftType ShiftType { get; private set; }
|
||||||
|
|
||||||
|
public OpCodeAluRsImm32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
Rm = (opCode >> 0) & 0xf;
|
||||||
|
Imm = (opCode >> 7) & 0x1f;
|
||||||
|
|
||||||
|
ShiftType = (ShiftType)((opCode >> 5) & 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
ChocolArm64/Decoders/OpCodeBImm32.cs
Normal file
29
ChocolArm64/Decoders/OpCodeBImm32.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeBImm32 : OpCode32, IOpCodeBImm32
|
||||||
|
{
|
||||||
|
public long Imm { get; private set; }
|
||||||
|
|
||||||
|
public OpCodeBImm32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
uint pc = GetPc();
|
||||||
|
|
||||||
|
//When the codition is never, the instruction is BLX to Thumb mode.
|
||||||
|
if (Cond != Condition.Nv)
|
||||||
|
{
|
||||||
|
pc &= ~3u;
|
||||||
|
}
|
||||||
|
|
||||||
|
Imm = pc + DecoderHelper.DecodeImm24_2(opCode);
|
||||||
|
|
||||||
|
if (Cond == Condition.Nv)
|
||||||
|
{
|
||||||
|
long H = (opCode >> 23) & 2;
|
||||||
|
|
||||||
|
Imm |= H;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ using ChocolArm64.Instructions;
|
||||||
|
|
||||||
namespace ChocolArm64.Decoders
|
namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeBImm64 : OpCode64
|
class OpCodeBImm64 : OpCode64, IOpCodeBImm
|
||||||
{
|
{
|
||||||
public long Imm { get; protected set; }
|
public long Imm { get; protected set; }
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeBImmCond64 : OpCodeBImm64, IOpCodeCond64
|
class OpCodeBImmCond64 : OpCodeBImm64, IOpCodeCond64
|
||||||
{
|
{
|
||||||
public Cond Cond { get; private set; }
|
public Condition Cond { get; private set; }
|
||||||
|
|
||||||
public OpCodeBImmCond64(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCodeBImmCond64(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ namespace ChocolArm64.Decoders
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Cond = (Cond)(opCode & 0xf);
|
Cond = (Condition)(opCode & 0xf);
|
||||||
|
|
||||||
Imm = position + DecoderHelper.DecodeImmS19_2(opCode);
|
Imm = position + DecoderHelper.DecodeImmS19_2(opCode);
|
||||||
}
|
}
|
||||||
|
|
14
ChocolArm64/Decoders/OpCodeBReg32.cs
Normal file
14
ChocolArm64/Decoders/OpCodeBReg32.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeBReg32 : OpCode32, IOpCodeBReg32
|
||||||
|
{
|
||||||
|
public int Rm { get; private set; }
|
||||||
|
|
||||||
|
public OpCodeBReg32(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
Rm = opCode & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
ChocolArm64/Decoders/OpCodeBRegT16.cs
Normal file
14
ChocolArm64/Decoders/OpCodeBRegT16.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeBRegT16 : OpCodeT16, IOpCodeBReg32
|
||||||
|
{
|
||||||
|
public int Rm { get; private set; }
|
||||||
|
|
||||||
|
public OpCodeBRegT16(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
Rm = (opCode >> 3) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,7 @@ namespace ChocolArm64.Decoders
|
||||||
public int Nzcv { get; private set; }
|
public int Nzcv { get; private set; }
|
||||||
protected int RmImm;
|
protected int RmImm;
|
||||||
|
|
||||||
public Cond Cond { get; private set; }
|
public Condition Cond { get; private set; }
|
||||||
|
|
||||||
public OpCodeCcmp64(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCodeCcmp64(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
|
@ -21,11 +21,11 @@ namespace ChocolArm64.Decoders
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Nzcv = (opCode >> 0) & 0xf;
|
Nzcv = (opCode >> 0) & 0xf;
|
||||||
Cond = (Cond)((opCode >> 12) & 0xf);
|
Cond = (Condition)((opCode >> 12) & 0xf);
|
||||||
RmImm = (opCode >> 16) & 0x1f;
|
RmImm = (opCode >> 16) & 0x1f;
|
||||||
|
|
||||||
Rd = CpuThreadState.ZrIndex;
|
Rd = RegisterAlias.Zr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,12 +6,12 @@ namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
public int Rm { get; private set; }
|
public int Rm { get; private set; }
|
||||||
|
|
||||||
public Cond Cond { get; private set; }
|
public Condition Cond { get; private set; }
|
||||||
|
|
||||||
public OpCodeCsel64(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCodeCsel64(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
Rm = (opCode >> 16) & 0x1f;
|
Rm = (opCode >> 16) & 0x1f;
|
||||||
Cond = (Cond)((opCode >> 12) & 0xf);
|
Cond = (Condition)((opCode >> 12) & 0xf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,12 +6,12 @@ namespace ChocolArm64.Decoders
|
||||||
{
|
{
|
||||||
public int Nzcv { get; private set; }
|
public int Nzcv { get; private set; }
|
||||||
|
|
||||||
public Cond Cond { get; private set; }
|
public Condition Cond { get; private set; }
|
||||||
|
|
||||||
public OpCodeSimdFcond64(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
public OpCodeSimdFcond64(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
{
|
{
|
||||||
Nzcv = (opCode >> 0) & 0xf;
|
Nzcv = (opCode >> 0) & 0xf;
|
||||||
Cond = (Cond)((opCode >> 12) & 0xf);
|
Cond = (Condition)((opCode >> 12) & 0xf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
ChocolArm64/Decoders/OpCodeT16.cs
Normal file
14
ChocolArm64/Decoders/OpCodeT16.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using ChocolArm64.Instructions;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16 : OpCode32
|
||||||
|
{
|
||||||
|
public OpCodeT16(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
||||||
|
{
|
||||||
|
Cond = Condition.Al;
|
||||||
|
|
||||||
|
OpCodeSizeInBytes = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +0,0 @@
|
||||||
using ChocolArm64.Decoders;
|
|
||||||
using ChocolArm64.Instructions;
|
|
||||||
|
|
||||||
namespace ChocolArm64.Decoders32
|
|
||||||
{
|
|
||||||
class A32OpCode : OpCode64
|
|
||||||
{
|
|
||||||
public Cond Cond { get; private set; }
|
|
||||||
|
|
||||||
public A32OpCode(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
|
||||||
{
|
|
||||||
Cond = (Cond)((uint)opCode >> 28);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
using ChocolArm64.Instructions;
|
|
||||||
|
|
||||||
namespace ChocolArm64.Decoders32
|
|
||||||
{
|
|
||||||
class A32OpCodeBImmAl : A32OpCode
|
|
||||||
{
|
|
||||||
public int Imm;
|
|
||||||
public int H;
|
|
||||||
|
|
||||||
public A32OpCodeBImmAl(Inst inst, long position, int opCode) : base(inst, position, opCode)
|
|
||||||
{
|
|
||||||
Imm = (opCode << 8) >> 6;
|
|
||||||
H = (opCode >> 23) & 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,17 +4,15 @@ namespace ChocolArm64.Instructions
|
||||||
{
|
{
|
||||||
struct Inst
|
struct Inst
|
||||||
{
|
{
|
||||||
public InstInterpreter Interpreter { get; private set; }
|
public InstEmitter Emitter { get; }
|
||||||
public InstEmitter Emitter { get; private set; }
|
public Type Type { get; }
|
||||||
public Type Type { get; private set; }
|
|
||||||
|
|
||||||
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;
|
||||||
Emitter = emitter;
|
Type = type;
|
||||||
Type = type;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
99
ChocolArm64/Instructions/InstEmit32Helper.cs
Normal file
99
ChocolArm64/Instructions/InstEmit32Helper.cs
Normal file
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,7 +17,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
private static void EmitAdc(ILEmitterCtx context, bool setFlags)
|
private static void EmitAdc(ILEmitterCtx context, bool setFlags)
|
||||||
{
|
{
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Add);
|
context.Emit(OpCodes.Add);
|
||||||
|
|
||||||
|
@ -44,14 +44,14 @@ namespace ChocolArm64.Instructions
|
||||||
EmitAddsVCheck(context);
|
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)
|
public static void Adds(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Add);
|
context.Emit(OpCodes.Add);
|
||||||
|
|
||||||
|
@ -59,14 +59,14 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
EmitAddsCCheck(context);
|
EmitAddsCCheck(context);
|
||||||
EmitAddsVCheck(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)
|
public static void Ands(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.And);
|
context.Emit(OpCodes.And);
|
||||||
|
|
||||||
|
@ -74,17 +74,17 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitZnFlagCheck();
|
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 Bic(ILEmitterCtx context) => EmitBic(context, false);
|
||||||
public static void Bics(ILEmitterCtx context) => EmitBic(context, true);
|
public static void Bics(ILEmitterCtx context) => EmitBic(context, true);
|
||||||
|
|
||||||
private static void EmitBic(ILEmitterCtx context, bool setFlags)
|
private static void EmitBic(ILEmitterCtx context, bool setFlags)
|
||||||
{
|
{
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Not);
|
context.Emit(OpCodes.Not);
|
||||||
context.Emit(OpCodes.And);
|
context.Emit(OpCodes.And);
|
||||||
|
@ -96,7 +96,7 @@ namespace ChocolArm64.Instructions
|
||||||
context.EmitZnFlagCheck();
|
context.EmitZnFlagCheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitDataStore(context, setFlags);
|
EmitAluStore(context, setFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Cls(ILEmitterCtx context)
|
public static void Cls(ILEmitterCtx context)
|
||||||
|
@ -136,15 +136,15 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void Eon(ILEmitterCtx context)
|
public static void Eon(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Not);
|
context.Emit(OpCodes.Not);
|
||||||
context.Emit(OpCodes.Xor);
|
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)
|
public static void Extr(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
|
@ -166,18 +166,18 @@ namespace ChocolArm64.Instructions
|
||||||
context.Emit(OpCodes.Or);
|
context.Emit(OpCodes.Or);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitDataStore(context);
|
EmitAluStore(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Lslv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shl);
|
public static void Lslv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shl);
|
||||||
public static void Lsrv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shr_Un);
|
public static void Lsrv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shr_Un);
|
||||||
|
|
||||||
public static void Sbc(ILEmitterCtx context) => EmitSbc(context, false);
|
public static void Sbc(ILEmitterCtx context) => EmitSbc(context, false);
|
||||||
public static void Sbcs(ILEmitterCtx context) => EmitSbc(context, true);
|
public static void Sbcs(ILEmitterCtx context) => EmitSbc(context, true);
|
||||||
|
|
||||||
private static void EmitSbc(ILEmitterCtx context, bool setFlags)
|
private static void EmitSbc(ILEmitterCtx context, bool setFlags)
|
||||||
{
|
{
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Sub);
|
context.Emit(OpCodes.Sub);
|
||||||
|
|
||||||
|
@ -208,16 +208,16 @@ namespace ChocolArm64.Instructions
|
||||||
EmitSubsVCheck(context);
|
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)
|
public static void Subs(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
context.TryOptMarkCondWithoutCmp();
|
context.TryOptMarkCondWithoutCmp();
|
||||||
|
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Sub);
|
context.Emit(OpCodes.Sub);
|
||||||
|
|
||||||
|
@ -225,20 +225,20 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
EmitSubsCCheck(context);
|
EmitSubsCCheck(context);
|
||||||
EmitSubsVCheck(context);
|
EmitSubsVCheck(context);
|
||||||
EmitDataStoreS(context);
|
EmitAluStoreS(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Orn(ILEmitterCtx context)
|
public static void Orn(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Not);
|
context.Emit(OpCodes.Not);
|
||||||
context.Emit(OpCodes.Or);
|
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,
|
public static void Rbit(ILEmitterCtx context) => EmitFallback32_64(context,
|
||||||
nameof(SoftFallback.ReverseBits32),
|
nameof(SoftFallback.ReverseBits32),
|
||||||
|
@ -283,22 +283,22 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
public static void Rorv(ILEmitterCtx context)
|
public static void Rorv(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
EmitDataLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
EmitDataLoadShift(context);
|
EmitAluLoadShift(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Shr_Un);
|
context.Emit(OpCodes.Shr_Un);
|
||||||
|
|
||||||
EmitDataLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
|
|
||||||
context.EmitLdc_I4(context.CurrOp.GetBitsCount());
|
context.EmitLdc_I4(context.CurrOp.GetBitsCount());
|
||||||
|
|
||||||
EmitDataLoadShift(context);
|
EmitAluLoadShift(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Sub);
|
context.Emit(OpCodes.Sub);
|
||||||
context.Emit(OpCodes.Shl);
|
context.Emit(OpCodes.Shl);
|
||||||
context.Emit(OpCodes.Or);
|
context.Emit(OpCodes.Or);
|
||||||
|
|
||||||
EmitDataStore(context);
|
EmitAluStore(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Sdiv(ILEmitterCtx context) => EmitDiv(context, OpCodes.Div);
|
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).
|
//If Rm == 0, Rd = 0 (division by zero).
|
||||||
context.EmitLdc_I(0);
|
context.EmitLdc_I(0);
|
||||||
|
|
||||||
EmitDataLoadRm(context);
|
EmitAluLoadRm(context);
|
||||||
|
|
||||||
context.EmitLdc_I(0);
|
context.EmitLdc_I(0);
|
||||||
|
|
||||||
|
@ -325,13 +325,13 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitLdc_I(intMin);
|
context.EmitLdc_I(intMin);
|
||||||
|
|
||||||
EmitDataLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
|
|
||||||
context.EmitLdc_I(intMin);
|
context.EmitLdc_I(intMin);
|
||||||
|
|
||||||
context.Emit(OpCodes.Ceq);
|
context.Emit(OpCodes.Ceq);
|
||||||
|
|
||||||
EmitDataLoadRm(context);
|
EmitAluLoadRm(context);
|
||||||
|
|
||||||
context.EmitLdc_I(-1);
|
context.EmitLdc_I(-1);
|
||||||
|
|
||||||
|
@ -341,38 +341,38 @@ namespace ChocolArm64.Instructions
|
||||||
context.Emit(OpCodes.Pop);
|
context.Emit(OpCodes.Pop);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitDataLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
EmitDataLoadRm(context);
|
EmitAluLoadRm(context);
|
||||||
|
|
||||||
context.Emit(ilOp);
|
context.Emit(ilOp);
|
||||||
|
|
||||||
context.MarkLabel(badDiv);
|
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);
|
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);
|
EmitAluLoadRn(context);
|
||||||
EmitDataLoadShift(context);
|
EmitAluLoadShift(context);
|
||||||
|
|
||||||
context.Emit(ilOp);
|
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);
|
context.EmitLdc_I(context.CurrOp.GetBitsCount() - 1);
|
||||||
|
|
||||||
|
@ -398,5 +398,22 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitStflg((int)PState.CBit);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
123
ChocolArm64/Instructions/InstEmitAlu32.cs
Normal file
123
ChocolArm64/Instructions/InstEmitAlu32.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
using ChocolArm64.Decoders;
|
using ChocolArm64.Decoders;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using ChocolArm64.Translation;
|
using ChocolArm64.Translation;
|
||||||
|
using System;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
namespace ChocolArm64.Instructions
|
namespace ChocolArm64.Instructions
|
||||||
|
@ -14,7 +15,7 @@ namespace ChocolArm64.Instructions
|
||||||
context.EmitLdtmp();
|
context.EmitLdtmp();
|
||||||
context.EmitLdtmp();
|
context.EmitLdtmp();
|
||||||
|
|
||||||
EmitDataLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Ceq);
|
context.Emit(OpCodes.Ceq);
|
||||||
|
|
||||||
|
@ -24,7 +25,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitLdtmp();
|
context.EmitLdtmp();
|
||||||
|
|
||||||
EmitDataLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Clt_Un);
|
context.Emit(OpCodes.Clt_Un);
|
||||||
context.Emit(OpCodes.Or);
|
context.Emit(OpCodes.Or);
|
||||||
|
@ -37,7 +38,7 @@ namespace ChocolArm64.Instructions
|
||||||
//C = Rd < Rn
|
//C = Rd < Rn
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
||||||
EmitDataLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Clt_Un);
|
context.Emit(OpCodes.Clt_Un);
|
||||||
|
|
||||||
|
@ -49,11 +50,11 @@ namespace ChocolArm64.Instructions
|
||||||
//V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0
|
//V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
||||||
EmitDataLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Xor);
|
context.Emit(OpCodes.Xor);
|
||||||
|
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Xor);
|
context.Emit(OpCodes.Xor);
|
||||||
context.Emit(OpCodes.Not);
|
context.Emit(OpCodes.Not);
|
||||||
|
@ -69,7 +70,7 @@ namespace ChocolArm64.Instructions
|
||||||
public static void EmitSbcsCCheck(ILEmitterCtx context)
|
public static void EmitSbcsCCheck(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//C = (Rn == Rm && CIn) || Rn > Rm
|
//C = (Rn == Rm && CIn) || Rn > Rm
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Ceq);
|
context.Emit(OpCodes.Ceq);
|
||||||
|
|
||||||
|
@ -77,7 +78,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.Emit(OpCodes.And);
|
context.Emit(OpCodes.And);
|
||||||
|
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Cgt_Un);
|
context.Emit(OpCodes.Cgt_Un);
|
||||||
context.Emit(OpCodes.Or);
|
context.Emit(OpCodes.Or);
|
||||||
|
@ -88,7 +89,7 @@ namespace ChocolArm64.Instructions
|
||||||
public static void EmitSubsCCheck(ILEmitterCtx context)
|
public static void EmitSubsCCheck(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
//C = Rn == Rm || Rn > Rm = !(Rn < Rm)
|
//C = Rn == Rm || Rn > Rm = !(Rn < Rm)
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Clt_Un);
|
context.Emit(OpCodes.Clt_Un);
|
||||||
|
|
||||||
|
@ -104,11 +105,11 @@ namespace ChocolArm64.Instructions
|
||||||
//V = (Rd ^ Rn) & (Rn ^ Rm) < 0
|
//V = (Rd ^ Rn) & (Rn ^ Rm) < 0
|
||||||
context.Emit(OpCodes.Dup);
|
context.Emit(OpCodes.Dup);
|
||||||
|
|
||||||
EmitDataLoadRn(context);
|
EmitAluLoadRn(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Xor);
|
context.Emit(OpCodes.Xor);
|
||||||
|
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
context.Emit(OpCodes.Xor);
|
context.Emit(OpCodes.Xor);
|
||||||
context.Emit(OpCodes.And);
|
context.Emit(OpCodes.And);
|
||||||
|
@ -120,35 +121,76 @@ namespace ChocolArm64.Instructions
|
||||||
context.EmitStflg((int)PState.VBit);
|
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)
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
context.EmitLdintzr(op.Rn);
|
context.EmitLdintzr(op.Rm);
|
||||||
|
}
|
||||||
|
else if (context.CurrOp is OpCodeAluRsImm32 op32)
|
||||||
|
{
|
||||||
|
InstEmit32Helper.EmitLoadFromRegister(context, op32.Rm);
|
||||||
}
|
}
|
||||||
else
|
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)
|
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:
|
case IOpCodeAluImm64 op:
|
||||||
context.EmitLdc_I(op.Imm);
|
context.EmitLdc_I(op.Imm);
|
||||||
break;
|
break;
|
||||||
|
@ -170,23 +212,8 @@ namespace ChocolArm64.Instructions
|
||||||
context.EmitCast(op.IntType);
|
context.EmitCast(op.IntType);
|
||||||
context.EmitLsl(op.Shift);
|
context.EmitLsl(op.Shift);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void EmitDataStore(ILEmitterCtx context) => EmitDataStore(context, false);
|
default: throw new InvalidOperationException();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,5 +244,219 @@ namespace ChocolArm64.Instructions
|
||||||
context.Emit(OpCodes.And);
|
context.Emit(OpCodes.And);
|
||||||
context.EmitStflg((int)PState.NBit);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.MarkLabel(lblTrue);
|
context.MarkLabel(lblTrue);
|
||||||
|
|
||||||
EmitDataLoadOpers(context);
|
EmitAluLoadOpers(context);
|
||||||
|
|
||||||
if (cmpOp == CcmpOp.Cmp)
|
if (cmpOp == CcmpOp.Cmp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,36 +36,10 @@ namespace ChocolArm64.Instructions
|
||||||
OpCodeBImmAl64 op = (OpCodeBImmAl64)context.CurrOp;
|
OpCodeBImmAl64 op = (OpCodeBImmAl64)context.CurrOp;
|
||||||
|
|
||||||
context.EmitLdc_I(op.Position + 4);
|
context.EmitLdc_I(op.Position + 4);
|
||||||
context.EmitStint(CpuThreadState.LrIndex);
|
context.EmitStint(RegisterAlias.Lr);
|
||||||
context.EmitStoreState();
|
context.EmitStoreState();
|
||||||
|
|
||||||
if (context.TryOptEmitSubroutineCall())
|
InstEmitFlowHelper.EmitCall(context, op.Imm);
|
||||||
{
|
|
||||||
//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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Blr(ILEmitterCtx context)
|
public static void Blr(ILEmitterCtx context)
|
||||||
|
@ -74,7 +48,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitLdintzr(op.Rn);
|
context.EmitLdintzr(op.Rn);
|
||||||
context.EmitLdc_I(op.Position + 4);
|
context.EmitLdc_I(op.Position + 4);
|
||||||
context.EmitStint(CpuThreadState.LrIndex);
|
context.EmitStint(RegisterAlias.Lr);
|
||||||
context.EmitStoreState();
|
context.EmitStoreState();
|
||||||
|
|
||||||
context.Emit(OpCodes.Ret);
|
context.Emit(OpCodes.Ret);
|
||||||
|
@ -106,7 +80,7 @@ namespace ChocolArm64.Instructions
|
||||||
public static void Ret(ILEmitterCtx context)
|
public static void Ret(ILEmitterCtx context)
|
||||||
{
|
{
|
||||||
context.EmitStoreState();
|
context.EmitStoreState();
|
||||||
context.EmitLdint(CpuThreadState.LrIndex);
|
context.EmitLdint(RegisterAlias.Lr);
|
||||||
|
|
||||||
context.Emit(OpCodes.Ret);
|
context.Emit(OpCodes.Ret);
|
||||||
}
|
}
|
||||||
|
@ -128,7 +102,7 @@ namespace ChocolArm64.Instructions
|
||||||
EmitBranch(context, ilOp);
|
EmitBranch(context, ilOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitBranch(ILEmitterCtx context, Cond cond)
|
private static void EmitBranch(ILEmitterCtx context, Condition cond)
|
||||||
{
|
{
|
||||||
OpCodeBImm64 op = (OpCodeBImm64)context.CurrOp;
|
OpCodeBImm64 op = (OpCodeBImm64)context.CurrOp;
|
||||||
|
|
||||||
|
|
99
ChocolArm64/Instructions/InstEmitFlow32.cs
Normal file
99
ChocolArm64/Instructions/InstEmitFlow32.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
ChocolArm64/Instructions/InstEmitFlowHelper.cs
Normal file
39
ChocolArm64/Instructions/InstEmitFlowHelper.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -168,7 +168,7 @@ namespace ChocolArm64.Instructions
|
||||||
|
|
||||||
context.EmitLdint(op.Rn);
|
context.EmitLdint(op.Rn);
|
||||||
|
|
||||||
if (op.Rm != CpuThreadState.ZrIndex)
|
if (op.Rm != RegisterAlias.Zr)
|
||||||
{
|
{
|
||||||
context.EmitLdint(op.Rm);
|
context.EmitLdint(op.Rm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace ChocolArm64.Instructions32
|
|
||||||
{
|
|
||||||
static partial class A32InstInterpret
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
using ChocolArm64.Decoders;
|
|
||||||
using ChocolArm64.Decoders32;
|
|
||||||
using ChocolArm64.Memory;
|
|
||||||
using ChocolArm64.State;
|
|
||||||
|
|
||||||
using static ChocolArm64.Instructions32.A32InstInterpretHelper;
|
|
||||||
|
|
||||||
namespace ChocolArm64.Instructions32
|
|
||||||
{
|
|
||||||
static partial class A32InstInterpret
|
|
||||||
{
|
|
||||||
public static void B(CpuThreadState state, MemoryManager memory, OpCode64 opCode)
|
|
||||||
{
|
|
||||||
A32OpCodeBImmAl op = (A32OpCodeBImmAl)opCode;
|
|
||||||
|
|
||||||
if (IsConditionTrue(state, op.Cond))
|
|
||||||
{
|
|
||||||
BranchWritePc(state, GetPc(state) + (uint)op.Imm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Bl(CpuThreadState state, MemoryManager memory, OpCode64 opCode)
|
|
||||||
{
|
|
||||||
Blx(state, memory, opCode, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Blx(CpuThreadState state, MemoryManager memory, OpCode64 opCode)
|
|
||||||
{
|
|
||||||
Blx(state, memory, opCode, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Blx(CpuThreadState state, MemoryManager memory, OpCode64 opCode, bool x)
|
|
||||||
{
|
|
||||||
A32OpCodeBImmAl op = (A32OpCodeBImmAl)opCode;
|
|
||||||
|
|
||||||
if (IsConditionTrue(state, op.Cond))
|
|
||||||
{
|
|
||||||
uint pc = GetPc(state);
|
|
||||||
|
|
||||||
if (state.Thumb)
|
|
||||||
{
|
|
||||||
state.R14 = pc | 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
state.R14 = pc - 4U;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x)
|
|
||||||
{
|
|
||||||
state.Thumb = !state.Thumb;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!state.Thumb)
|
|
||||||
{
|
|
||||||
pc &= ~3U;
|
|
||||||
}
|
|
||||||
|
|
||||||
BranchWritePc(state, pc + (uint)op.Imm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void BranchWritePc(CpuThreadState state, uint pc)
|
|
||||||
{
|
|
||||||
state.R15 = state.Thumb
|
|
||||||
? pc & ~1U
|
|
||||||
: pc & ~3U;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,65 +0,0 @@
|
||||||
using ChocolArm64.Decoders;
|
|
||||||
using ChocolArm64.State;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace ChocolArm64.Instructions32
|
|
||||||
{
|
|
||||||
static class A32InstInterpretHelper
|
|
||||||
{
|
|
||||||
public static bool IsConditionTrue(CpuThreadState state, Cond cond)
|
|
||||||
{
|
|
||||||
switch (cond)
|
|
||||||
{
|
|
||||||
case Cond.Eq: return state.Zero;
|
|
||||||
case Cond.Ne: return !state.Zero;
|
|
||||||
case Cond.GeUn: return state.Carry;
|
|
||||||
case Cond.LtUn: return !state.Carry;
|
|
||||||
case Cond.Mi: return state.Negative;
|
|
||||||
case Cond.Pl: return !state.Negative;
|
|
||||||
case Cond.Vs: return state.Overflow;
|
|
||||||
case Cond.Vc: return !state.Overflow;
|
|
||||||
case Cond.GtUn: return state.Carry && !state.Zero;
|
|
||||||
case Cond.LeUn: return !state.Carry && state.Zero;
|
|
||||||
case Cond.Ge: return state.Negative == state.Overflow;
|
|
||||||
case Cond.Lt: return state.Negative != state.Overflow;
|
|
||||||
case Cond.Gt: return state.Negative == state.Overflow && !state.Zero;
|
|
||||||
case Cond.Le: return state.Negative != state.Overflow && state.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe static uint GetReg(CpuThreadState state, int reg)
|
|
||||||
{
|
|
||||||
if ((uint)reg > 15)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(reg));
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed (uint* ptr = &state.R0)
|
|
||||||
{
|
|
||||||
return *(ptr + reg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe static void SetReg(CpuThreadState state, int reg, uint value)
|
|
||||||
{
|
|
||||||
if ((uint)reg > 15)
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(reg));
|
|
||||||
}
|
|
||||||
|
|
||||||
fixed (uint* ptr = &state.R0)
|
|
||||||
{
|
|
||||||
*(ptr + reg) = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static uint GetPc(CpuThreadState state)
|
|
||||||
{
|
|
||||||
//Due to the old fetch-decode-execute pipeline of old ARM CPUs,
|
|
||||||
//the PC is 4 or 8 bytes (2 instructions) ahead of the current instruction.
|
|
||||||
return state.R15 + (state.Thumb ? 2U : 4U);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,5 @@
|
||||||
using ChocolArm64.Decoders;
|
using ChocolArm64.Decoders;
|
||||||
using ChocolArm64.Decoders32;
|
|
||||||
using ChocolArm64.Instructions;
|
using ChocolArm64.Instructions;
|
||||||
using ChocolArm64.Instructions32;
|
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -10,13 +8,47 @@ namespace ChocolArm64
|
||||||
{
|
{
|
||||||
static class OpCodeTable
|
static class OpCodeTable
|
||||||
{
|
{
|
||||||
|
private const int FastLookupSize = 0x1000;
|
||||||
|
|
||||||
|
private class InstInfo
|
||||||
|
{
|
||||||
|
public int Mask;
|
||||||
|
public int Value;
|
||||||
|
|
||||||
|
public Inst Inst;
|
||||||
|
|
||||||
|
public InstInfo(int mask, int value, Inst inst)
|
||||||
|
{
|
||||||
|
Mask = mask;
|
||||||
|
Value = value;
|
||||||
|
Inst = inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<InstInfo> _allInstA32 = new List<InstInfo>();
|
||||||
|
private static List<InstInfo> _allInstT32 = new List<InstInfo>();
|
||||||
|
private static List<InstInfo> _allInstA64 = new List<InstInfo>();
|
||||||
|
|
||||||
|
private static InstInfo[][] _instA32FastLookup = new InstInfo[FastLookupSize][];
|
||||||
|
private static InstInfo[][] _instT32FastLookup = new InstInfo[FastLookupSize][];
|
||||||
|
private static InstInfo[][] _instA64FastLookup = new InstInfo[FastLookupSize][];
|
||||||
|
|
||||||
static OpCodeTable()
|
static OpCodeTable()
|
||||||
{
|
{
|
||||||
#region "OpCode Table (AArch32)"
|
#region "OpCode Table (AArch32)"
|
||||||
//Integer
|
//Integer
|
||||||
SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", A32InstInterpret.B, typeof(A32OpCodeBImmAl));
|
SetA32("<<<<0010100xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Add, typeof(OpCodeAluImm32));
|
||||||
SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", A32InstInterpret.Bl, typeof(A32OpCodeBImmAl));
|
SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Add, typeof(OpCodeAluRsImm32));
|
||||||
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", A32InstInterpret.Blx, typeof(A32OpCodeBImmAl));
|
SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.B, typeof(OpCodeBImm32));
|
||||||
|
SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.Bl, typeof(OpCodeBImm32));
|
||||||
|
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstEmit32.Blx, typeof(OpCodeBImm32));
|
||||||
|
SetA32("<<<<000100101111111111110001xxxx", InstEmit32.Bx, typeof(OpCodeBReg32));
|
||||||
|
SetT32( "010001110xxxx000", InstEmit32.Bx, typeof(OpCodeBRegT16));
|
||||||
|
SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstEmit32.Mov, typeof(OpCodeAluImm32));
|
||||||
|
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstEmit32.Mov, typeof(OpCodeAluRsImm32));
|
||||||
|
SetT32( "00100xxxxxxxxxxx", InstEmit32.Mov, typeof(OpCodeAluImm8T16));
|
||||||
|
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Sub, typeof(OpCodeAluImm32));
|
||||||
|
SetA32("<<<<0000010xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Sub, typeof(OpCodeAluRsImm32));
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "OpCode Table (AArch64)"
|
#region "OpCode Table (AArch64)"
|
||||||
|
@ -544,63 +576,29 @@ namespace ChocolArm64
|
||||||
SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstEmit.Zip2_V, typeof(OpCodeSimdReg64));
|
SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstEmit.Zip2_V, typeof(OpCodeSimdReg64));
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "Generate InstA64FastLookup Table (AArch64)"
|
FillFastLookupTable(_instA32FastLookup, _allInstA32);
|
||||||
var tmp = new List<InstInfo>[_fastLookupSize];
|
FillFastLookupTable(_instT32FastLookup, _allInstT32);
|
||||||
for (int i = 0; i < _fastLookupSize; i++)
|
FillFastLookupTable(_instA64FastLookup, _allInstA64);
|
||||||
{
|
|
||||||
tmp[i] = new List<InstInfo>();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var inst in _allInstA64)
|
|
||||||
{
|
|
||||||
int mask = ToFastLookupIndex(inst.Mask);
|
|
||||||
int value = ToFastLookupIndex(inst.Value);
|
|
||||||
|
|
||||||
for (int i = 0; i < _fastLookupSize; i++)
|
|
||||||
{
|
|
||||||
if ((i & mask) == value)
|
|
||||||
{
|
|
||||||
tmp[i].Add(inst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < _fastLookupSize; i++)
|
|
||||||
{
|
|
||||||
_instA64FastLookup[i] = tmp[i].ToArray();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class InstInfo
|
private static void SetA32(string encoding, InstEmitter emitter, Type type)
|
||||||
{
|
{
|
||||||
public int Mask;
|
Set(encoding, new Inst(emitter, type), ExecutionMode.Aarch32Arm);
|
||||||
public int Value;
|
|
||||||
|
|
||||||
public Inst Inst;
|
|
||||||
|
|
||||||
public InstInfo(int mask, int value, Inst inst)
|
|
||||||
{
|
|
||||||
Mask = mask;
|
|
||||||
Value = value;
|
|
||||||
Inst = inst;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<InstInfo> _allInstA32 = new List<InstInfo>();
|
private static void SetT32(string encoding, InstEmitter emitter, Type type)
|
||||||
private static List<InstInfo> _allInstA64 = new List<InstInfo>();
|
|
||||||
|
|
||||||
private static int _fastLookupSize = 0x1000;
|
|
||||||
private static InstInfo[][] _instA64FastLookup = new InstInfo[_fastLookupSize][];
|
|
||||||
|
|
||||||
private static void SetA32(string encoding, InstInterpreter interpreter, Type type)
|
|
||||||
{
|
{
|
||||||
Set(encoding, new Inst(interpreter, null, type), ExecutionMode.AArch32);
|
if (encoding.Length == 16)
|
||||||
|
{
|
||||||
|
encoding = "xxxxxxxxxxxxxxxx" + encoding;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set(encoding, new Inst(emitter, type), ExecutionMode.Aarch32Thumb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetA64(string encoding, InstEmitter emitter, Type type)
|
private static void SetA64(string encoding, InstEmitter emitter, Type type)
|
||||||
{
|
{
|
||||||
Set(encoding, new Inst(null, emitter, type), ExecutionMode.AArch64);
|
Set(encoding, new Inst(emitter, type), ExecutionMode.Aarch64);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Set(string encoding, Inst inst, ExecutionMode mode)
|
private static void Set(string encoding, Inst inst, ExecutionMode mode)
|
||||||
|
@ -673,27 +671,55 @@ namespace ChocolArm64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InsertInst(
|
private static void InsertInst(int xMask, int value, Inst inst, ExecutionMode mode)
|
||||||
int xMask,
|
|
||||||
int value,
|
|
||||||
Inst inst,
|
|
||||||
ExecutionMode mode)
|
|
||||||
{
|
{
|
||||||
InstInfo info = new InstInfo(xMask, value, inst);
|
InstInfo info = new InstInfo(xMask, value, inst);
|
||||||
|
|
||||||
if (mode == ExecutionMode.AArch64)
|
switch (mode)
|
||||||
{
|
{
|
||||||
_allInstA64.Add(info);
|
case ExecutionMode.Aarch32Arm: _allInstA32.Add(info); break;
|
||||||
|
case ExecutionMode.Aarch32Thumb: _allInstT32.Add(info); break;
|
||||||
|
case ExecutionMode.Aarch64: _allInstA64.Add(info); break;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts)
|
||||||
|
{
|
||||||
|
List<InstInfo>[] tmp = new List<InstInfo>[FastLookupSize];
|
||||||
|
|
||||||
|
for (int i = 0; i < FastLookupSize; i++)
|
||||||
{
|
{
|
||||||
_allInstA32.Add(info);
|
tmp[i] = new List<InstInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (InstInfo inst in allInsts)
|
||||||
|
{
|
||||||
|
int mask = ToFastLookupIndex(inst.Mask);
|
||||||
|
int value = ToFastLookupIndex(inst.Value);
|
||||||
|
|
||||||
|
for (int i = 0; i < FastLookupSize; i++)
|
||||||
|
{
|
||||||
|
if ((i & mask) == value)
|
||||||
|
{
|
||||||
|
tmp[i].Add(inst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < FastLookupSize; i++)
|
||||||
|
{
|
||||||
|
table[i] = tmp[i].ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Inst GetInstA32(int opCode)
|
public static Inst GetInstA32(int opCode)
|
||||||
{
|
{
|
||||||
return GetInstFromList(_allInstA32, opCode);
|
return GetInstFromList(_instA32FastLookup[ToFastLookupIndex(opCode)], opCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Inst GetInstT32(int opCode)
|
||||||
|
{
|
||||||
|
return GetInstFromList(_instT32FastLookup[ToFastLookupIndex(opCode)], opCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Inst GetInstA64(int opCode)
|
public static Inst GetInstA64(int opCode)
|
||||||
|
@ -708,7 +734,7 @@ namespace ChocolArm64
|
||||||
|
|
||||||
private static Inst GetInstFromList(IEnumerable<InstInfo> instList, int opCode)
|
private static Inst GetInstFromList(IEnumerable<InstInfo> instList, int opCode)
|
||||||
{
|
{
|
||||||
foreach (var node in instList)
|
foreach (InstInfo node in instList)
|
||||||
{
|
{
|
||||||
if ((opCode & node.Mask) == node.Value)
|
if ((opCode & node.Mask) == node.Value)
|
||||||
{
|
{
|
||||||
|
|
15
ChocolArm64/State/Aarch32Mode.cs
Normal file
15
ChocolArm64/State/Aarch32Mode.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
namespace ChocolArm64.State
|
||||||
|
{
|
||||||
|
enum Aarch32Mode
|
||||||
|
{
|
||||||
|
User = 0b10000,
|
||||||
|
Fiq = 0b10001,
|
||||||
|
Irq = 0b10010,
|
||||||
|
Supervisor = 0b10011,
|
||||||
|
Monitor = 0b10110,
|
||||||
|
Abort = 0b10111,
|
||||||
|
Hypervisor = 0b11010,
|
||||||
|
Undefined = 0b11011,
|
||||||
|
System = 0b11111
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,25 +8,13 @@ namespace ChocolArm64.State
|
||||||
{
|
{
|
||||||
public class CpuThreadState
|
public class CpuThreadState
|
||||||
{
|
{
|
||||||
internal const int LrIndex = 30;
|
|
||||||
internal const int ZrIndex = 31;
|
|
||||||
|
|
||||||
internal const int ErgSizeLog2 = 4;
|
internal const int ErgSizeLog2 = 4;
|
||||||
internal const int DczSizeLog2 = 4;
|
internal const int DczSizeLog2 = 4;
|
||||||
|
|
||||||
private const int MinInstForCheck = 4000000;
|
private const int MinInstForCheck = 4000000;
|
||||||
|
|
||||||
internal ExecutionMode ExecutionMode;
|
|
||||||
|
|
||||||
//AArch32 state.
|
|
||||||
public uint R0, R1, R2, R3,
|
|
||||||
R4, R5, R6, R7,
|
|
||||||
R8, R9, R10, R11,
|
|
||||||
R12, R13, R14, R15;
|
|
||||||
|
|
||||||
public bool Thumb;
|
public bool Thumb;
|
||||||
|
|
||||||
//AArch64 state.
|
|
||||||
public ulong X0, X1, X2, X3, X4, X5, X6, X7,
|
public ulong X0, X1, X2, X3, X4, X5, X6, X7,
|
||||||
X8, X9, X10, X11, X12, X13, X14, X15,
|
X8, X9, X10, X11, X12, X13, X14, X15,
|
||||||
X16, X17, X18, X19, X20, X21, X22, X23,
|
X16, X17, X18, X19, X20, X21, X22, X23,
|
||||||
|
@ -42,6 +30,10 @@ namespace ChocolArm64.State
|
||||||
public bool Zero;
|
public bool Zero;
|
||||||
public bool Negative;
|
public bool Negative;
|
||||||
|
|
||||||
|
public bool IsAarch32;
|
||||||
|
|
||||||
|
public int ElrHyp;
|
||||||
|
|
||||||
public bool Running { get; set; }
|
public bool Running { get; set; }
|
||||||
public int Core { get; set; }
|
public int Core { get; set; }
|
||||||
|
|
||||||
|
@ -146,6 +138,18 @@ namespace ChocolArm64.State
|
||||||
Undefined?.Invoke(this, new InstUndefinedEventArgs(position, rawOpCode));
|
Undefined?.Invoke(this, new InstUndefinedEventArgs(position, rawOpCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal ExecutionMode GetExecutionMode()
|
||||||
|
{
|
||||||
|
if (!IsAarch32)
|
||||||
|
{
|
||||||
|
return ExecutionMode.Aarch64;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Thumb ? ExecutionMode.Aarch32Thumb : ExecutionMode.Aarch32Arm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal bool GetFpcrFlag(Fpcr flag)
|
internal bool GetFpcrFlag(Fpcr flag)
|
||||||
{
|
{
|
||||||
return (Fpcr & (1 << (int)flag)) != 0;
|
return (Fpcr & (1 << (int)flag)) != 0;
|
||||||
|
|
|
@ -2,7 +2,8 @@ namespace ChocolArm64.State
|
||||||
{
|
{
|
||||||
enum ExecutionMode
|
enum ExecutionMode
|
||||||
{
|
{
|
||||||
AArch32,
|
Aarch64,
|
||||||
AArch64
|
Aarch32Arm,
|
||||||
|
Aarch32Thumb
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -5,11 +5,15 @@ namespace ChocolArm64.State
|
||||||
[Flags]
|
[Flags]
|
||||||
enum PState
|
enum PState
|
||||||
{
|
{
|
||||||
|
TBit = 5,
|
||||||
|
|
||||||
VBit = 28,
|
VBit = 28,
|
||||||
CBit = 29,
|
CBit = 29,
|
||||||
ZBit = 30,
|
ZBit = 30,
|
||||||
NBit = 31,
|
NBit = 31,
|
||||||
|
|
||||||
|
T = 1 << TBit,
|
||||||
|
|
||||||
V = 1 << VBit,
|
V = 1 << VBit,
|
||||||
C = 1 << CBit,
|
C = 1 << CBit,
|
||||||
Z = 1 << ZBit,
|
Z = 1 << ZBit,
|
||||||
|
|
|
@ -43,6 +43,8 @@ namespace ChocolArm64.State
|
||||||
{
|
{
|
||||||
switch ((PState)Index)
|
switch ((PState)Index)
|
||||||
{
|
{
|
||||||
|
case PState.TBit: return GetField(nameof(CpuThreadState.Thumb));
|
||||||
|
|
||||||
case PState.VBit: return GetField(nameof(CpuThreadState.Overflow));
|
case PState.VBit: return GetField(nameof(CpuThreadState.Overflow));
|
||||||
case PState.CBit: return GetField(nameof(CpuThreadState.Carry));
|
case PState.CBit: return GetField(nameof(CpuThreadState.Carry));
|
||||||
case PState.ZBit: return GetField(nameof(CpuThreadState.Zero));
|
case PState.ZBit: return GetField(nameof(CpuThreadState.Zero));
|
||||||
|
|
41
ChocolArm64/State/RegisterAlias.cs
Normal file
41
ChocolArm64/State/RegisterAlias.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
namespace ChocolArm64.State
|
||||||
|
{
|
||||||
|
static class RegisterAlias
|
||||||
|
{
|
||||||
|
public const int R8Usr = 8;
|
||||||
|
public const int R9Usr = 9;
|
||||||
|
public const int R10Usr = 10;
|
||||||
|
public const int R11Usr = 11;
|
||||||
|
public const int R12Usr = 12;
|
||||||
|
public const int SpUsr = 13;
|
||||||
|
public const int LrUsr = 14;
|
||||||
|
|
||||||
|
public const int SpHyp = 15;
|
||||||
|
|
||||||
|
public const int LrIrq = 16;
|
||||||
|
public const int SpIrq = 17;
|
||||||
|
|
||||||
|
public const int LrSvc = 18;
|
||||||
|
public const int SpSvc = 19;
|
||||||
|
|
||||||
|
public const int LrAbt = 20;
|
||||||
|
public const int SpAbt = 21;
|
||||||
|
|
||||||
|
public const int LrUnd = 22;
|
||||||
|
public const int SpUnd = 23;
|
||||||
|
|
||||||
|
public const int R8Fiq = 24;
|
||||||
|
public const int R9Fiq = 25;
|
||||||
|
public const int R10Fiq = 26;
|
||||||
|
public const int R11Fiq = 27;
|
||||||
|
public const int R12Fiq = 28;
|
||||||
|
public const int SpFiq = 29;
|
||||||
|
public const int LrFiq = 30;
|
||||||
|
|
||||||
|
public const int Aarch32Lr = 14;
|
||||||
|
public const int Aarch32Pc = 15;
|
||||||
|
|
||||||
|
public const int Lr = 30;
|
||||||
|
public const int Zr = 31;
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,8 @@ namespace ChocolArm64.Translation
|
||||||
public Block CurrBlock => _currBlock;
|
public Block CurrBlock => _currBlock;
|
||||||
public OpCode64 CurrOp => _currBlock?.OpCodes[_opcIndex];
|
public OpCode64 CurrOp => _currBlock?.OpCodes[_opcIndex];
|
||||||
|
|
||||||
|
public Aarch32Mode Mode { get; } = Aarch32Mode.User; //TODO
|
||||||
|
|
||||||
private Dictionary<Block, ILBlock> _visitedBlocks;
|
private Dictionary<Block, ILBlock> _visitedBlocks;
|
||||||
|
|
||||||
private Queue<Block> _branchTargets;
|
private Queue<Block> _branchTargets;
|
||||||
|
@ -97,11 +99,52 @@ namespace ChocolArm64.Translation
|
||||||
EmitSynchronization();
|
EmitSynchronization();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//On AARCH32 mode, (almost) all instruction can be conditionally
|
||||||
|
//executed, and the required condition is encoded on the opcode.
|
||||||
|
//We handle that here, skipping the instruction if the condition
|
||||||
|
//is not met. We can just ignore it when the condition is "Always",
|
||||||
|
//because in this case the instruction is always going to be executed.
|
||||||
|
//Condition "Never" is also ignored because this is a special encoding
|
||||||
|
//used by some unconditional instructions.
|
||||||
|
ILLabel lblSkip = null;
|
||||||
|
|
||||||
|
if (CurrOp is OpCode32 op && op.Cond < Condition.Al)
|
||||||
|
{
|
||||||
|
lblSkip = new ILLabel();
|
||||||
|
|
||||||
|
EmitCondBranch(lblSkip, GetInverseCond(op.Cond));
|
||||||
|
}
|
||||||
|
|
||||||
CurrOp.Emitter(this);
|
CurrOp.Emitter(this);
|
||||||
|
|
||||||
|
if (lblSkip != null)
|
||||||
|
{
|
||||||
|
MarkLabel(lblSkip);
|
||||||
|
|
||||||
|
//If this is the last op on the block, and there's no "next" block
|
||||||
|
//after this one, then we have to return right now, with the address
|
||||||
|
//of the next instruction to be executed (in the case that the condition
|
||||||
|
//is false, and the branch was not taken, as all basic blocks should end with
|
||||||
|
//some kind of branch).
|
||||||
|
if (CurrOp == CurrBlock.GetLastOp() && CurrBlock.Next == null)
|
||||||
|
{
|
||||||
|
EmitStoreState();
|
||||||
|
EmitLdc_I8(CurrOp.Position + CurrOp.OpCodeSizeInBytes);
|
||||||
|
|
||||||
|
Emit(OpCodes.Ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ilBlock.Add(new ILBarrier());
|
_ilBlock.Add(new ILBarrier());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Condition GetInverseCond(Condition cond)
|
||||||
|
{
|
||||||
|
//Bit 0 of all conditions is basically a negation bit, so
|
||||||
|
//inverting this bit has the effect of inverting the condition.
|
||||||
|
return (Condition)((int)cond ^ 1);
|
||||||
|
}
|
||||||
|
|
||||||
private void EmitSynchronization()
|
private void EmitSynchronization()
|
||||||
{
|
{
|
||||||
EmitLdarg(TranslatedSub.StateArgIdx);
|
EmitLdarg(TranslatedSub.StateArgIdx);
|
||||||
|
@ -243,27 +286,27 @@ namespace ChocolArm64.Translation
|
||||||
{
|
{
|
||||||
_optOpLastCompare = CurrOp;
|
_optOpLastCompare = CurrOp;
|
||||||
|
|
||||||
InstEmitAluHelper.EmitDataLoadOpers(this);
|
InstEmitAluHelper.EmitAluLoadOpers(this);
|
||||||
|
|
||||||
Stloc(CmpOptTmp2Index, IoType.Int);
|
Stloc(CmpOptTmp2Index, IoType.Int);
|
||||||
Stloc(CmpOptTmp1Index, IoType.Int);
|
Stloc(CmpOptTmp1Index, IoType.Int);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Dictionary<Cond, OpCode> _branchOps = new Dictionary<Cond, OpCode>()
|
private Dictionary<Condition, OpCode> _branchOps = new Dictionary<Condition, OpCode>()
|
||||||
{
|
{
|
||||||
{ Cond.Eq, OpCodes.Beq },
|
{ Condition.Eq, OpCodes.Beq },
|
||||||
{ Cond.Ne, OpCodes.Bne_Un },
|
{ Condition.Ne, OpCodes.Bne_Un },
|
||||||
{ Cond.GeUn, OpCodes.Bge_Un },
|
{ Condition.GeUn, OpCodes.Bge_Un },
|
||||||
{ Cond.LtUn, OpCodes.Blt_Un },
|
{ Condition.LtUn, OpCodes.Blt_Un },
|
||||||
{ Cond.GtUn, OpCodes.Bgt_Un },
|
{ Condition.GtUn, OpCodes.Bgt_Un },
|
||||||
{ Cond.LeUn, OpCodes.Ble_Un },
|
{ Condition.LeUn, OpCodes.Ble_Un },
|
||||||
{ Cond.Ge, OpCodes.Bge },
|
{ Condition.Ge, OpCodes.Bge },
|
||||||
{ Cond.Lt, OpCodes.Blt },
|
{ Condition.Lt, OpCodes.Blt },
|
||||||
{ Cond.Gt, OpCodes.Bgt },
|
{ Condition.Gt, OpCodes.Bgt },
|
||||||
{ Cond.Le, OpCodes.Ble }
|
{ Condition.Le, OpCodes.Ble }
|
||||||
};
|
};
|
||||||
|
|
||||||
public void EmitCondBranch(ILLabel target, Cond cond)
|
public void EmitCondBranch(ILLabel target, Condition cond)
|
||||||
{
|
{
|
||||||
OpCode ilOp;
|
OpCode ilOp;
|
||||||
|
|
||||||
|
@ -432,7 +475,7 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public void EmitLdintzr(int index)
|
public void EmitLdintzr(int index)
|
||||||
{
|
{
|
||||||
if (index != CpuThreadState.ZrIndex)
|
if (index != RegisterAlias.Zr)
|
||||||
{
|
{
|
||||||
EmitLdint(index);
|
EmitLdint(index);
|
||||||
}
|
}
|
||||||
|
@ -444,7 +487,7 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public void EmitStintzr(int index)
|
public void EmitStintzr(int index)
|
||||||
{
|
{
|
||||||
if (index != CpuThreadState.ZrIndex)
|
if (index != RegisterAlias.Zr)
|
||||||
{
|
{
|
||||||
EmitStint(index);
|
EmitStint(index);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ using ChocolArm64.Memory;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using ChocolArm64.Translation;
|
using ChocolArm64.Translation;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection.Emit;
|
|
||||||
|
|
||||||
namespace ChocolArm64
|
namespace ChocolArm64
|
||||||
{
|
{
|
||||||
|
@ -23,34 +22,10 @@ namespace ChocolArm64
|
||||||
|
|
||||||
internal void ExecuteSubroutine(CpuThread thread, long position)
|
internal void ExecuteSubroutine(CpuThread thread, long position)
|
||||||
{
|
{
|
||||||
//TODO: Both the execute A32/A64 methods should be merged on the future,
|
ExecuteSubroutine(thread.ThreadState, thread.Memory, position);
|
||||||
//when both ISAs are implemented with the interpreter and JIT.
|
|
||||||
//As of now, A32 only has a interpreter and A64 a JIT.
|
|
||||||
CpuThreadState state = thread.ThreadState;
|
|
||||||
MemoryManager memory = thread.Memory;
|
|
||||||
|
|
||||||
if (state.ExecutionMode == ExecutionMode.AArch32)
|
|
||||||
{
|
|
||||||
ExecuteSubroutineA32(state, memory);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ExecuteSubroutineA64(state, memory, position);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecuteSubroutineA32(CpuThreadState state, MemoryManager memory)
|
private void ExecuteSubroutine(CpuThreadState state, MemoryManager memory, long position)
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
OpCode64 opCode = Decoder.DecodeOpCode(state, memory, state.R15);
|
|
||||||
|
|
||||||
opCode.Interpreter(state, memory, opCode);
|
|
||||||
}
|
|
||||||
while (state.R15 != 0 && state.Running);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExecuteSubroutineA64(CpuThreadState state, MemoryManager memory, long position)
|
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -61,12 +36,12 @@ namespace ChocolArm64
|
||||||
|
|
||||||
if (!_cache.TryGetSubroutine(position, out TranslatedSub sub))
|
if (!_cache.TryGetSubroutine(position, out TranslatedSub sub))
|
||||||
{
|
{
|
||||||
sub = TranslateTier0(state, memory, position);
|
sub = TranslateTier0(memory, position, state.GetExecutionMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sub.ShouldReJit())
|
if (sub.ShouldReJit())
|
||||||
{
|
{
|
||||||
TranslateTier1(state, memory, position);
|
TranslateTier1(memory, position, state.GetExecutionMode());
|
||||||
}
|
}
|
||||||
|
|
||||||
position = sub.Execute(state, memory);
|
position = sub.Execute(state, memory);
|
||||||
|
@ -79,9 +54,9 @@ namespace ChocolArm64
|
||||||
return _cache.HasSubroutine(position);
|
return _cache.HasSubroutine(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TranslatedSub TranslateTier0(CpuThreadState state, MemoryManager memory, long position)
|
private TranslatedSub TranslateTier0(MemoryManager memory, long position, ExecutionMode mode)
|
||||||
{
|
{
|
||||||
Block block = Decoder.DecodeBasicBlock(state, memory, position);
|
Block block = Decoder.DecodeBasicBlock(memory, position, mode);
|
||||||
|
|
||||||
ILEmitterCtx context = new ILEmitterCtx(_cache, block);
|
ILEmitterCtx context = new ILEmitterCtx(_cache, block);
|
||||||
|
|
||||||
|
@ -98,9 +73,9 @@ namespace ChocolArm64
|
||||||
return subroutine;
|
return subroutine;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TranslateTier1(CpuThreadState state, MemoryManager memory, long position)
|
private void TranslateTier1(MemoryManager memory, long position, ExecutionMode mode)
|
||||||
{
|
{
|
||||||
Block graph = Decoder.DecodeSubroutine(_cache, state, memory, position);
|
Block graph = Decoder.DecodeSubroutine(_cache, memory, position, mode);
|
||||||
|
|
||||||
ILEmitterCtx context = new ILEmitterCtx(_cache, graph);
|
ILEmitterCtx context = new ILEmitterCtx(_cache, graph);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
|
@ -225,11 +225,6 @@ namespace Ryujinx.HLE.HOS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!metaData.Is64Bits)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("32-bit titles are unsupported!");
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
|
CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
|
||||||
|
|
||||||
LoadNso("rtld");
|
LoadNso("rtld");
|
||||||
|
@ -428,11 +423,6 @@ namespace Ryujinx.HLE.HOS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!metaData.Is64Bits)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("32-bit titles are unsupported!");
|
|
||||||
}
|
|
||||||
|
|
||||||
CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
|
CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
|
||||||
|
|
||||||
LoadNso("rtld");
|
LoadNso("rtld");
|
||||||
|
@ -543,11 +533,6 @@ namespace Ryujinx.HLE.HOS
|
||||||
CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
|
CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!metaData.Is64Bits)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException("32-bit titles are not supported!");
|
|
||||||
}
|
|
||||||
|
|
||||||
LoadNso("rtld");
|
LoadNso("rtld");
|
||||||
LoadNso("main");
|
LoadNso("main");
|
||||||
LoadNso("subsdk");
|
LoadNso("subsdk");
|
||||||
|
|
|
@ -78,6 +78,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: ARM32.
|
||||||
long framePointer = (long)threadState.X29;
|
long framePointer = (long)threadState.X29;
|
||||||
|
|
||||||
while (framePointer != 0)
|
while (framePointer != 0)
|
||||||
|
@ -245,6 +246,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
long ehHdrEndOffset = memory.ReadInt32(mod0Offset + 0x14) + mod0Offset;
|
long ehHdrEndOffset = memory.ReadInt32(mod0Offset + 0x14) + mod0Offset;
|
||||||
long modObjOffset = memory.ReadInt32(mod0Offset + 0x18) + mod0Offset;
|
long modObjOffset = memory.ReadInt32(mod0Offset + 0x18) + mod0Offset;
|
||||||
|
|
||||||
|
//TODO: Elf32.
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
long tagVal = memory.ReadInt64(dynamicOffset + 0);
|
long tagVal = memory.ReadInt64(dynamicOffset + 0);
|
||||||
|
|
|
@ -3,6 +3,7 @@ using ChocolArm64.Events;
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.HLE.Exceptions;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
|
using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
|
||||||
|
@ -797,6 +798,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
context.ThreadState.Interrupt += InterruptHandler;
|
context.ThreadState.Interrupt += InterruptHandler;
|
||||||
context.ThreadState.SvcCall += _svcHandler.SvcCall;
|
context.ThreadState.SvcCall += _svcHandler.SvcCall;
|
||||||
|
context.ThreadState.Undefined += UndefinedInstructionHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InterruptHandler(object sender, EventArgs e)
|
private void InterruptHandler(object sender, EventArgs e)
|
||||||
|
@ -1021,5 +1023,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||||
{
|
{
|
||||||
Logger.PrintInfo(LogClass.Cpu, $"Executing at 0x{e.Position:X16}.");
|
Logger.PrintInfo(LogClass.Cpu, $"Executing at 0x{e.Position:X16}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UndefinedInstructionHandler(object sender, InstUndefinedEventArgs e)
|
||||||
|
{
|
||||||
|
throw new UndefinedInstructionException(e.Position, e.RawOpCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -152,6 +152,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||||
|
|
||||||
Context = new CpuThread(owner.Translator, owner.CpuMemory, (long)entrypoint);
|
Context = new CpuThread(owner.Translator, owner.CpuMemory, (long)entrypoint);
|
||||||
|
|
||||||
|
Context.ThreadState.IsAarch32 = (Owner.MmuFlags & 1) == 0;
|
||||||
|
|
||||||
Context.ThreadState.X0 = argsPtr;
|
Context.ThreadState.X0 = argsPtr;
|
||||||
Context.ThreadState.X31 = stackTop;
|
Context.ThreadState.X31 = stackTop;
|
||||||
|
|
||||||
|
|
|
@ -125,9 +125,14 @@ namespace Ryujinx.HLE.HOS
|
||||||
IExecutable[] staticObjects,
|
IExecutable[] staticObjects,
|
||||||
byte[] arguments = null)
|
byte[] arguments = null)
|
||||||
{
|
{
|
||||||
|
if (!metaData.Is64Bits)
|
||||||
|
{
|
||||||
|
Logger.PrintWarning(LogClass.Loader, "32-bits application detected!");
|
||||||
|
}
|
||||||
|
|
||||||
ulong argsStart = 0;
|
ulong argsStart = 0;
|
||||||
int argsSize = 0;
|
int argsSize = 0;
|
||||||
ulong codeStart = 0x8000000;
|
ulong codeStart = metaData.Is64Bits ? 0x8000000UL : 0x200000UL;
|
||||||
int codeSize = 0;
|
int codeSize = 0;
|
||||||
|
|
||||||
ulong[] nsoBase = new ulong[staticObjects.Length];
|
ulong[] nsoBase = new ulong[staticObjects.Length];
|
||||||
|
|
Loading…
Reference in a new issue