InstEmitSystem.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. using ARMeilleure.Decoders;
  2. using ARMeilleure.IntermediateRepresentation;
  3. using ARMeilleure.State;
  4. using ARMeilleure.Translation;
  5. using System;
  6. using System.Reflection;
  7. using static ARMeilleure.Instructions.InstEmitHelper;
  8. using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
  9. namespace ARMeilleure.Instructions
  10. {
  11. static partial class InstEmit
  12. {
  13. private const int DczSizeLog2 = 4; // Log2 size in words
  14. public const int DczSizeInBytes = 4 << DczSizeLog2;
  15. public static void Isb(ArmEmitterContext context)
  16. {
  17. // Execute as no-op.
  18. }
  19. public static void Mrs(ArmEmitterContext context)
  20. {
  21. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  22. MethodInfo info;
  23. switch (GetPackedId(op))
  24. {
  25. case 0b11_011_0000_0000_001:
  26. info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0));
  27. break;
  28. case 0b11_011_0000_0000_111:
  29. info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0));
  30. break;
  31. case 0b11_011_0100_0010_000:
  32. EmitGetNzcv(context);
  33. return;
  34. case 0b11_011_0100_0100_000:
  35. EmitGetFpcr(context);
  36. return;
  37. case 0b11_011_0100_0100_001:
  38. EmitGetFpsr(context);
  39. return;
  40. case 0b11_011_1101_0000_010:
  41. EmitGetTpidrEl0(context);
  42. return;
  43. case 0b11_011_1101_0000_011:
  44. EmitGetTpidrroEl0(context);
  45. return;
  46. case 0b11_011_1101_0000_101:
  47. EmitGetTpidr2El0(context);
  48. return;
  49. case 0b11_011_1110_0000_000:
  50. info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0));
  51. break;
  52. case 0b11_011_1110_0000_001:
  53. info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0));
  54. break;
  55. case 0b11_011_1110_0000_010:
  56. info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0));
  57. break;
  58. default:
  59. throw new NotImplementedException($"Unknown MRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
  60. }
  61. SetIntOrZR(context, op.Rt, context.Call(info));
  62. }
  63. public static void Msr(ArmEmitterContext context)
  64. {
  65. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  66. switch (GetPackedId(op))
  67. {
  68. case 0b11_011_0100_0010_000:
  69. EmitSetNzcv(context);
  70. return;
  71. case 0b11_011_0100_0100_000:
  72. EmitSetFpcr(context);
  73. return;
  74. case 0b11_011_0100_0100_001:
  75. EmitSetFpsr(context);
  76. return;
  77. case 0b11_011_1101_0000_010:
  78. EmitSetTpidrEl0(context);
  79. return;
  80. case 0b11_011_1101_0000_101:
  81. EmitSetTpidr2El0(context);
  82. return;
  83. default:
  84. throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
  85. }
  86. }
  87. public static void Nop(ArmEmitterContext context)
  88. {
  89. // Do nothing.
  90. }
  91. public static void Sys(ArmEmitterContext context)
  92. {
  93. // This instruction is used to do some operations on the CPU like cache invalidation,
  94. // address translation and the like.
  95. // We treat it as no-op here since we don't have any cache being emulated anyway.
  96. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  97. switch (GetPackedId(op))
  98. {
  99. case 0b11_011_0111_0100_001:
  100. {
  101. // DC ZVA
  102. Operand t = GetIntOrZR(context, op.Rt);
  103. for (long offset = 0; offset < DczSizeInBytes; offset += 8)
  104. {
  105. Operand address = context.Add(t, Const(offset));
  106. InstEmitMemoryHelper.EmitStore(context, address, RegisterConsts.ZeroIndex, 3);
  107. }
  108. break;
  109. }
  110. // No-op
  111. case 0b11_011_0111_1110_001: // DC CIVAC
  112. break;
  113. case 0b11_011_0111_0101_001: // IC IVAU
  114. Operand target = Register(op.Rt, RegisterType.Integer, OperandType.I64);
  115. context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)), target);
  116. break;
  117. }
  118. }
  119. private static int GetPackedId(OpCodeSystem op)
  120. {
  121. int id;
  122. id = op.Op2 << 0;
  123. id |= op.CRm << 3;
  124. id |= op.CRn << 7;
  125. id |= op.Op1 << 11;
  126. id |= op.Op0 << 14;
  127. return id;
  128. }
  129. private static void EmitGetNzcv(ArmEmitterContext context)
  130. {
  131. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  132. Operand nzcv = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
  133. nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)));
  134. nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)));
  135. nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)));
  136. SetIntOrZR(context, op.Rt, nzcv);
  137. }
  138. private static void EmitGetFpcr(ArmEmitterContext context)
  139. {
  140. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  141. Operand fpcr = Const(0);
  142. for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
  143. {
  144. if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
  145. {
  146. fpcr = context.BitwiseOr(fpcr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
  147. }
  148. }
  149. SetIntOrZR(context, op.Rt, fpcr);
  150. }
  151. private static void EmitGetFpsr(ArmEmitterContext context)
  152. {
  153. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  154. context.SyncQcFlag();
  155. Operand fpsr = Const(0);
  156. for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
  157. {
  158. if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
  159. {
  160. fpsr = context.BitwiseOr(fpsr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
  161. }
  162. }
  163. SetIntOrZR(context, op.Rt, fpsr);
  164. }
  165. private static void EmitGetTpidrEl0(ArmEmitterContext context)
  166. {
  167. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  168. Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
  169. Operand result = context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())));
  170. SetIntOrZR(context, op.Rt, result);
  171. }
  172. private static void EmitGetTpidrroEl0(ArmEmitterContext context)
  173. {
  174. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  175. Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
  176. Operand result = context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrroEl0Offset())));
  177. SetIntOrZR(context, op.Rt, result);
  178. }
  179. private static void EmitGetTpidr2El0(ArmEmitterContext context)
  180. {
  181. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  182. Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
  183. Operand result = context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidr2El0Offset())));
  184. SetIntOrZR(context, op.Rt, result);
  185. }
  186. private static void EmitSetNzcv(ArmEmitterContext context)
  187. {
  188. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  189. Operand nzcv = GetIntOrZR(context, op.Rt);
  190. nzcv = context.ConvertI64ToI32(nzcv);
  191. SetFlag(context, PState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.VFlag)), Const(1)));
  192. SetFlag(context, PState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.CFlag)), Const(1)));
  193. SetFlag(context, PState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.ZFlag)), Const(1)));
  194. SetFlag(context, PState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.NFlag)), Const(1)));
  195. }
  196. private static void EmitSetFpcr(ArmEmitterContext context)
  197. {
  198. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  199. Operand fpcr = GetIntOrZR(context, op.Rt);
  200. fpcr = context.ConvertI64ToI32(fpcr);
  201. for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
  202. {
  203. if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
  204. {
  205. SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpcr, Const(flag)), Const(1)));
  206. }
  207. }
  208. context.UpdateArmFpMode();
  209. }
  210. private static void EmitSetFpsr(ArmEmitterContext context)
  211. {
  212. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  213. context.ClearQcFlagIfModified();
  214. Operand fpsr = GetIntOrZR(context, op.Rt);
  215. fpsr = context.ConvertI64ToI32(fpsr);
  216. for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
  217. {
  218. if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
  219. {
  220. SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpsr, Const(flag)), Const(1)));
  221. }
  222. }
  223. context.UpdateArmFpMode();
  224. }
  225. private static void EmitSetTpidrEl0(ArmEmitterContext context)
  226. {
  227. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  228. Operand value = GetIntOrZR(context, op.Rt);
  229. Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
  230. context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())), value);
  231. }
  232. private static void EmitSetTpidr2El0(ArmEmitterContext context)
  233. {
  234. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  235. Operand value = GetIntOrZR(context, op.Rt);
  236. Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
  237. context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidr2El0Offset())), value);
  238. }
  239. }
  240. }