InstEmitSystem.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
  26. case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
  27. case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
  28. case 0b11_011_0100_0100_000: EmitGetFpcr(context); return;
  29. case 0b11_011_0100_0100_001: EmitGetFpsr(context); return;
  30. case 0b11_011_1101_0000_010: EmitGetTpidrEl0(context); return;
  31. case 0b11_011_1101_0000_011: EmitGetTpidrroEl0(context); return;
  32. case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
  33. case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
  34. case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break;
  35. default: throw new NotImplementedException($"Unknown MRS 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
  36. }
  37. SetIntOrZR(context, op.Rt, context.Call(info));
  38. }
  39. public static void Msr(ArmEmitterContext context)
  40. {
  41. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  42. switch (GetPackedId(op))
  43. {
  44. case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
  45. case 0b11_011_0100_0100_000: EmitSetFpcr(context); return;
  46. case 0b11_011_0100_0100_001: EmitSetFpsr(context); return;
  47. case 0b11_011_1101_0000_010: EmitSetTpidrEl0(context); return;
  48. default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
  49. }
  50. }
  51. public static void Nop(ArmEmitterContext context)
  52. {
  53. // Do nothing.
  54. }
  55. public static void Sys(ArmEmitterContext context)
  56. {
  57. // This instruction is used to do some operations on the CPU like cache invalidation,
  58. // address translation and the like.
  59. // We treat it as no-op here since we don't have any cache being emulated anyway.
  60. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  61. switch (GetPackedId(op))
  62. {
  63. case 0b11_011_0111_0100_001:
  64. {
  65. // DC ZVA
  66. Operand t = GetIntOrZR(context, op.Rt);
  67. for (long offset = 0; offset < DczSizeInBytes; offset += 8)
  68. {
  69. Operand address = context.Add(t, Const(offset));
  70. InstEmitMemoryHelper.EmitStore(context, address, RegisterConsts.ZeroIndex, 3);
  71. }
  72. break;
  73. }
  74. // No-op
  75. case 0b11_011_0111_1110_001: // DC CIVAC
  76. break;
  77. case 0b11_011_0111_0101_001: // IC IVAU
  78. Operand target = Register(op.Rt, RegisterType.Integer, OperandType.I64);
  79. context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)), target);
  80. break;
  81. }
  82. }
  83. private static int GetPackedId(OpCodeSystem op)
  84. {
  85. int id;
  86. id = op.Op2 << 0;
  87. id |= op.CRm << 3;
  88. id |= op.CRn << 7;
  89. id |= op.Op1 << 11;
  90. id |= op.Op0 << 14;
  91. return id;
  92. }
  93. private static void EmitGetNzcv(ArmEmitterContext context)
  94. {
  95. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  96. Operand nzcv = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
  97. nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)));
  98. nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)));
  99. nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)));
  100. SetIntOrZR(context, op.Rt, nzcv);
  101. }
  102. private static void EmitGetFpcr(ArmEmitterContext context)
  103. {
  104. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  105. Operand fpcr = Const(0);
  106. for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
  107. {
  108. if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
  109. {
  110. fpcr = context.BitwiseOr(fpcr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
  111. }
  112. }
  113. SetIntOrZR(context, op.Rt, fpcr);
  114. }
  115. private static void EmitGetFpsr(ArmEmitterContext context)
  116. {
  117. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  118. context.SyncQcFlag();
  119. Operand fpsr = Const(0);
  120. for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
  121. {
  122. if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
  123. {
  124. fpsr = context.BitwiseOr(fpsr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
  125. }
  126. }
  127. SetIntOrZR(context, op.Rt, fpsr);
  128. }
  129. private static void EmitGetTpidrEl0(ArmEmitterContext context)
  130. {
  131. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  132. Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
  133. Operand result = context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())));
  134. SetIntOrZR(context, op.Rt, result);
  135. }
  136. private static void EmitGetTpidrroEl0(ArmEmitterContext context)
  137. {
  138. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  139. Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
  140. Operand result = context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrroEl0Offset())));
  141. SetIntOrZR(context, op.Rt, result);
  142. }
  143. private static void EmitSetNzcv(ArmEmitterContext context)
  144. {
  145. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  146. Operand nzcv = GetIntOrZR(context, op.Rt);
  147. nzcv = context.ConvertI64ToI32(nzcv);
  148. SetFlag(context, PState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.VFlag)), Const(1)));
  149. SetFlag(context, PState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.CFlag)), Const(1)));
  150. SetFlag(context, PState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.ZFlag)), Const(1)));
  151. SetFlag(context, PState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.NFlag)), Const(1)));
  152. }
  153. private static void EmitSetFpcr(ArmEmitterContext context)
  154. {
  155. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  156. Operand fpcr = GetIntOrZR(context, op.Rt);
  157. fpcr = context.ConvertI64ToI32(fpcr);
  158. for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
  159. {
  160. if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
  161. {
  162. SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpcr, Const(flag)), Const(1)));
  163. }
  164. }
  165. context.UpdateArmFpMode();
  166. }
  167. private static void EmitSetFpsr(ArmEmitterContext context)
  168. {
  169. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  170. context.ClearQcFlagIfModified();
  171. Operand fpsr = GetIntOrZR(context, op.Rt);
  172. fpsr = context.ConvertI64ToI32(fpsr);
  173. for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
  174. {
  175. if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
  176. {
  177. SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpsr, Const(flag)), Const(1)));
  178. }
  179. }
  180. context.UpdateArmFpMode();
  181. }
  182. private static void EmitSetTpidrEl0(ArmEmitterContext context)
  183. {
  184. OpCodeSystem op = (OpCodeSystem)context.CurrOp;
  185. Operand value = GetIntOrZR(context, op.Rt);
  186. Operand nativeContext = context.LoadArgument(OperandType.I64, 0);
  187. context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())), value);
  188. }
  189. }
  190. }