diff --git a/ChocolArm64/AThread.cs b/ChocolArm64/AThread.cs index 5c03228943..6e018db684 100644 --- a/ChocolArm64/AThread.cs +++ b/ChocolArm64/AThread.cs @@ -28,14 +28,14 @@ namespace ChocolArm64 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.Priority = Priority; this.EntryPoint = EntryPoint; ThreadState = new AThreadState(); - Translator = new ATranslator(this); ExecuteLock = new object(); } @@ -55,7 +55,7 @@ namespace ChocolArm64 Work = new Thread(delegate() { - Translator.ExecuteSubroutine(EntryPoint); + Translator.ExecuteSubroutine(this, EntryPoint); Memory.RemoveMonitor(ThreadId); diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs index 96bbc89ead..2daf7bbc96 100644 --- a/ChocolArm64/ATranslator.cs +++ b/ChocolArm64/ATranslator.cs @@ -1,47 +1,70 @@ using ChocolArm64.Decoder; +using ChocolArm64.Events; using ChocolArm64.Instruction; +using ChocolArm64.Memory; using ChocolArm64.Translation; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection.Emit; namespace ChocolArm64 { - class ATranslator + public class ATranslator { - public AThread Thread { get; private set; } + private ConcurrentDictionary CachedSubs; - private Dictionary CachedSubs; + private ConcurrentDictionary SymbolTable; + + public event EventHandler CpuTrace; + + public bool EnableCpuTrace { get; set; } private bool KeepRunning; - public ATranslator(AThread Parent) + public ATranslator(IReadOnlyDictionary SymbolTable = null) { - this.Thread = Parent; + CachedSubs = new ConcurrentDictionary(); - CachedSubs = new Dictionary(); + if (SymbolTable != null) + { + this.SymbolTable = new ConcurrentDictionary(SymbolTable); + } + else + { + this.SymbolTable = new ConcurrentDictionary(); + } KeepRunning = true; } public void StopExecution() => KeepRunning = false; - public void ExecuteSubroutine(long Position) + public void ExecuteSubroutine(AThread Thread, long Position) { 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); } - public bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub) + internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub) { if (OpCode.Emitter != AInstEmit.Bl) { @@ -53,24 +76,29 @@ namespace ChocolArm64 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); } - public bool HasCachedSub(long Position) + internal bool HasCachedSub(long 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( this, Cfg.Graph, - Cfg.Root); + Cfg.Root, + SubName); if (Context.CurrBlock.Position != Position) { @@ -95,12 +123,24 @@ namespace ChocolArm64 ATranslatedSub Subroutine = Context.GetSubroutine(); - if (!CachedSubs.TryAdd(Position, Subroutine)) - { - CachedSubs[Position] = Subroutine; - } + CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => 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); + } + } + } } } \ No newline at end of file diff --git a/ChocolArm64/Decoder/ADecoder.cs b/ChocolArm64/Decoder/ADecoder.cs index a3f44e4707..4430229034 100644 --- a/ChocolArm64/Decoder/ADecoder.cs +++ b/ChocolArm64/Decoder/ADecoder.cs @@ -18,7 +18,10 @@ namespace ChocolArm64.Decoder OpActivators = new ConcurrentDictionary(); } - 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 Visited = new Dictionary(); Dictionary VisitedEnd = new Dictionary(); @@ -45,7 +48,7 @@ namespace ChocolArm64.Decoder { ABlock Current = Blocks.Dequeue(); - FillBlock(Translator.Thread.Memory, Current); + FillBlock(Memory, Current); //Set child blocks. "Branch" is the block the branch instruction //points to (when taken), "Next" is the block at the next address, diff --git a/ChocolArm64/Events/ACpuTraceEventArgs.cs b/ChocolArm64/Events/ACpuTraceEventArgs.cs new file mode 100644 index 0000000000..fedf3865b1 --- /dev/null +++ b/ChocolArm64/Events/ACpuTraceEventArgs.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Events/AInstExceptionEventArgs.cs b/ChocolArm64/Events/AInstExceptionEventArgs.cs new file mode 100644 index 0000000000..34f90c8eec --- /dev/null +++ b/ChocolArm64/Events/AInstExceptionEventArgs.cs @@ -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; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/State/AInstUndEventArgs.cs b/ChocolArm64/Events/AInstUndefinedEventArgs.cs similarity index 60% rename from ChocolArm64/State/AInstUndEventArgs.cs rename to ChocolArm64/Events/AInstUndefinedEventArgs.cs index 53de65a33d..cdc1728bd8 100644 --- a/ChocolArm64/State/AInstUndEventArgs.cs +++ b/ChocolArm64/Events/AInstUndefinedEventArgs.cs @@ -1,13 +1,13 @@ using System; -namespace ChocolArm64.State +namespace ChocolArm64.Events { - public class AInstUndEventArgs : EventArgs + public class AInstUndefinedEventArgs : EventArgs { public long Position { 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.RawOpCode = RawOpCode; diff --git a/ChocolArm64/Instruction/AInstEmitCsel.cs b/ChocolArm64/Instruction/AInstEmitCsel.cs index 330809806a..218767524e 100644 --- a/ChocolArm64/Instruction/AInstEmitCsel.cs +++ b/ChocolArm64/Instruction/AInstEmitCsel.cs @@ -44,16 +44,15 @@ namespace ChocolArm64.Instruction Context.Emit(OpCodes.Neg); } - Context.EmitStintzr(Op.Rd); - Context.Emit(OpCodes.Br_S, LblEnd); Context.MarkLabel(LblTrue); Context.EmitLdintzr(Op.Rn); - Context.EmitStintzr(Op.Rd); Context.MarkLabel(LblEnd); + + Context.EmitStintzr(Op.Rd); } } } \ No newline at end of file diff --git a/ChocolArm64/State/AInstExceptEventArgs.cs b/ChocolArm64/State/AInstExceptEventArgs.cs deleted file mode 100644 index f2ee039b6b..0000000000 --- a/ChocolArm64/State/AInstExceptEventArgs.cs +++ /dev/null @@ -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; - } - } -} \ No newline at end of file diff --git a/ChocolArm64/State/AThreadState.cs b/ChocolArm64/State/AThreadState.cs index cdab4034ec..2d988a6536 100644 --- a/ChocolArm64/State/AThreadState.cs +++ b/ChocolArm64/State/AThreadState.cs @@ -1,3 +1,4 @@ +using ChocolArm64.Events; using System; namespace ChocolArm64.State @@ -42,23 +43,23 @@ namespace ChocolArm64.State public long CntpctEl0 => Environment.TickCount * TicksPerMS; - public event EventHandler Break; - public event EventHandler SvcCall; - public event EventHandler Undefined; + public event EventHandler Break; + public event EventHandler SvcCall; + public event EventHandler Undefined; internal void OnBreak(int Imm) { - Break?.Invoke(this, new AInstExceptEventArgs(Imm)); + Break?.Invoke(this, new AInstExceptionEventArgs(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) { - Undefined?.Invoke(this, new AInstUndEventArgs(Position, RawOpCode)); + Undefined?.Invoke(this, new AInstUndefinedEventArgs(Position, RawOpCode)); } } } \ No newline at end of file diff --git a/ChocolArm64/Translation/AILBarrier.cs b/ChocolArm64/Translation/AILBarrier.cs new file mode 100644 index 0000000000..25b08de31d --- /dev/null +++ b/ChocolArm64/Translation/AILBarrier.cs @@ -0,0 +1,7 @@ +namespace ChocolArm64.Translation +{ + struct AILBarrier : IAILEmit + { + public void Emit(AILEmitter Context) { } + } +} \ No newline at end of file diff --git a/ChocolArm64/Translation/AILBlock.cs b/ChocolArm64/Translation/AILBlock.cs index bed195aaf0..e580e09c9b 100644 --- a/ChocolArm64/Translation/AILBlock.cs +++ b/ChocolArm64/Translation/AILBlock.cs @@ -4,11 +4,13 @@ namespace ChocolArm64.Translation { class AILBlock : IAILEmit { - public long IntInputs { get; private set; } - public long IntOutputs { get; private set; } + public long IntInputs { get; private set; } + public long IntOutputs { get; private set; } + public long IntAwOutputs { get; private set; } - public long VecInputs { get; private set; } - public long VecOutputs { get; private set; } + public long VecInputs { get; private set; } + public long VecOutputs { get; private set; } + public long VecAwOutputs { get; private set; } public bool HasStateStore { get; private set; } @@ -24,13 +26,22 @@ namespace ChocolArm64.Translation 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) { - case AIoType.Flag: IntInputs |= ((1L << Ld.Index) << 32) & ~IntOutputs; break; - case AIoType.Int: IntInputs |= (1L << Ld.Index) & ~IntOutputs; break; - case AIoType.Vector: VecInputs |= (1L << Ld.Index) & ~VecOutputs; break; + case AIoType.Flag: IntInputs |= ((1L << Ld.Index) << 32) & ~IntAwOutputs; break; + case AIoType.Int: IntInputs |= (1L << Ld.Index) & ~IntAwOutputs; break; + case AIoType.Vector: VecInputs |= (1L << Ld.Index) & ~VecAwOutputs; break; } } else if (ILEmitter is AILOpCodeStore St) diff --git a/ChocolArm64/Translation/AILEmitterCtx.cs b/ChocolArm64/Translation/AILEmitterCtx.cs index 9199eddc6f..ffcfa851ae 100644 --- a/ChocolArm64/Translation/AILEmitterCtx.cs +++ b/ChocolArm64/Translation/AILEmitterCtx.cs @@ -39,14 +39,16 @@ namespace ChocolArm64.Translation private const int Tmp4Index = -4; 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.Graph = Graph; this.Root = Root; - string SubName = $"Sub{Root.Position:X16}"; - Labels = new Dictionary(); Emitter = new AILEmitter(Graph, Root, SubName); @@ -92,6 +94,8 @@ namespace ChocolArm64.Translation } CurrOp.Emitter(this); + + ILBlock.Add(new AILBarrier()); } public bool TryOptEmitSubroutineCall() diff --git a/ChocolArm64/Translation/AILOpCodeLoad.cs b/ChocolArm64/Translation/AILOpCodeLoad.cs index 7cb431e2dc..d60ce539f7 100644 --- a/ChocolArm64/Translation/AILOpCodeLoad.cs +++ b/ChocolArm64/Translation/AILOpCodeLoad.cs @@ -11,12 +11,10 @@ namespace ChocolArm64.Translation 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) + public AILOpCodeLoad(int Index, AIoType IoType, ARegisterSize RegisterSize = 0) { - this.IoType = IoType; this.Index = Index; + this.IoType = IoType; this.RegisterSize = RegisterSize; } diff --git a/ChocolArm64/Translation/AILOpCodeStore.cs b/ChocolArm64/Translation/AILOpCodeStore.cs index c4ea53abaf..a0feb43773 100644 --- a/ChocolArm64/Translation/AILOpCodeStore.cs +++ b/ChocolArm64/Translation/AILOpCodeStore.cs @@ -11,10 +11,10 @@ namespace ChocolArm64.Translation 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.IoType = IoType; this.RegisterSize = RegisterSize; } diff --git a/ChocolArm64/Translation/ALocalAlloc.cs b/ChocolArm64/Translation/ALocalAlloc.cs index 0661ddc8dd..f23af9c767 100644 --- a/ChocolArm64/Translation/ALocalAlloc.cs +++ b/ChocolArm64/Translation/ALocalAlloc.cs @@ -67,7 +67,7 @@ namespace ChocolArm64.Translation public long VecOutputs; } - private const int MaxOptGraphLength = 120; + private const int MaxOptGraphLength = 55; public ALocalAlloc(AILBlock[] Graph, AILBlock Root) { @@ -149,11 +149,7 @@ namespace ChocolArm64.Translation if (RetTarget) { - BlkIO.Entry = Block; - BlkIO.IntInputs = 0; - BlkIO.VecInputs = 0; - BlkIO.IntOutputs = 0; - BlkIO.VecOutputs = 0; + BlkIO.Entry = Block; } else { diff --git a/Ryujinx.Core/Loaders/ElfSym.cs b/Ryujinx.Core/Loaders/ElfSym.cs index 35a45500a4..89e7c61f66 100644 --- a/Ryujinx.Core/Loaders/ElfSym.cs +++ b/Ryujinx.Core/Loaders/ElfSym.cs @@ -16,17 +16,15 @@ namespace Ryujinx.Core.Loaders Binding == ElfSymBinding.STB_GLOBAL || Binding == ElfSymBinding.STB_WEAK; - public int SHIdx { get; private set; } - public long ValueAbs { get; private set; } - public long Value { get; private set; } - public long Size { get; private set; } + public int SHIdx { get; private set; } + public long Value { get; private set; } + public long Size { get; private set; } public ElfSym( string Name, int Info, int Other, int SHIdx, - long ImageBase, long Value, long Size) { @@ -35,7 +33,6 @@ namespace Ryujinx.Core.Loaders this.Binding = (ElfSymBinding)(Info >> 4); this.Visibility = (ElfSymVisibility)Other; this.SHIdx = SHIdx; - this.ValueAbs = Value + ImageBase; this.Value = Value; this.Size = Size; } diff --git a/Ryujinx.Core/Loaders/Executable.cs b/Ryujinx.Core/Loaders/Executable.cs index e26608389b..c6770c7b37 100644 --- a/Ryujinx.Core/Loaders/Executable.cs +++ b/Ryujinx.Core/Loaders/Executable.cs @@ -9,13 +9,21 @@ namespace Ryujinx.Core.Loaders { private AMemory Memory; - private ElfDyn[] Dynamic; + private List Dynamic; + + private Dictionary m_SymbolTable; + + public IReadOnlyDictionary SymbolTable => m_SymbolTable; public long ImageBase { get; private set; } public long ImageEnd { get; private set; } public Executable(IExecutable Exe, AMemory Memory, long ImageBase) { + Dynamic = new List(); + + m_SymbolTable = new Dictionary(); + this.Memory = Memory; this.ImageBase = ImageBase; this.ImageEnd = ImageBase; @@ -48,9 +56,7 @@ namespace Ryujinx.Core.Loaders MapBss(BssStartOffset, BssEndOffset - BssStartOffset); - ImageEnd = BssEndOffset; - - List Dynamic = new List(); + ImageEnd = ImageBase + BssEndOffset; while (true) { @@ -69,7 +75,19 @@ namespace Ryujinx.Core.Loaders 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( @@ -135,7 +153,7 @@ namespace Ryujinx.Core.Loaders 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) diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs index 3e265ed341..60e71ee995 100644 --- a/Ryujinx.Core/OsHle/Process.cs +++ b/Ryujinx.Core/OsHle/Process.cs @@ -1,6 +1,6 @@ using ChocolArm64; +using ChocolArm64.Events; using ChocolArm64.Memory; -using ChocolArm64.State; using Ryujinx.Core.Loaders; using Ryujinx.Core.Loaders.Executables; using Ryujinx.Core.OsHle.Exceptions; @@ -24,6 +24,8 @@ namespace Ryujinx.Core.OsHle private Switch Ns; + private ATranslator Translator; + public int ProcessId { get; private set; } public AMemory Memory { get; private set; } @@ -171,7 +173,7 @@ namespace Ryujinx.Core.OsHle 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); @@ -201,16 +203,45 @@ namespace Ryujinx.Core.OsHle return Handle; } - private void BreakHandler(object sender, AInstExceptEventArgs e) + private void BreakHandler(object sender, AInstExceptionEventArgs e) { throw new GuestBrokeExecutionException(); } - private void UndefinedHandler(object sender, AInstUndEventArgs e) + private void UndefinedHandler(object sender, AInstUndefinedEventArgs e) { throw new UndefinedInstructionException(e.Position, e.RawOpCode); } + private ATranslator GetTranslator() + { + if (Translator == null) + { + Dictionary SymbolTable = new Dictionary(); + + foreach (Executable Exe in Executables) + { + foreach (KeyValuePair 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) { for (int Index = 1; Index < TotalTlsSlots; Index++) diff --git a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs index c5b6da04b6..ec53f47ff2 100644 --- a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs +++ b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs @@ -1,3 +1,4 @@ +using ChocolArm64.Events; using ChocolArm64.Memory; using ChocolArm64.State; using System; @@ -62,7 +63,7 @@ namespace Ryujinx.Core.OsHle.Svc Rng = new Random(); } - public void SvcCall(object sender, AInstExceptEventArgs e) + public void SvcCall(object sender, AInstExceptionEventArgs e) { AThreadState ThreadState = (AThreadState)sender; diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs index 7af2d55d0a..bf9d90e33d 100644 --- a/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/Ryujinx.Tests/Cpu/CpuTest.cs @@ -30,10 +30,11 @@ namespace Ryujinx.Tests.Cpu EntryPoint = Position; Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize); + ATranslator Translator = new ATranslator(); Allocator = new AMemoryAlloc(); Memory = new AMemory(Ram, Allocator); 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]