/ src / ARMeilleure / Instructions / InstEmitFlow32.cs
InstEmitFlow32.cs
  1  using ARMeilleure.Decoders;
  2  using ARMeilleure.IntermediateRepresentation;
  3  using ARMeilleure.State;
  4  using ARMeilleure.Translation;
  5  
  6  using static ARMeilleure.Instructions.InstEmitFlowHelper;
  7  using static ARMeilleure.Instructions.InstEmitHelper;
  8  using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
  9  
 10  namespace ARMeilleure.Instructions
 11  {
 12      static partial class InstEmit32
 13      {
 14          public static void B(ArmEmitterContext context)
 15          {
 16              IOpCode32BImm op = (IOpCode32BImm)context.CurrOp;
 17  
 18              context.Branch(context.GetLabel((ulong)op.Immediate));
 19          }
 20  
 21          public static void Bl(ArmEmitterContext context)
 22          {
 23              Blx(context, x: false);
 24          }
 25  
 26          public static void Blx(ArmEmitterContext context)
 27          {
 28              Blx(context, x: true);
 29          }
 30  
 31          private static void Blx(ArmEmitterContext context, bool x)
 32          {
 33              IOpCode32BImm op = (IOpCode32BImm)context.CurrOp;
 34  
 35              uint pc = op.GetPc();
 36  
 37              bool isThumb = ((OpCode32)context.CurrOp).IsThumb;
 38  
 39              uint currentPc = isThumb
 40                  ? pc | 1
 41                  : pc - 4;
 42  
 43              SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
 44  
 45              // If x is true, then this is a branch with link and exchange.
 46              // In this case we need to swap the mode between Arm <-> Thumb.
 47              if (x)
 48              {
 49                  SetFlag(context, PState.TFlag, Const(isThumb ? 0 : 1));
 50              }
 51  
 52              EmitCall(context, (ulong)op.Immediate);
 53          }
 54  
 55          public static void Blxr(ArmEmitterContext context)
 56          {
 57              IOpCode32BReg op = (IOpCode32BReg)context.CurrOp;
 58  
 59              uint pc = op.GetPc();
 60  
 61              Operand addr = context.Copy(GetIntA32(context, op.Rm));
 62              Operand bitOne = context.BitwiseAnd(addr, Const(1));
 63  
 64              bool isThumb = ((OpCode32)context.CurrOp).IsThumb;
 65  
 66              uint currentPc = isThumb
 67                  ? (pc - 2) | 1
 68                  : pc - 4;
 69  
 70              SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
 71  
 72              SetFlag(context, PState.TFlag, bitOne);
 73  
 74              EmitBxWritePc(context, addr);
 75          }
 76  
 77          public static void Bx(ArmEmitterContext context)
 78          {
 79              IOpCode32BReg op = (IOpCode32BReg)context.CurrOp;
 80  
 81              EmitBxWritePc(context, GetIntA32(context, op.Rm), op.Rm);
 82          }
 83  
 84          public static void Cbnz(ArmEmitterContext context) => EmitCb(context, onNotZero: true);
 85          public static void Cbz(ArmEmitterContext context) => EmitCb(context, onNotZero: false);
 86  
 87          private static void EmitCb(ArmEmitterContext context, bool onNotZero)
 88          {
 89              OpCodeT16BImmCmp op = (OpCodeT16BImmCmp)context.CurrOp;
 90  
 91              Operand value = GetIntA32(context, op.Rn);
 92              Operand lblTarget = context.GetLabel((ulong)op.Immediate);
 93  
 94              if (onNotZero)
 95              {
 96                  context.BranchIfTrue(lblTarget, value);
 97              }
 98              else
 99              {
100                  context.BranchIfFalse(lblTarget, value);
101              }
102          }
103  
104          public static void It(ArmEmitterContext context)
105          {
106              OpCodeT16IfThen op = (OpCodeT16IfThen)context.CurrOp;
107  
108              context.SetIfThenBlockState(op.IfThenBlockConds);
109          }
110  
111          public static void Tbb(ArmEmitterContext context) => EmitTb(context, halfword: false);
112          public static void Tbh(ArmEmitterContext context) => EmitTb(context, halfword: true);
113  
114          private static void EmitTb(ArmEmitterContext context, bool halfword)
115          {
116              OpCodeT32Tb op = (OpCodeT32Tb)context.CurrOp;
117  
118              Operand halfwords;
119  
120              if (halfword)
121              {
122                  Operand address = context.Add(GetIntA32(context, op.Rn), context.ShiftLeft(GetIntA32(context, op.Rm), Const(1)));
123                  halfwords = InstEmitMemoryHelper.EmitReadInt(context, address, 1);
124              }
125              else
126              {
127                  Operand address = context.Add(GetIntA32(context, op.Rn), GetIntA32(context, op.Rm));
128                  halfwords = InstEmitMemoryHelper.EmitReadIntAligned(context, address, 0);
129              }
130  
131              Operand targetAddress = context.Add(Const((int)op.GetPc()), context.ShiftLeft(halfwords, Const(1)));
132  
133              EmitVirtualJump(context, targetAddress, isReturn: false);
134          }
135      }
136  }