aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2019-01-24 23:59:53 -0200
committerGitHub <noreply@github.com>2019-01-24 23:59:53 -0200
commit36b9ab0e48b6893c057a954e1ef3181b452add1c (patch)
tree16a4ae56019b55d0cb61f1aa105481933ada733e
parent72157e03eb09d4fb5d6d004efc2d13d3194e8c90 (diff)
Add ARM32 support on the translator (#561)
* Remove ARM32 interpreter and add ARM32 support on the translator * Nits. * Rename Cond -> Condition * Align code again * Rename Data to Alu * Enable ARM32 support and handle undefined instructions * Use the IsThumb method to check if its a thumb opcode * Remove another 32-bits check
-rw-r--r--ChocolArm64/CpuThread.cs2
-rw-r--r--ChocolArm64/Decoders/BitUtils.cs (renamed from ChocolArm64/BitUtils.cs)12
-rw-r--r--ChocolArm64/Decoders/Condition.cs (renamed from ChocolArm64/Decoders/Cond.cs)2
-rw-r--r--ChocolArm64/Decoders/Decoder.cs67
-rw-r--r--ChocolArm64/Decoders/DecoderHelper.cs5
-rw-r--r--ChocolArm64/Decoders/IOpCode32.cs9
-rw-r--r--ChocolArm64/Decoders/IOpCodeAlu32.cs10
-rw-r--r--ChocolArm64/Decoders/IOpCodeBImm.cs7
-rw-r--r--ChocolArm64/Decoders/IOpCodeBImm32.cs4
-rw-r--r--ChocolArm64/Decoders/IOpCodeBReg32.cs7
-rw-r--r--ChocolArm64/Decoders/IOpCodeCond64.cs2
-rw-r--r--ChocolArm64/Decoders/OpCode32.cs24
-rw-r--r--ChocolArm64/Decoders/OpCode64.cs10
-rw-r--r--ChocolArm64/Decoders/OpCodeAlu32.cs20
-rw-r--r--ChocolArm64/Decoders/OpCodeAluImm32.cs21
-rw-r--r--ChocolArm64/Decoders/OpCodeAluImm8T16.cs22
-rw-r--r--ChocolArm64/Decoders/OpCodeAluRsImm32.cs20
-rw-r--r--ChocolArm64/Decoders/OpCodeBImm32.cs29
-rw-r--r--ChocolArm64/Decoders/OpCodeBImm64.cs2
-rw-r--r--ChocolArm64/Decoders/OpCodeBImmCond64.cs4
-rw-r--r--ChocolArm64/Decoders/OpCodeBReg32.cs14
-rw-r--r--ChocolArm64/Decoders/OpCodeBRegT16.cs14
-rw-r--r--ChocolArm64/Decoders/OpCodeCcmp64.cs10
-rw-r--r--ChocolArm64/Decoders/OpCodeCsel64.cs6
-rw-r--r--ChocolArm64/Decoders/OpCodeSimdFcond64.cs6
-rw-r--r--ChocolArm64/Decoders/OpCodeT16.cs14
-rw-r--r--ChocolArm64/Decoders32/A32OpCode.cs15
-rw-r--r--ChocolArm64/Decoders32/A32OpCodeBImmAl.cs16
-rw-r--r--ChocolArm64/Instructions/Inst.cs14
-rw-r--r--ChocolArm64/Instructions/InstEmit32Helper.cs99
-rw-r--r--ChocolArm64/Instructions/InstEmitAlu.cs107
-rw-r--r--ChocolArm64/Instructions/InstEmitAlu32.cs123
-rw-r--r--ChocolArm64/Instructions/InstEmitAluHelper.cs317
-rw-r--r--ChocolArm64/Instructions/InstEmitCcmp.cs2
-rw-r--r--ChocolArm64/Instructions/InstEmitFlow.cs36
-rw-r--r--ChocolArm64/Instructions/InstEmitFlow32.cs99
-rw-r--r--ChocolArm64/Instructions/InstEmitFlowHelper.cs39
-rw-r--r--ChocolArm64/Instructions/InstEmitSimdMemory.cs2
-rw-r--r--ChocolArm64/Instructions/InstInterpreter.cs8
-rw-r--r--ChocolArm64/Instructions32/A32InstInterpretAlu.cs7
-rw-r--r--ChocolArm64/Instructions32/A32InstInterpretFlow.cs70
-rw-r--r--ChocolArm64/Instructions32/A32InstInterpretHelper.cs65
-rw-r--r--ChocolArm64/OpCodeTable.cs150
-rw-r--r--ChocolArm64/State/Aarch32Mode.cs15
-rw-r--r--ChocolArm64/State/CpuThreadState.cs28
-rw-r--r--ChocolArm64/State/ExecutionMode.cs5
-rw-r--r--ChocolArm64/State/PState.cs4
-rw-r--r--ChocolArm64/State/Register.cs2
-rw-r--r--ChocolArm64/State/RegisterAlias.cs41
-rw-r--r--ChocolArm64/Translation/ILEmitterCtx.cs73
-rw-r--r--ChocolArm64/Translator.cs41
-rw-r--r--ChocolArm64/TranslatorCache.cs1
-rw-r--r--Ryujinx.HLE/HOS/Horizon.cs15
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs2
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs7
-rw-r--r--Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs2
-rw-r--r--Ryujinx.HLE/HOS/ProgramLoader.cs7
57 files changed, 1267 insertions, 488 deletions
diff --git a/ChocolArm64/CpuThread.cs b/ChocolArm64/CpuThread.cs
index dac376a1..87b21395 100644
--- a/ChocolArm64/CpuThread.cs
+++ b/ChocolArm64/CpuThread.cs
@@ -25,8 +25,6 @@ namespace ChocolArm64
ThreadState = new CpuThreadState();
- ThreadState.ExecutionMode = ExecutionMode.AArch64;
-
ThreadState.Running = true;
Work = new Thread(delegate()
diff --git a/ChocolArm64/BitUtils.cs b/ChocolArm64/Decoders/BitUtils.cs
index 881ee248..8b9fb5e3 100644
--- a/ChocolArm64/BitUtils.cs
+++ b/ChocolArm64/Decoders/BitUtils.cs
@@ -1,4 +1,4 @@
-namespace ChocolArm64
+namespace ChocolArm64.Decoders
{
static class BitUtils
{
@@ -36,6 +36,16 @@ namespace ChocolArm64
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)
{
return (long)RotateRight((ulong)bits, shift, size);
diff --git a/ChocolArm64/Decoders/Cond.cs b/ChocolArm64/Decoders/Condition.cs
index 57e12cd6..d1aa5772 100644
--- a/ChocolArm64/Decoders/Cond.cs
+++ b/ChocolArm64/Decoders/Condition.cs
@@ -1,6 +1,6 @@
namespace ChocolArm64.Decoders
{
- enum Cond
+ enum Condition
{
Eq = 0,
Ne = 1,
diff --git a/ChocolArm64/Decoders/Decoder.cs b/ChocolArm64/Decoders/Decoder.cs
index 1d4f397a..6c60e1fe 100644
--- a/ChocolArm64/Decoders/Decoder.cs
+++ b/ChocolArm64/Decoders/Decoder.cs
@@ -19,20 +19,20 @@ namespace ChocolArm64.Decoders
_opActivators = new ConcurrentDictionary<Type, OpActivator>();
}
- public static Block DecodeBasicBlock(CpuThreadState state, MemoryManager memory, long start)
+ public static Block DecodeBasicBlock(MemoryManager memory, long start, ExecutionMode mode)
{
Block block = new Block(start);
- FillBlock(state, memory, block);
+ FillBlock(memory, mode, block);
return block;
}
public static Block DecodeSubroutine(
TranslatorCache cache,
- CpuThreadState state,
MemoryManager memory,
- long start)
+ long start,
+ ExecutionMode mode)
{
Dictionary<long, Block> visited = new Dictionary<long, Block>();
Dictionary<long, Block> visitedEnd = new Dictionary<long, Block>();
@@ -59,7 +59,7 @@ namespace ChocolArm64.Decoders
{
Block current = blocks.Dequeue();
- FillBlock(state, memory, current);
+ FillBlock(memory, mode, current);
//Set child blocks. "Branch" is the block the branch instruction
//points to (when taken), "Next" is the block at the next address,
@@ -71,7 +71,7 @@ namespace ChocolArm64.Decoders
OpCode64 lastOp = current.GetLastOp();
- if (lastOp is OpCodeBImm64 op)
+ if (lastOp is IOpCodeBImm op)
{
if (op.Emitter == InstEmit.Bl)
{
@@ -83,8 +83,7 @@ namespace ChocolArm64.Decoders
}
}
- if (!((lastOp is OpCodeBImmAl64) ||
- (lastOp is OpCodeBReg64)) || hasCachedSub)
+ if (!IsUnconditionalBranch(lastOp) || hasCachedSub)
{
current.Next = Enqueue(current.EndPosition);
}
@@ -121,7 +120,7 @@ namespace ChocolArm64.Decoders
return entry;
}
- private static void FillBlock(CpuThreadState state, MemoryManager memory, Block block)
+ private static void FillBlock(MemoryManager memory, ExecutionMode mode, Block block)
{
long position = block.Position;
@@ -129,13 +128,11 @@ namespace ChocolArm64.Decoders
do
{
- //TODO: This needs to be changed to support both AArch32 and AArch64,
- //once JIT support is introduced on AArch32 aswell.
- opCode = DecodeOpCode(state, memory, position);
+ opCode = DecodeOpCode(memory, position, mode);
block.OpCodes.Add(opCode);
- position += 4;
+ position += opCode.OpCodeSizeInBytes;
}
while (!(IsBranch(opCode) || IsException(opCode)));
@@ -145,7 +142,35 @@ namespace ChocolArm64.Decoders
private static bool IsBranch(OpCode64 opCode)
{
return opCode is OpCodeBImm64 ||
- opCode is OpCodeBReg64;
+ opCode is OpCodeBReg64 || IsAarch32Branch(opCode);
+ }
+
+ private static bool IsUnconditionalBranch(OpCode64 opCode)
+ {
+ return opCode is OpCodeBImmAl64 ||
+ opCode is OpCodeBReg64 || IsAarch32UnconditionalBranch(opCode);
+ }
+
+ private static bool IsAarch32UnconditionalBranch(OpCode64 opCode)
+ {
+ if (!(opCode is OpCode32 op))
+ {
+ return false;
+ }
+
+ //Note: On ARM32, most instructions have conditional execution,
+ //so there's no "Always" (unconditional) branch like on ARM64.
+ //We need to check if the condition is "Always" instead.
+ return IsAarch32Branch(op) && op.Cond >= Condition.Al;
+ }
+
+ private static bool IsAarch32Branch(OpCode64 opCode)
+ {
+ //Note: On ARM32, most ALU operations can write to R15 (PC),
+ //so we must consider such operations as a branch in potential aswell.
+ return opCode is IOpCodeBImm32 ||
+ opCode is IOpCodeBReg32 ||
+ (opCode is IOpCodeAlu32 op && op.Rd == RegisterAlias.Aarch32Pc);
}
private static bool IsException(OpCode64 opCode)
@@ -155,20 +180,26 @@ namespace ChocolArm64.Decoders
opCode.Emitter == InstEmit.Und;
}
- public static OpCode64 DecodeOpCode(CpuThreadState state, MemoryManager memory, long position)
+ public static OpCode64 DecodeOpCode(MemoryManager memory, long position, ExecutionMode mode)
{
int opCode = memory.ReadInt32(position);
Inst inst;
- if (state.ExecutionMode == ExecutionMode.AArch64)
+ if (mode == ExecutionMode.Aarch64)
{
inst = OpCodeTable.GetInstA64(opCode);
}
else
{
- //TODO: Thumb support.
- inst = OpCodeTable.GetInstA32(opCode);
+ if (mode == ExecutionMode.Aarch32Arm)
+ {
+ inst = OpCodeTable.GetInstA32(opCode);
+ }
+ else /* if (mode == ExecutionMode.Aarch32Thumb) */
+ {
+ inst = OpCodeTable.GetInstT32(opCode);
+ }
}
OpCode64 decodedOpCode = new OpCode64(Inst.Undefined, position, opCode);
diff --git a/ChocolArm64/Decoders/DecoderHelper.cs b/ChocolArm64/Decoders/DecoderHelper.cs
index 6ee279d7..2209472b 100644
--- a/ChocolArm64/Decoders/DecoderHelper.cs
+++ b/ChocolArm64/Decoders/DecoderHelper.cs
@@ -89,6 +89,11 @@ namespace ChocolArm64.Decoders
return value;
}
+ public static long DecodeImm24_2(int opCode)
+ {
+ return ((long)opCode << 40) >> 38;
+ }
+
public static long DecodeImm26_2(int opCode)
{
return ((long)opCode << 38) >> 36;
diff --git a/ChocolArm64/Decoders/IOpCode32.cs b/ChocolArm64/Decoders/IOpCode32.cs
new file mode 100644
index 00000000..3353ffe8
--- /dev/null
+++ b/ChocolArm64/Decoders/IOpCode32.cs
@@ -0,0 +1,9 @@
+namespace ChocolArm64.Decoders
+{
+ interface IOpCode32 : IOpCode64
+ {
+ Condition Cond { get; }
+
+ uint GetPc();
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/IOpCodeAlu32.cs b/ChocolArm64/Decoders/IOpCodeAlu32.cs
new file mode 100644
index 00000000..9a464886
--- /dev/null
+++ b/ChocolArm64/Decoders/IOpCodeAlu32.cs
@@ -0,0 +1,10 @@
+namespace ChocolArm64.Decoders
+{
+ interface IOpCodeAlu32 : IOpCode32
+ {
+ int Rd { get; }
+ int Rn { get; }
+
+ bool SetFlags { get; }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/IOpCodeBImm.cs b/ChocolArm64/Decoders/IOpCodeBImm.cs
new file mode 100644
index 00000000..f0c6a832
--- /dev/null
+++ b/ChocolArm64/Decoders/IOpCodeBImm.cs
@@ -0,0 +1,7 @@
+namespace ChocolArm64.Decoders
+{
+ interface IOpCodeBImm : IOpCode64
+ {
+ long Imm { get; }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/IOpCodeBImm32.cs b/ChocolArm64/Decoders/IOpCodeBImm32.cs
new file mode 100644
index 00000000..cc8248f2
--- /dev/null
+++ b/ChocolArm64/Decoders/IOpCodeBImm32.cs
@@ -0,0 +1,4 @@
+namespace ChocolArm64.Decoders
+{
+ interface IOpCodeBImm32 : IOpCode32, IOpCodeBImm { }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/IOpCodeBReg32.cs b/ChocolArm64/Decoders/IOpCodeBReg32.cs
new file mode 100644
index 00000000..fb9d94ea
--- /dev/null
+++ b/ChocolArm64/Decoders/IOpCodeBReg32.cs
@@ -0,0 +1,7 @@
+namespace ChocolArm64.Decoders
+{
+ interface IOpCodeBReg32 : IOpCode32
+ {
+ int Rm { get; }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/IOpCodeCond64.cs b/ChocolArm64/Decoders/IOpCodeCond64.cs
index 9c39d633..2c465406 100644
--- a/ChocolArm64/Decoders/IOpCodeCond64.cs
+++ b/ChocolArm64/Decoders/IOpCodeCond64.cs
@@ -2,6 +2,6 @@ namespace ChocolArm64.Decoders
{
interface IOpCodeCond64 : IOpCode64
{
- Cond Cond { get; }
+ Condition Cond { get; }
}
} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCode32.cs b/ChocolArm64/Decoders/OpCode32.cs
new file mode 100644
index 00000000..8534b78f
--- /dev/null
+++ b/ChocolArm64/Decoders/OpCode32.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCode64.cs b/ChocolArm64/Decoders/OpCode64.cs
index b2dc363b..1072228e 100644
--- a/ChocolArm64/Decoders/OpCode64.cs
+++ b/ChocolArm64/Decoders/OpCode64.cs
@@ -9,9 +9,10 @@ namespace ChocolArm64.Decoders
public long Position { get; private set; }
public int RawOpCode { get; private set; }
- public InstEmitter Emitter { get; protected set; }
- public InstInterpreter Interpreter { get; protected set; }
- public RegisterSize RegisterSize { get; protected set; }
+ public int OpCodeSizeInBytes { get; protected set; } = 4;
+
+ public InstEmitter Emitter { get; protected set; }
+ public RegisterSize RegisterSize { get; protected set; }
public OpCode64(Inst inst, long position, int opCode)
{
@@ -20,8 +21,7 @@ namespace ChocolArm64.Decoders
RegisterSize = RegisterSize.Int64;
- Emitter = inst.Emitter;
- Interpreter = inst.Interpreter;
+ Emitter = inst.Emitter;
}
public int GetBitsCount()
diff --git a/ChocolArm64/Decoders/OpCodeAlu32.cs b/ChocolArm64/Decoders/OpCodeAlu32.cs
new file mode 100644
index 00000000..9612d9c2
--- /dev/null
+++ b/ChocolArm64/Decoders/OpCodeAlu32.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCodeAluImm32.cs b/ChocolArm64/Decoders/OpCodeAluImm32.cs
new file mode 100644
index 00000000..22436709
--- /dev/null
+++ b/ChocolArm64/Decoders/OpCodeAluImm32.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCodeAluImm8T16.cs b/ChocolArm64/Decoders/OpCodeAluImm8T16.cs
new file mode 100644
index 00000000..beb6dcaa
--- /dev/null
+++ b/ChocolArm64/Decoders/OpCodeAluImm8T16.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCodeAluRsImm32.cs b/ChocolArm64/Decoders/OpCodeAluRsImm32.cs
new file mode 100644
index 00000000..7b860448
--- /dev/null
+++ b/ChocolArm64/Decoders/OpCodeAluRsImm32.cs
@@ -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);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCodeBImm32.cs b/ChocolArm64/Decoders/OpCodeBImm32.cs
new file mode 100644
index 00000000..127ac174
--- /dev/null
+++ b/ChocolArm64/Decoders/OpCodeBImm32.cs
@@ -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;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCodeBImm64.cs b/ChocolArm64/Decoders/OpCodeBImm64.cs
index 71c61bab..bb5326ce 100644
--- a/ChocolArm64/Decoders/OpCodeBImm64.cs
+++ b/ChocolArm64/Decoders/OpCodeBImm64.cs
@@ -2,7 +2,7 @@ using ChocolArm64.Instructions;
namespace ChocolArm64.Decoders
{
- class OpCodeBImm64 : OpCode64
+ class OpCodeBImm64 : OpCode64, IOpCodeBImm
{
public long Imm { get; protected set; }
diff --git a/ChocolArm64/Decoders/OpCodeBImmCond64.cs b/ChocolArm64/Decoders/OpCodeBImmCond64.cs
index 22702309..ca7df554 100644
--- a/ChocolArm64/Decoders/OpCodeBImmCond64.cs
+++ b/ChocolArm64/Decoders/OpCodeBImmCond64.cs
@@ -4,7 +4,7 @@ namespace ChocolArm64.Decoders
{
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)
{
@@ -17,7 +17,7 @@ namespace ChocolArm64.Decoders
return;
}
- Cond = (Cond)(opCode & 0xf);
+ Cond = (Condition)(opCode & 0xf);
Imm = position + DecoderHelper.DecodeImmS19_2(opCode);
}
diff --git a/ChocolArm64/Decoders/OpCodeBReg32.cs b/ChocolArm64/Decoders/OpCodeBReg32.cs
new file mode 100644
index 00000000..f89b1ae1
--- /dev/null
+++ b/ChocolArm64/Decoders/OpCodeBReg32.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCodeBRegT16.cs b/ChocolArm64/Decoders/OpCodeBRegT16.cs
new file mode 100644
index 00000000..c6c25130
--- /dev/null
+++ b/ChocolArm64/Decoders/OpCodeBRegT16.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCodeCcmp64.cs b/ChocolArm64/Decoders/OpCodeCcmp64.cs
index 8e91f15a..d65a24a4 100644
--- a/ChocolArm64/Decoders/OpCodeCcmp64.cs
+++ b/ChocolArm64/Decoders/OpCodeCcmp64.cs
@@ -8,7 +8,7 @@ namespace ChocolArm64.Decoders
public int Nzcv { get; private set; }
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)
{
@@ -21,11 +21,11 @@ namespace ChocolArm64.Decoders
return;
}
- Nzcv = (opCode >> 0) & 0xf;
- Cond = (Cond)((opCode >> 12) & 0xf);
- RmImm = (opCode >> 16) & 0x1f;
+ Nzcv = (opCode >> 0) & 0xf;
+ Cond = (Condition)((opCode >> 12) & 0xf);
+ RmImm = (opCode >> 16) & 0x1f;
- Rd = CpuThreadState.ZrIndex;
+ Rd = RegisterAlias.Zr;
}
}
} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCodeCsel64.cs b/ChocolArm64/Decoders/OpCodeCsel64.cs
index d1a5a2db..108a2798 100644
--- a/ChocolArm64/Decoders/OpCodeCsel64.cs
+++ b/ChocolArm64/Decoders/OpCodeCsel64.cs
@@ -6,12 +6,12 @@ namespace ChocolArm64.Decoders
{
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)
{
- Rm = (opCode >> 16) & 0x1f;
- Cond = (Cond)((opCode >> 12) & 0xf);
+ Rm = (opCode >> 16) & 0x1f;
+ Cond = (Condition)((opCode >> 12) & 0xf);
}
}
} \ No newline at end of file
diff --git a/ChocolArm64/Decoders/OpCodeSimdFcond64.cs b/ChocolArm64/Decoders/OpCodeSimdFcond64.cs
index f805b3c1..47de231c 100644
--- a/ChocolArm64/Decoders/OpCodeSimdFcond64.cs
+++ b/ChocolArm64/Decoders/OpCodeSimdFcond64.cs
@@ -6,12 +6,12 @@ namespace ChocolArm64.Decoders
{
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)
{
- Nzcv = (opCode >> 0) & 0xf;
- Cond = (Cond)((opCode >> 12) & 0xf);
+ Nzcv = (opCode >> 0) & 0xf;
+ Cond = (Condition)((opCode >> 12) & 0xf);
}
}
}
diff --git a/ChocolArm64/Decoders/OpCodeT16.cs b/ChocolArm64/Decoders/OpCodeT16.cs
new file mode 100644
index 00000000..005c470d
--- /dev/null
+++ b/ChocolArm64/Decoders/OpCodeT16.cs
@@ -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;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoders32/A32OpCode.cs b/ChocolArm64/Decoders32/A32OpCode.cs
deleted file mode 100644
index f0177a43..00000000
--- a/ChocolArm64/Decoders32/A32OpCode.cs
+++ /dev/null
@@ -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);
- }
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Decoders32/A32OpCodeBImmAl.cs b/ChocolArm64/Decoders32/A32OpCodeBImmAl.cs
deleted file mode 100644
index c4a196b6..00000000
--- a/ChocolArm64/Decoders32/A32OpCodeBImmAl.cs
+++ /dev/null
@@ -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;
- }
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Instructions/Inst.cs b/ChocolArm64/Instructions/Inst.cs
index 5f6740ca..de9ec18b 100644
--- a/ChocolArm64/Instructions/Inst.cs
+++ b/ChocolArm64/Instructions/Inst.cs
@@ -4,17 +4,15 @@ namespace ChocolArm64.Instructions
{
struct Inst
{
- public InstInterpreter Interpreter { get; private set; }
- public InstEmitter Emitter { get; private set; }
- public Type Type { get; private set; }
+ public InstEmitter Emitter { get; }
+ public Type Type { get; }
- public static Inst Undefined => new Inst(null, InstEmit.Und, null);
+ public static Inst Undefined => new Inst(InstEmit.Und, null);
- public Inst(InstInterpreter interpreter, InstEmitter emitter, Type type)
+ public Inst(InstEmitter emitter, Type type)
{
- Interpreter = interpreter;
- Emitter = emitter;
- Type = type;
+ Emitter = emitter;
+ Type = type;
}
}
} \ No newline at end of file
diff --git a/ChocolArm64/Instructions/InstEmit32Helper.cs b/ChocolArm64/Instructions/InstEmit32Helper.cs
new file mode 100644
index 00000000..d3ff8138
--- /dev/null
+++ b/ChocolArm64/Instructions/InstEmit32Helper.cs
@@ -0,0 +1,99 @@
+using ChocolArm64.Decoders;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System;
+
+namespace ChocolArm64.Instructions
+{
+ static class InstEmit32Helper
+ {
+ public static bool IsThumb(OpCode64 op)
+ {
+ return op is OpCodeT16;
+ }
+
+ public static void EmitLoadFromRegister(ILEmitterCtx context, int register)
+ {
+ if (register == RegisterAlias.Aarch32Pc)
+ {
+ OpCode32 op = (OpCode32)context.CurrOp;
+
+ context.EmitLdc_I4((int)op.GetPc());
+ }
+ else
+ {
+ context.EmitLdint(InstEmit32Helper.GetRegisterAlias(context.Mode, register));
+ }
+ }
+
+ public static int GetRegisterAlias(Aarch32Mode mode, int register)
+ {
+ //Only registers >= 8 are banked, with registers in the range [8, 12] being
+ //banked for the FIQ mode, and registers 13 and 14 being banked for all modes.
+ if ((uint)register < 8)
+ {
+ return register;
+ }
+
+ return GetBankedRegisterAlias(mode, register);
+ }
+
+ public static int GetBankedRegisterAlias(Aarch32Mode mode, int register)
+ {
+ switch (register)
+ {
+ case 8: return mode == Aarch32Mode.Fiq
+ ? RegisterAlias.R8Fiq
+ : RegisterAlias.R8Usr;
+
+ case 9: return mode == Aarch32Mode.Fiq
+ ? RegisterAlias.R9Fiq
+ : RegisterAlias.R9Usr;
+
+ case 10: return mode == Aarch32Mode.Fiq
+ ? RegisterAlias.R10Fiq
+ : RegisterAlias.R10Usr;
+
+ case 11: return mode == Aarch32Mode.Fiq
+ ? RegisterAlias.R11Fiq
+ : RegisterAlias.R11Usr;
+
+ case 12: return mode == Aarch32Mode.Fiq
+ ? RegisterAlias.R12Fiq
+ : RegisterAlias.R12Usr;
+
+ case 13:
+ switch (mode)
+ {
+ case Aarch32Mode.User:
+ case Aarch32Mode.System: return RegisterAlias.SpUsr;
+ case Aarch32Mode.Fiq: return RegisterAlias.SpFiq;
+ case Aarch32Mode.Irq: return RegisterAlias.SpIrq;
+ case Aarch32Mode.Supervisor: return RegisterAlias.SpSvc;
+ case Aarch32Mode.Abort: return RegisterAlias.SpAbt;
+ case Aarch32Mode.Hypervisor: return RegisterAlias.SpHyp;
+ case Aarch32Mode.Undefined: return RegisterAlias.SpUnd;
+
+ default: throw new ArgumentException(nameof(mode));
+ }
+
+ case 14:
+ switch (mode)
+ {
+ case Aarch32Mode.User:
+ case Aarch32Mode.Hypervisor:
+ case Aarch32Mode.System: return RegisterAlias.LrUsr;
+ case Aarch32Mode.Fiq: return RegisterAlias.LrFiq;
+ case Aarch32Mode.Irq: return RegisterAlias.LrIrq;
+ case Aarch32Mode.Supervisor: return RegisterAlias.LrSvc;
+ case Aarch32Mode.Abort: return RegisterAlias.LrAbt;
+ case Aarch32Mode.Undefined: return RegisterAlias.LrUnd;
+
+ default: throw new ArgumentException(nameof(mode));
+ }
+
+ default: throw new ArgumentOutOfRangeException(nameof(register));
+ }
+ }
+ }
+}
diff --git a/ChocolArm64/Instructions/InstEmitAlu.cs b/ChocolArm64/Instructions/InstEmitAlu.cs
index c0258ed2..d5d9cd65 100644
--- a/ChocolArm64/Instructions/InstEmitAlu.cs
+++ b/ChocolArm64/Instructions/InstEmitAlu.cs
@@ -17,7 +17,7 @@ namespace ChocolArm64.Instructions
private static void EmitAdc(ILEmitterCtx context, bool setFlags)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Add);
@@ -44,14 +44,14 @@ namespace ChocolArm64.Instructions
EmitAddsVCheck(context);
}
- EmitDataStore(context);
+ EmitAluStore(context);
}
- public static void Add(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Add);
+ public static void Add(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Add);
public static void Adds(ILEmitterCtx context)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Add);
@@ -59,14 +59,14 @@ namespace ChocolArm64.Instructions
EmitAddsCCheck(context);
EmitAddsVCheck(context);
- EmitDataStoreS(context);
+ EmitAluStoreS(context);
}
- public static void And(ILEmitterCtx context) => EmitDataOp(context, OpCodes.And);
+ public static void And(ILEmitterCtx context) => EmitAluOp(context, OpCodes.And);
public static void Ands(ILEmitterCtx context)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.And);
@@ -74,17 +74,17 @@ namespace ChocolArm64.Instructions
context.EmitZnFlagCheck();
- EmitDataStoreS(context);
+ EmitAluStoreS(context);
}
- public static void Asrv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shr);
+ public static void Asrv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shr);
public static void Bic(ILEmitterCtx context) => EmitBic(context, false);
public static void Bics(ILEmitterCtx context) => EmitBic(context, true);
private static void EmitBic(ILEmitterCtx context, bool setFlags)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Not);
context.Emit(OpCodes.And);
@@ -96,7 +96,7 @@ namespace ChocolArm64.Instructions
context.EmitZnFlagCheck();
}
- EmitDataStore(context, setFlags);
+ EmitAluStore(context, setFlags);
}
public static void Cls(ILEmitterCtx context)
@@ -136,15 +136,15 @@ namespace ChocolArm64.Instructions
public static void Eon(ILEmitterCtx context)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Not);
context.Emit(OpCodes.Xor);
- EmitDataStore(context);
+ EmitAluStore(context);
}
- public static void Eor(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Xor);
+ public static void Eor(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Xor);
public static void Extr(ILEmitterCtx context)
{
@@ -166,18 +166,18 @@ namespace ChocolArm64.Instructions
context.Emit(OpCodes.Or);
}
- EmitDataStore(context);
+ EmitAluStore(context);
}
- public static void Lslv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shl);
- public static void Lsrv(ILEmitterCtx context) => EmitDataOpShift(context, OpCodes.Shr_Un);
+ public static void Lslv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shl);
+ public static void Lsrv(ILEmitterCtx context) => EmitAluOpShift(context, OpCodes.Shr_Un);
public static void Sbc(ILEmitterCtx context) => EmitSbc(context, false);
public static void Sbcs(ILEmitterCtx context) => EmitSbc(context, true);
private static void EmitSbc(ILEmitterCtx context, bool setFlags)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Sub);
@@ -208,16 +208,16 @@ namespace ChocolArm64.Instructions
EmitSubsVCheck(context);
}
- EmitDataStore(context);
+ EmitAluStore(context);
}
- public static void Sub(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Sub);
+ public static void Sub(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Sub);
public static void Subs(ILEmitterCtx context)
{
context.TryOptMarkCondWithoutCmp();
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Sub);
@@ -225,20 +225,20 @@ namespace ChocolArm64.Instructions
EmitSubsCCheck(context);
EmitSubsVCheck(context);
- EmitDataStoreS(context);
+ EmitAluStoreS(context);
}
public static void Orn(ILEmitterCtx context)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Not);
context.Emit(OpCodes.Or);
- EmitDataStore(context);
+ EmitAluStore(context);
}
- public static void Orr(ILEmitterCtx context) => EmitDataOp(context, OpCodes.Or);
+ public static void Orr(ILEmitterCtx context) => EmitAluOp(context, OpCodes.Or);
public static void Rbit(ILEmitterCtx context) => EmitFallback32_64(context,
nameof(SoftFallback.ReverseBits32),
@@ -283,22 +283,22 @@ namespace ChocolArm64.Instructions
public static void Rorv(ILEmitterCtx context)
{
- EmitDataLoadRn(context);
- EmitDataLoadShift(context);
+ EmitAluLoadRn(context);
+ EmitAluLoadShift(context);
context.Emit(OpCodes.Shr_Un);
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.EmitLdc_I4(context.CurrOp.GetBitsCount());
- EmitDataLoadShift(context);
+ EmitAluLoadShift(context);
context.Emit(OpCodes.Sub);
context.Emit(OpCodes.Shl);
context.Emit(OpCodes.Or);
- EmitDataStore(context);
+ EmitAluStore(context);
}
public static void Sdiv(ILEmitterCtx context) => EmitDiv(context, OpCodes.Div);
@@ -309,7 +309,7 @@ namespace ChocolArm64.Instructions
//If Rm == 0, Rd = 0 (division by zero).
context.EmitLdc_I(0);
- EmitDataLoadRm(context);
+ EmitAluLoadRm(context);
context.EmitLdc_I(0);
@@ -325,13 +325,13 @@ namespace ChocolArm64.Instructions
context.EmitLdc_I(intMin);
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.EmitLdc_I(intMin);
context.Emit(OpCodes.Ceq);
- EmitDataLoadRm(context);
+ EmitAluLoadRm(context);
context.EmitLdc_I(-1);
@@ -341,38 +341,38 @@ namespace ChocolArm64.Instructions
context.Emit(OpCodes.Pop);
}
- EmitDataLoadRn(context);
- EmitDataLoadRm(context);
+ EmitAluLoadRn(context);
+ EmitAluLoadRm(context);
context.Emit(ilOp);
context.MarkLabel(badDiv);
- EmitDataStore(context);
+ EmitAluStore(context);
}
- private static void EmitDataOp(ILEmitterCtx context, OpCode ilOp)
+ private static void EmitAluOp(ILEmitterCtx context, OpCode ilOp)
{
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(ilOp);
- EmitDataStore(context);
+ EmitAluStore(context);
}
- private static void EmitDataOpShift(ILEmitterCtx context, OpCode ilOp)
+ private static void EmitAluOpShift(ILEmitterCtx context, OpCode ilOp)
{
- EmitDataLoadRn(context);
- EmitDataLoadShift(context);
+ EmitAluLoadRn(context);
+ EmitAluLoadShift(context);
context.Emit(ilOp);
- EmitDataStore(context);
+ EmitAluStore(context);
}
- private static void EmitDataLoadShift(ILEmitterCtx context)
+ private static void EmitAluLoadShift(ILEmitterCtx context)
{
- EmitDataLoadRm(context);
+ EmitAluLoadRm(context);
context.EmitLdc_I(context.CurrOp.GetBitsCount() - 1);
@@ -398,5 +398,22 @@ namespace ChocolArm64.Instructions
context.EmitStflg((int)PState.CBit);
}
+
+ public static void EmitAluStore(ILEmitterCtx context) => EmitAluStore(context, false);
+ public static void EmitAluStoreS(ILEmitterCtx context) => EmitAluStore(context, true);
+
+ public static void EmitAluStore(ILEmitterCtx context, bool setFlags)
+ {
+ IOpCodeAlu64 op = (IOpCodeAlu64)context.CurrOp;
+
+ if (setFlags || op is IOpCodeAluRs64)
+ {
+ context.EmitStintzr(op.Rd);
+ }
+ else
+ {
+ context.EmitStint(op.Rd);
+ }
+ }
}
}
diff --git a/ChocolArm64/Instructions/InstEmitAlu32.cs b/ChocolArm64/Instructions/InstEmitAlu32.cs
new file mode 100644
index 00000000..2ebb8073
--- /dev/null
+++ b/ChocolArm64/Instructions/InstEmitAlu32.cs
@@ -0,0 +1,123 @@
+using ChocolArm64.Decoders;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instructions.InstEmit32Helper;
+using static ChocolArm64.Instructions.InstEmitAluHelper;
+
+namespace ChocolArm64.Instructions
+{
+ static partial class InstEmit32
+ {
+ public static void Add(ILEmitterCtx context)
+ {
+ IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
+
+ EmitAluLoadOpers(context, setCarry: false);
+
+ context.Emit(OpCodes.Add);
+
+ if (op.SetFlags)
+ {
+ context.EmitZnFlagCheck();
+
+ EmitAddsCCheck(context);
+ EmitAddsVCheck(context);
+ }
+
+ EmitAluStore(context);
+ }
+
+ public static void Mov(ILEmitterCtx context)
+ {
+ IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
+
+ EmitAluLoadOper2(context);
+
+ if (op.SetFlags)
+ {
+ context.EmitZnFlagCheck();
+ }
+
+ EmitAluStore(context);
+ }
+
+ public static void Sub(ILEmitterCtx context)
+ {
+ IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
+
+ EmitAluLoadOpers(context, setCarry: false);
+
+ context.Emit(OpCodes.Sub);
+
+ if (op.SetFlags)
+ {
+ context.EmitZnFlagCheck();
+
+ EmitSubsCCheck(context);
+ EmitSubsVCheck(context);
+ }
+
+ EmitAluStore(context);
+ }
+
+ private static void EmitAluStore(ILEmitterCtx context)
+ {
+ IOpCodeAlu32 op = (IOpCodeAlu32)context.CurrOp;
+
+ if (op.Rd == RegisterAlias.Aarch32Pc)
+ {
+ if (op.SetFlags)
+ {
+ //TODO: Load SPSR etc.
+
+ context.EmitLdflg((int)PState.TBit);
+
+ ILLabel lblThumb = new ILLabel();
+ ILLabel lblEnd = new ILLabel();
+
+ context.Emit(OpCodes.Brtrue_S, lblThumb);
+
+ context.EmitLdc_I4(~3);
+
+ context.Emit(OpCodes.Br_S, lblEnd);
+
+ context.MarkLabel(lblThumb);
+
+ context.EmitLdc_I4(~1);
+
+ context.MarkLabel(lblEnd);
+
+ context.Emit(OpCodes.And);
+ context.Emit(OpCodes.Conv_U8);
+ context.Emit(OpCodes.Ret);
+ }
+ else
+ {
+ EmitAluWritePc(context);
+ }
+ }
+ else
+ {
+ context.EmitStint(GetRegisterAlias(context.Mode, op.Rd));
+ }
+ }
+
+ private static void EmitAluWritePc(ILEmitterCtx context)
+ {
+ if (IsThumb(context.CurrOp))
+ {
+ context.EmitLdc_I4(~1);
+
+ context.Emit(OpCodes.And);
+ context.Emit(OpCodes.Conv_U8);
+ context.Emit(OpCodes.Ret);
+ }
+ else
+ {
+ EmitBxWritePc(context);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Instructions/InstEmitAluHelper.cs b/ChocolArm64/Instructions/InstEmitAluHelper.cs
index 97c50564..db8fd0e5 100644
--- a/ChocolArm64/Instructions/InstEmitAluHelper.cs
+++ b/ChocolArm64/Instructions/InstEmitAluHelper.cs
@@ -1,6 +1,7 @@
using ChocolArm64.Decoders;
using ChocolArm64.State;
using ChocolArm64.Translation;
+using System;
using System.Reflection.Emit;
namespace ChocolArm64.Instructions
@@ -14,7 +15,7 @@ namespace ChocolArm64.Instructions
context.EmitLdtmp();
context.EmitLdtmp();
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.Emit(OpCodes.Ceq);
@@ -24,7 +25,7 @@ namespace ChocolArm64.Instructions
context.EmitLdtmp();
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.Emit(OpCodes.Clt_Un);
context.Emit(OpCodes.Or);
@@ -37,7 +38,7 @@ namespace ChocolArm64.Instructions
//C = Rd < Rn
context.Emit(OpCodes.Dup);
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.Emit(OpCodes.Clt_Un);
@@ -49,11 +50,11 @@ namespace ChocolArm64.Instructions
//V = (Rd ^ Rn) & ~(Rn ^ Rm) < 0
context.Emit(OpCodes.Dup);
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.Emit(OpCodes.Xor);
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Xor);
context.Emit(OpCodes.Not);
@@ -69,7 +70,7 @@ namespace ChocolArm64.Instructions
public static void EmitSbcsCCheck(ILEmitterCtx context)
{
//C = (Rn == Rm && CIn) || Rn > Rm
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Ceq);
@@ -77,7 +78,7 @@ namespace ChocolArm64.Instructions
context.Emit(OpCodes.And);
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Cgt_Un);
context.Emit(OpCodes.Or);
@@ -88,7 +89,7 @@ namespace ChocolArm64.Instructions
public static void EmitSubsCCheck(ILEmitterCtx context)
{
//C = Rn == Rm || Rn > Rm = !(Rn < Rm)
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Clt_Un);
@@ -104,11 +105,11 @@ namespace ChocolArm64.Instructions
//V = (Rd ^ Rn) & (Rn ^ Rm) < 0
context.Emit(OpCodes.Dup);
- EmitDataLoadRn(context);
+ EmitAluLoadRn(context);
context.Emit(OpCodes.Xor);
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
context.Emit(OpCodes.Xor);
context.Emit(OpCodes.And);
@@ -120,35 +121,76 @@ namespace ChocolArm64.Instructions
context.EmitStflg((int)PState.VBit);
}
- public static void EmitDataLoadRm(ILEmitterCtx context)
+ public static void EmitAluLoadRm(ILEmitterCtx context)
{
- context.EmitLdintzr(((IOpCodeAluRs64)context.CurrOp).Rm);
+ if (context.CurrOp is IOpCodeAluRs64 op)
+ {
+ context.EmitLdintzr(op.Rm);
+ }
+ else if (context.CurrOp is OpCodeAluRsImm32 op32)
+ {
+ InstEmit32Helper.EmitLoadFromRegister(context, op32.Rm);
+ }
+ else
+ {
+ throw new InvalidOperationException();
+ }
}
- public static void EmitDataLoadOpers(ILEmitterCtx context)
+ public static void EmitAluLoadOpers(ILEmitterCtx context, bool setCarry = true)
{
- EmitDataLoadRn(context);
- EmitDataLoadOper2(context);
+ EmitAluLoadRn(context);
+ EmitAluLoadOper2(context, setCarry);
}
- public static void EmitDataLoadRn(ILEmitterCtx context)
+ public static void EmitAluLoadRn(ILEmitterCtx context)
{
- IOpCodeAlu64 op = (IOpCodeAlu64)context.CurrOp;
-
- if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs64)
+ if (context.CurrOp is IOpCodeAlu64 op)
{
- context.EmitLdintzr(op.Rn);
+ if (op.DataOp == DataOp.Logical || op is IOpCodeAluRs64)
+ {
+ context.EmitLdintzr(op.Rn);
+ }
+ else
+ {
+ context.EmitLdint(op.Rn);
+ }
+ }
+ else if (context.CurrOp is IOpCodeAlu32 op32)
+ {
+ InstEmit32Helper.EmitLoadFromRegister(context, op32.Rn);
}
else
{
- context.EmitLdint(op.Rn);
+ throw new InvalidOperationException();
}
}
- public static void EmitDataLoadOper2(ILEmitterCtx context)
+ public static void EmitAluLoadOper2(ILEmitterCtx context, bool setCarry = true)
{
switch (context.CurrOp)
{
+ //ARM32.
+ case OpCodeAluImm32 op:
+ context.EmitLdc_I4(op.Imm);
+
+ if (op.SetFlags && op.IsRotated)
+ {
+ context.EmitLdc_I4((int)((uint)op.Imm >> 31));
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ break;
+
+ case OpCodeAluRsImm32 op:
+ EmitLoadRmShiftedByImmediate(context, op, setCarry);
+ break;
+
+ case OpCodeAluImm8T16 op:
+ context.EmitLdc_I4(op.Imm);
+ break;
+
+ //ARM64.
case IOpCodeAluImm64 op:
context.EmitLdc_I(op.Imm);
break;
@@ -170,23 +212,8 @@ namespace ChocolArm64.Instructions
context.EmitCast(op.IntType);
context.EmitLsl(op.Shift);
break;
- }
- }
- public static void EmitDataStore(ILEmitterCtx context) => EmitDataStore(context, false);
- public static void EmitDataStoreS(ILEmitterCtx context) => EmitDataStore(context, true);
-
- public static void EmitDataStore(ILEmitterCtx context, bool setFlags)
- {
- IOpCodeAlu64 op = (IOpCodeAlu64)context.CurrOp;
-
- if (setFlags || op is IOpCodeAluRs64)
- {
- context.EmitStintzr(op.Rd);
- }
- else
- {
- context.EmitStint(op.Rd);
+ default: throw new InvalidOperationException();
}
}
@@ -217,5 +244,219 @@ namespace ChocolArm64.Instructions
context.Emit(OpCodes.And);
context.EmitStflg((int)PState.NBit);
}
+
+ //ARM32 helpers.
+ private static void EmitLoadRmShiftedByImmediate(ILEmitterCtx context, OpCodeAluRsImm32 op, bool setCarry)
+ {
+ int shift = op.Imm;
+
+ if (shift == 0)
+ {
+ switch (op.ShiftType)
+ {
+ case ShiftType.Lsr: shift = 32; break;
+ case ShiftType.Asr: shift = 32; break;
+ case ShiftType.Ror: shift = 1; break;
+ }
+ }
+
+ context.EmitLdint(op.Rm);
+
+ if (shift != 0)
+ {
+ setCarry &= op.SetFlags;
+
+ switch (op.ShiftType)
+ {
+ case ShiftType.Lsl: EmitLslC(context, setCarry, shift); break;
+ case ShiftType.Lsr: EmitLsrC(context, setCarry, shift); break;
+ case ShiftType.Asr: EmitAsrC(context, setCarry, shift); break;
+ case ShiftType.Ror:
+ if (op.Imm != 0)
+ {
+ EmitRorC(context, setCarry, shift);
+ }
+ else
+ {
+ EmitRrxC(context, setCarry);
+ }
+ break;
+ }
+ }
+ }
+
+ private static void EmitLslC(ILEmitterCtx context, bool setCarry, int shift)
+ {
+ if ((uint)shift > 32)
+ {
+ EmitShiftByMoreThan32(context, setCarry);
+ }
+ else if (shift == 32)
+ {
+ if (setCarry)
+ {
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ else
+ {
+ context.Emit(OpCodes.Pop);
+ }
+
+ context.EmitLdc_I4(0);
+ }
+ else
+ {
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLsr(32 - shift);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+
+ context.EmitLsl(shift);
+ }
+ }
+
+ private static void EmitLsrC(ILEmitterCtx context, bool setCarry, int shift)
+ {
+ if ((uint)shift > 32)
+ {
+ EmitShiftByMoreThan32(context, setCarry);
+ }
+ else if (shift == 32)
+ {
+ if (setCarry)
+ {
+ context.EmitLsr(31);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ else
+ {
+ context.Emit(OpCodes.Pop);
+ }
+
+ context.EmitLdc_I4(0);
+ }
+ else
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLsr(shift - 1);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.CBit);
+
+ context.EmitLsr(shift);
+ }
+ }
+
+ private static void EmitShiftByMoreThan32(ILEmitterCtx context, bool setCarry)
+ {
+ context.Emit(OpCodes.Pop);
+
+ context.EmitLdc_I4(0);
+
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ }
+
+ private static void EmitAsrC(ILEmitterCtx context, bool setCarry, int shift)
+ {
+ if ((uint)shift >= 32)
+ {
+ context.EmitAsr(31);
+
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ }
+ else
+ {
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLsr(shift - 1);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+
+ context.EmitAsr(shift);
+ }
+ }
+
+ private static void EmitRorC(ILEmitterCtx context, bool setCarry, int shift)
+ {
+ shift &= 0x1f;
+
+ context.EmitRor(shift);
+
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLsr(31);
+
+ context.EmitStflg((int)PState.CBit);
+ }
+ }
+
+ private static void EmitRrxC(ILEmitterCtx context, bool setCarry)
+ {
+ //Rotate right by 1 with carry.
+ if (setCarry)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitSttmp();
+ }
+
+ context.EmitLsr(1);
+
+ context.EmitLdflg((int)PState.CBit);
+
+ context.EmitLsl(31);
+
+ context.Emit(OpCodes.Or);
+
+ if (setCarry)
+ {
+ context.EmitLdtmp();
+ context.EmitStflg((int)PState.CBit);
+ }
+ }
}
}
diff --git a/ChocolArm64/Instructions/InstEmitCcmp.cs b/ChocolArm64/Instructions/InstEmitCcmp.cs
index b91104c9..714ae06a 100644
--- a/ChocolArm64/Instructions/InstEmitCcmp.cs
+++ b/ChocolArm64/Instructions/InstEmitCcmp.cs
@@ -48,7 +48,7 @@ namespace ChocolArm64.Instructions
context.MarkLabel(lblTrue);
- EmitDataLoadOpers(context);
+ EmitAluLoadOpers(context);
if (cmpOp == CcmpOp.Cmp)
{
diff --git a/ChocolArm64/Instructions/InstEmitFlow.cs b/ChocolArm64/Instructions/InstEmitFlow.cs
index 758bf212..181c6a04 100644
--- a/ChocolArm64/Instructions/InstEmitFlow.cs
+++ b/ChocolArm64/Instructions/InstEmitFlow.cs
@@ -36,36 +36,10 @@ namespace ChocolArm64.Instructions
OpCodeBImmAl64 op = (OpCodeBImmAl64)context.CurrOp;
context.EmitLdc_I(op.Position + 4);
- context.EmitStint(CpuThreadState.LrIndex);
+ context.EmitStint(RegisterAlias.Lr);
context.EmitStoreState();
- if (context.TryOptEmitSubroutineCall())
- {
- //Note: the return value of the called method will be placed
- //at the Stack, the return value is always a Int64 with the
- //return address of the function. We check if the address is
- //correct, if it isn't we keep returning until we reach the dispatcher.
- context.Emit(OpCodes.Dup);
-
- context.EmitLdc_I8(op.Position + 4);
-
- ILLabel lblContinue = new ILLabel();
-
- context.Emit(OpCodes.Beq_S, lblContinue);
- context.Emit(OpCodes.Ret);
-
- context.MarkLabel(lblContinue);
-
- context.Emit(OpCodes.Pop);
-
- context.EmitLoadState();
- }
- else
- {
- context.EmitLdc_I8(op.Imm);
-
- context.Emit(OpCodes.Ret);
- }
+ InstEmitFlowHelper.EmitCall(context, op.Imm);
}
public static void Blr(ILEmitterCtx context)
@@ -74,7 +48,7 @@ namespace ChocolArm64.Instructions
context.EmitLdintzr(op.Rn);
context.EmitLdc_I(op.Position + 4);
- context.EmitStint(CpuThreadState.LrIndex);
+ context.EmitStint(RegisterAlias.Lr);
context.EmitStoreState();
context.Emit(OpCodes.Ret);
@@ -106,7 +80,7 @@ namespace ChocolArm64.Instructions
public static void Ret(ILEmitterCtx context)
{
context.EmitStoreState();
- context.EmitLdint(CpuThreadState.LrIndex);
+ context.EmitLdint(RegisterAlias.Lr);
context.Emit(OpCodes.Ret);
}
@@ -128,7 +102,7 @@ namespace ChocolArm64.Instructions
EmitBranch(context, ilOp);
}
- private static void EmitBranch(ILEmitterCtx context, Cond cond)
+ private static void EmitBranch(ILEmitterCtx context, Condition cond)
{
OpCodeBImm64 op = (OpCodeBImm64)context.CurrOp;
diff --git a/ChocolArm64/Instructions/InstEmitFlow32.cs b/ChocolArm64/Instructions/InstEmitFlow32.cs
new file mode 100644
index 00000000..03b39936
--- /dev/null
+++ b/ChocolArm64/Instructions/InstEmitFlow32.cs
@@ -0,0 +1,99 @@
+using ChocolArm64.Decoders;
+using ChocolArm64.State;
+using ChocolArm64.Translation;
+using System.Reflection.Emit;
+
+using static ChocolArm64.Instructions.InstEmit32Helper;
+
+namespace ChocolArm64.Instructions
+{
+ static partial class InstEmit32
+ {
+ public static void B(ILEmitterCtx context)
+ {
+ IOpCodeBImm32 op = (IOpCodeBImm32)context.CurrOp;
+
+ if (context.CurrBlock.Branch != null)
+ {
+ context.Emit(OpCodes.Br, context.GetLabel(op.Imm));
+ }
+ else
+ {
+ context.EmitStoreState();
+ context.EmitLdc_I8(op.Imm);
+
+ context.Emit(OpCodes.Ret);
+ }
+ }
+
+ public static void Bl(ILEmitterCtx context)
+ {
+ Blx(context, x: false);
+ }
+
+ public static void Blx(ILEmitterCtx context)
+ {
+ Blx(context, x: true);
+ }
+
+ public static void Bx(ILEmitterCtx context)
+ {
+ IOpCodeBReg32 op = (IOpCodeBReg32)context.CurrOp;
+
+ context.EmitStoreState();
+
+ EmitLoadFromRegister(context, op.Rm);
+
+ EmitBxWritePc(context);
+ }
+
+ private static void Blx(ILEmitterCtx context, bool x)
+ {
+ IOpCodeBImm32 op = (IOpCodeBImm32)context.CurrOp;
+
+ uint pc = op.GetPc();
+
+ bool isThumb = IsThumb(context.CurrOp);
+
+ if (!isThumb)
+ {
+ context.EmitLdc_I(op.GetPc() - 4);
+ }
+ else
+ {
+ context.EmitLdc_I(op.GetPc() | 1);
+ }
+
+ context.EmitStint(GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr));
+ context.EmitStoreState();
+
+ //If x is true, then this is a branch with link and exchange.
+ //In this case we need to swap the mode between Arm <-> Thumb.
+ if (x)
+ {
+ context.EmitLdc_I4(isThumb ? 0 : 1);
+
+ context.EmitStflg((int)PState.TBit);
+ }
+
+ InstEmitFlowHelper.EmitCall(context, op.Imm);
+ }
+
+ private static void EmitBxWritePc(ILEmitterCtx context)
+ {
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLdc_I4(1);
+
+ context.Emit(OpCodes.And);
+
+ context.EmitStflg((int)PState.TBit);
+
+ context.EmitLdc_I4(~1);
+
+ context.Emit(OpCodes.And);
+ context.Emit(OpCodes.Conv_U8);
+ context.Emit(OpCodes.Ret);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Instructions/InstEmitFlowHelper.cs b/ChocolArm64/Instructions/InstEmitFlowHelper.cs
new file mode 100644
index 00000000..cf093bb3
--- /dev/null
+++ b/ChocolArm64/Instructions/InstEmitFlowHelper.cs
@@ -0,0 +1,39 @@
+using ChocolArm64.Translation;
+using System.Reflection.Emit;
+
+namespace ChocolArm64.Instructions
+{
+ static class InstEmitFlowHelper
+ {
+ public static void EmitCall(ILEmitterCtx context, long imm)
+ {
+ if (context.TryOptEmitSubroutineCall())
+ {
+ //Note: the return value of the called method will be placed
+ //at the Stack, the return value is always a Int64 with the
+ //return address of the function. We check if the address is
+ //correct, if it isn't we keep returning until we reach the dispatcher.
+ context.Emit(OpCodes.Dup);
+
+ context.EmitLdc_I8(context.CurrOp.Position + 4);
+
+ ILLabel lblContinue = new ILLabel();
+
+ context.Emit(OpCodes.Beq_S, lblContinue);
+ context.Emit(OpCodes.Ret);
+
+ context.MarkLabel(lblContinue);
+
+ context.Emit(OpCodes.Pop);
+
+ context.EmitLoadState();
+ }
+ else
+ {
+ context.EmitLdc_I8(imm);
+
+ context.Emit(OpCodes.Ret);
+ }
+ }
+ }
+}
diff --git a/ChocolArm64/Instructions/InstEmitSimdMemory.cs b/ChocolArm64/Instructions/InstEmitSimdMemory.cs
index eb053257..9b84eb86 100644
--- a/ChocolArm64/Instructions/InstEmitSimdMemory.cs
+++ b/ChocolArm64/Instructions/InstEmitSimdMemory.cs
@@ -168,7 +168,7 @@ namespace ChocolArm64.Instructions
context.EmitLdint(op.Rn);
- if (op.Rm != CpuThreadState.ZrIndex)
+ if (op.Rm != RegisterAlias.Zr)
{
context.EmitLdint(op.Rm);
}
diff --git a/ChocolArm64/Instructions/InstInterpreter.cs b/ChocolArm64/Instructions/InstInterpreter.cs
deleted file mode 100644
index e6354fd5..00000000
--- a/ChocolArm64/Instructions/InstInterpreter.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-using ChocolArm64.Decoders;
-using ChocolArm64.Memory;
-using ChocolArm64.State;
-
-namespace ChocolArm64.Instructions
-{
- delegate void InstInterpreter(CpuThreadState state, MemoryManager memory, OpCode64 opCode);
-} \ No newline at end of file
diff --git a/ChocolArm64/Instructions32/A32InstInterpretAlu.cs b/ChocolArm64/Instructions32/A32InstInterpretAlu.cs
deleted file mode 100644
index f3be823f..00000000
--- a/ChocolArm64/Instructions32/A32InstInterpretAlu.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace ChocolArm64.Instructions32
-{
- static partial class A32InstInterpret
- {
-
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Instructions32/A32InstInterpretFlow.cs b/ChocolArm64/Instructions32/A32InstInterpretFlow.cs
deleted file mode 100644
index cdf7e4c6..00000000
--- a/ChocolArm64/Instructions32/A32InstInterpretFlow.cs
+++ /dev/null
@@ -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;
- }
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/Instructions32/A32InstInterpretHelper.cs b/ChocolArm64/Instructions32/A32InstInterpretHelper.cs
deleted file mode 100644
index b08e1298..00000000
--- a/ChocolArm64/Instructions32/A32InstInterpretHelper.cs
+++ /dev/null
@@ -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);
- }
- }
-} \ No newline at end of file
diff --git a/ChocolArm64/OpCodeTable.cs b/ChocolArm64/OpCodeTable.cs
index adb71ae7..34b420fb 100644
--- a/ChocolArm64/OpCodeTable.cs
+++ b/ChocolArm64/OpCodeTable.cs
@@ -1,7 +1,5 @@
using ChocolArm64.Decoders;
-using ChocolArm64.Decoders32;
using ChocolArm64.Instructions;
-using ChocolArm64.Instructions32;
using ChocolArm64.State;
using System;
using System.Collections.Generic;
@@ -10,13 +8,47 @@ namespace ChocolArm64
{
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()
{
#region "OpCode Table (AArch32)"
//Integer
- SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", A32InstInterpret.B, typeof(A32OpCodeBImmAl));
- SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", A32InstInterpret.Bl, typeof(A32OpCodeBImmAl));
- SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", A32InstInterpret.Blx, typeof(A32OpCodeBImmAl));
+ SetA32("<<<<0010100xxxxxxxxxxxxxxxxxxxxx", InstEmit32.Add, typeof(OpCodeAluImm32));
+ SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstEmit32.Add, typeof(OpCodeAluRsImm32));
+ 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
#region "OpCode Table (AArch64)"
@@ -544,63 +576,29 @@ namespace ChocolArm64
SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstEmit.Zip2_V, typeof(OpCodeSimdReg64));
#endregion
-#region "Generate InstA64FastLookup Table (AArch64)"
- var tmp = new List<InstInfo>[_fastLookupSize];
- for (int i = 0; i < _fastLookupSize; i++)
- {
- 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
+ FillFastLookupTable(_instA32FastLookup, _allInstA32);
+ FillFastLookupTable(_instT32FastLookup, _allInstT32);
+ FillFastLookupTable(_instA64FastLookup, _allInstA64);
}
- private class InstInfo
+ private static void SetA32(string encoding, InstEmitter emitter, Type type)
{
- public int Mask;
- public int Value;
-
- public Inst Inst;
+ Set(encoding, new Inst(emitter, type), ExecutionMode.Aarch32Arm);
+ }
- public InstInfo(int mask, int value, Inst inst)
+ private static void SetT32(string encoding, InstEmitter emitter, Type type)
+ {
+ if (encoding.Length == 16)
{
- Mask = mask;
- Value = value;
- Inst = inst;
+ encoding = "xxxxxxxxxxxxxxxx" + encoding;
}
- }
-
- private static List<InstInfo> _allInstA32 = new List<InstInfo>();
- 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);
+ Set(encoding, new Inst(emitter, type), ExecutionMode.Aarch32Thumb);
}
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)
@@ -673,27 +671,55 @@ namespace ChocolArm64
}
}
- private static void InsertInst(
- int xMask,
- int value,
- Inst inst,
- ExecutionMode mode)
+ private static void InsertInst(int xMask, int value, Inst inst, ExecutionMode mode)
{
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)
{
- 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)
@@ -708,7 +734,7 @@ namespace ChocolArm64
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)
{
diff --git a/ChocolArm64/State/Aarch32Mode.cs b/ChocolArm64/State/Aarch32Mode.cs
new file mode 100644
index 00000000..bc4e4b64
--- /dev/null
+++ b/ChocolArm64/State/Aarch32Mode.cs
@@ -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
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/State/CpuThreadState.cs b/ChocolArm64/State/CpuThreadState.cs
index a4ee5d07..6c00bf48 100644
--- a/ChocolArm64/State/CpuThreadState.cs
+++ b/ChocolArm64/State/CpuThreadState.cs
@@ -8,25 +8,13 @@ namespace ChocolArm64.State
{
public class CpuThreadState
{
- internal const int LrIndex = 30;
- internal const int ZrIndex = 31;
-
internal const int ErgSizeLog2 = 4;
internal const int DczSizeLog2 = 4;
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;
- //AArch64 state.
public ulong X0, X1, X2, X3, X4, X5, X6, X7,
X8, X9, X10, X11, X12, X13, X14, X15,
X16, X17, X18, X19, X20, X21, X22, X23,
@@ -42,6 +30,10 @@ namespace ChocolArm64.State
public bool Zero;
public bool Negative;
+ public bool IsAarch32;
+
+ public int ElrHyp;
+
public bool Running { get; set; }
public int Core { get; set; }
@@ -146,6 +138,18 @@ namespace ChocolArm64.State
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)
{
return (Fpcr & (1 << (int)flag)) != 0;
diff --git a/ChocolArm64/State/ExecutionMode.cs b/ChocolArm64/State/ExecutionMode.cs
index 4b8c17ce..b735fd5f 100644
--- a/ChocolArm64/State/ExecutionMode.cs
+++ b/ChocolArm64/State/ExecutionMode.cs
@@ -2,7 +2,8 @@ namespace ChocolArm64.State
{
enum ExecutionMode
{
- AArch32,
- AArch64
+ Aarch64,
+ Aarch32Arm,
+ Aarch32Thumb
}
} \ No newline at end of file
diff --git a/ChocolArm64/State/PState.cs b/ChocolArm64/State/PState.cs
index 40636c87..aef5f53b 100644
--- a/ChocolArm64/State/PState.cs
+++ b/ChocolArm64/State/PState.cs
@@ -5,11 +5,15 @@ namespace ChocolArm64.State
[Flags]
enum PState
{
+ TBit = 5,
+
VBit = 28,
CBit = 29,
ZBit = 30,
NBit = 31,
+ T = 1 << TBit,
+
V = 1 << VBit,
C = 1 << CBit,
Z = 1 << ZBit,
diff --git a/ChocolArm64/State/Register.cs b/ChocolArm64/State/Register.cs
index ea29e7b6..34588231 100644
--- a/ChocolArm64/State/Register.cs
+++ b/ChocolArm64/State/Register.cs
@@ -43,6 +43,8 @@ namespace ChocolArm64.State
{
switch ((PState)Index)
{
+ case PState.TBit: return GetField(nameof(CpuThreadState.Thumb));
+
case PState.VBit: return GetField(nameof(CpuThreadState.Overflow));
case PState.CBit: return GetField(nameof(CpuThreadState.Carry));
case PState.ZBit: return GetField(nameof(CpuThreadState.Zero));
diff --git a/ChocolArm64/State/RegisterAlias.cs b/ChocolArm64/State/RegisterAlias.cs
new file mode 100644
index 00000000..8c2b95d7
--- /dev/null
+++ b/ChocolArm64/State/RegisterAlias.cs
@@ -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;
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Translation/ILEmitterCtx.cs b/ChocolArm64/Translation/ILEmitterCtx.cs
index 778b29ad..d4bd93ab 100644
--- a/ChocolArm64/Translation/ILEmitterCtx.cs
+++ b/ChocolArm64/Translation/ILEmitterCtx.cs
@@ -23,6 +23,8 @@ namespace ChocolArm64.Translation
public Block CurrBlock => _currBlock;
public OpCode64 CurrOp => _currBlock?.OpCodes[_opcIndex];
+ public Aarch32Mode Mode { get; } = Aarch32Mode.User; //TODO
+
private Dictionary<Block, ILBlock> _visitedBlocks;
private Queue<Block> _branchTargets;
@@ -97,11 +99,52 @@ namespace ChocolArm64.Translation
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);
+ 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());
}
+ 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()
{
EmitLdarg(TranslatedSub.StateArgIdx);
@@ -243,27 +286,27 @@ namespace ChocolArm64.Translation
{
_optOpLastCompare = CurrOp;
- InstEmitAluHelper.EmitDataLoadOpers(this);
+ InstEmitAluHelper.EmitAluLoadOpers(this);
Stloc(CmpOptTmp2Index, 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 },
- { Cond.Ne, OpCodes.Bne_Un },
- { Cond.GeUn, OpCodes.Bge_Un },
- { Cond.LtUn, OpCodes.Blt_Un },
- { Cond.GtUn, OpCodes.Bgt_Un },
- { Cond.LeUn, OpCodes.Ble_Un },
- { Cond.Ge, OpCodes.Bge },
- { Cond.Lt, OpCodes.Blt },
- { Cond.Gt, OpCodes.Bgt },
- { Cond.Le, OpCodes.Ble }
+ { Condition.Eq, OpCodes.Beq },
+ { Condition.Ne, OpCodes.Bne_Un },
+ { Condition.GeUn, OpCodes.Bge_Un },
+ { Condition.LtUn, OpCodes.Blt_Un },
+ { Condition.GtUn, OpCodes.Bgt_Un },
+ { Condition.LeUn, OpCodes.Ble_Un },
+ { Condition.Ge, OpCodes.Bge },
+ { Condition.Lt, OpCodes.Blt },
+ { Condition.Gt, OpCodes.Bgt },
+ { Condition.Le, OpCodes.Ble }
};
- public void EmitCondBranch(ILLabel target, Cond cond)
+ public void EmitCondBranch(ILLabel target, Condition cond)
{
OpCode ilOp;
@@ -432,7 +475,7 @@ namespace ChocolArm64.Translation
public void EmitLdintzr(int index)
{
- if (index != CpuThreadState.ZrIndex)
+ if (index != RegisterAlias.Zr)
{
EmitLdint(index);
}
@@ -444,7 +487,7 @@ namespace ChocolArm64.Translation
public void EmitStintzr(int index)
{
- if (index != CpuThreadState.ZrIndex)
+ if (index != RegisterAlias.Zr)
{
EmitStint(index);
}
diff --git a/ChocolArm64/Translator.cs b/ChocolArm64/Translator.cs
index 47a05ba2..af2586f4 100644
--- a/ChocolArm64/Translator.cs
+++ b/ChocolArm64/Translator.cs
@@ -4,7 +4,6 @@ using ChocolArm64.Memory;
using ChocolArm64.State;
using ChocolArm64.Translation;
using System;
-using System.Reflection.Emit;
namespace ChocolArm64
{
@@ -23,34 +22,10 @@ namespace ChocolArm64
internal void ExecuteSubroutine(CpuThread thread, long position)
{
- //TODO: Both the execute A32/A64 methods should be merged on the future,
- //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)
- {
- do
- {
- OpCode64 opCode = Decoder.DecodeOpCode(state, memory, state.R15);
-
- opCode.Interpreter(state, memory, opCode);
- }
- while (state.R15 != 0 && state.Running);
+ ExecuteSubroutine(thread.ThreadState, thread.Memory, position);
}
- private void ExecuteSubroutineA64(CpuThreadState state, MemoryManager memory, long position)
+ private void ExecuteSubroutine(CpuThreadState state, MemoryManager memory, long position)
{
do
{
@@ -61,12 +36,12 @@ namespace ChocolArm64
if (!_cache.TryGetSubroutine(position, out TranslatedSub sub))
{
- sub = TranslateTier0(state, memory, position);
+ sub = TranslateTier0(memory, position, state.GetExecutionMode());
}
if (sub.ShouldReJit())
{
- TranslateTier1(state, memory, position);
+ TranslateTier1(memory, position, state.GetExecutionMode());
}
position = sub.Execute(state, memory);
@@ -79,9 +54,9 @@ namespace ChocolArm64
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);
@@ -98,9 +73,9 @@ namespace ChocolArm64
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);
diff --git a/ChocolArm64/TranslatorCache.cs b/ChocolArm64/TranslatorCache.cs
index 93da555e..9903ccaa 100644
--- a/ChocolArm64/TranslatorCache.cs
+++ b/ChocolArm64/TranslatorCache.cs
@@ -1,4 +1,3 @@
-using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index 840624be..8a419af3 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -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");
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");
LoadNso("rtld");
@@ -543,11 +533,6 @@ namespace Ryujinx.HLE.HOS
CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
}
- if (!metaData.Is64Bits)
- {
- throw new NotImplementedException("32-bit titles are not supported!");
- }
-
LoadNso("rtld");
LoadNso("main");
LoadNso("subsdk");
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
index 30fa4a5f..0268de7d 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/HleProcessDebugger.cs
@@ -78,6 +78,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
+ //TODO: ARM32.
long framePointer = (long)threadState.X29;
while (framePointer != 0)
@@ -245,6 +246,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
long ehHdrEndOffset = memory.ReadInt32(mod0Offset + 0x14) + mod0Offset;
long modObjOffset = memory.ReadInt32(mod0Offset + 0x18) + mod0Offset;
+ //TODO: Elf32.
while (true)
{
long tagVal = memory.ReadInt64(dynamicOffset + 0);
diff --git a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
index 855f3a18..fd473014 100644
--- a/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Process/KProcess.cs
@@ -3,6 +3,7 @@ using ChocolArm64.Events;
using ChocolArm64.Memory;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
+using Ryujinx.HLE.Exceptions;
using Ryujinx.HLE.HOS.Kernel.Common;
using Ryujinx.HLE.HOS.Kernel.Memory;
using Ryujinx.HLE.HOS.Kernel.SupervisorCall;
@@ -797,6 +798,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
{
context.ThreadState.Interrupt += InterruptHandler;
context.ThreadState.SvcCall += _svcHandler.SvcCall;
+ context.ThreadState.Undefined += UndefinedInstructionHandler;
}
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}.");
}
+
+ private void UndefinedInstructionHandler(object sender, InstUndefinedEventArgs e)
+ {
+ throw new UndefinedInstructionException(e.Position, e.RawOpCode);
+ }
}
} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
index 302e8f41..c29b0fbc 100644
--- a/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
+++ b/Ryujinx.HLE/HOS/Kernel/Threading/KThread.cs
@@ -152,6 +152,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
Context = new CpuThread(owner.Translator, owner.CpuMemory, (long)entrypoint);
+ Context.ThreadState.IsAarch32 = (Owner.MmuFlags & 1) == 0;
+
Context.ThreadState.X0 = argsPtr;
Context.ThreadState.X31 = stackTop;
diff --git a/Ryujinx.HLE/HOS/ProgramLoader.cs b/Ryujinx.HLE/HOS/ProgramLoader.cs
index 568c56ef..a41df557 100644
--- a/Ryujinx.HLE/HOS/ProgramLoader.cs
+++ b/Ryujinx.HLE/HOS/ProgramLoader.cs
@@ -125,9 +125,14 @@ namespace Ryujinx.HLE.HOS
IExecutable[] staticObjects,
byte[] arguments = null)
{
+ if (!metaData.Is64Bits)
+ {
+ Logger.PrintWarning(LogClass.Loader, "32-bits application detected!");
+ }
+
ulong argsStart = 0;
int argsSize = 0;
- ulong codeStart = 0x8000000;
+ ulong codeStart = metaData.Is64Bits ? 0x8000000UL : 0x200000UL;
int codeSize = 0;
ulong[] nsoBase = new ulong[staticObjects.Length];