Exclusive access instructions, fix to mul, system instructions.

Now gets to a break after SignalProcessWideKey64.
This commit is contained in:
riperiperi 2019-12-27 22:27:53 +00:00 committed by Thog
parent b1ba16a4d4
commit aed13bcdd4
No known key found for this signature in database
GPG key ID: 0CD291558FAFDBC6
21 changed files with 814 additions and 23 deletions

View file

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
interface IOpCode32MemEx : IOpCode32Mem
{
public int Rd { get; }
}
}

View file

@ -22,7 +22,7 @@ namespace ARMeilleure.Decoders
Rn = (opCode >> 0) & 0xf;
Msb = ((opCode >> 16) & 31);
Lsb = Msb - ((opCode >> 10) & 31);
Lsb = ((opCode >> 7) & 31);
}
}
}

View file

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32AluMla : OpCode32, IOpCode32AluReg
{
public int Rn { get; private set; }
public int Rm { get; private set; }
public int Ra { get; private set; }
public int Rd { get; private set; }
public bool SetFlags { get; private set; }
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;
SetFlags = ((opCode >> 20) & 1) != 0;
}
}
}

View file

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32MemLdEx : OpCode32Mem, IOpCode32MemEx
{
public int Rd { get; internal set; }
public OpCode32MemLdEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = opCode & 0xf;
}
}
}

View file

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32MemStEx : OpCode32Mem, IOpCode32MemEx
{
public int Rd { get; internal set; }
public new int Rt { get; private set; }
public OpCode32MemStEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rd = (opCode >> 12) & 0xf;
Rt = (opCode >> 0) & 0xf;
}
}
}

View file

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32SimdSpecial : OpCode32
{
public int Rt { get; private set; }
public int Sreg { get; private set; }
public OpCode32SimdSpecial(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Rt = (opCode >> 12) & 0xf;
Sreg = (opCode >> 16) & 0xf;
}
}
}

View file

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace ARMeilleure.Decoders
{
class OpCode32System : OpCode32
{
public int Opc1 { get; internal set; }
public int CRn { get; internal set; }
public int Rt { get; internal set; }
public int Opc2 { get; internal set; }
public int CRm { get; internal set; }
public int Coproc { get; internal set; }
public OpCode32System(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
{
Opc1 = (opCode >> 21) & 0x7;
CRn = (opCode >> 16) & 0xf;
Rt = (opCode >> 12) & 0xf;
Opc2 = (opCode >> 5) & 0x7;
CRm = (opCode >> 0) & 0xf;
Coproc = (opCode >> 8) & 0xf;
}
}
}

View file

@ -616,6 +616,7 @@ namespace ARMeilleure.Decoders
SetA32("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, typeof(OpCode32BReg));
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, typeof(OpCode32BReg));
SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx, InstEmit32.Bx, typeof(OpCodeT16BReg));
SetA32("11110101011111111111000000011111", InstName.Clrex, InstEmit32.Clrex, typeof(OpCode32));
SetA32("<<<<000101101111xxxx11110001xxxx", InstName.Clz, InstEmit32.Clz, typeof(OpCode32AluReg));
SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, typeof(OpCode32AluImm));
SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstName.Cmp, InstEmit32.Cmp, typeof(OpCode32AluRsImm));
@ -625,6 +626,13 @@ namespace ARMeilleure.Decoders
SetA32("<<<<0010001xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluImm));
SetA32("<<<<0000001xxxxxxxxxxxxxxxx0xxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<00011001xxxxxxxx110010011111", InstName.Lda, InstEmit32.Lda, typeof(OpCode32MemLdEx));
SetA32("<<<<00011101xxxxxxxx110010011111", InstName.Ldab, InstEmit32.Ldab, typeof(OpCode32MemLdEx));
SetA32("<<<<00011001xxxxxxxx111010011111", InstName.Ldaex, InstEmit32.Ldaex, typeof(OpCode32MemLdEx));
SetA32("<<<<00011101xxxxxxxx111010011111", InstName.Ldaexb,InstEmit32.Ldaexb,typeof(OpCode32MemLdEx));
SetA32("<<<<00011011xxxxxxxx111010011111", InstName.Ldaexd,InstEmit32.Ldaexd,typeof(OpCode32MemLdEx));
SetA32("<<<<00011111xxxxxxxx111010011111", InstName.Ldaexh,InstEmit32.Ldaexh,typeof(OpCode32MemLdEx));
SetA32("<<<<00011111xxxxxxxx110010011111", InstName.Ldah, InstEmit32.Ldah, typeof(OpCode32MemLdEx));
SetA32("<<<<100xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, typeof(OpCode32MemMult));
SetA32("<<<<010xx0x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, typeof(OpCode32MemImm));
SetA32("<<<<011xx0x1xxxxxxxxxxxxxxx0xxxx", InstName.Ldr, InstEmit32.Ldr, typeof(OpCode32MemRsImm));
@ -632,16 +640,23 @@ namespace ARMeilleure.Decoders
SetA32("<<<<011xx1x1xxxxxxxxxxxxxxx0xxxx", InstName.Ldrb, InstEmit32.Ldrb, typeof(OpCode32MemRsImm));
SetA32("<<<<000xx1x0xxxxxxxxxxxx1101xxxx", InstName.Ldrd, InstEmit32.Ldrd, typeof(OpCode32MemImm8));
//SetA32("<<<<000xx0x0xxxxxxxx00001101xxxx", InstName.Ldrd, InstEmit32.Ldrd, typeof(OpCode32MemReg)); //??? wip
SetA32("<<<<00011001xxxxxxxx111110011111", InstName.Ldrex, InstEmit32.Ldrex, typeof(OpCode32MemLdEx));
SetA32("<<<<00011101xxxxxxxx111110011111", InstName.Ldrexb,InstEmit32.Ldrexb,typeof(OpCode32MemLdEx));
SetA32("<<<<00011011xxxxxxxx111110011111", InstName.Ldrexd,InstEmit32.Ldrexd,typeof(OpCode32MemLdEx));
SetA32("<<<<00011111xxxxxxxx111110011111", InstName.Ldrexh,InstEmit32.Ldrexh,typeof(OpCode32MemLdEx));
SetA32("<<<<000xx1x1xxxxxxxxxxxx1011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemImm8));
//SetA32("<<<<000xx0x1xxxxxxxx00001011xxxx", InstName.Ldrh, InstEmit32.Ldrh, typeof(OpCode32MemReg)); //??? wip
SetA32("<<<<000xx1x1xxxxxxxxxxxx1101xxxx", InstName.Ldrsb, InstEmit32.Ldrsb, typeof(OpCode32MemImm8));
SetA32("<<<<000xx1x1xxxxxxxxxxxx1111xxxx", InstName.Ldrsh, InstEmit32.Ldrsh, typeof(OpCode32MemImm8));
SetA32("<<<<1110xxx0xxxxxxxx111xxxx1xxxx", InstName.Mcr, InstEmit32.Mcr, typeof(OpCode32System));
SetA32("<<<<0000001xxxxxxxxxxxxx1001xxxx", InstName.Mla, InstEmit32.Mla, typeof(OpCode32AluMla));
SetA32("<<<<0011101x0000xxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluImm));
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluRsImm));
SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCode32AluImm16));
SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, typeof(OpCodeT16AluImm8));
SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, typeof(OpCode32AluImm16));
SetA32("<<<<0000000xxxxx0000xxxx1001xxxx", InstName.Mul, InstEmit32.Mul, typeof(OpCode32AluReg));
SetA32("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc, InstEmit32.Mrc, typeof(OpCode32System));
SetA32("<<<<0000000xxxxx0000xxxx1001xxxx", InstName.Mul, InstEmit32.Mul, typeof(OpCode32AluMla));
SetA32("<<<<0011111x0000xxxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, typeof(OpCode32AluImm));
SetA32("<<<<0001111x0000xxxxxxxxxxx0xxxx", InstName.Mvn, InstEmit32.Mvn, typeof(OpCode32AluRsImm));
//RsReg missing
@ -651,6 +666,13 @@ namespace ARMeilleure.Decoders
SetA32("<<<<0010011xxxxxxxxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluImm));
SetA32("<<<<0000011xxxxxxxxxxxxxxxx0xxxx", InstName.Rsb, InstEmit32.Rsb, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<00011000xxxx111111001001xxxx", InstName.Stl, InstEmit32.Stl, typeof(OpCode32MemStEx));
SetA32("<<<<00011100xxxx111111001001xxxx", InstName.Stlb, InstEmit32.Stlb, typeof(OpCode32MemStEx));
SetA32("<<<<00011000xxxxxxxx11101001xxxx", InstName.Stlex, InstEmit32.Stlex, typeof(OpCode32MemStEx));
SetA32("<<<<00011100xxxxxxxx11101001xxxx", InstName.Stlexb,InstEmit32.Stlexb,typeof(OpCode32MemStEx));
SetA32("<<<<00011010xxxxxxxx11101001xxxx", InstName.Stlexd,InstEmit32.Stlexd,typeof(OpCode32MemStEx));
SetA32("<<<<00011110xxxxxxxx11101001xxxx", InstName.Stlexh,InstEmit32.Stlexh,typeof(OpCode32MemStEx));
SetA32("<<<<00011110xxxx111111001001xxxx", InstName.Stlh, InstEmit32.Stlh, typeof(OpCode32MemStEx));
SetA32("<<<<100xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, typeof(OpCode32MemMult));
SetA32("<<<<010xx0x0xxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit32.Str, typeof(OpCode32MemImm));
SetA32("<<<<011xx0x0xxxxxxxxxxxxxxx0xxxx", InstName.Str, InstEmit32.Str, typeof(OpCode32MemRsImm));
@ -658,6 +680,11 @@ namespace ARMeilleure.Decoders
SetA32("<<<<011xx1x0xxxxxxxxxxxxxxx0xxxx", InstName.Strb, InstEmit32.Strb, typeof(OpCode32MemRsImm));
SetA32("<<<<000xx1x0xxxxxxxxxxxx1111xxxx", InstName.Strd, InstEmit32.Strd, typeof(OpCode32MemImm8));
//SetA32("<<<<000xx0x0xxxxxxxx00001111xxxx", InstName.Strd, InstEmit32.Strd, typeof(OpCode32MemReg)); //??? wip
SetA32("<<<<00011000xxxxxxxx11111001xxxx", InstName.Strex, InstEmit32.Strex, typeof(OpCode32MemStEx));
SetA32("<<<<00011100xxxxxxxx11111001xxxx", InstName.Strexb,InstEmit32.Strexb,typeof(OpCode32MemStEx));
SetA32("<<<<00011010xxxxxxxx11111001xxxx", InstName.Strexd,InstEmit32.Strexd,typeof(OpCode32MemStEx));
SetA32("<<<<00011110xxxxxxxx11111001xxxx", InstName.Strexh,InstEmit32.Strexh,typeof(OpCode32MemStEx));
SetA32("<<<<00011110xxxx111111001001xxxx", InstName.Stlh, InstEmit32.Stlh, typeof(OpCode32MemStEx));
SetA32("<<<<000xx1x0xxxxxxxxxxxx1011xxxx", InstName.Strh, InstEmit32.Strh, typeof(OpCode32MemImm8));
//SetA32("<<<<000xx0x0xxxxxxxx00001011xxxx", InstName.Strh, InstEmit32.Strh, typeof(OpCode32MemReg)); //??? wip
SetA32("<<<<0010010xxxxxxxxxxxxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, typeof(OpCode32AluImm));
@ -668,12 +695,16 @@ namespace ARMeilleure.Decoders
SetA32("<<<<00110001xxxx0000xxxxxxxxxxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluImm));
SetA32("<<<<00010001xxxx0000xxxxxxx0xxxx", InstName.Tst, InstEmit32.Tst, typeof(OpCode32AluRsImm));
//RsReg missing
SetA32("<<<<0111111xxxxxxxxxxxxxx101xxxx", InstName.Ubfx, InstEmit32.Ubfx, typeof(OpCode32AluBf));
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, typeof(OpCode32AluUmull));
SetA32("<<<<01101110xxxxxxxxxx000111xxxx", InstName.Uxtb, InstEmit32.Uxtb, typeof(OpCode32AluUx));
SetA32("<<<<011011111111xxxxxx000111xxxx", InstName.Uxth, InstEmit32.Uxth, typeof(OpCode32AluUx));
// FP & SIMD (AArch32)
SetA32("<<<<11001x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, typeof(OpCode32SimdMemMult));
SetA32("<<<<11001x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, typeof(OpCode32SimdMemMult));
SetA32("<<<<11101111xxxxxxxx101000010000", InstName.Vmrs, InstEmit32.Vmrs, typeof(OpCode32SimdSpecial));
SetA32("<<<<11101110xxxxxxxx101000010000", InstName.Vmsr, InstEmit32.Vmsr, typeof(OpCode32SimdSpecial));
SetA32("<<<<11010x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, typeof(OpCode32SimdMemMult));
SetA32("<<<<11010x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, typeof(OpCode32SimdMemMult));
#endregion

View file

@ -37,6 +37,7 @@ namespace ARMeilleure.Instructions
delegate ushort _U16_F32(float a1);
delegate ushort _U16_U64(ulong a1);
delegate uint _U32();
delegate uint _U32_F32(float a1);
delegate uint _U32_F64(double a1);
delegate uint _U32_U32(uint a1);
@ -74,6 +75,7 @@ namespace ARMeilleure.Instructions
delegate V128 _V128_V128_V128_V128(V128 a1, V128 a2, V128 a3);
delegate void _Void();
delegate void _Void_U32(uint a1);
delegate void _Void_U64(ulong a1);
delegate void _Void_U64_S32(ulong a1, int a2);
delegate void _Void_U64_U16(ulong a1, ushort a2);

View file

@ -243,6 +243,51 @@ namespace ARMeilleure.Instructions
EmitAluStore(context, res);
}
public static void Uxth(ArmEmitterContext context)
{
IOpCode32AluUx op = (IOpCode32AluUx)context.CurrOp;
Operand m = GetAluM(context);
Operand res;
if (op.RotateBits == 0)
{
res = m;
}
else
{
Operand rotate = Const(op.RotateBits);
res = context.RotateRight(m, rotate);
}
res = context.ZeroExtend16(OperandType.I32, res);
if (op.Add)
{
res = context.Add(res, GetAluN(context));
}
EmitAluStore(context, res);
}
public static void Mla(ArmEmitterContext context)
{
OpCode32AluMla op = (OpCode32AluMla)context.CurrOp;
Operand n = GetAluN(context);
Operand m = GetAluM(context);
Operand a = GetIntA32(context, op.Ra);
Operand res = context.Add(context.Multiply(n, m), a);
if (op.SetFlags)
{
EmitNZFlagsCheck(context, res);
}
EmitAluStore(context, res);
}
public static void Movt(ArmEmitterContext context)
{
OpCode32AluImm16 op = (OpCode32AluImm16)context.CurrOp;
@ -311,6 +356,19 @@ namespace ARMeilleure.Instructions
SetIntA32(context, op.Rd, res);
}
public static void Ubfx(ArmEmitterContext context)
{
OpCode32AluBf op = (OpCode32AluBf)context.CurrOp;
var msb = op.Lsb + op.Msb; //for this instruction, the msb is actually a width
var mask = (int)(0xFFFFFFFF >> (31 - msb)) << op.Lsb;
Operand n = GetIntOrZR(context, op.Rn);
Operand res = context.ShiftRightUI(context.BitwiseAnd(n, Const(mask)), Const(op.Lsb));
SetIntA32(context, op.Rd, res);
}
private static void EmitAluStore(ArmEmitterContext context, Operand value)
{
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;

View file

@ -122,7 +122,7 @@ namespace ARMeilleure.Instructions
case OpCodeT16AluImm8 op: return Const(op.Immediate);
case OpCode32AluReg op: return GetIntA32(context, op.Rm);
case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
// ARM64.
case IOpCodeAluImm op:

View file

@ -16,6 +16,7 @@ namespace ARMeilleure.Instructions
private const int HWordSizeLog2 = 1;
private const int WordSizeLog2 = 2;
private const int DWordSizeLog2 = 3;
private const int QWordSizeLog2 = 4;
[Flags]
enum AccessType
@ -23,6 +24,8 @@ namespace ARMeilleure.Instructions
Store = 0,
Signed = 1,
Load = 2,
Ordered = 4,
Exclusive = 8,
LoadZx = Load,
LoadSx = Load | Signed,

View file

@ -0,0 +1,312 @@
using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System;
using System.Collections.Generic;
using System.Text;
using ARMeilleure.Instructions;
using static ARMeilleure.Instructions.InstEmitHelper;
using static ARMeilleure.Instructions.InstEmitMemoryHelper;
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
using ARMeilleure.Decoders;
using ARMeilleure.State;
namespace ARMeilleure.Instructions
{
static partial class InstEmit32
{
public static void Clrex(ArmEmitterContext context)
{
context.Call(new _Void(NativeInterface.ClearExclusive));
}
public static void Ldrex(ArmEmitterContext context)
{
EmitExLoadOrStore(context, WordSizeLog2, AccessType.LoadZx | AccessType.Exclusive);
}
public static void Ldrexb(ArmEmitterContext context)
{
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Exclusive);
}
public static void Ldrexd(ArmEmitterContext context)
{
EmitExLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive);
}
public static void Ldrexh(ArmEmitterContext context)
{
EmitExLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive);
}
public static void Lda(ArmEmitterContext context)
{
EmitExLoadOrStore(context, WordSizeLog2, AccessType.LoadZx | AccessType.Ordered);
}
public static void Ldab(ArmEmitterContext context)
{
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Ordered);
}
public static void Ldaex(ArmEmitterContext context)
{
EmitExLoadOrStore(context, WordSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered);
}
public static void Ldaexb(ArmEmitterContext context)
{
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered);
}
public static void Ldaexd(ArmEmitterContext context)
{
EmitExLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered);
}
public static void Ldaexh(ArmEmitterContext context)
{
EmitExLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered);
}
public static void Ldah(ArmEmitterContext context)
{
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Ordered);
}
// stores
public static void Strex(ArmEmitterContext context)
{
EmitExLoadOrStore(context, WordSizeLog2, AccessType.Store | AccessType.Exclusive);
}
public static void Strexb(ArmEmitterContext context)
{
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.Store | AccessType.Exclusive);
}
public static void Strexd(ArmEmitterContext context)
{
EmitExLoadOrStore(context, DWordSizeLog2, AccessType.Store | AccessType.Exclusive);
}
public static void Strexh(ArmEmitterContext context)
{
EmitExLoadOrStore(context, HWordSizeLog2, AccessType.Store | AccessType.Exclusive);
}
public static void Stl(ArmEmitterContext context)
{
EmitExLoadOrStore(context, WordSizeLog2, AccessType.Store | AccessType.Ordered);
}
public static void Stlb(ArmEmitterContext context)
{
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.Store | AccessType.Ordered);
}
public static void Stlex(ArmEmitterContext context)
{
EmitExLoadOrStore(context, WordSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered);
}
public static void Stlexb(ArmEmitterContext context)
{
EmitExLoadOrStore(context, ByteSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered);
}
public static void Stlexd(ArmEmitterContext context)
{
EmitExLoadOrStore(context, DWordSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered);
}
public static void Stlexh(ArmEmitterContext context)
{
EmitExLoadOrStore(context, HWordSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered);
}
public static void Stlh(ArmEmitterContext context)
{
EmitExLoadOrStore(context, HWordSizeLog2, AccessType.Store | AccessType.Ordered);
}
private static void EmitExLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
{
IOpCode32MemEx op = (IOpCode32MemEx)context.CurrOp;
Operand address = context.Copy(GetIntA32(context, op.Rn));
var exclusive = (accType & AccessType.Exclusive) != 0;
var ordered = (accType & AccessType.Ordered) != 0;
if (ordered)
{
EmitBarrier(context);
}
if ((accType & AccessType.Load) != 0)
{
if (size == DWordSizeLog2)
{
// keep loads atomic - make the call to get the whole region and then decompose it into parts
// for the registers.
Operand value = EmitExLoad(context, address, exclusive, size);
Operand valueLow = context.ConvertI64ToI32(value);
valueLow = context.ZeroExtend32(OperandType.I64, valueLow);
Operand valueHigh = context.ShiftRightUI(value, Const(32));
Operand lblBigEndian = Label();
Operand lblEnd = Label();
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
SetIntA32(context, op.Rt, valueLow);
SetIntA32(context, op.Rt | 1, valueHigh);
context.Branch(lblEnd);
context.MarkLabel(lblBigEndian);
SetIntA32(context, op.Rt | 1, valueLow);
SetIntA32(context, op.Rt, valueHigh);
context.MarkLabel(lblEnd);
}
else
{
SetIntA32(context, op.Rt, EmitExLoad(context, address, exclusive, size));
}
}
else
{
Operand s = null;
if (size == DWordSizeLog2)
{
//split the result into 2 words (based on endianness)
Operand lo = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt));
Operand hi = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt | 1));
Operand toStore = Local(OperandType.I64);
Operand lblBigEndian = Label();
Operand lblEnd = Label();
context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag));
Operand leResult = context.BitwiseOr(lo, context.ShiftLeft(hi, Const(32)));
Operand leS = EmitExStore(context, address, leResult, true, size);
if (exclusive) SetIntA32(context, op.Rd, leS);
context.Branch(lblEnd);
context.MarkLabel(lblBigEndian);
Operand beResult = context.BitwiseOr(hi, context.ShiftLeft(lo, Const(32)));
Operand beS = EmitExStore(context, address, beResult, true, size);
if (exclusive) SetIntA32(context, op.Rd, beS);
context.MarkLabel(lblEnd);
}
else
{
s = EmitExStore(context, address, context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt)), true, size);
// This is only needed for exclusive stores. The function returns 0
// when the store is successful, and 1 otherwise.
if (exclusive) SetIntA32(context, op.Rd, s);
}
}
}
private static Operand EmitExLoad(
ArmEmitterContext context,
Operand address,
bool exclusive,
int size)
{
Delegate fallbackMethodDlg = null;
if (exclusive)
{
switch (size)
{
case 0: fallbackMethodDlg = new _U8_U64(NativeInterface.ReadByteExclusive); break;
case 1: fallbackMethodDlg = new _U16_U64(NativeInterface.ReadUInt16Exclusive); break;
case 2: fallbackMethodDlg = new _U32_U64(NativeInterface.ReadUInt32Exclusive); break;
case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64Exclusive); break;
case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128Exclusive); break;
}
}
else
{
switch (size)
{
case 0: fallbackMethodDlg = new _U8_U64(NativeInterface.ReadByte); break;
case 1: fallbackMethodDlg = new _U16_U64(NativeInterface.ReadUInt16); break;
case 2: fallbackMethodDlg = new _U32_U64(NativeInterface.ReadUInt32); break;
case 3: fallbackMethodDlg = new _U64_U64(NativeInterface.ReadUInt64); break;
case 4: fallbackMethodDlg = new _V128_U64(NativeInterface.ReadVector128); break;
}
}
return context.Call(fallbackMethodDlg, address);
}
private static Operand EmitExStore(
ArmEmitterContext context,
Operand address,
Operand value,
bool exclusive,
int size)
{
if (size < 3)
{
value = context.ConvertI64ToI32(value);
}
Delegate fallbackMethodDlg = null;
if (exclusive)
{
switch (size)
{
case 0: fallbackMethodDlg = new _S32_U64_U8(NativeInterface.WriteByteExclusive); break;
case 1: fallbackMethodDlg = new _S32_U64_U16(NativeInterface.WriteUInt16Exclusive); break;
case 2: fallbackMethodDlg = new _S32_U64_U32(NativeInterface.WriteUInt32Exclusive); break;
case 3: fallbackMethodDlg = new _S32_U64_U64(NativeInterface.WriteUInt64Exclusive); break;
case 4: fallbackMethodDlg = new _S32_U64_V128(NativeInterface.WriteVector128Exclusive); break;
}
return context.Call(fallbackMethodDlg, address, value);
}
else
{
switch (size)
{
case 0: fallbackMethodDlg = new _Void_U64_U8(NativeInterface.WriteByte); break;
case 1: fallbackMethodDlg = new _Void_U64_U16(NativeInterface.WriteUInt16); break;
case 2: fallbackMethodDlg = new _Void_U64_U32(NativeInterface.WriteUInt32); break;
case 3: fallbackMethodDlg = new _Void_U64_U64(NativeInterface.WriteUInt64); break;
case 4: fallbackMethodDlg = new _Void_U64_V128(NativeInterface.WriteVector128); break;
}
context.Call(fallbackMethodDlg, address, value);
return null;
}
}
private static void EmitBarrier(ArmEmitterContext context)
{
// Note: This barrier is most likely not necessary, and probably
// doesn't make any difference since we need to do a ton of stuff
// (software MMU emulation) to read or write anything anyway.
}
}
}

View file

@ -0,0 +1,177 @@
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
{
public static void Vmrs(ArmEmitterContext context)
{
var op = (OpCode32SimdSpecial)context.CurrOp;
if (op.Rt == 15 && op.Sreg == 0b0001)
{
//special behavior: copy NZCV flags into APSR
EmitSetNzcv(context, context.Call(new _U32(NativeInterface.GetFpscr)));
return;
}
Delegate dlg;
switch (op.Sreg)
{
case 0b0000: //FPSID
throw new NotImplementedException("Supervisor Only");
case 0b0001: //FPSCR
dlg = new _U32(NativeInterface.GetFpscr); break;
case 0b0101: //MVFR2
throw new NotImplementedException("MVFR2");
case 0b0110: //MVFR1
throw new NotImplementedException("MVFR1");
case 0b0111: //MVFR0
throw new NotImplementedException("MVFR0");
case 0b1000: //FPEXC
throw new NotImplementedException("Supervisor Only");
default: throw new NotImplementedException($"Unknown VMRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
SetIntA32(context, op.Rt, context.Call(dlg));
}
public static void Vmsr(ArmEmitterContext context)
{
var op = (OpCode32SimdSpecial)context.CurrOp;
Delegate dlg;
switch (op.Sreg)
{
case 0b0000: //FPSID
throw new NotImplementedException("Supervisor Only");
case 0b0001: //FPSCR
dlg = new _Void_U32(NativeInterface.SetFpscr); break;
case 0b0101: //MVFR2
throw new Exception("MVFR2");
case 0b0110: //MVFR1
throw new Exception("MVFR1");
case 0b0111: //MVFR0
throw new Exception("MVFR0");
case 0b1000: //FPEXC
throw new NotImplementedException("Supervisor Only");
default: throw new NotImplementedException($"Unknown VMSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
context.Call(dlg, GetIntA32(context, op.Rt));
}
public static void Mrc(ArmEmitterContext context)
{
var op = (OpCode32System)context.CurrOp;
if (op.Coproc != 15)
{
throw new NotImplementedException($"Unknown MRC Coprocessor ID 0x{op.Coproc:X16} at 0x{op.Address:X16}.");
}
if (op.Opc1 != 0)
{
throw new NotImplementedException($"Unknown MRC Opc1 0x{op.Opc1:X16} at 0x{op.Address:X16}.");
}
Delegate dlg;
switch (op.CRn)
{
case 13: // Process and Thread Info
if (op.CRm != 0)
{
throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}.");
}
switch (op.Opc2)
{
case 2:
dlg = new _U32(NativeInterface.GetTpidrEl032); break;
case 3:
dlg = new _U32(NativeInterface.GetTpidr32); break;
default:
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}.");
}
break;
default: throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
if (op.Rt == 15)
{
//special behavior: copy NZCV flags into APSR
EmitSetNzcv(context, context.Call(dlg));
return;
}
else
{
SetIntA32(context, op.Rt, context.Call(dlg));
}
}
public static void Mcr(ArmEmitterContext context)
{
var op = (OpCode32System)context.CurrOp;
if (op.Coproc != 15)
{
throw new NotImplementedException($"Unknown MRC Coprocessor ID 0x{op.Coproc:X16} at 0x{op.Address:X16}.");
}
if (op.Opc1 != 0)
{
throw new NotImplementedException($"Unknown MRC Opc1 0x{op.Opc1:X16} at 0x{op.Address:X16}.");
}
Delegate dlg;
switch (op.CRn)
{
case 13: // Process and Thread Info
if (op.CRm != 0)
{
throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16}.");
}
switch (op.Opc2)
{
case 2:
dlg = new _Void_U32(NativeInterface.SetTpidrEl032); break;
default:
throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16}.");
}
break;
default: throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
}
context.Call(dlg, GetIntA32(context, op.Rt));
}
private static void EmitSetNzcv(ArmEmitterContext context, Operand t)
{
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
v = context.BitwiseAnd(v, Const(1));
Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
c = context.BitwiseAnd(c, Const(1));
Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
z = context.BitwiseAnd(z, Const(1));
Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
n = context.BitwiseAnd(n, Const(1));
SetFlag(context, PState.VFlag, v);
SetFlag(context, PState.CFlag, c);
SetFlag(context, PState.ZFlag, z);
SetFlag(context, PState.NFlag, n);
}
}
}

View file

@ -453,26 +453,55 @@ namespace ARMeilleure.Instructions
Cmn,
Movt,
Mul,
Lda,
Ldab,
Ldaex,
Ldaexb,
Ldaexd,
Ldaexh,
Ldah,
Ldm,
Ldrb,
Ldrd,
Ldrex,
Ldrexb,
Ldrexd,
Ldrexh,
Ldrh,
Ldrsb,
Ldrsh,
Mcr,
Mla,
Mov,
Mrc,
Mvn,
Rsb,
Stl,
Stlb,
Stlex,
Stlexb,
Stlexd,
Stlexh,
Stlh,
Stm,
Strb,
Strd,
Strex,
Strexb,
Strexd,
Strexh,
Strh,
Teq,
Tst,
Ubfx,
Umull,
Uxtb,
Uxth,
// FP & SIMD (AArch32)
Vstm,
Vmrs,
Vmsr,
Vldm
}
}

View file

@ -87,16 +87,32 @@ namespace ARMeilleure.Instructions
return (ulong)GetContext().Fpsr;
}
public static uint GetFpscr()
{
ExecutionContext context = GetContext();
return (uint)(context.Fpsr & FPSR.A32Mask) | (uint)(context.Fpcr & FPCR.A32Mask);
}
public static ulong GetTpidrEl0()
{
return (ulong)GetContext().TpidrEl0;
}
public static uint GetTpidrEl032()
{
return (uint)GetContext().TpidrEl0;
}
public static ulong GetTpidr()
{
return (ulong)GetContext().Tpidr;
}
public static uint GetTpidr32()
{
return (uint)GetContext().Tpidr;
}
public static ulong GetCntfrqEl0()
{
return GetContext().CntfrqEl0;
@ -117,13 +133,25 @@ namespace ARMeilleure.Instructions
GetContext().Fpsr = (FPSR)value;
}
public static void SetFpscr(uint value)
{
ExecutionContext context = GetContext();
context.Fpsr = FPSR.A32Mask & (FPSR)value;
context.Fpcr = FPCR.A32Mask & (FPCR)value;
}
public static void SetTpidrEl0(ulong value)
{
GetContext().TpidrEl0 = (long)value;
}
#endregion
#region "Read"
public static void SetTpidrEl032(uint value)
{
GetContext().TpidrEl0 = (long)value;
}
#endregion
#region "Read"
public static byte ReadByte(ulong address)
{
return GetMemoryManager().ReadByte((long)address);

View file

@ -3,12 +3,14 @@ using System;
namespace ARMeilleure.State
{
[Flags]
public enum FPCR
public enum FPCR : ulong
{
Ufe = 1 << 11,
Fz = 1 << 24,
Dn = 1 << 25,
Ahp = 1 << 26
Ahp = 1 << 26,
A32Mask = 0x07ffff00
}
public static class FPCRExtensions

View file

@ -3,9 +3,11 @@ using System;
namespace ARMeilleure.State
{
[Flags]
public enum FPSR
public enum FPSR : ulong
{
Ufc = 1 << 3,
Qc = 1 << 27
Qc = 1 << 27,
A32Mask = 0xf800000f
}
}

View file

@ -72,25 +72,46 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
}
}
// TODO: ARM32.
long framePointer = (long)context.GetX(29);
trace.AppendLine($"Process: {_owner.Name}, PID: {_owner.Pid}");
while (framePointer != 0)
if (context.IsAarch32)
{
if ((framePointer & 7) != 0 ||
!_owner.CpuMemory.IsMapped(framePointer) ||
!_owner.CpuMemory.IsMapped(framePointer + 8))
long framePointer = (long)context.GetX(0xd);
while (framePointer != 0)
{
break;
if ((framePointer & 7) != 0 ||
!_owner.CpuMemory.IsMapped(framePointer) ||
!_owner.CpuMemory.IsMapped(framePointer + 4))
{
break;
}
// Note: This is the return address, we need to subtract one instruction
// worth of bytes to get the branch instruction address.
AppendTrace(_owner.CpuMemory.ReadInt32(framePointer + 4) - 4);
framePointer = _owner.CpuMemory.ReadInt32(framePointer);
}
}
else
{
long framePointer = (long)context.GetX(29);
// Note: This is the return address, we need to subtract one instruction
// worth of bytes to get the branch instruction address.
AppendTrace(_owner.CpuMemory.ReadInt64(framePointer + 8) - 4);
while (framePointer != 0)
{
if ((framePointer & 7) != 0 ||
!_owner.CpuMemory.IsMapped(framePointer) ||
!_owner.CpuMemory.IsMapped(framePointer + 8))
{
break;
}
framePointer = _owner.CpuMemory.ReadInt64(framePointer);
// Note: This is the return address, we need to subtract one instruction
// worth of bytes to get the branch instruction address.
AppendTrace(_owner.CpuMemory.ReadInt64(framePointer + 8) - 4);
framePointer = _owner.CpuMemory.ReadInt64(framePointer);
}
}
return trace.ToString();

View file

@ -257,6 +257,15 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
return GetInfo(id, handle, subId, out value);
}
public KernelResult GetInfo32(uint subIdLo, uint id, int handle, uint subIdHi, out uint valueLo, out uint valueHi)
{
long value;
KernelResult result = GetInfo(id, handle, subIdHi | ((long)subIdLo << 32), out value);
valueLo = (uint)(value >> 32);
valueHi = (uint)value;
return result;
}
private KernelResult GetInfo(uint id, int handle, long subId, out long value)
{
value = 0;

View file

@ -3,6 +3,7 @@ using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS.Kernel.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
@ -84,7 +85,8 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
_svcFuncs32 = new Dictionary<int, string>
{
{ 0x06, nameof(SvcHandler.QueryMemory32) },
{ 0x27, nameof(SvcHandler.OutputDebugString32) }
{ 0x27, nameof(SvcHandler.OutputDebugString32) },
{ 0x29, nameof(SvcHandler.GetInfo64) }
};
_svcTable64 = new Action<SvcHandler, ExecutionContext>[0x80];
@ -126,7 +128,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
int maxArgs = aarch32 ? SvcFuncMaxArguments32 : SvcFuncMaxArguments;
if (methodArgs.Length > maxArgs)
if (methodArgs.Count(x => !x.IsOut) > maxArgs)
{
throw new InvalidOperationException($"Method \"{svcName}\" has too many arguments, max is {maxArgs}.");
}