diff --git a/src/binary_translation/CMakeLists.txt b/src/binary_translation/CMakeLists.txt index 8b98d2511..e981ffb43 100644 --- a/src/binary_translation/CMakeLists.txt +++ b/src/binary_translation/CMakeLists.txt @@ -9,6 +9,7 @@ set(SRCS Instructions/Instruction.cpp Instructions/DataProcessing.cpp + Instructions/Branch.cpp ) set(HEADERS CodeGen.h @@ -21,6 +22,7 @@ set(HEADERS Instructions/Types.h Instructions/Instruction.h Instructions/DataProcessing.h + Instructions/Branch.h ) create_directory_groups(${SRCS} ${HEADERS}) diff --git a/src/binary_translation/InstructionBlock.cpp b/src/binary_translation/InstructionBlock.cpp index b00d9b414..e84ac7807 100644 --- a/src/binary_translation/InstructionBlock.cpp +++ b/src/binary_translation/InstructionBlock.cpp @@ -35,7 +35,7 @@ void InstructionBlock::GenerateCode() // If not, jump to the next instruction if (!basic_block->getTerminator()) { - Module()->WritePCConst(Address() + 4); + Module()->BranchWritePCConst(Address() + 4); } } @@ -49,7 +49,7 @@ llvm::Value *InstructionBlock::Write(Register reg, llvm::Value *value) return module->Machine()->WriteRegiser(reg, value); } -size_t InstructionBlock::Address() +u32 InstructionBlock::Address() { return instruction->Address(); } \ No newline at end of file diff --git a/src/binary_translation/InstructionBlock.h b/src/binary_translation/InstructionBlock.h index 81f9d34ae..e8b862d00 100644 --- a/src/binary_translation/InstructionBlock.h +++ b/src/binary_translation/InstructionBlock.h @@ -1,5 +1,6 @@ #include #include +#include namespace llvm { @@ -43,7 +44,7 @@ public: */ llvm::Value *Write(Register reg, llvm::Value *value); - size_t Address(); + u32 Address(); ModuleGen *Module() { return module; } llvm::BasicBlock *GetEntryBasicBlock() { return entry_basic_block; } diff --git a/src/binary_translation/Instructions/Branch.cpp b/src/binary_translation/Instructions/Branch.cpp new file mode 100644 index 000000000..498040f86 --- /dev/null +++ b/src/binary_translation/Instructions/Branch.cpp @@ -0,0 +1,51 @@ +#include "Branch.h" +#include "Disassembler.h" +#include "InstructionBlock.h" +#include "ModuleGen.h" + +static RegisterInstruction register_instruction; + +bool Branch::Decode() +{ + // B imm, BL imm + if (ReadFields({ FieldDef<4>(&cond), FieldDef<3>(5), FieldDef<1>(&link), FieldDef<24>(&imm24) })) + { + if (cond != Condition::AL) return false; + + form = Form::Immediate; + return true; + } + // BLX reg + if (ReadFields({ FieldDef<4>(&cond), FieldDef<24>(0x12fff3), FieldDef<4>(&rm)})) + { + if (cond != Condition::AL) return false; + if (rm == Register::PC) return false; + + link = true; + form = Form::Register; + return true; + } + return false; +} + +void Branch::GenerateCode(InstructionBlock* instruction_block) +{ + auto ir_builder = instruction_block->Module()->IrBuilder(); + if (link) + { + instruction_block->Write(Register::LR, ir_builder->getInt32(instruction_block->Address() + 4)); + } + if (form == Form::Immediate) + { + auto pc = static_cast(imm24 << 2); + pc = pc << 6 >> 6; // Sign extend + pc += instruction_block->Address() + 8; + instruction_block->Module()->BranchWritePCConst(pc); + } + else + { + auto pc = instruction_block->Read(rm); + instruction_block->Write(Register::PC, pc); + instruction_block->Module()->BranchReadPC(); + } +} \ No newline at end of file diff --git a/src/binary_translation/Instructions/Branch.h b/src/binary_translation/Instructions/Branch.h new file mode 100644 index 000000000..fe5f4b8a8 --- /dev/null +++ b/src/binary_translation/Instructions/Branch.h @@ -0,0 +1,26 @@ +#include "Instruction.h" +#include "Types.h" + +/* + * Data processing instructions + * ARMv7-A 5.2.1 (register), 5.2.2 (register-shifted register, 5.2.3 (immediate) + */ + +class Branch : public Instruction +{ +public: + enum class Form + { + Immediate, Register + }; + +public: + virtual bool Decode() override; + void GenerateCode(InstructionBlock* instruction_block) override; +private: + Form form; + Condition cond; + bool link; + u32 imm24; + Register rm; +}; \ No newline at end of file diff --git a/src/binary_translation/Instructions/DataProcessing.cpp b/src/binary_translation/Instructions/DataProcessing.cpp index 8a63db40d..ce762ba9b 100644 --- a/src/binary_translation/Instructions/DataProcessing.cpp +++ b/src/binary_translation/Instructions/DataProcessing.cpp @@ -37,6 +37,6 @@ void DataProcessing::GenerateCode(InstructionBlock* instruction_block) if (rd == Register::PC) { - instruction_block->Module()->ReadPC(); + instruction_block->Module()->BranchReadPC(); } } \ No newline at end of file diff --git a/src/binary_translation/ModuleGen.cpp b/src/binary_translation/ModuleGen.cpp index 1de6c451f..0e27e9a1a 100644 --- a/src/binary_translation/ModuleGen.cpp +++ b/src/binary_translation/ModuleGen.cpp @@ -42,12 +42,12 @@ void ModuleGen::Run() GenerateBlockAddressArray(); } -void ModuleGen::ReadPC() +void ModuleGen::BranchReadPC() { ir_builder->CreateBr(run_function_re_entry); } -void ModuleGen::WritePCConst(u32 pc) +void ModuleGen::BranchWritePCConst(u32 pc) { auto i = instruction_blocks_by_pc.find(pc); if (i != instruction_blocks_by_pc.end()) diff --git a/src/binary_translation/ModuleGen.h b/src/binary_translation/ModuleGen.h index 34419be01..85fb3d178 100644 --- a/src/binary_translation/ModuleGen.h +++ b/src/binary_translation/ModuleGen.h @@ -22,9 +22,9 @@ public: void Run(); // Generate code to read pc and run all following instructions, used in cases of indirect branch - void ReadPC(); + void BranchReadPC(); // Generate code to write to pc and run all following instructions, used in cases of direct branch - void WritePCConst(u32 pc); + void BranchWritePCConst(u32 pc); llvm::IRBuilder<> *IrBuilder() { return ir_builder.get(); } llvm::Module *Module() { return module; }