Skip to content

Commit

Permalink
DRC cleanup and minor optimisation: [Windy Fairy, Vas Crabb]
Browse files Browse the repository at this point in the history
* Build all native back-ends if any native back-end is enabled so errors
  caused by changing interfaces can be found faster.
* cpu/drcbeut.cpp: Moved resolved member function stuff to a place where
  it can be shared by back-ends.
* cpu/drcbearm64.cpp: Use ubfx instruction to extract unordered flag.
* cpu/drcbearm64.cpp, cpu/drcbex64.cpp: Bypass trampolines when calling
  get map variable value and debugger instruction hook functions.
* cpu/drcbearm64.cpp: Moved some internal helpers that don't need to be
  members to anonymous namespace.
* cpu/drcbearm64.cpp: Added a comment with some info to help when
  debugging generated code.
* cpu/drcbec.cpp: Put code in the drc namespace.
  • Loading branch information
cuavas committed Jan 15, 2025
1 parent 8cfc62f commit 26d8e47
Show file tree
Hide file tree
Showing 10 changed files with 469 additions and 404 deletions.
7 changes: 0 additions & 7 deletions scripts/src/3rdparty.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1959,13 +1959,6 @@ project "asmjit"
end
end

if (_OPTIONS["PLATFORM"]=="arm64") then
configuration { }
defines {
"ASMJIT_NO_X86",
}
end

files {
MAME_DIR .. "3rdparty/asmjit/src/asmjit/a64.h",
MAME_DIR .. "3rdparty/asmjit/src/asmjit/arm.h",
Expand Down
21 changes: 8 additions & 13 deletions scripts/src/cpu.lua
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,14 @@ if (CPU_INCLUDE_DRC) then
MAME_DIR .. "src/devices/cpu/drcumlsh.h",
}
if not _OPTIONS["FORCE_DRC_C_BACKEND"] then
if (_OPTIONS["PLATFORM"]=="arm64") then
files {
MAME_DIR .. "src/devices/cpu/drcbearm64.cpp",
MAME_DIR .. "src/devices/cpu/drcbearm64.h",
}
else
files {
MAME_DIR .. "src/devices/cpu/drcbex64.cpp",
MAME_DIR .. "src/devices/cpu/drcbex64.h",
MAME_DIR .. "src/devices/cpu/drcbex86.cpp",
MAME_DIR .. "src/devices/cpu/drcbex86.h",
}
end
files {
MAME_DIR .. "src/devices/cpu/drcbearm64.cpp",
MAME_DIR .. "src/devices/cpu/drcbearm64.h",
MAME_DIR .. "src/devices/cpu/drcbex64.cpp",
MAME_DIR .. "src/devices/cpu/drcbex64.h",
MAME_DIR .. "src/devices/cpu/drcbex86.cpp",
MAME_DIR .. "src/devices/cpu/drcbex86.h",
}
end

if _OPTIONS["targetos"]=="macosx" and _OPTIONS["gcc"]~=nil then
Expand Down
531 changes: 289 additions & 242 deletions src/devices/cpu/drcbearm64.cpp

Large diffs are not rendered by default.

45 changes: 4 additions & 41 deletions src/devices/cpu/drcbearm64.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,8 @@ class drcbe_arm64 : public drcbe_interface


// helper functions
asmjit::a64::Vec select_register(asmjit::a64::Vec const &reg, uint32_t regsize) const;
asmjit::a64::Gp select_register(asmjit::a64::Gp const &reg, uint32_t regsize) const;

static bool is_valid_immediate(uint64_t val, size_t bits);
static bool is_valid_immediate_signed(int64_t val, size_t bits);
static bool is_valid_immediate_mask(uint64_t val, size_t bytes);

asmjit::arm::Mem get_mem_absolute(asmjit::a64::Assembler &a, const void *ptr) const;
void get_imm_relative(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const uint64_t ptr) const;

bool emit_add_optimized(asmjit::a64::Assembler &a, const asmjit::a64::Gp &dst, const asmjit::a64::Gp &src, int64_t val) const;
bool emit_sub_optimized(asmjit::a64::Assembler &a, const asmjit::a64::Gp &dst, const asmjit::a64::Gp &src, int64_t val) const;

void emit_ldr_str_base_mem(asmjit::a64::Assembler &a, asmjit::a64::Inst::Id opcode, const asmjit::a64::Reg &reg, const void *ptr) const;
void emit_ldr_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
void emit_ldrb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
Expand All @@ -203,8 +192,6 @@ class drcbe_arm64 : public drcbe_interface
void get_unordered(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg) const;
void check_unordered_condition(asmjit::a64::Assembler &a, uml::condition_t cond, asmjit::Label condition_met, bool not_equal) const;

void get_shifted_bit(asmjit::a64::Assembler &a, const asmjit::a64::Gp &dst, const asmjit::a64::Gp &src, uint32_t bits, uint32_t shift) const;

void calculate_carry_shift_left(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const asmjit::a64::Gp &shift, int maxBits) const;
void calculate_carry_shift_left_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const int shift, int maxBits) const;

Expand Down Expand Up @@ -238,9 +225,6 @@ class drcbe_arm64 : public drcbe_interface

struct near_state
{
void *debug_cpu_instruction_hook;
void *drcmap_get_value;

uint32_t emulated_flags;
};
near_state &m_near;
Expand All @@ -254,33 +238,12 @@ class drcbe_arm64 : public drcbe_interface
static const opcode_table_entry s_opcode_table_source[];
static opcode_generate_func s_opcode_table[uml::OP_MAX];

struct resolved_handler { uintptr_t obj = 0; void *func = nullptr; };
struct resolved_accessors
{

resolved_handler read_byte;
resolved_handler read_byte_masked;
resolved_handler read_word;
resolved_handler read_word_masked;
resolved_handler read_dword;
resolved_handler read_dword_masked;
resolved_handler read_qword;
resolved_handler read_qword_masked;

resolved_handler write_byte;
resolved_handler write_byte_masked;
resolved_handler write_word;
resolved_handler write_word_masked;
resolved_handler write_dword;
resolved_handler write_dword_masked;
resolved_handler write_qword;
resolved_handler write_qword_masked;
};
using resolved_accessors_vector = std::vector<resolved_accessors>;
resolved_accessors_vector m_resolved_accessors;
resolved_member_function m_debug_cpu_instruction_hook;
resolved_member_function m_drcmap_get_value;
resolved_memory_accessors_vector m_resolved_accessors;
};

}
} // namespace drc

using drc::drcbe_arm64;

Expand Down
4 changes: 4 additions & 0 deletions src/devices/cpu/drcbec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include <cmath>

namespace drc {

using namespace uml;


Expand Down Expand Up @@ -2436,3 +2438,5 @@ uint64_t drcbe_c::tzcount64(uint64_t value)
}
return 64;
}

} // namespace drc
4 changes: 4 additions & 0 deletions src/devices/cpu/drcbec.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "drcbeut.h"


namespace drc {

//**************************************************************************
// TYPE DEFINITIONS
Expand Down Expand Up @@ -57,5 +58,8 @@ class drcbe_c : public drcbe_interface
static uint64_t s_immediate_zero;
};

} // namespace drc

using drc::drcbe_c;

#endif // MAME_CPU_DRCBEC_H
61 changes: 48 additions & 13 deletions src/devices/cpu/drcbeut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include "emu.h"
#include "drcbeut.h"

namespace drc {

using namespace uml;


Expand All @@ -30,19 +32,19 @@ using namespace uml;
// drc_hash_table - constructor
//-------------------------------------------------

drc_hash_table::drc_hash_table(drc_cache &cache, uint32_t modes, uint8_t addrbits, uint8_t ignorebits)
: m_cache(cache),
m_modes(modes),
m_nocodeptr(nullptr),
m_l1bits((addrbits - ignorebits) / 2),
m_l2bits((addrbits - ignorebits) - m_l1bits),
m_l1shift(ignorebits + m_l2bits),
m_l2shift(ignorebits),
m_l1mask((1 << m_l1bits) - 1),
m_l2mask((1 << m_l2bits) - 1),
m_base(reinterpret_cast<drccodeptr ***>(cache.alloc(modes * sizeof(**m_base)))),
m_emptyl1(nullptr),
m_emptyl2(nullptr)
drc_hash_table::drc_hash_table(drc_cache &cache, uint32_t modes, uint8_t addrbits, uint8_t ignorebits) :
m_cache(cache),
m_modes(modes),
m_nocodeptr(nullptr),
m_l1bits((addrbits - ignorebits) / 2),
m_l2bits((addrbits - ignorebits) - m_l1bits),
m_l1shift(ignorebits + m_l2bits),
m_l2shift(ignorebits),
m_l1mask((1 << m_l1bits) - 1),
m_l2mask((1 << m_l2bits) - 1),
m_base(reinterpret_cast<drccodeptr ***>(cache.alloc(modes * sizeof(**m_base)))),
m_emptyl1(nullptr),
m_emptyl2(nullptr)
{
reset();
}
Expand Down Expand Up @@ -577,3 +579,36 @@ void drc_label_list::oob_callback(drccodeptr *codeptr, void *param1, void *param
label_fixup *fixup = reinterpret_cast<label_fixup *>(param1);
fixup->m_callback(param2, fixup->m_label->m_codeptr);
}



//**************************************************************************
// RESOLVED MEMORY ACCESSORS
//**************************************************************************

//-------------------------------------------------
// set - bind to address space
//-------------------------------------------------

void resolved_memory_accessors::set(address_space &space) noexcept
{
read_byte .set(space, static_cast<u8 (address_space::*)(offs_t) >(&address_space::read_byte));
read_byte_masked .set(space, static_cast<u8 (address_space::*)(offs_t, u8) >(&address_space::read_byte));
read_word .set(space, static_cast<u16 (address_space::*)(offs_t) >(&address_space::read_word));
read_word_masked .set(space, static_cast<u16 (address_space::*)(offs_t, u16)>(&address_space::read_word));
read_dword .set(space, static_cast<u32 (address_space::*)(offs_t) >(&address_space::read_dword));
read_dword_masked .set(space, static_cast<u32 (address_space::*)(offs_t, u32)>(&address_space::read_dword));
read_qword .set(space, static_cast<u64 (address_space::*)(offs_t) >(&address_space::read_qword));
read_qword_masked .set(space, static_cast<u64 (address_space::*)(offs_t, u64)>(&address_space::read_qword));

write_byte .set(space, static_cast<void (address_space::*)(offs_t, u8) >(&address_space::write_byte));
write_byte_masked .set(space, static_cast<void (address_space::*)(offs_t, u8, u8) >(&address_space::write_byte));
write_word .set(space, static_cast<void (address_space::*)(offs_t, u16) >(&address_space::write_word));
write_word_masked .set(space, static_cast<void (address_space::*)(offs_t, u16, u16)>(&address_space::write_word));
write_dword .set(space, static_cast<void (address_space::*)(offs_t, u32) >(&address_space::write_dword));
write_dword_masked .set(space, static_cast<void (address_space::*)(offs_t, u32, u32)>(&address_space::write_dword));
write_qword .set(space, static_cast<void (address_space::*)(offs_t, u64) >(&address_space::write_qword));
write_qword_masked .set(space, static_cast<void (address_space::*)(offs_t, u64, u64)>(&address_space::write_qword));
}

} // namespace drc
77 changes: 68 additions & 9 deletions src/devices/cpu/drcbeut.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@

#include "drcuml.h"

#include "mfpresolve.h"

#include <utility>
#include <vector>


namespace drc {

//**************************************************************************
// TYPE DEFINITIONS
Expand Down Expand Up @@ -55,14 +62,14 @@ class drc_hash_table
private:
// internal state
drc_cache & m_cache; // cache where allocations come from
uint32_t m_modes; // number of modes supported
uint32_t m_modes; // number of modes supported

drccodeptr m_nocodeptr; // pointer to code which will handle missing entries

uint8_t m_l1bits; // bits worth of entries in l1 hash tables
uint8_t m_l2bits; // bits worth of entries in l2 hash tables
uint8_t m_l1shift; // shift to apply to the PC to get the l1 hash entry
uint8_t m_l2shift; // shift to apply to the PC to get the l2 hash entry
uint8_t m_l1bits; // bits worth of entries in l1 hash tables
uint8_t m_l2bits; // bits worth of entries in l2 hash tables
uint8_t m_l1shift; // shift to apply to the PC to get the l1 hash entry
uint8_t m_l2shift; // shift to apply to the PC to get the l2 hash entry
offs_t m_l1mask; // mask to apply after shifting
offs_t m_l2mask; // mask to apply after shifting

Expand Down Expand Up @@ -97,17 +104,17 @@ class drc_map_variables
private:
// internal state
drc_cache & m_cache; // pointer to the cache
uint64_t m_uniquevalue; // unique value used to find the table
uint32_t m_mapvalue[uml::MAPVAR_END - uml::MAPVAR_M0]; // array of current values
uint64_t m_uniquevalue; // unique value used to find the table
uint32_t m_mapvalue[uml::MAPVAR_END - uml::MAPVAR_M0]; // array of current values

// list of entries
struct map_entry
{
map_entry *next() const { return m_next; }
map_entry * m_next; // pointer to next map entry
drccodeptr m_codeptr; // pointer to the relevant code
uint32_t m_mapvar; // map variable id
uint32_t m_newval; // value of the variable starting at codeptr
uint32_t m_mapvar; // map variable id
uint32_t m_newval; // value of the variable starting at codeptr
};
simple_list<map_entry> m_entry_list; // list of entries
};
Expand Down Expand Up @@ -163,4 +170,56 @@ class drc_label_list
};


// ======================> resolved_member_function

struct resolved_member_function
{
uintptr_t obj = uintptr_t(nullptr);
uint8_t *func = nullptr;

explicit operator bool() const noexcept
{
return bool(func);
}

template <typename C, typename F>
void set(C &&instance, F &&mfp) noexcept
{
auto const [entrypoint, adjusted] = util::resolve_member_function(std::forward<F>(mfp), std::forward<C>(instance));
obj = adjusted;
func = reinterpret_cast<uint8_t *>(entrypoint);
}
};


// ======================> resolved_memory_accessors

struct resolved_memory_accessors
{
resolved_member_function read_byte;
resolved_member_function read_byte_masked;
resolved_member_function read_word;
resolved_member_function read_word_masked;
resolved_member_function read_dword;
resolved_member_function read_dword_masked;
resolved_member_function read_qword;
resolved_member_function read_qword_masked;

resolved_member_function write_byte;
resolved_member_function write_byte_masked;
resolved_member_function write_word;
resolved_member_function write_word_masked;
resolved_member_function write_dword;
resolved_member_function write_dword_masked;
resolved_member_function write_qword;
resolved_member_function write_qword_masked;

void set(address_space &space) noexcept;
};

using resolved_memory_accessors_vector = std::vector<resolved_memory_accessors>;

} // namespace drc


#endif // MAME_CPU_DRCBEUT_H
Loading

2 comments on commit 26d8e47

@cuavas
Copy link
Member Author

@cuavas cuavas commented on 26d8e47 Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’d appreciate if someone with a 64-bit ARMv8 development setup could test this. The parts that aren’t tested can be exercised by:

  • Running a game that uses the DRC with the debugger enable (e.g. mame -debug fiveside or mame -debug coolmini) and stepping over a few instructions. This will check that the debugger hook still works.
  • Checking that Scud Race and Power Macintosh 6100/60 still boot (e.g. mame scud or mame pmac6100). This will check that reading top-level map variables from subroutines still works.

@rb6502
Copy link
Contributor

@rb6502 rb6502 commented on 26d8e47 Jan 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of those things work. Stepping, stepping over a BLR, breakpoints in general, all fine. And mame pmac6100 mac750 boots to Finder.

Please sign in to comment.