AInstEmitMemoryEx.cs 5.7 KB

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