Exclusive access instructions, fix to mul, system instructions.
Now gets to a break after SignalProcessWideKey64.
This commit is contained in:
parent
b1ba16a4d4
commit
aed13bcdd4
21 changed files with 814 additions and 23 deletions
11
ARMeilleure/Decoders/IOpCode32MemEx.cs
Normal file
11
ARMeilleure/Decoders/IOpCode32MemEx.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32MemEx : IOpCode32Mem
|
||||
{
|
||||
public int Rd { get; }
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ namespace ARMeilleure.Decoders
|
|||
Rn = (opCode >> 0) & 0xf;
|
||||
|
||||
Msb = ((opCode >> 16) & 31);
|
||||
Lsb = Msb - ((opCode >> 10) & 31);
|
||||
Lsb = ((opCode >> 7) & 31);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
26
ARMeilleure/Decoders/OpCode32AluMla.cs
Normal file
26
ARMeilleure/Decoders/OpCode32AluMla.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
15
ARMeilleure/Decoders/OpCode32MemLdEx.cs
Normal file
15
ARMeilleure/Decoders/OpCode32MemLdEx.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
17
ARMeilleure/Decoders/OpCode32MemStEx.cs
Normal file
17
ARMeilleure/Decoders/OpCode32MemStEx.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
18
ARMeilleure/Decoders/OpCode32SimdSpecial.cs
Normal file
18
ARMeilleure/Decoders/OpCode32SimdSpecial.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
28
ARMeilleure/Decoders/OpCode32System.cs
Normal file
28
ARMeilleure/Decoders/OpCode32System.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
312
ARMeilleure/Instructions/InstEmitMemoryEx32.cs
Normal file
312
ARMeilleure/Instructions/InstEmitMemoryEx32.cs
Normal 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.
|
||||
}
|
||||
}
|
||||
}
|
177
ARMeilleure/Instructions/InstEmitSystem32.cs
Normal file
177
ARMeilleure/Instructions/InstEmitSystem32.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}.");
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue