InstEmitMemoryEx32.cs
1 using ARMeilleure.Decoders; 2 using ARMeilleure.IntermediateRepresentation; 3 using ARMeilleure.State; 4 using ARMeilleure.Translation; 5 6 using static ARMeilleure.Instructions.InstEmitHelper; 7 using static ARMeilleure.Instructions.InstEmitMemoryExHelper; 8 using static ARMeilleure.IntermediateRepresentation.Operand.Factory; 9 10 namespace ARMeilleure.Instructions 11 { 12 static partial class InstEmit32 13 { 14 public static void Clrex(ArmEmitterContext context) 15 { 16 EmitClearExclusive(context); 17 } 18 19 public static void Csdb(ArmEmitterContext context) 20 { 21 // Execute as no-op. 22 } 23 24 public static void Dmb(ArmEmitterContext context) => EmitBarrier(context); 25 26 public static void Dsb(ArmEmitterContext context) => EmitBarrier(context); 27 28 public static void Ldrex(ArmEmitterContext context) 29 { 30 EmitExLoadOrStore(context, WordSizeLog2, AccessType.LoadZx | AccessType.Exclusive); 31 } 32 33 public static void Ldrexb(ArmEmitterContext context) 34 { 35 EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Exclusive); 36 } 37 38 public static void Ldrexd(ArmEmitterContext context) 39 { 40 EmitExLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive); 41 } 42 43 public static void Ldrexh(ArmEmitterContext context) 44 { 45 EmitExLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive); 46 } 47 48 public static void Lda(ArmEmitterContext context) 49 { 50 EmitExLoadOrStore(context, WordSizeLog2, AccessType.LoadZx | AccessType.Ordered); 51 } 52 53 public static void Ldab(ArmEmitterContext context) 54 { 55 EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Ordered); 56 } 57 58 public static void Ldaex(ArmEmitterContext context) 59 { 60 EmitExLoadOrStore(context, WordSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered); 61 } 62 63 public static void Ldaexb(ArmEmitterContext context) 64 { 65 EmitExLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered); 66 } 67 68 public static void Ldaexd(ArmEmitterContext context) 69 { 70 EmitExLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered); 71 } 72 73 public static void Ldaexh(ArmEmitterContext context) 74 { 75 EmitExLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx | AccessType.Exclusive | AccessType.Ordered); 76 } 77 78 public static void Ldah(ArmEmitterContext context) 79 { 80 EmitExLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx | AccessType.Ordered); 81 } 82 83 // Stores. 84 85 public static void Strex(ArmEmitterContext context) 86 { 87 EmitExLoadOrStore(context, WordSizeLog2, AccessType.Store | AccessType.Exclusive); 88 } 89 90 public static void Strexb(ArmEmitterContext context) 91 { 92 EmitExLoadOrStore(context, ByteSizeLog2, AccessType.Store | AccessType.Exclusive); 93 } 94 95 public static void Strexd(ArmEmitterContext context) 96 { 97 EmitExLoadOrStore(context, DWordSizeLog2, AccessType.Store | AccessType.Exclusive); 98 } 99 100 public static void Strexh(ArmEmitterContext context) 101 { 102 EmitExLoadOrStore(context, HWordSizeLog2, AccessType.Store | AccessType.Exclusive); 103 } 104 105 public static void Stl(ArmEmitterContext context) 106 { 107 EmitExLoadOrStore(context, WordSizeLog2, AccessType.Store | AccessType.Ordered); 108 } 109 110 public static void Stlb(ArmEmitterContext context) 111 { 112 EmitExLoadOrStore(context, ByteSizeLog2, AccessType.Store | AccessType.Ordered); 113 } 114 115 public static void Stlex(ArmEmitterContext context) 116 { 117 EmitExLoadOrStore(context, WordSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered); 118 } 119 120 public static void Stlexb(ArmEmitterContext context) 121 { 122 EmitExLoadOrStore(context, ByteSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered); 123 } 124 125 public static void Stlexd(ArmEmitterContext context) 126 { 127 EmitExLoadOrStore(context, DWordSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered); 128 } 129 130 public static void Stlexh(ArmEmitterContext context) 131 { 132 EmitExLoadOrStore(context, HWordSizeLog2, AccessType.Store | AccessType.Exclusive | AccessType.Ordered); 133 } 134 135 public static void Stlh(ArmEmitterContext context) 136 { 137 EmitExLoadOrStore(context, HWordSizeLog2, AccessType.Store | AccessType.Ordered); 138 } 139 140 private static void EmitExLoadOrStore(ArmEmitterContext context, int size, AccessType accType) 141 { 142 IOpCode32MemEx op = (IOpCode32MemEx)context.CurrOp; 143 144 Operand address = context.Copy(GetIntA32(context, op.Rn)); 145 146 var exclusive = (accType & AccessType.Exclusive) != 0; 147 var ordered = (accType & AccessType.Ordered) != 0; 148 149 if ((accType & AccessType.Load) != 0) 150 { 151 if (ordered) 152 { 153 EmitBarrier(context); 154 } 155 156 if (size == DWordSizeLog2) 157 { 158 // Keep loads atomic - make the call to get the whole region and then decompose it into parts 159 // for the registers. 160 161 Operand value = EmitLoadExclusive(context, address, exclusive, size); 162 163 Operand valueLow = context.ConvertI64ToI32(value); 164 165 valueLow = context.ZeroExtend32(OperandType.I64, valueLow); 166 167 Operand valueHigh = context.ShiftRightUI(value, Const(32)); 168 169 Operand lblBigEndian = Label(); 170 Operand lblEnd = Label(); 171 172 context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); 173 174 SetIntA32(context, op.Rt, valueLow); 175 SetIntA32(context, op.Rt2, valueHigh); 176 177 context.Branch(lblEnd); 178 179 context.MarkLabel(lblBigEndian); 180 181 SetIntA32(context, op.Rt2, valueLow); 182 SetIntA32(context, op.Rt, valueHigh); 183 184 context.MarkLabel(lblEnd); 185 } 186 else 187 { 188 SetIntA32(context, op.Rt, EmitLoadExclusive(context, address, exclusive, size)); 189 } 190 } 191 else 192 { 193 if (size == DWordSizeLog2) 194 { 195 // Split the result into 2 words (based on endianness) 196 197 Operand lo = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt)); 198 Operand hi = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt2)); 199 200 Operand lblBigEndian = Label(); 201 Operand lblEnd = Label(); 202 203 context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); 204 205 Operand leResult = context.BitwiseOr(lo, context.ShiftLeft(hi, Const(32))); 206 EmitStoreExclusive(context, address, leResult, exclusive, size, op.Rd, a32: true); 207 208 context.Branch(lblEnd); 209 210 context.MarkLabel(lblBigEndian); 211 212 Operand beResult = context.BitwiseOr(hi, context.ShiftLeft(lo, Const(32))); 213 EmitStoreExclusive(context, address, beResult, exclusive, size, op.Rd, a32: true); 214 215 context.MarkLabel(lblEnd); 216 } 217 else 218 { 219 Operand value = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt)); 220 EmitStoreExclusive(context, address, value, exclusive, size, op.Rd, a32: true); 221 } 222 223 if (ordered) 224 { 225 EmitBarrier(context); 226 } 227 } 228 } 229 230 private static void EmitBarrier(ArmEmitterContext context) 231 { 232 // Note: This barrier is most likely not necessary, and probably 233 // doesn't make any difference since we need to do a ton of stuff 234 // (software MMU emulation) to read or write anything anyway. 235 } 236 } 237 }