InstEmitSystem32.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 using static ARMeilleure.Instructions.InstEmitHelper; 8 using static ARMeilleure.IntermediateRepresentation.Operand.Factory; 9 10 namespace ARMeilleure.Instructions 11 { 12 static partial class InstEmit32 13 { 14 public static void Mcr(ArmEmitterContext context) 15 { 16 OpCode32System op = (OpCode32System)context.CurrOp; 17 18 if (op.Coproc != 15 || op.Opc1 != 0) 19 { 20 InstEmit.Und(context); 21 22 return; 23 } 24 25 switch (op.CRn) 26 { 27 case 13: // Process and Thread Info. 28 if (op.CRm != 0) 29 { 30 throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X} at 0x{op.Address:X} (0x{op.RawOpCode:X})."); 31 } 32 33 switch (op.Opc2) 34 { 35 case 2: 36 EmitSetTpidrEl0(context); 37 return; 38 39 default: 40 throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X} at 0x{op.Address:X} (0x{op.RawOpCode:X})."); 41 } 42 43 case 7: 44 switch (op.CRm) // Cache and Memory barrier. 45 { 46 case 10: 47 switch (op.Opc2) 48 { 49 case 5: // Data Memory Barrier Register. 50 return; // No-op. 51 52 default: 53 throw new NotImplementedException($"Unknown MRC Opc2 0x{op.Opc2:X16} at 0x{op.Address:X16} (0x{op.RawOpCode:X})."); 54 } 55 56 default: 57 throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X16} at 0x{op.Address:X16} (0x{op.RawOpCode:X})."); 58 } 59 60 default: 61 throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X8} at 0x{op.Address:X16}."); 62 } 63 } 64 65 public static void Mrc(ArmEmitterContext context) 66 { 67 OpCode32System op = (OpCode32System)context.CurrOp; 68 69 if (op.Coproc != 15 || op.Opc1 != 0) 70 { 71 InstEmit.Und(context); 72 73 return; 74 } 75 76 Operand result; 77 78 switch (op.CRn) 79 { 80 case 13: // Process and Thread Info. 81 if (op.CRm != 0) 82 { 83 throw new NotImplementedException($"Unknown MRC CRm 0x{op.CRm:X} at 0x{op.Address:X} (0x{op.RawOpCode:X})."); 84 } 85 86 result = op.Opc2 switch 87 { 88 2 => EmitGetTpidrEl0(context), 89 3 => EmitGetTpidrroEl0(context), 90 _ => throw new NotImplementedException( 91 $"Unknown MRC Opc2 0x{op.Opc2:X} at 0x{op.Address:X} (0x{op.RawOpCode:X})."), 92 }; 93 94 break; 95 96 default: 97 throw new NotImplementedException($"Unknown MRC 0x{op.RawOpCode:X} at 0x{op.Address:X}."); 98 } 99 100 if (op.Rt == RegisterAlias.Aarch32Pc) 101 { 102 // Special behavior: copy NZCV flags into APSR. 103 EmitSetNzcv(context, result); 104 105 return; 106 } 107 else 108 { 109 SetIntA32(context, op.Rt, result); 110 } 111 } 112 113 public static void Mrrc(ArmEmitterContext context) 114 { 115 OpCode32System op = (OpCode32System)context.CurrOp; 116 117 if (op.Coproc != 15) 118 { 119 InstEmit.Und(context); 120 121 return; 122 } 123 124 int opc = op.MrrcOp; 125 MethodInfo info = op.CRm switch 126 { 127 // Timer. 128 14 => opc switch 129 { 130 0 => typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)), 131 _ => throw new NotImplementedException($"Unknown MRRC Opc1 0x{opc:X} at 0x{op.Address:X} (0x{op.RawOpCode:X})."), 132 }, 133 _ => throw new NotImplementedException($"Unknown MRRC 0x{op.RawOpCode:X} at 0x{op.Address:X}."), 134 }; 135 Operand result = context.Call(info); 136 137 SetIntA32(context, op.Rt, context.ConvertI64ToI32(result)); 138 SetIntA32(context, op.CRn, context.ConvertI64ToI32(context.ShiftRightUI(result, Const(32)))); 139 } 140 141 public static void Mrs(ArmEmitterContext context) 142 { 143 OpCode32Mrs op = (OpCode32Mrs)context.CurrOp; 144 145 if (op.R) 146 { 147 throw new NotImplementedException("SPSR"); 148 } 149 else 150 { 151 Operand spsr = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag)); 152 spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag))); 153 spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag))); 154 spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag))); 155 spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag))); 156 157 // TODO: Remaining flags. 158 159 SetIntA32(context, op.Rd, spsr); 160 } 161 } 162 163 public static void Msr(ArmEmitterContext context) 164 { 165 OpCode32MsrReg op = (OpCode32MsrReg)context.CurrOp; 166 167 if (op.R) 168 { 169 throw new NotImplementedException("SPSR"); 170 } 171 else 172 { 173 if ((op.Mask & 8) != 0) 174 { 175 Operand value = GetIntA32(context, op.Rn); 176 177 EmitSetNzcv(context, value); 178 179 Operand q = context.BitwiseAnd(context.ShiftRightUI(value, Const((int)PState.QFlag)), Const(1)); 180 181 SetFlag(context, PState.QFlag, q); 182 } 183 184 if ((op.Mask & 4) != 0) 185 { 186 throw new NotImplementedException("APSR_g"); 187 } 188 189 if ((op.Mask & 2) != 0) 190 { 191 throw new NotImplementedException("CPSR_x"); 192 } 193 194 if ((op.Mask & 1) != 0) 195 { 196 throw new NotImplementedException("CPSR_c"); 197 } 198 } 199 } 200 201 public static void Nop(ArmEmitterContext context) { } 202 203 public static void Vmrs(ArmEmitterContext context) 204 { 205 OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp; 206 207 if (op.Rt == RegisterAlias.Aarch32Pc && op.Sreg == 0b0001) 208 { 209 // Special behavior: copy NZCV flags into APSR. 210 SetFlag(context, PState.VFlag, GetFpFlag(FPState.VFlag)); 211 SetFlag(context, PState.CFlag, GetFpFlag(FPState.CFlag)); 212 SetFlag(context, PState.ZFlag, GetFpFlag(FPState.ZFlag)); 213 SetFlag(context, PState.NFlag, GetFpFlag(FPState.NFlag)); 214 215 return; 216 } 217 218 switch (op.Sreg) 219 { 220 case 0b0000: // FPSID 221 throw new NotImplementedException("Supervisor Only"); 222 case 0b0001: // FPSCR 223 EmitGetFpscr(context); 224 return; 225 case 0b0101: // MVFR2 226 throw new NotImplementedException("MVFR2"); 227 case 0b0110: // MVFR1 228 throw new NotImplementedException("MVFR1"); 229 case 0b0111: // MVFR0 230 throw new NotImplementedException("MVFR0"); 231 case 0b1000: // FPEXC 232 throw new NotImplementedException("Supervisor Only"); 233 default: 234 throw new NotImplementedException($"Unknown VMRS 0x{op.RawOpCode:X} at 0x{op.Address:X}."); 235 } 236 } 237 238 public static void Vmsr(ArmEmitterContext context) 239 { 240 OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp; 241 242 switch (op.Sreg) 243 { 244 case 0b0000: // FPSID 245 throw new NotImplementedException("Supervisor Only"); 246 case 0b0001: // FPSCR 247 EmitSetFpscr(context); 248 return; 249 case 0b0101: // MVFR2 250 throw new NotImplementedException("MVFR2"); 251 case 0b0110: // MVFR1 252 throw new NotImplementedException("MVFR1"); 253 case 0b0111: // MVFR0 254 throw new NotImplementedException("MVFR0"); 255 case 0b1000: // FPEXC 256 throw new NotImplementedException("Supervisor Only"); 257 default: 258 throw new NotImplementedException($"Unknown VMSR 0x{op.RawOpCode:X} at 0x{op.Address:X}."); 259 } 260 } 261 262 private static void EmitSetNzcv(ArmEmitterContext context, Operand t) 263 { 264 Operand v = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.VFlag)), Const(1)); 265 Operand c = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.CFlag)), Const(1)); 266 Operand z = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.ZFlag)), Const(1)); 267 Operand n = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.NFlag)), Const(1)); 268 269 SetFlag(context, PState.VFlag, v); 270 SetFlag(context, PState.CFlag, c); 271 SetFlag(context, PState.ZFlag, z); 272 SetFlag(context, PState.NFlag, n); 273 } 274 275 private static void EmitGetFpscr(ArmEmitterContext context) 276 { 277 OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp; 278 279 Operand fpscr = Const(0); 280 281 for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) 282 { 283 if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag))) 284 { 285 fpscr = context.BitwiseOr(fpscr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag))); 286 } 287 } 288 289 SetIntA32(context, op.Rt, fpscr); 290 } 291 292 private static void EmitSetFpscr(ArmEmitterContext context) 293 { 294 OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp; 295 296 Operand fpscr = GetIntA32(context, op.Rt); 297 298 for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++) 299 { 300 if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag))) 301 { 302 SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpscr, Const(flag)), Const(1))); 303 } 304 } 305 306 context.UpdateArmFpMode(); 307 } 308 309 private static Operand EmitGetTpidrEl0(ArmEmitterContext context) 310 { 311 OpCode32System op = (OpCode32System)context.CurrOp; 312 313 Operand nativeContext = context.LoadArgument(OperandType.I64, 0); 314 315 return context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset()))); 316 } 317 318 private static Operand EmitGetTpidrroEl0(ArmEmitterContext context) 319 { 320 OpCode32System op = (OpCode32System)context.CurrOp; 321 322 Operand nativeContext = context.LoadArgument(OperandType.I64, 0); 323 324 return context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrroEl0Offset()))); 325 } 326 327 private static void EmitSetTpidrEl0(ArmEmitterContext context) 328 { 329 OpCode32System op = (OpCode32System)context.CurrOp; 330 331 Operand value = GetIntA32(context, op.Rt); 332 333 Operand nativeContext = context.LoadArgument(OperandType.I64, 0); 334 335 context.Store(context.Add(nativeContext, Const((ulong)NativeContext.GetTpidrEl0Offset())), context.ZeroExtend32(OperandType.I64, value)); 336 } 337 } 338 }