/ src / ARMeilleure / Instructions / InstEmitMemoryEx32.cs
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  }