diff --git a/src/dual/CMakeLists.txt b/src/dual/CMakeLists.txt index a4148ac..6df4f4a 100644 --- a/src/dual/CMakeLists.txt +++ b/src/dual/CMakeLists.txt @@ -10,6 +10,7 @@ set(SOURCES src/arm/dynarec/ir/disassemble.cpp src/arm/dynarec/dynarec_cpu.cpp src/arm/dynarec/state.cpp + src/arm/dynarec/translator_a32.cpp src/arm/interpreter/tablegen/tablegen.cpp src/arm/interpreter/interpreter_cpu.cpp src/common/scheduler.cpp @@ -72,6 +73,7 @@ set(HEADERS src/arm/dynarec/ir/value.hpp src/arm/dynarec/dynarec_cpu.hpp src/arm/dynarec/state.hpp + src/arm/dynarec/translator_a32.hpp src/arm/interpreter/handlers/arithmetic.inl src/arm/interpreter/handlers/handler16.inl src/arm/interpreter/handlers/handler32.inl diff --git a/src/dual/src/arm/dynarec/dynarec_cpu.cpp b/src/dual/src/arm/dynarec/dynarec_cpu.cpp index 8341501..dd14d88 100644 --- a/src/dual/src/arm/dynarec/dynarec_cpu.cpp +++ b/src/dual/src/arm/dynarec/dynarec_cpu.cpp @@ -153,7 +153,6 @@ void DynarecCPU::Run(int cycles) { using_jit = true; } m_backend->Execute(*function, false); - m_tmp_memory_arena.Reset(); } else { CopyB2A_Fast(m_fallback_cpu, m_cpu_state); if(using_jit) { @@ -178,20 +177,25 @@ jit::ir::Function* DynarecCPU::TryJit() { const PSR cpsr = m_cpu_state.GetCPSR(); if(cpsr.thumb == 0) { - const u32 pc = m_cpu_state.GetGPR(GPR::PC) - 8u; - const u32 instruction = m_memory.ReadWord(pc, Memory::Bus::Code); + const u32 r15 = m_cpu_state.GetGPR(GPR::PC); + const u32 instruction = m_memory.ReadWord(r15 - 8u, Memory::Bus::Code); const Mode cpu_mode = (Mode)cpsr.mode; - if(instruction == 0xE3A00000 && (stupid_counter++ % 10) == 0) { + if((stupid_counter++ % 10) == 0) { + m_tmp_memory_arena.Reset(); + // TODO: implement ir::FunctionBuilder, or something like that. ir::Function* function = new(m_tmp_memory_arena.Allocate(sizeof(ir::Function))) ir::Function{}; // TODO: check failure ir::BasicBlock* bb = new(m_tmp_memory_arena.Allocate(sizeof(ir::BasicBlock))) ir::BasicBlock{0u}; // TODO: check failure function->basic_blocks.push_back(bb); ir::Emitter emitter{*bb, m_tmp_memory_arena}; - emitter.STGPR(GPR::R0, cpu_mode, emitter.LDCONST(0u)); - emitter.EXIT(); - return function; + + const TranslatorA32::Code code = m_translator_a32.Translate(r15, cpu_mode, instruction, emitter); + if(code == TranslatorA32::Code::Success) { + emitter.EXIT(); + return function; + } } } else { // ... diff --git a/src/dual/src/arm/dynarec/dynarec_cpu.hpp b/src/dual/src/arm/dynarec/dynarec_cpu.hpp index 5c4794a..5be1091 100644 --- a/src/dual/src/arm/dynarec/dynarec_cpu.hpp +++ b/src/dual/src/arm/dynarec/dynarec_cpu.hpp @@ -12,6 +12,7 @@ #include "backend/backend.hpp" #include "ir/emitter.hpp" #include "state.hpp" +#include "translator_a32.hpp" namespace dual::arm { @@ -63,6 +64,7 @@ class DynarecCPU final : public CPU { Memory& m_memory; std::unique_ptr m_backend{}; + jit::TranslatorA32 m_translator_a32{}; atom::Arena m_tmp_memory_arena{16384u}; }; diff --git a/src/dual/src/arm/dynarec/translator_a32.cpp b/src/dual/src/arm/dynarec/translator_a32.cpp new file mode 100644 index 0000000..852d78c --- /dev/null +++ b/src/dual/src/arm/dynarec/translator_a32.cpp @@ -0,0 +1,78 @@ + +#include + +#include "translator_a32.hpp" + +namespace dual::arm::jit { + +TranslatorA32::TranslatorA32() { + BuildLUT(); +} + +TranslatorA32::Code TranslatorA32::Translate(u32 r15, CPU::Mode cpu_mode, u32 instruction, ir::Emitter& emitter) { + using namespace ir; + + // Bail out on unconditional instructions for now, those need to be handled with special care + if((instruction >> 28) == 15) { + return Code::Fallback; + } + + // Also bail out on conditionally executed instructions + if((instruction >> 28) != 14) { + return Code::Fallback; + } + + const int hash = (instruction >> 16) & 0xFF0u | (instruction >> 4) & 0xFu; + return m_handler_lut[hash](*this, instruction); +} + +void TranslatorA32::BuildLUT() { + for(u32 hash = 0u; hash < 0x1000; hash++) { + const u32 instruction = (hash & 0xFF0u) << 16 | (hash & 0xFu) << 4; + m_handler_lut[hash] = GetInstructionHandler(instruction); + } +} + +TranslatorA32::HandlerFn TranslatorA32::GetInstructionHandler(u32 instruction) { + namespace bit = atom::bit; + + const auto Unimplemented = [](TranslatorA32& self, u32 instruction) { + return Code::Fallback; + }; + + if(bit::match_pattern<"cccc00010x00xxxxxxxxxxxx0000xxxx">(instruction)) return Unimplemented; // Move status register to register + if(bit::match_pattern<"cccc00010x10xxxxxxxxxxxx0000xxxx">(instruction)) return Unimplemented; // Move register to status register + if(bit::match_pattern<"cccc00010xx0xxxxxxxxxxxx1xx0xxxx">(instruction)) return Unimplemented; // Enhanced DSP multiplies + if(bit::match_pattern<"cccc000xxxxxxxxxxxxxxxxxxxx0xxxx">(instruction)) return Unimplemented; // Data Processing (Shift-by-Immediate) + if(bit::match_pattern<"cccc00010010xxxxxxxxxxxx0001xxxx">(instruction)) return Unimplemented; // Branch/exchange instruction set + if(bit::match_pattern<"cccc00010110xxxxxxxxxxxx0001xxxx">(instruction)) return Unimplemented; // Count leading zeros + if(bit::match_pattern<"cccc00010010xxxxxxxxxxxx0011xxxx">(instruction)) return Unimplemented; // Branch and link/exchange instruction set + if(bit::match_pattern<"cccc00010xx0xxxxxxxxxxxx0101xxxx">(instruction)) return Unimplemented; // Enhanced DSP add/subtracts + if(bit::match_pattern<"cccc00010010xxxxxxxxxxxx0111xxxx">(instruction)) return Unimplemented; // Software breakpoint + if(bit::match_pattern<"cccc000xxxxxxxxxxxxxxxxx0xx1xxxx">(instruction)) return Unimplemented; // Data Processing (Shift-by-Register) + if(bit::match_pattern<"cccc000000xxxxxxxxxxxxxx1001xxxx">(instruction)) return Unimplemented; // Multiply (accumulate) + if(bit::match_pattern<"cccc00001xxxxxxxxxxxxxxx1001xxxx">(instruction)) return Unimplemented; // Multiply (accumulate) long + if(bit::match_pattern<"cccc00010x00xxxxxxxxxxxx1001xxxx">(instruction)) return Unimplemented; + if(bit::match_pattern<"cccc000xx0xxxxxxxxxxxxxx1011xxxx">(instruction)) return Unimplemented; // Load/store halfword register offset + if(bit::match_pattern<"cccc000xx1xxxxxxxxxxxxxx1011xxxx">(instruction)) return Unimplemented; // Load/store halfword immediate offset + if(bit::match_pattern<"cccc000xx0x0xxxxxxxxxxxx11x1xxxx">(instruction)) return Unimplemented; // Load/store two words register offset + if(bit::match_pattern<"cccc000xx0x1xxxxxxxxxxxx11x1xxxx">(instruction)) return Unimplemented; // Load signed halfword/byte register offset + if(bit::match_pattern<"cccc000xx1x0xxxxxxxxxxxx11x1xxxx">(instruction)) return Unimplemented; // Load/store two words immediate offset + if(bit::match_pattern<"cccc000xx1x1xxxxxxxxxxxx11x1xxxx">(instruction)) return Unimplemented; // Load signed halfword/byte register offset + if(bit::match_pattern<"cccc00110x00xxxxxxxxxxxxxxxxxxxx">(instruction)) return Unimplemented; + if(bit::match_pattern<"cccc00110x10xxxxxxxxxxxxxxxxxxxx">(instruction)) return Unimplemented; // Move immediate to status register + if(bit::match_pattern<"cccc001xxxxxxxxxxxxxxxxxxxxxxxxx">(instruction)) return Unimplemented; // Data Processing (Immediate) + if(bit::match_pattern<"cccc010xxxxxxxxxxxxxxxxxxxxxxxxx">(instruction)) return Unimplemented; // Load/Store (Immediate Offset) + if(bit::match_pattern<"cccc011xxxxxxxxxxxxxxxxxxxx0xxxx">(instruction)) return Unimplemented; // Load/Store (Register Offset) + if(bit::match_pattern<"cccc011xxxxxxxxxxxxxxxxxxxx1xxxx">(instruction)) return Unimplemented; + if(bit::match_pattern<"cccc100xxxxxxxxxxxxxxxxxxxxxxxxx">(instruction)) return Unimplemented; + if(bit::match_pattern<"cccc101xxxxxxxxxxxxxxxxxxxxxxxxx">(instruction)) return Unimplemented; + if(bit::match_pattern<"cccc110xxxxxxxxxxxxxxxxxxxxxxxxx">(instruction)) return Unimplemented; + if(bit::match_pattern<"cccc1110xxxxxxxxxxxxxxxxxxx0xxxx">(instruction)) return Unimplemented; + if(bit::match_pattern<"cccc1110xxxxxxxxxxxxxxxxxxx1xxxx">(instruction)) return Unimplemented; + if(bit::match_pattern<"cccc1111xxxxxxxxxxxxxxxxxxxxxxxx">(instruction)) return Unimplemented; + + return Unimplemented; +} + +} // namespace dual::arm::jit diff --git a/src/dual/src/arm/dynarec/translator_a32.hpp b/src/dual/src/arm/dynarec/translator_a32.hpp new file mode 100644 index 0000000..fef93f6 --- /dev/null +++ b/src/dual/src/arm/dynarec/translator_a32.hpp @@ -0,0 +1,31 @@ + +#pragma once + +#include +#include + +#include "ir/emitter.hpp" + +namespace dual::arm::jit { + +class TranslatorA32 { + public: + enum class Code { + Success, + Fallback + }; + + TranslatorA32(); + + Code Translate(u32 r15, ir::Mode cpu_mode, u32 instruction, ir::Emitter& emitter); + + private: + + // TODO: make some of this stuff static and constexpr? + using HandlerFn = Code (*)(TranslatorA32& self, u32 instruction); + void BuildLUT(); + HandlerFn GetInstructionHandler(u32 instruction); + std::array m_handler_lut{}; +}; + +} // namespace dual::arm::jit