Split main project into core,graphics and chocolarm4 subproject (#29)

This commit is contained in:
emmauss 2018-02-20 22:09:23 +02:00 committed by gdkchan
parent cb665bb715
commit 62b827f474
257 changed files with 415 additions and 285 deletions

View file

@ -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;
}
}
}

View file

@ -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
}
}

View file

@ -0,0 +1,10 @@
namespace ChocolArm64.Decoder
{
enum ADataOp
{
Adr = 0,
Arithmetic = 1,
Logical = 2,
BitField = 3
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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
}
}

View file

@ -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();
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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));
}
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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) { }
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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) { }
}
}

View file

@ -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) { }
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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));
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -0,0 +1,10 @@
namespace ChocolArm64.Decoder
{
enum AShiftType
{
Lsl,
Lsr,
Asr,
Ror
}
}

View file

@ -0,0 +1,13 @@
using ChocolArm64.Instruction;
using ChocolArm64.State;
namespace ChocolArm64.Decoder
{
interface IAOpCode
{
long Position { get; }
AInstEmitter Emitter { get; }
ARegisterSize RegisterSize { get; }
}
}

View file

@ -0,0 +1,10 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeAlu : IAOpCode
{
int Rd { get; }
int Rn { get; }
ADataOp DataOp { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeAluImm : IAOpCodeAlu
{
long Imm { get; }
}
}

View file

@ -0,0 +1,10 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeAluRs : IAOpCodeAlu
{
int Shift { get; }
int Rm { get; }
AShiftType ShiftType { get; }
}
}

View file

@ -0,0 +1,10 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeAluRx : IAOpCodeAlu
{
int Shift { get; }
int Rm { get; }
AIntType IntType { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeCond : IAOpCode
{
ACond Cond { get; }
}
}

View file

@ -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; }
}
}

View file

@ -0,0 +1,7 @@
namespace ChocolArm64.Decoder
{
interface IAOpCodeSimd : IAOpCode
{
int Size { get; }
}
}