diff options
Diffstat (limited to 'ChocolArm64/Decoders')
25 files changed, 349 insertions, 39 deletions
diff --git a/ChocolArm64/Decoders/BitUtils.cs b/ChocolArm64/Decoders/BitUtils.cs new file mode 100644 index 00000000..8b9fb5e3 --- /dev/null +++ b/ChocolArm64/Decoders/BitUtils.cs @@ -0,0 +1,59 @@ +namespace ChocolArm64.Decoders +{ + static class BitUtils + { + public static int HighestBitSet32(int value) + { + for (int bit = 31; bit >= 0; bit--) + { + if (((value >> bit) & 1) != 0) + { + return bit; + } + } + + return -1; + } + + private static readonly sbyte[] HbsNibbleTbl = { -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; + + public static int HighestBitSetNibble(int value) => HbsNibbleTbl[value & 0b1111]; + + public static long Replicate(long bits, int size) + { + long output = 0; + + for (int bit = 0; bit < 64; bit += size) + { + output |= bits << bit; + } + + return output; + } + + public static long FillWithOnes(int bits) + { + 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); + } + + public static ulong RotateRight(ulong bits, int shift, int size) + { + return (bits >> shift) | (bits << (size - shift)); + } + } +} 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 |
