/ src / ARMeilleure / Instructions / InstEmitMemory.cs
InstEmitMemory.cs
  1  using ARMeilleure.Decoders;
  2  using ARMeilleure.IntermediateRepresentation;
  3  using ARMeilleure.Translation;
  4  
  5  using static ARMeilleure.Instructions.InstEmitHelper;
  6  using static ARMeilleure.Instructions.InstEmitMemoryHelper;
  7  using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
  8  
  9  namespace ARMeilleure.Instructions
 10  {
 11      static partial class InstEmit
 12      {
 13          public static void Adr(ArmEmitterContext context)
 14          {
 15              OpCodeAdr op = (OpCodeAdr)context.CurrOp;
 16  
 17              SetIntOrZR(context, op.Rd, Const(op.Address + (ulong)op.Immediate));
 18          }
 19  
 20          public static void Adrp(ArmEmitterContext context)
 21          {
 22              OpCodeAdr op = (OpCodeAdr)context.CurrOp;
 23  
 24              ulong address = (op.Address & ~0xfffUL) + ((ulong)op.Immediate << 12);
 25  
 26              SetIntOrZR(context, op.Rd, Const(address));
 27          }
 28  
 29          public static void Ldr(ArmEmitterContext context) => EmitLdr(context, signed: false);
 30          public static void Ldrs(ArmEmitterContext context) => EmitLdr(context, signed: true);
 31  
 32          private static void EmitLdr(ArmEmitterContext context, bool signed)
 33          {
 34              OpCodeMem op = (OpCodeMem)context.CurrOp;
 35  
 36              Operand address = GetAddress(context);
 37  
 38              if (signed && op.Extend64)
 39              {
 40                  EmitLoadSx64(context, address, op.Rt, op.Size);
 41              }
 42              else if (signed)
 43              {
 44                  EmitLoadSx32(context, address, op.Rt, op.Size);
 45              }
 46              else
 47              {
 48                  EmitLoadZx(context, address, op.Rt, op.Size);
 49              }
 50  
 51              EmitWBackIfNeeded(context, address);
 52          }
 53  
 54          public static void Ldr_Literal(ArmEmitterContext context)
 55          {
 56              IOpCodeLit op = (IOpCodeLit)context.CurrOp;
 57  
 58              if (op.Prefetch)
 59              {
 60                  return;
 61              }
 62  
 63              if (op.Signed)
 64              {
 65                  EmitLoadSx64(context, Const(op.Immediate), op.Rt, op.Size);
 66              }
 67              else
 68              {
 69                  EmitLoadZx(context, Const(op.Immediate), op.Rt, op.Size);
 70              }
 71          }
 72  
 73          public static void Ldp(ArmEmitterContext context)
 74          {
 75              OpCodeMemPair op = (OpCodeMemPair)context.CurrOp;
 76  
 77              void EmitLoad(int rt, Operand ldAddr)
 78              {
 79                  if (op.Extend64)
 80                  {
 81                      EmitLoadSx64(context, ldAddr, rt, op.Size);
 82                  }
 83                  else
 84                  {
 85                      EmitLoadZx(context, ldAddr, rt, op.Size);
 86                  }
 87              }
 88  
 89              Operand address = GetAddress(context);
 90              Operand address2 = GetAddress(context, 1L << op.Size);
 91  
 92              EmitLoad(op.Rt, address);
 93              EmitLoad(op.Rt2, address2);
 94  
 95              EmitWBackIfNeeded(context, address);
 96          }
 97  
 98          public static void Str(ArmEmitterContext context)
 99          {
100              OpCodeMem op = (OpCodeMem)context.CurrOp;
101  
102              Operand address = GetAddress(context);
103  
104              EmitStore(context, address, op.Rt, op.Size);
105  
106              EmitWBackIfNeeded(context, address);
107          }
108  
109          public static void Stp(ArmEmitterContext context)
110          {
111              OpCodeMemPair op = (OpCodeMemPair)context.CurrOp;
112  
113              Operand address = GetAddress(context);
114              Operand address2 = GetAddress(context, 1L << op.Size);
115  
116              EmitStore(context, address, op.Rt, op.Size);
117              EmitStore(context, address2, op.Rt2, op.Size);
118  
119              EmitWBackIfNeeded(context, address);
120          }
121  
122          private static Operand GetAddress(ArmEmitterContext context, long addend = 0)
123          {
124              Operand address = default;
125  
126              switch (context.CurrOp)
127              {
128                  case OpCodeMemImm op:
129                      {
130                          address = context.Copy(GetIntOrSP(context, op.Rn));
131  
132                          // Pre-indexing.
133                          if (!op.PostIdx)
134                          {
135                              address = context.Add(address, Const(op.Immediate + addend));
136                          }
137                          else if (addend != 0)
138                          {
139                              address = context.Add(address, Const(addend));
140                          }
141  
142                          break;
143                      }
144  
145                  case OpCodeMemReg op:
146                      {
147                          Operand n = GetIntOrSP(context, op.Rn);
148  
149                          Operand m = GetExtendedM(context, op.Rm, op.IntType);
150  
151                          if (op.Shift)
152                          {
153                              m = context.ShiftLeft(m, Const(op.Size));
154                          }
155  
156                          address = context.Add(n, m);
157  
158                          if (addend != 0)
159                          {
160                              address = context.Add(address, Const(addend));
161                          }
162  
163                          break;
164                      }
165              }
166  
167              return address;
168          }
169  
170          private static void EmitWBackIfNeeded(ArmEmitterContext context, Operand address)
171          {
172              // Check whenever the current OpCode has post-indexed write back, if so write it.
173              if (context.CurrOp is OpCodeMemImm op && op.WBack)
174              {
175                  if (op.PostIdx)
176                  {
177                      address = context.Add(address, Const(op.Immediate));
178                  }
179  
180                  SetIntOrSP(context, op.Rn, address);
181              }
182          }
183      }
184  }