Port over the ARM32 instructions

This commit is contained in:
gdkchan 2019-07-29 01:38:53 -03:00
parent 8938e9f2e0
commit eaa734b8e6
14 changed files with 588 additions and 66 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

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

View file

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

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

View file

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

View file

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

View file

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

View file

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