InstEmitMemory32.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. using ChocolArm64.Decoders;
  2. using ChocolArm64.IntermediateRepresentation;
  3. using ChocolArm64.State;
  4. using ChocolArm64.Translation;
  5. using System;
  6. using System.Reflection.Emit;
  7. using static ChocolArm64.Instructions.InstEmit32Helper;
  8. using static ChocolArm64.Instructions.InstEmitMemoryHelper;
  9. namespace ChocolArm64.Instructions
  10. {
  11. static partial class InstEmit32
  12. {
  13. private const int ByteSizeLog2 = 0;
  14. private const int HWordSizeLog2 = 1;
  15. private const int WordSizeLog2 = 2;
  16. private const int DWordSizeLog2 = 3;
  17. [Flags]
  18. enum AccessType
  19. {
  20. Store = 0,
  21. Signed = 1,
  22. Load = 2,
  23. LoadZx = Load,
  24. LoadSx = Load | Signed,
  25. }
  26. public static void Ldm(ILEmitterCtx context)
  27. {
  28. OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
  29. EmitLoadFromRegister(context, op.Rn);
  30. bool writesToPc = (op.RegisterMask & (1 << RegisterAlias.Aarch32Pc)) != 0;
  31. bool writeBack = op.PostOffset != 0 && (op.Rn != RegisterAlias.Aarch32Pc || !writesToPc);
  32. if (writeBack)
  33. {
  34. context.Emit(OpCodes.Dup);
  35. }
  36. context.EmitLdc_I4(op.Offset);
  37. context.Emit(OpCodes.Add);
  38. context.EmitSttmp();
  39. if (writeBack)
  40. {
  41. context.EmitLdc_I4(op.PostOffset);
  42. context.Emit(OpCodes.Add);
  43. EmitStoreToRegister(context, op.Rn);
  44. }
  45. int mask = op.RegisterMask;
  46. int offset = 0;
  47. for (int register = 0; mask != 0; mask >>= 1, register++)
  48. {
  49. if ((mask & 1) != 0)
  50. {
  51. context.EmitLdtmp();
  52. context.EmitLdc_I4(offset);
  53. context.Emit(OpCodes.Add);
  54. EmitReadZxCall(context, WordSizeLog2);
  55. EmitStoreToRegister(context, register);
  56. offset += 4;
  57. }
  58. }
  59. }
  60. public static void Ldr(ILEmitterCtx context)
  61. {
  62. EmitLoadOrStore(context, WordSizeLog2, AccessType.LoadZx);
  63. }
  64. public static void Ldrb(ILEmitterCtx context)
  65. {
  66. EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx);
  67. }
  68. public static void Ldrd(ILEmitterCtx context)
  69. {
  70. EmitLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx);
  71. }
  72. public static void Ldrh(ILEmitterCtx context)
  73. {
  74. EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx);
  75. }
  76. public static void Ldrsb(ILEmitterCtx context)
  77. {
  78. EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadSx);
  79. }
  80. public static void Ldrsh(ILEmitterCtx context)
  81. {
  82. EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadSx);
  83. }
  84. public static void Stm(ILEmitterCtx context)
  85. {
  86. OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
  87. EmitLoadFromRegister(context, op.Rn);
  88. context.EmitLdc_I4(op.Offset);
  89. context.Emit(OpCodes.Add);
  90. context.EmitSttmp();
  91. int mask = op.RegisterMask;
  92. int offset = 0;
  93. for (int register = 0; mask != 0; mask >>= 1, register++)
  94. {
  95. if ((mask & 1) != 0)
  96. {
  97. context.EmitLdtmp();
  98. context.EmitLdc_I4(offset);
  99. context.Emit(OpCodes.Add);
  100. EmitLoadFromRegister(context, register);
  101. EmitWriteCall(context, WordSizeLog2);
  102. // Note: If Rn is also specified on the register list,
  103. // and Rn is the first register on this list, then the
  104. // value that is written to memory is the unmodified value,
  105. // before the write back. If it is on the list, but it's
  106. // not the first one, then the value written to memory
  107. // varies between CPUs.
  108. if (offset == 0 && op.PostOffset != 0)
  109. {
  110. // Emit write back after the first write.
  111. EmitLoadFromRegister(context, op.Rn);
  112. context.EmitLdc_I4(op.PostOffset);
  113. context.Emit(OpCodes.Add);
  114. EmitStoreToRegister(context, op.Rn);
  115. }
  116. offset += 4;
  117. }
  118. }
  119. }
  120. public static void Str(ILEmitterCtx context)
  121. {
  122. EmitLoadOrStore(context, WordSizeLog2, AccessType.Store);
  123. }
  124. public static void Strb(ILEmitterCtx context)
  125. {
  126. EmitLoadOrStore(context, ByteSizeLog2, AccessType.Store);
  127. }
  128. public static void Strd(ILEmitterCtx context)
  129. {
  130. EmitLoadOrStore(context, DWordSizeLog2, AccessType.Store);
  131. }
  132. public static void Strh(ILEmitterCtx context)
  133. {
  134. EmitLoadOrStore(context, HWordSizeLog2, AccessType.Store);
  135. }
  136. private static void EmitLoadOrStore(ILEmitterCtx context, int size, AccessType accType)
  137. {
  138. OpCode32Mem op = (OpCode32Mem)context.CurrOp;
  139. if (op.Index || op.WBack)
  140. {
  141. EmitLoadFromRegister(context, op.Rn);
  142. context.EmitLdc_I4(op.Imm);
  143. context.Emit(op.Add ? OpCodes.Add : OpCodes.Sub);
  144. context.EmitSttmp();
  145. }
  146. if (op.Index)
  147. {
  148. context.EmitLdtmp();
  149. }
  150. else
  151. {
  152. EmitLoadFromRegister(context, op.Rn);
  153. }
  154. if ((accType & AccessType.Load) != 0)
  155. {
  156. if ((accType & AccessType.Signed) != 0)
  157. {
  158. EmitReadSx32Call(context, size);
  159. }
  160. else
  161. {
  162. EmitReadZxCall(context, size);
  163. }
  164. if (op.WBack)
  165. {
  166. context.EmitLdtmp();
  167. EmitStoreToRegister(context, op.Rn);
  168. }
  169. if (size == DWordSizeLog2)
  170. {
  171. context.Emit(OpCodes.Dup);
  172. context.EmitLdflg((int)PState.EBit);
  173. ILLabel lblBigEndian = new ILLabel();
  174. ILLabel lblEnd = new ILLabel();
  175. context.Emit(OpCodes.Brtrue_S, lblBigEndian);
  176. // Little endian mode.
  177. context.Emit(OpCodes.Conv_U4);
  178. EmitStoreToRegister(context, op.Rt);
  179. context.EmitLsr(32);
  180. context.Emit(OpCodes.Conv_U4);
  181. EmitStoreToRegister(context, op.Rt | 1);
  182. context.Emit(OpCodes.Br_S, lblEnd);
  183. // Big endian mode.
  184. context.MarkLabel(lblBigEndian);
  185. context.EmitLsr(32);
  186. context.Emit(OpCodes.Conv_U4);
  187. EmitStoreToRegister(context, op.Rt);
  188. context.Emit(OpCodes.Conv_U4);
  189. EmitStoreToRegister(context, op.Rt | 1);
  190. context.MarkLabel(lblEnd);
  191. }
  192. else
  193. {
  194. EmitStoreToRegister(context, op.Rt);
  195. }
  196. }
  197. else
  198. {
  199. if (op.WBack)
  200. {
  201. context.EmitLdtmp();
  202. EmitStoreToRegister(context, op.Rn);
  203. }
  204. EmitLoadFromRegister(context, op.Rt);
  205. if (size == DWordSizeLog2)
  206. {
  207. context.Emit(OpCodes.Conv_U8);
  208. context.EmitLdflg((int)PState.EBit);
  209. ILLabel lblBigEndian = new ILLabel();
  210. ILLabel lblEnd = new ILLabel();
  211. context.Emit(OpCodes.Brtrue_S, lblBigEndian);
  212. // Little endian mode.
  213. EmitLoadFromRegister(context, op.Rt | 1);
  214. context.Emit(OpCodes.Conv_U8);
  215. context.EmitLsl(32);
  216. context.Emit(OpCodes.Or);
  217. context.Emit(OpCodes.Br_S, lblEnd);
  218. // Big endian mode.
  219. context.MarkLabel(lblBigEndian);
  220. context.EmitLsl(32);
  221. EmitLoadFromRegister(context, op.Rt | 1);
  222. context.Emit(OpCodes.Conv_U8);
  223. context.Emit(OpCodes.Or);
  224. context.MarkLabel(lblEnd);
  225. }
  226. EmitWriteCall(context, size);
  227. }
  228. }
  229. }
  230. }