mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-11-23 11:32:02 +00: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);
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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 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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Ryujinx.OsHle.Objects
|
|||
{
|
||||
Context.Memory.WriteInt32(Position + Offset, 5);
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue