Move solution and projects to src
This commit is contained in:
parent
cd124bda58
commit
cee7121058
3466 changed files with 55 additions and 55 deletions
101
src/ARMeilleure/Decoders/Block.cs
Normal file
101
src/ARMeilleure/Decoders/Block.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
32
src/ARMeilleure/Decoders/Condition.cs
Normal file
32
src/ARMeilleure/Decoders/Condition.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
10
src/ARMeilleure/Decoders/DataOp.cs
Normal file
10
src/ARMeilleure/Decoders/DataOp.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
enum DataOp
|
||||
{
|
||||
Adr = 0,
|
||||
Arithmetic = 1,
|
||||
Logical = 2,
|
||||
BitField = 3
|
||||
}
|
||||
}
|
391
src/ARMeilleure/Decoders/Decoder.cs
Normal file
391
src/ARMeilleure/Decoders/Decoder.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
167
src/ARMeilleure/Decoders/DecoderHelper.cs
Normal file
167
src/ARMeilleure/Decoders/DecoderHelper.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
9
src/ARMeilleure/Decoders/DecoderMode.cs
Normal file
9
src/ARMeilleure/Decoders/DecoderMode.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
enum DecoderMode
|
||||
{
|
||||
MultipleBlocks,
|
||||
SingleBlock,
|
||||
SingleInstruction,
|
||||
}
|
||||
}
|
17
src/ARMeilleure/Decoders/IOpCode.cs
Normal file
17
src/ARMeilleure/Decoders/IOpCode.cs
Normal 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();
|
||||
}
|
||||
}
|
9
src/ARMeilleure/Decoders/IOpCode32.cs
Normal file
9
src/ARMeilleure/Decoders/IOpCode32.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32 : IOpCode
|
||||
{
|
||||
Condition Cond { get; }
|
||||
|
||||
uint GetPc();
|
||||
}
|
||||
}
|
9
src/ARMeilleure/Decoders/IOpCode32Adr.cs
Normal file
9
src/ARMeilleure/Decoders/IOpCode32Adr.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32Adr
|
||||
{
|
||||
int Rd { get; }
|
||||
|
||||
int Immediate { get; }
|
||||
}
|
||||
}
|
8
src/ARMeilleure/Decoders/IOpCode32Alu.cs
Normal file
8
src/ARMeilleure/Decoders/IOpCode32Alu.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32Alu : IOpCode32, IOpCode32HasSetFlags
|
||||
{
|
||||
int Rd { get; }
|
||||
int Rn { get; }
|
||||
}
|
||||
}
|
14
src/ARMeilleure/Decoders/IOpCode32AluBf.cs
Normal file
14
src/ARMeilleure/Decoders/IOpCode32AluBf.cs
Normal 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);
|
||||
}
|
||||
}
|
9
src/ARMeilleure/Decoders/IOpCode32AluImm.cs
Normal file
9
src/ARMeilleure/Decoders/IOpCode32AluImm.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32AluImm : IOpCode32Alu
|
||||
{
|
||||
int Immediate { get; }
|
||||
|
||||
bool IsRotated { get; }
|
||||
}
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCode32AluImm16.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCode32AluImm16.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32AluImm16 : IOpCode32Alu
|
||||
{
|
||||
int Immediate { get; }
|
||||
}
|
||||
}
|
11
src/ARMeilleure/Decoders/IOpCode32AluMla.cs
Normal file
11
src/ARMeilleure/Decoders/IOpCode32AluMla.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32AluMla : IOpCode32AluReg
|
||||
{
|
||||
int Ra { get; }
|
||||
|
||||
bool NHigh { get; }
|
||||
bool MHigh { get; }
|
||||
bool R { get; }
|
||||
}
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCode32AluReg.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCode32AluReg.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32AluReg : IOpCode32Alu
|
||||
{
|
||||
int Rm { get; }
|
||||
}
|
||||
}
|
10
src/ARMeilleure/Decoders/IOpCode32AluRsImm.cs
Normal file
10
src/ARMeilleure/Decoders/IOpCode32AluRsImm.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32AluRsImm : IOpCode32Alu
|
||||
{
|
||||
int Rm { get; }
|
||||
int Immediate { get; }
|
||||
|
||||
ShiftType ShiftType { get; }
|
||||
}
|
||||
}
|
10
src/ARMeilleure/Decoders/IOpCode32AluRsReg.cs
Normal file
10
src/ARMeilleure/Decoders/IOpCode32AluRsReg.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32AluRsReg : IOpCode32Alu
|
||||
{
|
||||
int Rm { get; }
|
||||
int Rs { get; }
|
||||
|
||||
ShiftType ShiftType { get; }
|
||||
}
|
||||
}
|
13
src/ARMeilleure/Decoders/IOpCode32AluUmull.cs
Normal file
13
src/ARMeilleure/Decoders/IOpCode32AluUmull.cs
Normal 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; }
|
||||
}
|
||||
}
|
8
src/ARMeilleure/Decoders/IOpCode32AluUx.cs
Normal file
8
src/ARMeilleure/Decoders/IOpCode32AluUx.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32AluUx : IOpCode32AluReg
|
||||
{
|
||||
int RotateBits { get; }
|
||||
bool Add { get; }
|
||||
}
|
||||
}
|
4
src/ARMeilleure/Decoders/IOpCode32BImm.cs
Normal file
4
src/ARMeilleure/Decoders/IOpCode32BImm.cs
Normal file
|
@ -0,0 +1,4 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32BImm : IOpCode32, IOpCodeBImm { }
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCode32BReg.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCode32BReg.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32BReg : IOpCode32
|
||||
{
|
||||
int Rm { get; }
|
||||
}
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCode32Exception.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCode32Exception.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32Exception
|
||||
{
|
||||
int Id { get; }
|
||||
}
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCode32HasSetFlags.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCode32HasSetFlags.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32HasSetFlags
|
||||
{
|
||||
bool? SetFlags { get; }
|
||||
}
|
||||
}
|
16
src/ARMeilleure/Decoders/IOpCode32Mem.cs
Normal file
16
src/ARMeilleure/Decoders/IOpCode32Mem.cs
Normal 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; }
|
||||
}
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCode32MemEx.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCode32MemEx.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32MemEx : IOpCode32Mem
|
||||
{
|
||||
int Rd { get; }
|
||||
}
|
||||
}
|
15
src/ARMeilleure/Decoders/IOpCode32MemMult.cs
Normal file
15
src/ARMeilleure/Decoders/IOpCode32MemMult.cs
Normal 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; }
|
||||
}
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCode32MemReg.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCode32MemReg.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32MemReg : IOpCode32Mem
|
||||
{
|
||||
int Rm { get; }
|
||||
}
|
||||
}
|
8
src/ARMeilleure/Decoders/IOpCode32MemRsImm.cs
Normal file
8
src/ARMeilleure/Decoders/IOpCode32MemRsImm.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32MemRsImm : IOpCode32Mem
|
||||
{
|
||||
int Rm { get; }
|
||||
ShiftType ShiftType { get; }
|
||||
}
|
||||
}
|
4
src/ARMeilleure/Decoders/IOpCode32Simd.cs
Normal file
4
src/ARMeilleure/Decoders/IOpCode32Simd.cs
Normal file
|
@ -0,0 +1,4 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32Simd : IOpCode32, IOpCodeSimd { }
|
||||
}
|
9
src/ARMeilleure/Decoders/IOpCode32SimdImm.cs
Normal file
9
src/ARMeilleure/Decoders/IOpCode32SimdImm.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32SimdImm : IOpCode32Simd
|
||||
{
|
||||
int Vd { get; }
|
||||
long Immediate { get; }
|
||||
int Elems { get; }
|
||||
}
|
||||
}
|
10
src/ARMeilleure/Decoders/IOpCodeAlu.cs
Normal file
10
src/ARMeilleure/Decoders/IOpCodeAlu.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCodeAlu : IOpCode
|
||||
{
|
||||
int Rd { get; }
|
||||
int Rn { get; }
|
||||
|
||||
DataOp DataOp { get; }
|
||||
}
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCodeAluImm.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCodeAluImm.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCodeAluImm : IOpCodeAlu
|
||||
{
|
||||
long Immediate { get; }
|
||||
}
|
||||
}
|
10
src/ARMeilleure/Decoders/IOpCodeAluRs.cs
Normal file
10
src/ARMeilleure/Decoders/IOpCodeAluRs.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCodeAluRs : IOpCodeAlu
|
||||
{
|
||||
int Shift { get; }
|
||||
int Rm { get; }
|
||||
|
||||
ShiftType ShiftType { get; }
|
||||
}
|
||||
}
|
10
src/ARMeilleure/Decoders/IOpCodeAluRx.cs
Normal file
10
src/ARMeilleure/Decoders/IOpCodeAluRx.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCodeAluRx : IOpCodeAlu
|
||||
{
|
||||
int Shift { get; }
|
||||
int Rm { get; }
|
||||
|
||||
IntType IntType { get; }
|
||||
}
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCodeBImm.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCodeBImm.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCodeBImm : IOpCode
|
||||
{
|
||||
long Immediate { get; }
|
||||
}
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCodeCond.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCodeCond.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCodeCond : IOpCode
|
||||
{
|
||||
Condition Cond { get; }
|
||||
}
|
||||
}
|
11
src/ARMeilleure/Decoders/IOpCodeLit.cs
Normal file
11
src/ARMeilleure/Decoders/IOpCodeLit.cs
Normal 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; }
|
||||
}
|
||||
}
|
7
src/ARMeilleure/Decoders/IOpCodeSimd.cs
Normal file
7
src/ARMeilleure/Decoders/IOpCodeSimd.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCodeSimd : IOpCode
|
||||
{
|
||||
int Size { get; }
|
||||
}
|
||||
}
|
18
src/ARMeilleure/Decoders/InstDescriptor.cs
Normal file
18
src/ARMeilleure/Decoders/InstDescriptor.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
6
src/ARMeilleure/Decoders/InstEmitter.cs
Normal file
6
src/ARMeilleure/Decoders/InstEmitter.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
using ARMeilleure.Translation;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
delegate void InstEmitter(ArmEmitterContext context);
|
||||
}
|
14
src/ARMeilleure/Decoders/IntType.cs
Normal file
14
src/ARMeilleure/Decoders/IntType.cs
Normal 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
|
||||
}
|
||||
}
|
49
src/ARMeilleure/Decoders/OpCode.cs
Normal file
49
src/ARMeilleure/Decoders/OpCode.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
34
src/ARMeilleure/Decoders/OpCode32.cs
Normal file
34
src/ARMeilleure/Decoders/OpCode32.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
src/ARMeilleure/Decoders/OpCode32Alu.cs
Normal file
20
src/ARMeilleure/Decoders/OpCode32Alu.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
22
src/ARMeilleure/Decoders/OpCode32AluBf.cs
Normal file
22
src/ARMeilleure/Decoders/OpCode32AluBf.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
23
src/ARMeilleure/Decoders/OpCode32AluImm.cs
Normal file
23
src/ARMeilleure/Decoders/OpCode32AluImm.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
17
src/ARMeilleure/Decoders/OpCode32AluImm16.cs
Normal file
17
src/ARMeilleure/Decoders/OpCode32AluImm16.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
30
src/ARMeilleure/Decoders/OpCode32AluMla.cs
Normal file
30
src/ARMeilleure/Decoders/OpCode32AluMla.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
14
src/ARMeilleure/Decoders/OpCode32AluReg.cs
Normal file
14
src/ARMeilleure/Decoders/OpCode32AluReg.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
20
src/ARMeilleure/Decoders/OpCode32AluRsImm.cs
Normal file
20
src/ARMeilleure/Decoders/OpCode32AluRsImm.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
20
src/ARMeilleure/Decoders/OpCode32AluRsReg.cs
Normal file
20
src/ARMeilleure/Decoders/OpCode32AluRsReg.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
30
src/ARMeilleure/Decoders/OpCode32AluUmull.cs
Normal file
30
src/ARMeilleure/Decoders/OpCode32AluUmull.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
18
src/ARMeilleure/Decoders/OpCode32AluUx.cs
Normal file
18
src/ARMeilleure/Decoders/OpCode32AluUx.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
29
src/ARMeilleure/Decoders/OpCode32BImm.cs
Normal file
29
src/ARMeilleure/Decoders/OpCode32BImm.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
14
src/ARMeilleure/Decoders/OpCode32BReg.cs
Normal file
14
src/ARMeilleure/Decoders/OpCode32BReg.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
14
src/ARMeilleure/Decoders/OpCode32Exception.cs
Normal file
14
src/ARMeilleure/Decoders/OpCode32Exception.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
39
src/ARMeilleure/Decoders/OpCode32Mem.cs
Normal file
39
src/ARMeilleure/Decoders/OpCode32Mem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
12
src/ARMeilleure/Decoders/OpCode32MemImm.cs
Normal file
12
src/ARMeilleure/Decoders/OpCode32MemImm.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
15
src/ARMeilleure/Decoders/OpCode32MemImm8.cs
Normal file
15
src/ARMeilleure/Decoders/OpCode32MemImm8.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
14
src/ARMeilleure/Decoders/OpCode32MemLdEx.cs
Normal file
14
src/ARMeilleure/Decoders/OpCode32MemLdEx.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
52
src/ARMeilleure/Decoders/OpCode32MemMult.cs
Normal file
52
src/ARMeilleure/Decoders/OpCode32MemMult.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
14
src/ARMeilleure/Decoders/OpCode32MemReg.cs
Normal file
14
src/ARMeilleure/Decoders/OpCode32MemReg.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
18
src/ARMeilleure/Decoders/OpCode32MemRsImm.cs
Normal file
18
src/ARMeilleure/Decoders/OpCode32MemRsImm.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
15
src/ARMeilleure/Decoders/OpCode32MemStEx.cs
Normal file
15
src/ARMeilleure/Decoders/OpCode32MemStEx.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
16
src/ARMeilleure/Decoders/OpCode32Mrs.cs
Normal file
16
src/ARMeilleure/Decoders/OpCode32Mrs.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
29
src/ARMeilleure/Decoders/OpCode32MsrReg.cs
Normal file
29
src/ARMeilleure/Decoders/OpCode32MsrReg.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
src/ARMeilleure/Decoders/OpCode32Sat.cs
Normal file
24
src/ARMeilleure/Decoders/OpCode32Sat.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
18
src/ARMeilleure/Decoders/OpCode32Sat16.cs
Normal file
18
src/ARMeilleure/Decoders/OpCode32Sat16.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
33
src/ARMeilleure/Decoders/OpCode32Simd.cs
Normal file
33
src/ARMeilleure/Decoders/OpCode32Simd.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
55
src/ARMeilleure/Decoders/OpCode32SimdBase.cs
Normal file
55
src/ARMeilleure/Decoders/OpCode32SimdBase.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
21
src/ARMeilleure/Decoders/OpCode32SimdBinary.cs
Normal file
21
src/ARMeilleure/Decoders/OpCode32SimdBinary.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
18
src/ARMeilleure/Decoders/OpCode32SimdCmpZ.cs
Normal file
18
src/ARMeilleure/Decoders/OpCode32SimdCmpZ.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
src/ARMeilleure/Decoders/OpCode32SimdCvtFI.cs
Normal file
24
src/ARMeilleure/Decoders/OpCode32SimdCvtFI.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
44
src/ARMeilleure/Decoders/OpCode32SimdCvtTB.cs
Normal file
44
src/ARMeilleure/Decoders/OpCode32SimdCvtTB.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
src/ARMeilleure/Decoders/OpCode32SimdDupElem.cs
Normal file
43
src/ARMeilleure/Decoders/OpCode32SimdDupElem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
36
src/ARMeilleure/Decoders/OpCode32SimdDupGP.cs
Normal file
36
src/ARMeilleure/Decoders/OpCode32SimdDupGP.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
src/ARMeilleure/Decoders/OpCode32SimdExt.cs
Normal file
20
src/ARMeilleure/Decoders/OpCode32SimdExt.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
src/ARMeilleure/Decoders/OpCode32SimdImm.cs
Normal file
38
src/ARMeilleure/Decoders/OpCode32SimdImm.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
41
src/ARMeilleure/Decoders/OpCode32SimdImm44.cs
Normal file
41
src/ARMeilleure/Decoders/OpCode32SimdImm44.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
30
src/ARMeilleure/Decoders/OpCode32SimdLong.cs
Normal file
30
src/ARMeilleure/Decoders/OpCode32SimdLong.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
40
src/ARMeilleure/Decoders/OpCode32SimdMemImm.cs
Normal file
40
src/ARMeilleure/Decoders/OpCode32SimdMemImm.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
76
src/ARMeilleure/Decoders/OpCode32SimdMemMult.cs
Normal file
76
src/ARMeilleure/Decoders/OpCode32SimdMemMult.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
50
src/ARMeilleure/Decoders/OpCode32SimdMemPair.cs
Normal file
50
src/ARMeilleure/Decoders/OpCode32SimdMemPair.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
51
src/ARMeilleure/Decoders/OpCode32SimdMemSingle.cs
Normal file
51
src/ARMeilleure/Decoders/OpCode32SimdMemSingle.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
31
src/ARMeilleure/Decoders/OpCode32SimdMovGp.cs
Normal file
31
src/ARMeilleure/Decoders/OpCode32SimdMovGp.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
36
src/ARMeilleure/Decoders/OpCode32SimdMovGpDouble.cs
Normal file
36
src/ARMeilleure/Decoders/OpCode32SimdMovGpDouble.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
51
src/ARMeilleure/Decoders/OpCode32SimdMovGpElem.cs
Normal file
51
src/ARMeilleure/Decoders/OpCode32SimdMovGpElem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
13
src/ARMeilleure/Decoders/OpCode32SimdMovn.cs
Normal file
13
src/ARMeilleure/Decoders/OpCode32SimdMovn.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
25
src/ARMeilleure/Decoders/OpCode32SimdReg.cs
Normal file
25
src/ARMeilleure/Decoders/OpCode32SimdReg.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
src/ARMeilleure/Decoders/OpCode32SimdRegElem.cs
Normal file
31
src/ARMeilleure/Decoders/OpCode32SimdRegElem.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
22
src/ARMeilleure/Decoders/OpCode32SimdRegElemLong.cs
Normal file
22
src/ARMeilleure/Decoders/OpCode32SimdRegElemLong.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
src/ARMeilleure/Decoders/OpCode32SimdRegLong.cs
Normal file
24
src/ARMeilleure/Decoders/OpCode32SimdRegLong.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
src/ARMeilleure/Decoders/OpCode32SimdRegS.cs
Normal file
23
src/ARMeilleure/Decoders/OpCode32SimdRegS.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
src/ARMeilleure/Decoders/OpCode32SimdRegWide.cs
Normal file
20
src/ARMeilleure/Decoders/OpCode32SimdRegWide.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
src/ARMeilleure/Decoders/OpCode32SimdRev.cs
Normal file
23
src/ARMeilleure/Decoders/OpCode32SimdRev.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
39
src/ARMeilleure/Decoders/OpCode32SimdS.cs
Normal file
39
src/ARMeilleure/Decoders/OpCode32SimdS.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
src/ARMeilleure/Decoders/OpCode32SimdSel.cs
Normal file
23
src/ARMeilleure/Decoders/OpCode32SimdSel.cs
Normal 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
|
||||
}
|
||||
}
|
46
src/ARMeilleure/Decoders/OpCode32SimdShImm.cs
Normal file
46
src/ARMeilleure/Decoders/OpCode32SimdShImm.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
43
src/ARMeilleure/Decoders/OpCode32SimdShImmLong.cs
Normal file
43
src/ARMeilleure/Decoders/OpCode32SimdShImmLong.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
src/ARMeilleure/Decoders/OpCode32SimdShImmNarrow.cs
Normal file
10
src/ARMeilleure/Decoders/OpCode32SimdShImmNarrow.cs
Normal 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
Loading…
Add table
Add a link
Reference in a new issue