mirror of
https://github.com/GreemDev/Ryujinx
synced 2024-11-21 17:40:52 +01:00
Improve access to system registers by using properties, also use exclusive region granularity on exclusive load/stores, and ensure that acquires without releases won't hold the address forever, remove unused ALU rev method
This commit is contained in:
parent
6ae5587b5e
commit
2347c44bbf
9 changed files with 130 additions and 138 deletions
|
@ -175,17 +175,6 @@ namespace ChocolArm64.Instruction
|
||||||
Context.EmitStintzr(Op.Rd);
|
Context.EmitStintzr(Op.Rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitRev(AILEmitterCtx Context, string Name)
|
|
||||||
{
|
|
||||||
AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp;
|
|
||||||
|
|
||||||
Context.EmitLdintzr(Op.Rn);
|
|
||||||
|
|
||||||
ASoftFallback.EmitCall(Context, Name);
|
|
||||||
|
|
||||||
Context.EmitStintzr(Op.Rd);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Rorv(AILEmitterCtx Context)
|
public static void Rorv(AILEmitterCtx Context)
|
||||||
{
|
{
|
||||||
EmitDataLoadRn(Context);
|
EmitDataLoadRn(Context);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using ChocolArm64.Decoder;
|
using ChocolArm64.Decoder;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using ChocolArm64.Translation;
|
using ChocolArm64.Translation;
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
namespace ChocolArm64.Instruction
|
namespace ChocolArm64.Instruction
|
||||||
|
@ -13,13 +15,30 @@ namespace ChocolArm64.Instruction
|
||||||
|
|
||||||
Context.EmitLdarg(ATranslatedSub.RegistersArgIdx);
|
Context.EmitLdarg(ATranslatedSub.RegistersArgIdx);
|
||||||
|
|
||||||
Context.EmitLdc_I4(Op.Op0);
|
string PropName;
|
||||||
Context.EmitLdc_I4(Op.Op1);
|
|
||||||
Context.EmitLdc_I4(Op.CRn);
|
|
||||||
Context.EmitLdc_I4(Op.CRm);
|
|
||||||
Context.EmitLdc_I4(Op.Op2);
|
|
||||||
|
|
||||||
Context.EmitCall(typeof(ARegisters), nameof(ARegisters.GetSystemReg));
|
switch (GetPackedId(Op))
|
||||||
|
{
|
||||||
|
case 0b11_011_0000_0000_001: PropName = nameof(ARegisters.CtrEl0); break;
|
||||||
|
case 0b11_011_0000_0000_111: PropName = nameof(ARegisters.DczidEl0); break;
|
||||||
|
case 0b11_011_0100_0100_000: PropName = nameof(ARegisters.Fpcr); break;
|
||||||
|
case 0b11_011_0100_0100_001: PropName = nameof(ARegisters.Fpsr); break;
|
||||||
|
case 0b11_011_1101_0000_010: PropName = nameof(ARegisters.TpidrEl0); break;
|
||||||
|
case 0b11_011_1101_0000_011: PropName = nameof(ARegisters.Tpidr); break;
|
||||||
|
case 0b11_011_1110_0000_001: PropName = nameof(ARegisters.CntpctEl0); break;
|
||||||
|
|
||||||
|
default: throw new NotImplementedException($"Unknown MRS at {Op.Position:x16}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Context.EmitCallPropGet(typeof(ARegisters), PropName);
|
||||||
|
|
||||||
|
PropertyInfo PropInfo = typeof(ARegisters).GetProperty(PropName);
|
||||||
|
|
||||||
|
if (PropInfo.PropertyType != typeof(long) &&
|
||||||
|
PropInfo.PropertyType != typeof(ulong))
|
||||||
|
{
|
||||||
|
Context.Emit(OpCodes.Conv_U8);
|
||||||
|
}
|
||||||
|
|
||||||
Context.EmitStintzr(Op.Rt);
|
Context.EmitStintzr(Op.Rt);
|
||||||
}
|
}
|
||||||
|
@ -29,15 +48,28 @@ namespace ChocolArm64.Instruction
|
||||||
AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
|
AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
|
||||||
|
|
||||||
Context.EmitLdarg(ATranslatedSub.RegistersArgIdx);
|
Context.EmitLdarg(ATranslatedSub.RegistersArgIdx);
|
||||||
|
|
||||||
Context.EmitLdc_I4(Op.Op0);
|
|
||||||
Context.EmitLdc_I4(Op.Op1);
|
|
||||||
Context.EmitLdc_I4(Op.CRn);
|
|
||||||
Context.EmitLdc_I4(Op.CRm);
|
|
||||||
Context.EmitLdc_I4(Op.Op2);
|
|
||||||
Context.EmitLdintzr(Op.Rt);
|
Context.EmitLdintzr(Op.Rt);
|
||||||
|
|
||||||
Context.EmitCall(typeof(ARegisters), nameof(ARegisters.SetSystemReg));
|
string PropName;
|
||||||
|
|
||||||
|
switch (GetPackedId(Op))
|
||||||
|
{
|
||||||
|
case 0b11_011_0100_0100_000: PropName = nameof(ARegisters.Fpcr); break;
|
||||||
|
case 0b11_011_0100_0100_001: PropName = nameof(ARegisters.Fpsr); break;
|
||||||
|
case 0b11_011_1101_0000_010: PropName = nameof(ARegisters.TpidrEl0); break;
|
||||||
|
|
||||||
|
default: throw new NotImplementedException($"Unknown MSR at {Op.Position:x16}");
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyInfo PropInfo = typeof(ARegisters).GetProperty(PropName);
|
||||||
|
|
||||||
|
if (PropInfo.PropertyType != typeof(long) &&
|
||||||
|
PropInfo.PropertyType != typeof(ulong))
|
||||||
|
{
|
||||||
|
Context.Emit(OpCodes.Conv_U4);
|
||||||
|
}
|
||||||
|
|
||||||
|
Context.EmitCallPropSet(typeof(ARegisters), PropName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Nop(AILEmitterCtx Context)
|
public static void Nop(AILEmitterCtx Context)
|
||||||
|
@ -52,19 +84,12 @@ namespace ChocolArm64.Instruction
|
||||||
//We treat it as no-op here since we don't have any cache being emulated anyway.
|
//We treat it as no-op here since we don't have any cache being emulated anyway.
|
||||||
AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
|
AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
|
||||||
|
|
||||||
int Id;
|
switch (GetPackedId(Op))
|
||||||
|
|
||||||
Id = Op.Op2 << 0;
|
|
||||||
Id |= Op.CRm << 3;
|
|
||||||
Id |= Op.CRn << 7;
|
|
||||||
Id |= Op.Op1 << 11;
|
|
||||||
|
|
||||||
switch (Id)
|
|
||||||
{
|
{
|
||||||
case 0b011_0111_0100_001:
|
case 0b11_011_0111_0100_001:
|
||||||
{
|
{
|
||||||
//DC ZVA
|
//DC ZVA
|
||||||
for (int Offs = 0; Offs < 64; Offs += 8)
|
for (int Offs = 0; Offs < (4 << ARegisters.DczSizeLog2); Offs += 8)
|
||||||
{
|
{
|
||||||
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
Context.EmitLdarg(ATranslatedSub.MemoryArgIdx);
|
||||||
Context.EmitLdint(Op.Rt);
|
Context.EmitLdint(Op.Rt);
|
||||||
|
@ -80,5 +105,18 @@ namespace ChocolArm64.Instruction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int GetPackedId(AOpCodeSystem Op)
|
||||||
|
{
|
||||||
|
int Id;
|
||||||
|
|
||||||
|
Id = Op.Op2 << 0;
|
||||||
|
Id |= Op.CRm << 3;
|
||||||
|
Id |= Op.CRn << 7;
|
||||||
|
Id |= Op.Op1 << 11;
|
||||||
|
Id |= Op.Op0 << 14;
|
||||||
|
|
||||||
|
return Id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -6,6 +6,8 @@ namespace ChocolArm64.Memory
|
||||||
{
|
{
|
||||||
public unsafe class AMemory
|
public unsafe class AMemory
|
||||||
{
|
{
|
||||||
|
private const long ErgMask = (4 << ARegisters.ErgSizeLog2) - 1;
|
||||||
|
|
||||||
public AMemoryMgr Manager { get; private set; }
|
public AMemoryMgr Manager { get; private set; }
|
||||||
|
|
||||||
private struct ExMonitor
|
private struct ExMonitor
|
||||||
|
@ -52,6 +54,11 @@ namespace ChocolArm64.Memory
|
||||||
{
|
{
|
||||||
lock (Monitors)
|
lock (Monitors)
|
||||||
{
|
{
|
||||||
|
if (Monitors.TryGetValue(ThreadId, out ExMonitor Monitor))
|
||||||
|
{
|
||||||
|
ExAddrs.Remove(Monitor.Position);
|
||||||
|
}
|
||||||
|
|
||||||
Monitors.Remove(ThreadId);
|
Monitors.Remove(ThreadId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,14 +67,16 @@ namespace ChocolArm64.Memory
|
||||||
{
|
{
|
||||||
lock (Monitors)
|
lock (Monitors)
|
||||||
{
|
{
|
||||||
bool ExState = !ExAddrs.Contains(Position);
|
Position &= ~ErgMask;
|
||||||
|
|
||||||
if (ExState)
|
if (Monitors.TryGetValue(Registers.ThreadId, out ExMonitor Monitor))
|
||||||
{
|
{
|
||||||
ExAddrs.Add(Position);
|
ExAddrs.Remove(Monitor.Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExMonitor Monitor = new ExMonitor(Position, ExState);
|
bool ExState = ExAddrs.Add(Position);
|
||||||
|
|
||||||
|
Monitor = new ExMonitor(Position, ExState);
|
||||||
|
|
||||||
if (!Monitors.TryAdd(Registers.ThreadId, Monitor))
|
if (!Monitors.TryAdd(Registers.ThreadId, Monitor))
|
||||||
{
|
{
|
||||||
|
@ -80,6 +89,8 @@ namespace ChocolArm64.Memory
|
||||||
{
|
{
|
||||||
lock (Monitors)
|
lock (Monitors)
|
||||||
{
|
{
|
||||||
|
Position &= ~ErgMask;
|
||||||
|
|
||||||
if (!Monitors.TryGetValue(Registers.ThreadId, out ExMonitor Monitor))
|
if (!Monitors.TryGetValue(Registers.ThreadId, out ExMonitor Monitor))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
namespace ChocolArm64.State
|
|
||||||
{
|
|
||||||
public enum ACoreType
|
|
||||||
{
|
|
||||||
CortexA53,
|
|
||||||
CortexA57
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,6 +7,12 @@ namespace ChocolArm64.State
|
||||||
internal const int LRIndex = 30;
|
internal const int LRIndex = 30;
|
||||||
internal const int ZRIndex = 31;
|
internal const int ZRIndex = 31;
|
||||||
|
|
||||||
|
internal const int ErgSizeLog2 = 4;
|
||||||
|
internal const int DczSizeLog2 = 4;
|
||||||
|
|
||||||
|
private const long TicksPerS = 19_200_000;
|
||||||
|
private const long TicksPerMS = TicksPerS / 1_000;
|
||||||
|
|
||||||
public ulong X0, X1, X2, X3, X4, X5, X6, X7,
|
public ulong X0, X1, X2, X3, X4, X5, X6, X7,
|
||||||
X8, X9, X10, X11, X12, X13, X14, X15,
|
X8, X9, X10, X11, X12, X13, X14, X15,
|
||||||
X16, X17, X18, X19, X20, X21, X22, X23,
|
X16, X17, X18, X19, X20, X21, X22, X23,
|
||||||
|
@ -22,97 +28,23 @@ namespace ChocolArm64.State
|
||||||
public bool Zero;
|
public bool Zero;
|
||||||
public bool Negative;
|
public bool Negative;
|
||||||
|
|
||||||
public int ProcessId;
|
public int ProcessId;
|
||||||
public int ThreadId;
|
public int ThreadId;
|
||||||
public long TlsAddrEl0;
|
|
||||||
public long TlsAddr;
|
|
||||||
|
|
||||||
private int FPCR;
|
public long TpidrEl0 { get; set; }
|
||||||
private int FPSR;
|
public long Tpidr { get; set; }
|
||||||
|
|
||||||
public ACoreType CoreType;
|
public int Fpcr { get; set; }
|
||||||
|
public int Fpsr { get; set; }
|
||||||
|
|
||||||
private const ulong A53DczidEl0 = 4;
|
public uint CtrEl0 => 0x8444c004;
|
||||||
private const ulong A53CtrEl0 = 0x84448004;
|
public uint DczidEl0 => 0x00000004;
|
||||||
private const ulong A57CtrEl0 = 0x8444c004;
|
|
||||||
|
|
||||||
private const ulong TicksPerS = 19_200_000;
|
public long CntpctEl0 => Environment.TickCount * TicksPerMS;
|
||||||
private const ulong TicksPerMS = TicksPerS / 1_000;
|
|
||||||
|
|
||||||
public event EventHandler<SvcEventArgs> SvcCall;
|
public event EventHandler<SvcEventArgs> SvcCall;
|
||||||
public event EventHandler<EventArgs> Undefined;
|
public event EventHandler<EventArgs> Undefined;
|
||||||
|
|
||||||
public ulong GetSystemReg(int Op0, int Op1, int CRn, int CRm, int Op2)
|
|
||||||
{
|
|
||||||
switch (PackRegId(Op0, Op1, CRn, CRm, Op2))
|
|
||||||
{
|
|
||||||
case 0b11_011_0000_0000_001: return GetCtrEl0();
|
|
||||||
case 0b11_011_0000_0000_111: return GetDczidEl0();
|
|
||||||
case 0b11_011_0100_0100_000: return (ulong)PackFPCR();
|
|
||||||
case 0b11_011_0100_0100_001: return (ulong)PackFPSR();
|
|
||||||
case 0b11_011_1101_0000_010: return (ulong)TlsAddrEl0;
|
|
||||||
case 0b11_011_1101_0000_011: return (ulong)TlsAddr;
|
|
||||||
case 0b11_011_1110_0000_001: return (ulong)Environment.TickCount * TicksPerMS;
|
|
||||||
|
|
||||||
default: throw new ArgumentException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetSystemReg(int Op0, int Op1, int CRn, int CRm, int Op2, ulong Value)
|
|
||||||
{
|
|
||||||
switch (PackRegId(Op0, Op1, CRn, CRm, Op2))
|
|
||||||
{
|
|
||||||
case 0b11_011_0100_0100_000: UnpackFPCR((int)Value); break;
|
|
||||||
case 0b11_011_0100_0100_001: UnpackFPSR((int)Value); break;
|
|
||||||
case 0b11_011_1101_0000_010: TlsAddrEl0 = (long)Value; break;
|
|
||||||
|
|
||||||
default: throw new ArgumentException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int PackRegId(int Op0, int Op1, int CRn, int CRm, int Op2)
|
|
||||||
{
|
|
||||||
int Id;
|
|
||||||
|
|
||||||
Id = Op2 << 0;
|
|
||||||
Id |= CRm << 3;
|
|
||||||
Id |= CRn << 7;
|
|
||||||
Id |= Op1 << 11;
|
|
||||||
Id |= Op0 << 14;
|
|
||||||
|
|
||||||
return Id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong GetCtrEl0()
|
|
||||||
{
|
|
||||||
return CoreType == ACoreType.CortexA53 ? A53CtrEl0 : A57CtrEl0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ulong GetDczidEl0()
|
|
||||||
{
|
|
||||||
return A53DczidEl0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int PackFPCR()
|
|
||||||
{
|
|
||||||
return FPCR; //TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
public int PackFPSR()
|
|
||||||
{
|
|
||||||
return FPSR; //TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnpackFPCR(int Value)
|
|
||||||
{
|
|
||||||
FPCR = Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnpackFPSR(int Value)
|
|
||||||
{
|
|
||||||
FPSR = Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void OnSvcCall(int Imm)
|
public void OnSvcCall(int Imm)
|
||||||
{
|
{
|
||||||
SvcCall?.Invoke(this, new SvcEventArgs(Imm));
|
SvcCall?.Invoke(this, new SvcEventArgs(Imm));
|
||||||
|
|
|
@ -467,11 +467,41 @@ namespace ChocolArm64.Translation
|
||||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EmitCall(Type MthdType, string MthdName)
|
public void EmitCallPropGet(Type ObjType, string PropName)
|
||||||
{
|
{
|
||||||
if (MthdType == null)
|
if (ObjType == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(MthdType));
|
throw new ArgumentNullException(nameof(ObjType));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PropName == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(PropName));
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitCall(ObjType.GetMethod($"get_{PropName}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EmitCallPropSet(Type ObjType, string PropName)
|
||||||
|
{
|
||||||
|
if (ObjType == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(ObjType));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PropName == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(PropName));
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitCall(ObjType.GetMethod($"set_{PropName}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EmitCall(Type ObjType, string MthdName)
|
||||||
|
{
|
||||||
|
if (ObjType == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(ObjType));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MthdName == null)
|
if (MthdName == null)
|
||||||
|
@ -479,7 +509,7 @@ namespace ChocolArm64.Translation
|
||||||
throw new ArgumentNullException(nameof(MthdName));
|
throw new ArgumentNullException(nameof(MthdName));
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitCall(MthdType.GetMethod(MthdName));
|
EmitCall(ObjType.GetMethod(MthdName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EmitCall(MethodInfo MthdInfo)
|
public void EmitCall(MethodInfo MthdInfo)
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Ryujinx.OsHle.Objects
|
||||||
{
|
{
|
||||||
Context.Memory.WriteInt32(Position + Offset, 5);
|
Context.Memory.WriteInt32(Position + Offset, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ namespace Ryujinx.OsHle
|
||||||
Thread.Registers.SvcCall += SvcHandler.SvcCall;
|
Thread.Registers.SvcCall += SvcHandler.SvcCall;
|
||||||
Thread.Registers.ProcessId = ProcessId;
|
Thread.Registers.ProcessId = ProcessId;
|
||||||
Thread.Registers.ThreadId = Ns.Os.IdGen.GenerateId();
|
Thread.Registers.ThreadId = Ns.Os.IdGen.GenerateId();
|
||||||
Thread.Registers.TlsAddr = TlsPageAddr + TlsSlot * TlsSize;
|
Thread.Registers.Tpidr = TlsPageAddr + TlsSlot * TlsSize;
|
||||||
Thread.Registers.X0 = (ulong)ArgsPtr;
|
Thread.Registers.X0 = (ulong)ArgsPtr;
|
||||||
Thread.Registers.X1 = (ulong)Handle;
|
Thread.Registers.X1 = (ulong)Handle;
|
||||||
Thread.Registers.X31 = (ulong)StackTop;
|
Thread.Registers.X31 = (ulong)StackTop;
|
||||||
|
@ -165,7 +165,7 @@ namespace Ryujinx.OsHle
|
||||||
{
|
{
|
||||||
if (sender is AThread Thread)
|
if (sender is AThread Thread)
|
||||||
{
|
{
|
||||||
TlsSlots.TryRemove(GetTlsSlot(Thread.Registers.TlsAddr), out _);
|
TlsSlots.TryRemove(GetTlsSlot(Thread.Registers.Tpidr), out _);
|
||||||
|
|
||||||
Ns.Os.IdGen.DeleteId(Thread.ThreadId);
|
Ns.Os.IdGen.DeleteId(Thread.ThreadId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace Ryujinx.OsHle.Svc
|
||||||
|
|
||||||
private static void SvcGetSystemTick(Switch Ns, ARegisters Registers, AMemory Memory)
|
private static void SvcGetSystemTick(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||||
{
|
{
|
||||||
Registers.X0 = (ulong)Registers.GetSystemReg(3, 3, 14, 0, 1);
|
Registers.X0 = (ulong)Registers.CntpctEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SvcConnectToNamedPort(Switch Ns, ARegisters Registers, AMemory Memory)
|
private static void SvcConnectToNamedPort(Switch Ns, ARegisters Registers, AMemory Memory)
|
||||||
|
@ -70,7 +70,7 @@ namespace Ryujinx.OsHle.Svc
|
||||||
|
|
||||||
private static void SendSyncRequest(Switch Ns, ARegisters Registers, AMemory Memory, bool IsUser)
|
private static void SendSyncRequest(Switch Ns, ARegisters Registers, AMemory Memory, bool IsUser)
|
||||||
{
|
{
|
||||||
long CmdPtr = Registers.TlsAddr;
|
long CmdPtr = Registers.Tpidr;
|
||||||
long Size = 0x100;
|
long Size = 0x100;
|
||||||
int Handle = 0;
|
int Handle = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue