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 }