Translator.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. using ChocolArm64.Decoders;
  2. using ChocolArm64.Events;
  3. using ChocolArm64.Memory;
  4. using ChocolArm64.State;
  5. using ChocolArm64.Translation;
  6. using System;
  7. using System.Reflection.Emit;
  8. namespace ChocolArm64
  9. {
  10. public class Translator
  11. {
  12. private TranslatorCache _cache;
  13. public event EventHandler<CpuTraceEventArgs> CpuTrace;
  14. public bool EnableCpuTrace { get; set; }
  15. public Translator()
  16. {
  17. _cache = new TranslatorCache();
  18. }
  19. internal void ExecuteSubroutine(CpuThread thread, long position)
  20. {
  21. //TODO: Both the execute A32/A64 methods should be merged on the future,
  22. //when both ISAs are implemented with the interpreter and JIT.
  23. //As of now, A32 only has a interpreter and A64 a JIT.
  24. CpuThreadState state = thread.ThreadState;
  25. MemoryManager memory = thread.Memory;
  26. if (state.ExecutionMode == ExecutionMode.AArch32)
  27. {
  28. ExecuteSubroutineA32(state, memory);
  29. }
  30. else
  31. {
  32. ExecuteSubroutineA64(state, memory, position);
  33. }
  34. }
  35. private void ExecuteSubroutineA32(CpuThreadState state, MemoryManager memory)
  36. {
  37. do
  38. {
  39. OpCode64 opCode = Decoder.DecodeOpCode(state, memory, state.R15);
  40. opCode.Interpreter(state, memory, opCode);
  41. }
  42. while (state.R15 != 0 && state.Running);
  43. }
  44. private void ExecuteSubroutineA64(CpuThreadState state, MemoryManager memory, long position)
  45. {
  46. do
  47. {
  48. if (EnableCpuTrace)
  49. {
  50. CpuTrace?.Invoke(this, new CpuTraceEventArgs(position));
  51. }
  52. if (!_cache.TryGetSubroutine(position, out TranslatedSub sub))
  53. {
  54. sub = TranslateTier0(state, memory, position);
  55. }
  56. if (sub.ShouldReJit())
  57. {
  58. TranslateTier1(state, memory, position);
  59. }
  60. position = sub.Execute(state, memory);
  61. }
  62. while (position != 0 && state.Running);
  63. }
  64. internal bool HasCachedSub(long position)
  65. {
  66. return _cache.HasSubroutine(position);
  67. }
  68. private TranslatedSub TranslateTier0(CpuThreadState state, MemoryManager memory, long position)
  69. {
  70. Block block = Decoder.DecodeBasicBlock(state, memory, position);
  71. ILEmitterCtx context = new ILEmitterCtx(_cache, block);
  72. string subName = GetSubroutineName(position);
  73. ILMethodBuilder ilMthdBuilder = new ILMethodBuilder(context.GetILBlocks(), subName);
  74. TranslatedSub subroutine = ilMthdBuilder.GetSubroutine();
  75. subroutine.SetType(TranslatedSubType.SubTier0);
  76. _cache.AddOrUpdate(position, subroutine, block.OpCodes.Count);
  77. return subroutine;
  78. }
  79. private void TranslateTier1(CpuThreadState state, MemoryManager memory, long position)
  80. {
  81. Block graph = Decoder.DecodeSubroutine(_cache, state, memory, position);
  82. ILEmitterCtx context = new ILEmitterCtx(_cache, graph);
  83. ILBlock[] ilBlocks = context.GetILBlocks();
  84. string subName = GetSubroutineName(position);
  85. ILMethodBuilder ilMthdBuilder = new ILMethodBuilder(ilBlocks, subName);
  86. TranslatedSub subroutine = ilMthdBuilder.GetSubroutine();
  87. subroutine.SetType(TranslatedSubType.SubTier1);
  88. int ilOpCount = 0;
  89. foreach (ILBlock ilBlock in ilBlocks)
  90. {
  91. ilOpCount += ilBlock.Count;
  92. }
  93. _cache.AddOrUpdate(position, subroutine, ilOpCount);
  94. //Mark all methods that calls this method for ReJiting,
  95. //since we can now call it directly which is faster.
  96. if (_cache.TryGetSubroutine(position, out TranslatedSub oldSub))
  97. {
  98. foreach (long callerPos in oldSub.GetCallerPositions())
  99. {
  100. if (_cache.TryGetSubroutine(position, out TranslatedSub callerSub))
  101. {
  102. callerSub.MarkForReJit();
  103. }
  104. }
  105. }
  106. }
  107. private string GetSubroutineName(long position)
  108. {
  109. return $"Sub{position:x16}";
  110. }
  111. }
  112. }