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);
}
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)
{
EmitDataLoadRn(Context);

View file

@ -1,6 +1,8 @@
using ChocolArm64.Decoder;
using ChocolArm64.State;
using ChocolArm64.Translation;
using System;
using System.Reflection;
using System.Reflection.Emit;
namespace ChocolArm64.Instruction
@ -13,13 +15,30 @@ namespace ChocolArm64.Instruction
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);
string PropName;
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);
}
@ -29,15 +48,28 @@ namespace ChocolArm64.Instruction
AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
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.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)
@ -52,19 +84,12 @@ namespace ChocolArm64.Instruction
//We treat it as no-op here since we don't have any cache being emulated anyway.
AOpCodeSystem Op = (AOpCodeSystem)Context.CurrOp;
int Id;
Id = Op.Op2 << 0;
Id |= Op.CRm << 3;
Id |= Op.CRn << 7;
Id |= Op.Op1 << 11;
switch (Id)
switch (GetPackedId(Op))
{
case 0b011_0111_0100_001:
case 0b11_011_0111_0100_001:
{
//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.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
{
private const long ErgMask = (4 << ARegisters.ErgSizeLog2) - 1;
public AMemoryMgr Manager { get; private set; }
private struct ExMonitor
@ -52,6 +54,11 @@ namespace ChocolArm64.Memory
{
lock (Monitors)
{
if (Monitors.TryGetValue(ThreadId, out ExMonitor Monitor))
{
ExAddrs.Remove(Monitor.Position);
}
Monitors.Remove(ThreadId);
}
}
@ -60,14 +67,16 @@ namespace ChocolArm64.Memory
{
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))
{
@ -80,6 +89,8 @@ namespace ChocolArm64.Memory
{
lock (Monitors)
{
Position &= ~ErgMask;
if (!Monitors.TryGetValue(Registers.ThreadId, out ExMonitor Monitor))
{
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 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,
X8, X9, X10, X11, X12, X13, X14, X15,
X16, X17, X18, X19, X20, X21, X22, X23,
@ -22,97 +28,23 @@ namespace ChocolArm64.State
public bool Zero;
public bool Negative;
public int ProcessId;
public int ThreadId;
public long TlsAddrEl0;
public long TlsAddr;
public int ProcessId;
public int ThreadId;
private int FPCR;
private int FPSR;
public long TpidrEl0 { get; set; }
public long Tpidr { get; set; }
public ACoreType CoreType;
public int Fpcr { get; set; }
public int Fpsr { get; set; }
private const ulong A53DczidEl0 = 4;
private const ulong A53CtrEl0 = 0x84448004;
private const ulong A57CtrEl0 = 0x8444c004;
public uint CtrEl0 => 0x8444c004;
public uint DczidEl0 => 0x00000004;
private const ulong TicksPerS = 19_200_000;
private const ulong TicksPerMS = TicksPerS / 1_000;
public long CntpctEl0 => Environment.TickCount * TicksPerMS;
public event EventHandler<SvcEventArgs> SvcCall;
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)
{
SvcCall?.Invoke(this, new SvcEventArgs(Imm));

View file

@ -467,11 +467,41 @@ namespace ChocolArm64.Translation
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)
@ -479,7 +509,7 @@ namespace ChocolArm64.Translation
throw new ArgumentNullException(nameof(MthdName));
}
EmitCall(MthdType.GetMethod(MthdName));
EmitCall(ObjType.GetMethod(MthdName));
}
public void EmitCall(MethodInfo MthdInfo)

View file

@ -138,7 +138,7 @@ namespace Ryujinx.OsHle
Thread.Registers.SvcCall += SvcHandler.SvcCall;
Thread.Registers.ProcessId = ProcessId;
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.X1 = (ulong)Handle;
Thread.Registers.X31 = (ulong)StackTop;
@ -165,7 +165,7 @@ namespace Ryujinx.OsHle
{
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);
}

View file

@ -39,7 +39,7 @@ namespace Ryujinx.OsHle.Svc
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)
@ -70,7 +70,7 @@ namespace Ryujinx.OsHle.Svc
private static void SendSyncRequest(Switch Ns, ARegisters Registers, AMemory Memory, bool IsUser)
{
long CmdPtr = Registers.TlsAddr;
long CmdPtr = Registers.Tpidr;
long Size = 0x100;
int Handle = 0;