Translator.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. Block[] graph = new Block[] { block };
  72. string subName = GetSubroutineName(position);
  73. ILEmitterCtx context = new ILEmitterCtx(_cache, graph, block, subName);
  74. do
  75. {
  76. context.EmitOpCode();
  77. }
  78. while (context.AdvanceOpCode());
  79. TranslatedSub subroutine = context.GetSubroutine();
  80. subroutine.SetType(TranslatedSubType.SubTier0);
  81. _cache.AddOrUpdate(position, subroutine, block.OpCodes.Count);
  82. OpCode64 lastOp = block.GetLastOp();
  83. return subroutine;
  84. }
  85. private void TranslateTier1(CpuThreadState state, MemoryManager memory, long position)
  86. {
  87. (Block[] graph, Block root) = Decoder.DecodeSubroutine(_cache, state, memory, position);
  88. string subName = GetSubroutineName(position);
  89. ILEmitterCtx context = new ILEmitterCtx(_cache, graph, root, subName);
  90. if (context.CurrBlock.Position != position)
  91. {
  92. context.Emit(OpCodes.Br, context.GetLabel(position));
  93. }
  94. do
  95. {
  96. context.EmitOpCode();
  97. }
  98. while (context.AdvanceOpCode());
  99. //Mark all methods that calls this method for ReJiting,
  100. //since we can now call it directly which is faster.
  101. if (_cache.TryGetSubroutine(position, out TranslatedSub oldSub))
  102. {
  103. foreach (long callerPos in oldSub.GetCallerPositions())
  104. {
  105. if (_cache.TryGetSubroutine(position, out TranslatedSub callerSub))
  106. {
  107. callerSub.MarkForReJit();
  108. }
  109. }
  110. }
  111. TranslatedSub subroutine = context.GetSubroutine();
  112. subroutine.SetType(TranslatedSubType.SubTier1);
  113. _cache.AddOrUpdate(position, subroutine, GetGraphInstCount(graph));
  114. }
  115. private string GetSubroutineName(long position)
  116. {
  117. return $"Sub{position:x16}";
  118. }
  119. private int GetGraphInstCount(Block[] graph)
  120. {
  121. int size = 0;
  122. foreach (Block block in graph)
  123. {
  124. size += block.OpCodes.Count;
  125. }
  126. return size;
  127. }
  128. }
  129. }