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:
gdkchan 2018-02-06 12:15:08 -03:00
parent 6ae5587b5e
commit 2347c44bbf
9 changed files with 130 additions and 138 deletions

View File

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

View File

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

View File

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

View File

@ -1,8 +0,0 @@
namespace ChocolArm64.State
{
public enum ACoreType
{
CortexA53,
CortexA57
}
}

View File

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

View File

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

View File

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

View File

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