Port over the ARM32 instructions
This commit is contained in:
parent
8938e9f2e0
commit
eaa734b8e6
14 changed files with 588 additions and 66 deletions
|
@ -7,7 +7,7 @@ namespace ARMeilleure.Decoders
|
|||
public int Rt { get; private set; }
|
||||
public int Rn { get; private set; }
|
||||
|
||||
public int Imm { get; protected set; }
|
||||
public int Immediate { get; protected set; }
|
||||
|
||||
public bool Index { get; private set; }
|
||||
public bool Add { get; private set; }
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace ARMeilleure.Decoders
|
|||
{
|
||||
public OpCode32MemImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Imm = opCode & 0xfff;
|
||||
Immediate = opCode & 0xfff;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ namespace ARMeilleure.Decoders
|
|||
int imm4L = (opCode >> 0) & 0xf;
|
||||
int imm4H = (opCode >> 8) & 0xf;
|
||||
|
||||
Imm = imm4L | (imm4H << 4);
|
||||
Immediate = imm4L | (imm4H << 4);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -594,32 +594,32 @@ namespace ARMeilleure.Decoders
|
|||
|
||||
#region "OpCode Table (AArch32)"
|
||||
// Base
|
||||
SetA32("<<<<0010100xxxxxxxxxxxxxxxxxxxxx", InstName.Add, null, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstName.Add, null, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstName.B, null, typeof(OpCode32BImm));
|
||||
SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bl, null, typeof(OpCode32BImm));
|
||||
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx, null, typeof(OpCode32BImm));
|
||||
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, null, typeof(OpCode32BReg));
|
||||
SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx, null, typeof(OpCodeT16BReg));
|
||||
SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstName.Cmp, null, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstName.Cmp, null, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<100xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, null, typeof(OpCode32MemMult));
|
||||
SetA32("<<<<010xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, null, typeof(OpCode32MemImm));
|
||||
SetA32("<<<<010xx1x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, null, typeof(OpCode32MemImm));
|
||||
SetA32("<<<<000xx1x0xxxxxxxxxxxx1101xxxx", InstName.Ldrd, null, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<000xx1x1xxxxxxxxxxxx1011xxxx", InstName.Ldrh, null, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<000xx1x1xxxxxxxxxxxx1101xxxx", InstName.Ldrsb, null, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<000xx1x1xxxxxxxxxxxx1111xxxx", InstName.Ldrsh, null, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstName.Mov, null, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, null, typeof(OpCode32AluRsImm));
|
||||
SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov, null, typeof(OpCodeT16AluImm8));
|
||||
SetA32("<<<<100xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Stm, null, typeof(OpCode32MemMult));
|
||||
SetA32("<<<<010xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Str, null, typeof(OpCode32MemImm));
|
||||
SetA32("<<<<010xx1x0xxxxxxxxxxxxxxxxxxxx", InstName.Strb, null, typeof(OpCode32MemImm));
|
||||
SetA32("<<<<000xx1x0xxxxxxxxxxxx1111xxxx", InstName.Strd, null, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<000xx1x0xxxxxxxxxxxx1011xxxx", InstName.Strh, null, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstName.Sub, null, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0000010xxxxxxxxxxxxxxxx0xxxx", InstName.Sub, null, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<0010100xxxxxxxxxxxxxxxxxxxxx", InstName.Add, InstEmit32.Add, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0000100xxxxxxxxxxxxxxxx0xxxx", InstName.Add, InstEmit32.Add, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", InstName.B, InstEmit32.B, typeof(OpCode32BImm));
|
||||
SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", InstName.Bl, InstEmit32.Bl, typeof(OpCode32BImm));
|
||||
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx, InstEmit32.Blx, typeof(OpCode32BImm));
|
||||
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, typeof(OpCode32BReg));
|
||||
SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx, InstEmit32.Bx, typeof(OpCodeT16BReg));
|
||||
SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstName.Cmp, InstEmit32.Cmp, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<100xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, typeof(OpCode32MemMult));
|
||||
SetA32("<<<<010xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, typeof(OpCode32MemImm));
|
||||
SetA32("<<<<010xx1x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, typeof(OpCode32MemImm));
|
||||
SetA32("<<<<000xx1x0xxxxxxxxxxxx1101xxxx", InstName.Ldrd, InstEmit32.Ldrd, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<000xx1x1xxxxxxxxxxxx1011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<000xx1x1xxxxxxxxxxxx1101xxxx", InstName.Ldrsb, InstEmit32.Ldrsb, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<000xx1x1xxxxxxxxxxxx1111xxxx", InstName.Ldrsh, InstEmit32.Ldrsh, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluRsImm));
|
||||
SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCodeT16AluImm8));
|
||||
SetA32("<<<<100xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, typeof(OpCode32MemMult));
|
||||
SetA32("<<<<010xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit32.Str, typeof(OpCode32MemImm));
|
||||
SetA32("<<<<010xx1x0xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, typeof(OpCode32MemImm));
|
||||
SetA32("<<<<000xx1x0xxxxxxxxxxxx1111xxxx", InstName.Strd, InstEmit32.Strd, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<000xx1x0xxxxxxxxxxxx1011xxxx", InstName.Strh, InstEmit32.Strh, typeof(OpCode32MemImm8));
|
||||
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0000010xxxxxxxxxxxxxxxx0xxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluRsImm));
|
||||
#endregion
|
||||
|
||||
FillFastLookupTable(_instA32FastLookup, _allInstA32);
|
||||
|
|
|
@ -338,12 +338,6 @@ namespace ARMeilleure.Instructions
|
|||
return context.BitwiseAnd(m, Const(context.CurrOp.GetBitsCount() - 1));
|
||||
}
|
||||
|
||||
private static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
|
||||
{
|
||||
SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
|
||||
SetFlag(context, PState.ZFlag, context.ICompareEqual(d, Const(d.Type, 0)));
|
||||
}
|
||||
|
||||
private static void EmitCVFlagsClear(ArmEmitterContext context)
|
||||
{
|
||||
SetFlag(context, PState.CFlag, Const(0));
|
||||
|
|
129
ARMeilleure/Instructions/InstEmitAlu32.cs
Normal file
129
ARMeilleure/Instructions/InstEmitAlu32.cs
Normal file
|
@ -0,0 +1,129 @@
|
|||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitAluHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static partial class InstEmit32
|
||||
{
|
||||
public static void Add(ArmEmitterContext context)
|
||||
{
|
||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||
|
||||
Operand n = GetAluN(context);
|
||||
Operand m = GetAluM(context, setCarry: false);
|
||||
|
||||
Operand res = context.Add(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
EmitAddsCCheck(context, n, res);
|
||||
EmitAddsVCheck(context, n, m, res);
|
||||
}
|
||||
|
||||
EmitAluStore(context, res);
|
||||
}
|
||||
|
||||
public static void Cmp(ArmEmitterContext context)
|
||||
{
|
||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||
|
||||
Operand n = GetAluN(context);
|
||||
Operand m = GetAluM(context, setCarry: false);
|
||||
|
||||
Operand res = context.Subtract(n, m);
|
||||
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
EmitSubsCCheck(context, n, res);
|
||||
EmitSubsVCheck(context, n, m, res);
|
||||
}
|
||||
|
||||
public static void Mov(ArmEmitterContext context)
|
||||
{
|
||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||
|
||||
Operand m = GetAluM(context);
|
||||
|
||||
if (op.SetFlags)
|
||||
{
|
||||
EmitNZFlagsCheck(context, m);
|
||||
}
|
||||
|
||||
EmitAluStore(context, m);
|
||||
}
|
||||
|
||||
public static void Sub(ArmEmitterContext context)
|
||||
{
|
||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||
|
||||
Operand n = GetAluN(context);
|
||||
Operand m = GetAluM(context, setCarry: false);
|
||||
|
||||
Operand res = context.Subtract(n, m);
|
||||
|
||||
if (op.SetFlags)
|
||||
{
|
||||
EmitNZFlagsCheck(context, res);
|
||||
|
||||
EmitSubsCCheck(context, n, res);
|
||||
EmitSubsVCheck(context, n, m, res);
|
||||
}
|
||||
|
||||
EmitAluStore(context, res);
|
||||
}
|
||||
|
||||
private static void EmitAluStore(ArmEmitterContext context, Operand value)
|
||||
{
|
||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||
|
||||
if (op.Rd == RegisterAlias.Aarch32Pc)
|
||||
{
|
||||
if (op.SetFlags)
|
||||
{
|
||||
// TODO: Load SPSR etc.
|
||||
Operand isThumb = GetFlag(PState.TFlag);
|
||||
|
||||
Operand lblThumb = Label();
|
||||
|
||||
context.BranchIfTrue(lblThumb, isThumb);
|
||||
|
||||
context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(value, Const(~3))));
|
||||
|
||||
context.MarkLabel(lblThumb);
|
||||
|
||||
context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(value, Const(~1))));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitAluWritePc(context, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SetIntA32(context, op.Rd, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitAluWritePc(ArmEmitterContext context, Operand value)
|
||||
{
|
||||
context.StoreToContext();
|
||||
|
||||
if (IsThumb(context.CurrOp))
|
||||
{
|
||||
context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(value, Const(~1))));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitBxWritePc(context, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,12 @@ namespace ARMeilleure.Instructions
|
|||
{
|
||||
static class InstEmitAluHelper
|
||||
{
|
||||
public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
|
||||
{
|
||||
SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
|
||||
SetFlag(context, PState.ZFlag, context.ICompareEqual(d, Const(d.Type, 0)));
|
||||
}
|
||||
|
||||
public static void EmitAdcsCCheck(ArmEmitterContext context, Operand n, Operand d)
|
||||
{
|
||||
// C = (Rd == Rn && CIn) || Rd < Rn
|
||||
|
@ -71,6 +77,7 @@ namespace ARMeilleure.Instructions
|
|||
SetFlag(context, PState.VFlag, vOut);
|
||||
}
|
||||
|
||||
|
||||
public static Operand GetAluN(ArmEmitterContext context)
|
||||
{
|
||||
if (context.CurrOp is IOpCodeAlu op)
|
||||
|
|
71
ARMeilleure/Instructions/InstEmitFlow32.cs
Normal file
71
ARMeilleure/Instructions/InstEmitFlow32.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static partial class InstEmit32
|
||||
{
|
||||
public static void B(ArmEmitterContext context)
|
||||
{
|
||||
IOpCode32BImm op = (IOpCode32BImm)context.CurrOp;
|
||||
|
||||
if (context.CurrBlock.Branch != null)
|
||||
{
|
||||
context.Branch(context.GetLabel((ulong)op.Immediate));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.StoreToContext();
|
||||
|
||||
context.Return(Const(op.Immediate));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Bl(ArmEmitterContext context)
|
||||
{
|
||||
Blx(context, x: false);
|
||||
}
|
||||
|
||||
public static void Blx(ArmEmitterContext context)
|
||||
{
|
||||
Blx(context, x: true);
|
||||
}
|
||||
|
||||
public static void Bx(ArmEmitterContext context)
|
||||
{
|
||||
IOpCode32BReg op = (IOpCode32BReg)context.CurrOp;
|
||||
|
||||
context.StoreToContext();
|
||||
|
||||
EmitBxWritePc(context, GetIntA32(context, op.Rm));
|
||||
}
|
||||
|
||||
private static void Blx(ArmEmitterContext context, bool x)
|
||||
{
|
||||
IOpCode32BImm op = (IOpCode32BImm)context.CurrOp;
|
||||
|
||||
uint pc = op.GetPc();
|
||||
|
||||
bool isThumb = IsThumb(context.CurrOp);
|
||||
|
||||
uint currentPc = isThumb
|
||||
? op.GetPc() | 1
|
||||
: op.GetPc() - 4;
|
||||
|
||||
SetIntOrSP(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
|
||||
|
||||
// If x is true, then this is a branch with link and exchange.
|
||||
// In this case we need to swap the mode between Arm <-> Thumb.
|
||||
if (x)
|
||||
{
|
||||
SetFlag(context, PState.TFlag, Const(isThumb ? 0 : 1));
|
||||
}
|
||||
|
||||
InstEmitFlowHelper.EmitCall(context, (ulong)op.Immediate);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,9 +33,9 @@ namespace ARMeilleure.Instructions
|
|||
return value;
|
||||
}
|
||||
|
||||
public static Operand GetIntA32(ArmEmitterContext context, int register)
|
||||
public static Operand GetIntA32(ArmEmitterContext context, int regIndex)
|
||||
{
|
||||
if (register == RegisterAlias.Aarch32Pc)
|
||||
if (regIndex == RegisterAlias.Aarch32Pc)
|
||||
{
|
||||
OpCode32 op = (OpCode32)context.CurrOp;
|
||||
|
||||
|
@ -43,27 +43,41 @@ namespace ARMeilleure.Instructions
|
|||
}
|
||||
else
|
||||
{
|
||||
return GetIntOrSP(context, GetRegisterAlias(context.Mode, register));
|
||||
return GetIntOrSP(context, GetRegisterAlias(context.Mode, regIndex));
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetRegisterAlias(Aarch32Mode mode, int register)
|
||||
public static void SetIntA32(ArmEmitterContext context, int regIndex, Operand value)
|
||||
{
|
||||
if (regIndex == RegisterAlias.Aarch32Pc)
|
||||
{
|
||||
context.StoreToContext();
|
||||
|
||||
EmitBxWritePc(context, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetIntOrSP(context, GetRegisterAlias(context.Mode, regIndex), value);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetRegisterAlias(Aarch32Mode mode, int regIndex)
|
||||
{
|
||||
// Only registers >= 8 are banked,
|
||||
// with registers in the range [8, 12] being
|
||||
// banked for the FIQ mode, and registers
|
||||
// 13 and 14 being banked for all modes.
|
||||
if ((uint)register < 8)
|
||||
if ((uint)regIndex < 8)
|
||||
{
|
||||
return register;
|
||||
return regIndex;
|
||||
}
|
||||
|
||||
return GetBankedRegisterAlias(mode, register);
|
||||
return GetBankedRegisterAlias(mode, regIndex);
|
||||
}
|
||||
|
||||
public static int GetBankedRegisterAlias(Aarch32Mode mode, int register)
|
||||
public static int GetBankedRegisterAlias(Aarch32Mode mode, int regIndex)
|
||||
{
|
||||
switch (register)
|
||||
switch (regIndex)
|
||||
{
|
||||
case 8: return mode == Aarch32Mode.Fiq
|
||||
? RegisterAlias.R8Fiq
|
||||
|
@ -115,20 +129,25 @@ namespace ARMeilleure.Instructions
|
|||
default: throw new ArgumentException(nameof(mode));
|
||||
}
|
||||
|
||||
default: throw new ArgumentOutOfRangeException(nameof(register));
|
||||
default: throw new ArgumentOutOfRangeException(nameof(regIndex));
|
||||
}
|
||||
}
|
||||
|
||||
public static Operand GetIntOrZR32(int regIndex)
|
||||
public static void EmitBxWritePc(ArmEmitterContext context, Operand pc)
|
||||
{
|
||||
if (regIndex == RegisterConsts.ZeroIndex)
|
||||
{
|
||||
return Const(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Register(regIndex, RegisterType.Integer, OperandType.I32);
|
||||
}
|
||||
Operand mode = context.BitwiseAnd(pc, Const(1));
|
||||
|
||||
SetFlag(context, PState.TFlag, mode);
|
||||
|
||||
Operand lblArmMode = Label();
|
||||
|
||||
context.BranchIfTrue(lblArmMode, mode);
|
||||
|
||||
context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(pc, Const(~1))));
|
||||
|
||||
context.MarkLabel(lblArmMode);
|
||||
|
||||
context.Return(context.ZeroExtend32(OperandType.I64, context.BitwiseAnd(pc, Const(~3))));
|
||||
}
|
||||
|
||||
public static Operand GetIntOrZR(ArmEmitterContext context, int regIndex)
|
||||
|
|
256
ARMeilleure/Instructions/InstEmitMemory32.cs
Normal file
256
ARMeilleure/Instructions/InstEmitMemory32.cs
Normal file
|
@ -0,0 +1,256 @@
|
|||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitMemoryHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static partial class InstEmit32
|
||||
{
|
||||
private const int ByteSizeLog2 = 0;
|
||||
private const int HWordSizeLog2 = 1;
|
||||
private const int WordSizeLog2 = 2;
|
||||
private const int DWordSizeLog2 = 3;
|
||||
|
||||
[Flags]
|
||||
enum AccessType
|
||||
{
|
||||
Store = 0,
|
||||
Signed = 1,
|
||||
Load = 2,
|
||||
|
||||
LoadZx = Load,
|
||||
LoadSx = Load | Signed,
|
||||
}
|
||||
|
||||
public static void Ldm(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
|
||||
|
||||
Operand n = GetIntA32(context, op.Rn);
|
||||
|
||||
Operand baseAddress = context.Add(n, Const(op.Offset));
|
||||
|
||||
bool writesToPc = (op.RegisterMask & (1 << RegisterAlias.Aarch32Pc)) != 0;
|
||||
|
||||
bool writeBack = op.PostOffset != 0 && (op.Rn != RegisterAlias.Aarch32Pc || !writesToPc);
|
||||
|
||||
if (writeBack)
|
||||
{
|
||||
SetIntA32(context, op.Rn, context.Add(n, Const(op.PostOffset)));
|
||||
}
|
||||
|
||||
int mask = op.RegisterMask;
|
||||
int offset = 0;
|
||||
|
||||
for (int register = 0; mask != 0; mask >>= 1, register++)
|
||||
{
|
||||
if ((mask & 1) != 0)
|
||||
{
|
||||
Operand address = context.Add(baseAddress, Const(offset));
|
||||
|
||||
EmitLoadZx(context, address, register, WordSizeLog2);
|
||||
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ldr(ArmEmitterContext context)
|
||||
{
|
||||
EmitLoadOrStore(context, WordSizeLog2, AccessType.LoadZx);
|
||||
}
|
||||
|
||||
public static void Ldrb(ArmEmitterContext context)
|
||||
{
|
||||
EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx);
|
||||
}
|
||||
|
||||
public static void Ldrd(ArmEmitterContext context)
|
||||
{
|
||||
EmitLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx);
|
||||
}
|
||||
|
||||
public static void Ldrh(ArmEmitterContext context)
|
||||
{
|
||||
EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx);
|
||||
}
|
||||
|
||||
public static void Ldrsb(ArmEmitterContext context)
|
||||
{
|
||||
EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadSx);
|
||||
}
|
||||
|
||||
public static void Ldrsh(ArmEmitterContext context)
|
||||
{
|
||||
EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadSx);
|
||||
}
|
||||
|
||||
public static void Stm(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
|
||||
|
||||
Operand n = GetIntA32(context, op.Rn);
|
||||
|
||||
Operand baseAddress = context.Add(n, Const(op.Offset));
|
||||
|
||||
int mask = op.RegisterMask;
|
||||
int offset = 0;
|
||||
|
||||
for (int register = 0; mask != 0; mask >>= 1, register++)
|
||||
{
|
||||
if ((mask & 1) != 0)
|
||||
{
|
||||
Operand address = context.Add(baseAddress, Const(offset));
|
||||
|
||||
EmitStore(context, address, register, WordSizeLog2);
|
||||
|
||||
// Note: If Rn is also specified on the register list,
|
||||
// and Rn is the first register on this list, then the
|
||||
// value that is written to memory is the unmodified value,
|
||||
// before the write back. If it is on the list, but it's
|
||||
// not the first one, then the value written to memory
|
||||
// varies between CPUs.
|
||||
if (offset == 0 && op.PostOffset != 0)
|
||||
{
|
||||
// Emit write back after the first write.
|
||||
SetIntA32(context, op.Rn, context.Add(n, Const(op.PostOffset)));
|
||||
}
|
||||
|
||||
offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Str(ArmEmitterContext context)
|
||||
{
|
||||
EmitLoadOrStore(context, WordSizeLog2, AccessType.Store);
|
||||
}
|
||||
|
||||
public static void Strb(ArmEmitterContext context)
|
||||
{
|
||||
EmitLoadOrStore(context, ByteSizeLog2, AccessType.Store);
|
||||
}
|
||||
|
||||
public static void Strd(ArmEmitterContext context)
|
||||
{
|
||||
EmitLoadOrStore(context, DWordSizeLog2, AccessType.Store);
|
||||
}
|
||||
|
||||
public static void Strh(ArmEmitterContext context)
|
||||
{
|
||||
EmitLoadOrStore(context, HWordSizeLog2, AccessType.Store);
|
||||
}
|
||||
|
||||
private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
|
||||
{
|
||||
OpCode32Mem op = (OpCode32Mem)context.CurrOp;
|
||||
|
||||
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
||||
|
||||
Operand temp = null;
|
||||
|
||||
if (op.Index || op.WBack)
|
||||
{
|
||||
temp = op.Add
|
||||
? context.Add (n, Const(op.Immediate))
|
||||
: context.Subtract(n, Const(op.Immediate));
|
||||
}
|
||||
|
||||
if (op.WBack)
|
||||
{
|
||||
SetIntA32(context, op.Rn, temp);
|
||||
}
|
||||
|
||||
Operand address;
|
||||
|
||||
if (op.Index)
|
||||
{
|
||||
address = temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
address = n;
|
||||
}
|
||||
|
||||
if ((accType & AccessType.Load) != 0)
|
||||
{
|
||||
void Load(int rt, int offs, int loadSize)
|
||||
{
|
||||
Operand addr = context.Add(address, Const(offs));
|
||||
|
||||
if ((accType & AccessType.Signed) != 0)
|
||||
{
|
||||
EmitLoadSx32(context, addr, rt, loadSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitLoadZx(context, addr, rt, loadSize);
|
||||
}
|
||||
}
|
||||
|
||||
if (size == DWordSizeLog2)
|
||||
{
|
||||
Operand lblBigEndian = Label();
|
||||
Operand lblEnd = Label();
|
||||
|
||||
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
||||
|
||||
Load(op.Rt, 0, WordSizeLog2);
|
||||
Load(op.Rt | 1, 4, WordSizeLog2);
|
||||
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblBigEndian);
|
||||
|
||||
Load(op.Rt | 1, 0, WordSizeLog2);
|
||||
Load(op.Rt, 4, WordSizeLog2);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
Load(op.Rt, 0, size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
void Store(int rt, int offs, int storeSize)
|
||||
{
|
||||
Operand addr = context.Add(address, Const(offs));
|
||||
|
||||
EmitStore(context, addr, rt, storeSize);
|
||||
}
|
||||
|
||||
if (size == DWordSizeLog2)
|
||||
{
|
||||
Operand lblBigEndian = Label();
|
||||
Operand lblEnd = Label();
|
||||
|
||||
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
|
||||
|
||||
Store(op.Rt, 0, WordSizeLog2);
|
||||
Store(op.Rt | 1, 4, WordSizeLog2);
|
||||
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblBigEndian);
|
||||
|
||||
Store(op.Rt | 1, 0, WordSizeLog2);
|
||||
Store(op.Rt, 4, WordSizeLog2);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
Store(op.Rt, 0, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -159,7 +159,7 @@ namespace ARMeilleure.Instructions
|
|||
break;
|
||||
}
|
||||
|
||||
SetIntOrZR(context, rt, value);
|
||||
SetInt(context, rt, value);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
}
|
||||
|
@ -245,9 +245,9 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath);
|
||||
|
||||
Operand value = GetIntOrZR(context, rt);
|
||||
Operand value = GetInt(context, rt);
|
||||
|
||||
if (size < 3)
|
||||
if (size < 3 && value.Type == OperandType.I64)
|
||||
{
|
||||
value = context.ConvertI64ToI32(value);
|
||||
}
|
||||
|
@ -322,7 +322,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
addressCheckMask |= (1u << size) - 1;
|
||||
|
||||
return context.BitwiseAnd(address, Const(addressCheckMask));
|
||||
return context.BitwiseAnd(address, Const(address.Type, addressCheckMask));
|
||||
}
|
||||
|
||||
private static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblFallbackPath)
|
||||
|
@ -339,11 +339,16 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
if (bit < context.Memory.AddressSpaceBits)
|
||||
{
|
||||
addrPart = context.BitwiseAnd(addrPart, Const((long)context.Memory.PtLevelMask));
|
||||
addrPart = context.BitwiseAnd(addrPart, Const(addrPart.Type, context.Memory.PtLevelMask));
|
||||
}
|
||||
|
||||
Operand pteOffset = context.ShiftLeft(addrPart, Const(3));
|
||||
|
||||
if (pteOffset.Type == OperandType.I32)
|
||||
{
|
||||
pteOffset = context.ZeroExtend32(OperandType.I64, pteOffset);
|
||||
}
|
||||
|
||||
Operand pteAddress = context.Add(pte, pteOffset);
|
||||
|
||||
pte = context.Load(OperandType.I64, pteAddress);
|
||||
|
@ -357,7 +362,12 @@ namespace ARMeilleure.Instructions
|
|||
context.BranchIfTrue(lblFallbackPath, hasFlagSet);
|
||||
}
|
||||
|
||||
Operand pageOffset = context.BitwiseAnd(address, Const((long)MemoryManager.PageMask));
|
||||
Operand pageOffset = context.BitwiseAnd(address, Const(address.Type, MemoryManager.PageMask));
|
||||
|
||||
if (pageOffset.Type == OperandType.I32)
|
||||
{
|
||||
pageOffset = context.ZeroExtend32(OperandType.I64, pageOffset);
|
||||
}
|
||||
|
||||
Operand physAddr = context.Add(pte, pageOffset);
|
||||
|
||||
|
@ -376,7 +386,7 @@ namespace ARMeilleure.Instructions
|
|||
case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64); break;
|
||||
}
|
||||
|
||||
SetIntOrZR(context, rt, context.Call(fallbackMethodDlg, address));
|
||||
SetInt(context, rt, context.Call(fallbackMethodDlg, address));
|
||||
}
|
||||
|
||||
private static void EmitReadVectorFallback(
|
||||
|
@ -423,9 +433,9 @@ namespace ARMeilleure.Instructions
|
|||
case 3: fallbackMethodDlg = new _Void_U64_U64(NativeInterface.WriteUInt64); break;
|
||||
}
|
||||
|
||||
Operand value = GetIntOrZR(context, rt);
|
||||
Operand value = GetInt(context, rt);
|
||||
|
||||
if (size < 3)
|
||||
if (size < 3 && value.Type == OperandType.I64)
|
||||
{
|
||||
value = context.ConvertI64ToI32(value);
|
||||
}
|
||||
|
@ -481,5 +491,22 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
context.Call(fallbackMethodDlg, address, value);
|
||||
}
|
||||
|
||||
private static Operand GetInt(ArmEmitterContext context, int rt)
|
||||
{
|
||||
return context.CurrOp is OpCode32 ? GetIntA32(context, rt) : GetIntOrZR(context, rt);
|
||||
}
|
||||
|
||||
private static void SetInt(ArmEmitterContext context, int rt, Operand value)
|
||||
{
|
||||
if (context.CurrOp is OpCode32)
|
||||
{
|
||||
SetIntA32(context, rt, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetIntOrZR(context, rt, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,6 +37,25 @@ namespace ARMeilleure.State
|
|||
public FPCR Fpcr { get; set; }
|
||||
public FPSR Fpsr { get; set; }
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
internal ExecutionMode ExecutionMode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsAarch32)
|
||||
{
|
||||
return GetPstateFlag(PState.TFlag)
|
||||
? ExecutionMode.Aarch32Thumb
|
||||
: ExecutionMode.Aarch32Arm;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ExecutionMode.Aarch64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Running { get; set; }
|
||||
|
||||
public event EventHandler<EventArgs> Interrupt;
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
public Operand Call(Delegate func, params Operand[] callArgs)
|
||||
{
|
||||
// Add the delegate to the cache to ensure it will not be garbage collected.
|
||||
//Add the delegate to the cache to ensure it will not be garbage collected.
|
||||
func = DelegateCache.GetOrAdd(func);
|
||||
|
||||
IntPtr ptr = Marshal.GetFunctionPointerForDelegate<Delegate>(func);
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
public ulong ExecuteSingle(ExecutionContext context, ulong address)
|
||||
{
|
||||
TranslatedFunction func = GetOrTranslate(address, ExecutionMode.Aarch64);
|
||||
TranslatedFunction func = GetOrTranslate(address, context.ExecutionMode);
|
||||
|
||||
Statistics.StartTimer();
|
||||
|
||||
|
@ -70,7 +70,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
Logger.StartPass(PassName.Decoding);
|
||||
|
||||
Block[] blocks = Decoder.DecodeFunction(_memory, address, ExecutionMode.Aarch64);
|
||||
Block[] blocks = Decoder.DecodeFunction(_memory, address, mode);
|
||||
|
||||
Logger.EndPass(PassName.Decoding);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue