InstEmitMemory32.cs
1 using ARMeilleure.Decoders; 2 using ARMeilleure.IntermediateRepresentation; 3 using ARMeilleure.State; 4 using ARMeilleure.Translation; 5 using System; 6 using static ARMeilleure.Instructions.InstEmitHelper; 7 using static ARMeilleure.Instructions.InstEmitMemoryHelper; 8 using static ARMeilleure.IntermediateRepresentation.Operand.Factory; 9 10 namespace ARMeilleure.Instructions 11 { 12 static partial class InstEmit32 13 { 14 private const int ByteSizeLog2 = 0; 15 private const int HWordSizeLog2 = 1; 16 private const int WordSizeLog2 = 2; 17 private const int DWordSizeLog2 = 3; 18 19 [Flags] 20 enum AccessType 21 { 22 Store = 0, 23 Signed = 1, 24 Load = 2, 25 Ordered = 4, 26 Exclusive = 8, 27 28 LoadZx = Load, 29 LoadSx = Load | Signed, 30 } 31 32 public static void Ldm(ArmEmitterContext context) 33 { 34 IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp; 35 36 Operand n = GetIntA32(context, op.Rn); 37 38 Operand baseAddress = context.Add(n, Const(op.Offset)); 39 40 bool writesToPc = (op.RegisterMask & (1 << RegisterAlias.Aarch32Pc)) != 0; 41 42 bool writeBack = op.PostOffset != 0 && (op.Rn != RegisterAlias.Aarch32Pc || !writesToPc); 43 44 if (writeBack) 45 { 46 SetIntA32(context, op.Rn, context.Add(n, Const(op.PostOffset))); 47 } 48 49 int mask = op.RegisterMask; 50 int offset = 0; 51 52 for (int register = 0; mask != 0; mask >>= 1, register++) 53 { 54 if ((mask & 1) != 0) 55 { 56 Operand address = context.Add(baseAddress, Const(offset)); 57 58 EmitLoadZx(context, address, register, WordSizeLog2); 59 60 offset += 4; 61 } 62 } 63 } 64 65 public static void Ldr(ArmEmitterContext context) 66 { 67 EmitLoadOrStore(context, WordSizeLog2, AccessType.LoadZx); 68 } 69 70 public static void Ldrb(ArmEmitterContext context) 71 { 72 EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadZx); 73 } 74 75 public static void Ldrd(ArmEmitterContext context) 76 { 77 EmitLoadOrStore(context, DWordSizeLog2, AccessType.LoadZx); 78 } 79 80 public static void Ldrh(ArmEmitterContext context) 81 { 82 EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadZx); 83 } 84 85 public static void Ldrsb(ArmEmitterContext context) 86 { 87 EmitLoadOrStore(context, ByteSizeLog2, AccessType.LoadSx); 88 } 89 90 public static void Ldrsh(ArmEmitterContext context) 91 { 92 EmitLoadOrStore(context, HWordSizeLog2, AccessType.LoadSx); 93 } 94 95 public static void Stm(ArmEmitterContext context) 96 { 97 IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp; 98 99 Operand n = context.Copy(GetIntA32(context, op.Rn)); 100 101 Operand baseAddress = context.Add(n, Const(op.Offset)); 102 103 int mask = op.RegisterMask; 104 int offset = 0; 105 106 for (int register = 0; mask != 0; mask >>= 1, register++) 107 { 108 if ((mask & 1) != 0) 109 { 110 Operand address = context.Add(baseAddress, Const(offset)); 111 112 EmitStore(context, address, register, WordSizeLog2); 113 114 // Note: If Rn is also specified on the register list, 115 // and Rn is the first register on this list, then the 116 // value that is written to memory is the unmodified value, 117 // before the write back. If it is on the list, but it's 118 // not the first one, then the value written to memory 119 // varies between CPUs. 120 if (offset == 0 && op.PostOffset != 0) 121 { 122 // Emit write back after the first write. 123 SetIntA32(context, op.Rn, context.Add(n, Const(op.PostOffset))); 124 } 125 126 offset += 4; 127 } 128 } 129 } 130 131 public static void Str(ArmEmitterContext context) 132 { 133 EmitLoadOrStore(context, WordSizeLog2, AccessType.Store); 134 } 135 136 public static void Strb(ArmEmitterContext context) 137 { 138 EmitLoadOrStore(context, ByteSizeLog2, AccessType.Store); 139 } 140 141 public static void Strd(ArmEmitterContext context) 142 { 143 EmitLoadOrStore(context, DWordSizeLog2, AccessType.Store); 144 } 145 146 public static void Strh(ArmEmitterContext context) 147 { 148 EmitLoadOrStore(context, HWordSizeLog2, AccessType.Store); 149 } 150 151 private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType) 152 { 153 IOpCode32Mem op = (IOpCode32Mem)context.CurrOp; 154 155 Operand n = context.Copy(GetIntA32AlignedPC(context, op.Rn)); 156 Operand m = GetMemM(context, setCarry: false); 157 158 Operand temp = default; 159 160 if (op.Index || op.WBack) 161 { 162 temp = op.Add 163 ? context.Add(n, m) 164 : context.Subtract(n, m); 165 } 166 167 if (op.WBack) 168 { 169 SetIntA32(context, op.Rn, temp); 170 } 171 172 Operand address; 173 174 if (op.Index) 175 { 176 address = temp; 177 } 178 else 179 { 180 address = n; 181 } 182 183 if ((accType & AccessType.Load) != 0) 184 { 185 void Load(int rt, int offs, int loadSize) 186 { 187 Operand addr = context.Add(address, Const(offs)); 188 189 if ((accType & AccessType.Signed) != 0) 190 { 191 EmitLoadSx32(context, addr, rt, loadSize); 192 } 193 else 194 { 195 EmitLoadZx(context, addr, rt, loadSize); 196 } 197 } 198 199 if (size == DWordSizeLog2) 200 { 201 Operand lblBigEndian = Label(); 202 Operand lblEnd = Label(); 203 204 context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); 205 206 Load(op.Rt, 0, WordSizeLog2); 207 Load(op.Rt2, 4, WordSizeLog2); 208 209 context.Branch(lblEnd); 210 211 context.MarkLabel(lblBigEndian); 212 213 Load(op.Rt2, 0, WordSizeLog2); 214 Load(op.Rt, 4, WordSizeLog2); 215 216 context.MarkLabel(lblEnd); 217 } 218 else 219 { 220 Load(op.Rt, 0, size); 221 } 222 } 223 else 224 { 225 void Store(int rt, int offs, int storeSize) 226 { 227 Operand addr = context.Add(address, Const(offs)); 228 229 EmitStore(context, addr, rt, storeSize); 230 } 231 232 if (size == DWordSizeLog2) 233 { 234 Operand lblBigEndian = Label(); 235 Operand lblEnd = Label(); 236 237 context.BranchIfTrue(lblBigEndian, GetFlag(PState.EFlag)); 238 239 Store(op.Rt, 0, WordSizeLog2); 240 Store(op.Rt2, 4, WordSizeLog2); 241 242 context.Branch(lblEnd); 243 244 context.MarkLabel(lblBigEndian); 245 246 Store(op.Rt2, 0, WordSizeLog2); 247 Store(op.Rt, 4, WordSizeLog2); 248 249 context.MarkLabel(lblEnd); 250 } 251 else 252 { 253 Store(op.Rt, 0, size); 254 } 255 } 256 } 257 258 public static void Adr(ArmEmitterContext context) 259 { 260 IOpCode32Adr op = (IOpCode32Adr)context.CurrOp; 261 SetIntA32(context, op.Rd, Const(op.Immediate)); 262 } 263 } 264 }