diff options
| author | Alex Barney <thealexbarney@gmail.com> | 2018-10-30 19:43:02 -0600 |
|---|---|---|
| committer | gdkchan <gab.dark.100@gmail.com> | 2018-10-30 22:43:02 -0300 |
| commit | 9cb57fb4bb3bbae0ae052a5af4a96a49fc5d864d (patch) | |
| tree | 0c97425aeb311c142bc92a6fcc503cb2c07d4376 /ChocolArm64/Decoders | |
| parent | 5a87e58183578f5b84ca8d01cbb76aed11820f78 (diff) | |
Adjust naming conventions for Ryujinx and ChocolArm64 projects (#484)
* Change naming convention for Ryujinx project
* Change naming convention for ChocolArm64 project
* Fix NaN
* Remove unneeded this. from Ryujinx project
* Adjust naming from new PRs
* Name changes based on feedback
* How did this get removed?
* Rebasing fix
* Change FP enum case
* Remove prefix from ChocolArm64 classes - Part 1
* Remove prefix from ChocolArm64 classes - Part 2
* Fix alignment from last commit's renaming
* Rename namespaces
* Rename stragglers
* Fix alignment
* Rename OpCode class
* Missed a few
* Adjust alignment
Diffstat (limited to 'ChocolArm64/Decoders')
60 files changed, 1742 insertions, 0 deletions
diff --git a/ChocolArm64/Decoders/Block.cs b/ChocolArm64/Decoders/Block.cs new file mode 100644 index 00000000..c89ea7c6 --- /dev/null +++ b/ChocolArm64/Decoders/Block.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +namespace ChocolArm64.Decoders +{ + class Block + { + public long Position { get; set; } + public long EndPosition { get; set; } + + public Block Next { get; set; } + public Block Branch { get; set; } + + public List<OpCode64> OpCodes { get; private set; } + + public Block() + { + OpCodes = new List<OpCode64>(); + } + + public Block(long position) : this() + { + Position = position; + } + + public OpCode64 GetLastOp() + { + if (OpCodes.Count > 0) + { + return OpCodes[OpCodes.Count - 1]; + } + + return null; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/Cond.cs b/ChocolArm64/Decoders/Cond.cs new file mode 100644 index 00000000..57e12cd6 --- /dev/null +++ b/ChocolArm64/Decoders/Cond.cs @@ -0,0 +1,22 @@ +namespace ChocolArm64.Decoders +{ + enum Cond + { + Eq = 0, + Ne = 1, + GeUn = 2, + LtUn = 3, + Mi = 4, + Pl = 5, + Vs = 6, + Vc = 7, + GtUn = 8, + LeUn = 9, + Ge = 10, + Lt = 11, + Gt = 12, + Le = 13, + Al = 14, + Nv = 15 + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/DataOp.cs b/ChocolArm64/Decoders/DataOp.cs new file mode 100644 index 00000000..b7768bb4 --- /dev/null +++ b/ChocolArm64/Decoders/DataOp.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.Decoders +{ + enum DataOp + { + Adr = 0, + Arithmetic = 1, + Logical = 2, + BitField = 3 + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/Decoder.cs b/ChocolArm64/Decoders/Decoder.cs new file mode 100644 index 00000000..db43ac4f --- /dev/null +++ b/ChocolArm64/Decoders/Decoder.cs @@ -0,0 +1,239 @@ +using ChocolArm64.Instructions; +using ChocolArm64.Memory; +using ChocolArm64.State; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Reflection.Emit; + +namespace ChocolArm64.Decoders +{ + static class Decoder + { + private delegate object OpActivator(Inst inst, long position, int opCode); + + private static ConcurrentDictionary<Type, OpActivator> _opActivators; + + static Decoder() + { + _opActivators = new ConcurrentDictionary<Type, OpActivator>(); + } + + public static Block DecodeBasicBlock(CpuThreadState state, MemoryManager memory, long start) + { + Block block = new Block(start); + + FillBlock(state, memory, block); + + return block; + } + + public static (Block[] Graph, Block Root) DecodeSubroutine( + TranslatorCache cache, + CpuThreadState state, + MemoryManager memory, + long start) + { + Dictionary<long, Block> visited = new Dictionary<long, Block>(); + Dictionary<long, Block> visitedEnd = new Dictionary<long, Block>(); + + Queue<Block> blocks = new Queue<Block>(); + + Block Enqueue(long position) + { + if (!visited.TryGetValue(position, out Block output)) + { + output = new Block(position); + + blocks.Enqueue(output); + + visited.Add(position, output); + } + + return output; + } + + Block root = Enqueue(start); + + while (blocks.Count > 0) + { + Block current = blocks.Dequeue(); + + FillBlock(state, memory, current); + + //Set child blocks. "Branch" is the block the branch instruction + //points to (when taken), "Next" is the block at the next address, + //executed when the branch is not taken. For Unconditional Branches + //(except BL/BLR that are sub calls) or end of executable, Next is null. + if (current.OpCodes.Count > 0) + { + bool hasCachedSub = false; + + OpCode64 lastOp = current.GetLastOp(); + + if (lastOp is OpCodeBImm64 op) + { + if (op.Emitter == InstEmit.Bl) + { + hasCachedSub = cache.HasSubroutine(op.Imm); + } + else + { + current.Branch = Enqueue(op.Imm); + } + } + + if (!((lastOp is OpCodeBImmAl64) || + (lastOp is OpCodeBReg64)) || hasCachedSub) + { + current.Next = Enqueue(current.EndPosition); + } + } + + //If we have on the graph two blocks with the same end position, + //then we need to split the bigger block and have two small blocks, + //the end position of the bigger "Current" block should then be == to + //the position of the "Smaller" block. + while (visitedEnd.TryGetValue(current.EndPosition, out Block smaller)) + { + if (current.Position > smaller.Position) + { + Block temp = smaller; + + smaller = current; + current = temp; + } + + current.EndPosition = smaller.Position; + current.Next = smaller; + current.Branch = null; + + current.OpCodes.RemoveRange( + current.OpCodes.Count - smaller.OpCodes.Count, + smaller.OpCodes.Count); + + visitedEnd[smaller.EndPosition] = smaller; + } + + visitedEnd.Add(current.EndPosition, current); + } + + //Make and sort Graph blocks array by position. + Block[] graph = new Block[visited.Count]; + + while (visited.Count > 0) + { + ulong firstPos = ulong.MaxValue; + + foreach (Block block in visited.Values) + { + if (firstPos > (ulong)block.Position) + firstPos = (ulong)block.Position; + } + + Block current = visited[(long)firstPos]; + + do + { + graph[graph.Length - visited.Count] = current; + + visited.Remove(current.Position); + + current = current.Next; + } + while (current != null); + } + + return (graph, root); + } + + private static void FillBlock(CpuThreadState state, MemoryManager memory, Block block) + { + long position = block.Position; + + OpCode64 opCode; + + 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); + + block.OpCodes.Add(opCode); + + position += 4; + } + while (!(IsBranch(opCode) || IsException(opCode))); + + block.EndPosition = position; + } + + private static bool IsBranch(OpCode64 opCode) + { + return opCode is OpCodeBImm64 || + opCode is OpCodeBReg64; + } + + private static bool IsException(OpCode64 opCode) + { + return opCode.Emitter == InstEmit.Brk || + opCode.Emitter == InstEmit.Svc || + opCode.Emitter == InstEmit.Und; + } + + public static OpCode64 DecodeOpCode(CpuThreadState state, MemoryManager memory, long position) + { + int opCode = memory.ReadInt32(position); + + Inst inst; + + if (state.ExecutionMode == ExecutionMode.AArch64) + { + inst = OpCodeTable.GetInstA64(opCode); + } + else + { + //TODO: Thumb support. + inst = OpCodeTable.GetInstA32(opCode); + } + + OpCode64 decodedOpCode = new OpCode64(Inst.Undefined, position, opCode); + + if (inst.Type != null) + { + decodedOpCode = MakeOpCode(inst.Type, inst, position, opCode); + } + + return decodedOpCode; + } + + private static OpCode64 MakeOpCode(Type type, Inst inst, long position, int opCode) + { + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + OpActivator createInstance = _opActivators.GetOrAdd(type, CacheOpActivator); + + return (OpCode64)createInstance(inst, position, opCode); + } + + private static OpActivator CacheOpActivator(Type type) + { + Type[] argTypes = new Type[] { typeof(Inst), typeof(long), typeof(int) }; + + DynamicMethod mthd = new DynamicMethod($"Make{type.Name}", type, argTypes); + + ILGenerator generator = mthd.GetILGenerator(); + + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldarg_1); + generator.Emit(OpCodes.Ldarg_2); + generator.Emit(OpCodes.Newobj, type.GetConstructor(argTypes)); + generator.Emit(OpCodes.Ret); + + return (OpActivator)mthd.CreateDelegate(typeof(OpActivator)); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/DecoderHelper.cs b/ChocolArm64/Decoders/DecoderHelper.cs new file mode 100644 index 00000000..6ee279d7 --- /dev/null +++ b/ChocolArm64/Decoders/DecoderHelper.cs @@ -0,0 +1,107 @@ +using System; + +namespace ChocolArm64.Decoders +{ + static class DecoderHelper + { + public struct BitMask + { + public long WMask; + public long TMask; + public int Pos; + public int Shift; + public bool IsUndefined; + + public static BitMask Invalid => new BitMask { IsUndefined = true }; + } + + public static BitMask DecodeBitMask(int opCode, bool immediate) + { + int immS = (opCode >> 10) & 0x3f; + int immR = (opCode >> 16) & 0x3f; + + int n = (opCode >> 22) & 1; + int sf = (opCode >> 31) & 1; + + int length = BitUtils.HighestBitSet32((~immS & 0x3f) | (n << 6)); + + if (length < 1 || (sf == 0 && n != 0)) + { + return BitMask.Invalid; + } + + int size = 1 << length; + + int levels = size - 1; + + int s = immS & levels; + int r = immR & levels; + + if (immediate && s == levels) + { + return BitMask.Invalid; + } + + long wMask = BitUtils.FillWithOnes(s + 1); + long tMask = BitUtils.FillWithOnes(((s - r) & levels) + 1); + + if (r > 0) + { + wMask = BitUtils.RotateRight(wMask, r, size); + wMask &= BitUtils.FillWithOnes(size); + } + + return new BitMask() + { + WMask = BitUtils.Replicate(wMask, size), + TMask = BitUtils.Replicate(tMask, size), + + Pos = immS, + Shift = immR + }; + } + + public static long DecodeImm8Float(long imm, int size) + { + int e = 0, f = 0; + + switch (size) + { + case 0: e = 8; f = 23; break; + case 1: e = 11; f = 52; break; + + default: throw new ArgumentOutOfRangeException(nameof(size)); + } + + long value = (imm & 0x3f) << f - 4; + + long eBit = (imm >> 6) & 1; + long sBit = (imm >> 7) & 1; + + if (eBit != 0) + { + value |= (1L << e - 3) - 1 << f + 2; + } + + value |= (eBit ^ 1) << f + e - 1; + value |= sBit << f + e; + + return value; + } + + public static long DecodeImm26_2(int opCode) + { + return ((long)opCode << 38) >> 36; + } + + public static long DecodeImmS19_2(int opCode) + { + return (((long)opCode << 40) >> 43) & ~3; + } + + public static long DecodeImmS14_2(int opCode) + { + return (((long)opCode << 45) >> 48) & ~3; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCode64.cs b/ChocolArm64/Decoders/IOpCode64.cs new file mode 100644 index 00000000..e9407123 --- /dev/null +++ b/ChocolArm64/Decoders/IOpCode64.cs @@ -0,0 +1,13 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; + +namespace ChocolArm64.Decoders +{ + interface IOpCode64 + { + long Position { get; } + + InstEmitter Emitter { get; } + RegisterSize RegisterSize { get; } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCodeAlu64.cs b/ChocolArm64/Decoders/IOpCodeAlu64.cs new file mode 100644 index 00000000..b9a5fe9e --- /dev/null +++ b/ChocolArm64/Decoders/IOpCodeAlu64.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.Decoders +{ + interface IOpCodeAlu64 : IOpCode64 + { + int Rd { get; } + int Rn { get; } + + DataOp DataOp { get; } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCodeAluImm64.cs b/ChocolArm64/Decoders/IOpCodeAluImm64.cs new file mode 100644 index 00000000..4b305e27 --- /dev/null +++ b/ChocolArm64/Decoders/IOpCodeAluImm64.cs @@ -0,0 +1,7 @@ +namespace ChocolArm64.Decoders +{ + interface IOpCodeAluImm64 : IOpCodeAlu64 + { + long Imm { get; } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCodeAluRs64.cs b/ChocolArm64/Decoders/IOpCodeAluRs64.cs new file mode 100644 index 00000000..df503ae9 --- /dev/null +++ b/ChocolArm64/Decoders/IOpCodeAluRs64.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.Decoders +{ + interface IOpCodeAluRs64 : IOpCodeAlu64 + { + int Shift { get; } + int Rm { get; } + + ShiftType ShiftType { get; } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCodeAluRx64.cs b/ChocolArm64/Decoders/IOpCodeAluRx64.cs new file mode 100644 index 00000000..f41fc4d2 --- /dev/null +++ b/ChocolArm64/Decoders/IOpCodeAluRx64.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.Decoders +{ + interface IOpCodeAluRx64 : IOpCodeAlu64 + { + int Shift { get; } + int Rm { get; } + + IntType IntType { get; } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCodeCond64.cs b/ChocolArm64/Decoders/IOpCodeCond64.cs new file mode 100644 index 00000000..9c39d633 --- /dev/null +++ b/ChocolArm64/Decoders/IOpCodeCond64.cs @@ -0,0 +1,7 @@ +namespace ChocolArm64.Decoders +{ + interface IOpCodeCond64 : IOpCode64 + { + Cond Cond { get; } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCodeLit64.cs b/ChocolArm64/Decoders/IOpCodeLit64.cs new file mode 100644 index 00000000..c6dc2c7f --- /dev/null +++ b/ChocolArm64/Decoders/IOpCodeLit64.cs @@ -0,0 +1,11 @@ +namespace ChocolArm64.Decoders +{ + interface IOpCodeLit64 : IOpCode64 + { + int Rt { get; } + long Imm { get; } + int Size { get; } + bool Signed { get; } + bool Prefetch { get; } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IOpCodeSimd64.cs b/ChocolArm64/Decoders/IOpCodeSimd64.cs new file mode 100644 index 00000000..fc8f54d6 --- /dev/null +++ b/ChocolArm64/Decoders/IOpCodeSimd64.cs @@ -0,0 +1,7 @@ +namespace ChocolArm64.Decoders +{ + interface IOpCodeSimd64 : IOpCode64 + { + int Size { get; } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/IntType.cs b/ChocolArm64/Decoders/IntType.cs new file mode 100644 index 00000000..70f833ec --- /dev/null +++ b/ChocolArm64/Decoders/IntType.cs @@ -0,0 +1,14 @@ +namespace ChocolArm64.Decoders +{ + enum IntType + { + UInt8 = 0, + UInt16 = 1, + UInt32 = 2, + UInt64 = 3, + Int8 = 4, + Int16 = 5, + Int32 = 6, + Int64 = 7 + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCode64.cs b/ChocolArm64/Decoders/OpCode64.cs new file mode 100644 index 00000000..b2dc363b --- /dev/null +++ b/ChocolArm64/Decoders/OpCode64.cs @@ -0,0 +1,40 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; +using System; + +namespace ChocolArm64.Decoders +{ + class OpCode64 : IOpCode64 + { + 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 OpCode64(Inst inst, long position, int opCode) + { + Position = position; + RawOpCode = opCode; + + RegisterSize = RegisterSize.Int64; + + Emitter = inst.Emitter; + Interpreter = inst.Interpreter; + } + + public int GetBitsCount() + { + switch (RegisterSize) + { + case RegisterSize.Int32: return 32; + case RegisterSize.Int64: return 64; + case RegisterSize.Simd64: return 64; + case RegisterSize.Simd128: return 128; + } + + throw new InvalidOperationException(); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeAdr64.cs b/ChocolArm64/Decoders/OpCodeAdr64.cs new file mode 100644 index 00000000..98b2f07b --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeAdr64.cs @@ -0,0 +1,18 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeAdr64 : OpCode64 + { + public int Rd { get; private set; } + public long Imm { get; private set; } + + public OpCodeAdr64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rd = opCode & 0x1f; + + Imm = DecoderHelper.DecodeImmS19_2(opCode); + Imm |= ((long)opCode >> 29) & 3; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeAlu64.cs b/ChocolArm64/Decoders/OpCodeAlu64.cs new file mode 100644 index 00000000..5f094572 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeAlu64.cs @@ -0,0 +1,24 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; + +namespace ChocolArm64.Decoders +{ + class OpCodeAlu64 : OpCode64, IOpCodeAlu64 + { + public int Rd { get; protected set; } + public int Rn { get; private set; } + + public DataOp DataOp { get; private set; } + + public OpCodeAlu64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rd = (opCode >> 0) & 0x1f; + Rn = (opCode >> 5) & 0x1f; + DataOp = (DataOp)((opCode >> 24) & 0x3); + + RegisterSize = (opCode >> 31) != 0 + ? State.RegisterSize.Int64 + : State.RegisterSize.Int32; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeAluImm64.cs b/ChocolArm64/Decoders/OpCodeAluImm64.cs new file mode 100644 index 00000000..64ac08a7 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeAluImm64.cs @@ -0,0 +1,39 @@ +using ChocolArm64.Instructions; +using System; + +namespace ChocolArm64.Decoders +{ + class OpCodeAluImm64 : OpCodeAlu64, IOpCodeAluImm64 + { + public long Imm { get; private set; } + + public OpCodeAluImm64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + if (DataOp == DataOp.Arithmetic) + { + Imm = (opCode >> 10) & 0xfff; + + int shift = (opCode >> 22) & 3; + + Imm <<= shift * 12; + } + else if (DataOp == DataOp.Logical) + { + var bm = DecoderHelper.DecodeBitMask(opCode, true); + + if (bm.IsUndefined) + { + Emitter = InstEmit.Und; + + return; + } + + Imm = bm.WMask; + } + else + { + throw new ArgumentException(nameof(opCode)); + } + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeAluRs64.cs b/ChocolArm64/Decoders/OpCodeAluRs64.cs new file mode 100644 index 00000000..f24c7f37 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeAluRs64.cs @@ -0,0 +1,29 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeAluRs64 : OpCodeAlu64, IOpCodeAluRs64 + { + public int Shift { get; private set; } + public int Rm { get; private set; } + + public ShiftType ShiftType { get; private set; } + + public OpCodeAluRs64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + int shift = (opCode >> 10) & 0x3f; + + if (shift >= GetBitsCount()) + { + Emitter = InstEmit.Und; + + return; + } + + Shift = shift; + + Rm = (opCode >> 16) & 0x1f; + ShiftType = (ShiftType)((opCode >> 22) & 0x3); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeAluRx64.cs b/ChocolArm64/Decoders/OpCodeAluRx64.cs new file mode 100644 index 00000000..a36f94ca --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeAluRx64.cs @@ -0,0 +1,19 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeAluRx64 : OpCodeAlu64, IOpCodeAluRx64 + { + public int Shift { get; private set; } + public int Rm { get; private set; } + + public IntType IntType { get; private set; } + + public OpCodeAluRx64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Shift = (opCode >> 10) & 0x7; + IntType = (IntType)((opCode >> 13) & 0x7); + Rm = (opCode >> 16) & 0x1f; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeBImm64.cs b/ChocolArm64/Decoders/OpCodeBImm64.cs new file mode 100644 index 00000000..71c61bab --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeBImm64.cs @@ -0,0 +1,11 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeBImm64 : OpCode64 + { + public long Imm { get; protected set; } + + public OpCodeBImm64(Inst inst, long position, int opCode) : base(inst, position, opCode) { } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeBImmAl64.cs b/ChocolArm64/Decoders/OpCodeBImmAl64.cs new file mode 100644 index 00000000..f419ffa0 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeBImmAl64.cs @@ -0,0 +1,12 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeBImmAl64 : OpCodeBImm64 + { + public OpCodeBImmAl64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Imm = position + DecoderHelper.DecodeImm26_2(opCode); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeBImmCmp64.cs b/ChocolArm64/Decoders/OpCodeBImmCmp64.cs new file mode 100644 index 00000000..6f433199 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeBImmCmp64.cs @@ -0,0 +1,21 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; + +namespace ChocolArm64.Decoders +{ + class OpCodeBImmCmp64 : OpCodeBImm64 + { + public int Rt { get; private set; } + + public OpCodeBImmCmp64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rt = opCode & 0x1f; + + Imm = position + DecoderHelper.DecodeImmS19_2(opCode); + + RegisterSize = (opCode >> 31) != 0 + ? State.RegisterSize.Int64 + : State.RegisterSize.Int32; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeBImmCond64.cs b/ChocolArm64/Decoders/OpCodeBImmCond64.cs new file mode 100644 index 00000000..22702309 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeBImmCond64.cs @@ -0,0 +1,25 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeBImmCond64 : OpCodeBImm64, IOpCodeCond64 + { + public Cond Cond { get; private set; } + + public OpCodeBImmCond64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + int o0 = (opCode >> 4) & 1; + + if (o0 != 0) + { + Emitter = InstEmit.Und; + + return; + } + + Cond = (Cond)(opCode & 0xf); + + Imm = position + DecoderHelper.DecodeImmS19_2(opCode); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeBImmTest64.cs b/ChocolArm64/Decoders/OpCodeBImmTest64.cs new file mode 100644 index 00000000..a2e8baea --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeBImmTest64.cs @@ -0,0 +1,20 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeBImmTest64 : OpCodeBImm64 + { + public int Rt { get; private set; } + public int Pos { get; private set; } + + public OpCodeBImmTest64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rt = opCode & 0x1f; + + Imm = position + DecoderHelper.DecodeImmS14_2(opCode); + + Pos = (opCode >> 19) & 0x1f; + Pos |= (opCode >> 26) & 0x20; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeBReg64.cs b/ChocolArm64/Decoders/OpCodeBReg64.cs new file mode 100644 index 00000000..74dbff58 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeBReg64.cs @@ -0,0 +1,24 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeBReg64 : OpCode64 + { + public int Rn { get; private set; } + + public OpCodeBReg64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + int op4 = (opCode >> 0) & 0x1f; + int op2 = (opCode >> 16) & 0x1f; + + if (op2 != 0b11111 || op4 != 0b00000) + { + Emitter = InstEmit.Und; + + return; + } + + Rn = (opCode >> 5) & 0x1f; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeBfm64.cs b/ChocolArm64/Decoders/OpCodeBfm64.cs new file mode 100644 index 00000000..6891a8f4 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeBfm64.cs @@ -0,0 +1,29 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeBfm64 : OpCodeAlu64 + { + public long WMask { get; private set; } + public long TMask { get; private set; } + public int Pos { get; private set; } + public int Shift { get; private set; } + + public OpCodeBfm64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + var bm = DecoderHelper.DecodeBitMask(opCode, false); + + if (bm.IsUndefined) + { + Emitter = InstEmit.Und; + + return; + } + + WMask = bm.WMask; + TMask = bm.TMask; + Pos = bm.Pos; + Shift = bm.Shift; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeCcmp64.cs b/ChocolArm64/Decoders/OpCodeCcmp64.cs new file mode 100644 index 00000000..e2aae96d --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeCcmp64.cs @@ -0,0 +1,31 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; + +namespace ChocolArm64.Decoders +{ + class OpCodeCcmp64 : OpCodeAlu64, IOpCodeCond64 + { + public int Nzcv { get; private set; } + protected int RmImm; + + public Cond Cond { get; private set; } + + public OpCodeCcmp64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + int o3 = (opCode >> 4) & 1; + + if (o3 != 0) + { + Emitter = InstEmit.Und; + + return; + } + + Nzcv = (opCode >> 0) & 0xf; + Cond = (Cond)((opCode >> 12) & 0xf); + RmImm = (opCode >> 16) & 0x1f; + + Rd = CpuThreadState.ZrIndex; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeCcmpImm64.cs b/ChocolArm64/Decoders/OpCodeCcmpImm64.cs new file mode 100644 index 00000000..78d5de55 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeCcmpImm64.cs @@ -0,0 +1,11 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeCcmpImm64 : OpCodeCcmp64, IOpCodeAluImm64 + { + public long Imm => RmImm; + + public OpCodeCcmpImm64(Inst inst, long position, int opCode) : base(inst, position, opCode) { } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeCcmpReg64.cs b/ChocolArm64/Decoders/OpCodeCcmpReg64.cs new file mode 100644 index 00000000..a0544d98 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeCcmpReg64.cs @@ -0,0 +1,15 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeCcmpReg64 : OpCodeCcmp64, IOpCodeAluRs64 + { + public int Rm => RmImm; + + public int Shift => 0; + + public ShiftType ShiftType => ShiftType.Lsl; + + public OpCodeCcmpReg64(Inst inst, long position, int opCode) : base(inst, position, opCode) { } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeCsel64.cs b/ChocolArm64/Decoders/OpCodeCsel64.cs new file mode 100644 index 00000000..d085a823 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeCsel64.cs @@ -0,0 +1,17 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeCsel64 : OpCodeAlu64, IOpCodeCond64 + { + public int Rm { get; private set; } + + public Cond 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); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeException64.cs b/ChocolArm64/Decoders/OpCodeException64.cs new file mode 100644 index 00000000..2554124c --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeException64.cs @@ -0,0 +1,14 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeException64 : OpCode64 + { + public int Id { get; private set; } + + public OpCodeException64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Id = (opCode >> 5) & 0xffff; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeMem64.cs b/ChocolArm64/Decoders/OpCodeMem64.cs new file mode 100644 index 00000000..36e67583 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeMem64.cs @@ -0,0 +1,19 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeMem64 : OpCode64 + { + public int Rt { get; protected set; } + public int Rn { get; protected set; } + public int Size { get; protected set; } + public bool Extend64 { get; protected set; } + + public OpCodeMem64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rt = (opCode >> 0) & 0x1f; + Rn = (opCode >> 5) & 0x1f; + Size = (opCode >> 30) & 0x3; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeMemEx64.cs b/ChocolArm64/Decoders/OpCodeMemEx64.cs new file mode 100644 index 00000000..39935eb3 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeMemEx64.cs @@ -0,0 +1,16 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeMemEx64 : OpCodeMem64 + { + public int Rt2 { get; private set; } + public int Rs { get; private set; } + + public OpCodeMemEx64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rt2 = (opCode >> 10) & 0x1f; + Rs = (opCode >> 16) & 0x1f; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeMemImm64.cs b/ChocolArm64/Decoders/OpCodeMemImm64.cs new file mode 100644 index 00000000..edaa4970 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeMemImm64.cs @@ -0,0 +1,53 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeMemImm64 : OpCodeMem64 + { + public long Imm { get; protected set; } + public bool WBack { get; protected set; } + public bool PostIdx { get; protected set; } + protected bool Unscaled { get; private set; } + + private enum MemOp + { + Unscaled = 0, + PostIndexed = 1, + Unprivileged = 2, + PreIndexed = 3, + Unsigned + } + + public OpCodeMemImm64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Extend64 = ((opCode >> 22) & 3) == 2; + WBack = ((opCode >> 24) & 1) == 0; + + //The type is not valid for the Unsigned Immediate 12-bits encoding, + //because the bits 11:10 are used for the larger Immediate offset. + MemOp type = WBack ? (MemOp)((opCode >> 10) & 3) : MemOp.Unsigned; + + PostIdx = type == MemOp.PostIndexed; + Unscaled = type == MemOp.Unscaled || + type == MemOp.Unprivileged; + + //Unscaled and Unprivileged doesn't write back, + //but they do use the 9-bits Signed Immediate. + if (Unscaled) + { + WBack = false; + } + + if (WBack || Unscaled) + { + //9-bits Signed Immediate. + Imm = (opCode << 43) >> 55; + } + else + { + //12-bits Unsigned Immediate. + Imm = ((opCode >> 10) & 0xfff) << Size; + } + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeMemLit64.cs b/ChocolArm64/Decoders/OpCodeMemLit64.cs new file mode 100644 index 00000000..29bfeee3 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeMemLit64.cs @@ -0,0 +1,28 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeMemLit64 : OpCode64, IOpCodeLit64 + { + public int Rt { get; private set; } + public long Imm { get; private set; } + public int Size { get; private set; } + public bool Signed { get; private set; } + public bool Prefetch { get; private set; } + + public OpCodeMemLit64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rt = opCode & 0x1f; + + Imm = position + DecoderHelper.DecodeImmS19_2(opCode); + + switch ((opCode >> 30) & 3) + { + case 0: Size = 2; Signed = false; Prefetch = false; break; + case 1: Size = 3; Signed = false; Prefetch = false; break; + case 2: Size = 2; Signed = true; Prefetch = false; break; + case 3: Size = 0; Signed = false; Prefetch = true; break; + } + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeMemPair64.cs b/ChocolArm64/Decoders/OpCodeMemPair64.cs new file mode 100644 index 00000000..5b81c755 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeMemPair64.cs @@ -0,0 +1,25 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeMemPair64 : OpCodeMemImm64 + { + public int Rt2 { get; private set; } + + public OpCodeMemPair64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rt2 = (opCode >> 10) & 0x1f; + WBack = ((opCode >> 23) & 0x1) != 0; + PostIdx = ((opCode >> 23) & 0x3) == 1; + Extend64 = ((opCode >> 30) & 0x3) == 1; + Size = ((opCode >> 31) & 0x1) | 2; + + DecodeImm(opCode); + } + + protected void DecodeImm(int opCode) + { + Imm = ((long)(opCode >> 15) << 57) >> (57 - Size); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeMemReg64.cs b/ChocolArm64/Decoders/OpCodeMemReg64.cs new file mode 100644 index 00000000..3dd210fb --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeMemReg64.cs @@ -0,0 +1,20 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeMemReg64 : OpCodeMem64 + { + public bool Shift { get; private set; } + public int Rm { get; private set; } + + public IntType IntType { get; private set; } + + public OpCodeMemReg64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Shift = ((opCode >> 12) & 0x1) != 0; + IntType = (IntType)((opCode >> 13) & 0x7); + Rm = (opCode >> 16) & 0x1f; + Extend64 = ((opCode >> 22) & 0x3) == 2; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeMov64.cs b/ChocolArm64/Decoders/OpCodeMov64.cs new file mode 100644 index 00000000..f9697854 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeMov64.cs @@ -0,0 +1,36 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; + +namespace ChocolArm64.Decoders +{ + class OpCodeMov64 : OpCode64 + { + public int Rd { get; private set; } + public long Imm { get; private set; } + public int Pos { get; private set; } + + public OpCodeMov64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + int p1 = (opCode >> 22) & 1; + int sf = (opCode >> 31) & 1; + + if (sf == 0 && p1 != 0) + { + Emitter = InstEmit.Und; + + return; + } + + Rd = (opCode >> 0) & 0x1f; + Imm = (opCode >> 5) & 0xffff; + Pos = (opCode >> 21) & 0x3; + + Pos <<= 4; + Imm <<= Pos; + + RegisterSize = (opCode >> 31) != 0 + ? State.RegisterSize.Int64 + : State.RegisterSize.Int32; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeMul64.cs b/ChocolArm64/Decoders/OpCodeMul64.cs new file mode 100644 index 00000000..176b7b93 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeMul64.cs @@ -0,0 +1,16 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeMul64 : OpCodeAlu64 + { + public int Rm { get; private set; } + public int Ra { get; private set; } + + public OpCodeMul64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Ra = (opCode >> 10) & 0x1f; + Rm = (opCode >> 16) & 0x1f; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimd64.cs b/ChocolArm64/Decoders/OpCodeSimd64.cs new file mode 100644 index 00000000..a705e489 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimd64.cs @@ -0,0 +1,25 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimd64 : OpCode64, IOpCodeSimd64 + { + public int Rd { get; private set; } + public int Rn { get; private set; } + public int Opc { get; private set; } + public int Size { get; protected set; } + + public OpCodeSimd64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rd = (opCode >> 0) & 0x1f; + Rn = (opCode >> 5) & 0x1f; + Opc = (opCode >> 15) & 0x3; + Size = (opCode >> 22) & 0x3; + + RegisterSize = ((opCode >> 30) & 1) != 0 + ? RegisterSize.Simd128 + : RegisterSize.Simd64; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdCvt64.cs b/ChocolArm64/Decoders/OpCodeSimdCvt64.cs new file mode 100644 index 00000000..6c68a3af --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdCvt64.cs @@ -0,0 +1,31 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdCvt64 : OpCodeSimd64 + { + public int FBits { get; private set; } + + public OpCodeSimdCvt64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + //TODO: + //Und of Fixed Point variants. + int scale = (opCode >> 10) & 0x3f; + int sf = (opCode >> 31) & 0x1; + + /*if (Type != SF && !(Type == 2 && SF == 1)) + { + Emitter = AInstEmit.Und; + + return; + }*/ + + FBits = 64 - scale; + + RegisterSize = sf != 0 + ? State.RegisterSize.Int64 + : State.RegisterSize.Int32; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdExt64.cs b/ChocolArm64/Decoders/OpCodeSimdExt64.cs new file mode 100644 index 00000000..1c57f19c --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdExt64.cs @@ -0,0 +1,14 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdExt64 : OpCodeSimdReg64 + { + public int Imm4 { get; private set; } + + public OpCodeSimdExt64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Imm4 = (opCode >> 11) & 0xf; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdFcond64.cs b/ChocolArm64/Decoders/OpCodeSimdFcond64.cs new file mode 100644 index 00000000..b0f1c0eb --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdFcond64.cs @@ -0,0 +1,17 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdFcond64 : OpCodeSimdReg64, IOpCodeCond64 + { + public int Nzcv { get; private set; } + + public Cond 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); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdFmov64.cs b/ChocolArm64/Decoders/OpCodeSimdFmov64.cs new file mode 100644 index 00000000..6752e185 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdFmov64.cs @@ -0,0 +1,33 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdFmov64 : OpCode64, IOpCodeSimd64 + { + public int Rd { get; private set; } + public long Imm { get; private set; } + public int Size { get; private set; } + + public OpCodeSimdFmov64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + int imm5 = (opCode >> 5) & 0x1f; + int type = (opCode >> 22) & 0x3; + + if (imm5 != 0b00000 || type > 1) + { + Emitter = InstEmit.Und; + + return; + } + + Size = type; + + long imm; + + Rd = (opCode >> 0) & 0x1f; + imm = (opCode >> 13) & 0xff; + + Imm = DecoderHelper.DecodeImm8Float(imm, type); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdImm64.cs b/ChocolArm64/Decoders/OpCodeSimdImm64.cs new file mode 100644 index 00000000..3ef6a8c6 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdImm64.cs @@ -0,0 +1,101 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdImm64 : OpCode64, IOpCodeSimd64 + { + public int Rd { get; private set; } + public long Imm { get; private set; } + public int Size { get; private set; } + + public OpCodeSimdImm64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rd = opCode & 0x1f; + + int cMode = (opCode >> 12) & 0xf; + int op = (opCode >> 29) & 0x1; + + int modeLow = cMode & 1; + int modeHigh = cMode >> 1; + + long imm; + + imm = ((uint)opCode >> 5) & 0x1f; + imm |= ((uint)opCode >> 11) & 0xe0; + + if (modeHigh == 0b111) + { + Size = modeLow != 0 ? op : 3; + + switch (op | (modeLow << 1)) + { + case 0: + //64-bits Immediate. + //Transform abcd efgh into abcd efgh abcd efgh ... + imm = (long)((ulong)imm * 0x0101010101010101); + break; + + case 1: + //64-bits Immediate. + //Transform abcd efgh into aaaa aaaa bbbb bbbb ... + imm = (imm & 0xf0) >> 4 | (imm & 0x0f) << 4; + imm = (imm & 0xcc) >> 2 | (imm & 0x33) << 2; + imm = (imm & 0xaa) >> 1 | (imm & 0x55) << 1; + + imm = (long)((ulong)imm * 0x8040201008040201); + imm = (long)((ulong)imm & 0x8080808080808080); + + imm |= imm >> 4; + imm |= imm >> 2; + imm |= imm >> 1; + break; + + case 2: + case 3: + //Floating point Immediate. + imm = DecoderHelper.DecodeImm8Float(imm, Size); + break; + } + } + else if ((modeHigh & 0b110) == 0b100) + { + //16-bits shifted Immediate. + Size = 1; imm <<= (modeHigh & 1) << 3; + } + else if ((modeHigh & 0b100) == 0b000) + { + //32-bits shifted Immediate. + Size = 2; imm <<= modeHigh << 3; + } + else if ((modeHigh & 0b111) == 0b110) + { + //32-bits shifted Immediate (fill with ones). + Size = 2; imm = ShlOnes(imm, 8 << modeLow); + } + else + { + //8 bits without shift. + Size = 0; + } + + Imm = imm; + + RegisterSize = ((opCode >> 30) & 1) != 0 + ? State.RegisterSize.Simd128 + : State.RegisterSize.Simd64; + } + + private static long ShlOnes(long value, int shift) + { + if (shift != 0) + { + return value << shift | (long)(ulong.MaxValue >> (64 - shift)); + } + else + { + return value; + } + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdIns64.cs b/ChocolArm64/Decoders/OpCodeSimdIns64.cs new file mode 100644 index 00000000..3b25faeb --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdIns64.cs @@ -0,0 +1,36 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdIns64 : OpCodeSimd64 + { + public int SrcIndex { get; private set; } + public int DstIndex { get; private set; } + + public OpCodeSimdIns64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + int imm4 = (opCode >> 11) & 0xf; + int imm5 = (opCode >> 16) & 0x1f; + + if (imm5 == 0b10000) + { + Emitter = InstEmit.Und; + + return; + } + + Size = imm5 & -imm5; + + switch (Size) + { + case 1: Size = 0; break; + case 2: Size = 1; break; + case 4: Size = 2; break; + case 8: Size = 3; break; + } + + SrcIndex = imm4 >> Size; + DstIndex = imm5 >> (Size + 1); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdMemImm64.cs b/ChocolArm64/Decoders/OpCodeSimdMemImm64.cs new file mode 100644 index 00000000..9fbab567 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdMemImm64.cs @@ -0,0 +1,19 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdMemImm64 : OpCodeMemImm64, IOpCodeSimd64 + { + public OpCodeSimdMemImm64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Size |= (opCode >> 21) & 4; + + if (!WBack && !Unscaled && Size >= 4) + { + Imm <<= 4; + } + + Extend64 = false; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdMemLit64.cs b/ChocolArm64/Decoders/OpCodeSimdMemLit64.cs new file mode 100644 index 00000000..c98ffd03 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdMemLit64.cs @@ -0,0 +1,31 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdMemLit64 : OpCode64, IOpCodeSimd64, IOpCodeLit64 + { + public int Rt { get; private set; } + public long Imm { get; private set; } + public int Size { get; private set; } + public bool Signed => false; + public bool Prefetch => false; + + public OpCodeSimdMemLit64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + int opc = (opCode >> 30) & 3; + + if (opc == 3) + { + Emitter = InstEmit.Und; + + return; + } + + Rt = opCode & 0x1f; + + Imm = position + DecoderHelper.DecodeImmS19_2(opCode); + + Size = opc + 2; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdMemMs64.cs b/ChocolArm64/Decoders/OpCodeSimdMemMs64.cs new file mode 100644 index 00000000..0748ef43 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdMemMs64.cs @@ -0,0 +1,49 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdMemMs64 : OpCodeMemReg64, IOpCodeSimd64 + { + public int Reps { get; private set; } + public int SElems { get; private set; } + public int Elems { get; private set; } + public bool WBack { get; private set; } + + public OpCodeSimdMemMs64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + switch ((opCode >> 12) & 0xf) + { + case 0b0000: Reps = 1; SElems = 4; break; + case 0b0010: Reps = 4; SElems = 1; break; + case 0b0100: Reps = 1; SElems = 3; break; + case 0b0110: Reps = 3; SElems = 1; break; + case 0b0111: Reps = 1; SElems = 1; break; + case 0b1000: Reps = 1; SElems = 2; break; + case 0b1010: Reps = 2; SElems = 1; break; + + default: inst = Inst.Undefined; return; + } + + Size = (opCode >> 10) & 3; + WBack = ((opCode >> 23) & 1) != 0; + + bool q = ((opCode >> 30) & 1) != 0; + + if (!q && Size == 3 && SElems != 1) + { + inst = Inst.Undefined; + + return; + } + + Extend64 = false; + + RegisterSize = q + ? State.RegisterSize.Simd128 + : State.RegisterSize.Simd64; + + Elems = (GetBitsCount() >> 3) >> Size; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdMemPair64.cs b/ChocolArm64/Decoders/OpCodeSimdMemPair64.cs new file mode 100644 index 00000000..1b796742 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdMemPair64.cs @@ -0,0 +1,16 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdMemPair64 : OpCodeMemPair64, IOpCodeSimd64 + { + public OpCodeSimdMemPair64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Size = ((opCode >> 30) & 3) + 2; + + Extend64 = false; + + DecodeImm(opCode); + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdMemReg64.cs b/ChocolArm64/Decoders/OpCodeSimdMemReg64.cs new file mode 100644 index 00000000..4ccbbed2 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdMemReg64.cs @@ -0,0 +1,14 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdMemReg64 : OpCodeMemReg64, IOpCodeSimd64 + { + public OpCodeSimdMemReg64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Size |= (opCode >> 21) & 4; + + Extend64 = false; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdMemSs64.cs b/ChocolArm64/Decoders/OpCodeSimdMemSs64.cs new file mode 100644 index 00000000..07ec8ab7 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdMemSs64.cs @@ -0,0 +1,98 @@ +using ChocolArm64.Instructions; +using ChocolArm64.State; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdMemSs64 : OpCodeMemReg64, IOpCodeSimd64 + { + public int SElems { get; private set; } + public int Index { get; private set; } + public bool Replicate { get; private set; } + public bool WBack { get; private set; } + + public OpCodeSimdMemSs64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + int size = (opCode >> 10) & 3; + int s = (opCode >> 12) & 1; + int sElems = (opCode >> 12) & 2; + int scale = (opCode >> 14) & 3; + int l = (opCode >> 22) & 1; + int q = (opCode >> 30) & 1; + + sElems |= (opCode >> 21) & 1; + + sElems++; + + int index = (q << 3) | (s << 2) | size; + + switch (scale) + { + case 1: + { + if ((size & 1) != 0) + { + inst = Inst.Undefined; + + return; + } + + index >>= 1; + + break; + } + + case 2: + { + if ((size & 2) != 0 || + ((size & 1) != 0 && s != 0)) + { + inst = Inst.Undefined; + + return; + } + + if ((size & 1) != 0) + { + index >>= 3; + + scale = 3; + } + else + { + index >>= 2; + } + + break; + } + + case 3: + { + if (l == 0 || s != 0) + { + inst = Inst.Undefined; + + return; + } + + scale = size; + + Replicate = true; + + break; + } + } + + Index = index; + SElems = sElems; + Size = scale; + + Extend64 = false; + + WBack = ((opCode >> 23) & 1) != 0; + + RegisterSize = q != 0 + ? State.RegisterSize.Simd128 + : State.RegisterSize.Simd64; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdReg64.cs b/ChocolArm64/Decoders/OpCodeSimdReg64.cs new file mode 100644 index 00000000..4bf462de --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdReg64.cs @@ -0,0 +1,18 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdReg64 : OpCodeSimd64 + { + public bool Bit3 { get; private set; } + public int Ra { get; private set; } + public int Rm { get; protected set; } + + public OpCodeSimdReg64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Bit3 = ((opCode >> 3) & 0x1) != 0; + Ra = (opCode >> 10) & 0x1f; + Rm = (opCode >> 16) & 0x1f; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdRegElem64.cs b/ChocolArm64/Decoders/OpCodeSimdRegElem64.cs new file mode 100644 index 00000000..04e95861 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdRegElem64.cs @@ -0,0 +1,31 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdRegElem64 : OpCodeSimdReg64 + { + public int Index { get; private set; } + + public OpCodeSimdRegElem64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + switch (Size) + { + case 1: + Index = (opCode >> 20) & 3 | + (opCode >> 9) & 4; + + Rm &= 0xf; + + break; + + case 2: + Index = (opCode >> 21) & 1 | + (opCode >> 10) & 2; + + break; + + default: Emitter = InstEmit.Und; return; + } + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSimdRegElemF64.cs b/ChocolArm64/Decoders/OpCodeSimdRegElemF64.cs new file mode 100644 index 00000000..b5db7345 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdRegElemF64.cs @@ -0,0 +1,33 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdRegElemF64 : OpCodeSimdReg64 + { + public int Index { get; private set; } + + public OpCodeSimdRegElemF64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + switch ((opCode >> 21) & 3) // sz:L + { + case 0: // H:0 + Index = (opCode >> 10) & 2; // 0, 2 + + break; + + case 1: // H:1 + Index = (opCode >> 10) & 2; + Index++; // 1, 3 + + break; + + case 2: // H + Index = (opCode >> 11) & 1; // 0, 1 + + break; + + default: Emitter = InstEmit.Und; return; + } + } + } +} diff --git a/ChocolArm64/Decoders/OpCodeSimdShImm64.cs b/ChocolArm64/Decoders/OpCodeSimdShImm64.cs new file mode 100644 index 00000000..d4cd88d1 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdShImm64.cs @@ -0,0 +1,16 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdShImm64 : OpCodeSimd64 + { + public int Imm { get; private set; } + + public OpCodeSimdShImm64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Imm = (opCode >> 16) & 0x7f; + + Size = BitUtils.HighestBitSetNibble(Imm >> 3); + } + } +} diff --git a/ChocolArm64/Decoders/OpCodeSimdTbl64.cs b/ChocolArm64/Decoders/OpCodeSimdTbl64.cs new file mode 100644 index 00000000..13cc9090 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSimdTbl64.cs @@ -0,0 +1,12 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSimdTbl64 : OpCodeSimdReg64 + { + public OpCodeSimdTbl64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Size = ((opCode >> 13) & 3) + 1; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/OpCodeSystem64.cs b/ChocolArm64/Decoders/OpCodeSystem64.cs new file mode 100644 index 00000000..41c51565 --- /dev/null +++ b/ChocolArm64/Decoders/OpCodeSystem64.cs @@ -0,0 +1,24 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders +{ + class OpCodeSystem64 : OpCode64 + { + public int Rt { get; private set; } + public int Op2 { get; private set; } + public int CRm { get; private set; } + public int CRn { get; private set; } + public int Op1 { get; private set; } + public int Op0 { get; private set; } + + public OpCodeSystem64(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rt = (opCode >> 0) & 0x1f; + Op2 = (opCode >> 5) & 0x7; + CRm = (opCode >> 8) & 0xf; + CRn = (opCode >> 12) & 0xf; + Op1 = (opCode >> 16) & 0x7; + Op0 = ((opCode >> 19) & 0x1) | 2; + } + } +}
\ No newline at end of file diff --git a/ChocolArm64/Decoders/ShiftType.cs b/ChocolArm64/Decoders/ShiftType.cs new file mode 100644 index 00000000..5f6a7a4c --- /dev/null +++ b/ChocolArm64/Decoders/ShiftType.cs @@ -0,0 +1,10 @@ +namespace ChocolArm64.Decoders +{ + enum ShiftType + { + Lsl, + Lsr, + Asr, + Ror + } +}
\ No newline at end of file |
