Move solution and projects to src

This commit is contained in:
TSR Berry 2023-04-08 01:22:00 +02:00 committed by Mary
parent cd124bda58
commit cee7121058
3466 changed files with 55 additions and 55 deletions

View file

@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
namespace ARMeilleure.Decoders
{
class Block
{
public ulong Address { get; set; }
public ulong EndAddress { get; set; }
public Block Next { get; set; }
public Block Branch { get; set; }
public bool Exit { get; set; }
public List<OpCode> OpCodes { get; }
public Block()
{
OpCodes = new List<OpCode>();
}
public Block(ulong address) : this()
{
Address = address;
}
public void Split(Block rightBlock)
{
int splitIndex = BinarySearch(OpCodes, rightBlock.Address);
if (OpCodes[splitIndex].Address < rightBlock.Address)
{
splitIndex++;
}
int splitCount = OpCodes.Count - splitIndex;
if (splitCount <= 0)
{
throw new ArgumentException("Can't split at right block address.");
}
rightBlock.EndAddress = EndAddress;
rightBlock.Next = Next;
rightBlock.Branch = Branch;
rightBlock.OpCodes.AddRange(OpCodes.GetRange(splitIndex, splitCount));
EndAddress = rightBlock.Address;
Next = rightBlock;
Branch = null;
OpCodes.RemoveRange(splitIndex, splitCount);
}
private static int BinarySearch(List<OpCode> opCodes, ulong address)
{
int left = 0;
int middle = 0;
int right = opCodes.Count - 1;
while (left <= right)
{
int size = right - left;
middle = left + (size >> 1);
OpCode opCode = opCodes[middle];
if (address == (ulong)opCode.Address)
{
break;
}
if (address < (ulong)opCode.Address)
{
right = middle - 1;
}
else
{
left = middle + 1;
}
}
return middle;
}
public OpCode GetLastOp()
{
if (OpCodes.Count > 0)
{
return OpCodes[OpCodes.Count - 1];
}
return null;
}
}
}

View file

@ -0,0 +1,32 @@
namespace ARMeilleure.Decoders
{
enum Condition
{
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
}
static class ConditionExtensions
{
public static Condition Invert(this Condition cond)
{
// Bit 0 of all conditions is basically a negation bit, so
// inverting this bit has the effect of inverting the condition.
return (Condition)((int)cond ^ 1);
}
}
}

View file

@ -0,0 +1,10 @@
namespace ARMeilleure.Decoders
{
enum DataOp
{
Adr = 0,
Arithmetic = 1,
Logical = 2,
BitField = 3
}
}

View file

@ -0,0 +1,391 @@
using ARMeilleure.Decoders.Optimizations;
using ARMeilleure.Instructions;
using ARMeilleure.Memory;
using ARMeilleure.State;
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace ARMeilleure.Decoders
{
static class Decoder
{
// We define a limit on the number of instructions that a function may have,
// this prevents functions being potentially too large, which would
// take too long to compile and use too much memory.
private const int MaxInstsPerFunction = 2500;
// For lower code quality translation, we set a lower limit since we're blocking execution.
private const int MaxInstsPerFunctionLowCq = 500;
public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, DecoderMode dMode)
{
List<Block> blocks = new List<Block>();
Queue<Block> workQueue = new Queue<Block>();
Dictionary<ulong, Block> visited = new Dictionary<ulong, Block>();
Debug.Assert(MaxInstsPerFunctionLowCq <= MaxInstsPerFunction);
int opsCount = 0;
int instructionLimit = highCq ? MaxInstsPerFunction : MaxInstsPerFunctionLowCq;
Block GetBlock(ulong blkAddress)
{
if (!visited.TryGetValue(blkAddress, out Block block))
{
block = new Block(blkAddress);
if ((dMode != DecoderMode.MultipleBlocks && visited.Count >= 1) || opsCount > instructionLimit || !memory.IsMapped(blkAddress))
{
block.Exit = true;
block.EndAddress = blkAddress;
}
workQueue.Enqueue(block);
visited.Add(blkAddress, block);
}
return block;
}
GetBlock(address);
while (workQueue.TryDequeue(out Block currBlock))
{
// Check if the current block is inside another block.
if (BinarySearch(blocks, currBlock.Address, out int nBlkIndex))
{
Block nBlock = blocks[nBlkIndex];
if (nBlock.Address == currBlock.Address)
{
throw new InvalidOperationException("Found duplicate block address on the list.");
}
currBlock.Exit = false;
nBlock.Split(currBlock);
blocks.Insert(nBlkIndex + 1, currBlock);
continue;
}
if (!currBlock.Exit)
{
// If we have a block after the current one, set the limit address.
ulong limitAddress = ulong.MaxValue;
if (nBlkIndex != blocks.Count)
{
Block nBlock = blocks[nBlkIndex];
int nextIndex = nBlkIndex + 1;
if (nBlock.Address < currBlock.Address && nextIndex < blocks.Count)
{
limitAddress = blocks[nextIndex].Address;
}
else if (nBlock.Address > currBlock.Address)
{
limitAddress = blocks[nBlkIndex].Address;
}
}
if (dMode == DecoderMode.SingleInstruction)
{
// Only read at most one instruction
limitAddress = currBlock.Address + 1;
}
FillBlock(memory, mode, currBlock, limitAddress);
opsCount += currBlock.OpCodes.Count;
if (currBlock.OpCodes.Count != 0)
{
// 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.
OpCode lastOp = currBlock.GetLastOp();
bool isCall = IsCall(lastOp);
if (lastOp is IOpCodeBImm op && !isCall)
{
currBlock.Branch = GetBlock((ulong)op.Immediate);
}
if (isCall || !(IsUnconditionalBranch(lastOp) || IsTrap(lastOp)))
{
currBlock.Next = GetBlock(currBlock.EndAddress);
}
}
}
// Insert the new block on the list (sorted by address).
if (blocks.Count != 0)
{
Block nBlock = blocks[nBlkIndex];
blocks.Insert(nBlkIndex + (nBlock.Address < currBlock.Address ? 1 : 0), currBlock);
}
else
{
blocks.Add(currBlock);
}
}
if (blocks.Count == 1 && blocks[0].OpCodes.Count == 0)
{
Debug.Assert(blocks[0].Exit);
Debug.Assert(blocks[0].Address == blocks[0].EndAddress);
throw new InvalidOperationException($"Decoded a single empty exit block. Entry point = 0x{address:X}.");
}
if (dMode == DecoderMode.MultipleBlocks)
{
return TailCallRemover.RunPass(address, blocks);
}
else
{
return blocks.ToArray();
}
}
public static bool BinarySearch(List<Block> blocks, ulong address, out int index)
{
index = 0;
int left = 0;
int right = blocks.Count - 1;
while (left <= right)
{
int size = right - left;
int middle = left + (size >> 1);
Block block = blocks[middle];
index = middle;
if (address >= block.Address && address < block.EndAddress)
{
return true;
}
if (address < block.Address)
{
right = middle - 1;
}
else
{
left = middle + 1;
}
}
return false;
}
private static void FillBlock(
IMemoryManager memory,
ExecutionMode mode,
Block block,
ulong limitAddress)
{
ulong address = block.Address;
int itBlockSize = 0;
OpCode opCode;
do
{
if (address >= limitAddress && itBlockSize == 0)
{
break;
}
opCode = DecodeOpCode(memory, address, mode);
block.OpCodes.Add(opCode);
address += (ulong)opCode.OpCodeSizeInBytes;
if (opCode is OpCodeT16IfThen it)
{
itBlockSize = it.IfThenBlockSize;
}
else if (itBlockSize > 0)
{
itBlockSize--;
}
}
while (!(IsBranch(opCode) || IsException(opCode)));
block.EndAddress = address;
}
private static bool IsBranch(OpCode opCode)
{
return opCode is OpCodeBImm ||
opCode is OpCodeBReg || IsAarch32Branch(opCode);
}
private static bool IsUnconditionalBranch(OpCode opCode)
{
return opCode is OpCodeBImmAl ||
opCode is OpCodeBReg || IsAarch32UnconditionalBranch(opCode);
}
private static bool IsAarch32UnconditionalBranch(OpCode opCode)
{
if (!(opCode is OpCode32 op))
{
return false;
}
// Compare and branch instructions are always conditional.
if (opCode.Instruction.Name == InstName.Cbz ||
opCode.Instruction.Name == InstName.Cbnz)
{
return false;
}
// Note: On ARM32, most instructions have conditional execution,
// so there's no "Always" (unconditional) branch like on ARM64.
// We need to check if the condition is "Always" instead.
return IsAarch32Branch(op) && op.Cond >= Condition.Al;
}
private static bool IsAarch32Branch(OpCode opCode)
{
// Note: On ARM32, most ALU operations can write to R15 (PC),
// so we must consider such operations as a branch in potential aswell.
if (opCode is IOpCode32Alu opAlu && opAlu.Rd == RegisterAlias.Aarch32Pc)
{
if (opCode is OpCodeT32)
{
return opCode.Instruction.Name != InstName.Tst && opCode.Instruction.Name != InstName.Teq &&
opCode.Instruction.Name != InstName.Cmp && opCode.Instruction.Name != InstName.Cmn;
}
return true;
}
// Same thing for memory operations. We have the cases where PC is a target
// register (Rt == 15 or (mask & (1 << 15)) != 0), and cases where there is
// a write back to PC (wback == true && Rn == 15), however the later may
// be "undefined" depending on the CPU, so compilers should not produce that.
if (opCode is IOpCode32Mem || opCode is IOpCode32MemMult)
{
int rt, rn;
bool wBack, isLoad;
if (opCode is IOpCode32Mem opMem)
{
rt = opMem.Rt;
rn = opMem.Rn;
wBack = opMem.WBack;
isLoad = opMem.IsLoad;
// For the dual load, we also need to take into account the
// case were Rt2 == 15 (PC).
if (rt == 14 && opMem.Instruction.Name == InstName.Ldrd)
{
rt = RegisterAlias.Aarch32Pc;
}
}
else if (opCode is IOpCode32MemMult opMemMult)
{
const int pcMask = 1 << RegisterAlias.Aarch32Pc;
rt = (opMemMult.RegisterMask & pcMask) != 0 ? RegisterAlias.Aarch32Pc : 0;
rn = opMemMult.Rn;
wBack = opMemMult.PostOffset != 0;
isLoad = opMemMult.IsLoad;
}
else
{
throw new NotImplementedException($"The type \"{opCode.GetType().Name}\" is not implemented on the decoder.");
}
if ((rt == RegisterAlias.Aarch32Pc && isLoad) ||
(rn == RegisterAlias.Aarch32Pc && wBack))
{
return true;
}
}
// Explicit branch instructions.
return opCode is IOpCode32BImm ||
opCode is IOpCode32BReg;
}
private static bool IsCall(OpCode opCode)
{
return opCode.Instruction.Name == InstName.Bl ||
opCode.Instruction.Name == InstName.Blr ||
opCode.Instruction.Name == InstName.Blx;
}
private static bool IsException(OpCode opCode)
{
return IsTrap(opCode) || opCode.Instruction.Name == InstName.Svc;
}
private static bool IsTrap(OpCode opCode)
{
return opCode.Instruction.Name == InstName.Brk ||
opCode.Instruction.Name == InstName.Trap ||
opCode.Instruction.Name == InstName.Und;
}
public static OpCode DecodeOpCode(IMemoryManager memory, ulong address, ExecutionMode mode)
{
int opCode = memory.Read<int>(address);
InstDescriptor inst;
OpCodeTable.MakeOp makeOp;
if (mode == ExecutionMode.Aarch64)
{
(inst, makeOp) = OpCodeTable.GetInstA64(opCode);
}
else
{
if (mode == ExecutionMode.Aarch32Arm)
{
(inst, makeOp) = OpCodeTable.GetInstA32(opCode);
}
else /* if (mode == ExecutionMode.Aarch32Thumb) */
{
(inst, makeOp) = OpCodeTable.GetInstT32(opCode);
}
}
if (makeOp != null)
{
return makeOp(inst, address, opCode);
}
else
{
if (mode == ExecutionMode.Aarch32Thumb)
{
return new OpCodeT16(inst, address, opCode);
}
else
{
return new OpCode(inst, address, opCode);
}
}
}
}
}

View file

@ -0,0 +1,167 @@
using ARMeilleure.Common;
namespace ARMeilleure.Decoders
{
static class DecoderHelper
{
static DecoderHelper()
{
Imm8ToFP32Table = BuildImm8ToFP32Table();
Imm8ToFP64Table = BuildImm8ToFP64Table();
}
public static readonly uint[] Imm8ToFP32Table;
public static readonly ulong[] Imm8ToFP64Table;
private static uint[] BuildImm8ToFP32Table()
{
uint[] tbl = new uint[256];
for (int idx = 0; idx < tbl.Length; idx++)
{
tbl[idx] = ExpandImm8ToFP32((uint)idx);
}
return tbl;
}
private static ulong[] BuildImm8ToFP64Table()
{
ulong[] tbl = new ulong[256];
for (int idx = 0; idx < tbl.Length; idx++)
{
tbl[idx] = ExpandImm8ToFP64((ulong)idx);
}
return tbl;
}
// abcdefgh -> aBbbbbbc defgh000 00000000 00000000 (B = ~b)
private static uint ExpandImm8ToFP32(uint imm)
{
uint MoveBit(uint bits, int from, int to)
{
return ((bits >> from) & 1U) << to;
}
return MoveBit(imm, 7, 31) | MoveBit(~imm, 6, 30) |
MoveBit(imm, 6, 29) | MoveBit( imm, 6, 28) |
MoveBit(imm, 6, 27) | MoveBit( imm, 6, 26) |
MoveBit(imm, 6, 25) | MoveBit( imm, 5, 24) |
MoveBit(imm, 4, 23) | MoveBit( imm, 3, 22) |
MoveBit(imm, 2, 21) | MoveBit( imm, 1, 20) |
MoveBit(imm, 0, 19);
}
// abcdefgh -> aBbbbbbb bbcdefgh 00000000 00000000 00000000 00000000 00000000 00000000 (B = ~b)
private static ulong ExpandImm8ToFP64(ulong imm)
{
ulong MoveBit(ulong bits, int from, int to)
{
return ((bits >> from) & 1UL) << to;
}
return MoveBit(imm, 7, 63) | MoveBit(~imm, 6, 62) |
MoveBit(imm, 6, 61) | MoveBit( imm, 6, 60) |
MoveBit(imm, 6, 59) | MoveBit( imm, 6, 58) |
MoveBit(imm, 6, 57) | MoveBit( imm, 6, 56) |
MoveBit(imm, 6, 55) | MoveBit( imm, 6, 54) |
MoveBit(imm, 5, 53) | MoveBit( imm, 4, 52) |
MoveBit(imm, 3, 51) | MoveBit( imm, 2, 50) |
MoveBit(imm, 1, 49) | MoveBit( imm, 0, 48);
}
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.HighestBitSet((~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 DecodeImm24_2(int opCode)
{
return ((long)opCode << 40) >> 38;
}
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;
}
public static bool VectorArgumentsInvalid(bool q, params int[] args)
{
if (q)
{
for (int i = 0; i < args.Length; i++)
{
if ((args[i] & 1) == 1)
{
return true;
}
}
}
return false;
}
}
}

View file

@ -0,0 +1,9 @@
namespace ARMeilleure.Decoders
{
enum DecoderMode
{
MultipleBlocks,
SingleBlock,
SingleInstruction,
}
}

View file

@ -0,0 +1,17 @@
using ARMeilleure.IntermediateRepresentation;
namespace ARMeilleure.Decoders
{
interface IOpCode
{
ulong Address { get; }
InstDescriptor Instruction { get; }
RegisterSize RegisterSize { get; }
int GetBitsCount();
OperandType GetOperandType();
}
}

View file

@ -0,0 +1,9 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32 : IOpCode
{
Condition Cond { get; }
uint GetPc();
}
}

View file

@ -0,0 +1,9 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32Adr
{
int Rd { get; }
int Immediate { get; }
}
}

View file

@ -0,0 +1,8 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32Alu : IOpCode32, IOpCode32HasSetFlags
{
int Rd { get; }
int Rn { get; }
}
}

View file

@ -0,0 +1,14 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluBf
{
int Rd { get; }
int Rn { get; }
int Msb { get; }
int Lsb { get; }
int SourceMask => (int)(0xFFFFFFFF >> (31 - Msb));
int DestMask => SourceMask & (int)(0xFFFFFFFF << Lsb);
}
}

View file

@ -0,0 +1,9 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluImm : IOpCode32Alu
{
int Immediate { get; }
bool IsRotated { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluImm16 : IOpCode32Alu
{
int Immediate { get; }
}
}

View file

@ -0,0 +1,11 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluMla : IOpCode32AluReg
{
int Ra { get; }
bool NHigh { get; }
bool MHigh { get; }
bool R { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluReg : IOpCode32Alu
{
int Rm { get; }
}
}

View file

@ -0,0 +1,10 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluRsImm : IOpCode32Alu
{
int Rm { get; }
int Immediate { get; }
ShiftType ShiftType { get; }
}
}

View file

@ -0,0 +1,10 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluRsReg : IOpCode32Alu
{
int Rm { get; }
int Rs { get; }
ShiftType ShiftType { get; }
}
}

View file

@ -0,0 +1,13 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluUmull : IOpCode32, IOpCode32HasSetFlags
{
int RdLo { get; }
int RdHi { get; }
int Rn { get; }
int Rm { get; }
bool NHigh { get; }
bool MHigh { get; }
}
}

View file

@ -0,0 +1,8 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32AluUx : IOpCode32AluReg
{
int RotateBits { get; }
bool Add { get; }
}
}

View file

@ -0,0 +1,4 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32BImm : IOpCode32, IOpCodeBImm { }
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32BReg : IOpCode32
{
int Rm { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32Exception
{
int Id { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32HasSetFlags
{
bool? SetFlags { get; }
}
}

View file

@ -0,0 +1,16 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32Mem : IOpCode32
{
int Rt { get; }
int Rt2 => Rt | 1;
int Rn { get; }
bool WBack { get; }
bool IsLoad { get; }
bool Index { get; }
bool Add { get; }
int Immediate { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32MemEx : IOpCode32Mem
{
int Rd { get; }
}
}

View file

@ -0,0 +1,15 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32MemMult : IOpCode32
{
int Rn { get; }
int RegisterMask { get; }
int PostOffset { get; }
bool IsLoad { get; }
int Offset { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32MemReg : IOpCode32Mem
{
int Rm { get; }
}
}

View file

@ -0,0 +1,8 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32MemRsImm : IOpCode32Mem
{
int Rm { get; }
ShiftType ShiftType { get; }
}
}

View file

@ -0,0 +1,4 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32Simd : IOpCode32, IOpCodeSimd { }
}

View file

@ -0,0 +1,9 @@
namespace ARMeilleure.Decoders
{
interface IOpCode32SimdImm : IOpCode32Simd
{
int Vd { get; }
long Immediate { get; }
int Elems { get; }
}
}

View file

@ -0,0 +1,10 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeAlu : IOpCode
{
int Rd { get; }
int Rn { get; }
DataOp DataOp { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeAluImm : IOpCodeAlu
{
long Immediate { get; }
}
}

View file

@ -0,0 +1,10 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeAluRs : IOpCodeAlu
{
int Shift { get; }
int Rm { get; }
ShiftType ShiftType { get; }
}
}

View file

@ -0,0 +1,10 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeAluRx : IOpCodeAlu
{
int Shift { get; }
int Rm { get; }
IntType IntType { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeBImm : IOpCode
{
long Immediate { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeCond : IOpCode
{
Condition Cond { get; }
}
}

View file

@ -0,0 +1,11 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeLit : IOpCode
{
int Rt { get; }
long Immediate { get; }
int Size { get; }
bool Signed { get; }
bool Prefetch { get; }
}
}

View file

@ -0,0 +1,7 @@
namespace ARMeilleure.Decoders
{
interface IOpCodeSimd : IOpCode
{
int Size { get; }
}
}

View file

@ -0,0 +1,18 @@
using ARMeilleure.Instructions;
namespace ARMeilleure.Decoders
{
readonly struct InstDescriptor
{
public static InstDescriptor Undefined => new InstDescriptor(InstName.Und, InstEmit.Und);
public InstName Name { get; }
public InstEmitter Emitter { get; }
public InstDescriptor(InstName name, InstEmitter emitter)
{
Name = name;
Emitter = emitter;
}
}
}

View file

@ -0,0 +1,6 @@
using ARMeilleure.Translation;
namespace ARMeilleure.Decoders
{
delegate void InstEmitter(ArmEmitterContext context);
}

View file

@ -0,0 +1,14 @@
namespace ARMeilleure.Decoders
{
enum IntType
{
UInt8 = 0,
UInt16 = 1,
UInt32 = 2,
UInt64 = 3,
Int8 = 4,
Int16 = 5,
Int32 = 6,
Int64 = 7
}
}

View file

@ -0,0 +1,49 @@
using ARMeilleure.IntermediateRepresentation;
using System;
namespace ARMeilleure.Decoders
{
class OpCode : IOpCode
{
public ulong Address { get; }
public int RawOpCode { get; }
public int OpCodeSizeInBytes { get; protected set; } = 4;
public InstDescriptor Instruction { get; protected set; }
public RegisterSize RegisterSize { get; protected set; }
public static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode(inst, address, opCode);
public OpCode(InstDescriptor inst, ulong address, int opCode)
{
Instruction = inst;
Address = address;
RawOpCode = opCode;
RegisterSize = RegisterSize.Int64;
}
public int GetPairsCount() => GetBitsCount() / 16;
public int GetBytesCount() => GetBitsCount() / 8;
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();
}
public OperandType GetOperandType()
{
return RegisterSize == RegisterSize.Int32 ? OperandType.I32 : OperandType.I64;
}
}
}

View file

@ -0,0 +1,34 @@
namespace ARMeilleure.Decoders
{
class OpCode32 : OpCode
{
public Condition Cond { get; protected set; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32(inst, address, opCode);
public OpCode32(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
RegisterSize = RegisterSize.Int32;
Cond = (Condition)((uint)opCode >> 28);
}
public bool IsThumb { get; protected init; } = false;
public uint GetPc()
{
// Due to backwards compatibility and legacy behavior of ARMv4 CPUs pipeline,
// the PC actually points 2 instructions ahead.
if (IsThumb)
{
// PC is ahead by 4 in thumb mode whether or not the current instruction
// is 16 or 32 bit.
return (uint)Address + 4u;
}
else
{
return (uint)Address + 8u;
}
}
}
}

View file

@ -0,0 +1,20 @@
namespace ARMeilleure.Decoders
{
class OpCode32Alu : OpCode32, IOpCode32Alu
{
public int Rd { get; }
public int Rn { get; }
public bool? SetFlags { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Alu(inst, address, opCode);
public OpCode32Alu(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 12) & 0xf;
Rn = (opCode >> 16) & 0xf;
SetFlags = ((opCode >> 20) & 1) != 0;
}
}
}

View file

@ -0,0 +1,22 @@
namespace ARMeilleure.Decoders
{
class OpCode32AluBf : OpCode32, IOpCode32AluBf
{
public int Rd { get; }
public int Rn { get; }
public int Msb { get; }
public int Lsb { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluBf(inst, address, opCode);
public OpCode32AluBf(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 12) & 0xf;
Rn = (opCode >> 0) & 0xf;
Msb = (opCode >> 16) & 0x1f;
Lsb = (opCode >> 7) & 0x1f;
}
}
}

View file

@ -0,0 +1,23 @@
using ARMeilleure.Common;
namespace ARMeilleure.Decoders
{
class OpCode32AluImm : OpCode32Alu, IOpCode32AluImm
{
public int Immediate { get; }
public bool IsRotated { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluImm(inst, address, opCode);
public OpCode32AluImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
int value = (opCode >> 0) & 0xff;
int shift = (opCode >> 8) & 0xf;
Immediate = BitUtils.RotateRight(value, shift * 2, 32);
IsRotated = shift != 0;
}
}
}

View file

@ -0,0 +1,17 @@
namespace ARMeilleure.Decoders
{
class OpCode32AluImm16 : OpCode32Alu, IOpCode32AluImm16
{
public int Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluImm16(inst, address, opCode);
public OpCode32AluImm16(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
int imm12 = opCode & 0xfff;
int imm4 = (opCode >> 16) & 0xf;
Immediate = (imm4 << 12) | imm12;
}
}
}

View file

@ -0,0 +1,30 @@
namespace ARMeilleure.Decoders
{
class OpCode32AluMla : OpCode32, IOpCode32AluMla
{
public int Rn { get; }
public int Rm { get; }
public int Ra { get; }
public int Rd { get; }
public bool NHigh { get; }
public bool MHigh { get; }
public bool R { get; }
public bool? SetFlags { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluMla(inst, address, opCode);
public OpCode32AluMla(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rn = (opCode >> 0) & 0xf;
Rm = (opCode >> 8) & 0xf;
Ra = (opCode >> 12) & 0xf;
Rd = (opCode >> 16) & 0xf;
R = (opCode & (1 << 5)) != 0;
NHigh = ((opCode >> 5) & 0x1) == 1;
MHigh = ((opCode >> 6) & 0x1) == 1;
SetFlags = ((opCode >> 20) & 1) != 0;
}
}
}

View file

@ -0,0 +1,14 @@
namespace ARMeilleure.Decoders
{
class OpCode32AluReg : OpCode32Alu, IOpCode32AluReg
{
public int Rm { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluReg(inst, address, opCode);
public OpCode32AluReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rm = (opCode >> 0) & 0xf;
}
}
}

View file

@ -0,0 +1,20 @@
namespace ARMeilleure.Decoders
{
class OpCode32AluRsImm : OpCode32Alu, IOpCode32AluRsImm
{
public int Rm { get; }
public int Immediate { get; }
public ShiftType ShiftType { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluRsImm(inst, address, opCode);
public OpCode32AluRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rm = (opCode >> 0) & 0xf;
Immediate = (opCode >> 7) & 0x1f;
ShiftType = (ShiftType)((opCode >> 5) & 3);
}
}
}

View file

@ -0,0 +1,20 @@
namespace ARMeilleure.Decoders
{
class OpCode32AluRsReg : OpCode32Alu, IOpCode32AluRsReg
{
public int Rm { get; }
public int Rs { get; }
public ShiftType ShiftType { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluRsReg(inst, address, opCode);
public OpCode32AluRsReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rm = (opCode >> 0) & 0xf;
Rs = (opCode >> 8) & 0xf;
ShiftType = (ShiftType)((opCode >> 5) & 3);
}
}
}

View file

@ -0,0 +1,30 @@
namespace ARMeilleure.Decoders
{
class OpCode32AluUmull : OpCode32, IOpCode32AluUmull
{
public int RdLo { get; }
public int RdHi { get; }
public int Rn { get; }
public int Rm { get; }
public bool NHigh { get; }
public bool MHigh { get; }
public bool? SetFlags { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluUmull(inst, address, opCode);
public OpCode32AluUmull(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
RdLo = (opCode >> 12) & 0xf;
RdHi = (opCode >> 16) & 0xf;
Rm = (opCode >> 8) & 0xf;
Rn = (opCode >> 0) & 0xf;
NHigh = ((opCode >> 5) & 0x1) == 1;
MHigh = ((opCode >> 6) & 0x1) == 1;
SetFlags = ((opCode >> 20) & 0x1) != 0;
}
}
}

View file

@ -0,0 +1,18 @@
using ARMeilleure.State;
namespace ARMeilleure.Decoders
{
class OpCode32AluUx : OpCode32AluReg, IOpCode32AluUx
{
public int Rotate { get; }
public int RotateBits => Rotate * 8;
public bool Add => Rn != RegisterAlias.Aarch32Pc;
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluUx(inst, address, opCode);
public OpCode32AluUx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rotate = (opCode >> 10) & 0x3;
}
}
}

View file

@ -0,0 +1,29 @@
namespace ARMeilleure.Decoders
{
class OpCode32BImm : OpCode32, IOpCode32BImm
{
public long Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32BImm(inst, address, opCode);
public OpCode32BImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
uint pc = GetPc();
// When the condition is never, the instruction is BLX to Thumb mode.
if (Cond != Condition.Nv)
{
pc &= ~3u;
}
Immediate = pc + DecoderHelper.DecodeImm24_2(opCode);
if (Cond == Condition.Nv)
{
long H = (opCode >> 23) & 2;
Immediate |= H;
}
}
}
}

View file

@ -0,0 +1,14 @@
namespace ARMeilleure.Decoders
{
class OpCode32BReg : OpCode32, IOpCode32BReg
{
public int Rm { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32BReg(inst, address, opCode);
public OpCode32BReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rm = opCode & 0xf;
}
}
}

View file

@ -0,0 +1,14 @@
namespace ARMeilleure.Decoders
{
class OpCode32Exception : OpCode32, IOpCode32Exception
{
public int Id { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Exception(inst, address, opCode);
public OpCode32Exception(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Id = opCode & 0xFFFFFF;
}
}
}

View file

@ -0,0 +1,39 @@
using ARMeilleure.Instructions;
namespace ARMeilleure.Decoders
{
class OpCode32Mem : OpCode32, IOpCode32Mem
{
public int Rt { get; protected set; }
public int Rn { get; }
public int Immediate { get; protected set; }
public bool Index { get; }
public bool Add { get; }
public bool WBack { get; }
public bool Unprivileged { get; }
public bool IsLoad { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Mem(inst, address, opCode);
public OpCode32Mem(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rt = (opCode >> 12) & 0xf;
Rn = (opCode >> 16) & 0xf;
bool isLoad = (opCode & (1 << 20)) != 0;
bool w = (opCode & (1 << 21)) != 0;
bool u = (opCode & (1 << 23)) != 0;
bool p = (opCode & (1 << 24)) != 0;
Index = p;
Add = u;
WBack = !p || w;
Unprivileged = !p && w;
IsLoad = isLoad || inst.Name == InstName.Ldrd;
}
}
}

View file

@ -0,0 +1,12 @@
namespace ARMeilleure.Decoders
{
class OpCode32MemImm : OpCode32Mem
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MemImm(inst, address, opCode);
public OpCode32MemImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Immediate = opCode & 0xfff;
}
}
}

View file

@ -0,0 +1,15 @@
namespace ARMeilleure.Decoders
{
class OpCode32MemImm8 : OpCode32Mem
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MemImm8(inst, address, opCode);
public OpCode32MemImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
int imm4L = (opCode >> 0) & 0xf;
int imm4H = (opCode >> 8) & 0xf;
Immediate = imm4L | (imm4H << 4);
}
}
}

View file

@ -0,0 +1,14 @@
namespace ARMeilleure.Decoders
{
class OpCode32MemLdEx : OpCode32Mem, IOpCode32MemEx
{
public int Rd { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MemLdEx(inst, address, opCode);
public OpCode32MemLdEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = opCode & 0xf;
}
}
}

View file

@ -0,0 +1,52 @@
using System.Numerics;
namespace ARMeilleure.Decoders
{
class OpCode32MemMult : OpCode32, IOpCode32MemMult
{
public int Rn { get; }
public int RegisterMask { get; }
public int Offset { get; }
public int PostOffset { get; }
public bool IsLoad { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MemMult(inst, address, opCode);
public OpCode32MemMult(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rn = (opCode >> 16) & 0xf;
bool isLoad = (opCode & (1 << 20)) != 0;
bool w = (opCode & (1 << 21)) != 0;
bool u = (opCode & (1 << 23)) != 0;
bool p = (opCode & (1 << 24)) != 0;
RegisterMask = opCode & 0xffff;
int regsSize = BitOperations.PopCount((uint)RegisterMask) * 4;
if (!u)
{
Offset -= regsSize;
}
if (u == p)
{
Offset += 4;
}
if (w)
{
PostOffset = u ? regsSize : -regsSize;
}
else
{
PostOffset = 0;
}
IsLoad = isLoad;
}
}
}

View file

@ -0,0 +1,14 @@
namespace ARMeilleure.Decoders
{
class OpCode32MemReg : OpCode32Mem, IOpCode32MemReg
{
public int Rm { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MemReg(inst, address, opCode);
public OpCode32MemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rm = (opCode >> 0) & 0xf;
}
}
}

View file

@ -0,0 +1,18 @@
namespace ARMeilleure.Decoders
{
class OpCode32MemRsImm : OpCode32Mem, IOpCode32MemRsImm
{
public int Rm { get; }
public ShiftType ShiftType { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MemRsImm(inst, address, opCode);
public OpCode32MemRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rm = (opCode >> 0) & 0xf;
Immediate = (opCode >> 7) & 0x1f;
ShiftType = (ShiftType)((opCode >> 5) & 3);
}
}
}

View file

@ -0,0 +1,15 @@
namespace ARMeilleure.Decoders
{
class OpCode32MemStEx : OpCode32Mem, IOpCode32MemEx
{
public int Rd { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MemStEx(inst, address, opCode);
public OpCode32MemStEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 12) & 0xf;
Rt = (opCode >> 0) & 0xf;
}
}
}

View file

@ -0,0 +1,16 @@
namespace ARMeilleure.Decoders
{
class OpCode32Mrs : OpCode32
{
public bool R { get; }
public int Rd { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Mrs(inst, address, opCode);
public OpCode32Mrs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
R = ((opCode >> 22) & 1) != 0;
Rd = (opCode >> 12) & 0xf;
}
}
}

View file

@ -0,0 +1,29 @@
using ARMeilleure.State;
namespace ARMeilleure.Decoders
{
class OpCode32MsrReg : OpCode32
{
public bool R { get; }
public int Mask { get; }
public int Rd { get; }
public bool Banked { get; }
public int Rn { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32MsrReg(inst, address, opCode);
public OpCode32MsrReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
R = ((opCode >> 22) & 1) != 0;
Mask = (opCode >> 16) & 0xf;
Rd = (opCode >> 12) & 0xf;
Banked = ((opCode >> 9) & 1) != 0;
Rn = (opCode >> 0) & 0xf;
if (Rn == RegisterAlias.Aarch32Pc || Mask == 0)
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,24 @@
namespace ARMeilleure.Decoders
{
class OpCode32Sat : OpCode32
{
public int Rn { get; }
public int Imm5 { get; }
public int Rd { get; }
public int SatImm { get; }
public ShiftType ShiftType { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Sat(inst, address, opCode);
public OpCode32Sat(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rn = (opCode >> 0) & 0xf;
Imm5 = (opCode >> 7) & 0x1f;
Rd = (opCode >> 12) & 0xf;
SatImm = (opCode >> 16) & 0x1f;
ShiftType = (ShiftType)((opCode >> 5) & 2);
}
}
}

View file

@ -0,0 +1,18 @@
namespace ARMeilleure.Decoders
{
class OpCode32Sat16 : OpCode32
{
public int Rn { get; }
public int Rd { get; }
public int SatImm { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Sat16(inst, address, opCode);
public OpCode32Sat16(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rn = (opCode >> 0) & 0xf;
Rd = (opCode >> 12) & 0xf;
SatImm = (opCode >> 16) & 0xf;
}
}
}

View file

@ -0,0 +1,33 @@
namespace ARMeilleure.Decoders
{
class OpCode32Simd : OpCode32SimdBase
{
public int Opc { get; protected set; }
public bool Q { get; protected set; }
public bool F { get; protected set; }
public bool U { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Simd(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32Simd(inst, address, opCode, true);
public OpCode32Simd(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Size = (opCode >> 20) & 0x3;
Q = ((opCode >> 6) & 0x1) != 0;
F = ((opCode >> 10) & 0x1) != 0;
U = ((opCode >> (isThumb ? 28 : 24)) & 0x1) != 0;
Opc = (opCode >> 7) & 0x3;
RegisterSize = Q ? RegisterSize.Simd128 : RegisterSize.Simd64;
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
Vm = ((opCode >> 1) & 0x10) | ((opCode >> 0) & 0xf);
// Subclasses have their own handling of Vx to account for before checking.
if (GetType() == typeof(OpCode32Simd) && DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,55 @@
using System;
namespace ARMeilleure.Decoders
{
abstract class OpCode32SimdBase : OpCode32, IOpCode32Simd
{
public int Vd { get; protected set; }
public int Vm { get; protected set; }
public int Size { get; protected set; }
// Helpers to index doublewords within quad words. Essentially, looping over the vector starts at quadword Q and index Fx or Ix within it,
// depending on instruction type.
//
// Qx: The quadword register that the target vector is contained in.
// Ix: The starting index of the target vector within the quadword, with size treated as integer.
// Fx: The starting index of the target vector within the quadword, with size treated as floating point. (16 or 32)
public int Qd => GetQuadwordIndex(Vd);
public int Id => GetQuadwordSubindex(Vd) << (3 - Size);
public int Fd => GetQuadwordSubindex(Vd) << (1 - (Size & 1)); // When the top bit is truncated, 1 is fp16 which is an optional extension in ARMv8.2. We always assume 64.
public int Qm => GetQuadwordIndex(Vm);
public int Im => GetQuadwordSubindex(Vm) << (3 - Size);
public int Fm => GetQuadwordSubindex(Vm) << (1 - (Size & 1));
protected int GetQuadwordIndex(int index)
{
switch (RegisterSize)
{
case RegisterSize.Simd128:
case RegisterSize.Simd64:
return index >> 1;
}
throw new InvalidOperationException();
}
protected int GetQuadwordSubindex(int index)
{
switch (RegisterSize)
{
case RegisterSize.Simd128:
return 0;
case RegisterSize.Simd64:
return index & 1;
}
throw new InvalidOperationException();
}
protected OpCode32SimdBase(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
}
}
}

View file

@ -0,0 +1,21 @@
namespace ARMeilleure.Decoders
{
/// <summary>
/// A special alias that always runs in 64 bit int, to speed up binary ops a little.
/// </summary>
class OpCode32SimdBinary : OpCode32SimdReg
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdBinary(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdBinary(inst, address, opCode, true);
public OpCode32SimdBinary(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Size = 3;
if (DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm, Vn))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,18 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdCmpZ : OpCode32Simd
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCmpZ(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCmpZ(inst, address, opCode, true);
public OpCode32SimdCmpZ(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Size = (opCode >> 18) & 0x3;
if (DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,24 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdCvtFI : OpCode32SimdS
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtFI(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtFI(inst, address, opCode, true);
public OpCode32SimdCvtFI(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Opc = (opCode >> 7) & 0x1;
bool toInteger = (Opc2 & 0b100) != 0;
if (toInteger)
{
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
}
else
{
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
}
}
}
}

View file

@ -0,0 +1,44 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdCvtTB : OpCode32, IOpCode32Simd
{
public int Vd { get; }
public int Vm { get; }
public bool Op { get; } // Convert to Half / Convert from Half
public bool T { get; } // Top / Bottom
public int Size { get; } // Double / Single
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtTB(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdCvtTB(inst, address, opCode, true);
public OpCode32SimdCvtTB(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
Op = ((opCode >> 16) & 0x1) != 0;
T = ((opCode >> 7) & 0x1) != 0;
Size = ((opCode >> 8) & 0x1);
RegisterSize = Size == 1 ? RegisterSize.Int64 : RegisterSize.Int32;
if (Size == 1)
{
if (Op)
{
Vm = ((opCode >> 1) & 0x10) | ((opCode >> 0) & 0xf);
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
}
else
{
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
}
}
else
{
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
}
}
}
}

View file

@ -0,0 +1,43 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdDupElem : OpCode32Simd
{
public int Index { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdDupElem(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdDupElem(inst, address, opCode, true);
public OpCode32SimdDupElem(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
var opc = (opCode >> 16) & 0xf;
if ((opc & 0b1) == 1)
{
Size = 0;
Index = (opc >> 1) & 0x7;
}
else if ((opc & 0b11) == 0b10)
{
Size = 1;
Index = (opc >> 2) & 0x3;
}
else if ((opc & 0b111) == 0b100)
{
Size = 2;
Index = (opc >> 3) & 0x1;
}
else
{
Instruction = InstDescriptor.Undefined;
}
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
Vm = ((opCode >> 1) & 0x10) | ((opCode >> 0) & 0xf);
if (DecoderHelper.VectorArgumentsInvalid(Q, Vd))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,36 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdDupGP : OpCode32, IOpCode32Simd
{
public int Size { get; }
public int Vd { get; }
public int Rt { get; }
public bool Q { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdDupGP(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdDupGP(inst, address, opCode, true);
public OpCode32SimdDupGP(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
Size = 2 - (((opCode >> 21) & 0x2) | ((opCode >> 5) & 0x1)); // B:E - 0 for 32, 16 then 8.
if (Size == -1)
{
Instruction = InstDescriptor.Undefined;
return;
}
Q = ((opCode >> 21) & 0x1) != 0;
RegisterSize = Q ? RegisterSize.Simd128 : RegisterSize.Simd64;
Vd = ((opCode >> 3) & 0x10) | ((opCode >> 16) & 0xf);
Rt = ((opCode >> 12) & 0xf);
if (DecoderHelper.VectorArgumentsInvalid(Q, Vd))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,20 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdExt : OpCode32SimdReg
{
public int Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdExt(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdExt(inst, address, opCode, true);
public OpCode32SimdExt(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Immediate = (opCode >> 8) & 0xf;
Size = 0;
if (DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm, Vn) || (!Q && Immediate > 7))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,38 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdImm : OpCode32SimdBase, IOpCode32SimdImm
{
public bool Q { get; }
public long Immediate { get; }
public int Elems => GetBytesCount() >> Size;
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdImm(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdImm(inst, address, opCode, true);
public OpCode32SimdImm(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Vd = (opCode >> 12) & 0xf;
Vd |= (opCode >> 18) & 0x10;
Q = ((opCode >> 6) & 0x1) > 0;
int cMode = (opCode >> 8) & 0xf;
int op = (opCode >> 5) & 0x1;
long imm;
imm = ((uint)opCode >> 0) & 0xf;
imm |= ((uint)opCode >> 12) & 0x70;
imm |= ((uint)opCode >> (isThumb ? 21 : 17)) & 0x80;
(Immediate, Size) = OpCodeSimdHelper.GetSimdImmediateAndSize(cMode, op, imm);
RegisterSize = Q ? RegisterSize.Simd128 : RegisterSize.Simd64;
if (DecoderHelper.VectorArgumentsInvalid(Q, Vd))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,41 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdImm44 : OpCode32, IOpCode32SimdImm
{
public int Vd { get; }
public long Immediate { get; }
public int Size { get; }
public int Elems { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdImm44(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdImm44(inst, address, opCode, true);
public OpCode32SimdImm44(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
Size = (opCode >> 8) & 0x3;
bool single = Size != 3;
if (single)
{
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
}
else
{
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
}
long imm;
imm = ((uint)opCode >> 0) & 0xf;
imm |= ((uint)opCode >> 12) & 0xf0;
Immediate = (Size == 3) ? (long)DecoderHelper.Imm8ToFP64Table[(int)imm] : DecoderHelper.Imm8ToFP32Table[(int)imm];
RegisterSize = (!single) ? RegisterSize.Int64 : RegisterSize.Int32;
Elems = 1;
}
}
}

View file

@ -0,0 +1,30 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdLong : OpCode32SimdBase
{
public bool U { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdLong(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdLong(inst, address, opCode, true);
public OpCode32SimdLong(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
int imm3h = (opCode >> 19) & 0x7;
// The value must be a power of 2, otherwise it is the encoding of another instruction.
switch (imm3h)
{
case 1: Size = 0; break;
case 2: Size = 1; break;
case 4: Size = 2; break;
}
U = ((opCode >> (isThumb ? 28 : 24)) & 0x1) != 0;
RegisterSize = RegisterSize.Simd64;
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
Vm = ((opCode >> 1) & 0x10) | ((opCode >> 0) & 0xf);
}
}
}

View file

@ -0,0 +1,40 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdMemImm : OpCode32, IOpCode32Simd
{
public int Vd { get; }
public int Rn { get; }
public int Size { get; }
public bool Add { get; }
public int Immediate { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemImm(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemImm(inst, address, opCode, true);
public OpCode32SimdMemImm(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
Immediate = opCode & 0xff;
Rn = (opCode >> 16) & 0xf;
Size = (opCode >> 8) & 0x3;
Immediate <<= (Size == 1) ? 1 : 2;
bool u = (opCode & (1 << 23)) != 0;
Add = u;
bool single = Size != 3;
if (single)
{
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
}
else
{
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
}
}
}
}

View file

@ -0,0 +1,76 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdMemMult : OpCode32
{
public int Rn { get; }
public int Vd { get; }
public int RegisterRange { get; }
public int Offset { get; }
public int PostOffset { get; }
public bool IsLoad { get; }
public bool DoubleWidth { get; }
public bool Add { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemMult(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemMult(inst, address, opCode, true);
public OpCode32SimdMemMult(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
Rn = (opCode >> 16) & 0xf;
bool isLoad = (opCode & (1 << 20)) != 0;
bool w = (opCode & (1 << 21)) != 0;
bool u = (opCode & (1 << 23)) != 0;
bool p = (opCode & (1 << 24)) != 0;
if (p == u && w)
{
Instruction = InstDescriptor.Undefined;
return;
}
DoubleWidth = (opCode & (1 << 8)) != 0;
if (!DoubleWidth)
{
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
}
else
{
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
}
Add = u;
RegisterRange = opCode & 0xff;
int regsSize = RegisterRange * 4; // Double mode is still measured in single register size.
if (!u)
{
Offset -= regsSize;
}
if (w)
{
PostOffset = u ? regsSize : -regsSize;
}
else
{
PostOffset = 0;
}
IsLoad = isLoad;
int regs = DoubleWidth ? RegisterRange / 2 : RegisterRange;
if (RegisterRange == 0 || RegisterRange > 32 || Vd + regs > 32)
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,50 @@
using ARMeilleure.State;
namespace ARMeilleure.Decoders
{
class OpCode32SimdMemPair : OpCode32, IOpCode32Simd
{
private static int[] _regsMap =
{
1, 1, 4, 2,
1, 1, 3, 1,
1, 1, 2, 1,
1, 1, 1, 1
};
public int Vd { get; }
public int Rn { get; }
public int Rm { get; }
public int Align { get; }
public bool WBack { get; }
public bool RegisterIndex { get; }
public int Size { get; }
public int Elems => 8 >> Size;
public int Regs { get; }
public int Increment { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemPair(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemPair(inst, address, opCode, true);
public OpCode32SimdMemPair(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
Vd = (opCode >> 12) & 0xf;
Vd |= (opCode >> 18) & 0x10;
Size = (opCode >> 6) & 0x3;
Align = (opCode >> 4) & 0x3;
Rm = (opCode >> 0) & 0xf;
Rn = (opCode >> 16) & 0xf;
WBack = Rm != RegisterAlias.Aarch32Pc;
RegisterIndex = Rm != RegisterAlias.Aarch32Pc && Rm != RegisterAlias.Aarch32Sp;
Regs = _regsMap[(opCode >> 8) & 0xf];
Increment = ((opCode >> 8) & 0x1) + 1;
}
}
}

View file

@ -0,0 +1,51 @@
using ARMeilleure.State;
namespace ARMeilleure.Decoders
{
class OpCode32SimdMemSingle : OpCode32, IOpCode32Simd
{
public int Vd { get; }
public int Rn { get; }
public int Rm { get; }
public int IndexAlign { get; }
public int Index { get; }
public bool WBack { get; }
public bool RegisterIndex { get; }
public int Size { get; }
public bool Replicate { get; }
public int Increment { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemSingle(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMemSingle(inst, address, opCode, true);
public OpCode32SimdMemSingle(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
Vd = (opCode >> 12) & 0xf;
Vd |= (opCode >> 18) & 0x10;
IndexAlign = (opCode >> 4) & 0xf;
Size = (opCode >> 10) & 0x3;
Replicate = Size == 3;
if (Replicate)
{
Size = (opCode >> 6) & 0x3;
Increment = ((opCode >> 5) & 1) + 1;
Index = 0;
}
else
{
Increment = (((IndexAlign >> Size) & 1) == 0) ? 1 : 2;
Index = IndexAlign >> (1 + Size);
}
Rm = (opCode >> 0) & 0xf;
Rn = (opCode >> 16) & 0xf;
WBack = Rm != RegisterAlias.Aarch32Pc;
RegisterIndex = Rm != RegisterAlias.Aarch32Pc && Rm != RegisterAlias.Aarch32Sp;
}
}
}

View file

@ -0,0 +1,31 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdMovGp : OpCode32, IOpCode32Simd
{
public int Size => 2;
public int Vn { get; }
public int Rt { get; }
public int Op { get; }
public int Opc1 { get; }
public int Opc2 { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGp(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGp(inst, address, opCode, true);
public OpCode32SimdMovGp(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
// Which one is used is instruction dependant.
Op = (opCode >> 20) & 0x1;
Opc1 = (opCode >> 21) & 0x3;
Opc2 = (opCode >> 5) & 0x3;
Vn = ((opCode >> 7) & 0x1) | ((opCode >> 15) & 0x1e);
Rt = (opCode >> 12) & 0xf;
}
}
}

View file

@ -0,0 +1,36 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdMovGpDouble : OpCode32, IOpCode32Simd
{
public int Size => 3;
public int Vm { get; }
public int Rt { get; }
public int Rt2 { get; }
public int Op { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGpDouble(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGpDouble(inst, address, opCode, true);
public OpCode32SimdMovGpDouble(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
// Which one is used is instruction dependant.
Op = (opCode >> 20) & 0x1;
Rt = (opCode >> 12) & 0xf;
Rt2 = (opCode >> 16) & 0xf;
bool single = (opCode & (1 << 8)) == 0;
if (single)
{
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
}
else
{
Vm = ((opCode >> 1) & 0x10) | ((opCode >> 0) & 0xf);
}
}
}
}

View file

@ -0,0 +1,51 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdMovGpElem : OpCode32, IOpCode32Simd
{
public int Size { get; }
public int Vd { get; }
public int Rt { get; }
public int Op { get; }
public bool U { get; }
public int Index { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGpElem(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovGpElem(inst, address, opCode, true);
public OpCode32SimdMovGpElem(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
Op = (opCode >> 20) & 0x1;
U = ((opCode >> 23) & 1) != 0;
var opc = (((opCode >> 23) & 1) << 4) | (((opCode >> 21) & 0x3) << 2) | ((opCode >> 5) & 0x3);
if ((opc & 0b01000) == 0b01000)
{
Size = 0;
Index = opc & 0x7;
}
else if ((opc & 0b01001) == 0b00001)
{
Size = 1;
Index = (opc >> 1) & 0x3;
}
else if ((opc & 0b11011) == 0)
{
Size = 2;
Index = (opc >> 2) & 0x1;
}
else
{
Instruction = InstDescriptor.Undefined;
return;
}
Vd = ((opCode >> 3) & 0x10) | ((opCode >> 16) & 0xf);
Rt = (opCode >> 12) & 0xf;
}
}
}

View file

@ -0,0 +1,13 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdMovn : OpCode32Simd
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovn(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdMovn(inst, address, opCode, true);
public OpCode32SimdMovn(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Size = (opCode >> 18) & 0x3;
}
}
}

View file

@ -0,0 +1,25 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdReg : OpCode32Simd
{
public int Vn { get; }
public int Qn => GetQuadwordIndex(Vn);
public int In => GetQuadwordSubindex(Vn) << (3 - Size);
public int Fn => GetQuadwordSubindex(Vn) << (1 - (Size & 1));
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdReg(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdReg(inst, address, opCode, true);
public OpCode32SimdReg(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Vn = ((opCode >> 3) & 0x10) | ((opCode >> 16) & 0xf);
// Subclasses have their own handling of Vx to account for before checking.
if (GetType() == typeof(OpCode32SimdReg) && DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm, Vn))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,31 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdRegElem : OpCode32SimdReg
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegElem(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegElem(inst, address, opCode, true);
public OpCode32SimdRegElem(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Q = ((opCode >> (isThumb ? 28 : 24)) & 0x1) != 0;
F = ((opCode >> 8) & 0x1) != 0;
Size = (opCode >> 20) & 0x3;
RegisterSize = Q ? RegisterSize.Simd128 : RegisterSize.Simd64;
if (Size == 1)
{
Vm = ((opCode >> 3) & 0x1) | ((opCode >> 4) & 0x2) | ((opCode << 2) & 0x1c);
}
else /* if (Size == 2) */
{
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
}
if (GetType() == typeof(OpCode32SimdRegElem) && DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vn) || Size == 0 || (Size == 1 && F))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,22 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdRegElemLong : OpCode32SimdRegElem
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegElemLong(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegElemLong(inst, address, opCode, true);
public OpCode32SimdRegElemLong(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Q = false;
F = false;
RegisterSize = RegisterSize.Simd64;
// (Vd & 1) != 0 || Size == 3 are also invalid, but they are checked on encoding.
if (Size == 0)
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,24 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdRegLong : OpCode32SimdReg
{
public bool Polynomial { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegLong(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegLong(inst, address, opCode, true);
public OpCode32SimdRegLong(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Q = false;
RegisterSize = RegisterSize.Simd64;
Polynomial = ((opCode >> 9) & 0x1) != 0;
// Subclasses have their own handling of Vx to account for before checking.
if (GetType() == typeof(OpCode32SimdRegLong) && DecoderHelper.VectorArgumentsInvalid(true, Vd))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,23 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdRegS : OpCode32SimdS
{
public int Vn { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegS(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegS(inst, address, opCode, true);
public OpCode32SimdRegS(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
bool single = Size != 3;
if (single)
{
Vn = ((opCode >> 7) & 0x1) | ((opCode >> 15) & 0x1e);
}
else
{
Vn = ((opCode >> 3) & 0x10) | ((opCode >> 16) & 0xf);
}
}
}
}

View file

@ -0,0 +1,20 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdRegWide : OpCode32SimdReg
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegWide(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRegWide(inst, address, opCode, true);
public OpCode32SimdRegWide(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Q = false;
RegisterSize = RegisterSize.Simd64;
// Subclasses have their own handling of Vx to account for before checking.
if (GetType() == typeof(OpCode32SimdRegWide) && DecoderHelper.VectorArgumentsInvalid(true, Vd, Vn))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,23 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdRev : OpCode32SimdCmpZ
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRev(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdRev(inst, address, opCode, true);
public OpCode32SimdRev(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
if (Opc + Size >= 3)
{
Instruction = InstDescriptor.Undefined;
return;
}
// Currently, this instruction is treated as though it's OPCODE is the true size,
// which lets us deal with reversing vectors on a single element basis (eg. math magic an I64 rather than insert lots of I8s).
int tempSize = Size;
Size = 3 - Opc; // Op 0 is 64 bit, 1 is 32 and so on.
Opc = tempSize;
}
}
}

View file

@ -0,0 +1,39 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdS : OpCode32, IOpCode32Simd
{
public int Vd { get; protected set; }
public int Vm { get; protected set; }
public int Opc { get; protected set; } // "with_zero" (Opc<1>) [Vcmp, Vcmpe].
public int Opc2 { get; } // opc2 or RM (opc2<1:0>) [Vcvt, Vrint].
public int Size { get; protected set; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdS(inst, address, opCode, false);
public static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdS(inst, address, opCode, true);
public OpCode32SimdS(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode)
{
IsThumb = isThumb;
Opc = (opCode >> 15) & 0x3;
Opc2 = (opCode >> 16) & 0x7;
Size = (opCode >> 8) & 0x3;
bool single = Size != 3;
RegisterSize = single ? RegisterSize.Int32 : RegisterSize.Int64;
if (single)
{
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
}
else
{
Vm = ((opCode >> 1) & 0x10) | ((opCode >> 0) & 0xf);
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
}
}
}
}

View file

@ -0,0 +1,23 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdSel : OpCode32SimdRegS
{
public OpCode32SimdSelMode Cc { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSel(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdSel(inst, address, opCode, true);
public OpCode32SimdSel(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Cc = (OpCode32SimdSelMode)((opCode >> 20) & 3);
}
}
enum OpCode32SimdSelMode : int
{
Eq = 0,
Vs,
Ge,
Gt
}
}

View file

@ -0,0 +1,46 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdShImm : OpCode32Simd
{
public int Shift { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImm(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImm(inst, address, opCode, true);
public OpCode32SimdShImm(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
int imm6 = (opCode >> 16) & 0x3f;
int limm6 = ((opCode >> 1) & 0x40) | imm6;
if ((limm6 & 0x40) == 0b1000000)
{
Size = 3;
Shift = imm6;
}
else if ((limm6 & 0x60) == 0b0100000)
{
Size = 2;
Shift = imm6 - 32;
}
else if ((limm6 & 0x70) == 0b0010000)
{
Size = 1;
Shift = imm6 - 16;
}
else if ((limm6 & 0x78) == 0b0001000)
{
Size = 0;
Shift = imm6 - 8;
}
else
{
Instruction = InstDescriptor.Undefined;
}
if (GetType() == typeof(OpCode32SimdShImm) && DecoderHelper.VectorArgumentsInvalid(Q, Vd, Vm))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,43 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdShImmLong : OpCode32Simd
{
public int Shift { get; }
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImmLong(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImmLong(inst, address, opCode, true);
public OpCode32SimdShImmLong(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb)
{
Q = false;
RegisterSize = RegisterSize.Simd64;
int imm6 = (opCode >> 16) & 0x3f;
if ((imm6 & 0x20) == 0b100000)
{
Size = 2;
Shift = imm6 - 32;
}
else if ((imm6 & 0x30) == 0b010000)
{
Size = 1;
Shift = imm6 - 16;
}
else if ((imm6 & 0x38) == 0b001000)
{
Size = 0;
Shift = imm6 - 8;
}
else
{
Instruction = InstDescriptor.Undefined;
}
if (GetType() == typeof(OpCode32SimdShImmLong) && DecoderHelper.VectorArgumentsInvalid(true, Vd))
{
Instruction = InstDescriptor.Undefined;
}
}
}
}

View file

@ -0,0 +1,10 @@
namespace ARMeilleure.Decoders
{
class OpCode32SimdShImmNarrow : OpCode32SimdShImm
{
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImmNarrow(inst, address, opCode, false);
public new static OpCode CreateT32(InstDescriptor inst, ulong address, int opCode) => new OpCode32SimdShImmNarrow(inst, address, opCode, true);
public OpCode32SimdShImmNarrow(InstDescriptor inst, ulong address, int opCode, bool isThumb) : base(inst, address, opCode, isThumb) { }
}
}

Some files were not shown because too many files have changed in this diff Show more