InstEmitMemoryEx.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. using ChocolArm64.Decoders;
  2. using ChocolArm64.Memory;
  3. using ChocolArm64.State;
  4. using ChocolArm64.Translation;
  5. using System;
  6. using System.Reflection.Emit;
  7. using System.Threading;
  8. using static ChocolArm64.Instructions.InstEmitMemoryHelper;
  9. namespace ChocolArm64.Instructions
  10. {
  11. static partial class InstEmit
  12. {
  13. [Flags]
  14. private enum AccessType
  15. {
  16. None = 0,
  17. Ordered = 1,
  18. Exclusive = 2,
  19. OrderedEx = Ordered | Exclusive
  20. }
  21. public static void Clrex(ILEmitterCtx context)
  22. {
  23. EmitMemoryCall(context, nameof(MemoryManager.ClearExclusive));
  24. }
  25. public static void Dmb(ILEmitterCtx context) => EmitBarrier(context);
  26. public static void Dsb(ILEmitterCtx context) => EmitBarrier(context);
  27. public static void Ldar(ILEmitterCtx context) => EmitLdr(context, AccessType.Ordered);
  28. public static void Ldaxr(ILEmitterCtx context) => EmitLdr(context, AccessType.OrderedEx);
  29. public static void Ldxr(ILEmitterCtx context) => EmitLdr(context, AccessType.Exclusive);
  30. public static void Ldxp(ILEmitterCtx context) => EmitLdp(context, AccessType.Exclusive);
  31. public static void Ldaxp(ILEmitterCtx context) => EmitLdp(context, AccessType.OrderedEx);
  32. private static void EmitLdr(ILEmitterCtx context, AccessType accType)
  33. {
  34. EmitLoad(context, accType, false);
  35. }
  36. private static void EmitLdp(ILEmitterCtx context, AccessType accType)
  37. {
  38. EmitLoad(context, accType, true);
  39. }
  40. private static void EmitLoad(ILEmitterCtx context, AccessType accType, bool pair)
  41. {
  42. OpCodeMemEx64 op = (OpCodeMemEx64)context.CurrOp;
  43. bool ordered = (accType & AccessType.Ordered) != 0;
  44. bool exclusive = (accType & AccessType.Exclusive) != 0;
  45. if (ordered)
  46. {
  47. EmitBarrier(context);
  48. }
  49. if (exclusive)
  50. {
  51. EmitMemoryCall(context, nameof(MemoryManager.SetExclusive), op.Rn);
  52. }
  53. context.EmitLdint(op.Rn);
  54. context.EmitSttmp();
  55. context.EmitLdarg(TranslatedSub.MemoryArgIdx);
  56. context.EmitLdtmp();
  57. EmitReadZxCall(context, op.Size);
  58. context.EmitStintzr(op.Rt);
  59. if (pair)
  60. {
  61. context.EmitLdarg(TranslatedSub.MemoryArgIdx);
  62. context.EmitLdtmp();
  63. context.EmitLdc_I8(1 << op.Size);
  64. context.Emit(OpCodes.Add);
  65. EmitReadZxCall(context, op.Size);
  66. context.EmitStintzr(op.Rt2);
  67. }
  68. }
  69. public static void Pfrm(ILEmitterCtx context)
  70. {
  71. //Memory Prefetch, execute as no-op.
  72. }
  73. public static void Stlr(ILEmitterCtx context) => EmitStr(context, AccessType.Ordered);
  74. public static void Stlxr(ILEmitterCtx context) => EmitStr(context, AccessType.OrderedEx);
  75. public static void Stxr(ILEmitterCtx context) => EmitStr(context, AccessType.Exclusive);
  76. public static void Stxp(ILEmitterCtx context) => EmitStp(context, AccessType.Exclusive);
  77. public static void Stlxp(ILEmitterCtx context) => EmitStp(context, AccessType.OrderedEx);
  78. private static void EmitStr(ILEmitterCtx context, AccessType accType)
  79. {
  80. EmitStore(context, accType, false);
  81. }
  82. private static void EmitStp(ILEmitterCtx context, AccessType accType)
  83. {
  84. EmitStore(context, accType, true);
  85. }
  86. private static void EmitStore(ILEmitterCtx context, AccessType accType, bool pair)
  87. {
  88. OpCodeMemEx64 op = (OpCodeMemEx64)context.CurrOp;
  89. bool ordered = (accType & AccessType.Ordered) != 0;
  90. bool exclusive = (accType & AccessType.Exclusive) != 0;
  91. if (ordered)
  92. {
  93. EmitBarrier(context);
  94. }
  95. ILLabel lblEx = new ILLabel();
  96. ILLabel lblEnd = new ILLabel();
  97. if (exclusive)
  98. {
  99. EmitMemoryCall(context, nameof(MemoryManager.TestExclusive), op.Rn);
  100. context.Emit(OpCodes.Brtrue_S, lblEx);
  101. context.EmitLdc_I8(1);
  102. context.EmitStintzr(op.Rs);
  103. context.Emit(OpCodes.Br_S, lblEnd);
  104. }
  105. context.MarkLabel(lblEx);
  106. context.EmitLdarg(TranslatedSub.MemoryArgIdx);
  107. context.EmitLdint(op.Rn);
  108. context.EmitLdintzr(op.Rt);
  109. EmitWriteCall(context, op.Size);
  110. if (pair)
  111. {
  112. context.EmitLdarg(TranslatedSub.MemoryArgIdx);
  113. context.EmitLdint(op.Rn);
  114. context.EmitLdc_I8(1 << op.Size);
  115. context.Emit(OpCodes.Add);
  116. context.EmitLdintzr(op.Rt2);
  117. EmitWriteCall(context, op.Size);
  118. }
  119. if (exclusive)
  120. {
  121. context.EmitLdc_I8(0);
  122. context.EmitStintzr(op.Rs);
  123. EmitMemoryCall(context, nameof(MemoryManager.ClearExclusiveForStore));
  124. }
  125. context.MarkLabel(lblEnd);
  126. }
  127. private static void EmitMemoryCall(ILEmitterCtx context, string name, int rn = -1)
  128. {
  129. context.EmitLdarg(TranslatedSub.MemoryArgIdx);
  130. context.EmitLdarg(TranslatedSub.StateArgIdx);
  131. context.EmitCallPropGet(typeof(CpuThreadState), nameof(CpuThreadState.Core));
  132. if (rn != -1)
  133. {
  134. context.EmitLdint(rn);
  135. }
  136. context.EmitCall(typeof(MemoryManager), name);
  137. }
  138. private static void EmitBarrier(ILEmitterCtx context)
  139. {
  140. //Note: This barrier is most likely not necessary, and probably
  141. //doesn't make any difference since we need to do a ton of stuff
  142. //(software MMU emulation) to read or write anything anyway.
  143. context.EmitCall(typeof(Thread), nameof(Thread.MemoryBarrier));
  144. }
  145. }
  146. }