summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2025-02-22 06:07:07 +1100
committer Vas Crabb <vas@vastheman.com>2025-02-22 06:07:07 +1100
commite0b33abadbe6ff1e1ec973f62704c34609d0b4d9 (patch)
tree7505fba659892fb307a45aa98117d2d9117212a2
parent9a58e39d6e8a4aba4e1dbad28d4e4179c9a896d3 (diff)
cpu: Moved DRC backend declarations out of headers and into anonymous namespaces.
-rw-r--r--src/devices/cpu/drcbearm64.cpp278
-rw-r--r--src/devices/cpu/drcbearm64.h247
-rw-r--r--src/devices/cpu/drcbec.cpp317
-rw-r--r--src/devices/cpu/drcbec.h51
-rw-r--r--src/devices/cpu/drcbex64.cpp296
-rw-r--r--src/devices/cpu/drcbex64.h284
-rw-r--r--src/devices/cpu/drcbex86.cpp676
-rw-r--r--src/devices/cpu/drcbex86.h298
-rw-r--r--src/devices/cpu/drcuml.cpp13
9 files changed, 1262 insertions, 1198 deletions
diff --git a/src/devices/cpu/drcbearm64.cpp b/src/devices/cpu/drcbearm64.cpp
index a49745e9533..5477343ce57 100644
--- a/src/devices/cpu/drcbearm64.cpp
+++ b/src/devices/cpu/drcbearm64.cpp
@@ -75,21 +75,27 @@ the location FP points to.
#include "emu.h"
#include "drcbearm64.h"
+#include "drcbeut.h"
+#include "uml.h"
+
#include "debug/debugcpu.h"
#include "emuopts.h"
-#include "uml.h"
+
+#include "asmjit/src/asmjit/asmjit.h"
+#include "asmjit/src/asmjit/a64.h"
#include <cstddef>
+#include <vector>
namespace drc {
+namespace {
+
using namespace uml;
using namespace asmjit;
-namespace {
-
const uint32_t PTYPE_M = 1 << parameter::PTYPE_MEMORY;
const uint32_t PTYPE_I = 1 << parameter::PTYPE_IMMEDIATE;
const uint32_t PTYPE_R = 1 << parameter::PTYPE_INT_REGISTER;
@@ -343,7 +349,237 @@ void get_imm_absolute(a64::Assembler &a, const a64::Gp &reg, const uint64_t val)
a.mov(reg, val);
}
-} // anonymous namespace
+
+class drcbe_arm64 : public drcbe_interface
+{
+ using arm64_entry_point_func = uint32_t (*)(void *entry);
+
+public:
+ drcbe_arm64(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits);
+ virtual ~drcbe_arm64();
+
+ virtual void reset() override;
+ virtual int execute(uml::code_handle &entry) override;
+ virtual void generate(drcuml_block &block, const uml::instruction *instlist, uint32_t numinst) override;
+ virtual bool hash_exists(uint32_t mode, uint32_t pc) override;
+ virtual void get_info(drcbe_info &info) override;
+ virtual bool logging() const override { return false; }
+
+private:
+ class be_parameter
+ {
+ static inline constexpr int REG_MAX = 30;
+
+ public:
+ // parameter types
+ enum be_parameter_type
+ {
+ PTYPE_NONE = 0, // invalid
+ PTYPE_IMMEDIATE, // immediate; value = sign-extended to 64 bits
+ PTYPE_INT_REGISTER, // integer register; value = 0-REG_MAX
+ PTYPE_FLOAT_REGISTER, // floating point register; value = 0-REG_MAX
+ PTYPE_MEMORY, // memory; value = pointer to memory
+ PTYPE_MAX
+ };
+
+ typedef uint64_t be_parameter_value;
+
+ be_parameter() : m_type(PTYPE_NONE), m_value(0) { }
+ be_parameter(uint64_t val) : m_type(PTYPE_IMMEDIATE), m_value(val) { }
+ be_parameter(drcbe_arm64 &drcbe, const uml::parameter &param, uint32_t allowed);
+ be_parameter(const be_parameter &param) = default;
+
+ static be_parameter make_ireg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_INT_REGISTER, regnum); }
+ static be_parameter make_freg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_FLOAT_REGISTER, regnum); }
+ static be_parameter make_memory(void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(base)); }
+ static be_parameter make_memory(const void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(const_cast<void *>(base))); }
+
+ bool operator==(const be_parameter &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); }
+ bool operator!=(const be_parameter &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); }
+
+ be_parameter_type type() const { return m_type; }
+ uint64_t immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; }
+ uint32_t ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value < REG_MAX); return m_value; }
+ uint32_t freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value < REG_MAX); return m_value; }
+ void *memory() const { assert(m_type == PTYPE_MEMORY); return reinterpret_cast<void *>(m_value); }
+
+ bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); }
+ bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); }
+ bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); }
+ bool is_memory() const { return (m_type == PTYPE_MEMORY); }
+
+ bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); }
+
+ asmjit::a64::Vec get_register_float(uint32_t regsize) const;
+ asmjit::a64::Gp get_register_int(uint32_t regsize) const;
+ 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;
+
+ private:
+ be_parameter(be_parameter_type type, be_parameter_value value) : m_type(type), m_value(value) { }
+
+ be_parameter_type m_type;
+ be_parameter_value m_value;
+ };
+
+ void op_handle(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_hash(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_label(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_comment(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_mapvar(asmjit::a64::Assembler &a, const uml::instruction &inst);
+
+ void op_nop(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_break(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_debug(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_exit(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_hashjmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_jmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_exh(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_callh(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_ret(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_callc(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_recover(asmjit::a64::Assembler &a, const uml::instruction &inst);
+
+ void op_setfmod(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_getfmod(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_getexp(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_getflgs(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_setflgs(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_save(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_restore(asmjit::a64::Assembler &a, const uml::instruction &inst);
+
+ void op_load(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_loads(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_store(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_read(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_readm(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_write(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_writem(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_carry(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_set(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_mov(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_sext(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_roland(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_rolins(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ template <asmjit::a64::Inst::Id Opcode> void op_add(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ template <asmjit::a64::Inst::Id Opcode> void op_sub(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_cmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_mulu(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_mululw(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_muls(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_mulslw(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ template <asmjit::a64::Inst::Id Opcode> void op_div(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_and(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_test(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_or(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_xor(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_lzcnt(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_tzcnt(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_bswap(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ template <asmjit::a64::Inst::Id Opcode> void op_shift(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_rol(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_rolc(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_rorc(asmjit::a64::Assembler &a, const uml::instruction &inst);
+
+ void op_fload(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_fstore(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_fread(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_fwrite(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_fmov(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_ftoint(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_ffrint(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_ffrflt(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_frnds(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_fcmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_fcopyi(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ void op_icopyf(asmjit::a64::Assembler &a, const uml::instruction &inst);
+
+ template <asmjit::a64::Inst::Id Opcode> void op_float_alu(asmjit::a64::Assembler &a, const uml::instruction &inst);
+ template <asmjit::a64::Inst::Id Opcode> void op_float_alu2(asmjit::a64::Assembler &a, const uml::instruction &inst);
+
+ size_t emit(asmjit::CodeHolder &ch);
+
+
+ // helper functions
+ void get_imm_relative(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const uint64_t ptr) const;
+
+ void emit_ldr_str_base_mem(asmjit::a64::Assembler &a, asmjit::a64::Inst::Id opcode, const asmjit::a64::Reg &reg, int max_shift, 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;
+ void emit_ldrh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
+ void emit_ldrsb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
+ void emit_ldrsh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
+ void emit_ldrsw_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
+ void emit_str_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
+ void emit_strb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
+ void emit_strh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
+
+ void emit_float_ldr_mem(asmjit::a64::Assembler &a, const asmjit::a64::Vec &reg, const void *ptr) const;
+ void emit_float_str_mem(asmjit::a64::Assembler &a, const asmjit::a64::Vec &reg, const void *ptr) const;
+
+ void get_carry(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, bool inverted = false) const;
+ void load_carry(asmjit::a64::Assembler &a, bool inverted = false) const;
+ void store_carry(asmjit::a64::Assembler &a, bool inverted = false) const;
+ void store_carry_reg(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg) const;
+
+ void store_unordered(asmjit::a64::Assembler &a) const;
+ 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 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;
+
+ void calculate_carry_shift_right(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const asmjit::a64::Gp &shift) const;
+ void calculate_carry_shift_right_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const int shift) const;
+
+ void mov_float_reg_param(asmjit::a64::Assembler &a, uint32_t regsize, asmjit::a64::Vec const &dst, const be_parameter &src) const;
+ void mov_float_param_param(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, const be_parameter &src) const;
+ void mov_float_param_reg(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, asmjit::a64::Vec const &src) const;
+ void mov_float_param_int_reg(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, asmjit::a64::Gp const &src) const;
+
+ void mov_reg_param(asmjit::a64::Assembler &a, uint32_t regsize, const asmjit::a64::Gp &dst, const be_parameter &src) const;
+ void mov_param_reg(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, const asmjit::a64::Gp &src) const;
+ void mov_param_imm(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, uint64_t src) const;
+ void mov_param_param(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, const be_parameter &src) const;
+ void mov_mem_param(asmjit::a64::Assembler &a, uint32_t regsize, void *dst, const be_parameter &src) const;
+ void mov_r64_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp &dst, uint64_t const src) const;
+
+ void call_arm_addr(asmjit::a64::Assembler &a, const void *offs) const;
+
+ drc_hash_table m_hash;
+ drc_map_variables m_map;
+ FILE * m_log_asmjit;
+
+ arm64_entry_point_func m_entry;
+ drccodeptr m_exit;
+ drccodeptr m_nocode;
+
+ uint8_t *m_baseptr;
+
+ struct near_state
+ {
+ uint32_t emulated_flags;
+ };
+ near_state &m_near;
+
+ using opcode_generate_func = void (drcbe_arm64::*)(asmjit::a64::Assembler &, const uml::instruction &);
+ struct opcode_table_entry
+ {
+ uml::opcode_t opcode;
+ opcode_generate_func func;
+ };
+ static const opcode_table_entry s_opcode_table_source[];
+ static opcode_generate_func s_opcode_table[uml::OP_MAX];
+
+ struct memory_accessors
+ {
+ resolved_memory_accessors resolved;
+ address_space::specific_access_info specific;
+ };
+ resolved_member_function m_debug_cpu_instruction_hook;
+ resolved_member_function m_drcmap_get_value;
+ std::vector<memory_accessors> m_memory_accessors;
+};
drcbe_arm64::opcode_generate_func drcbe_arm64::s_opcode_table[OP_MAX];
@@ -763,25 +999,6 @@ void drcbe_arm64::mov_param_imm(a64::Assembler &a, uint32_t regsize, const be_pa
}
}
-void drcbe_arm64::mov_signed_reg64_param32(a64::Assembler &a, const a64::Gp &dst, const be_parameter &src) const
-{
- if (src.is_memory())
- {
- emit_ldrsw_mem(a, dst.x(), src.memory());
- }
- else if (src.is_immediate())
- {
- get_imm_relative(a, dst.x(), src.immediate());
-
- if (!src.is_immediate_value(0))
- a.sxtw(dst.x(), dst.w());
- }
- else if (src.is_int_register())
- {
- a.sxtw(dst.x(), src.get_register_int(4));
- }
-}
-
void drcbe_arm64::mov_float_reg_param(a64::Assembler &a, uint32_t regsize, a64::Vec const &dst, const be_parameter &src) const
{
assert(!src.is_immediate());
@@ -4126,4 +4343,19 @@ void drcbe_arm64::op_icopyf(a64::Assembler &a, const uml::instruction &inst)
mov_param_reg(a, inst.size(), dstp, dstreg);
}
+} // anonymous namespace
+
+
+std::unique_ptr<drcbe_interface> make_drcbe_arm64(
+ drcuml_state &drcuml,
+ device_t &device,
+ drc_cache &cache,
+ uint32_t flags,
+ int modes,
+ int addrbits,
+ int ignorebits)
+{
+ return std::unique_ptr<drcbe_interface>(new drcbe_arm64(drcuml, device, cache, flags, modes, addrbits, ignorebits));
}
+
+} // namespace drc
diff --git a/src/devices/cpu/drcbearm64.h b/src/devices/cpu/drcbearm64.h
index 0e54234bc42..2006b4a14ab 100644
--- a/src/devices/cpu/drcbearm64.h
+++ b/src/devices/cpu/drcbearm64.h
@@ -6,250 +6,21 @@
#pragma once
#include "drcuml.h"
-#include "drcbeut.h"
-#include "asmjit/src/asmjit/asmjit.h"
-#include "asmjit/src/asmjit/a64.h"
-
-#include <vector>
+#include <memory>
namespace drc {
-class drcbe_arm64 : public drcbe_interface
-{
- using arm64_entry_point_func = uint32_t (*)(void *entry);
-
-public:
- drcbe_arm64(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits);
- virtual ~drcbe_arm64();
-
- virtual void reset() override;
- virtual int execute(uml::code_handle &entry) override;
- virtual void generate(drcuml_block &block, const uml::instruction *instlist, uint32_t numinst) override;
- virtual bool hash_exists(uint32_t mode, uint32_t pc) override;
- virtual void get_info(drcbe_info &info) override;
- virtual bool logging() const override { return false; }
-
-private:
- class be_parameter
- {
- static inline constexpr int REG_MAX = 30;
-
- public:
- // parameter types
- enum be_parameter_type
- {
- PTYPE_NONE = 0, // invalid
- PTYPE_IMMEDIATE, // immediate; value = sign-extended to 64 bits
- PTYPE_INT_REGISTER, // integer register; value = 0-REG_MAX
- PTYPE_FLOAT_REGISTER, // floating point register; value = 0-REG_MAX
- PTYPE_MEMORY, // memory; value = pointer to memory
- PTYPE_MAX
- };
-
- typedef uint64_t be_parameter_value;
-
- be_parameter() : m_type(PTYPE_NONE), m_value(0) { }
- be_parameter(uint64_t val) : m_type(PTYPE_IMMEDIATE), m_value(val) { }
- be_parameter(drcbe_arm64 &drcbe, const uml::parameter &param, uint32_t allowed);
- be_parameter(const be_parameter &param) = default;
-
- static be_parameter make_ireg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_INT_REGISTER, regnum); }
- static be_parameter make_freg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_FLOAT_REGISTER, regnum); }
- static be_parameter make_memory(void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(base)); }
- static be_parameter make_memory(const void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(const_cast<void *>(base))); }
-
- bool operator==(const be_parameter &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); }
- bool operator!=(const be_parameter &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); }
-
- be_parameter_type type() const { return m_type; }
- uint64_t immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; }
- uint32_t ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value < REG_MAX); return m_value; }
- uint32_t freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value < REG_MAX); return m_value; }
- void *memory() const { assert(m_type == PTYPE_MEMORY); return reinterpret_cast<void *>(m_value); }
-
- bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); }
- bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); }
- bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); }
- bool is_memory() const { return (m_type == PTYPE_MEMORY); }
-
- bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); }
-
- asmjit::a64::Vec get_register_float(uint32_t regsize) const;
- asmjit::a64::Gp get_register_int(uint32_t regsize) const;
- 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;
-
- private:
- be_parameter(be_parameter_type type, be_parameter_value value) : m_type(type), m_value(value) { }
-
- be_parameter_type m_type;
- be_parameter_value m_value;
- };
-
- void op_handle(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_hash(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_label(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_comment(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_mapvar(asmjit::a64::Assembler &a, const uml::instruction &inst);
-
- void op_nop(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_break(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_debug(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_exit(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_hashjmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_jmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_exh(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_callh(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_ret(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_callc(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_recover(asmjit::a64::Assembler &a, const uml::instruction &inst);
-
- void op_setfmod(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_getfmod(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_getexp(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_getflgs(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_setflgs(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_save(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_restore(asmjit::a64::Assembler &a, const uml::instruction &inst);
-
- void op_load(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_loads(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_store(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_read(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_readm(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_write(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_writem(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_carry(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_set(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_mov(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_sext(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_roland(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_rolins(asmjit::a64::Assembler &a, const uml::instruction &inst);
- template <asmjit::a64::Inst::Id Opcode> void op_add(asmjit::a64::Assembler &a, const uml::instruction &inst);
- template <asmjit::a64::Inst::Id Opcode> void op_sub(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_cmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_mulu(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_mululw(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_muls(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_mulslw(asmjit::a64::Assembler &a, const uml::instruction &inst);
- template <asmjit::a64::Inst::Id Opcode> void op_div(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_and(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_test(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_or(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_xor(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_lzcnt(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_tzcnt(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_bswap(asmjit::a64::Assembler &a, const uml::instruction &inst);
- template <asmjit::a64::Inst::Id Opcode> void op_shift(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_rol(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_rolc(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_rorc(asmjit::a64::Assembler &a, const uml::instruction &inst);
-
- void op_fload(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_fstore(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_fread(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_fwrite(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_fmov(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_ftoint(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_ffrint(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_ffrflt(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_frnds(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_fcmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_fcopyi(asmjit::a64::Assembler &a, const uml::instruction &inst);
- void op_icopyf(asmjit::a64::Assembler &a, const uml::instruction &inst);
-
- template <asmjit::a64::Inst::Id Opcode> void op_float_alu(asmjit::a64::Assembler &a, const uml::instruction &inst);
- template <asmjit::a64::Inst::Id Opcode> void op_float_alu2(asmjit::a64::Assembler &a, const uml::instruction &inst);
-
- size_t emit(asmjit::CodeHolder &ch);
-
-
- // helper functions
- void get_imm_relative(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const uint64_t ptr) const;
-
- void emit_ldr_str_base_mem(asmjit::a64::Assembler &a, asmjit::a64::Inst::Id opcode, const asmjit::a64::Reg &reg, int max_shift, 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;
- void emit_ldrh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
- void emit_ldrsb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
- void emit_ldrsh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
- void emit_ldrsw_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
- void emit_str_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
- void emit_strb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
- void emit_strh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
-
- void emit_float_ldr_mem(asmjit::a64::Assembler &a, const asmjit::a64::Vec &reg, const void *ptr) const;
- void emit_float_str_mem(asmjit::a64::Assembler &a, const asmjit::a64::Vec &reg, const void *ptr) const;
-
- void get_carry(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, bool inverted = false) const;
- void load_carry(asmjit::a64::Assembler &a, bool inverted = false) const;
- void store_carry(asmjit::a64::Assembler &a, bool inverted = false) const;
- void store_carry_reg(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg) const;
-
- void store_unordered(asmjit::a64::Assembler &a) const;
- 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 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;
-
- void calculate_carry_shift_right(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const asmjit::a64::Gp &shift) const;
- void calculate_carry_shift_right_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const int shift) const;
-
- void mov_float_reg_param(asmjit::a64::Assembler &a, uint32_t regsize, asmjit::a64::Vec const &dst, const be_parameter &src) const;
- void mov_float_param_param(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, const be_parameter &src) const;
- void mov_float_param_reg(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, asmjit::a64::Vec const &src) const;
- void mov_float_param_int_reg(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, asmjit::a64::Gp const &src) const;
-
- void mov_reg_param(asmjit::a64::Assembler &a, uint32_t regsize, const asmjit::a64::Gp &dst, const be_parameter &src) const;
- void mov_param_reg(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, const asmjit::a64::Gp &src) const;
- void mov_param_imm(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, uint64_t src) const;
- void mov_param_param(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, const be_parameter &src) const;
- void mov_mem_param(asmjit::a64::Assembler &a, uint32_t regsize, void *dst, const be_parameter &src) const;
- void mov_signed_reg64_param32(asmjit::a64::Assembler &a, const asmjit::a64::Gp &dst, const be_parameter &src) const;
- void mov_r64_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp &dst, uint64_t const src) const;
-
- void call_arm_addr(asmjit::a64::Assembler &a, const void *offs) const;
-
- drc_hash_table m_hash;
- drc_map_variables m_map;
- FILE * m_log_asmjit;
-
- arm64_entry_point_func m_entry;
- drccodeptr m_exit;
- drccodeptr m_nocode;
-
- uint8_t *m_baseptr;
-
- struct near_state
- {
- uint32_t emulated_flags;
- };
- near_state &m_near;
-
- using opcode_generate_func = void (drcbe_arm64::*)(asmjit::a64::Assembler &, const uml::instruction &);
- struct opcode_table_entry
- {
- uml::opcode_t opcode;
- opcode_generate_func func;
- };
- static const opcode_table_entry s_opcode_table_source[];
- static opcode_generate_func s_opcode_table[uml::OP_MAX];
-
- struct memory_accessors
- {
- resolved_memory_accessors resolved;
- address_space::specific_access_info specific;
- };
- resolved_member_function m_debug_cpu_instruction_hook;
- resolved_member_function m_drcmap_get_value;
- std::vector<memory_accessors> m_memory_accessors;
-};
+std::unique_ptr<drcbe_interface> make_drcbe_arm64(
+ drcuml_state &drcuml,
+ device_t &device,
+ drc_cache &cache,
+ uint32_t flags,
+ int modes,
+ int addrbits,
+ int ignorebits);
} // namespace drc
-using drc::drcbe_arm64;
-
#endif // MAME_CPU_DRCBEARM64_H
diff --git a/src/devices/cpu/drcbec.cpp b/src/devices/cpu/drcbec.cpp
index d2fa0e744ab..f6f1e1a9242 100644
--- a/src/devices/cpu/drcbec.cpp
+++ b/src/devices/cpu/drcbec.cpp
@@ -9,13 +9,19 @@
***************************************************************************/
#include "emu.h"
-#include "debug/debugcpu.h"
#include "drcbec.h"
+#include "drcbeut.h"
+
+#include "debug/debugcpu.h"
+
#include <cmath>
+
namespace drc {
+namespace {
+
using namespace uml;
@@ -24,22 +30,22 @@ using namespace uml;
//**************************************************************************
// define a bit to match each possible condition, starting at bit 12
-#define ZBIT (0x1000 << (COND_Z & 15))
-#define NZBIT (0x1000 << (COND_NZ & 15))
-#define SBIT (0x1000 << (COND_S & 15))
-#define NSBIT (0x1000 << (COND_NS & 15))
-#define CBIT (0x1000 << (COND_C & 15))
-#define NCBIT (0x1000 << (COND_NC & 15))
-#define VBIT (0x1000 << (COND_V & 15))
-#define NVBIT (0x1000 << (COND_NV & 15))
-#define UBIT (0x1000 << (COND_U & 15))
-#define NUBIT (0x1000 << (COND_NU & 15))
-#define ABIT (0x1000 << (COND_A & 15))
-#define BEBIT (0x1000 << (COND_BE & 15))
-#define GBIT (0x1000 << (COND_G & 15))
-#define GEBIT (0x1000 << (COND_GE & 15))
-#define LBIT (0x1000 << (COND_L & 15))
-#define LEBIT (0x1000 << (COND_LE & 15))
+constexpr uint32_t ZBIT = 0x1000 << (COND_Z & 15);
+constexpr uint32_t NZBIT = 0x1000 << (COND_NZ & 15);
+constexpr uint32_t SBIT = 0x1000 << (COND_S & 15);
+constexpr uint32_t NSBIT = 0x1000 << (COND_NS & 15);
+constexpr uint32_t CBIT = 0x1000 << (COND_C & 15);
+constexpr uint32_t NCBIT = 0x1000 << (COND_NC & 15);
+constexpr uint32_t VBIT = 0x1000 << (COND_V & 15);
+constexpr uint32_t NVBIT = 0x1000 << (COND_NV & 15);
+constexpr uint32_t UBIT = 0x1000 << (COND_U & 15);
+constexpr uint32_t NUBIT = 0x1000 << (COND_NU & 15);
+constexpr uint32_t ABIT = 0x1000 << (COND_A & 15);
+constexpr uint32_t BEBIT = 0x1000 << (COND_BE & 15);
+constexpr uint32_t GBIT = 0x1000 << (COND_G & 15);
+constexpr uint32_t GEBIT = 0x1000 << (COND_GE & 15);
+constexpr uint32_t LBIT = 0x1000 << (COND_L & 15);
+constexpr uint32_t LEBIT = 0x1000 << (COND_LE & 15);
// internal opcodes
@@ -207,6 +213,121 @@ enum
#define FLAGS64_NZCV_SUBC(r,a,b,c) (FLAGS64_NZ(r) | FLAGS64_C_SUBC(a,b,c) | FLAGS64_V_SUB(r,a,b))
+//-------------------------------------------------
+// dmulu - perform a double-wide unsigned multiply
+//-------------------------------------------------
+
+inline int dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2, bool flags)
+{
+ // shortcut if we don't care about the high bits or the flags
+ if (&dstlo == &dsthi && !flags)
+ {
+ dstlo = src1 * src2;
+ return 0;
+ }
+
+ // fetch source values
+ uint64_t a = src1;
+ uint64_t b = src2;
+ if (a == 0 || b == 0)
+ {
+ dsthi = dstlo = 0;
+ return FLAG_Z;
+ }
+
+ // compute high and low parts first
+ uint64_t lo = uint64_t(uint32_t(a >> 0)) * uint64_t(uint32_t(b >> 0));
+ uint64_t hi = uint64_t(uint32_t(a >> 32)) * uint64_t(uint32_t(b >> 32));
+
+ // compute middle parts
+ uint64_t prevlo = lo;
+ uint64_t temp = uint64_t(uint32_t(a >> 32)) * uint64_t(uint32_t(b >> 0));
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ prevlo = lo;
+ temp = uint64_t(uint32_t(a >> 0)) * uint64_t(uint32_t(b >> 32));
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ // store the results
+ dsthi = hi;
+ dstlo = lo;
+ return ((hi >> 60) & FLAG_S) | ((hi != 0) << 1);
+}
+
+
+//-------------------------------------------------
+// dmuls - perform a double-wide signed multiply
+//-------------------------------------------------
+
+inline int dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2, bool flags)
+{
+ // shortcut if we don't care about the high bits or the flags
+ if (&dstlo == &dsthi && !flags)
+ {
+ dstlo = src1 * src2;
+ return 0;
+ }
+
+ // fetch absolute source values
+ uint64_t a = src1; if (int64_t(a) < 0) a = -a;
+ uint64_t b = src2; if (int64_t(b) < 0) b = -b;
+ if (a == 0 || b == 0)
+ {
+ dsthi = dstlo = 0;
+ return FLAG_Z;
+ }
+
+ // compute high and low parts first
+ uint64_t lo = uint64_t(uint32_t(a >> 0)) * uint64_t(uint32_t(b >> 0));
+ uint64_t hi = uint64_t(uint32_t(a >> 32)) * uint64_t(uint32_t(b >> 32));
+
+ // compute middle parts
+ uint64_t prevlo = lo;
+ uint64_t temp = uint64_t(uint32_t(a >> 32)) * uint64_t(uint32_t(b >> 0));
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ prevlo = lo;
+ temp = uint64_t(uint32_t(a >> 0)) * uint64_t(uint32_t(b >> 32));
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ // adjust for signage
+ if (int64_t(src1 ^ src2) < 0)
+ {
+ hi = ~hi + ((lo == 0) ? 1 : 0);
+ lo = ~lo + 1;
+ }
+
+ // store the results
+ dsthi = hi;
+ dstlo = lo;
+ return ((hi >> 60) & FLAG_S) | ((hi != (int64_t(lo) >> 63)) << 1);
+}
+
+inline uint32_t tzcount32(uint32_t value)
+{
+ for (int i = 0; i < 32; i++)
+ {
+ if (value & (uint32_t(1) << i))
+ return i;
+ }
+ return 32;
+}
+
+inline uint64_t tzcount64(uint64_t value)
+{
+ for (int i = 0; i < 64; i++)
+ {
+ if (value & (uint64_t(1) << i))
+ return i;
+ }
+ return 64;
+}
+
+
//**************************************************************************
// TYPE DEFINITIONS
@@ -236,6 +357,36 @@ union drcbec_instruction
};
+class drcbe_c : public drcbe_interface
+{
+public:
+ // construction/destruction
+ drcbe_c(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits);
+ virtual ~drcbe_c();
+
+ // required overrides
+ virtual void reset() override;
+ virtual int execute(uml::code_handle &entry) override;
+ virtual void generate(drcuml_block &block, const uml::instruction *instlist, uint32_t numinst) override;
+ virtual bool hash_exists(uint32_t mode, uint32_t pc) override;
+ virtual void get_info(drcbe_info &info) override;
+
+private:
+ // helpers
+ void output_parameter(drcbec_instruction **dstptr, void **immedptr, int size, const uml::parameter &param);
+ void fixup_label(void *parameter, drccodeptr labelcodeptr);
+
+ // internal state
+ drc_hash_table m_hash; // hash table state
+ drc_map_variables m_map; // code map
+ drc_label_list m_labels; // label list
+ drc_label_fixup_delegate m_fixup_delegate; // precomputed delegate
+
+ static const uint32_t s_condition_map[32];
+ static uint64_t s_immediate_zero;
+};
+
+
//**************************************************************************
// GLOBAL VARIABLES
@@ -289,12 +440,12 @@ const uint32_t drcbe_c::s_condition_map[] =
// drcbe_c - constructor
//-------------------------------------------------
-drcbe_c::drcbe_c(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits)
- : drcbe_interface(drcuml, cache, device),
- m_hash(cache, modes, addrbits, ignorebits),
- m_map(cache, 0xaaaaaaaa55555555),
- m_labels(cache),
- m_fixup_delegate(&drcbe_c::fixup_label, this)
+drcbe_c::drcbe_c(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits) :
+ drcbe_interface(drcuml, cache, device),
+ m_hash(cache, modes, addrbits, ignorebits),
+ m_map(cache, 0xaaaaaaaa55555555),
+ m_labels(cache),
+ m_fixup_delegate(&drcbe_c::fixup_label, this)
{
}
@@ -2324,119 +2475,19 @@ void drcbe_c::fixup_label(void *parameter, drccodeptr labelcodeptr)
dst->inst = (drcbec_instruction *)labelcodeptr;
}
+} // anonymous namespace
-//-------------------------------------------------
-// dmulu - perform a double-wide unsigned multiply
-//-------------------------------------------------
-
-int drcbe_c::dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2, bool flags)
-{
- // shortcut if we don't care about the high bits or the flags
- if (&dstlo == &dsthi && flags == false)
- {
- dstlo = src1 * src2;
- return 0;
- }
-
- // fetch source values
- uint64_t a = src1;
- uint64_t b = src2;
- if (a == 0 || b == 0)
- {
- dsthi = dstlo = 0;
- return FLAG_Z;
- }
-
- // compute high and low parts first
- uint64_t lo = (uint64_t)(uint32_t)(a >> 0) * (uint64_t)(uint32_t)(b >> 0);
- uint64_t hi = (uint64_t)(uint32_t)(a >> 32) * (uint64_t)(uint32_t)(b >> 32);
-
- // compute middle parts
- uint64_t prevlo = lo;
- uint64_t temp = (uint64_t)(uint32_t)(a >> 32) * (uint64_t)(uint32_t)(b >> 0);
- lo += temp << 32;
- hi += (temp >> 32) + (lo < prevlo);
-
- prevlo = lo;
- temp = (uint64_t)(uint32_t)(a >> 0) * (uint64_t)(uint32_t)(b >> 32);
- lo += temp << 32;
- hi += (temp >> 32) + (lo < prevlo);
-
- // store the results
- dsthi = hi;
- dstlo = lo;
- return ((hi >> 60) & FLAG_S) | ((hi != 0) << 1);
-}
-
-
-//-------------------------------------------------
-// dmuls - perform a double-wide signed multiply
-//-------------------------------------------------
-
-int drcbe_c::dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2, bool flags)
-{
- // shortcut if we don't care about the high bits or the flags
- if (&dstlo == &dsthi && flags == false)
- {
- dstlo = src1 * src2;
- return 0;
- }
-
- // fetch absolute source values
- uint64_t a = src1; if ((int64_t)a < 0) a = -a;
- uint64_t b = src2; if ((int64_t)b < 0) b = -b;
- if (a == 0 || b == 0)
- {
- dsthi = dstlo = 0;
- return FLAG_Z;
- }
-
- // compute high and low parts first
- uint64_t lo = (uint64_t)(uint32_t)(a >> 0) * (uint64_t)(uint32_t)(b >> 0);
- uint64_t hi = (uint64_t)(uint32_t)(a >> 32) * (uint64_t)(uint32_t)(b >> 32);
-
- // compute middle parts
- uint64_t prevlo = lo;
- uint64_t temp = (uint64_t)(uint32_t)(a >> 32) * (uint64_t)(uint32_t)(b >> 0);
- lo += temp << 32;
- hi += (temp >> 32) + (lo < prevlo);
-
- prevlo = lo;
- temp = (uint64_t)(uint32_t)(a >> 0) * (uint64_t)(uint32_t)(b >> 32);
- lo += temp << 32;
- hi += (temp >> 32) + (lo < prevlo);
-
- // adjust for signage
- if ((int64_t)(src1 ^ src2) < 0)
- {
- hi = ~hi + (lo == 0);
- lo = ~lo + 1;
- }
-
- // store the results
- dsthi = hi;
- dstlo = lo;
- return ((hi >> 60) & FLAG_S) | ((hi != ((int64_t)lo >> 63)) << 1);
-}
-
-uint32_t drcbe_c::tzcount32(uint32_t value)
-{
- for (int i = 0; i < 32; i++)
- {
- if (value & (1 << i))
- return i;
- }
- return 32;
-}
-uint64_t drcbe_c::tzcount64(uint64_t value)
+std::unique_ptr<drcbe_interface> make_drcbe_c(
+ drcuml_state &drcuml,
+ device_t &device,
+ drc_cache &cache,
+ uint32_t flags,
+ int modes,
+ int addrbits,
+ int ignorebits)
{
- for (int i = 0; i < 64; i++)
- {
- if (value & ((uint64_t)(1) << i))
- return i;
- }
- return 64;
+ return std::unique_ptr<drcbe_interface>(new drcbe_c(drcuml, device, cache, flags, modes, addrbits, ignorebits));
}
} // namespace drc
diff --git a/src/devices/cpu/drcbec.h b/src/devices/cpu/drcbec.h
index 6c572fb65b0..4bfea5a46f4 100644
--- a/src/devices/cpu/drcbec.h
+++ b/src/devices/cpu/drcbec.h
@@ -14,52 +14,21 @@
#pragma once
#include "drcuml.h"
-#include "drcbeut.h"
+#include <memory>
-namespace drc {
-
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-union drcbec_instruction;
-
-class drcbe_c : public drcbe_interface
-{
-public:
- // construction/destruction
- drcbe_c(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits);
- virtual ~drcbe_c();
- // required overrides
- virtual void reset() override;
- virtual int execute(uml::code_handle &entry) override;
- virtual void generate(drcuml_block &block, const uml::instruction *instlist, uint32_t numinst) override;
- virtual bool hash_exists(uint32_t mode, uint32_t pc) override;
- virtual void get_info(drcbe_info &info) override;
-
-private:
- // helpers
- void output_parameter(drcbec_instruction **dstptr, void **immedptr, int size, const uml::parameter &param);
- void fixup_label(void *parameter, drccodeptr labelcodeptr);
- int dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2, bool flags);
- int dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2, bool flags);
- uint32_t tzcount32(uint32_t value);
- uint64_t tzcount64(uint64_t value);
-
- // internal state
- drc_hash_table m_hash; // hash table state
- drc_map_variables m_map; // code map
- drc_label_list m_labels; // label list
- drc_label_fixup_delegate m_fixup_delegate; // precomputed delegate
+namespace drc {
- static const uint32_t s_condition_map[32];
- static uint64_t s_immediate_zero;
-};
+std::unique_ptr<drcbe_interface> make_drcbe_c(
+ drcuml_state &drcuml,
+ device_t &device,
+ drc_cache &cache,
+ uint32_t flags,
+ int modes,
+ int addrbits,
+ int ignorebits);
} // namespace drc
-using drc::drcbe_c;
-
#endif // MAME_CPU_DRCBEC_H
diff --git a/src/devices/cpu/drcbex64.cpp b/src/devices/cpu/drcbex64.cpp
index 1d2033f2977..d6dab04f58d 100644
--- a/src/devices/cpu/drcbex64.cpp
+++ b/src/devices/cpu/drcbex64.cpp
@@ -190,24 +190,30 @@
#include "emu.h"
#include "drcbex64.h"
+#include "drcbeut.h"
+#include "x86log.h"
+
#include "debug/debugcpu.h"
#include "emuopts.h"
+#include "asmjit/src/asmjit/asmjit.h"
+
#include <cstddef>
+#include <vector>
// This is a trick to make it build on Android where the ARM SDK declares ::REG_Rn
// and the x64 SDK declares ::REG_Exx and ::REG_Rxx
namespace drc {
+namespace {
+
using namespace uml;
using namespace asmjit;
using namespace asmjit::x86;
-namespace {
-
//**************************************************************************
// DEBUGGING
//**************************************************************************
@@ -343,7 +349,276 @@ inline bool is_nonvolatile_register(Gp reg)
#endif
}
-} // anonymous namespace
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class drcbe_x64 : public drcbe_interface
+{
+ using x86_entry_point_func = uint32_t (*)(uint8_t *rbpvalue, x86code *entry);
+
+public:
+ // construction/destruction
+ drcbe_x64(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits);
+ virtual ~drcbe_x64();
+
+ // required overrides
+ virtual void reset() override;
+ virtual int execute(uml::code_handle &entry) override;
+ virtual void generate(drcuml_block &block, const uml::instruction *instlist, uint32_t numinst) override;
+ virtual bool hash_exists(uint32_t mode, uint32_t pc) override;
+ virtual void get_info(drcbe_info &info) override;
+ virtual bool logging() const override { return m_log != nullptr; }
+
+private:
+ // a be_parameter is similar to a uml::parameter but maps to native registers/memory
+ class be_parameter
+ {
+ public:
+ // HACK: leftover from x86emit
+ static inline constexpr int REG_MAX = 16;
+
+ // parameter types
+ enum be_parameter_type
+ {
+ PTYPE_NONE = 0, // invalid
+ PTYPE_IMMEDIATE, // immediate; value = sign-extended to 64 bits
+ PTYPE_INT_REGISTER, // integer register; value = 0-REG_MAX
+ PTYPE_FLOAT_REGISTER, // floating point register; value = 0-REG_MAX
+ PTYPE_MEMORY, // memory; value = pointer to memory
+ PTYPE_MAX
+ };
+
+ // represents the value of a parameter
+ typedef uint64_t be_parameter_value;
+
+ // construction
+ be_parameter() : m_type(PTYPE_NONE), m_value(0) { }
+ be_parameter(uint64_t val) : m_type(PTYPE_IMMEDIATE), m_value(val) { }
+ be_parameter(drcbe_x64 &drcbe, const uml::parameter &param, uint32_t allowed);
+ be_parameter(const be_parameter &param) = default;
+
+ // creators for types that don't safely default
+ static be_parameter make_ireg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_INT_REGISTER, regnum); }
+ static be_parameter make_freg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_FLOAT_REGISTER, regnum); }
+ static be_parameter make_memory(void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(base)); }
+ static be_parameter make_memory(const void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(const_cast<void *>(base))); }
+
+ // operators
+ bool operator==(be_parameter const &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); }
+ bool operator!=(be_parameter const &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); }
+
+ // getters
+ be_parameter_type type() const { return m_type; }
+ uint64_t immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; }
+ uint32_t ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value < REG_MAX); return m_value; }
+ uint32_t freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value < REG_MAX); return m_value; }
+ void *memory() const { assert(m_type == PTYPE_MEMORY); return reinterpret_cast<void *>(m_value); }
+
+ // type queries
+ bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); }
+ bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); }
+ bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); }
+ bool is_memory() const { return (m_type == PTYPE_MEMORY); }
+
+ // other queries
+ bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); }
+
+ // helpers
+ asmjit::x86::Gp select_register(asmjit::x86::Gp defreg) const;
+ asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg) const;
+ asmjit::x86::Gp select_register(asmjit::x86::Gp defreg, be_parameter const &checkparam) const;
+ asmjit::x86::Gp select_register(asmjit::x86::Gp defreg, be_parameter const &checkparam, be_parameter const &checkparam2) const;
+ asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg, be_parameter const &checkparam) const;
+
+ private:
+ // private constructor
+ be_parameter(be_parameter_type type, be_parameter_value value) : m_type(type), m_value(value) { }
+
+ // internals
+ be_parameter_type m_type; // parameter type
+ be_parameter_value m_value; // parameter value
+ };
+
+ // helpers
+ asmjit::x86::Mem MABS(const void *ptr, const uint32_t size = 0) const { return asmjit::x86::Mem(asmjit::x86::rbp, offset_from_rbp(ptr), size); }
+ bool short_immediate(int64_t immediate) const { return (int32_t)immediate == immediate; }
+ void normalize_commutative(be_parameter &inner, be_parameter &outer);
+ int32_t offset_from_rbp(const void *ptr) const;
+ asmjit::x86::Gp get_base_register_and_offset(asmjit::x86::Assembler &a, void *target, asmjit::x86::Gp const &reg, int32_t &offset);
+ void smart_call_r64(asmjit::x86::Assembler &a, x86code *target, asmjit::x86::Gp const &reg);
+ void smart_call_m64(asmjit::x86::Assembler &a, x86code **target);
+
+ static void debug_log_hashjmp(offs_t pc, int mode);
+ static void debug_log_hashjmp_fail();
+
+ // code generators
+ void op_handle(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_hash(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_label(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_comment(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_mapvar(asmjit::x86::Assembler &a, const uml::instruction &inst);
+
+ void op_nop(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_break(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_debug(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_exit(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_hashjmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_jmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_exh(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_callh(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_ret(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_callc(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_recover(asmjit::x86::Assembler &a, const uml::instruction &inst);
+
+ void op_setfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_getfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_getexp(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_getflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_setflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_save(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_restore(asmjit::x86::Assembler &a, const uml::instruction &inst);
+
+ void op_load(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_loads(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_store(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_read(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_readm(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_write(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_writem(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_carry(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_set(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_mov(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_sext(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_roland(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_rolins(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_add(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_addc(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_sub(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_subc(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_cmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_mulu(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_mululw(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_muls(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_mulslw(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_divu(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_divs(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_and(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_test(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_or(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_xor(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_lzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_tzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_bswap(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ template <asmjit::x86::Inst::Id Opcode> void op_shift(asmjit::x86::Assembler &a, const uml::instruction &inst);
+
+ void op_fload(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fstore(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fread(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fwrite(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fmov(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_ftoint(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_ffrint(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_ffrflt(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_frnds(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fadd(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fsub(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fcmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fmul(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fdiv(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fneg(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fabs(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_frecip(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_frsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fcopyi(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_icopyf(asmjit::x86::Assembler &a, const uml::instruction &inst);
+
+ // alu and shift operation helpers
+ static bool ones(u64 const value, unsigned const size) noexcept { return (size == 4) ? u32(value) == 0xffffffffU : value == 0xffffffff'ffffffffULL; }
+ void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param, std::function<bool(asmjit::x86::Assembler &a, asmjit::Operand const &dst, be_parameter const &src)> optimize = [](asmjit::x86::Assembler &a, asmjit::Operand dst, be_parameter const &src) { return false; });
+ void shift_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, size_t opsize, asmjit::Operand const &dst, be_parameter const &param, bool update_flags);
+
+ // parameter helpers
+ void mov_reg_param(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param, bool const keepflags = false);
+ void mov_param_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reg);
+ void mov_mem_param(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref, be_parameter const &param);
+
+ // special-case move helpers
+ void movsx_r64_p32(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param);
+ void mov_r64_imm(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, uint64_t const imm);
+
+ // floating-point helpers
+ void movss_r128_p32(asmjit::x86::Assembler &a, asmjit::x86::Xmm const &reg, be_parameter const &param);
+ void movss_p32_r128(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Xmm const &reg);
+ void movsd_r128_p64(asmjit::x86::Assembler &a, asmjit::x86::Xmm const &reg, be_parameter const &param);
+ void movsd_p64_r128(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Xmm const &reg);
+
+ void calculate_status_flags(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::Operand const &dst, u8 flags);
+ void calculate_status_flags_mul(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo, asmjit::x86::Gp const &hi);
+ void calculate_status_flags_mul_low(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo);
+
+ size_t emit(asmjit::CodeHolder &ch);
+
+ // internal state
+ drc_hash_table m_hash; // hash table state
+ drc_map_variables m_map; // code map
+ x86log_context * m_log; // logging
+ FILE * m_log_asmjit;
+
+ uint32_t * m_absmask32; // absolute value mask (32-bit)
+ uint64_t * m_absmask64; // absolute value mask (32-bit)
+ uint8_t * m_rbpvalue; // value of RBP
+
+ x86_entry_point_func m_entry; // entry point
+ x86code * m_exit; // exit point
+ x86code * m_nocode; // nocode handler
+
+ // state to live in the near cache
+ struct near_state
+ {
+ x86code * debug_log_hashjmp; // hashjmp debugging
+ x86code * debug_log_hashjmp_fail; // hashjmp debugging
+
+ uint32_t ssemode; // saved SSE mode
+ uint32_t ssemodesave; // temporary location for saving
+ uint32_t ssecontrol[4]; // copy of the sse_control array
+ float single1; // 1.0 in single-precision
+ double double1; // 1.0 in double-precision
+
+ void * stacksave; // saved stack pointer
+
+ uint8_t flagsmap[0x1000]; // flags map
+ uint64_t flagsunmap[0x20]; // flags unmapper
+ };
+ near_state & m_near;
+
+ // resolved memory handler functions
+ struct memory_accessors
+ {
+ resolved_memory_accessors resolved;
+ address_space::specific_access_info specific;
+ offs_t address_mask;
+ bool no_mask;
+ bool has_high_bits;
+ bool mask_high_bits;
+ };
+ resolved_member_function m_debug_cpu_instruction_hook;
+ resolved_member_function m_drcmap_get_value;
+ std::vector<memory_accessors> m_memory_accessors;
+
+ // globals
+ using opcode_generate_func = void (drcbe_x64::*)(asmjit::x86::Assembler &, const uml::instruction &);
+ struct opcode_table_entry
+ {
+ uml::opcode_t opcode; // opcode in question
+ opcode_generate_func func; // function pointer to the work
+ };
+ static const opcode_table_entry s_opcode_table_source[];
+ static opcode_generate_func s_opcode_table[uml::OP_MAX];
+};
@@ -5800,4 +6075,19 @@ void drcbe_x64::op_icopyf(Assembler &a, const instruction &inst)
}
}
+} // anonymous namespace
+
+
+std::unique_ptr<drcbe_interface> make_drcbe_x64(
+ drcuml_state &drcuml,
+ device_t &device,
+ drc_cache &cache,
+ uint32_t flags,
+ int modes,
+ int addrbits,
+ int ignorebits)
+{
+ return std::unique_ptr<drcbe_interface>(new drcbe_x64(drcuml, device, cache, flags, modes, addrbits, ignorebits));
+}
+
} // namespace drc
diff --git a/src/devices/cpu/drcbex64.h b/src/devices/cpu/drcbex64.h
index e3d8ee3f4b3..116b4939730 100644
--- a/src/devices/cpu/drcbex64.h
+++ b/src/devices/cpu/drcbex64.h
@@ -13,287 +13,21 @@
#pragma once
#include "drcuml.h"
-#include "drcbeut.h"
-#include "x86log.h"
-#include "asmjit/src/asmjit/asmjit.h"
-
-#include <vector>
+#include <memory>
namespace drc {
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-class drcbe_x64 : public drcbe_interface
-{
- using x86_entry_point_func = uint32_t (*)(uint8_t *rbpvalue, x86code *entry);
-
-public:
- // construction/destruction
- drcbe_x64(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits);
- virtual ~drcbe_x64();
-
- // required overrides
- virtual void reset() override;
- virtual int execute(uml::code_handle &entry) override;
- virtual void generate(drcuml_block &block, const uml::instruction *instlist, uint32_t numinst) override;
- virtual bool hash_exists(uint32_t mode, uint32_t pc) override;
- virtual void get_info(drcbe_info &info) override;
- virtual bool logging() const override { return m_log != nullptr; }
-
-private:
- // a be_parameter is similar to a uml::parameter but maps to native registers/memory
- class be_parameter
- {
- public:
- // HACK: leftover from x86emit
- static inline constexpr int REG_MAX = 16;
-
- // parameter types
- enum be_parameter_type
- {
- PTYPE_NONE = 0, // invalid
- PTYPE_IMMEDIATE, // immediate; value = sign-extended to 64 bits
- PTYPE_INT_REGISTER, // integer register; value = 0-REG_MAX
- PTYPE_FLOAT_REGISTER, // floating point register; value = 0-REG_MAX
- PTYPE_MEMORY, // memory; value = pointer to memory
- PTYPE_MAX
- };
-
- // represents the value of a parameter
- typedef uint64_t be_parameter_value;
-
- // construction
- be_parameter() : m_type(PTYPE_NONE), m_value(0) { }
- be_parameter(uint64_t val) : m_type(PTYPE_IMMEDIATE), m_value(val) { }
- be_parameter(drcbe_x64 &drcbe, const uml::parameter &param, uint32_t allowed);
- be_parameter(const be_parameter &param) = default;
-
- // creators for types that don't safely default
- static be_parameter make_ireg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_INT_REGISTER, regnum); }
- static be_parameter make_freg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_FLOAT_REGISTER, regnum); }
- static be_parameter make_memory(void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(base)); }
- static be_parameter make_memory(const void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(const_cast<void *>(base))); }
-
- // operators
- bool operator==(be_parameter const &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); }
- bool operator!=(be_parameter const &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); }
-
- // getters
- be_parameter_type type() const { return m_type; }
- uint64_t immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; }
- uint32_t ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value < REG_MAX); return m_value; }
- uint32_t freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value < REG_MAX); return m_value; }
- void *memory() const { assert(m_type == PTYPE_MEMORY); return reinterpret_cast<void *>(m_value); }
-
- // type queries
- bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); }
- bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); }
- bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); }
- bool is_memory() const { return (m_type == PTYPE_MEMORY); }
-
- // other queries
- bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); }
-
- // helpers
- asmjit::x86::Gp select_register(asmjit::x86::Gp defreg) const;
- asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg) const;
- asmjit::x86::Gp select_register(asmjit::x86::Gp defreg, be_parameter const &checkparam) const;
- asmjit::x86::Gp select_register(asmjit::x86::Gp defreg, be_parameter const &checkparam, be_parameter const &checkparam2) const;
- asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg, be_parameter const &checkparam) const;
-
- private:
- // private constructor
- be_parameter(be_parameter_type type, be_parameter_value value) : m_type(type), m_value(value) { }
-
- // internals
- be_parameter_type m_type; // parameter type
- be_parameter_value m_value; // parameter value
- };
-
- // helpers
- asmjit::x86::Mem MABS(const void *ptr, const uint32_t size = 0) const { return asmjit::x86::Mem(asmjit::x86::rbp, offset_from_rbp(ptr), size); }
- bool short_immediate(int64_t immediate) const { return (int32_t)immediate == immediate; }
- void normalize_commutative(be_parameter &inner, be_parameter &outer);
- int32_t offset_from_rbp(const void *ptr) const;
- asmjit::x86::Gp get_base_register_and_offset(asmjit::x86::Assembler &a, void *target, asmjit::x86::Gp const &reg, int32_t &offset);
- void smart_call_r64(asmjit::x86::Assembler &a, x86code *target, asmjit::x86::Gp const &reg);
- void smart_call_m64(asmjit::x86::Assembler &a, x86code **target);
-
- static void debug_log_hashjmp(offs_t pc, int mode);
- static void debug_log_hashjmp_fail();
-
- // code generators
- void op_handle(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_hash(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_label(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_comment(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_mapvar(asmjit::x86::Assembler &a, const uml::instruction &inst);
-
- void op_nop(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_break(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_debug(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_exit(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_hashjmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_jmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_exh(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_callh(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_ret(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_callc(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_recover(asmjit::x86::Assembler &a, const uml::instruction &inst);
-
- void op_setfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_getfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_getexp(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_getflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_setflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_save(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_restore(asmjit::x86::Assembler &a, const uml::instruction &inst);
-
- void op_load(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_loads(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_store(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_read(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_readm(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_write(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_writem(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_carry(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_set(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_mov(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_sext(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_roland(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_rolins(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_add(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_addc(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_sub(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_subc(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_cmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_mulu(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_mululw(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_muls(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_mulslw(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_divu(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_divs(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_and(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_test(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_or(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_xor(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_lzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_tzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_bswap(asmjit::x86::Assembler &a, const uml::instruction &inst);
- template <asmjit::x86::Inst::Id Opcode> void op_shift(asmjit::x86::Assembler &a, const uml::instruction &inst);
-
- void op_fload(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fstore(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fread(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fwrite(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fmov(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_ftoint(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_ffrint(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_ffrflt(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_frnds(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fadd(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fsub(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fcmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fmul(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fdiv(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fneg(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fabs(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_frecip(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_frsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fcopyi(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_icopyf(asmjit::x86::Assembler &a, const uml::instruction &inst);
-
- // alu and shift operation helpers
- static bool ones(u64 const value, unsigned const size) noexcept { return (size == 4) ? u32(value) == 0xffffffffU : value == 0xffffffff'ffffffffULL; }
- void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param, std::function<bool(asmjit::x86::Assembler &a, asmjit::Operand const &dst, be_parameter const &src)> optimize = [](asmjit::x86::Assembler &a, asmjit::Operand dst, be_parameter const &src) { return false; });
- void shift_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, size_t opsize, asmjit::Operand const &dst, be_parameter const &param, bool update_flags);
-
- // parameter helpers
- void mov_reg_param(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param, bool const keepflags = false);
- void mov_param_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reg);
- void mov_mem_param(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref, be_parameter const &param);
-
- // special-case move helpers
- void movsx_r64_p32(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param);
- void mov_r64_imm(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, uint64_t const imm);
-
- // floating-point helpers
- void movss_r128_p32(asmjit::x86::Assembler &a, asmjit::x86::Xmm const &reg, be_parameter const &param);
- void movss_p32_r128(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Xmm const &reg);
- void movsd_r128_p64(asmjit::x86::Assembler &a, asmjit::x86::Xmm const &reg, be_parameter const &param);
- void movsd_p64_r128(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Xmm const &reg);
-
- void calculate_status_flags(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::Operand const &dst, u8 flags);
- void calculate_status_flags_mul(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo, asmjit::x86::Gp const &hi);
- void calculate_status_flags_mul_low(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo);
-
- size_t emit(asmjit::CodeHolder &ch);
-
- // internal state
- drc_hash_table m_hash; // hash table state
- drc_map_variables m_map; // code map
- x86log_context * m_log; // logging
- FILE * m_log_asmjit;
-
- uint32_t * m_absmask32; // absolute value mask (32-bit)
- uint64_t * m_absmask64; // absolute value mask (32-bit)
- uint8_t * m_rbpvalue; // value of RBP
-
- x86_entry_point_func m_entry; // entry point
- x86code * m_exit; // exit point
- x86code * m_nocode; // nocode handler
-
- // state to live in the near cache
- struct near_state
- {
- x86code * debug_log_hashjmp; // hashjmp debugging
- x86code * debug_log_hashjmp_fail; // hashjmp debugging
-
- uint32_t ssemode; // saved SSE mode
- uint32_t ssemodesave; // temporary location for saving
- uint32_t ssecontrol[4]; // copy of the sse_control array
- float single1; // 1.0 in single-precision
- double double1; // 1.0 in double-precision
-
- void * stacksave; // saved stack pointer
-
- uint8_t flagsmap[0x1000]; // flags map
- uint64_t flagsunmap[0x20]; // flags unmapper
- };
- near_state & m_near;
-
- // resolved memory handler functions
- struct memory_accessors
- {
- resolved_memory_accessors resolved;
- address_space::specific_access_info specific;
- offs_t address_mask;
- bool no_mask;
- bool has_high_bits;
- bool mask_high_bits;
- };
- resolved_member_function m_debug_cpu_instruction_hook;
- resolved_member_function m_drcmap_get_value;
- std::vector<memory_accessors> m_memory_accessors;
-
- // globals
- using opcode_generate_func = void (drcbe_x64::*)(asmjit::x86::Assembler &, const uml::instruction &);
- struct opcode_table_entry
- {
- uml::opcode_t opcode; // opcode in question
- opcode_generate_func func; // function pointer to the work
- };
- static const opcode_table_entry s_opcode_table_source[];
- static opcode_generate_func s_opcode_table[uml::OP_MAX];
-};
+std::unique_ptr<drcbe_interface> make_drcbe_x64(
+ drcuml_state &drcuml,
+ device_t &device,
+ drc_cache &cache,
+ uint32_t flags,
+ int modes,
+ int addrbits,
+ int ignorebits);
} // namespace drc
-using drc::drcbe_x64;
-
#endif // MAME_CPU_DRCBEX64_H
diff --git a/src/devices/cpu/drcbex86.cpp b/src/devices/cpu/drcbex86.cpp
index 0bb540260cb..af3cf56a839 100644
--- a/src/devices/cpu/drcbex86.cpp
+++ b/src/devices/cpu/drcbex86.cpp
@@ -85,23 +85,27 @@
#include "emu.h"
#include "drcbex86.h"
+#include "drcbeut.h"
+#include "x86log.h"
+
#include "debug/debugcpu.h"
#include "emuopts.h"
-#include "drcuml.h"
+
+#include "asmjit/src/asmjit/asmjit.h"
#include <cstddef>
namespace drc {
+namespace {
+
using namespace uml;
using namespace asmjit;
using namespace asmjit::x86;
-namespace {
-
//**************************************************************************
// DEBUGGING
//**************************************************************************
@@ -190,6 +194,202 @@ const uint16_t fp_control[4] =
+//**************************************************************************
+// MISCELLAENOUS FUNCTIONS
+//**************************************************************************
+
+void calculate_status_flags(Assembler &a, Operand const &dst, u8 flags)
+{
+ // calculate status flags in a way that does not modify any other status flags
+ uint32_t flagmask = 0;
+
+ if (flags & FLAG_C) flagmask |= 0x001;
+ if (flags & FLAG_V) flagmask |= 0x800;
+ if (flags & FLAG_Z) flagmask |= 0x040;
+ if (flags & FLAG_S) flagmask |= 0x080;
+ if (flags & FLAG_U) flagmask |= 0x004;
+
+ if ((flags & (FLAG_Z | FLAG_S)) == flags)
+ {
+ Gp tempreg = dst.isMem() ? eax : dst.as<Gpd>().id() == ebx.id() ? eax : ebx;
+ Gp tempreg2 = dst.isMem() ? edx : dst.as<Gpd>().id() == ecx.id() ? edx : ecx;
+
+ if (dst.isMem())
+ {
+ a.push(tempreg2);
+ a.mov(tempreg2, dst.as<Mem>());
+ }
+
+ a.push(tempreg);
+
+ a.pushfd();
+ a.pop(tempreg);
+ a.and_(tempreg, ~flagmask);
+
+ a.add(dst.isMem() ? tempreg2.as<Gpd>() : dst.as<Gpd>(), 0);
+
+ a.pushfd();
+ a.and_(dword_ptr(esp), flagmask);
+ a.or_(dword_ptr(esp), tempreg);
+ a.popfd();
+
+ a.pop(tempreg);
+
+ if (dst.isMem())
+ a.pop(tempreg2);
+ }
+ else
+ {
+ fatalerror("drcbe_x86::calculate_status_flags: unknown flag combination requested: %02x\n", flags);
+ }
+}
+
+
+//-------------------------------------------------
+// dmulu - perform a double-wide unsigned multiply
+//-------------------------------------------------
+
+int dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2, bool flags, bool halfmul_flags)
+{
+ // shortcut if we don't care about the high bits or the flags
+ if (&dstlo == &dsthi && !flags)
+ {
+ dstlo = src1 * src2;
+ return 0;
+ }
+
+ // fetch source values
+ uint64_t a = src1;
+ uint64_t b = src2;
+ if (a == 0 || b == 0)
+ {
+ dsthi = dstlo = 0;
+ return FLAG_Z;
+ }
+
+ // compute high and low parts first
+ uint64_t lo = uint64_t(uint32_t(a >> 0)) * uint64_t(uint32_t(b >> 0));
+ uint64_t hi = uint64_t(uint32_t(a >> 32)) * uint64_t(uint32_t(b >> 32));
+
+ // compute middle parts
+ uint64_t prevlo = lo;
+ uint64_t temp = uint64_t(uint32_t(a >> 32)) * uint64_t(uint32_t(b >> 0));
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ prevlo = lo;
+ temp = uint64_t(uint32_t(a >> 0)) * uint64_t(uint32_t(b >> 32));
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ // store the results
+ dsthi = hi;
+ dstlo = lo;
+
+ if (halfmul_flags)
+ return ((lo >> 60) & FLAG_S) | ((hi != 0) << 1) | ((dstlo == 0) << 2);
+
+ return ((hi >> 60) & FLAG_S) | ((hi != 0) << 1) | ((dsthi == 0 && dstlo == 0) << 2);
+}
+
+
+//-------------------------------------------------
+// dmuls - perform a double-wide signed multiply
+//-------------------------------------------------
+
+int dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2, bool flags, bool halfmul_flags)
+{
+ uint64_t lo, hi, prevlo;
+ uint64_t a, b, temp;
+
+ // shortcut if we don't care about the high bits or the flags
+ if (&dstlo == &dsthi && !flags)
+ {
+ dstlo = src1 * src2;
+ return 0;
+ }
+
+ // fetch absolute source values
+ a = src1; if (int64_t(a) < 0) a = -a;
+ b = src2; if (int64_t(b) < 0) b = -b;
+ if (a == 0 || b == 0)
+ {
+ dsthi = dstlo = 0;
+ return FLAG_Z;
+ }
+
+ // compute high and low parts first
+ lo = uint64_t(uint32_t(a >> 0)) * uint64_t(uint32_t(b >> 0));
+ hi = uint64_t(uint32_t(a >> 32)) * uint64_t(uint32_t(b >> 32));
+
+ // compute middle parts
+ prevlo = lo;
+ temp = uint64_t(uint32_t(a >> 32)) * uint64_t(uint32_t(b >> 0));
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ prevlo = lo;
+ temp = uint64_t(uint32_t(a >> 0)) * uint64_t(uint32_t(b >> 32));
+ lo += temp << 32;
+ hi += (temp >> 32) + (lo < prevlo);
+
+ // adjust for signage
+ if (int64_t(src1 ^ src2) < 0)
+ {
+ hi = ~hi + (lo == 0);
+ lo = ~lo + 1;
+ }
+
+ // store the results
+ dsthi = hi;
+ dstlo = lo;
+
+ if (halfmul_flags)
+ return ((lo >> 60) & FLAG_S) | ((hi != (int64_t(lo) >> 63)) << 1) | ((dstlo == 0) << 2);
+
+ return ((hi >> 60) & FLAG_S) | ((hi != (int64_t(lo) >> 63)) << 1) | ((dsthi == 0 && dstlo == 0) << 2);
+}
+
+
+//-------------------------------------------------
+// ddivu - perform a double-wide unsigned divide
+//-------------------------------------------------
+
+int ddivu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2)
+{
+ // do nothing if src2 == 0
+ if (src2 == 0)
+ return FLAG_V;
+
+ dstlo = src1 / src2;
+ if (&dstlo != &dsthi)
+ dsthi = src1 % src2;
+ return ((dstlo == 0) << 2) | ((dstlo >> 60) & FLAG_S);
+}
+
+
+//-------------------------------------------------
+// ddivs - perform a double-wide signed divide
+//-------------------------------------------------
+
+int ddivs(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2)
+{
+ // do nothing if src2 == 0
+ if (src2 == 0)
+ return FLAG_V;
+
+ dstlo = src1 / src2;
+ if (&dstlo != &dsthi)
+ dsthi = src1 % src2;
+ return ((dstlo == 0) << 2) | ((dstlo >> 60) & FLAG_S);
+}
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
class ThrowableErrorHandler : public ErrorHandler
{
public:
@@ -199,7 +399,279 @@ public:
}
};
-} // anonymous namespace
+
+class drcbe_x86 : public drcbe_interface
+{
+ using x86_entry_point_func = uint32_t (*)(x86code *entry);
+
+public:
+ // construction/destruction
+ drcbe_x86(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits);
+ virtual ~drcbe_x86();
+
+ // required overrides
+ virtual void reset() override;
+ virtual int execute(uml::code_handle &entry) override;
+ virtual void generate(drcuml_block &block, const uml::instruction *instlist, uint32_t numinst) override;
+ virtual bool hash_exists(uint32_t mode, uint32_t pc) override;
+ virtual void get_info(drcbe_info &info) override;
+ virtual bool logging() const override { return m_log != nullptr; }
+
+private:
+ // HACK: leftover from x86emit
+ static inline constexpr int REG_MAX = 16;
+
+ // a be_parameter is similar to a uml::parameter but maps to native registers/memory
+ class be_parameter
+ {
+ public:
+ // parameter types
+ enum be_parameter_type
+ {
+ PTYPE_NONE = 0, // invalid
+ PTYPE_IMMEDIATE, // immediate; value = sign-extended to 64 bits
+ PTYPE_INT_REGISTER, // integer register; value = 0-REG_MAX
+ PTYPE_FLOAT_REGISTER, // floating point register; value = 0-REG_MAX
+ PTYPE_MEMORY, // memory; value = pointer to memory
+ PTYPE_MAX
+ };
+
+ // represents the value of a parameter
+ typedef uint64_t be_parameter_value;
+
+ // construction
+ be_parameter() : m_type(PTYPE_NONE), m_value(0) { }
+ be_parameter(uint64_t val) : m_type(PTYPE_IMMEDIATE), m_value(val) { }
+ be_parameter(drcbe_x86 &drcbe, const uml::parameter &param, uint32_t allowed);
+ be_parameter(const be_parameter &param) = default;
+
+ // creators for types that don't safely default
+ static be_parameter make_ireg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_INT_REGISTER, regnum); }
+ static be_parameter make_freg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_FLOAT_REGISTER, regnum); }
+ static be_parameter make_memory(void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(base)); }
+ static be_parameter make_memory(const void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(const_cast<void *>(base))); }
+
+ // operators
+ bool operator==(be_parameter const &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); }
+ bool operator!=(be_parameter const &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); }
+
+ // getters
+ be_parameter_type type() const { return m_type; }
+ uint64_t immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; }
+ uint32_t ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value < REG_MAX); return m_value; }
+ uint32_t freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value < REG_MAX); return m_value; }
+ void *memory(uint32_t offset = 0) const { assert(m_type == PTYPE_MEMORY); return reinterpret_cast<void *>(m_value + offset); }
+
+ // type queries
+ bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); }
+ bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); }
+ bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); }
+ bool is_memory() const { return (m_type == PTYPE_MEMORY); }
+
+ // other queries
+ bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); }
+
+ // helpers
+ asmjit::x86::Gpd select_register(asmjit::x86::Gpd const &defreg) const;
+ asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg) const;
+ template <typename T> T select_register(T defreg, be_parameter const &checkparam) const;
+ template <typename T> T select_register(T defreg, be_parameter const &checkparam, be_parameter const &checkparam2) const;
+
+ private:
+ // private constructor
+ be_parameter(be_parameter_type type, be_parameter_value value) : m_type(type), m_value(value) { }
+
+ // internals
+ be_parameter_type m_type; // parameter type
+ be_parameter_value m_value; // parameter value
+ };
+
+ // helpers
+ asmjit::x86::Mem MABS(void const *base, u32 const size = 0) const { return asmjit::x86::Mem(u64(base), size); }
+ void normalize_commutative(be_parameter &inner, be_parameter &outer);
+ void emit_combine_z_flags(asmjit::x86::Assembler &a);
+ void emit_combine_zs_flags(asmjit::x86::Assembler &a);
+ void emit_combine_z_shl_flags(asmjit::x86::Assembler &a);
+ void reset_last_upper_lower_reg();
+ void set_last_lower_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reglo);
+ void set_last_upper_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reghi);
+ bool can_skip_lower_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const &reglo);
+ bool can_skip_upper_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const &reghi);
+
+ static void debug_log_hashjmp(int mode, offs_t pc);
+
+ // code generators
+ void op_handle(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_hash(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_label(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_comment(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_mapvar(asmjit::x86::Assembler &a, const uml::instruction &inst);
+
+ void op_nop(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_break(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_debug(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_exit(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_hashjmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_jmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_exh(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_callh(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_ret(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_callc(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_recover(asmjit::x86::Assembler &a, const uml::instruction &inst);
+
+ void op_setfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_getfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_getexp(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_getflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_setflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_save(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_restore(asmjit::x86::Assembler &a, const uml::instruction &inst);
+
+ void op_load(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_loads(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_store(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_read(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_readm(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_write(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_writem(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_carry(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_set(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_mov(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_sext(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_roland(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_rolins(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_add(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_addc(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_sub(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_subc(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_cmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_mulu(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_mululw(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_muls(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_mulslw(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_divu(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_divs(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_and(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_test(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_or(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_xor(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_lzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_tzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_bswap(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_shl(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_shr(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_sar(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_ror(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_rol(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_rorc(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_rolc(asmjit::x86::Assembler &a, const uml::instruction &inst);
+
+ void op_fload(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fstore(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fread(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fwrite(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fmov(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_ftoint(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_ffrint(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_ffrflt(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_frnds(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fadd(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fsub(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fcmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fmul(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fdiv(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fneg(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fabs(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_frecip(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_frsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_fcopyi(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ void op_icopyf(asmjit::x86::Assembler &a, const uml::instruction &inst);
+
+ // 32-bit code emission helpers
+ void emit_mov_r32_p32(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param);
+ void emit_mov_r32_p32_keepflags(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param);
+ void emit_mov_m32_p32(asmjit::x86::Assembler &a, asmjit::x86::Mem memref, be_parameter const &param);
+ void emit_mov_p32_r32(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reg);
+
+ void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param, std::function<bool(asmjit::x86::Assembler &a, asmjit::Operand const &dst, be_parameter const &src)> optimize = [](asmjit::x86::Assembler &a, asmjit::Operand dst, be_parameter const &src) { return false; });
+ void shift_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, size_t opsize, asmjit::Operand const &dst, be_parameter const &param, std::function<bool(asmjit::x86::Assembler &a, asmjit::Operand const &dst, be_parameter const &src)> optimize, bool update_flags);
+
+ // 64-bit code emission helpers
+ void emit_mov_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param);
+ void emit_mov_r64_p64_keepflags(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param);
+ void emit_mov_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref, be_parameter const &param);
+ void emit_mov_p64_r64(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi);
+ void emit_and_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
+ void emit_and_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref_lo, asmjit::x86::Mem const &memref_hi, be_parameter const &param, const uml::instruction &inst);
+ void emit_or_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
+ void emit_or_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref_lo, asmjit::x86::Mem const &memref_hi, be_parameter const &param, const uml::instruction &inst);
+ void emit_xor_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
+ void emit_xor_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref_lo, asmjit::x86::Mem const &memref_hi, be_parameter const &param, const uml::instruction &inst);
+ void emit_shl_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
+ void emit_shr_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
+ void emit_sar_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
+ void emit_rol_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
+ void emit_ror_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
+ void emit_rcl_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
+ void emit_rcr_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
+
+ void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode_lo, asmjit::x86::Inst::Id const opcode_hi, asmjit::x86::Gp const &lo, asmjit::x86::Gp const &hi, be_parameter const &param, bool const saveflags);
+ void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode_lo, asmjit::x86::Inst::Id const opcode_hi, asmjit::x86::Mem const &lo, asmjit::x86::Mem const &hi, be_parameter const &param, bool const saveflags);
+
+ // floating-point code emission helpers
+ void emit_fld_p(asmjit::x86::Assembler &a, int size, be_parameter const &param);
+ void emit_fstp_p(asmjit::x86::Assembler &a, int size, be_parameter const &param);
+
+ size_t emit(asmjit::CodeHolder &ch);
+
+ // internal state
+ drc_hash_table m_hash; // hash table state
+ drc_map_variables m_map; // code map
+ x86log_context * m_log; // logging
+ FILE * m_log_asmjit;
+ bool m_logged_common; // logged common code already?
+ bool const m_sse3; // do we have SSE3 support?
+
+ x86_entry_point_func m_entry; // entry point
+ x86code * m_exit; // exit point
+ x86code * m_nocode; // nocode handler
+ x86code * m_save; // save handler
+ x86code * m_restore; // restore handler
+
+ uint32_t * m_reglo[REG_MAX]; // pointer to low part of data for each register
+ uint32_t * m_reghi[REG_MAX]; // pointer to high part of data for each register
+ asmjit::x86::Gp m_last_lower_reg; // last register we stored a lower from
+ x86code * m_last_lower_pc; // PC after instruction where we last stored a lower register
+ uint32_t * m_last_lower_addr; // address where we last stored an lower register
+ asmjit::x86::Gp m_last_upper_reg; // last register we stored an upper from
+ x86code * m_last_upper_pc; // PC after instruction where we last stored an upper register
+ uint32_t * m_last_upper_addr; // address where we last stored an upper register
+ double m_fptemp; // temporary storage for floating point
+
+ uint16_t m_fpumode; // saved FPU mode
+ uint16_t m_fmodesave; // temporary location for saving
+
+ void * m_stacksave; // saved stack pointer
+ void * m_hashstacksave; // saved stack pointer for hashjmp
+ uint64_t m_reslo; // extended low result
+ uint64_t m_reshi; // extended high result
+
+ // resolved memory handler functions
+ resolved_member_function m_debug_cpu_instruction_hook;
+ resolved_member_function m_drcmap_get_value;
+ resolved_memory_accessors_vector m_memory_accessors;
+
+ // globals
+ typedef void (drcbe_x86::*opcode_generate_func)(asmjit::x86::Assembler &a, const uml::instruction &inst);
+ struct opcode_table_entry
+ {
+ uml::opcode_t opcode; // opcode in question
+ opcode_generate_func func; // function pointer to the work
+ };
+ static const opcode_table_entry s_opcode_table_source[];
+ static opcode_generate_func s_opcode_table[uml::OP_MAX];
+};
@@ -1097,52 +1569,6 @@ void drcbe_x86::alu_op_param(Assembler &a, Inst::Id const opcode, Operand const
a.emit(opcode, dst, Gpd(param.ireg())); // op dst,param
}
-void drcbe_x86::calculate_status_flags(Assembler &a, Operand const &dst, u8 flags)
-{
- // calculate status flags in a way that does not modify any other status flags
- uint32_t flagmask = 0;
-
- if (flags & FLAG_C) flagmask |= 0x001;
- if (flags & FLAG_V) flagmask |= 0x800;
- if (flags & FLAG_Z) flagmask |= 0x040;
- if (flags & FLAG_S) flagmask |= 0x080;
- if (flags & FLAG_U) flagmask |= 0x004;
-
- if ((flags & (FLAG_Z | FLAG_S)) == flags)
- {
- Gp tempreg = dst.isMem() ? eax : dst.as<Gpd>().id() == ebx.id() ? eax : ebx;
- Gp tempreg2 = dst.isMem() ? edx : dst.as<Gpd>().id() == ecx.id() ? edx : ecx;
-
- if (dst.isMem())
- {
- a.push(tempreg2);
- a.mov(tempreg2, dst.as<Mem>());
- }
-
- a.push(tempreg);
-
- a.pushfd();
- a.pop(tempreg);
- a.and_(tempreg, ~flagmask);
-
- a.add(dst.isMem() ? tempreg2.as<Gpd>() : dst.as<Gpd>(), 0);
-
- a.pushfd();
- a.and_(dword_ptr(esp), flagmask);
- a.or_(dword_ptr(esp), tempreg);
- a.popfd();
-
- a.pop(tempreg);
-
- if (dst.isMem())
- a.pop(tempreg2);
- }
- else
- {
- fatalerror("drcbe_x86::calculate_status_flags: unknown flag combination requested: %02x\n", flags);
- }
-}
-
void drcbe_x86::shift_op_param(Assembler &a, Inst::Id const opcode, size_t opsize, Operand const &dst, be_parameter const &param, std::function<bool(Assembler &a, Operand const &dst, be_parameter const &src)> optimize, bool update_flags)
{
if (param.is_immediate())
@@ -6817,149 +7243,19 @@ void drcbe_x86::op_icopyf(Assembler &a, const instruction &inst)
}
}
+} // anonymous namespace
-//**************************************************************************
-// MISCELLAENOUS FUNCTIONS
-//**************************************************************************
-
-//-------------------------------------------------
-// dmulu - perform a double-wide unsigned multiply
-//-------------------------------------------------
-
-int drcbe_x86::dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2, bool flags, bool halfmul_flags)
-{
- // shortcut if we don't care about the high bits or the flags
- if (&dstlo == &dsthi && flags == false)
- {
- dstlo = src1 * src2;
- return 0;
- }
-
- // fetch source values
- uint64_t a = src1;
- uint64_t b = src2;
- if (a == 0 || b == 0)
- {
- dsthi = dstlo = 0;
- return FLAG_Z;
- }
-
- // compute high and low parts first
- uint64_t lo = (uint64_t)(uint32_t)(a >> 0) * (uint64_t)(uint32_t)(b >> 0);
- uint64_t hi = (uint64_t)(uint32_t)(a >> 32) * (uint64_t)(uint32_t)(b >> 32);
-
- // compute middle parts
- uint64_t prevlo = lo;
- uint64_t temp = (uint64_t)(uint32_t)(a >> 32) * (uint64_t)(uint32_t)(b >> 0);
- lo += temp << 32;
- hi += (temp >> 32) + (lo < prevlo);
-
- prevlo = lo;
- temp = (uint64_t)(uint32_t)(a >> 0) * (uint64_t)(uint32_t)(b >> 32);
- lo += temp << 32;
- hi += (temp >> 32) + (lo < prevlo);
-
- // store the results
- dsthi = hi;
- dstlo = lo;
-
- if (halfmul_flags)
- return ((lo >> 60) & FLAG_S) | ((hi != 0) << 1) | ((dstlo == 0) << 2);
-
- return ((hi >> 60) & FLAG_S) | ((hi != 0) << 1) | ((dsthi == 0 && dstlo == 0) << 2);
-}
-
-
-//-------------------------------------------------
-// dmuls - perform a double-wide signed multiply
-//-------------------------------------------------
-
-int drcbe_x86::dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2, bool flags, bool halfmul_flags)
-{
- uint64_t lo, hi, prevlo;
- uint64_t a, b, temp;
-
- // shortcut if we don't care about the high bits or the flags
- if (&dstlo == &dsthi && flags == false)
- {
- dstlo = src1 * src2;
- return 0;
- }
-
- // fetch absolute source values
- a = src1; if ((int64_t)a < 0) a = -a;
- b = src2; if ((int64_t)b < 0) b = -b;
- if (a == 0 || b == 0)
- {
- dsthi = dstlo = 0;
- return FLAG_Z;
- }
-
- // compute high and low parts first
- lo = (uint64_t)(uint32_t)(a >> 0) * (uint64_t)(uint32_t)(b >> 0);
- hi = (uint64_t)(uint32_t)(a >> 32) * (uint64_t)(uint32_t)(b >> 32);
-
- // compute middle parts
- prevlo = lo;
- temp = (uint64_t)(uint32_t)(a >> 32) * (uint64_t)(uint32_t)(b >> 0);
- lo += temp << 32;
- hi += (temp >> 32) + (lo < prevlo);
-
- prevlo = lo;
- temp = (uint64_t)(uint32_t)(a >> 0) * (uint64_t)(uint32_t)(b >> 32);
- lo += temp << 32;
- hi += (temp >> 32) + (lo < prevlo);
-
- // adjust for signage
- if ((int64_t)(src1 ^ src2) < 0)
- {
- hi = ~hi + (lo == 0);
- lo = ~lo + 1;
- }
-
- // store the results
- dsthi = hi;
- dstlo = lo;
-
- if (halfmul_flags)
- return ((lo >> 60) & FLAG_S) | ((hi != ((int64_t)lo >> 63)) << 1) | ((dstlo == 0) << 2);
-
- return ((hi >> 60) & FLAG_S) | ((hi != ((int64_t)lo >> 63)) << 1) | ((dsthi == 0 && dstlo == 0) << 2);
-}
-
-
-//-------------------------------------------------
-// ddivu - perform a double-wide unsigned divide
-//-------------------------------------------------
-
-int drcbe_x86::ddivu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2)
-{
- // do nothing if src2 == 0
- if (src2 == 0)
- return FLAG_V;
-
- dstlo = src1 / src2;
- if (&dstlo != &dsthi)
- dsthi = src1 % src2;
- return ((dstlo == 0) << 2) | ((dstlo >> 60) & FLAG_S);
-}
-
-
-//-------------------------------------------------
-// ddivs - perform a double-wide signed divide
-//-------------------------------------------------
-
-int drcbe_x86::ddivs(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2)
+std::unique_ptr<drcbe_interface> make_drcbe_x86(
+ drcuml_state &drcuml,
+ device_t &device,
+ drc_cache &cache,
+ uint32_t flags,
+ int modes,
+ int addrbits,
+ int ignorebits)
{
- // do nothing if src2 == 0
- if (src2 == 0)
- return FLAG_V;
-
- dstlo = src1 / src2;
- if (&dstlo != &dsthi)
- dsthi = src1 % src2;
- return ((dstlo == 0) << 2) | ((dstlo >> 60) & FLAG_S);
+ return std::unique_ptr<drcbe_interface>(new drcbe_x86(drcuml, device, cache, flags, modes, addrbits, ignorebits));
}
} // namespace drc
diff --git a/src/devices/cpu/drcbex86.h b/src/devices/cpu/drcbex86.h
index 25e926eef3c..3d873677fed 100644
--- a/src/devices/cpu/drcbex86.h
+++ b/src/devices/cpu/drcbex86.h
@@ -14,301 +14,21 @@
#pragma once
#include "drcuml.h"
-#include "drcbeut.h"
-#include "x86log.h"
-#include "asmjit/src/asmjit/asmjit.h"
+#include <memory>
namespace drc {
-//**************************************************************************
-// TYPE DEFINITIONS
-//**************************************************************************
-
-class drcbe_x86 : public drcbe_interface
-{
- using x86_entry_point_func = uint32_t (*)(x86code *entry);
-
-public:
- // construction/destruction
- drcbe_x86(drcuml_state &drcuml, device_t &device, drc_cache &cache, uint32_t flags, int modes, int addrbits, int ignorebits);
- virtual ~drcbe_x86();
-
- // required overrides
- virtual void reset() override;
- virtual int execute(uml::code_handle &entry) override;
- virtual void generate(drcuml_block &block, const uml::instruction *instlist, uint32_t numinst) override;
- virtual bool hash_exists(uint32_t mode, uint32_t pc) override;
- virtual void get_info(drcbe_info &info) override;
- virtual bool logging() const override { return m_log != nullptr; }
-
-private:
- // HACK: leftover from x86emit
- static inline constexpr int REG_MAX = 16;
-
- // a be_parameter is similar to a uml::parameter but maps to native registers/memory
- class be_parameter
- {
- public:
- // parameter types
- enum be_parameter_type
- {
- PTYPE_NONE = 0, // invalid
- PTYPE_IMMEDIATE, // immediate; value = sign-extended to 64 bits
- PTYPE_INT_REGISTER, // integer register; value = 0-REG_MAX
- PTYPE_FLOAT_REGISTER, // floating point register; value = 0-REG_MAX
- PTYPE_MEMORY, // memory; value = pointer to memory
- PTYPE_MAX
- };
-
- // represents the value of a parameter
- typedef uint64_t be_parameter_value;
-
- // construction
- be_parameter() : m_type(PTYPE_NONE), m_value(0) { }
- be_parameter(uint64_t val) : m_type(PTYPE_IMMEDIATE), m_value(val) { }
- be_parameter(drcbe_x86 &drcbe, const uml::parameter &param, uint32_t allowed);
- be_parameter(const be_parameter &param) = default;
-
- // creators for types that don't safely default
- static be_parameter make_ireg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_INT_REGISTER, regnum); }
- static be_parameter make_freg(int regnum) { assert(regnum >= 0 && regnum < REG_MAX); return be_parameter(PTYPE_FLOAT_REGISTER, regnum); }
- static be_parameter make_memory(void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(base)); }
- static be_parameter make_memory(const void *base) { return be_parameter(PTYPE_MEMORY, reinterpret_cast<be_parameter_value>(const_cast<void *>(base))); }
-
- // operators
- bool operator==(be_parameter const &rhs) const { return (m_type == rhs.m_type && m_value == rhs.m_value); }
- bool operator!=(be_parameter const &rhs) const { return (m_type != rhs.m_type || m_value != rhs.m_value); }
-
- // getters
- be_parameter_type type() const { return m_type; }
- uint64_t immediate() const { assert(m_type == PTYPE_IMMEDIATE); return m_value; }
- uint32_t ireg() const { assert(m_type == PTYPE_INT_REGISTER); assert(m_value < REG_MAX); return m_value; }
- uint32_t freg() const { assert(m_type == PTYPE_FLOAT_REGISTER); assert(m_value < REG_MAX); return m_value; }
- void *memory(uint32_t offset = 0) const { assert(m_type == PTYPE_MEMORY); return reinterpret_cast<void *>(m_value + offset); }
-
- // type queries
- bool is_immediate() const { return (m_type == PTYPE_IMMEDIATE); }
- bool is_int_register() const { return (m_type == PTYPE_INT_REGISTER); }
- bool is_float_register() const { return (m_type == PTYPE_FLOAT_REGISTER); }
- bool is_memory() const { return (m_type == PTYPE_MEMORY); }
-
- // other queries
- bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); }
-
- // helpers
- asmjit::x86::Gpd select_register(asmjit::x86::Gpd const &defreg) const;
- asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg) const;
- template <typename T> T select_register(T defreg, be_parameter const &checkparam) const;
- template <typename T> T select_register(T defreg, be_parameter const &checkparam, be_parameter const &checkparam2) const;
-
- private:
- // private constructor
- be_parameter(be_parameter_type type, be_parameter_value value) : m_type(type), m_value(value) { }
-
- // internals
- be_parameter_type m_type; // parameter type
- be_parameter_value m_value; // parameter value
- };
-
- // helpers
- asmjit::x86::Mem MABS(void const *base, u32 const size = 0) const { return asmjit::x86::Mem(u64(base), size); }
- void normalize_commutative(be_parameter &inner, be_parameter &outer);
- void emit_combine_z_flags(asmjit::x86::Assembler &a);
- void emit_combine_zs_flags(asmjit::x86::Assembler &a);
- void emit_combine_z_shl_flags(asmjit::x86::Assembler &a);
- void reset_last_upper_lower_reg();
- void set_last_lower_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reglo);
- void set_last_upper_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reghi);
- bool can_skip_lower_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const &reglo);
- bool can_skip_upper_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const &reghi);
-
- static void debug_log_hashjmp(int mode, offs_t pc);
-
- // code generators
- void op_handle(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_hash(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_label(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_comment(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_mapvar(asmjit::x86::Assembler &a, const uml::instruction &inst);
-
- void op_nop(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_break(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_debug(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_exit(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_hashjmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_jmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_exh(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_callh(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_ret(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_callc(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_recover(asmjit::x86::Assembler &a, const uml::instruction &inst);
-
- void op_setfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_getfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_getexp(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_getflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_setflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_save(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_restore(asmjit::x86::Assembler &a, const uml::instruction &inst);
-
- void op_load(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_loads(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_store(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_read(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_readm(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_write(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_writem(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_carry(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_set(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_mov(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_sext(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_roland(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_rolins(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_add(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_addc(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_sub(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_subc(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_cmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_mulu(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_mululw(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_muls(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_mulslw(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_divu(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_divs(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_and(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_test(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_or(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_xor(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_lzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_tzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_bswap(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_shl(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_shr(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_sar(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_ror(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_rol(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_rorc(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_rolc(asmjit::x86::Assembler &a, const uml::instruction &inst);
-
- void op_fload(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fstore(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fread(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fwrite(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fmov(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_ftoint(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_ffrint(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_ffrflt(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_frnds(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fadd(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fsub(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fcmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fmul(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fdiv(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fneg(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fabs(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_frecip(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_frsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_fcopyi(asmjit::x86::Assembler &a, const uml::instruction &inst);
- void op_icopyf(asmjit::x86::Assembler &a, const uml::instruction &inst);
-
- // 32-bit code emission helpers
- void emit_mov_r32_p32(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param);
- void emit_mov_r32_p32_keepflags(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param);
- void emit_mov_m32_p32(asmjit::x86::Assembler &a, asmjit::x86::Mem memref, be_parameter const &param);
- void emit_mov_p32_r32(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reg);
-
- void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param, std::function<bool(asmjit::x86::Assembler &a, asmjit::Operand const &dst, be_parameter const &src)> optimize = [](asmjit::x86::Assembler &a, asmjit::Operand dst, be_parameter const &src) { return false; });
- void shift_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, size_t opsize, asmjit::Operand const &dst, be_parameter const &param, std::function<bool(asmjit::x86::Assembler &a, asmjit::Operand const &dst, be_parameter const &src)> optimize, bool update_flags);
-
- // 64-bit code emission helpers
- void emit_mov_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param);
- void emit_mov_r64_p64_keepflags(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param);
- void emit_mov_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref, be_parameter const &param);
- void emit_mov_p64_r64(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi);
- void emit_and_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
- void emit_and_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref_lo, asmjit::x86::Mem const &memref_hi, be_parameter const &param, const uml::instruction &inst);
- void emit_or_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
- void emit_or_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref_lo, asmjit::x86::Mem const &memref_hi, be_parameter const &param, const uml::instruction &inst);
- void emit_xor_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
- void emit_xor_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref_lo, asmjit::x86::Mem const &memref_hi, be_parameter const &param, const uml::instruction &inst);
- void emit_shl_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
- void emit_shr_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
- void emit_sar_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
- void emit_rol_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
- void emit_ror_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
- void emit_rcl_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
- void emit_rcr_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
-
- void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode_lo, asmjit::x86::Inst::Id const opcode_hi, asmjit::x86::Gp const &lo, asmjit::x86::Gp const &hi, be_parameter const &param, bool const saveflags);
- void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode_lo, asmjit::x86::Inst::Id const opcode_hi, asmjit::x86::Mem const &lo, asmjit::x86::Mem const &hi, be_parameter const &param, bool const saveflags);
-
- // floating-point code emission helpers
- void emit_fld_p(asmjit::x86::Assembler &a, int size, be_parameter const &param);
- void emit_fstp_p(asmjit::x86::Assembler &a, int size, be_parameter const &param);
-
- // callback helpers
- static int dmulu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2, bool flags, bool halfmul_flags);
- static int dmuls(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2, bool flags, bool halfmul_flags);
- static int ddivu(uint64_t &dstlo, uint64_t &dsthi, uint64_t src1, uint64_t src2);
- static int ddivs(uint64_t &dstlo, uint64_t &dsthi, int64_t src1, int64_t src2);
-
- void calculate_status_flags(asmjit::x86::Assembler &a, asmjit::Operand const &dst, u8 flags);
-
- size_t emit(asmjit::CodeHolder &ch);
-
- // internal state
- drc_hash_table m_hash; // hash table state
- drc_map_variables m_map; // code map
- x86log_context * m_log; // logging
- FILE * m_log_asmjit;
- bool m_logged_common; // logged common code already?
- bool const m_sse3; // do we have SSE3 support?
-
- x86_entry_point_func m_entry; // entry point
- x86code * m_exit; // exit point
- x86code * m_nocode; // nocode handler
- x86code * m_save; // save handler
- x86code * m_restore; // restore handler
-
- uint32_t * m_reglo[REG_MAX]; // pointer to low part of data for each register
- uint32_t * m_reghi[REG_MAX]; // pointer to high part of data for each register
- asmjit::x86::Gp m_last_lower_reg; // last register we stored a lower from
- x86code * m_last_lower_pc; // PC after instruction where we last stored a lower register
- uint32_t * m_last_lower_addr; // address where we last stored an lower register
- asmjit::x86::Gp m_last_upper_reg; // last register we stored an upper from
- x86code * m_last_upper_pc; // PC after instruction where we last stored an upper register
- uint32_t * m_last_upper_addr; // address where we last stored an upper register
- double m_fptemp; // temporary storage for floating point
-
- uint16_t m_fpumode; // saved FPU mode
- uint16_t m_fmodesave; // temporary location for saving
-
- void * m_stacksave; // saved stack pointer
- void * m_hashstacksave; // saved stack pointer for hashjmp
- uint64_t m_reslo; // extended low result
- uint64_t m_reshi; // extended high result
-
- // resolved memory handler functions
- resolved_member_function m_debug_cpu_instruction_hook;
- resolved_member_function m_drcmap_get_value;
- resolved_memory_accessors_vector m_memory_accessors;
-
- // globals
- typedef void (drcbe_x86::*opcode_generate_func)(asmjit::x86::Assembler &a, const uml::instruction &inst);
- struct opcode_table_entry
- {
- uml::opcode_t opcode; // opcode in question
- opcode_generate_func func; // function pointer to the work
- };
- static const opcode_table_entry s_opcode_table_source[];
- static opcode_generate_func s_opcode_table[uml::OP_MAX];
-};
+std::unique_ptr<drcbe_interface> make_drcbe_x86(
+ drcuml_state &drcuml,
+ device_t &device,
+ drc_cache &cache,
+ uint32_t flags,
+ int modes,
+ int addrbits,
+ int ignorebits);
} // namespace drc
-using drc::drcbe_x86;
-
#endif // MAME_CPU_DRCBEX86_H
diff --git a/src/devices/cpu/drcuml.cpp b/src/devices/cpu/drcuml.cpp
index 6d21b262a4a..47de628574e 100644
--- a/src/devices/cpu/drcuml.cpp
+++ b/src/devices/cpu/drcuml.cpp
@@ -58,15 +58,16 @@
//**************************************************************************
-// TYPE DEFINITIONS
+// MACROS
//**************************************************************************
// determine the type of the native DRC, falling back to C
#ifndef NATIVE_DRC
-typedef drcbe_c drcbe_native;
-#else
-typedef NATIVE_DRC drcbe_native;
+#define NATIVE_DRC drcbe_c
#endif
+#define MAKE_DRCBE_IMPL(name) make_##name
+#define MAKE_DRCBE(name) MAKE_DRCBE_IMPL(name)
+#define make_drcbe_native MAKE_DRCBE(NATIVE_DRC)
// structure describing back-end validation test
@@ -137,8 +138,8 @@ drcuml_state::drcuml_state(device_t &device, drc_cache &cache, u32 flags, int mo
: m_device(device)
, m_cache(cache)
, m_beintf(device.machine().options().drc_use_c()
- ? std::unique_ptr<drcbe_interface>{ new drcbe_c(*this, device, cache, flags, modes, addrbits, ignorebits) }
- : std::unique_ptr<drcbe_interface>{ new drcbe_native(*this, device, cache, flags, modes, addrbits, ignorebits) })
+ ? drc::make_drcbe_c(*this, device, cache, flags, modes, addrbits, ignorebits)
+ : drc::make_drcbe_native(*this, device, cache, flags, modes, addrbits, ignorebits))
, m_umllog(device.machine().options().drc_log_uml()
? new std::ofstream(util::string_format("drcuml_%s.asm", device.shortname()))
: nullptr)