aboutsummaryrefslogtreecommitdiff
path: root/src/ARMeilleure/Instructions/InstEmitFlow32.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ARMeilleure/Instructions/InstEmitFlow32.cs')
-rw-r--r--src/ARMeilleure/Instructions/InstEmitFlow32.cs136
1 files changed, 136 insertions, 0 deletions
diff --git a/src/ARMeilleure/Instructions/InstEmitFlow32.cs b/src/ARMeilleure/Instructions/InstEmitFlow32.cs
new file mode 100644
index 00000000..3a7707ee
--- /dev/null
+++ b/src/ARMeilleure/Instructions/InstEmitFlow32.cs
@@ -0,0 +1,136 @@
+using ARMeilleure.Decoders;
+using ARMeilleure.IntermediateRepresentation;
+using ARMeilleure.State;
+using ARMeilleure.Translation;
+
+using static ARMeilleure.Instructions.InstEmitFlowHelper;
+using static ARMeilleure.Instructions.InstEmitHelper;
+using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
+
+namespace ARMeilleure.Instructions
+{
+ static partial class InstEmit32
+ {
+ public static void B(ArmEmitterContext context)
+ {
+ IOpCode32BImm op = (IOpCode32BImm)context.CurrOp;
+
+ context.Branch(context.GetLabel((ulong)op.Immediate));
+ }
+
+ public static void Bl(ArmEmitterContext context)
+ {
+ Blx(context, x: false);
+ }
+
+ public static void Blx(ArmEmitterContext context)
+ {
+ Blx(context, x: true);
+ }
+
+ private static void Blx(ArmEmitterContext context, bool x)
+ {
+ IOpCode32BImm op = (IOpCode32BImm)context.CurrOp;
+
+ uint pc = op.GetPc();
+
+ bool isThumb = ((OpCode32)context.CurrOp).IsThumb;
+
+ uint currentPc = isThumb
+ ? pc | 1
+ : pc - 4;
+
+ SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
+
+ // If x is true, then this is a branch with link and exchange.
+ // In this case we need to swap the mode between Arm <-> Thumb.
+ if (x)
+ {
+ SetFlag(context, PState.TFlag, Const(isThumb ? 0 : 1));
+ }
+
+ EmitCall(context, (ulong)op.Immediate);
+ }
+
+ public static void Blxr(ArmEmitterContext context)
+ {
+ IOpCode32BReg op = (IOpCode32BReg)context.CurrOp;
+
+ uint pc = op.GetPc();
+
+ Operand addr = context.Copy(GetIntA32(context, op.Rm));
+ Operand bitOne = context.BitwiseAnd(addr, Const(1));
+
+ bool isThumb = ((OpCode32)context.CurrOp).IsThumb;
+
+ uint currentPc = isThumb
+ ? (pc - 2) | 1
+ : pc - 4;
+
+ SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
+
+ SetFlag(context, PState.TFlag, bitOne);
+
+ EmitBxWritePc(context, addr);
+ }
+
+ public static void Bx(ArmEmitterContext context)
+ {
+ IOpCode32BReg op = (IOpCode32BReg)context.CurrOp;
+
+ EmitBxWritePc(context, GetIntA32(context, op.Rm), op.Rm);
+ }
+
+ public static void Cbnz(ArmEmitterContext context) => EmitCb(context, onNotZero: true);
+ public static void Cbz(ArmEmitterContext context) => EmitCb(context, onNotZero: false);
+
+ private static void EmitCb(ArmEmitterContext context, bool onNotZero)
+ {
+ OpCodeT16BImmCmp op = (OpCodeT16BImmCmp)context.CurrOp;
+
+ Operand value = GetIntA32(context, op.Rn);
+ Operand lblTarget = context.GetLabel((ulong)op.Immediate);
+
+ if (onNotZero)
+ {
+ context.BranchIfTrue(lblTarget, value);
+ }
+ else
+ {
+ context.BranchIfFalse(lblTarget, value);
+ }
+ }
+
+ public static void It(ArmEmitterContext context)
+ {
+ OpCodeT16IfThen op = (OpCodeT16IfThen)context.CurrOp;
+
+ context.SetIfThenBlockState(op.IfThenBlockConds);
+ }
+
+ public static void Tbb(ArmEmitterContext context) => EmitTb(context, halfword: false);
+ public static void Tbh(ArmEmitterContext context) => EmitTb(context, halfword: true);
+
+ private static void EmitTb(ArmEmitterContext context, bool halfword)
+ {
+ OpCodeT32Tb op = (OpCodeT32Tb)context.CurrOp;
+
+ Operand halfwords;
+
+ if (halfword)
+ {
+ Operand address = context.Add(GetIntA32(context, op.Rn), context.ShiftLeft(GetIntA32(context, op.Rm), Const(1)));
+ halfwords = InstEmitMemoryHelper.EmitReadInt(context, address, 1);
+ }
+ else
+ {
+ Operand address = context.Add(GetIntA32(context, op.Rn), GetIntA32(context, op.Rm));
+ halfwords = InstEmitMemoryHelper.EmitReadIntAligned(context, address, 0);
+ }
+
+ Operand targetAddress = context.Add(Const((int)op.GetPc()), context.ShiftLeft(halfwords, Const(1)));
+
+ EmitVirtualJump(context, targetAddress, isReturn: false);
+ }
+ }
+} \ No newline at end of file