From a22b30c2942c68a1d31dc20e2f3ee199a749fa23 Mon Sep 17 00:00:00 2001 From: arthurchan35 Date: Mon, 12 Nov 2018 06:04:54 +0800 Subject: [PATCH] add blx_reg for A32 --- ChocolArm64/Decoders32/A32OpCodeBReg.cs | 14 +++++ .../Instructions32/A32InstInterpretFlow.cs | 53 +++++++++++++++++-- ChocolArm64/OpCodeTable.cs | 1 + 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 ChocolArm64/Decoders32/A32OpCodeBReg.cs diff --git a/ChocolArm64/Decoders32/A32OpCodeBReg.cs b/ChocolArm64/Decoders32/A32OpCodeBReg.cs new file mode 100644 index 0000000000..eee555c034 --- /dev/null +++ b/ChocolArm64/Decoders32/A32OpCodeBReg.cs @@ -0,0 +1,14 @@ +using ChocolArm64.Instructions; + +namespace ChocolArm64.Decoders32 +{ + class A32OpCodeBReg : A32OpCode + { + public int Rm { get; private set; } + + public A32OpCodeBReg(Inst inst, long position, int opCode) : base(inst, position, opCode) + { + Rm = (opCode >> 0) & 0xf; + } + } +} \ No newline at end of file diff --git a/ChocolArm64/Instructions32/A32InstInterpretFlow.cs b/ChocolArm64/Instructions32/A32InstInterpretFlow.cs index cdf7e4c6af..b839a6d402 100644 --- a/ChocolArm64/Instructions32/A32InstInterpretFlow.cs +++ b/ChocolArm64/Instructions32/A32InstInterpretFlow.cs @@ -21,15 +21,23 @@ namespace ChocolArm64.Instructions32 public static void Bl(CpuThreadState state, MemoryManager memory, OpCode64 opCode) { - Blx(state, memory, opCode, false); + Blx_Imm(state, memory, opCode, false); } public static void Blx(CpuThreadState state, MemoryManager memory, OpCode64 opCode) { - Blx(state, memory, opCode, true); + switch (opCode) + { + case A32OpCodeBImmAl op: + Blx_Imm(state, memory, op, true); + break; + case A32OpCodeBReg op: + Blx_Reg(state, memory, op); + break; + } } - public static void Blx(CpuThreadState state, MemoryManager memory, OpCode64 opCode, bool x) + private static void Blx_Imm(CpuThreadState state, MemoryManager memory, OpCode64 opCode, bool x) { A32OpCodeBImmAl op = (A32OpCodeBImmAl)opCode; @@ -60,11 +68,50 @@ namespace ChocolArm64.Instructions32 } } + private static void Blx_Reg(CpuThreadState state, MemoryManager memory, OpCode64 opCode) + { + A32OpCodeBReg op = (A32OpCodeBReg)opCode; + if (IsConditionTrue(state, op.Cond)) + { + uint pc = GetPc(state); + if (state.Thumb) + { + state.R14 = (pc - 2U) | 1; + } + else + { + state.R14 = pc - 4U; + } + BXWritePC(state, GetReg(state, op.Rm)); + } + } + private static void BranchWritePc(CpuThreadState state, uint pc) { state.R15 = state.Thumb ? pc & ~1U : pc & ~3U; } + + private static void BXWritePC(CpuThreadState state, uint pc) + { + if ((pc & 1U) == 1) + { + state.Thumb = true; + state.R15 = pc & ~1U; + } + else + { + state.Thumb = false; + // For branches to an unaligned PC counter in A32 state, the processor takes the branch + // and does one of: + // * Forces the address to be aligned + // * Leaves the PC unaligned, meaning the target generates a PC Alignment fault. + if ((pc & 2U) == 2 /*&& ConstrainUnpredictableBool()*/) + { + state.R15 = pc & ~2U; + } + } + } } } \ No newline at end of file diff --git a/ChocolArm64/OpCodeTable.cs b/ChocolArm64/OpCodeTable.cs index 6b1a724d55..263823ab59 100644 --- a/ChocolArm64/OpCodeTable.cs +++ b/ChocolArm64/OpCodeTable.cs @@ -17,6 +17,7 @@ namespace ChocolArm64 SetA32("<<<<1010xxxxxxxxxxxxxxxxxxxxxxxx", A32InstInterpret.B, typeof(A32OpCodeBImmAl)); SetA32("<<<<1011xxxxxxxxxxxxxxxxxxxxxxxx", A32InstInterpret.Bl, typeof(A32OpCodeBImmAl)); SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", A32InstInterpret.Blx, typeof(A32OpCodeBImmAl)); + SetA32("<<<<000100101111111111110011xxxx", A32InstInterpret.Blx, typeof(A32OpCodeBReg)); #endregion #region "OpCode Table (AArch64)"