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