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 }