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<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;
 
-        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;
         }
 
         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<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> VisitedEnd = new Dictionary<long, ABlock>();
@@ -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<AInstExceptEventArgs> Break;
-        public event EventHandler<AInstExceptEventArgs> SvcCall;
-        public event EventHandler<AInstUndEventArgs>    Undefined;
+        public event EventHandler<AInstExceptionEventArgs> Break;
+        public event EventHandler<AInstExceptionEventArgs> SvcCall;
+        public event EventHandler<AInstUndefinedEventArgs> 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<long, AILLabel>();
 
             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<ElfDyn> Dynamic;
+
+        private Dictionary<long, string> m_SymbolTable;
+
+        public IReadOnlyDictionary<long, string> 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<ElfDyn>();
+
+            m_SymbolTable = new Dictionary<long, string>();
+
             this.Memory    = Memory;
             this.ImageBase = ImageBase;
             this.ImageEnd  = ImageBase;
@@ -48,9 +56,7 @@ namespace Ryujinx.Core.Loaders
 
             MapBss(BssStartOffset, BssEndOffset - BssStartOffset);
 
-            ImageEnd = BssEndOffset;
-
-            List<ElfDyn> Dynamic = new List<ElfDyn>();
+            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<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)
         {
             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]