Skip to content

Commit

Permalink
Add some initial framework for A32 translation
Browse files Browse the repository at this point in the history
  • Loading branch information
fleroviux committed Feb 8, 2025
1 parent 6a0db25 commit 134e9b3
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 7 deletions.
2 changes: 2 additions & 0 deletions src/dual/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
18 changes: 11 additions & 7 deletions src/dual/src/arm/dynarec/dynarec_cpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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 {
// ...
Expand Down
2 changes: 2 additions & 0 deletions src/dual/src/arm/dynarec/dynarec_cpu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "backend/backend.hpp"
#include "ir/emitter.hpp"
#include "state.hpp"
#include "translator_a32.hpp"

namespace dual::arm {

Expand Down Expand Up @@ -63,6 +64,7 @@ class DynarecCPU final : public CPU {
Memory& m_memory;
std::unique_ptr<jit::Backend> m_backend{};

jit::TranslatorA32 m_translator_a32{};
atom::Arena m_tmp_memory_arena{16384u};
};

Expand Down
78 changes: 78 additions & 0 deletions src/dual/src/arm/dynarec/translator_a32.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

#include <atom/bit.hpp>

#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
31 changes: 31 additions & 0 deletions src/dual/src/arm/dynarec/translator_a32.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

#pragma once

#include <atom/integer.hpp>
#include <array>

#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<HandlerFn, 4096u> m_handler_lut{};
};

} // namespace dual::arm::jit

0 comments on commit 134e9b3

Please sign in to comment.