aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/Decoder
diff options
context:
space:
mode:
authoremmauss <emmausssss@gmail.com>2018-02-20 22:09:23 +0200
committergdkchan <gab.dark.100@gmail.com>2018-02-20 17:09:23 -0300
commit62b827f474f0aa2152dd339fcc7cf31084e16a0b (patch)
tree0e5c55b341aee4db0ccb841a084f253ec5e05657 /ChocolArm64/Decoder
parentcb665bb715834526d73c9469d16114b287faaecd (diff)
Split main project into core,graphics and chocolarm4 subproject (#29)
Diffstat (limited to 'ChocolArm64/Decoder')
-rw-r--r--ChocolArm64/Decoder/ABlock.cs35
-rw-r--r--ChocolArm64/Decoder/ACond.cs22
-rw-r--r--ChocolArm64/Decoder/ADataOp.cs10
-rw-r--r--ChocolArm64/Decoder/ADecoder.cs207
-rw-r--r--ChocolArm64/Decoder/ADecoderHelper.cs107
-rw-r--r--ChocolArm64/Decoder/AIntType.cs14
-rw-r--r--ChocolArm64/Decoder/AOpCode.cs38
-rw-r--r--ChocolArm64/Decoder/AOpCodeAdr.cs18
-rw-r--r--ChocolArm64/Decoder/AOpCodeAlu.cs24
-rw-r--r--ChocolArm64/Decoder/AOpCodeAluImm.cs39
-rw-r--r--ChocolArm64/Decoder/AOpCodeAluRs.cs29
-rw-r--r--ChocolArm64/Decoder/AOpCodeAluRx.cs19
-rw-r--r--ChocolArm64/Decoder/AOpCodeBImm.cs11
-rw-r--r--ChocolArm64/Decoder/AOpCodeBImmAl.cs12
-rw-r--r--ChocolArm64/Decoder/AOpCodeBImmCmp.cs16
-rw-r--r--ChocolArm64/Decoder/AOpCodeBImmCond.cs25
-rw-r--r--ChocolArm64/Decoder/AOpCodeBImmTest.cs20
-rw-r--r--ChocolArm64/Decoder/AOpCodeBReg.cs24
-rw-r--r--ChocolArm64/Decoder/AOpCodeBfm.cs29
-rw-r--r--ChocolArm64/Decoder/AOpCodeCcmp.cs31
-rw-r--r--ChocolArm64/Decoder/AOpCodeCcmpImm.cs11
-rw-r--r--ChocolArm64/Decoder/AOpCodeCcmpReg.cs15
-rw-r--r--ChocolArm64/Decoder/AOpCodeCsel.cs17
-rw-r--r--ChocolArm64/Decoder/AOpCodeException.cs14
-rw-r--r--ChocolArm64/Decoder/AOpCodeMem.cs19
-rw-r--r--ChocolArm64/Decoder/AOpCodeMemEx.cs16
-rw-r--r--ChocolArm64/Decoder/AOpCodeMemImm.cs53
-rw-r--r--ChocolArm64/Decoder/AOpCodeMemLit.cs28
-rw-r--r--ChocolArm64/Decoder/AOpCodeMemPair.cs25
-rw-r--r--ChocolArm64/Decoder/AOpCodeMemReg.cs20
-rw-r--r--ChocolArm64/Decoder/AOpCodeMov.cs36
-rw-r--r--ChocolArm64/Decoder/AOpCodeMul.cs16
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimd.cs27
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdCvt.cs31
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdFcond.cs17
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdFmov.cs33
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdImm.cs94
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdIns.cs36
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdMemImm.cs19
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdMemLit.cs31
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdMemMs.cs49
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdMemPair.cs16
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdMemReg.cs14
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdMemSs.cs97
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdReg.cs18
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdRegElem.cs22
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdShImm.cs16
-rw-r--r--ChocolArm64/Decoder/AOpCodeSimdTbl.cs12
-rw-r--r--ChocolArm64/Decoder/AOpCodeSystem.cs24
-rw-r--r--ChocolArm64/Decoder/AShiftType.cs10
-rw-r--r--ChocolArm64/Decoder/IAOpCode.cs13
-rw-r--r--ChocolArm64/Decoder/IAOpCodeAlu.cs10
-rw-r--r--ChocolArm64/Decoder/IAOpCodeAluImm.cs7
-rw-r--r--ChocolArm64/Decoder/IAOpCodeAluRs.cs10
-rw-r--r--ChocolArm64/Decoder/IAOpCodeAluRx.cs10
-rw-r--r--ChocolArm64/Decoder/IAOpCodeCond.cs7
-rw-r--r--ChocolArm64/Decoder/IAOpCodeLit.cs11
-rw-r--r--ChocolArm64/Decoder/IAOpCodeSimd.cs7
58 files changed, 1641 insertions, 0 deletions
diff --git a/ChocolArm64/Decoder/ABlock.cs b/ChocolArm64/Decoder/ABlock.cs
new file mode 100644
index 00000000..32974c1a
--- /dev/null
+++ b/ChocolArm64/Decoder/ABlock.cs
@@ -0,0 +1,35 @@
+using System.Collections.Generic;
+
+namespace ChocolArm64.Decoder
+{
+ class ABlock
+ {
+ public long Position { get; set; }
+ public long EndPosition { get; set; }
+
+ public ABlock Next { get; set; }
+ public ABlock Branch { get; set; }
+
+ public List<AOpCode> OpCodes { get; private set; }
+
+ public ABlock()
+ {
+ OpCodes = new List<AOpCode>();
+ }
+
+ public ABlock(long Position) : this()
+ {
+ this.Position = Position;
+ }
+
+ public AOpCode GetLastOp()
+ {
+ if (OpCodes.Count > 0)
+ {
+ return OpCodes[OpCodes.Count - 1];
+ }
+
+ return null;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/ACond.cs b/ChocolArm64/Decoder/ACond.cs
new file mode 100644
index 00000000..f2da8bd2
--- /dev/null
+++ b/ChocolArm64/Decoder/ACond.cs
@@ -0,0 +1,22 @@
+namespace ChocolArm64.Decoder
+{
+ enum ACond
+ {
+ Eq = 0,
+ Ne = 1,
+ Ge_Un = 2,
+ Lt_Un = 3,
+ Mi = 4,
+ Pl = 5,
+ Vs = 6,
+ Vc = 7,
+ Gt_Un = 8,
+ Le_Un = 9,
+ Ge = 10,
+ Lt = 11,
+ Gt = 12,
+ Le = 13,
+ Al = 14,
+ Nv = 15
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/ADataOp.cs b/ChocolArm64/Decoder/ADataOp.cs
new file mode 100644
index 00000000..a5601a3a
--- /dev/null
+++ b/ChocolArm64/Decoder/ADataOp.cs
@@ -0,0 +1,10 @@
+namespace ChocolArm64.Decoder
+{
+ enum ADataOp
+ {
+ Adr = 0,
+ Arithmetic = 1,
+ Logical = 2,
+ BitField = 3
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/ADecoder.cs b/ChocolArm64/Decoder/ADecoder.cs
new file mode 100644
index 00000000..06a535c1
--- /dev/null
+++ b/ChocolArm64/Decoder/ADecoder.cs
@@ -0,0 +1,207 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.Memory;
+using System;
+using System.Collections.Generic;
+using System.Reflection.Emit;
+
+namespace ChocolArm64.Decoder
+{
+ static class ADecoder
+ {
+ public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(ATranslator Translator, long Start)
+ {
+ Dictionary<long, ABlock> Visited = new Dictionary<long, ABlock>();
+ Dictionary<long, ABlock> VisitedEnd = new Dictionary<long, ABlock>();
+
+ Queue<ABlock> Blocks = new Queue<ABlock>();
+
+ ABlock Enqueue(long Position)
+ {
+ if (!Visited.TryGetValue(Position, out ABlock Output))
+ {
+ Output = new ABlock(Position);
+
+ Blocks.Enqueue(Output);
+
+ Visited.Add(Position, Output);
+ }
+
+ return Output;
+ }
+
+ ABlock Root = Enqueue(Start);
+
+ while (Blocks.Count > 0)
+ {
+ ABlock Current = Blocks.Dequeue();
+
+ FillBlock(Translator.Thread.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;
+
+ AOpCode LastOp = Current.GetLastOp();
+
+ if (LastOp is AOpCodeBImm Op)
+ {
+ if (Op.Emitter == AInstEmit.Bl)
+ {
+ HasCachedSub = Translator.HasCachedSub(Op.Imm);
+ }
+ else
+ {
+ Current.Branch = Enqueue(Op.Imm);
+ }
+ }
+
+ if ((!(LastOp is AOpCodeBImmAl) &&
+ !(LastOp is AOpCodeBReg)) || HasCachedSub)
+ {
+ Current.Next = Enqueue(Current.EndPosition);
+ }
+ }
+
+ //If we have on the tree 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 ABlock Smaller))
+ {
+ if (Current.Position > Smaller.Position)
+ {
+ ABlock 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.
+ ABlock[] Graph = new ABlock[Visited.Count];
+
+ while (Visited.Count > 0)
+ {
+ ulong FirstPos = ulong.MaxValue;
+
+ foreach (ABlock Block in Visited.Values)
+ {
+ if (FirstPos > (ulong)Block.Position)
+ FirstPos = (ulong)Block.Position;
+ }
+
+ ABlock 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(AMemory Memory, ABlock Block)
+ {
+ long Position = Block.Position;
+
+ AOpCode OpCode;
+
+ do
+ {
+ OpCode = DecodeOpCode(Memory, Position);
+
+ Block.OpCodes.Add(OpCode);
+
+ Position += 4;
+ }
+ while (!(IsBranch(OpCode) || IsException(OpCode)));
+
+ Block.EndPosition = Position;
+ }
+
+ private static bool IsBranch(AOpCode OpCode)
+ {
+ return OpCode is AOpCodeBImm ||
+ OpCode is AOpCodeBReg;
+ }
+
+ private static bool IsException(AOpCode OpCode)
+ {
+ return OpCode.Emitter == AInstEmit.Brk ||
+ OpCode.Emitter == AInstEmit.Svc ||
+ OpCode.Emitter == AInstEmit.Und;
+ }
+
+ public static AOpCode DecodeOpCode(AMemory Memory, long Position)
+ {
+ int OpCode = Memory.ReadInt32(Position);
+
+ AInst Inst = AOpCodeTable.GetInst(OpCode);
+
+ AOpCode DecodedOpCode = new AOpCode(AInst.Undefined, Position, OpCode);
+
+ if (Inst.Type != null)
+ {
+ DecodedOpCode = CreateOpCode(Inst.Type, Inst, Position, OpCode);
+ }
+
+ return DecodedOpCode;
+ }
+
+ private delegate object OpActivator(AInst Inst, long Position, int OpCode);
+
+ private static Dictionary<Type, OpActivator> Activators = new Dictionary<Type, OpActivator>();
+
+ private static AOpCode CreateOpCode(Type Type, AInst Inst, long Position, int OpCode)
+ {
+ if (Type == null)
+ {
+ throw new ArgumentNullException(nameof(Type));
+ }
+
+ if (!Activators.TryGetValue(Type, out OpActivator CreateInstance))
+ {
+ Type[] ArgTypes = new Type[] { typeof(AInst), typeof(long), typeof(int) };
+
+ DynamicMethod Mthd = new DynamicMethod($"{Type.Name}_Create", 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);
+
+ CreateInstance = (OpActivator)Mthd.CreateDelegate(typeof(OpActivator));
+
+ Activators.Add(Type, CreateInstance);
+ }
+
+ return (AOpCode)CreateInstance(Inst, Position, OpCode);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/ADecoderHelper.cs b/ChocolArm64/Decoder/ADecoderHelper.cs
new file mode 100644
index 00000000..a2179f49
--- /dev/null
+++ b/ChocolArm64/Decoder/ADecoderHelper.cs
@@ -0,0 +1,107 @@
+using System;
+
+namespace ChocolArm64.Decoder
+{
+ static class ADecoderHelper
+ {
+ 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 = ABitUtils.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 = ABitUtils.FillWithOnes(S + 1);
+ long TMask = ABitUtils.FillWithOnes(((S - R) & Levels) + 1);
+
+ if (R > 0)
+ {
+ WMask = ABitUtils.RotateRight(WMask, R, Size);
+ WMask &= ABitUtils.FillWithOnes(Size);
+ }
+
+ return new BitMask()
+ {
+ WMask = ABitUtils.Replicate(WMask, Size),
+ TMask = ABitUtils.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/Decoder/AIntType.cs b/ChocolArm64/Decoder/AIntType.cs
new file mode 100644
index 00000000..242fdada
--- /dev/null
+++ b/ChocolArm64/Decoder/AIntType.cs
@@ -0,0 +1,14 @@
+namespace ChocolArm64.Decoder
+{
+ enum AIntType
+ {
+ 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/Decoder/AOpCode.cs b/ChocolArm64/Decoder/AOpCode.cs
new file mode 100644
index 00000000..5d127593
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCode.cs
@@ -0,0 +1,38 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+using System;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCode : IAOpCode
+ {
+ public long Position { get; private set; }
+ public int RawOpCode { get; private set; }
+
+ public AInstEmitter Emitter { get; protected set; }
+ public ARegisterSize RegisterSize { get; protected set; }
+
+ public AOpCode(AInst Inst, long Position, int OpCode)
+ {
+ this.Position = Position;
+ this.RawOpCode = OpCode;
+
+ RegisterSize = ARegisterSize.Int64;
+
+ Emitter = Inst.Emitter;
+ }
+
+ public int GetBitsCount()
+ {
+ switch (RegisterSize)
+ {
+ case ARegisterSize.Int32: return 32;
+ case ARegisterSize.Int64: return 64;
+ case ARegisterSize.SIMD64: return 64;
+ case ARegisterSize.SIMD128: return 128;
+ }
+
+ throw new InvalidOperationException();
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeAdr.cs b/ChocolArm64/Decoder/AOpCodeAdr.cs
new file mode 100644
index 00000000..3396281f
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeAdr.cs
@@ -0,0 +1,18 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeAdr : AOpCode
+ {
+ public int Rd { get; private set; }
+ public long Imm { get; private set; }
+
+ public AOpCodeAdr(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Rd = OpCode & 0x1f;
+
+ Imm = ADecoderHelper.DecodeImmS19_2(OpCode);
+ Imm |= ((long)OpCode >> 29) & 3;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeAlu.cs b/ChocolArm64/Decoder/AOpCodeAlu.cs
new file mode 100644
index 00000000..e1a44f04
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeAlu.cs
@@ -0,0 +1,24 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeAlu : AOpCode, IAOpCodeAlu
+ {
+ public int Rd { get; protected set; }
+ public int Rn { get; private set; }
+
+ public ADataOp DataOp { get; private set; }
+
+ public AOpCodeAlu(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Rd = (OpCode >> 0) & 0x1f;
+ Rn = (OpCode >> 5) & 0x1f;
+ DataOp = (ADataOp)((OpCode >> 24) & 0x3);
+
+ RegisterSize = (OpCode >> 31) != 0
+ ? ARegisterSize.Int64
+ : ARegisterSize.Int32;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeAluImm.cs b/ChocolArm64/Decoder/AOpCodeAluImm.cs
new file mode 100644
index 00000000..e913475a
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeAluImm.cs
@@ -0,0 +1,39 @@
+using ChocolArm64.Instruction;
+using System;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeAluImm : AOpCodeAlu, IAOpCodeAluImm
+ {
+ public long Imm { get; private set; }
+
+ public AOpCodeAluImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ if (DataOp == ADataOp.Arithmetic)
+ {
+ Imm = (OpCode >> 10) & 0xfff;
+
+ int Shift = (OpCode >> 22) & 3;
+
+ Imm <<= Shift * 12;
+ }
+ else if (DataOp == ADataOp.Logical)
+ {
+ var BM = ADecoderHelper.DecodeBitMask(OpCode, true);
+
+ if (BM.IsUndefined)
+ {
+ Emitter = AInstEmit.Und;
+
+ return;
+ }
+
+ Imm = BM.WMask;
+ }
+ else
+ {
+ throw new ArgumentException(nameof(OpCode));
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeAluRs.cs b/ChocolArm64/Decoder/AOpCodeAluRs.cs
new file mode 100644
index 00000000..9c215be3
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeAluRs.cs
@@ -0,0 +1,29 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeAluRs : AOpCodeAlu, IAOpCodeAluRs
+ {
+ public int Shift { get; private set; }
+ public int Rm { get; private set; }
+
+ public AShiftType ShiftType { get; private set; }
+
+ public AOpCodeAluRs(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ int Shift = (OpCode >> 10) & 0x3f;
+
+ if (Shift >= GetBitsCount())
+ {
+ Emitter = AInstEmit.Und;
+
+ return;
+ }
+
+ this.Shift = Shift;
+
+ Rm = (OpCode >> 16) & 0x1f;
+ ShiftType = (AShiftType)((OpCode >> 22) & 0x3);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeAluRx.cs b/ChocolArm64/Decoder/AOpCodeAluRx.cs
new file mode 100644
index 00000000..7dd72a68
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeAluRx.cs
@@ -0,0 +1,19 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeAluRx : AOpCodeAlu, IAOpCodeAluRx
+ {
+ public int Shift { get; private set; }
+ public int Rm { get; private set; }
+
+ public AIntType IntType { get; private set; }
+
+ public AOpCodeAluRx(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Shift = (OpCode >> 10) & 0x7;
+ IntType = (AIntType)((OpCode >> 13) & 0x7);
+ Rm = (OpCode >> 16) & 0x1f;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeBImm.cs b/ChocolArm64/Decoder/AOpCodeBImm.cs
new file mode 100644
index 00000000..6519d281
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeBImm.cs
@@ -0,0 +1,11 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeBImm : AOpCode
+ {
+ public long Imm { get; protected set; }
+
+ public AOpCodeBImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeBImmAl.cs b/ChocolArm64/Decoder/AOpCodeBImmAl.cs
new file mode 100644
index 00000000..a4ff686d
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeBImmAl.cs
@@ -0,0 +1,12 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeBImmAl : AOpCodeBImm
+ {
+ public AOpCodeBImmAl(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Imm = Position + ADecoderHelper.DecodeImm26_2(OpCode);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeBImmCmp.cs b/ChocolArm64/Decoder/AOpCodeBImmCmp.cs
new file mode 100644
index 00000000..1b6185da
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeBImmCmp.cs
@@ -0,0 +1,16 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeBImmCmp : AOpCodeBImm
+ {
+ public int Rt { get; private set; }
+
+ public AOpCodeBImmCmp(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Rt = OpCode & 0x1f;
+
+ Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeBImmCond.cs b/ChocolArm64/Decoder/AOpCodeBImmCond.cs
new file mode 100644
index 00000000..1310feb8
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeBImmCond.cs
@@ -0,0 +1,25 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeBImmCond : AOpCodeBImm, IAOpCodeCond
+ {
+ public ACond Cond { get; private set; }
+
+ public AOpCodeBImmCond(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ int O0 = (OpCode >> 4) & 1;
+
+ if (O0 != 0)
+ {
+ Emitter = AInstEmit.Und;
+
+ return;
+ }
+
+ Cond = (ACond)(OpCode & 0xf);
+
+ Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeBImmTest.cs b/ChocolArm64/Decoder/AOpCodeBImmTest.cs
new file mode 100644
index 00000000..73e57b7a
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeBImmTest.cs
@@ -0,0 +1,20 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeBImmTest : AOpCodeBImm
+ {
+ public int Rt { get; private set; }
+ public int Pos { get; private set; }
+
+ public AOpCodeBImmTest(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Rt = OpCode & 0x1f;
+
+ Imm = Position + ADecoderHelper.DecodeImmS14_2(OpCode);
+
+ Pos = (OpCode >> 19) & 0x1f;
+ Pos |= (OpCode >> 26) & 0x20;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeBReg.cs b/ChocolArm64/Decoder/AOpCodeBReg.cs
new file mode 100644
index 00000000..c9c600af
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeBReg.cs
@@ -0,0 +1,24 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeBReg : AOpCode
+ {
+ public int Rn { get; private set; }
+
+ public AOpCodeBReg(AInst 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 = AInstEmit.Und;
+
+ return;
+ }
+
+ Rn = (OpCode >> 5) & 0x1f;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeBfm.cs b/ChocolArm64/Decoder/AOpCodeBfm.cs
new file mode 100644
index 00000000..6498d8ec
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeBfm.cs
@@ -0,0 +1,29 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeBfm : AOpCodeAlu
+ {
+ 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 AOpCodeBfm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ var BM = ADecoderHelper.DecodeBitMask(OpCode, false);
+
+ if (BM.IsUndefined)
+ {
+ Emitter = AInstEmit.Und;
+
+ return;
+ }
+
+ WMask = BM.WMask;
+ TMask = BM.TMask;
+ Pos = BM.Pos;
+ Shift = BM.Shift;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeCcmp.cs b/ChocolArm64/Decoder/AOpCodeCcmp.cs
new file mode 100644
index 00000000..d0c7f779
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeCcmp.cs
@@ -0,0 +1,31 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeCcmp : AOpCodeAlu, IAOpCodeCond
+ {
+ public int NZCV { get; private set; }
+ protected int RmImm;
+
+ public ACond Cond { get; private set; }
+
+ public AOpCodeCcmp(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ int O3 = (OpCode >> 4) & 1;
+
+ if (O3 != 0)
+ {
+ Emitter = AInstEmit.Und;
+
+ return;
+ }
+
+ NZCV = (OpCode >> 0) & 0xf;
+ Cond = (ACond)((OpCode >> 12) & 0xf);
+ RmImm = (OpCode >> 16) & 0x1f;
+
+ Rd = AThreadState.ZRIndex;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeCcmpImm.cs b/ChocolArm64/Decoder/AOpCodeCcmpImm.cs
new file mode 100644
index 00000000..803eefc2
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeCcmpImm.cs
@@ -0,0 +1,11 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeCcmpImm : AOpCodeCcmp, IAOpCodeAluImm
+ {
+ public long Imm => RmImm;
+
+ public AOpCodeCcmpImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeCcmpReg.cs b/ChocolArm64/Decoder/AOpCodeCcmpReg.cs
new file mode 100644
index 00000000..c364ae68
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeCcmpReg.cs
@@ -0,0 +1,15 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeCcmpReg : AOpCodeCcmp, IAOpCodeAluRs
+ {
+ public int Rm => RmImm;
+
+ public int Shift => 0;
+
+ public AShiftType ShiftType => AShiftType.Lsl;
+
+ public AOpCodeCcmpReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode) { }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeCsel.cs b/ChocolArm64/Decoder/AOpCodeCsel.cs
new file mode 100644
index 00000000..cdef3e74
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeCsel.cs
@@ -0,0 +1,17 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeCsel : AOpCodeAlu, IAOpCodeCond
+ {
+ public int Rm { get; private set; }
+
+ public ACond Cond { get; private set; }
+
+ public AOpCodeCsel(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Rm = (OpCode >> 16) & 0x1f;
+ Cond = (ACond)((OpCode >> 12) & 0xf);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeException.cs b/ChocolArm64/Decoder/AOpCodeException.cs
new file mode 100644
index 00000000..4579c1a7
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeException.cs
@@ -0,0 +1,14 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeException : AOpCode
+ {
+ public int Id { get; private set; }
+
+ public AOpCodeException(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Id = (OpCode >> 5) & 0xffff;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeMem.cs b/ChocolArm64/Decoder/AOpCodeMem.cs
new file mode 100644
index 00000000..be5367cf
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeMem.cs
@@ -0,0 +1,19 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeMem : AOpCode
+ {
+ 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 AOpCodeMem(AInst 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/Decoder/AOpCodeMemEx.cs b/ChocolArm64/Decoder/AOpCodeMemEx.cs
new file mode 100644
index 00000000..3a28cfd7
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeMemEx.cs
@@ -0,0 +1,16 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeMemEx : AOpCodeMem
+ {
+ public int Rt2 { get; private set; }
+ public int Rs { get; private set; }
+
+ public AOpCodeMemEx(AInst 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/Decoder/AOpCodeMemImm.cs b/ChocolArm64/Decoder/AOpCodeMemImm.cs
new file mode 100644
index 00000000..14edc514
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeMemImm.cs
@@ -0,0 +1,53 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeMemImm : AOpCodeMem
+ {
+ 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 AOpCodeMemImm(AInst 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/Decoder/AOpCodeMemLit.cs b/ChocolArm64/Decoder/AOpCodeMemLit.cs
new file mode 100644
index 00000000..ad719a19
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeMemLit.cs
@@ -0,0 +1,28 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeMemLit : AOpCode, IAOpCodeLit
+ {
+ 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 AOpCodeMemLit(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Rt = OpCode & 0x1f;
+
+ Imm = Position + ADecoderHelper.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/Decoder/AOpCodeMemPair.cs b/ChocolArm64/Decoder/AOpCodeMemPair.cs
new file mode 100644
index 00000000..ec866c84
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeMemPair.cs
@@ -0,0 +1,25 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeMemPair : AOpCodeMemImm
+ {
+ public int Rt2 { get; private set; }
+
+ public AOpCodeMemPair(AInst 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/Decoder/AOpCodeMemReg.cs b/ChocolArm64/Decoder/AOpCodeMemReg.cs
new file mode 100644
index 00000000..98927128
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeMemReg.cs
@@ -0,0 +1,20 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeMemReg : AOpCodeMem
+ {
+ public bool Shift { get; private set; }
+ public int Rm { get; private set; }
+
+ public AIntType IntType { get; private set; }
+
+ public AOpCodeMemReg(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Shift = ((OpCode >> 12) & 0x1) != 0;
+ IntType = (AIntType)((OpCode >> 13) & 0x7);
+ Rm = (OpCode >> 16) & 0x1f;
+ Extend64 = ((OpCode >> 22) & 0x3) == 2;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeMov.cs b/ChocolArm64/Decoder/AOpCodeMov.cs
new file mode 100644
index 00000000..d5398646
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeMov.cs
@@ -0,0 +1,36 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeMov : AOpCode
+ {
+ public int Rd { get; private set; }
+ public long Imm { get; private set; }
+ public int Pos { get; private set; }
+
+ public AOpCodeMov(AInst 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 = AInstEmit.Und;
+
+ return;
+ }
+
+ Rd = (OpCode >> 0) & 0x1f;
+ Imm = (OpCode >> 5) & 0xffff;
+ Pos = (OpCode >> 21) & 0x3;
+
+ Pos <<= 4;
+ Imm <<= Pos;
+
+ RegisterSize = (OpCode >> 31) != 0
+ ? ARegisterSize.Int64
+ : ARegisterSize.Int32;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeMul.cs b/ChocolArm64/Decoder/AOpCodeMul.cs
new file mode 100644
index 00000000..ca2b0cdb
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeMul.cs
@@ -0,0 +1,16 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeMul : AOpCodeAlu
+ {
+ public int Rm { get; private set; }
+ public int Ra { get; private set; }
+
+ public AOpCodeMul(AInst 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/Decoder/AOpCodeSimd.cs b/ChocolArm64/Decoder/AOpCodeSimd.cs
new file mode 100644
index 00000000..5f940b22
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimd.cs
@@ -0,0 +1,27 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimd : AOpCode, IAOpCodeSimd
+ {
+ 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 int SizeF => Size & 1;
+
+ public AOpCodeSimd(AInst 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
+ ? ARegisterSize.SIMD128
+ : ARegisterSize.SIMD64;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSimdCvt.cs b/ChocolArm64/Decoder/AOpCodeSimdCvt.cs
new file mode 100644
index 00000000..41f4d3b1
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdCvt.cs
@@ -0,0 +1,31 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdCvt : AOpCodeSimd
+ {
+ public int FBits { get; private set; }
+
+ public AOpCodeSimdCvt(AInst 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
+ ? ARegisterSize.Int64
+ : ARegisterSize.Int32;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSimdFcond.cs b/ChocolArm64/Decoder/AOpCodeSimdFcond.cs
new file mode 100644
index 00000000..e38e7424
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdFcond.cs
@@ -0,0 +1,17 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdFcond : AOpCodeSimdReg, IAOpCodeCond
+ {
+ public int NZCV { get; private set; }
+
+ public ACond Cond { get; private set; }
+
+ public AOpCodeSimdFcond(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ NZCV = (OpCode >> 0) & 0xf;
+ Cond = (ACond)((OpCode >> 12) & 0xf);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSimdFmov.cs b/ChocolArm64/Decoder/AOpCodeSimdFmov.cs
new file mode 100644
index 00000000..3f888959
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdFmov.cs
@@ -0,0 +1,33 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdFmov : AOpCode, IAOpCodeSimd
+ {
+ public int Rd { get; private set; }
+ public long Imm { get; private set; }
+ public int Size { get; private set; }
+
+ public AOpCodeSimdFmov(AInst 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 = AInstEmit.Und;
+
+ return;
+ }
+
+ Size = Type;
+
+ long Imm;
+
+ Rd = (OpCode >> 0) & 0x1f;
+ Imm = (OpCode >> 13) & 0xff;
+
+ this.Imm = ADecoderHelper.DecodeImm8Float(Imm, Type);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSimdImm.cs b/ChocolArm64/Decoder/AOpCodeSimdImm.cs
new file mode 100644
index 00000000..2959aee6
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdImm.cs
@@ -0,0 +1,94 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdImm : AOpCode, IAOpCodeSimd
+ {
+ public int Rd { get; private set; }
+ public long Imm { get; private set; }
+ public int Size { get; private set; }
+
+ public AOpCodeSimdImm(AInst 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 = ADecoderHelper.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;
+ }
+
+ this.Imm = Imm;
+
+ RegisterSize = ((OpCode >> 30) & 1) != 0
+ ? ARegisterSize.SIMD128
+ : ARegisterSize.SIMD64;
+ }
+
+ private static long ShlOnes(long Value, int Shift)
+ {
+ return Value << Shift | (long)(ulong.MaxValue >> (64 - Shift));
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSimdIns.cs b/ChocolArm64/Decoder/AOpCodeSimdIns.cs
new file mode 100644
index 00000000..0b60bbe8
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdIns.cs
@@ -0,0 +1,36 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdIns : AOpCodeSimd
+ {
+ public int SrcIndex { get; private set; }
+ public int DstIndex { get; private set; }
+
+ public AOpCodeSimdIns(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ int Imm4 = (OpCode >> 11) & 0xf;
+ int Imm5 = (OpCode >> 16) & 0x1f;
+
+ if (Imm5 == 0b10000)
+ {
+ Emitter = AInstEmit.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/Decoder/AOpCodeSimdMemImm.cs b/ChocolArm64/Decoder/AOpCodeSimdMemImm.cs
new file mode 100644
index 00000000..1ef19a5d
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdMemImm.cs
@@ -0,0 +1,19 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdMemImm : AOpCodeMemImm, IAOpCodeSimd
+ {
+ public AOpCodeSimdMemImm(AInst 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/Decoder/AOpCodeSimdMemLit.cs b/ChocolArm64/Decoder/AOpCodeSimdMemLit.cs
new file mode 100644
index 00000000..ea6fe00b
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdMemLit.cs
@@ -0,0 +1,31 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdMemLit : AOpCode, IAOpCodeSimd, IAOpCodeLit
+ {
+ 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 AOpCodeSimdMemLit(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ int Opc = (OpCode >> 30) & 3;
+
+ if (Opc == 3)
+ {
+ Emitter = AInstEmit.Und;
+
+ return;
+ }
+
+ Rt = OpCode & 0x1f;
+
+ Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode);
+
+ Size = Opc + 2;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSimdMemMs.cs b/ChocolArm64/Decoder/AOpCodeSimdMemMs.cs
new file mode 100644
index 00000000..9ea979ba
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdMemMs.cs
@@ -0,0 +1,49 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdMemMs : AOpCodeMemReg, IAOpCodeSimd
+ {
+ 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 AOpCodeSimdMemMs(AInst 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 = AInst.Undefined; return;
+ }
+
+ Size = (OpCode >> 10) & 0x3;
+ WBack = ((OpCode >> 23) & 0x1) != 0;
+
+ bool Q = ((OpCode >> 30) & 1) != 0;
+
+ if (!Q && Size == 3 && SElems != 1)
+ {
+ Inst = AInst.Undefined;
+
+ return;
+ }
+
+ Extend64 = false;
+
+ RegisterSize = Q
+ ? ARegisterSize.SIMD128
+ : ARegisterSize.SIMD64;
+
+ Elems = (GetBitsCount() >> 3) >> Size;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSimdMemPair.cs b/ChocolArm64/Decoder/AOpCodeSimdMemPair.cs
new file mode 100644
index 00000000..db99e3d4
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdMemPair.cs
@@ -0,0 +1,16 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdMemPair : AOpCodeMemPair, IAOpCodeSimd
+ {
+ public AOpCodeSimdMemPair(AInst 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/Decoder/AOpCodeSimdMemReg.cs b/ChocolArm64/Decoder/AOpCodeSimdMemReg.cs
new file mode 100644
index 00000000..aabf4846
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdMemReg.cs
@@ -0,0 +1,14 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdMemReg : AOpCodeMemReg, IAOpCodeSimd
+ {
+ public AOpCodeSimdMemReg(AInst 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/Decoder/AOpCodeSimdMemSs.cs b/ChocolArm64/Decoder/AOpCodeSimdMemSs.cs
new file mode 100644
index 00000000..be4a8cd9
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdMemSs.cs
@@ -0,0 +1,97 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdMemSs : AOpCodeMemReg, IAOpCodeSimd
+ {
+ 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 AOpCodeSimdMemSs(AInst 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 = AInst.Undefined;
+
+ return;
+ }
+
+ Index >>= 1;
+
+ break;
+ }
+
+ case 2:
+ {
+ if ((Size & 2) != 0 ||
+ ((Size & 1) != 0 && S != 0))
+ {
+ Inst = AInst.Undefined;
+
+ return;
+ }
+
+ if ((Size & 1) != 0)
+ {
+ Index >>= 3;
+
+ Scale = 3;
+ }
+ else
+ {
+ Index >>= 2;
+ }
+
+ break;
+ }
+
+ case 3:
+ {
+ if (L == 0 || S != 0)
+ {
+ Inst = AInst.Undefined;
+
+ return;
+ }
+
+ Scale = Size;
+
+ Replicate = true;
+
+ break;
+ }
+ }
+
+ this.SElems = SElems;
+ this.Size = Scale;
+
+ Extend64 = false;
+
+ WBack = ((OpCode >> 23) & 0x1) != 0;
+
+ RegisterSize = Q != 0
+ ? ARegisterSize.SIMD128
+ : ARegisterSize.SIMD64;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSimdReg.cs b/ChocolArm64/Decoder/AOpCodeSimdReg.cs
new file mode 100644
index 00000000..10a4aff8
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdReg.cs
@@ -0,0 +1,18 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdReg : AOpCodeSimd
+ {
+ public bool Bit3 { get; private set; }
+ public int Ra { get; private set; }
+ public int Rm { get; private set; }
+
+ public AOpCodeSimdReg(AInst 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/Decoder/AOpCodeSimdRegElem.cs b/ChocolArm64/Decoder/AOpCodeSimdRegElem.cs
new file mode 100644
index 00000000..d878b12e
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdRegElem.cs
@@ -0,0 +1,22 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdRegElem : AOpCodeSimdReg
+ {
+ public int Index { get; private set; }
+
+ public AOpCodeSimdRegElem(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ if ((Size & 1) != 0)
+ {
+ Index = (OpCode >> 11) & 1;
+ }
+ else
+ {
+ Index = (OpCode >> 21) & 1 |
+ (OpCode >> 10) & 2;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSimdShImm.cs b/ChocolArm64/Decoder/AOpCodeSimdShImm.cs
new file mode 100644
index 00000000..6c839881
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdShImm.cs
@@ -0,0 +1,16 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdShImm : AOpCodeSimd
+ {
+ public int Imm { get; private set; }
+
+ public AOpCodeSimdShImm(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Imm = (OpCode >> 16) & 0x7f;
+
+ Size = ABitUtils.HighestBitSet32(Imm >> 3);
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSimdTbl.cs b/ChocolArm64/Decoder/AOpCodeSimdTbl.cs
new file mode 100644
index 00000000..c8ae5bac
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSimdTbl.cs
@@ -0,0 +1,12 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSimdTbl : AOpCodeSimdReg
+ {
+ public AOpCodeSimdTbl(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
+ {
+ Size = ((OpCode >> 13) & 3) + 1;
+ }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/AOpCodeSystem.cs b/ChocolArm64/Decoder/AOpCodeSystem.cs
new file mode 100644
index 00000000..3d81a5d4
--- /dev/null
+++ b/ChocolArm64/Decoder/AOpCodeSystem.cs
@@ -0,0 +1,24 @@
+using ChocolArm64.Instruction;
+
+namespace ChocolArm64.Decoder
+{
+ class AOpCodeSystem : AOpCode
+ {
+ 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 AOpCodeSystem(AInst 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/Decoder/AShiftType.cs b/ChocolArm64/Decoder/AShiftType.cs
new file mode 100644
index 00000000..34ceea20
--- /dev/null
+++ b/ChocolArm64/Decoder/AShiftType.cs
@@ -0,0 +1,10 @@
+namespace ChocolArm64.Decoder
+{
+ enum AShiftType
+ {
+ Lsl,
+ Lsr,
+ Asr,
+ Ror
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/IAOpCode.cs b/ChocolArm64/Decoder/IAOpCode.cs
new file mode 100644
index 00000000..44bf9cb2
--- /dev/null
+++ b/ChocolArm64/Decoder/IAOpCode.cs
@@ -0,0 +1,13 @@
+using ChocolArm64.Instruction;
+using ChocolArm64.State;
+
+namespace ChocolArm64.Decoder
+{
+ interface IAOpCode
+ {
+ long Position { get; }
+
+ AInstEmitter Emitter { get; }
+ ARegisterSize RegisterSize { get; }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/IAOpCodeAlu.cs b/ChocolArm64/Decoder/IAOpCodeAlu.cs
new file mode 100644
index 00000000..22af4c82
--- /dev/null
+++ b/ChocolArm64/Decoder/IAOpCodeAlu.cs
@@ -0,0 +1,10 @@
+namespace ChocolArm64.Decoder
+{
+ interface IAOpCodeAlu : IAOpCode
+ {
+ int Rd { get; }
+ int Rn { get; }
+
+ ADataOp DataOp { get; }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/IAOpCodeAluImm.cs b/ChocolArm64/Decoder/IAOpCodeAluImm.cs
new file mode 100644
index 00000000..04b5c5f7
--- /dev/null
+++ b/ChocolArm64/Decoder/IAOpCodeAluImm.cs
@@ -0,0 +1,7 @@
+namespace ChocolArm64.Decoder
+{
+ interface IAOpCodeAluImm : IAOpCodeAlu
+ {
+ long Imm { get; }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/IAOpCodeAluRs.cs b/ChocolArm64/Decoder/IAOpCodeAluRs.cs
new file mode 100644
index 00000000..5ca9de40
--- /dev/null
+++ b/ChocolArm64/Decoder/IAOpCodeAluRs.cs
@@ -0,0 +1,10 @@
+namespace ChocolArm64.Decoder
+{
+ interface IAOpCodeAluRs : IAOpCodeAlu
+ {
+ int Shift { get; }
+ int Rm { get; }
+
+ AShiftType ShiftType { get; }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/IAOpCodeAluRx.cs b/ChocolArm64/Decoder/IAOpCodeAluRx.cs
new file mode 100644
index 00000000..b49d5325
--- /dev/null
+++ b/ChocolArm64/Decoder/IAOpCodeAluRx.cs
@@ -0,0 +1,10 @@
+namespace ChocolArm64.Decoder
+{
+ interface IAOpCodeAluRx : IAOpCodeAlu
+ {
+ int Shift { get; }
+ int Rm { get; }
+
+ AIntType IntType { get; }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/IAOpCodeCond.cs b/ChocolArm64/Decoder/IAOpCodeCond.cs
new file mode 100644
index 00000000..1655abaa
--- /dev/null
+++ b/ChocolArm64/Decoder/IAOpCodeCond.cs
@@ -0,0 +1,7 @@
+namespace ChocolArm64.Decoder
+{
+ interface IAOpCodeCond : IAOpCode
+ {
+ ACond Cond { get; }
+ }
+} \ No newline at end of file
diff --git a/ChocolArm64/Decoder/IAOpCodeLit.cs b/ChocolArm64/Decoder/IAOpCodeLit.cs
new file mode 100644
index 00000000..0f5092d0
--- /dev/null
+++ b/ChocolArm64/Decoder/IAOpCodeLit.cs
@@ -0,0 +1,11 @@
+namespace ChocolArm64.Decoder
+{
+ interface IAOpCodeLit : IAOpCode
+ {
+ 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/Decoder/IAOpCodeSimd.cs b/ChocolArm64/Decoder/IAOpCodeSimd.cs
new file mode 100644
index 00000000..19032ad9
--- /dev/null
+++ b/ChocolArm64/Decoder/IAOpCodeSimd.cs
@@ -0,0 +1,7 @@
+namespace ChocolArm64.Decoder
+{
+ interface IAOpCodeSimd : IAOpCode
+ {
+ int Size { get; }
+ }
+} \ No newline at end of file