mirror of
https://git.naxdy.org/Mirror/Ryujinx.git
synced 2024-11-15 09:35:27 +00:00
Added initial support for function names from symbol table on the cpu with tracing, fix wrong ImageEnd on executables with MOD0, fix issue on the CPU on input elimination for instruction with more than one register store
This commit is contained in:
parent
e174100474
commit
950011c90f
|
@ -28,14 +28,14 @@ namespace ChocolArm64
|
||||||
|
|
||||||
private object ExecuteLock;
|
private object ExecuteLock;
|
||||||
|
|
||||||
public AThread(AMemory Memory, ThreadPriority Priority, long EntryPoint)
|
public AThread(ATranslator Translator, AMemory Memory, ThreadPriority Priority, long EntryPoint)
|
||||||
{
|
{
|
||||||
|
this.Translator = Translator;
|
||||||
this.Memory = Memory;
|
this.Memory = Memory;
|
||||||
this.Priority = Priority;
|
this.Priority = Priority;
|
||||||
this.EntryPoint = EntryPoint;
|
this.EntryPoint = EntryPoint;
|
||||||
|
|
||||||
ThreadState = new AThreadState();
|
ThreadState = new AThreadState();
|
||||||
Translator = new ATranslator(this);
|
|
||||||
ExecuteLock = new object();
|
ExecuteLock = new object();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ namespace ChocolArm64
|
||||||
|
|
||||||
Work = new Thread(delegate()
|
Work = new Thread(delegate()
|
||||||
{
|
{
|
||||||
Translator.ExecuteSubroutine(EntryPoint);
|
Translator.ExecuteSubroutine(this, EntryPoint);
|
||||||
|
|
||||||
Memory.RemoveMonitor(ThreadId);
|
Memory.RemoveMonitor(ThreadId);
|
||||||
|
|
||||||
|
|
|
@ -1,47 +1,70 @@
|
||||||
using ChocolArm64.Decoder;
|
using ChocolArm64.Decoder;
|
||||||
|
using ChocolArm64.Events;
|
||||||
using ChocolArm64.Instruction;
|
using ChocolArm64.Instruction;
|
||||||
|
using ChocolArm64.Memory;
|
||||||
using ChocolArm64.Translation;
|
using ChocolArm64.Translation;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
|
|
||||||
namespace ChocolArm64
|
namespace ChocolArm64
|
||||||
{
|
{
|
||||||
class ATranslator
|
public class ATranslator
|
||||||
{
|
{
|
||||||
public AThread Thread { get; private set; }
|
private ConcurrentDictionary<long, ATranslatedSub> CachedSubs;
|
||||||
|
|
||||||
private Dictionary<long, ATranslatedSub> CachedSubs;
|
private ConcurrentDictionary<long, string> SymbolTable;
|
||||||
|
|
||||||
|
public event EventHandler<ACpuTraceEventArgs> CpuTrace;
|
||||||
|
|
||||||
|
public bool EnableCpuTrace { get; set; }
|
||||||
|
|
||||||
private bool KeepRunning;
|
private bool KeepRunning;
|
||||||
|
|
||||||
public ATranslator(AThread Parent)
|
public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
|
||||||
{
|
{
|
||||||
this.Thread = Parent;
|
CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
|
||||||
|
|
||||||
CachedSubs = new Dictionary<long, ATranslatedSub>();
|
if (SymbolTable != null)
|
||||||
|
{
|
||||||
|
this.SymbolTable = new ConcurrentDictionary<long, string>(SymbolTable);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.SymbolTable = new ConcurrentDictionary<long, string>();
|
||||||
|
}
|
||||||
|
|
||||||
KeepRunning = true;
|
KeepRunning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopExecution() => KeepRunning = false;
|
public void StopExecution() => KeepRunning = false;
|
||||||
|
|
||||||
public void ExecuteSubroutine(long Position)
|
public void ExecuteSubroutine(AThread Thread, long Position)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (CachedSubs.TryGetValue(Position, out ATranslatedSub Sub) && !Sub.NeedsReJit)
|
if (EnableCpuTrace)
|
||||||
{
|
{
|
||||||
Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
|
if (!SymbolTable.TryGetValue(Position, out string SubName))
|
||||||
|
{
|
||||||
|
SubName = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
CpuTrace?.Invoke(this, new ACpuTraceEventArgs(Position, SubName));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (!CachedSubs.TryGetValue(Position, out ATranslatedSub Sub) || Sub.NeedsReJit)
|
||||||
{
|
{
|
||||||
Position = TranslateSubroutine(Position).Execute(Thread.ThreadState, Thread.Memory);
|
Sub = TranslateSubroutine(Thread.Memory, Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
|
||||||
}
|
}
|
||||||
while (Position != 0 && KeepRunning);
|
while (Position != 0 && KeepRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
|
internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
|
||||||
{
|
{
|
||||||
if (OpCode.Emitter != AInstEmit.Bl)
|
if (OpCode.Emitter != AInstEmit.Bl)
|
||||||
{
|
{
|
||||||
|
@ -53,24 +76,29 @@ namespace ChocolArm64
|
||||||
return TryGetCachedSub(((AOpCodeBImmAl)OpCode).Imm, out Sub);
|
return TryGetCachedSub(((AOpCodeBImmAl)OpCode).Imm, out Sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetCachedSub(long Position, out ATranslatedSub Sub)
|
internal bool TryGetCachedSub(long Position, out ATranslatedSub Sub)
|
||||||
{
|
{
|
||||||
return CachedSubs.TryGetValue(Position, out Sub);
|
return CachedSubs.TryGetValue(Position, out Sub);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasCachedSub(long Position)
|
internal bool HasCachedSub(long Position)
|
||||||
{
|
{
|
||||||
return CachedSubs.ContainsKey(Position);
|
return CachedSubs.ContainsKey(Position);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ATranslatedSub TranslateSubroutine(long Position)
|
private ATranslatedSub TranslateSubroutine(AMemory Memory, long Position)
|
||||||
{
|
{
|
||||||
(ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Position);
|
(ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Memory, Position);
|
||||||
|
|
||||||
|
string SubName = SymbolTable.GetOrAdd(Position, $"Sub{Position:x16}");
|
||||||
|
|
||||||
|
PropagateName(Cfg.Graph, SubName);
|
||||||
|
|
||||||
AILEmitterCtx Context = new AILEmitterCtx(
|
AILEmitterCtx Context = new AILEmitterCtx(
|
||||||
this,
|
this,
|
||||||
Cfg.Graph,
|
Cfg.Graph,
|
||||||
Cfg.Root);
|
Cfg.Root,
|
||||||
|
SubName);
|
||||||
|
|
||||||
if (Context.CurrBlock.Position != Position)
|
if (Context.CurrBlock.Position != Position)
|
||||||
{
|
{
|
||||||
|
@ -95,12 +123,24 @@ namespace ChocolArm64
|
||||||
|
|
||||||
ATranslatedSub Subroutine = Context.GetSubroutine();
|
ATranslatedSub Subroutine = Context.GetSubroutine();
|
||||||
|
|
||||||
if (!CachedSubs.TryAdd(Position, Subroutine))
|
CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine);
|
||||||
{
|
|
||||||
CachedSubs[Position] = Subroutine;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Subroutine;
|
return Subroutine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PropagateName(ABlock[] Graph, string Name)
|
||||||
|
{
|
||||||
|
foreach (ABlock Block in Graph)
|
||||||
|
{
|
||||||
|
AOpCode LastOp = Block.GetLastOp();
|
||||||
|
|
||||||
|
if (LastOp != null &&
|
||||||
|
(LastOp.Emitter == AInstEmit.Bl ||
|
||||||
|
LastOp.Emitter == AInstEmit.Blr))
|
||||||
|
{
|
||||||
|
SymbolTable.TryAdd(LastOp.Position + 4, Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,7 +18,10 @@ namespace ChocolArm64.Decoder
|
||||||
OpActivators = new ConcurrentDictionary<Type, OpActivator>();
|
OpActivators = new ConcurrentDictionary<Type, OpActivator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(ATranslator Translator, long Start)
|
public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(
|
||||||
|
ATranslator Translator,
|
||||||
|
AMemory Memory,
|
||||||
|
long Start)
|
||||||
{
|
{
|
||||||
Dictionary<long, ABlock> Visited = new Dictionary<long, ABlock>();
|
Dictionary<long, ABlock> Visited = new Dictionary<long, ABlock>();
|
||||||
Dictionary<long, ABlock> VisitedEnd = new Dictionary<long, ABlock>();
|
Dictionary<long, ABlock> VisitedEnd = new Dictionary<long, ABlock>();
|
||||||
|
@ -45,7 +48,7 @@ namespace ChocolArm64.Decoder
|
||||||
{
|
{
|
||||||
ABlock Current = Blocks.Dequeue();
|
ABlock Current = Blocks.Dequeue();
|
||||||
|
|
||||||
FillBlock(Translator.Thread.Memory, Current);
|
FillBlock(Memory, Current);
|
||||||
|
|
||||||
//Set child blocks. "Branch" is the block the branch instruction
|
//Set child blocks. "Branch" is the block the branch instruction
|
||||||
//points to (when taken), "Next" is the block at the next address,
|
//points to (when taken), "Next" is the block at the next address,
|
||||||
|
|
17
ChocolArm64/Events/ACpuTraceEventArgs.cs
Normal file
17
ChocolArm64/Events/ACpuTraceEventArgs.cs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Events
|
||||||
|
{
|
||||||
|
public class ACpuTraceEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public long Position { get; private set; }
|
||||||
|
|
||||||
|
public string SubName { get; private set; }
|
||||||
|
|
||||||
|
public ACpuTraceEventArgs(long Position, string SubName)
|
||||||
|
{
|
||||||
|
this.Position = Position;
|
||||||
|
this.SubName = SubName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
ChocolArm64/Events/AInstExceptionEventArgs.cs
Normal file
14
ChocolArm64/Events/AInstExceptionEventArgs.cs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ChocolArm64.Events
|
||||||
|
{
|
||||||
|
public class AInstExceptionEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public int Id { get; private set; }
|
||||||
|
|
||||||
|
public AInstExceptionEventArgs(int Id)
|
||||||
|
{
|
||||||
|
this.Id = Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,13 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace ChocolArm64.State
|
namespace ChocolArm64.Events
|
||||||
{
|
{
|
||||||
public class AInstUndEventArgs : EventArgs
|
public class AInstUndefinedEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public long Position { get; private set; }
|
public long Position { get; private set; }
|
||||||
public int RawOpCode { get; private set; }
|
public int RawOpCode { get; private set; }
|
||||||
|
|
||||||
public AInstUndEventArgs(long Position, int RawOpCode)
|
public AInstUndefinedEventArgs(long Position, int RawOpCode)
|
||||||
{
|
{
|
||||||
this.Position = Position;
|
this.Position = Position;
|
||||||
this.RawOpCode = RawOpCode;
|
this.RawOpCode = RawOpCode;
|
|
@ -44,16 +44,15 @@ namespace ChocolArm64.Instruction
|
||||||
Context.Emit(OpCodes.Neg);
|
Context.Emit(OpCodes.Neg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.EmitStintzr(Op.Rd);
|
|
||||||
|
|
||||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||||
|
|
||||||
Context.MarkLabel(LblTrue);
|
Context.MarkLabel(LblTrue);
|
||||||
|
|
||||||
Context.EmitLdintzr(Op.Rn);
|
Context.EmitLdintzr(Op.Rn);
|
||||||
Context.EmitStintzr(Op.Rd);
|
|
||||||
|
|
||||||
Context.MarkLabel(LblEnd);
|
Context.MarkLabel(LblEnd);
|
||||||
|
|
||||||
|
Context.EmitStintzr(Op.Rd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,14 +0,0 @@
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace ChocolArm64.State
|
|
||||||
{
|
|
||||||
public class AInstExceptEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public int Id { get; private set; }
|
|
||||||
|
|
||||||
public AInstExceptEventArgs(int Id)
|
|
||||||
{
|
|
||||||
this.Id = Id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using ChocolArm64.Events;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace ChocolArm64.State
|
namespace ChocolArm64.State
|
||||||
|
@ -42,23 +43,23 @@ namespace ChocolArm64.State
|
||||||
|
|
||||||
public long CntpctEl0 => Environment.TickCount * TicksPerMS;
|
public long CntpctEl0 => Environment.TickCount * TicksPerMS;
|
||||||
|
|
||||||
public event EventHandler<AInstExceptEventArgs> Break;
|
public event EventHandler<AInstExceptionEventArgs> Break;
|
||||||
public event EventHandler<AInstExceptEventArgs> SvcCall;
|
public event EventHandler<AInstExceptionEventArgs> SvcCall;
|
||||||
public event EventHandler<AInstUndEventArgs> Undefined;
|
public event EventHandler<AInstUndefinedEventArgs> Undefined;
|
||||||
|
|
||||||
internal void OnBreak(int Imm)
|
internal void OnBreak(int Imm)
|
||||||
{
|
{
|
||||||
Break?.Invoke(this, new AInstExceptEventArgs(Imm));
|
Break?.Invoke(this, new AInstExceptionEventArgs(Imm));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnSvcCall(int Imm)
|
internal void OnSvcCall(int Imm)
|
||||||
{
|
{
|
||||||
SvcCall?.Invoke(this, new AInstExceptEventArgs(Imm));
|
SvcCall?.Invoke(this, new AInstExceptionEventArgs(Imm));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnUndefined(long Position, int RawOpCode)
|
internal void OnUndefined(long Position, int RawOpCode)
|
||||||
{
|
{
|
||||||
Undefined?.Invoke(this, new AInstUndEventArgs(Position, RawOpCode));
|
Undefined?.Invoke(this, new AInstUndefinedEventArgs(Position, RawOpCode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
7
ChocolArm64/Translation/AILBarrier.cs
Normal file
7
ChocolArm64/Translation/AILBarrier.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace ChocolArm64.Translation
|
||||||
|
{
|
||||||
|
struct AILBarrier : IAILEmit
|
||||||
|
{
|
||||||
|
public void Emit(AILEmitter Context) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,11 +4,13 @@ namespace ChocolArm64.Translation
|
||||||
{
|
{
|
||||||
class AILBlock : IAILEmit
|
class AILBlock : IAILEmit
|
||||||
{
|
{
|
||||||
public long IntInputs { get; private set; }
|
public long IntInputs { get; private set; }
|
||||||
public long IntOutputs { get; private set; }
|
public long IntOutputs { get; private set; }
|
||||||
|
public long IntAwOutputs { get; private set; }
|
||||||
|
|
||||||
public long VecInputs { get; private set; }
|
public long VecInputs { get; private set; }
|
||||||
public long VecOutputs { get; private set; }
|
public long VecOutputs { get; private set; }
|
||||||
|
public long VecAwOutputs { get; private set; }
|
||||||
|
|
||||||
public bool HasStateStore { get; private set; }
|
public bool HasStateStore { get; private set; }
|
||||||
|
|
||||||
|
@ -24,13 +26,22 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public void Add(IAILEmit ILEmitter)
|
public void Add(IAILEmit ILEmitter)
|
||||||
{
|
{
|
||||||
if (ILEmitter is AILOpCodeLoad Ld && AILEmitter.IsRegIndex(Ld.Index))
|
if (ILEmitter is AILBarrier)
|
||||||
|
{
|
||||||
|
//Those barriers are used to separate the groups of CIL
|
||||||
|
//opcodes emitted by each ARM instruction.
|
||||||
|
//We can only consider the new outputs for doing input elimination
|
||||||
|
//after all the CIL opcodes used by the instruction being emitted.
|
||||||
|
IntAwOutputs = IntOutputs;
|
||||||
|
VecAwOutputs = VecOutputs;
|
||||||
|
}
|
||||||
|
else if (ILEmitter is AILOpCodeLoad Ld && AILEmitter.IsRegIndex(Ld.Index))
|
||||||
{
|
{
|
||||||
switch (Ld.IoType)
|
switch (Ld.IoType)
|
||||||
{
|
{
|
||||||
case AIoType.Flag: IntInputs |= ((1L << Ld.Index) << 32) & ~IntOutputs; break;
|
case AIoType.Flag: IntInputs |= ((1L << Ld.Index) << 32) & ~IntAwOutputs; break;
|
||||||
case AIoType.Int: IntInputs |= (1L << Ld.Index) & ~IntOutputs; break;
|
case AIoType.Int: IntInputs |= (1L << Ld.Index) & ~IntAwOutputs; break;
|
||||||
case AIoType.Vector: VecInputs |= (1L << Ld.Index) & ~VecOutputs; break;
|
case AIoType.Vector: VecInputs |= (1L << Ld.Index) & ~VecAwOutputs; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (ILEmitter is AILOpCodeStore St)
|
else if (ILEmitter is AILOpCodeStore St)
|
||||||
|
|
|
@ -39,14 +39,16 @@ namespace ChocolArm64.Translation
|
||||||
private const int Tmp4Index = -4;
|
private const int Tmp4Index = -4;
|
||||||
private const int Tmp5Index = -5;
|
private const int Tmp5Index = -5;
|
||||||
|
|
||||||
public AILEmitterCtx(ATranslator Translator, ABlock[] Graph, ABlock Root)
|
public AILEmitterCtx(
|
||||||
|
ATranslator Translator,
|
||||||
|
ABlock[] Graph,
|
||||||
|
ABlock Root,
|
||||||
|
string SubName)
|
||||||
{
|
{
|
||||||
this.Translator = Translator;
|
this.Translator = Translator;
|
||||||
this.Graph = Graph;
|
this.Graph = Graph;
|
||||||
this.Root = Root;
|
this.Root = Root;
|
||||||
|
|
||||||
string SubName = $"Sub{Root.Position:X16}";
|
|
||||||
|
|
||||||
Labels = new Dictionary<long, AILLabel>();
|
Labels = new Dictionary<long, AILLabel>();
|
||||||
|
|
||||||
Emitter = new AILEmitter(Graph, Root, SubName);
|
Emitter = new AILEmitter(Graph, Root, SubName);
|
||||||
|
@ -92,6 +94,8 @@ namespace ChocolArm64.Translation
|
||||||
}
|
}
|
||||||
|
|
||||||
CurrOp.Emitter(this);
|
CurrOp.Emitter(this);
|
||||||
|
|
||||||
|
ILBlock.Add(new AILBarrier());
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryOptEmitSubroutineCall()
|
public bool TryOptEmitSubroutineCall()
|
||||||
|
|
|
@ -11,12 +11,10 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public ARegisterSize RegisterSize { get; private set; }
|
public ARegisterSize RegisterSize { get; private set; }
|
||||||
|
|
||||||
public AILOpCodeLoad(int Index, AIoType IoType) : this(Index, IoType, ARegisterSize.Int64) { }
|
public AILOpCodeLoad(int Index, AIoType IoType, ARegisterSize RegisterSize = 0)
|
||||||
|
|
||||||
public AILOpCodeLoad(int Index, AIoType IoType, ARegisterSize RegisterSize)
|
|
||||||
{
|
{
|
||||||
this.IoType = IoType;
|
|
||||||
this.Index = Index;
|
this.Index = Index;
|
||||||
|
this.IoType = IoType;
|
||||||
this.RegisterSize = RegisterSize;
|
this.RegisterSize = RegisterSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,10 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
public ARegisterSize RegisterSize { get; private set; }
|
public ARegisterSize RegisterSize { get; private set; }
|
||||||
|
|
||||||
public AILOpCodeStore(int Index, AIoType IoType, ARegisterSize RegisterSize = ARegisterSize.Int64)
|
public AILOpCodeStore(int Index, AIoType IoType, ARegisterSize RegisterSize = 0)
|
||||||
{
|
{
|
||||||
this.IoType = IoType;
|
|
||||||
this.Index = Index;
|
this.Index = Index;
|
||||||
|
this.IoType = IoType;
|
||||||
this.RegisterSize = RegisterSize;
|
this.RegisterSize = RegisterSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ namespace ChocolArm64.Translation
|
||||||
public long VecOutputs;
|
public long VecOutputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private const int MaxOptGraphLength = 120;
|
private const int MaxOptGraphLength = 55;
|
||||||
|
|
||||||
public ALocalAlloc(AILBlock[] Graph, AILBlock Root)
|
public ALocalAlloc(AILBlock[] Graph, AILBlock Root)
|
||||||
{
|
{
|
||||||
|
@ -149,11 +149,7 @@ namespace ChocolArm64.Translation
|
||||||
|
|
||||||
if (RetTarget)
|
if (RetTarget)
|
||||||
{
|
{
|
||||||
BlkIO.Entry = Block;
|
BlkIO.Entry = Block;
|
||||||
BlkIO.IntInputs = 0;
|
|
||||||
BlkIO.VecInputs = 0;
|
|
||||||
BlkIO.IntOutputs = 0;
|
|
||||||
BlkIO.VecOutputs = 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,17 +16,15 @@ namespace Ryujinx.Core.Loaders
|
||||||
Binding == ElfSymBinding.STB_GLOBAL ||
|
Binding == ElfSymBinding.STB_GLOBAL ||
|
||||||
Binding == ElfSymBinding.STB_WEAK;
|
Binding == ElfSymBinding.STB_WEAK;
|
||||||
|
|
||||||
public int SHIdx { get; private set; }
|
public int SHIdx { get; private set; }
|
||||||
public long ValueAbs { get; private set; }
|
public long Value { get; private set; }
|
||||||
public long Value { get; private set; }
|
public long Size { get; private set; }
|
||||||
public long Size { get; private set; }
|
|
||||||
|
|
||||||
public ElfSym(
|
public ElfSym(
|
||||||
string Name,
|
string Name,
|
||||||
int Info,
|
int Info,
|
||||||
int Other,
|
int Other,
|
||||||
int SHIdx,
|
int SHIdx,
|
||||||
long ImageBase,
|
|
||||||
long Value,
|
long Value,
|
||||||
long Size)
|
long Size)
|
||||||
{
|
{
|
||||||
|
@ -35,7 +33,6 @@ namespace Ryujinx.Core.Loaders
|
||||||
this.Binding = (ElfSymBinding)(Info >> 4);
|
this.Binding = (ElfSymBinding)(Info >> 4);
|
||||||
this.Visibility = (ElfSymVisibility)Other;
|
this.Visibility = (ElfSymVisibility)Other;
|
||||||
this.SHIdx = SHIdx;
|
this.SHIdx = SHIdx;
|
||||||
this.ValueAbs = Value + ImageBase;
|
|
||||||
this.Value = Value;
|
this.Value = Value;
|
||||||
this.Size = Size;
|
this.Size = Size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,21 @@ namespace Ryujinx.Core.Loaders
|
||||||
{
|
{
|
||||||
private AMemory Memory;
|
private AMemory Memory;
|
||||||
|
|
||||||
private ElfDyn[] Dynamic;
|
private List<ElfDyn> Dynamic;
|
||||||
|
|
||||||
|
private Dictionary<long, string> m_SymbolTable;
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<long, string> SymbolTable => m_SymbolTable;
|
||||||
|
|
||||||
public long ImageBase { get; private set; }
|
public long ImageBase { get; private set; }
|
||||||
public long ImageEnd { get; private set; }
|
public long ImageEnd { get; private set; }
|
||||||
|
|
||||||
public Executable(IExecutable Exe, AMemory Memory, long ImageBase)
|
public Executable(IExecutable Exe, AMemory Memory, long ImageBase)
|
||||||
{
|
{
|
||||||
|
Dynamic = new List<ElfDyn>();
|
||||||
|
|
||||||
|
m_SymbolTable = new Dictionary<long, string>();
|
||||||
|
|
||||||
this.Memory = Memory;
|
this.Memory = Memory;
|
||||||
this.ImageBase = ImageBase;
|
this.ImageBase = ImageBase;
|
||||||
this.ImageEnd = ImageBase;
|
this.ImageEnd = ImageBase;
|
||||||
|
@ -48,9 +56,7 @@ namespace Ryujinx.Core.Loaders
|
||||||
|
|
||||||
MapBss(BssStartOffset, BssEndOffset - BssStartOffset);
|
MapBss(BssStartOffset, BssEndOffset - BssStartOffset);
|
||||||
|
|
||||||
ImageEnd = BssEndOffset;
|
ImageEnd = ImageBase + BssEndOffset;
|
||||||
|
|
||||||
List<ElfDyn> Dynamic = new List<ElfDyn>();
|
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -69,7 +75,19 @@ namespace Ryujinx.Core.Loaders
|
||||||
Dynamic.Add(new ElfDyn(Tag, Value));
|
Dynamic.Add(new ElfDyn(Tag, Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Dynamic = Dynamic.ToArray();
|
long StrTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_STRTAB);
|
||||||
|
long SymTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_SYMTAB);
|
||||||
|
|
||||||
|
long SymEntSize = GetFirstValue(ElfDynTag.DT_SYMENT);
|
||||||
|
|
||||||
|
while ((ulong)SymTblAddr < (ulong)StrTblAddr)
|
||||||
|
{
|
||||||
|
ElfSym Sym = GetSymbol(SymTblAddr, StrTblAddr);
|
||||||
|
|
||||||
|
m_SymbolTable.TryAdd(Sym.Value, Sym.Name);
|
||||||
|
|
||||||
|
SymTblAddr += SymEntSize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteData(
|
private void WriteData(
|
||||||
|
@ -135,7 +153,7 @@ namespace Ryujinx.Core.Loaders
|
||||||
Name += (char)Chr;
|
Name += (char)Chr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ElfSym(Name, Info, Other, SHIdx, ImageBase, Value, Size);
|
return new ElfSym(Name, Info, Other, SHIdx, Value, Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long GetFirstValue(ElfDynTag Tag)
|
private long GetFirstValue(ElfDynTag Tag)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
using ChocolArm64;
|
using ChocolArm64;
|
||||||
|
using ChocolArm64.Events;
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using ChocolArm64.State;
|
|
||||||
using Ryujinx.Core.Loaders;
|
using Ryujinx.Core.Loaders;
|
||||||
using Ryujinx.Core.Loaders.Executables;
|
using Ryujinx.Core.Loaders.Executables;
|
||||||
using Ryujinx.Core.OsHle.Exceptions;
|
using Ryujinx.Core.OsHle.Exceptions;
|
||||||
|
@ -24,6 +24,8 @@ namespace Ryujinx.Core.OsHle
|
||||||
|
|
||||||
private Switch Ns;
|
private Switch Ns;
|
||||||
|
|
||||||
|
private ATranslator Translator;
|
||||||
|
|
||||||
public int ProcessId { get; private set; }
|
public int ProcessId { get; private set; }
|
||||||
|
|
||||||
public AMemory Memory { get; private set; }
|
public AMemory Memory { get; private set; }
|
||||||
|
@ -171,7 +173,7 @@ namespace Ryujinx.Core.OsHle
|
||||||
ThreadPrio = ThreadPriority.Lowest;
|
ThreadPrio = ThreadPriority.Lowest;
|
||||||
}
|
}
|
||||||
|
|
||||||
AThread Thread = new AThread(Memory, ThreadPrio, EntryPoint);
|
AThread Thread = new AThread(GetTranslator(), Memory, ThreadPrio, EntryPoint);
|
||||||
|
|
||||||
HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority);
|
HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority);
|
||||||
|
|
||||||
|
@ -201,16 +203,45 @@ namespace Ryujinx.Core.OsHle
|
||||||
return Handle;
|
return Handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BreakHandler(object sender, AInstExceptEventArgs e)
|
private void BreakHandler(object sender, AInstExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
throw new GuestBrokeExecutionException();
|
throw new GuestBrokeExecutionException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UndefinedHandler(object sender, AInstUndEventArgs e)
|
private void UndefinedHandler(object sender, AInstUndefinedEventArgs e)
|
||||||
{
|
{
|
||||||
throw new UndefinedInstructionException(e.Position, e.RawOpCode);
|
throw new UndefinedInstructionException(e.Position, e.RawOpCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ATranslator GetTranslator()
|
||||||
|
{
|
||||||
|
if (Translator == null)
|
||||||
|
{
|
||||||
|
Dictionary<long, string> SymbolTable = new Dictionary<long, string>();
|
||||||
|
|
||||||
|
foreach (Executable Exe in Executables)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<long, string> KV in Exe.SymbolTable)
|
||||||
|
{
|
||||||
|
SymbolTable.Add(Exe.ImageBase + KV.Key, KV.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Translator = new ATranslator(SymbolTable);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Translator.CpuTrace += CpuTraceHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Translator;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CpuTraceHandler(object sender, ACpuTraceEventArgs e)
|
||||||
|
{
|
||||||
|
Logging.Info($"Executing at 0x{e.Position:x16} {e.SubName}");
|
||||||
|
}
|
||||||
|
|
||||||
private int GetFreeTlsSlot(AThread Thread)
|
private int GetFreeTlsSlot(AThread Thread)
|
||||||
{
|
{
|
||||||
for (int Index = 1; Index < TotalTlsSlots; Index++)
|
for (int Index = 1; Index < TotalTlsSlots; Index++)
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using ChocolArm64.Events;
|
||||||
using ChocolArm64.Memory;
|
using ChocolArm64.Memory;
|
||||||
using ChocolArm64.State;
|
using ChocolArm64.State;
|
||||||
using System;
|
using System;
|
||||||
|
@ -62,7 +63,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
||||||
Rng = new Random();
|
Rng = new Random();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SvcCall(object sender, AInstExceptEventArgs e)
|
public void SvcCall(object sender, AInstExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
AThreadState ThreadState = (AThreadState)sender;
|
AThreadState ThreadState = (AThreadState)sender;
|
||||||
|
|
||||||
|
|
|
@ -30,10 +30,11 @@ namespace Ryujinx.Tests.Cpu
|
||||||
EntryPoint = Position;
|
EntryPoint = Position;
|
||||||
|
|
||||||
Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize);
|
Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize);
|
||||||
|
ATranslator Translator = new ATranslator();
|
||||||
Allocator = new AMemoryAlloc();
|
Allocator = new AMemoryAlloc();
|
||||||
Memory = new AMemory(Ram, Allocator);
|
Memory = new AMemory(Ram, Allocator);
|
||||||
Memory.Manager.MapPhys(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute);
|
Memory.Manager.MapPhys(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute);
|
||||||
Thread = new AThread(Memory, ThreadPriority.Normal, EntryPoint);
|
Thread = new AThread(Translator, Memory, ThreadPriority.Normal, EntryPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TearDown]
|
[TearDown]
|
||||||
|
|
Loading…
Reference in a new issue