-cpu/e132xs: Got rid of "Mission Craft flags" compile time option.

* Assume ROL sets the V and C flags the same way as SHL and MOVI clears
  the V flag.

-cpu/drcbex64.cpp: Optimise SUB x,0,y to a NEG instruction (gets down to
 one instruction from two or three a lot of the time).  This had been a
 TODO comment for ages.

-cpu/drcbex86.cpp: Got rid of unnecessary std::function use.  This
 substantially reduces the code size and reduces allocations during code
 generation.

-cpu/drcbearm64.cpp, cpu/drcbex64.cpp, cpu/drcbex86.cpp: Got rid of the
 intermediate tables in favour of bit switch statements.  This improves
 startup time, reduces code size, and gives the compiler more
 optimisation opportunities.

-cpu/drcbearm64.cpp, cpu/drcbex64.cpp, cpu/drcbex86.cpp: Got rid of
 asmjit namespace qualifiers left over from when the class declarations
 were in headers and hence outside the scope of the using namespace
 statements.
This commit is contained in:
Vas Crabb 2025-04-04 03:49:01 +11:00
parent 9a2b909a9e
commit b1c09f02b4
6 changed files with 664 additions and 712 deletions

View File

@ -461,10 +461,10 @@ private:
bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); } bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); }
bool is_cold_register() const { return m_coldreg; } bool is_cold_register() const { return m_coldreg; }
asmjit::a64::Vec get_register_float(uint32_t regsize) const; a64::Vec get_register_float(uint32_t regsize) const;
asmjit::a64::Gp get_register_int(uint32_t regsize) const; a64::Gp get_register_int(uint32_t regsize) const;
asmjit::a64::Vec select_register(asmjit::a64::Vec const &reg, uint32_t regsize) const; a64::Vec select_register(a64::Vec const &reg, uint32_t regsize) const;
asmjit::a64::Gp select_register(asmjit::a64::Gp const &reg, uint32_t regsize) const; a64::Gp select_register(a64::Gp const &reg, uint32_t regsize) const;
private: private:
static inline constexpr int REG_MAX = 30; static inline constexpr int REG_MAX = 30;
@ -481,13 +481,6 @@ private:
uint32_t emulated_flags; uint32_t emulated_flags;
}; };
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;
};
struct memory_accessors struct memory_accessors
{ {
resolved_memory_accessors resolved; resolved_memory_accessors resolved;
@ -501,128 +494,130 @@ private:
using arm64_entry_point_func = uint32_t (*)(void *entry); using arm64_entry_point_func = uint32_t (*)(void *entry);
void op_handle(asmjit::a64::Assembler &a, const uml::instruction &inst); void generate_one(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_handle(a64::Assembler &a, const uml::instruction &inst);
void op_break(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_hash(a64::Assembler &a, const uml::instruction &inst);
void op_debug(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_label(a64::Assembler &a, const uml::instruction &inst);
void op_exit(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_comment(a64::Assembler &a, const uml::instruction &inst);
void op_hashjmp(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_mapvar(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_nop(a64::Assembler &a, const uml::instruction &inst);
void op_getfmod(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_break(a64::Assembler &a, const uml::instruction &inst);
void op_getexp(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_debug(a64::Assembler &a, const uml::instruction &inst);
void op_getflgs(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_exit(a64::Assembler &a, const uml::instruction &inst);
void op_setflgs(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_hashjmp(a64::Assembler &a, const uml::instruction &inst);
void op_save(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_jmp(a64::Assembler &a, const uml::instruction &inst);
void op_restore(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_exh(a64::Assembler &a, const uml::instruction &inst);
void op_callh(a64::Assembler &a, const uml::instruction &inst);
void op_ret(a64::Assembler &a, const uml::instruction &inst);
void op_callc(a64::Assembler &a, const uml::instruction &inst);
void op_recover(a64::Assembler &a, const uml::instruction &inst);
void op_load(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_setfmod(a64::Assembler &a, const uml::instruction &inst);
void op_loads(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_getfmod(a64::Assembler &a, const uml::instruction &inst);
void op_store(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_getexp(a64::Assembler &a, const uml::instruction &inst);
void op_read(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_getflgs(a64::Assembler &a, const uml::instruction &inst);
void op_readm(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_setflgs(a64::Assembler &a, const uml::instruction &inst);
void op_write(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_save(a64::Assembler &a, const uml::instruction &inst);
void op_writem(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_restore(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 <bool CarryIn> void op_add(asmjit::a64::Assembler &a, const uml::instruction &inst);
template <bool CarryIn> 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_load(a64::Assembler &a, const uml::instruction &inst);
void op_fstore(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_loads(a64::Assembler &a, const uml::instruction &inst);
void op_fread(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_store(a64::Assembler &a, const uml::instruction &inst);
void op_fwrite(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_read(a64::Assembler &a, const uml::instruction &inst);
void op_fmov(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_readm(a64::Assembler &a, const uml::instruction &inst);
void op_ftoint(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_write(a64::Assembler &a, const uml::instruction &inst);
void op_ffrint(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_writem(a64::Assembler &a, const uml::instruction &inst);
void op_ffrflt(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_carry(a64::Assembler &a, const uml::instruction &inst);
void op_frnds(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_set(a64::Assembler &a, const uml::instruction &inst);
void op_fcmp(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_mov(a64::Assembler &a, const uml::instruction &inst);
void op_fcopyi(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_sext(a64::Assembler &a, const uml::instruction &inst);
void op_icopyf(asmjit::a64::Assembler &a, const uml::instruction &inst); void op_roland(a64::Assembler &a, const uml::instruction &inst);
void op_rolins(a64::Assembler &a, const uml::instruction &inst);
template <bool CarryIn> void op_add(a64::Assembler &a, const uml::instruction &inst);
template <bool CarryIn> void op_sub(a64::Assembler &a, const uml::instruction &inst);
void op_cmp(a64::Assembler &a, const uml::instruction &inst);
void op_mulu(a64::Assembler &a, const uml::instruction &inst);
void op_mululw(a64::Assembler &a, const uml::instruction &inst);
void op_muls(a64::Assembler &a, const uml::instruction &inst);
void op_mulslw(a64::Assembler &a, const uml::instruction &inst);
template <a64::Inst::Id Opcode> void op_div(a64::Assembler &a, const uml::instruction &inst);
void op_and(a64::Assembler &a, const uml::instruction &inst);
void op_test(a64::Assembler &a, const uml::instruction &inst);
void op_or(a64::Assembler &a, const uml::instruction &inst);
void op_xor(a64::Assembler &a, const uml::instruction &inst);
void op_lzcnt(a64::Assembler &a, const uml::instruction &inst);
void op_tzcnt(a64::Assembler &a, const uml::instruction &inst);
void op_bswap(a64::Assembler &a, const uml::instruction &inst);
template <a64::Inst::Id Opcode> void op_shift(a64::Assembler &a, const uml::instruction &inst);
void op_rol(a64::Assembler &a, const uml::instruction &inst);
void op_rolc(a64::Assembler &a, const uml::instruction &inst);
void op_rorc(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); void op_fload(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); void op_fstore(a64::Assembler &a, const uml::instruction &inst);
void op_fread(a64::Assembler &a, const uml::instruction &inst);
void op_fwrite(a64::Assembler &a, const uml::instruction &inst);
void op_fmov(a64::Assembler &a, const uml::instruction &inst);
void op_ftoint(a64::Assembler &a, const uml::instruction &inst);
void op_ffrint(a64::Assembler &a, const uml::instruction &inst);
void op_ffrflt(a64::Assembler &a, const uml::instruction &inst);
void op_frnds(a64::Assembler &a, const uml::instruction &inst);
void op_fcmp(a64::Assembler &a, const uml::instruction &inst);
void op_fcopyi(a64::Assembler &a, const uml::instruction &inst);
void op_icopyf(a64::Assembler &a, const uml::instruction &inst);
size_t emit(asmjit::CodeHolder &ch); template <a64::Inst::Id Opcode> void op_float_alu(a64::Assembler &a, const uml::instruction &inst);
template <a64::Inst::Id Opcode> void op_float_alu2(a64::Assembler &a, const uml::instruction &inst);
size_t emit(CodeHolder &ch);
// helper functions // helper functions
void get_imm_relative(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const uint64_t ptr) const; void get_imm_relative(a64::Assembler &a, const 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_str_base_mem(a64::Assembler &a, a64::Inst::Id opcode, const 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_ldr_mem(a64::Assembler &a, const 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_ldrb_mem(a64::Assembler &a, const 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_ldrh_mem(a64::Assembler &a, const 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_ldrsb_mem(a64::Assembler &a, const 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_ldrsh_mem(a64::Assembler &a, const 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_ldrsw_mem(a64::Assembler &a, const 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_str_mem(a64::Assembler &a, const 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_strb_mem(a64::Assembler &a, const 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_strh_mem(a64::Assembler &a, const 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_ldr_mem(a64::Assembler &a, const 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 emit_float_str_mem(a64::Assembler &a, const a64::Vec &reg, const void *ptr) const;
void emit_skip(a64::Assembler &a, uml::condition_t cond, Label &skip); void emit_skip(a64::Assembler &a, uml::condition_t cond, Label &skip);
void emit_memaccess_setup(asmjit::a64::Assembler &a, const be_parameter &addrp, const memory_accessors &accessors, const address_space::specific_access_info::side &side) const; void emit_memaccess_setup(a64::Assembler &a, const be_parameter &addrp, const memory_accessors &accessors, const address_space::specific_access_info::side &side) const;
void emit_narrow_memwrite(asmjit::a64::Assembler &a, const be_parameter &addrp, const parameter &spacesizep, const memory_accessors &accessors) const; void emit_narrow_memwrite(a64::Assembler &a, const be_parameter &addrp, const parameter &spacesizep, const memory_accessors &accessors) const;
void store_carry(asmjit::a64::Assembler &a, bool inverted = false); void store_carry(a64::Assembler &a, bool inverted = false);
void load_carry(asmjit::a64::Assembler &a, bool inverted = false); void load_carry(a64::Assembler &a, bool inverted = false);
void set_flags(asmjit::a64::Assembler &a); void set_flags(a64::Assembler &a);
void calculate_carry_shift_left(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const asmjit::a64::Gp &shift, int maxBits); void calculate_carry_shift_left(a64::Assembler &a, const a64::Gp &reg, const a64::Gp &shift, int maxBits);
void calculate_carry_shift_left_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const int shift, int maxBits); void calculate_carry_shift_left_imm(a64::Assembler &a, const a64::Gp &reg, const int shift, int maxBits);
void calculate_carry_shift_right(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const asmjit::a64::Gp &shift); void calculate_carry_shift_right(a64::Assembler &a, const a64::Gp &reg, const a64::Gp &shift);
void calculate_carry_shift_right_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const int shift); void calculate_carry_shift_right_imm(a64::Assembler &a, const a64::Gp &reg, const int shift);
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_reg_param(a64::Assembler &a, uint32_t regsize, 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_param(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_reg(a64::Assembler &a, uint32_t regsize, const be_parameter &dst, 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_float_param_int_reg(a64::Assembler &a, uint32_t regsize, const be_parameter &dst, 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_reg_param(a64::Assembler &a, uint32_t regsize, const 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_reg(a64::Assembler &a, uint32_t regsize, const be_parameter &dst, const 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_imm(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_param_param(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_mem_param(a64::Assembler &a, uint32_t regsize, void *dst, const be_parameter &src) const;
void call_arm_addr(asmjit::a64::Assembler &a, const void *offs) const; void call_arm_addr(a64::Assembler &a, const void *offs) const;
[[noreturn]] void end_of_block() const; [[noreturn]] void end_of_block() const;
@ -643,107 +638,107 @@ private:
resolved_member_function m_debug_cpu_instruction_hook; resolved_member_function m_debug_cpu_instruction_hook;
resolved_member_function m_drcmap_get_value; resolved_member_function m_drcmap_get_value;
std::vector<memory_accessors> m_memory_accessors; std::vector<memory_accessors> m_memory_accessors;
static const opcode_table_entry s_opcode_table_source[];
static opcode_generate_func s_opcode_table[uml::OP_MAX];
}; };
drcbe_arm64::opcode_generate_func drcbe_arm64::s_opcode_table[OP_MAX]; inline void drcbe_arm64::generate_one(a64::Assembler &a, const uml::instruction &inst)
const drcbe_arm64::opcode_table_entry drcbe_arm64::s_opcode_table_source[] =
{ {
switch (inst.opcode())
{
// Compile-time opcodes // Compile-time opcodes
{ uml::OP_HANDLE, &drcbe_arm64::op_handle }, // HANDLE handle case uml::OP_HANDLE: op_handle(a, inst); break; // HANDLE handle
{ uml::OP_HASH, &drcbe_arm64::op_hash }, // HASH mode,pc case uml::OP_HASH: op_hash(a, inst); break; // HASH mode,pc
{ uml::OP_LABEL, &drcbe_arm64::op_label }, // LABEL imm case uml::OP_LABEL: op_label(a, inst); break; // LABEL imm
{ uml::OP_COMMENT, &drcbe_arm64::op_comment }, // COMMENT string case uml::OP_COMMENT: op_comment(a, inst); break; // COMMENT string
{ uml::OP_MAPVAR, &drcbe_arm64::op_mapvar }, // MAPVAR mapvar,value case uml::OP_MAPVAR: op_mapvar(a, inst); break; // MAPVAR mapvar,value
// Control Flow Operations // Control Flow Operations
{ uml::OP_NOP, &drcbe_arm64::op_nop }, // NOP case uml::OP_NOP: op_nop(a, inst); break; // NOP
{ uml::OP_BREAK, &drcbe_arm64::op_break }, // BREAK case uml::OP_BREAK: op_break(a, inst); break; // BREAK
{ uml::OP_DEBUG, &drcbe_arm64::op_debug }, // DEBUG pc case uml::OP_DEBUG: op_debug(a, inst); break; // DEBUG pc
{ uml::OP_EXIT, &drcbe_arm64::op_exit }, // EXIT src1[,c] case uml::OP_EXIT: op_exit(a, inst); break; // EXIT src1[,c]
{ uml::OP_HASHJMP, &drcbe_arm64::op_hashjmp }, // HASHJMP mode,pc,handle case uml::OP_HASHJMP: op_hashjmp(a, inst); break; // HASHJMP mode,pc,handle
{ uml::OP_JMP, &drcbe_arm64::op_jmp }, // JMP imm[,c] case uml::OP_JMP: op_jmp(a, inst); break; // JMP imm[,c]
{ uml::OP_EXH, &drcbe_arm64::op_exh }, // EXH handle,param[,c] case uml::OP_EXH: op_exh(a, inst); break; // EXH handle,param[,c]
{ uml::OP_CALLH, &drcbe_arm64::op_callh }, // CALLH handle[,c] case uml::OP_CALLH: op_callh(a, inst); break; // CALLH handle[,c]
{ uml::OP_RET, &drcbe_arm64::op_ret }, // RET [c] case uml::OP_RET: op_ret(a, inst); break; // RET [c]
{ uml::OP_CALLC, &drcbe_arm64::op_callc }, // CALLC func,ptr[,c] case uml::OP_CALLC: op_callc(a, inst); break; // CALLC func,ptr[,c]
{ uml::OP_RECOVER, &drcbe_arm64::op_recover }, // RECOVER dst,mapvar case uml::OP_RECOVER: op_recover(a, inst); break; // RECOVER dst,mapvar
// Internal Register Operations // Internal Register Operations
{ uml::OP_SETFMOD, &drcbe_arm64::op_setfmod }, // SETFMOD src case uml::OP_SETFMOD: op_setfmod(a, inst); break; // SETFMOD src
{ uml::OP_GETFMOD, &drcbe_arm64::op_getfmod }, // GETFMOD dst case uml::OP_GETFMOD: op_getfmod(a, inst); break; // GETFMOD dst
{ uml::OP_GETEXP, &drcbe_arm64::op_getexp }, // GETEXP dst case uml::OP_GETEXP: op_getexp(a, inst); break; // GETEXP dst
{ uml::OP_GETFLGS, &drcbe_arm64::op_getflgs }, // GETFLGS dst[,f] case uml::OP_GETFLGS: op_getflgs(a, inst); break; // GETFLGS dst[,f]
{ uml::OP_SETFLGS, &drcbe_arm64::op_setflgs }, // SETFLGS dst[,f] case uml::OP_SETFLGS: op_setflgs(a, inst); break; // SETFLGS dst[,f]
{ uml::OP_SAVE, &drcbe_arm64::op_save }, // SAVE dst case uml::OP_SAVE: op_save(a, inst); break; // SAVE dst
{ uml::OP_RESTORE, &drcbe_arm64::op_restore }, // RESTORE dst case uml::OP_RESTORE: op_restore(a, inst); break; // RESTORE dst
// Integer Operations // Integer Operations
{ uml::OP_LOAD, &drcbe_arm64::op_load }, // LOAD dst,base,index,size case uml::OP_LOAD: op_load(a, inst); break; // LOAD dst,base,index,size
{ uml::OP_LOADS, &drcbe_arm64::op_loads }, // LOADS dst,base,index,size case uml::OP_LOADS: op_loads(a, inst); break; // LOADS dst,base,index,size
{ uml::OP_STORE, &drcbe_arm64::op_store }, // STORE base,index,src,size case uml::OP_STORE: op_store(a, inst); break; // STORE base,index,src,size
{ uml::OP_READ, &drcbe_arm64::op_read }, // READ dst,src1,spacesize case uml::OP_READ: op_read(a, inst); break; // READ dst,src1,spacesize
{ uml::OP_READM, &drcbe_arm64::op_readm }, // READM dst,src1,mask,spacesize case uml::OP_READM: op_readm(a, inst); break; // READM dst,src1,mask,spacesize
{ uml::OP_WRITE, &drcbe_arm64::op_write }, // WRITE dst,src1,spacesize case uml::OP_WRITE: op_write(a, inst); break; // WRITE dst,src1,spacesize
{ uml::OP_WRITEM, &drcbe_arm64::op_writem }, // WRITEM dst,src1,spacesize case uml::OP_WRITEM: op_writem(a, inst); break; // WRITEM dst,src1,spacesize
{ uml::OP_CARRY, &drcbe_arm64::op_carry }, // CARRY src,bitnum case uml::OP_CARRY: op_carry(a, inst); break; // CARRY src,bitnum
{ uml::OP_SET, &drcbe_arm64::op_set }, // SET dst,c case uml::OP_SET: op_set(a, inst); break; // SET dst,c
{ uml::OP_MOV, &drcbe_arm64::op_mov }, // MOV dst,src[,c] case uml::OP_MOV: op_mov(a, inst); break; // MOV dst,src[,c]
{ uml::OP_SEXT, &drcbe_arm64::op_sext }, // SEXT dst,src case uml::OP_SEXT: op_sext(a, inst); break; // SEXT dst,src
{ uml::OP_ROLAND, &drcbe_arm64::op_roland }, // ROLAND dst,src1,src2,src3 case uml::OP_ROLAND: op_roland(a, inst); break; // ROLAND dst,src1,src2,src3
{ uml::OP_ROLINS, &drcbe_arm64::op_rolins }, // ROLINS dst,src1,src2,src3 case uml::OP_ROLINS: op_rolins(a, inst); break; // ROLINS dst,src1,src2,src3
{ uml::OP_ADD, &drcbe_arm64::op_add<false> }, // ADD dst,src1,src2[,f] case uml::OP_ADD: op_add<false>(a, inst); break; // ADD dst,src1,src2[,f]
{ uml::OP_ADDC, &drcbe_arm64::op_add<true> }, // ADDC dst,src1,src2[,f] case uml::OP_ADDC: op_add<true>(a, inst); break; // ADDC dst,src1,src2[,f]
{ uml::OP_SUB, &drcbe_arm64::op_sub<false> }, // SUB dst,src1,src2[,f] case uml::OP_SUB: op_sub<false>(a, inst); break; // SUB dst,src1,src2[,f]
{ uml::OP_SUBB, &drcbe_arm64::op_sub<true> }, // SUBB dst,src1,src2[,f] case uml::OP_SUBB: op_sub<true>(a, inst); break; // SUBB dst,src1,src2[,f]
{ uml::OP_CMP, &drcbe_arm64::op_cmp }, // CMP src1,src2[,f] case uml::OP_CMP: op_cmp(a, inst); break; // CMP src1,src2[,f]
{ uml::OP_MULU, &drcbe_arm64::op_mulu }, // MULU dst,edst,src1,src2[,f] case uml::OP_MULU: op_mulu(a, inst); break; // MULU dst,edst,src1,src2[,f]
{ uml::OP_MULULW, &drcbe_arm64::op_mululw }, // MULULW dst,src1,src2[,f] case uml::OP_MULULW: op_mululw(a, inst); break; // MULULW dst,src1,src2[,f]
{ uml::OP_MULS, &drcbe_arm64::op_muls }, // MULS dst,edst,src1,src2[,f] case uml::OP_MULS: op_muls(a, inst); break; // MULS dst,edst,src1,src2[,f]
{ uml::OP_MULSLW, &drcbe_arm64::op_mulslw }, // MULSLW dst,src1,src2[,f] case uml::OP_MULSLW: op_mulslw(a, inst); break; // MULSLW dst,src1,src2[,f]
{ uml::OP_DIVU, &drcbe_arm64::op_div<a64::Inst::kIdUdiv> }, // DIVU dst,edst,src1,src2[,f] case uml::OP_DIVU: op_div<a64::Inst::kIdUdiv>(a, inst); break; // DIVU dst,edst,src1,src2[,f]
{ uml::OP_DIVS, &drcbe_arm64::op_div<a64::Inst::kIdSdiv> }, // DIVS dst,edst,src1,src2[,f] case uml::OP_DIVS: op_div<a64::Inst::kIdSdiv>(a, inst); break; // DIVS dst,edst,src1,src2[,f]
{ uml::OP_AND, &drcbe_arm64::op_and }, // AND dst,src1,src2[,f] case uml::OP_AND: op_and(a, inst); break; // AND dst,src1,src2[,f]
{ uml::OP_TEST, &drcbe_arm64::op_test }, // TEST src1,src2[,f] case uml::OP_TEST: op_test(a, inst); break; // TEST src1,src2[,f]
{ uml::OP_OR, &drcbe_arm64::op_or }, // OR dst,src1,src2[,f] case uml::OP_OR: op_or(a, inst); break; // OR dst,src1,src2[,f]
{ uml::OP_XOR, &drcbe_arm64::op_xor }, // XOR dst,src1,src2[,f] case uml::OP_XOR: op_xor(a, inst); break; // XOR dst,src1,src2[,f]
{ uml::OP_LZCNT, &drcbe_arm64::op_lzcnt }, // LZCNT dst,src[,f] case uml::OP_LZCNT: op_lzcnt(a, inst); break; // LZCNT dst,src[,f]
{ uml::OP_TZCNT, &drcbe_arm64::op_tzcnt }, // TZCNT dst,src[,f] case uml::OP_TZCNT: op_tzcnt(a, inst); break; // TZCNT dst,src[,f]
{ uml::OP_BSWAP, &drcbe_arm64::op_bswap }, // BSWAP dst,src case uml::OP_BSWAP: op_bswap(a, inst); break; // BSWAP dst,src
{ uml::OP_SHL, &drcbe_arm64::op_shift<a64::Inst::kIdLsl> }, // SHL dst,src,count[,f] case uml::OP_SHL: op_shift<a64::Inst::kIdLsl>(a, inst); break; // SHL dst,src,count[,f]
{ uml::OP_SHR, &drcbe_arm64::op_shift<a64::Inst::kIdLsr> }, // SHR dst,src,count[,f] case uml::OP_SHR: op_shift<a64::Inst::kIdLsr>(a, inst); break; // SHR dst,src,count[,f]
{ uml::OP_SAR, &drcbe_arm64::op_shift<a64::Inst::kIdAsr> }, // SAR dst,src,count[,f] case uml::OP_SAR: op_shift<a64::Inst::kIdAsr>(a, inst); break; // SAR dst,src,count[,f]
{ uml::OP_ROL, &drcbe_arm64::op_rol }, // ROL dst,src,count[,f] case uml::OP_ROL: op_rol(a, inst); break; // ROL dst,src,count[,f]
{ uml::OP_ROLC, &drcbe_arm64::op_rolc }, // ROLC dst,src,count[,f] case uml::OP_ROLC: op_rolc(a, inst); break; // ROLC dst,src,count[,f]
{ uml::OP_ROR, &drcbe_arm64::op_shift<a64::Inst::kIdRor> }, // ROR dst,src,count[,f] case uml::OP_ROR: op_shift<a64::Inst::kIdRor>(a, inst); break; // ROR dst,src,count[,f]
{ uml::OP_RORC, &drcbe_arm64::op_rorc }, // RORC dst,src,count[,f] case uml::OP_RORC: op_rorc(a, inst); break; // RORC dst,src,count[,f]
// Floating Point Operations // Floating Point Operations
{ uml::OP_FLOAD, &drcbe_arm64::op_fload }, // FLOAD dst,base,index case uml::OP_FLOAD: op_fload(a, inst); break; // FLOAD dst,base,index
{ uml::OP_FSTORE, &drcbe_arm64::op_fstore }, // FSTORE base,index,src case uml::OP_FSTORE: op_fstore(a, inst); break; // FSTORE base,index,src
{ uml::OP_FREAD, &drcbe_arm64::op_fread }, // FREAD dst,space,src1 case uml::OP_FREAD: op_fread(a, inst); break; // FREAD dst,space,src1
{ uml::OP_FWRITE, &drcbe_arm64::op_fwrite }, // FWRITE space,dst,src1 case uml::OP_FWRITE: op_fwrite(a, inst); break; // FWRITE space,dst,src1
{ uml::OP_FMOV, &drcbe_arm64::op_fmov }, // FMOV dst,src1[,c] case uml::OP_FMOV: op_fmov(a, inst); break; // FMOV dst,src1[,c]
{ uml::OP_FTOINT, &drcbe_arm64::op_ftoint }, // FTOINT dst,src1,size,round case uml::OP_FTOINT: op_ftoint(a, inst); break; // FTOINT dst,src1,size,round
{ uml::OP_FFRINT, &drcbe_arm64::op_ffrint }, // FFRINT dst,src1,size case uml::OP_FFRINT: op_ffrint(a, inst); break; // FFRINT dst,src1,size
{ uml::OP_FFRFLT, &drcbe_arm64::op_ffrflt }, // FFRFLT dst,src1,size case uml::OP_FFRFLT: op_ffrflt(a, inst); break; // FFRFLT dst,src1,size
{ uml::OP_FRNDS, &drcbe_arm64::op_frnds }, // FRNDS dst,src1 case uml::OP_FRNDS: op_frnds(a, inst); break; // FRNDS dst,src1
{ uml::OP_FADD, &drcbe_arm64::op_float_alu<a64::Inst::kIdFadd_v> }, // FADD dst,src1,src2 case uml::OP_FADD: op_float_alu<a64::Inst::kIdFadd_v>(a, inst); break; // FADD dst,src1,src2
{ uml::OP_FSUB, &drcbe_arm64::op_float_alu<a64::Inst::kIdFsub_v> }, // FSUB dst,src1,src2 case uml::OP_FSUB: op_float_alu<a64::Inst::kIdFsub_v>(a, inst); break; // FSUB dst,src1,src2
{ uml::OP_FCMP, &drcbe_arm64::op_fcmp }, // FCMP src1,src2 case uml::OP_FCMP: op_fcmp(a, inst); break; // FCMP src1,src2
{ uml::OP_FMUL, &drcbe_arm64::op_float_alu<a64::Inst::kIdFmul_v> }, // FMUL dst,src1,src2 case uml::OP_FMUL: op_float_alu<a64::Inst::kIdFmul_v>(a, inst); break; // FMUL dst,src1,src2
{ uml::OP_FDIV, &drcbe_arm64::op_float_alu<a64::Inst::kIdFdiv_v> }, // FDIV dst,src1,src2 case uml::OP_FDIV: op_float_alu<a64::Inst::kIdFdiv_v> (a, inst); break; // FDIV dst,src1,src2
{ uml::OP_FNEG, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFneg_v> }, // FNEG dst,src1 case uml::OP_FNEG: op_float_alu2<a64::Inst::kIdFneg_v>(a, inst); break; // FNEG dst,src1
{ uml::OP_FABS, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFabs_v> }, // FABS dst,src1 case uml::OP_FABS: op_float_alu2<a64::Inst::kIdFabs_v>(a, inst); break; // FABS dst,src1
{ uml::OP_FSQRT, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFsqrt_v> }, // FSQRT dst,src1 case uml::OP_FSQRT: op_float_alu2<a64::Inst::kIdFsqrt_v>(a, inst); break; // FSQRT dst,src1
{ uml::OP_FRECIP, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFrecpe_v> }, // FRECIP dst,src1 case uml::OP_FRECIP: op_float_alu2<a64::Inst::kIdFrecpe_v>(a, inst); break; // FRECIP dst,src1
{ uml::OP_FRSQRT, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFrsqrte_v> }, // FRSQRT dst,src1 case uml::OP_FRSQRT: op_float_alu2<a64::Inst::kIdFrsqrte_v>(a, inst); break; // FRSQRT dst,src1
{ uml::OP_FCOPYI, &drcbe_arm64::op_fcopyi }, // FCOPYI dst,src case uml::OP_FCOPYI: op_fcopyi(a, inst); break; // FCOPYI dst,src
{ uml::OP_ICOPYF, &drcbe_arm64::op_icopyf } // ICOPYF dst,src case uml::OP_ICOPYF: op_icopyf(a, inst); break; // ICOPYF dst,src
default: throw emu_fatalerror("drcbe_arm64(%s): unhandled opcode %u\n", m_device.tag(), inst.opcode());
}
}; };
drcbe_arm64::be_parameter::be_parameter(drcbe_arm64 &drcbe, const parameter &param, uint32_t allowed) drcbe_arm64::be_parameter::be_parameter(drcbe_arm64 &drcbe, const parameter &param, uint32_t allowed)
@ -1012,7 +1007,7 @@ void drcbe_arm64::emit_skip(a64::Assembler &a, uml::condition_t cond, Label &ski
} }
} }
void drcbe_arm64::emit_memaccess_setup(asmjit::a64::Assembler &a, const be_parameter &addrp, const memory_accessors &accessors, const address_space::specific_access_info::side &side) const void drcbe_arm64::emit_memaccess_setup(a64::Assembler &a, const be_parameter &addrp, const memory_accessors &accessors, const address_space::specific_access_info::side &side) const
{ {
auto const addrreg = (accessors.no_mask || accessors.mask_simple) ? REG_PARAM2 : a64::x6; auto const addrreg = (accessors.no_mask || accessors.mask_simple) ? REG_PARAM2 : a64::x6;
mov_reg_param(a, 4, addrreg, addrp); mov_reg_param(a, 4, addrreg, addrp);
@ -1053,7 +1048,7 @@ void drcbe_arm64::emit_memaccess_setup(asmjit::a64::Assembler &a, const be_param
// x8, x7 and potentially x6 clobbered // x8, x7 and potentially x6 clobbered
} }
void drcbe_arm64::emit_narrow_memwrite(asmjit::a64::Assembler &a, const be_parameter &addrp, const parameter &spacesizep, const memory_accessors &accessors) const void drcbe_arm64::emit_narrow_memwrite(a64::Assembler &a, const be_parameter &addrp, const parameter &spacesizep, const memory_accessors &accessors) const
{ {
// expects data in REG_PARAM3 and mask in REG_PARAM4 // expects data in REG_PARAM3 and mask in REG_PARAM4
@ -1361,7 +1356,7 @@ void drcbe_arm64::load_carry(a64::Assembler &a, bool inverted)
} }
} }
void drcbe_arm64::set_flags(asmjit::a64::Assembler &a) void drcbe_arm64::set_flags(a64::Assembler &a)
{ {
// Set native condition codes after loading flags register // Set native condition codes after loading flags register
m_carry_state = carry_state::POISON; // TODO: take a bet they'll try a conditional branch and set the C flag? m_carry_state = carry_state::POISON; // TODO: take a bet they'll try a conditional branch and set the C flag?
@ -1473,10 +1468,6 @@ drcbe_arm64::drcbe_arm64(drcuml_state &drcuml, device_t &device, drc_cache &cach
{ {
m_near.emulated_flags = 0; m_near.emulated_flags = 0;
// build the opcode table (static but it doesn't hurt to regenerate it)
for (auto & elem : s_opcode_table_source)
s_opcode_table[elem.opcode] = elem.func;
// create the log // create the log
if (device.machine().options().drc_log_native()) if (device.machine().options().drc_log_native())
{ {
@ -1670,7 +1661,6 @@ void drcbe_arm64::generate(drcuml_block &block, const instruction *instlist, uin
for (int inum = 0; inum < numinst; inum++) for (int inum = 0; inum < numinst; inum++)
{ {
const instruction &inst = instlist[inum]; const instruction &inst = instlist[inum];
assert(inst.opcode() < std::size(s_opcode_table));
// must remain in scope until output // must remain in scope until output
std::string dasm; std::string dasm;
@ -1683,7 +1673,7 @@ void drcbe_arm64::generate(drcuml_block &block, const instruction *instlist, uin
} }
// generate code // generate code
(this->*s_opcode_table[inst.opcode()])(a, inst); generate_one(a, inst);
} }
// catch falling off the end of a block // catch falling off the end of a block

View File

@ -16,8 +16,6 @@
* Identify common pairs and optimize output * Identify common pairs and optimize output
* Convert SUB a,0,b to NEG
* Optimize, e.g., and [r5],i0,$FF to use rbx as temporary register * Optimize, e.g., and [r5],i0,$FF to use rbx as temporary register
(avoid initial move) if i0 is not needed going forward (avoid initial move) if i0 is not needed going forward
@ -439,11 +437,11 @@ private:
bool is_cold_register() const { return m_coldreg; } bool is_cold_register() const { return m_coldreg; }
// helpers // helpers
asmjit::x86::Gp select_register(asmjit::x86::Gp defreg) const; Gp select_register(Gp defreg) const;
asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg) const; Xmm select_register(Xmm defreg) const;
asmjit::x86::Gp select_register(asmjit::x86::Gp defreg, be_parameter const &checkparam) const; Gp select_register(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; Gp select_register(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; Xmm select_register(Xmm defreg, be_parameter const &checkparam) const;
private: private:
// HACK: leftover from x86emit // HACK: leftover from x86emit
@ -487,138 +485,132 @@ private:
bool mask_high_bits; bool mask_high_bits;
}; };
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
};
// helpers // 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); } Mem MABS(const void *ptr, const uint32_t size = 0) const { return Mem(rbp, offset_from_rbp(ptr), size); }
bool short_immediate(int64_t immediate) const { return (int32_t)immediate == immediate; } bool short_immediate(int64_t immediate) const { return (int32_t)immediate == immediate; }
void normalize_commutative(be_parameter &inner, be_parameter &outer); void normalize_commutative(be_parameter &inner, be_parameter &outer);
void normalize_commutative(const be_parameter &dst, be_parameter &inner, be_parameter &outer); void normalize_commutative(const be_parameter &dst, be_parameter &inner, be_parameter &outer);
int32_t offset_from_rbp(const void *ptr) const; 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); Gp get_base_register_and_offset(Assembler &a, void *target, Gp const &reg, int32_t &offset);
void smart_call_r64(asmjit::x86::Assembler &a, x86code *target, asmjit::x86::Gp const &reg) const; void smart_call_r64(Assembler &a, x86code *target, Gp const &reg) const;
void smart_call_m64(asmjit::x86::Assembler &a, x86code **target) const; void smart_call_m64(Assembler &a, x86code **target) const;
void emit_memaccess_setup(asmjit::x86::Assembler &a, const memory_accessors &accessors, const address_space::specific_access_info::side &side) const; void emit_memaccess_setup(Assembler &a, const memory_accessors &accessors, const address_space::specific_access_info::side &side) const;
[[noreturn]] void end_of_block() const; [[noreturn]] void end_of_block() const;
static void debug_log_hashjmp(offs_t pc, int mode); static void debug_log_hashjmp(offs_t pc, int mode);
static void debug_log_hashjmp_fail(); static void debug_log_hashjmp_fail();
void generate_one(Assembler &a, const uml::instruction &inst);
// code generators // code generators
void op_handle(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_handle(Assembler &a, const uml::instruction &inst);
void op_hash(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_hash(Assembler &a, const uml::instruction &inst);
void op_label(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_label(Assembler &a, const uml::instruction &inst);
void op_comment(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_comment(Assembler &a, const uml::instruction &inst);
void op_mapvar(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_mapvar(Assembler &a, const uml::instruction &inst);
void op_nop(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_nop(Assembler &a, const uml::instruction &inst);
void op_break(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_break(Assembler &a, const uml::instruction &inst);
void op_debug(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_debug(Assembler &a, const uml::instruction &inst);
void op_exit(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_exit(Assembler &a, const uml::instruction &inst);
void op_hashjmp(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_hashjmp(Assembler &a, const uml::instruction &inst);
void op_jmp(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_jmp(Assembler &a, const uml::instruction &inst);
void op_exh(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_exh(Assembler &a, const uml::instruction &inst);
void op_callh(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_callh(Assembler &a, const uml::instruction &inst);
void op_ret(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_ret(Assembler &a, const uml::instruction &inst);
void op_callc(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_callc(Assembler &a, const uml::instruction &inst);
void op_recover(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_recover(Assembler &a, const uml::instruction &inst);
void op_setfmod(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_setfmod(Assembler &a, const uml::instruction &inst);
void op_getfmod(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_getfmod(Assembler &a, const uml::instruction &inst);
void op_getexp(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_getexp(Assembler &a, const uml::instruction &inst);
void op_getflgs(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_getflgs(Assembler &a, const uml::instruction &inst);
void op_setflgs(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_setflgs(Assembler &a, const uml::instruction &inst);
void op_save(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_save(Assembler &a, const uml::instruction &inst);
void op_restore(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_restore(Assembler &a, const uml::instruction &inst);
void op_load(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_load(Assembler &a, const uml::instruction &inst);
void op_loads(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_loads(Assembler &a, const uml::instruction &inst);
void op_store(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_store(Assembler &a, const uml::instruction &inst);
void op_read(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_read(Assembler &a, const uml::instruction &inst);
void op_readm(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_readm(Assembler &a, const uml::instruction &inst);
void op_write(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_write(Assembler &a, const uml::instruction &inst);
void op_writem(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_writem(Assembler &a, const uml::instruction &inst);
void op_carry(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_carry(Assembler &a, const uml::instruction &inst);
void op_set(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_set(Assembler &a, const uml::instruction &inst);
void op_mov(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_mov(Assembler &a, const uml::instruction &inst);
void op_sext(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_sext(Assembler &a, const uml::instruction &inst);
void op_roland(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_roland(Assembler &a, const uml::instruction &inst);
void op_rolins(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_rolins(Assembler &a, const uml::instruction &inst);
void op_add(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_add(Assembler &a, const uml::instruction &inst);
void op_addc(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_addc(Assembler &a, const uml::instruction &inst);
void op_sub(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_sub(Assembler &a, const uml::instruction &inst);
void op_subc(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_subc(Assembler &a, const uml::instruction &inst);
void op_cmp(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_cmp(Assembler &a, const uml::instruction &inst);
void op_mulu(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_mulu(Assembler &a, const uml::instruction &inst);
void op_mululw(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_mululw(Assembler &a, const uml::instruction &inst);
void op_muls(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_muls(Assembler &a, const uml::instruction &inst);
void op_mulslw(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_mulslw(Assembler &a, const uml::instruction &inst);
void op_divu(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_divu(Assembler &a, const uml::instruction &inst);
void op_divs(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_divs(Assembler &a, const uml::instruction &inst);
void op_and(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_and(Assembler &a, const uml::instruction &inst);
void op_test(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_test(Assembler &a, const uml::instruction &inst);
void op_or(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_or(Assembler &a, const uml::instruction &inst);
void op_xor(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_xor(Assembler &a, const uml::instruction &inst);
void op_lzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_lzcnt(Assembler &a, const uml::instruction &inst);
void op_tzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_tzcnt(Assembler &a, const uml::instruction &inst);
void op_bswap(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_bswap(Assembler &a, const uml::instruction &inst);
template <asmjit::x86::Inst::Id Opcode> void op_shift(asmjit::x86::Assembler &a, const uml::instruction &inst); template <Inst::Id Opcode> void op_shift(Assembler &a, const uml::instruction &inst);
void op_fload(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fload(Assembler &a, const uml::instruction &inst);
void op_fstore(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fstore(Assembler &a, const uml::instruction &inst);
void op_fread(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fread(Assembler &a, const uml::instruction &inst);
void op_fwrite(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fwrite(Assembler &a, const uml::instruction &inst);
void op_fmov(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fmov(Assembler &a, const uml::instruction &inst);
void op_ftoint(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_ftoint(Assembler &a, const uml::instruction &inst);
void op_ffrint(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_ffrint(Assembler &a, const uml::instruction &inst);
void op_ffrflt(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_ffrflt(Assembler &a, const uml::instruction &inst);
void op_frnds(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_frnds(Assembler &a, const uml::instruction &inst);
void op_fadd(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fadd(Assembler &a, const uml::instruction &inst);
void op_fsub(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fsub(Assembler &a, const uml::instruction &inst);
void op_fcmp(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fcmp(Assembler &a, const uml::instruction &inst);
void op_fmul(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fmul(Assembler &a, const uml::instruction &inst);
void op_fdiv(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fdiv(Assembler &a, const uml::instruction &inst);
void op_fneg(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fneg(Assembler &a, const uml::instruction &inst);
void op_fabs(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fabs(Assembler &a, const uml::instruction &inst);
void op_fsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fsqrt(Assembler &a, const uml::instruction &inst);
void op_frecip(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_frecip(Assembler &a, const uml::instruction &inst);
void op_frsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_frsqrt(Assembler &a, const uml::instruction &inst);
void op_fcopyi(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fcopyi(Assembler &a, const uml::instruction &inst);
void op_icopyf(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_icopyf(Assembler &a, const uml::instruction &inst);
// alu and shift operation helpers // alu and shift operation helpers
static bool ones(u64 const value, unsigned const size) noexcept { return (size == 4) ? u32(value) == 0xffffffffU : value == 0xffffffff'ffffffffULL; } static bool ones(u64 const value, unsigned const size) noexcept { return (size == 4) ? u32(value) == 0xffffffffU : value == 0xffffffff'ffffffffULL; }
template <typename T> template <typename T>
void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param, T &&optimize); void alu_op_param(Assembler &a, Inst::Id const opcode, Operand const &dst, be_parameter const &param, T &&optimize);
void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param) { alu_op_param(a, opcode, dst, param, [] (asmjit::x86::Assembler &a, asmjit::Operand dst, be_parameter const &src) { return false; }); } void alu_op_param(Assembler &a, Inst::Id const opcode, Operand const &dst, be_parameter const &param) { alu_op_param(a, opcode, dst, param, [] (Assembler &a, Operand const &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, u8 update_flags); void shift_op_param(Assembler &a, Inst::Id const opcode, size_t opsize, Operand const &dst, be_parameter const &param, u8 update_flags);
// parameter helpers // 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_reg_param(Assembler &a, 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_param_reg(Assembler &a, be_parameter const &param, Gp const &reg);
void mov_mem_param(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref, be_parameter const &param); void mov_mem_param(Assembler &a, Mem const &memref, be_parameter const &param);
// special-case move helpers // special-case move helpers
void movsx_r64_p32(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param); void movsx_r64_p32(Assembler &a, Gp const &reg, be_parameter const &param);
void mov_r64_imm(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, uint64_t const imm) const; void mov_r64_imm(Assembler &a, Gp const &reg, uint64_t const imm) const;
// floating-point helpers // floating-point helpers
void movss_r128_p32(asmjit::x86::Assembler &a, asmjit::x86::Xmm const &reg, be_parameter const &param); void movss_r128_p32(Assembler &a, 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 movss_p32_r128(Assembler &a, be_parameter const &param, Xmm const &reg);
void movsd_r128_p64(asmjit::x86::Assembler &a, asmjit::x86::Xmm const &reg, be_parameter const &param); void movsd_r128_p64(Assembler &a, 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 movsd_p64_r128(Assembler &a, be_parameter const &param, Xmm const &reg);
void calculate_status_flags(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::Operand const &dst, u8 flags); void calculate_status_flags(Assembler &a, uint32_t instsize, 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(Assembler &a, uint32_t instsize, Gp const &lo, Gp const &hi);
void calculate_status_flags_mul_low(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo); void calculate_status_flags_mul_low(Assembler &a, uint32_t instsize, Gp const &lo);
size_t emit(asmjit::CodeHolder &ch); size_t emit(CodeHolder &ch);
// internal state // internal state
drc_hash_table m_hash; // hash table state drc_hash_table m_hash; // hash table state
@ -640,119 +632,112 @@ private:
resolved_member_function m_debug_cpu_instruction_hook; resolved_member_function m_debug_cpu_instruction_hook;
resolved_member_function m_drcmap_get_value; resolved_member_function m_drcmap_get_value;
std::vector<memory_accessors> m_memory_accessors; std::vector<memory_accessors> m_memory_accessors;
// globals
static const opcode_table_entry s_opcode_table_source[];
static opcode_generate_func s_opcode_table[uml::OP_MAX];
}; };
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
drcbe_x64::opcode_generate_func drcbe_x64::s_opcode_table[OP_MAX];
//************************************************************************** //**************************************************************************
// TABLES // TABLES
//************************************************************************** //**************************************************************************
const drcbe_x64::opcode_table_entry drcbe_x64::s_opcode_table_source[] = inline void drcbe_x64::generate_one(Assembler &a, const uml::instruction &inst)
{ {
switch (inst.opcode())
{
// Compile-time opcodes // Compile-time opcodes
{ uml::OP_HANDLE, &drcbe_x64::op_handle }, // HANDLE handle case uml::OP_HANDLE: op_handle(a, inst); break; // HANDLE handle
{ uml::OP_HASH, &drcbe_x64::op_hash }, // HASH mode,pc case uml::OP_HASH: op_hash(a, inst); break; // HASH mode,pc
{ uml::OP_LABEL, &drcbe_x64::op_label }, // LABEL imm case uml::OP_LABEL: op_label(a, inst); break; // LABEL imm
{ uml::OP_COMMENT, &drcbe_x64::op_comment }, // COMMENT string case uml::OP_COMMENT: op_comment(a, inst); break; // COMMENT string
{ uml::OP_MAPVAR, &drcbe_x64::op_mapvar }, // MAPVAR mapvar,value case uml::OP_MAPVAR: op_mapvar(a, inst); break; // MAPVAR mapvar,value
// Control Flow Operations // Control Flow Operations
{ uml::OP_NOP, &drcbe_x64::op_nop }, // NOP case uml::OP_NOP: op_nop(a, inst); break; // NOP
{ uml::OP_BREAK, &drcbe_x64::op_break }, // BREAK case uml::OP_BREAK: op_break(a, inst); break; // BREAK
{ uml::OP_DEBUG, &drcbe_x64::op_debug }, // DEBUG pc case uml::OP_DEBUG: op_debug(a, inst); break; // DEBUG pc
{ uml::OP_EXIT, &drcbe_x64::op_exit }, // EXIT src1[,c] case uml::OP_EXIT: op_exit(a, inst); break; // EXIT src1[,c]
{ uml::OP_HASHJMP, &drcbe_x64::op_hashjmp }, // HASHJMP mode,pc,handle case uml::OP_HASHJMP: op_hashjmp(a, inst); break; // HASHJMP mode,pc,handle
{ uml::OP_JMP, &drcbe_x64::op_jmp }, // JMP imm[,c] case uml::OP_JMP: op_jmp(a, inst); break; // JMP imm[,c]
{ uml::OP_EXH, &drcbe_x64::op_exh }, // EXH handle,param[,c] case uml::OP_EXH: op_exh(a, inst); break; // EXH handle,param[,c]
{ uml::OP_CALLH, &drcbe_x64::op_callh }, // CALLH handle[,c] case uml::OP_CALLH: op_callh(a, inst); break; // CALLH handle[,c]
{ uml::OP_RET, &drcbe_x64::op_ret }, // RET [c] case uml::OP_RET: op_ret(a, inst); break; // RET [c]
{ uml::OP_CALLC, &drcbe_x64::op_callc }, // CALLC func,ptr[,c] case uml::OP_CALLC: op_callc(a, inst); break; // CALLC func,ptr[,c]
{ uml::OP_RECOVER, &drcbe_x64::op_recover }, // RECOVER dst,mapvar case uml::OP_RECOVER: op_recover(a, inst); break; // RECOVER dst,mapvar
// Internal Register Operations // Internal Register Operations
{ uml::OP_SETFMOD, &drcbe_x64::op_setfmod }, // SETFMOD src case uml::OP_SETFMOD: op_setfmod(a, inst); break; // SETFMOD src
{ uml::OP_GETFMOD, &drcbe_x64::op_getfmod }, // GETFMOD dst case uml::OP_GETFMOD: op_getfmod(a, inst); break; // GETFMOD dst
{ uml::OP_GETEXP, &drcbe_x64::op_getexp }, // GETEXP dst case uml::OP_GETEXP: op_getexp(a, inst); break; // GETEXP dst
{ uml::OP_GETFLGS, &drcbe_x64::op_getflgs }, // GETFLGS dst[,f] case uml::OP_GETFLGS: op_getflgs(a, inst); break; // GETFLGS dst[,f]
{ uml::OP_SETFLGS, &drcbe_x64::op_setflgs }, // SETFLGS src case uml::OP_SETFLGS: op_setflgs(a, inst); break; // SETFLGS src
{ uml::OP_SAVE, &drcbe_x64::op_save }, // SAVE dst case uml::OP_SAVE: op_save(a, inst); break; // SAVE dst
{ uml::OP_RESTORE, &drcbe_x64::op_restore }, // RESTORE dst case uml::OP_RESTORE: op_restore(a, inst); break; // RESTORE dst
// Integer Operations // Integer Operations
{ uml::OP_LOAD, &drcbe_x64::op_load }, // LOAD dst,base,index,size case uml::OP_LOAD: op_load(a, inst); break; // LOAD dst,base,index,size
{ uml::OP_LOADS, &drcbe_x64::op_loads }, // LOADS dst,base,index,size case uml::OP_LOADS: op_loads(a, inst); break; // LOADS dst,base,index,size
{ uml::OP_STORE, &drcbe_x64::op_store }, // STORE base,index,src,size case uml::OP_STORE: op_store(a, inst); break; // STORE base,index,src,size
{ uml::OP_READ, &drcbe_x64::op_read }, // READ dst,src1,spacesize case uml::OP_READ: op_read(a, inst); break; // READ dst,src1,spacesize
{ uml::OP_READM, &drcbe_x64::op_readm }, // READM dst,src1,mask,spacesize case uml::OP_READM: op_readm(a, inst); break; // READM dst,src1,mask,spacesize
{ uml::OP_WRITE, &drcbe_x64::op_write }, // WRITE dst,src1,spacesize case uml::OP_WRITE: op_write(a, inst); break; // WRITE dst,src1,spacesize
{ uml::OP_WRITEM, &drcbe_x64::op_writem }, // WRITEM dst,src1,spacesize case uml::OP_WRITEM: op_writem(a, inst); break; // WRITEM dst,src1,spacesize
{ uml::OP_CARRY, &drcbe_x64::op_carry }, // CARRY src,bitnum case uml::OP_CARRY: op_carry(a, inst); break; // CARRY src,bitnum
{ uml::OP_SET, &drcbe_x64::op_set }, // SET dst,c case uml::OP_SET: op_set(a, inst); break; // SET dst,c
{ uml::OP_MOV, &drcbe_x64::op_mov }, // MOV dst,src[,c] case uml::OP_MOV: op_mov(a, inst); break; // MOV dst,src[,c]
{ uml::OP_SEXT, &drcbe_x64::op_sext }, // SEXT dst,src case uml::OP_SEXT: op_sext(a, inst); break; // SEXT dst,src
{ uml::OP_ROLAND, &drcbe_x64::op_roland }, // ROLAND dst,src1,src2,src3 case uml::OP_ROLAND: op_roland(a, inst); break; // ROLAND dst,src1,src2,src3
{ uml::OP_ROLINS, &drcbe_x64::op_rolins }, // ROLINS dst,src1,src2,src3 case uml::OP_ROLINS: op_rolins(a, inst); break; // ROLINS dst,src1,src2,src3
{ uml::OP_ADD, &drcbe_x64::op_add }, // ADD dst,src1,src2[,f] case uml::OP_ADD: op_add(a, inst); break; // ADD dst,src1,src2[,f]
{ uml::OP_ADDC, &drcbe_x64::op_addc }, // ADDC dst,src1,src2[,f] case uml::OP_ADDC: op_addc(a, inst); break; // ADDC dst,src1,src2[,f]
{ uml::OP_SUB, &drcbe_x64::op_sub }, // SUB dst,src1,src2[,f] case uml::OP_SUB: op_sub(a, inst); break; // SUB dst,src1,src2[,f]
{ uml::OP_SUBB, &drcbe_x64::op_subc }, // SUBB dst,src1,src2[,f] case uml::OP_SUBB: op_subc(a, inst); break; // SUBB dst,src1,src2[,f]
{ uml::OP_CMP, &drcbe_x64::op_cmp }, // CMP src1,src2[,f] case uml::OP_CMP: op_cmp(a, inst); break; // CMP src1,src2[,f]
{ uml::OP_MULU, &drcbe_x64::op_mulu }, // MULU dst,edst,src1,src2[,f] case uml::OP_MULU: op_mulu(a, inst); break; // MULU dst,edst,src1,src2[,f]
{ uml::OP_MULULW, &drcbe_x64::op_mululw }, // MULULW dst,src1,src2[,f] case uml::OP_MULULW: op_mululw(a, inst); break; // MULULW dst,src1,src2[,f]
{ uml::OP_MULS, &drcbe_x64::op_muls }, // MULS dst,edst,src1,src2[,f] case uml::OP_MULS: op_muls(a, inst); break; // MULS dst,edst,src1,src2[,f]
{ uml::OP_MULSLW, &drcbe_x64::op_mulslw }, // MULSLW dst,src1,src2[,f] case uml::OP_MULSLW: op_mulslw(a, inst); break; // MULSLW dst,src1,src2[,f]
{ uml::OP_DIVU, &drcbe_x64::op_divu }, // DIVU dst,edst,src1,src2[,f] case uml::OP_DIVU: op_divu(a, inst); break; // DIVU dst,edst,src1,src2[,f]
{ uml::OP_DIVS, &drcbe_x64::op_divs }, // DIVS dst,edst,src1,src2[,f] case uml::OP_DIVS: op_divs(a, inst); break; // DIVS dst,edst,src1,src2[,f]
{ uml::OP_AND, &drcbe_x64::op_and }, // AND dst,src1,src2[,f] case uml::OP_AND: op_and(a, inst); break; // AND dst,src1,src2[,f]
{ uml::OP_TEST, &drcbe_x64::op_test }, // TEST src1,src2[,f] case uml::OP_TEST: op_test(a, inst); break; // TEST src1,src2[,f]
{ uml::OP_OR, &drcbe_x64::op_or }, // OR dst,src1,src2[,f] case uml::OP_OR: op_or(a, inst); break; // OR dst,src1,src2[,f]
{ uml::OP_XOR, &drcbe_x64::op_xor }, // XOR dst,src1,src2[,f] case uml::OP_XOR: op_xor(a, inst); break; // XOR dst,src1,src2[,f]
{ uml::OP_LZCNT, &drcbe_x64::op_lzcnt }, // LZCNT dst,src[,f] case uml::OP_LZCNT: op_lzcnt(a, inst); break; // LZCNT dst,src[,f]
{ uml::OP_TZCNT, &drcbe_x64::op_tzcnt }, // TZCNT dst,src[,f] case uml::OP_TZCNT: op_tzcnt(a, inst); break; // TZCNT dst,src[,f]
{ uml::OP_BSWAP, &drcbe_x64::op_bswap }, // BSWAP dst,src case uml::OP_BSWAP: op_bswap(a, inst); break; // BSWAP dst,src
{ uml::OP_SHL, &drcbe_x64::op_shift<Inst::kIdShl> }, // SHL dst,src,count[,f] case uml::OP_SHL: op_shift<Inst::kIdShl>(a, inst); break; // SHL dst,src,count[,f]
{ uml::OP_SHR, &drcbe_x64::op_shift<Inst::kIdShr> }, // SHR dst,src,count[,f] case uml::OP_SHR: op_shift<Inst::kIdShr>(a, inst); break; // SHR dst,src,count[,f]
{ uml::OP_SAR, &drcbe_x64::op_shift<Inst::kIdSar> }, // SAR dst,src,count[,f] case uml::OP_SAR: op_shift<Inst::kIdSar>(a, inst); break; // SAR dst,src,count[,f]
{ uml::OP_ROL, &drcbe_x64::op_shift<Inst::kIdRol> }, // ROL dst,src,count[,f] case uml::OP_ROL: op_shift<Inst::kIdRol>(a, inst); break; // ROL dst,src,count[,f]
{ uml::OP_ROLC, &drcbe_x64::op_shift<Inst::kIdRcl> }, // ROLC dst,src,count[,f] case uml::OP_ROLC: op_shift<Inst::kIdRcl>(a, inst); break; // ROLC dst,src,count[,f]
{ uml::OP_ROR, &drcbe_x64::op_shift<Inst::kIdRor> }, // ROR dst,src,count[,f] case uml::OP_ROR: op_shift<Inst::kIdRor>(a, inst); break; // ROR dst,src,count[,f]
{ uml::OP_RORC, &drcbe_x64::op_shift<Inst::kIdRcr> }, // RORC dst,src,count[,f] case uml::OP_RORC: op_shift<Inst::kIdRcr>(a, inst); break; // RORC dst,src,count[,f]
// Floating Point Operations // Floating Point Operations
{ uml::OP_FLOAD, &drcbe_x64::op_fload }, // FLOAD dst,base,index case uml::OP_FLOAD: op_fload(a, inst); break; // FLOAD dst,base,index
{ uml::OP_FSTORE, &drcbe_x64::op_fstore }, // FSTORE base,index,src case uml::OP_FSTORE: op_fstore(a, inst); break; // FSTORE base,index,src
{ uml::OP_FREAD, &drcbe_x64::op_fread }, // FREAD dst,space,src1 case uml::OP_FREAD: op_fread(a, inst); break; // FREAD dst,space,src1
{ uml::OP_FWRITE, &drcbe_x64::op_fwrite }, // FWRITE space,dst,src1 case uml::OP_FWRITE: op_fwrite(a, inst); break; // FWRITE space,dst,src1
{ uml::OP_FMOV, &drcbe_x64::op_fmov }, // FMOV dst,src1[,c] case uml::OP_FMOV: op_fmov(a, inst); break; // FMOV dst,src1[,c]
{ uml::OP_FTOINT, &drcbe_x64::op_ftoint }, // FTOINT dst,src1,size,round case uml::OP_FTOINT: op_ftoint(a, inst); break; // FTOINT dst,src1,size,round
{ uml::OP_FFRINT, &drcbe_x64::op_ffrint }, // FFRINT dst,src1,size case uml::OP_FFRINT: op_ffrint(a, inst); break; // FFRINT dst,src1,size
{ uml::OP_FFRFLT, &drcbe_x64::op_ffrflt }, // FFRFLT dst,src1,size case uml::OP_FFRFLT: op_ffrflt(a, inst); break; // FFRFLT dst,src1,size
{ uml::OP_FRNDS, &drcbe_x64::op_frnds }, // FRNDS dst,src1 case uml::OP_FRNDS: op_frnds(a, inst); break; // FRNDS dst,src1
{ uml::OP_FADD, &drcbe_x64::op_fadd }, // FADD dst,src1,src2 case uml::OP_FADD: op_fadd(a, inst); break; // FADD dst,src1,src2
{ uml::OP_FSUB, &drcbe_x64::op_fsub }, // FSUB dst,src1,src2 case uml::OP_FSUB: op_fsub(a, inst); break; // FSUB dst,src1,src2
{ uml::OP_FCMP, &drcbe_x64::op_fcmp }, // FCMP src1,src2 case uml::OP_FCMP: op_fcmp(a, inst); break; // FCMP src1,src2
{ uml::OP_FMUL, &drcbe_x64::op_fmul }, // FMUL dst,src1,src2 case uml::OP_FMUL: op_fmul(a, inst); break; // FMUL dst,src1,src2
{ uml::OP_FDIV, &drcbe_x64::op_fdiv }, // FDIV dst,src1,src2 case uml::OP_FDIV: op_fdiv(a, inst); break; // FDIV dst,src1,src2
{ uml::OP_FNEG, &drcbe_x64::op_fneg }, // FNEG dst,src1 case uml::OP_FNEG: op_fneg(a, inst); break; // FNEG dst,src1
{ uml::OP_FABS, &drcbe_x64::op_fabs }, // FABS dst,src1 case uml::OP_FABS: op_fabs(a, inst); break; // FABS dst,src1
{ uml::OP_FSQRT, &drcbe_x64::op_fsqrt }, // FSQRT dst,src1 case uml::OP_FSQRT: op_fsqrt(a, inst); break; // FSQRT dst,src1
{ uml::OP_FRECIP, &drcbe_x64::op_frecip }, // FRECIP dst,src1 case uml::OP_FRECIP: op_frecip(a, inst); break; // FRECIP dst,src1
{ uml::OP_FRSQRT, &drcbe_x64::op_frsqrt }, // FRSQRT dst,src1 case uml::OP_FRSQRT: op_frsqrt(a, inst); break; // FRSQRT dst,src1
{ uml::OP_FCOPYI, &drcbe_x64::op_fcopyi }, // FCOPYI dst,src case uml::OP_FCOPYI: op_fcopyi(a, inst); break; // FCOPYI dst,src
{ uml::OP_ICOPYF, &drcbe_x64::op_icopyf } // ICOPYF dst,src case uml::OP_ICOPYF: op_icopyf(a, inst); break; // ICOPYF dst,src
default: throw emu_fatalerror("drcbe_x64(%s): unhandled opcode %u\n", m_device.tag(), inst.opcode());
}
}; };
@ -1101,10 +1086,6 @@ drcbe_x64::drcbe_x64(drcuml_state &drcuml, device_t &device, drc_cache &cache, u
} }
} }
// build the opcode table (static but it doesn't hurt to regenerate it)
for (auto & elem : s_opcode_table_source)
s_opcode_table[elem.opcode] = elem.func;
// create the log // create the log
if (device.machine().options().drc_log_native()) if (device.machine().options().drc_log_native())
{ {
@ -1327,7 +1308,6 @@ void drcbe_x64::generate(drcuml_block &block, const instruction *instlist, uint3
for (int inum = 0; inum < numinst; inum++) for (int inum = 0; inum < numinst; inum++)
{ {
const instruction &inst = instlist[inum]; const instruction &inst = instlist[inum];
assert(inst.opcode() < std::size(s_opcode_table));
// must remain in scope until output // must remain in scope until output
std::string dasm; std::string dasm;
@ -1351,7 +1331,7 @@ void drcbe_x64::generate(drcuml_block &block, const instruction *instlist, uint3
} }
// generate code // generate code
(this->*s_opcode_table[inst.opcode()])(a, inst); generate_one(a, inst);
} }
// catch falling off the end of a block // catch falling off the end of a block
@ -1495,7 +1475,7 @@ void drcbe_x64::calculate_status_flags(Assembler &a, uint32_t instsize, Operand
} }
} }
void drcbe_x64::calculate_status_flags_mul(Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo, asmjit::x86::Gp const &hi) void drcbe_x64::calculate_status_flags_mul(Assembler &a, uint32_t instsize, Gp const &lo, Gp const &hi)
{ {
Gp tempreg = r11; Gp tempreg = r11;
Gp tempreg2 = r10; Gp tempreg2 = r10;
@ -1548,7 +1528,7 @@ void drcbe_x64::calculate_status_flags_mul(Assembler &a, uint32_t instsize, asmj
a.sahf(); a.sahf();
} }
void drcbe_x64::calculate_status_flags_mul_low(Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo) void drcbe_x64::calculate_status_flags_mul_low(Assembler &a, uint32_t instsize, Gp const &lo)
{ {
// calculate zero, sign flags based on the lower half of the result but keep the overflow from the multiplication // calculate zero, sign flags based on the lower half of the result but keep the overflow from the multiplication
a.seto(dl); a.seto(dl);
@ -4387,10 +4367,25 @@ void drcbe_x64::op_sub(Assembler &a, const instruction &inst)
be_parameter src1p(*this, inst.param(1), PTYPE_MRI); be_parameter src1p(*this, inst.param(1), PTYPE_MRI);
be_parameter src2p(*this, inst.param(2), PTYPE_MRI); be_parameter src2p(*this, inst.param(2), PTYPE_MRI);
if (dstp.is_memory() && ((inst.size() == 8) || !dstp.is_cold_register()) && (dstp == src1p)) if (src1p.is_immediate_value(0))
{
if (dstp.is_memory() && (dstp == src2p) && ((inst.size() == 8) || !dstp.is_cold_register()))
{
a.neg(MABS(dstp.memory(), inst.size()));
}
else
{
Gp const dstreg = dstp.select_register((inst.size() == 4) ? Gp(eax) : Gp(rax));
mov_reg_param(a, dstreg, src2p);
a.neg(dstreg);
mov_param_reg(a, dstp, dstreg);
}
}
else if (dstp.is_memory() && ((inst.size() == 8) || !dstp.is_cold_register()) && (dstp == src1p))
{ {
// dstp == src1p in memory // dstp == src1p in memory
alu_op_param(a, Inst::kIdSub, MABS(dstp.memory(), inst.size()), src2p, // sub [dstp],src2p alu_op_param(a, Inst::kIdSub, MABS(dstp.memory(), inst.size()), src2p,
[inst] (Assembler &a, Operand const &dst, be_parameter const &src) [inst] (Assembler &a, Operand const &dst, be_parameter const &src)
{ {
// optimize zero case // optimize zero case
@ -4403,23 +4398,23 @@ void drcbe_x64::op_sub(Assembler &a, const instruction &inst)
Gp const dst = Gp::fromTypeAndId((inst.size() == 4) ? RegType::kX86_Gpd : RegType::kX86_Gpq, dstp.ireg()); Gp const dst = Gp::fromTypeAndId((inst.size() == 4) ? RegType::kX86_Gpd : RegType::kX86_Gpq, dstp.ireg());
Gp const src1 = Gp::fromTypeAndId((inst.size() == 4) ? RegType::kX86_Gpd : RegType::kX86_Gpq, src1p.ireg()); Gp const src1 = Gp::fromTypeAndId((inst.size() == 4) ? RegType::kX86_Gpd : RegType::kX86_Gpq, src1p.ireg());
a.lea(dst, ptr(src1, -src2p.immediate())); // lea dstp,[src1p-src2p] a.lea(dst, ptr(src1, -src2p.immediate()));
} }
else else
{ {
// general case // general case
// pick a target register for the general case // pick a target register for the general case
Gp dstreg = (inst.size() == 4) ? dstp.select_register(eax, src2p) : dstp.select_register(rax, src2p); Gp const dstreg = dstp.select_register((inst.size() == 4) ? Gp(eax) : Gp(rax), src2p);
mov_reg_param(a, dstreg, src1p); // mov dstreg,src1p mov_reg_param(a, dstreg, src1p);
alu_op_param(a, Inst::kIdSub, dstreg, src2p, // sub dstreg,src2p alu_op_param(a, Inst::kIdSub, dstreg, src2p,
[inst] (Assembler &a, Operand const &dst, be_parameter const &src) [inst] (Assembler &a, Operand const &dst, be_parameter const &src)
{ {
// optimize zero case // optimize zero case
return (!inst.flags() && !src.immediate() && (inst.size() != 4)); return (!inst.flags() && !src.immediate() && (inst.size() != 4));
}); });
mov_param_reg(a, dstp, dstreg); // mov dstp,dstreg mov_param_reg(a, dstp, dstreg);
} }
} }

View File

@ -476,8 +476,8 @@ private:
bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); } bool is_immediate_value(uint64_t value) const { return (m_type == PTYPE_IMMEDIATE && m_value == value); }
// helpers // helpers
asmjit::x86::Gpd select_register(asmjit::x86::Gpd const &defreg) const; Gpd select_register(Gpd const &defreg) const;
asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg) const; Xmm select_register(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) const;
template <typename T> T select_register(T defreg, be_parameter const &checkparam, be_parameter const &checkparam2) const; template <typename T> T select_register(T defreg, be_parameter const &checkparam, be_parameter const &checkparam2) const;
@ -491,142 +491,145 @@ private:
}; };
// helpers // helpers
asmjit::x86::Mem MABS(void const *base, u32 const size = 0) const { return asmjit::x86::Mem(u64(base), size); } Mem MABS(void const *base, u32 const size = 0) const { return Mem(u64(base), size); }
void normalize_commutative(be_parameter &inner, be_parameter &outer); void normalize_commutative(be_parameter &inner, be_parameter &outer);
void emit_combine_z_flags(asmjit::x86::Assembler &a); void emit_combine_z_flags(Assembler &a);
void emit_combine_zs_flags(asmjit::x86::Assembler &a); void emit_combine_zs_flags(Assembler &a);
void emit_combine_z_shl_flags(asmjit::x86::Assembler &a); void emit_combine_z_shl_flags(Assembler &a);
void reset_last_upper_lower_reg(); 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_lower_reg(Assembler &a, be_parameter const &param, Gp const &reglo);
void set_last_upper_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reghi); void set_last_upper_reg(Assembler &a, be_parameter const &param, Gp const &reghi);
bool can_skip_lower_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const &reglo); bool can_skip_lower_load(Assembler &a, uint32_t *memref, Gp const &reglo);
bool can_skip_upper_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const &reghi); bool can_skip_upper_load(Assembler &a, uint32_t *memref, Gp const &reghi);
[[noreturn]] void end_of_block() const; [[noreturn]] void end_of_block() const;
static void debug_log_hashjmp(int mode, offs_t pc); static void debug_log_hashjmp(int mode, offs_t pc);
void generate_one(Assembler &a, const uml::instruction &inst);
// code generators // code generators
void op_handle(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_handle(Assembler &a, const uml::instruction &inst);
void op_hash(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_hash(Assembler &a, const uml::instruction &inst);
void op_label(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_label(Assembler &a, const uml::instruction &inst);
void op_comment(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_comment(Assembler &a, const uml::instruction &inst);
void op_mapvar(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_mapvar(Assembler &a, const uml::instruction &inst);
void op_nop(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_nop(Assembler &a, const uml::instruction &inst);
void op_break(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_break(Assembler &a, const uml::instruction &inst);
void op_debug(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_debug(Assembler &a, const uml::instruction &inst);
void op_exit(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_exit(Assembler &a, const uml::instruction &inst);
void op_hashjmp(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_hashjmp(Assembler &a, const uml::instruction &inst);
void op_jmp(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_jmp(Assembler &a, const uml::instruction &inst);
void op_exh(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_exh(Assembler &a, const uml::instruction &inst);
void op_callh(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_callh(Assembler &a, const uml::instruction &inst);
void op_ret(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_ret(Assembler &a, const uml::instruction &inst);
void op_callc(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_callc(Assembler &a, const uml::instruction &inst);
void op_recover(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_recover(Assembler &a, const uml::instruction &inst);
void op_setfmod(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_setfmod(Assembler &a, const uml::instruction &inst);
void op_getfmod(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_getfmod(Assembler &a, const uml::instruction &inst);
void op_getexp(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_getexp(Assembler &a, const uml::instruction &inst);
void op_getflgs(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_getflgs(Assembler &a, const uml::instruction &inst);
void op_setflgs(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_setflgs(Assembler &a, const uml::instruction &inst);
void op_save(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_save(Assembler &a, const uml::instruction &inst);
void op_restore(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_restore(Assembler &a, const uml::instruction &inst);
void op_load(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_load(Assembler &a, const uml::instruction &inst);
void op_loads(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_loads(Assembler &a, const uml::instruction &inst);
void op_store(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_store(Assembler &a, const uml::instruction &inst);
void op_read(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_read(Assembler &a, const uml::instruction &inst);
void op_readm(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_readm(Assembler &a, const uml::instruction &inst);
void op_write(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_write(Assembler &a, const uml::instruction &inst);
void op_writem(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_writem(Assembler &a, const uml::instruction &inst);
void op_carry(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_carry(Assembler &a, const uml::instruction &inst);
void op_set(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_set(Assembler &a, const uml::instruction &inst);
void op_mov(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_mov(Assembler &a, const uml::instruction &inst);
void op_sext(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_sext(Assembler &a, const uml::instruction &inst);
void op_roland(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_roland(Assembler &a, const uml::instruction &inst);
void op_rolins(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_rolins(Assembler &a, const uml::instruction &inst);
void op_add(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_add(Assembler &a, const uml::instruction &inst);
void op_addc(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_addc(Assembler &a, const uml::instruction &inst);
void op_sub(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_sub(Assembler &a, const uml::instruction &inst);
void op_subc(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_subc(Assembler &a, const uml::instruction &inst);
void op_cmp(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_cmp(Assembler &a, const uml::instruction &inst);
void op_mulu(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_mulu(Assembler &a, const uml::instruction &inst);
void op_mululw(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_mululw(Assembler &a, const uml::instruction &inst);
void op_muls(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_muls(Assembler &a, const uml::instruction &inst);
void op_mulslw(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_mulslw(Assembler &a, const uml::instruction &inst);
void op_divu(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_divu(Assembler &a, const uml::instruction &inst);
void op_divs(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_divs(Assembler &a, const uml::instruction &inst);
void op_and(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_and(Assembler &a, const uml::instruction &inst);
void op_test(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_test(Assembler &a, const uml::instruction &inst);
void op_or(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_or(Assembler &a, const uml::instruction &inst);
void op_xor(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_xor(Assembler &a, const uml::instruction &inst);
void op_lzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_lzcnt(Assembler &a, const uml::instruction &inst);
void op_tzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_tzcnt(Assembler &a, const uml::instruction &inst);
void op_bswap(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_bswap(Assembler &a, const uml::instruction &inst);
void op_shl(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_shl(Assembler &a, const uml::instruction &inst);
void op_shr(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_shr(Assembler &a, const uml::instruction &inst);
void op_sar(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_sar(Assembler &a, const uml::instruction &inst);
void op_ror(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_ror(Assembler &a, const uml::instruction &inst);
void op_rol(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_rol(Assembler &a, const uml::instruction &inst);
void op_rorc(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_rorc(Assembler &a, const uml::instruction &inst);
void op_rolc(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_rolc(Assembler &a, const uml::instruction &inst);
void op_fload(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fload(Assembler &a, const uml::instruction &inst);
void op_fstore(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fstore(Assembler &a, const uml::instruction &inst);
void op_fread(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fread(Assembler &a, const uml::instruction &inst);
void op_fwrite(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fwrite(Assembler &a, const uml::instruction &inst);
void op_fmov(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fmov(Assembler &a, const uml::instruction &inst);
void op_ftoint(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_ftoint(Assembler &a, const uml::instruction &inst);
void op_ffrint(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_ffrint(Assembler &a, const uml::instruction &inst);
void op_ffrflt(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_ffrflt(Assembler &a, const uml::instruction &inst);
void op_frnds(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_frnds(Assembler &a, const uml::instruction &inst);
void op_fadd(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fadd(Assembler &a, const uml::instruction &inst);
void op_fsub(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fsub(Assembler &a, const uml::instruction &inst);
void op_fcmp(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fcmp(Assembler &a, const uml::instruction &inst);
void op_fmul(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fmul(Assembler &a, const uml::instruction &inst);
void op_fdiv(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fdiv(Assembler &a, const uml::instruction &inst);
void op_fneg(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fneg(Assembler &a, const uml::instruction &inst);
void op_fabs(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fabs(Assembler &a, const uml::instruction &inst);
void op_fsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fsqrt(Assembler &a, const uml::instruction &inst);
void op_frecip(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_frecip(Assembler &a, const uml::instruction &inst);
void op_frsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_frsqrt(Assembler &a, const uml::instruction &inst);
void op_fcopyi(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_fcopyi(Assembler &a, const uml::instruction &inst);
void op_icopyf(asmjit::x86::Assembler &a, const uml::instruction &inst); void op_icopyf(Assembler &a, const uml::instruction &inst);
// 32-bit code emission helpers // 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(Assembler &a, 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_r32_p32_keepflags(Assembler &a, 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_m32_p32(Assembler &a, 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 emit_mov_p32_r32(Assembler &a, be_parameter const &param, 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; }); template <typename T> void alu_op_param(Assembler &a, Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param, T &&optimize);
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); void alu_op_param(Assembler &a, Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param) { alu_op_param(a, opcode, dst, param, [](Assembler &a, asmjit::Operand dst, be_parameter const &src) { return false; }); }
template <typename T> void shift_op_param(Assembler &a, Inst::Id const opcode, size_t opsize, asmjit::Operand const &dst, be_parameter const &param, T &&optimize, bool update_flags);
// 64-bit code emission helpers // 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(Assembler &a, Gp const &reglo, 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_r64_p64_keepflags(Assembler &a, Gp const &reglo, 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_m64_p64(Assembler &a, 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_mov_p64_r64(Assembler &a, be_parameter const &param, Gp const &reglo, 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_r64_p64(Assembler &a, Gp const &reglo, 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_and_m64_p64(Assembler &a, Mem const &memref_lo, 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_r64_p64(Assembler &a, Gp const &reglo, 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_or_m64_p64(Assembler &a, Mem const &memref_lo, 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_r64_p64(Assembler &a, Gp const &reglo, 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_xor_m64_p64(Assembler &a, Mem const &memref_lo, 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_shl_r64_p64(Assembler &a, Gp const &reglo, 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_shr_r64_p64(Assembler &a, Gp const &reglo, 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_sar_r64_p64(Assembler &a, Gp const &reglo, 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_rol_r64_p64(Assembler &a, Gp const &reglo, 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_ror_r64_p64(Assembler &a, Gp const &reglo, 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_rcl_r64_p64(Assembler &a, Gp const &reglo, 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 emit_rcr_r64_p64(Assembler &a, Gp const &reglo, 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(Assembler &a, Inst::Id const opcode_lo, Inst::Id const opcode_hi, Gp const &lo, 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); void alu_op_param(Assembler &a, Inst::Id const opcode_lo, Inst::Id const opcode_hi, Mem const &lo, Mem const &hi, be_parameter const &param, bool const saveflags);
// floating-point code emission helpers // floating-point code emission helpers
void emit_fld_p(asmjit::x86::Assembler &a, int size, be_parameter const &param); void emit_fld_p(Assembler &a, int size, be_parameter const &param);
void emit_fstp_p(asmjit::x86::Assembler &a, int size, be_parameter const &param); void emit_fstp_p(Assembler &a, int size, be_parameter const &param);
size_t emit(asmjit::CodeHolder &ch); size_t emit(asmjit::CodeHolder &ch);
@ -647,10 +650,10 @@ private:
uint32_t * m_reglo[REG_MAX]; // pointer to low part of data for each register 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 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 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 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 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 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 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 uint32_t * m_last_upper_addr; // address where we last stored an upper register
double m_fptemp; // temporary storage for floating point double m_fptemp; // temporary storage for floating point
@ -667,125 +670,112 @@ private:
resolved_member_function m_debug_cpu_instruction_hook; resolved_member_function m_debug_cpu_instruction_hook;
resolved_member_function m_drcmap_get_value; resolved_member_function m_drcmap_get_value;
resolved_memory_accessors_vector m_memory_accessors; 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];
}; };
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
drcbe_x86::opcode_generate_func drcbe_x86::s_opcode_table[OP_MAX];
//************************************************************************** //**************************************************************************
// TABLES // TABLES
//************************************************************************** //**************************************************************************
const drcbe_x86::opcode_table_entry drcbe_x86::s_opcode_table_source[] = inline void drcbe_x86::generate_one(Assembler &a, const uml::instruction &inst)
{ {
switch (inst.opcode())
{
// Compile-time opcodes // Compile-time opcodes
{ uml::OP_HANDLE, &drcbe_x86::op_handle }, // HANDLE handle case uml::OP_HANDLE: op_handle(a, inst); break; // HANDLE handle
{ uml::OP_HASH, &drcbe_x86::op_hash }, // HASH mode,pc case uml::OP_HASH: op_hash(a, inst); break; // HASH mode,pc
{ uml::OP_LABEL, &drcbe_x86::op_label }, // LABEL imm case uml::OP_LABEL: op_label(a, inst); break; // LABEL imm
{ uml::OP_COMMENT, &drcbe_x86::op_comment }, // COMMENT string case uml::OP_COMMENT: op_comment(a, inst); break; // COMMENT string
{ uml::OP_MAPVAR, &drcbe_x86::op_mapvar }, // MAPVAR mapvar,value case uml::OP_MAPVAR: op_mapvar(a, inst); break; // MAPVAR mapvar,value
// Control Flow Operations // Control Flow Operations
{ uml::OP_NOP, &drcbe_x86::op_nop }, // NOP case uml::OP_NOP: op_nop(a, inst); break; // NOP
{ uml::OP_BREAK, &drcbe_x86::op_break }, // BREAK case uml::OP_BREAK: op_break(a, inst); break; // BREAK
{ uml::OP_DEBUG, &drcbe_x86::op_debug }, // DEBUG pc case uml::OP_DEBUG: op_debug(a, inst); break; // DEBUG pc
{ uml::OP_EXIT, &drcbe_x86::op_exit }, // EXIT src1[,c] case uml::OP_EXIT: op_exit(a, inst); break; // EXIT src1[,c]
{ uml::OP_HASHJMP, &drcbe_x86::op_hashjmp }, // HASHJMP mode,pc,handle case uml::OP_HASHJMP: op_hashjmp(a, inst); break; // HASHJMP mode,pc,handle
{ uml::OP_JMP, &drcbe_x86::op_jmp }, // JMP imm[,c] case uml::OP_JMP: op_jmp(a, inst); break; // JMP imm[,c]
{ uml::OP_EXH, &drcbe_x86::op_exh }, // EXH handle,param[,c] case uml::OP_EXH: op_exh(a, inst); break; // EXH handle,param[,c]
{ uml::OP_CALLH, &drcbe_x86::op_callh }, // CALLH handle[,c] case uml::OP_CALLH: op_callh(a, inst); break; // CALLH handle[,c]
{ uml::OP_RET, &drcbe_x86::op_ret }, // RET [c] case uml::OP_RET: op_ret(a, inst); break; // RET [c]
{ uml::OP_CALLC, &drcbe_x86::op_callc }, // CALLC func,ptr[,c] case uml::OP_CALLC: op_callc(a, inst); break; // CALLC func,ptr[,c]
{ uml::OP_RECOVER, &drcbe_x86::op_recover }, // RECOVER dst,mapvar case uml::OP_RECOVER: op_recover(a, inst); break; // RECOVER dst,mapvar
// Internal Register Operations // Internal Register Operations
{ uml::OP_SETFMOD, &drcbe_x86::op_setfmod }, // SETFMOD src case uml::OP_SETFMOD: op_setfmod(a, inst); break; // SETFMOD src
{ uml::OP_GETFMOD, &drcbe_x86::op_getfmod }, // GETFMOD dst case uml::OP_GETFMOD: op_getfmod(a, inst); break; // GETFMOD dst
{ uml::OP_GETEXP, &drcbe_x86::op_getexp }, // GETEXP dst case uml::OP_GETEXP: op_getexp(a, inst); break; // GETEXP dst
{ uml::OP_GETFLGS, &drcbe_x86::op_getflgs }, // GETFLGS dst[,f] case uml::OP_GETFLGS: op_getflgs(a, inst); break; // GETFLGS dst[,f]
{ uml::OP_SETFLGS, &drcbe_x86::op_setflgs }, // GETFLGS src case uml::OP_SETFLGS: op_setflgs(a, inst); break; // GETFLGS src
{ uml::OP_SAVE, &drcbe_x86::op_save }, // SAVE dst case uml::OP_SAVE: op_save(a, inst); break; // SAVE dst
{ uml::OP_RESTORE, &drcbe_x86::op_restore }, // RESTORE dst case uml::OP_RESTORE: op_restore(a, inst); break; // RESTORE dst
// Integer Operations // Integer Operations
{ uml::OP_LOAD, &drcbe_x86::op_load }, // LOAD dst,base,index,size case uml::OP_LOAD: op_load(a, inst); break; // LOAD dst,base,index,size
{ uml::OP_LOADS, &drcbe_x86::op_loads }, // LOADS dst,base,index,size case uml::OP_LOADS: op_loads(a, inst); break; // LOADS dst,base,index,size
{ uml::OP_STORE, &drcbe_x86::op_store }, // STORE base,index,src,size case uml::OP_STORE: op_store(a, inst); break; // STORE base,index,src,size
{ uml::OP_READ, &drcbe_x86::op_read }, // READ dst,src1,spacesize case uml::OP_READ: op_read(a, inst); break; // READ dst,src1,spacesize
{ uml::OP_READM, &drcbe_x86::op_readm }, // READM dst,src1,mask,spacesize case uml::OP_READM: op_readm(a, inst); break; // READM dst,src1,mask,spacesize
{ uml::OP_WRITE, &drcbe_x86::op_write }, // WRITE dst,src1,spacesize case uml::OP_WRITE: op_write(a, inst); break; // WRITE dst,src1,spacesize
{ uml::OP_WRITEM, &drcbe_x86::op_writem }, // WRITEM dst,src1,spacesize case uml::OP_WRITEM: op_writem(a, inst); break; // WRITEM dst,src1,spacesize
{ uml::OP_CARRY, &drcbe_x86::op_carry }, // CARRY src,bitnum case uml::OP_CARRY: op_carry(a, inst); break; // CARRY src,bitnum
{ uml::OP_SET, &drcbe_x86::op_set }, // SET dst,c case uml::OP_SET: op_set(a, inst); break; // SET dst,c
{ uml::OP_MOV, &drcbe_x86::op_mov }, // MOV dst,src[,c] case uml::OP_MOV: op_mov(a, inst); break; // MOV dst,src[,c]
{ uml::OP_SEXT, &drcbe_x86::op_sext }, // SEXT dst,src case uml::OP_SEXT: op_sext(a, inst); break; // SEXT dst,src
{ uml::OP_ROLAND, &drcbe_x86::op_roland }, // ROLAND dst,src1,src2,src3 case uml::OP_ROLAND: op_roland(a, inst); break; // ROLAND dst,src1,src2,src3
{ uml::OP_ROLINS, &drcbe_x86::op_rolins }, // ROLINS dst,src1,src2,src3 case uml::OP_ROLINS: op_rolins(a, inst); break; // ROLINS dst,src1,src2,src3
{ uml::OP_ADD, &drcbe_x86::op_add }, // ADD dst,src1,src2[,f] case uml::OP_ADD: op_add(a, inst); break; // ADD dst,src1,src2[,f]
{ uml::OP_ADDC, &drcbe_x86::op_addc }, // ADDC dst,src1,src2[,f] case uml::OP_ADDC: op_addc(a, inst); break; // ADDC dst,src1,src2[,f]
{ uml::OP_SUB, &drcbe_x86::op_sub }, // SUB dst,src1,src2[,f] case uml::OP_SUB: op_sub(a, inst); break; // SUB dst,src1,src2[,f]
{ uml::OP_SUBB, &drcbe_x86::op_subc }, // SUBB dst,src1,src2[,f] case uml::OP_SUBB: op_subc(a, inst); break; // SUBB dst,src1,src2[,f]
{ uml::OP_CMP, &drcbe_x86::op_cmp }, // CMP src1,src2[,f] case uml::OP_CMP: op_cmp(a, inst); break; // CMP src1,src2[,f]
{ uml::OP_MULU, &drcbe_x86::op_mulu }, // MULU dst,edst,src1,src2[,f] case uml::OP_MULU: op_mulu(a, inst); break; // MULU dst,edst,src1,src2[,f]
{ uml::OP_MULULW, &drcbe_x86::op_mululw }, // MULULW dst,src1,src2[,f] case uml::OP_MULULW: op_mululw(a, inst); break; // MULULW dst,src1,src2[,f]
{ uml::OP_MULS, &drcbe_x86::op_muls }, // MULS dst,edst,src1,src2[,f] case uml::OP_MULS: op_muls(a, inst); break; // MULS dst,edst,src1,src2[,f]
{ uml::OP_MULSLW, &drcbe_x86::op_mulslw }, // MULSLW dst,src1,src2[,f] case uml::OP_MULSLW: op_mulslw(a, inst); break; // MULSLW dst,src1,src2[,f]
{ uml::OP_DIVU, &drcbe_x86::op_divu }, // DIVU dst,edst,src1,src2[,f] case uml::OP_DIVU: op_divu(a, inst); break; // DIVU dst,edst,src1,src2[,f]
{ uml::OP_DIVS, &drcbe_x86::op_divs }, // DIVS dst,edst,src1,src2[,f] case uml::OP_DIVS: op_divs(a, inst); break; // DIVS dst,edst,src1,src2[,f]
{ uml::OP_AND, &drcbe_x86::op_and }, // AND dst,src1,src2[,f] case uml::OP_AND: op_and(a, inst); break; // AND dst,src1,src2[,f]
{ uml::OP_TEST, &drcbe_x86::op_test }, // TEST src1,src2[,f] case uml::OP_TEST: op_test(a, inst); break; // TEST src1,src2[,f]
{ uml::OP_OR, &drcbe_x86::op_or }, // OR dst,src1,src2[,f] case uml::OP_OR: op_or(a, inst); break; // OR dst,src1,src2[,f]
{ uml::OP_XOR, &drcbe_x86::op_xor }, // XOR dst,src1,src2[,f] case uml::OP_XOR: op_xor(a, inst); break; // XOR dst,src1,src2[,f]
{ uml::OP_LZCNT, &drcbe_x86::op_lzcnt }, // LZCNT dst,src[,f] case uml::OP_LZCNT: op_lzcnt(a, inst); break; // LZCNT dst,src[,f]
{ uml::OP_TZCNT, &drcbe_x86::op_tzcnt }, // TZCNT dst,src[,f] case uml::OP_TZCNT: op_tzcnt(a, inst); break; // TZCNT dst,src[,f]
{ uml::OP_BSWAP, &drcbe_x86::op_bswap }, // BSWAP dst,src case uml::OP_BSWAP: op_bswap(a, inst); break; // BSWAP dst,src
{ uml::OP_SHL, &drcbe_x86::op_shl }, // SHL dst,src,count[,f] case uml::OP_SHL: op_shl(a, inst); break; // SHL dst,src,count[,f]
{ uml::OP_SHR, &drcbe_x86::op_shr }, // SHR dst,src,count[,f] case uml::OP_SHR: op_shr(a, inst); break; // SHR dst,src,count[,f]
{ uml::OP_SAR, &drcbe_x86::op_sar }, // SAR dst,src,count[,f] case uml::OP_SAR: op_sar(a, inst); break; // SAR dst,src,count[,f]
{ uml::OP_ROL, &drcbe_x86::op_rol }, // ROL dst,src,count[,f] case uml::OP_ROL: op_rol(a, inst); break; // ROL dst,src,count[,f]
{ uml::OP_ROLC, &drcbe_x86::op_rolc }, // ROLC dst,src,count[,f] case uml::OP_ROLC: op_rolc(a, inst); break; // ROLC dst,src,count[,f]
{ uml::OP_ROR, &drcbe_x86::op_ror }, // ROR dst,src,count[,f] case uml::OP_ROR: op_ror(a, inst); break; // ROR dst,src,count[,f]
{ uml::OP_RORC, &drcbe_x86::op_rorc }, // RORC dst,src,count[,f] case uml::OP_RORC: op_rorc(a, inst); break; // RORC dst,src,count[,f]
// Floating Point Operations // Floating Point Operations
{ uml::OP_FLOAD, &drcbe_x86::op_fload }, // FLOAD dst,base,index case uml::OP_FLOAD: op_fload(a, inst); break; // FLOAD dst,base,index
{ uml::OP_FSTORE, &drcbe_x86::op_fstore }, // FSTORE base,index,src case uml::OP_FSTORE: op_fstore(a, inst); break; // FSTORE base,index,src
{ uml::OP_FREAD, &drcbe_x86::op_fread }, // FREAD dst,space,src1 case uml::OP_FREAD: op_fread(a, inst); break; // FREAD dst,space,src1
{ uml::OP_FWRITE, &drcbe_x86::op_fwrite }, // FWRITE space,dst,src1 case uml::OP_FWRITE: op_fwrite(a, inst); break; // FWRITE space,dst,src1
{ uml::OP_FMOV, &drcbe_x86::op_fmov }, // FMOV dst,src1[,c] case uml::OP_FMOV: op_fmov(a, inst); break; // FMOV dst,src1[,c]
{ uml::OP_FTOINT, &drcbe_x86::op_ftoint }, // FTOINT dst,src1,size,round case uml::OP_FTOINT: op_ftoint(a, inst); break; // FTOINT dst,src1,size,round
{ uml::OP_FFRINT, &drcbe_x86::op_ffrint }, // FFRINT dst,src1,size case uml::OP_FFRINT: op_ffrint(a, inst); break; // FFRINT dst,src1,size
{ uml::OP_FFRFLT, &drcbe_x86::op_ffrflt }, // FFRFLT dst,src1,size case uml::OP_FFRFLT: op_ffrflt(a, inst); break; // FFRFLT dst,src1,size
{ uml::OP_FRNDS, &drcbe_x86::op_frnds }, // FRNDS dst,src1 case uml::OP_FRNDS: op_frnds(a, inst); break; // FRNDS dst,src1
{ uml::OP_FADD, &drcbe_x86::op_fadd }, // FADD dst,src1,src2 case uml::OP_FADD: op_fadd(a, inst); break; // FADD dst,src1,src2
{ uml::OP_FSUB, &drcbe_x86::op_fsub }, // FSUB dst,src1,src2 case uml::OP_FSUB: op_fsub(a, inst); break; // FSUB dst,src1,src2
{ uml::OP_FCMP, &drcbe_x86::op_fcmp }, // FCMP src1,src2 case uml::OP_FCMP: op_fcmp(a, inst); break; // FCMP src1,src2
{ uml::OP_FMUL, &drcbe_x86::op_fmul }, // FMUL dst,src1,src2 case uml::OP_FMUL: op_fmul(a, inst); break; // FMUL dst,src1,src2
{ uml::OP_FDIV, &drcbe_x86::op_fdiv }, // FDIV dst,src1,src2 case uml::OP_FDIV: op_fdiv(a, inst); break; // FDIV dst,src1,src2
{ uml::OP_FNEG, &drcbe_x86::op_fneg }, // FNEG dst,src1 case uml::OP_FNEG: op_fneg(a, inst); break; // FNEG dst,src1
{ uml::OP_FABS, &drcbe_x86::op_fabs }, // FABS dst,src1 case uml::OP_FABS: op_fabs(a, inst); break; // FABS dst,src1
{ uml::OP_FSQRT, &drcbe_x86::op_fsqrt }, // FSQRT dst,src1 case uml::OP_FSQRT: op_fsqrt(a, inst); break; // FSQRT dst,src1
{ uml::OP_FRECIP, &drcbe_x86::op_frecip }, // FRECIP dst,src1 case uml::OP_FRECIP: op_frecip(a, inst); break; // FRECIP dst,src1
{ uml::OP_FRSQRT, &drcbe_x86::op_frsqrt }, // FRSQRT dst,src1 case uml::OP_FRSQRT: op_frsqrt(a, inst); break; // FRSQRT dst,src1
{ uml::OP_FCOPYI, &drcbe_x86::op_fcopyi }, // FCOPYI dst,src case uml::OP_FCOPYI: op_fcopyi(a, inst); break; // FCOPYI dst,src
{ uml::OP_ICOPYF, &drcbe_x86::op_icopyf }, // ICOPYF dst,src case uml::OP_ICOPYF: op_icopyf(a, inst); break; // ICOPYF dst,src
default: throw emu_fatalerror("drcbe_x86(%s): unhandled opcode %u\n", m_device.tag(), inst.opcode());
}
}; };
@ -1091,10 +1081,6 @@ drcbe_x86::drcbe_x86(drcuml_state &drcuml, device_t &device, drc_cache &cache, u
m_memory_accessors[space].set(*m_space[space]); m_memory_accessors[space].set(*m_space[space]);
} }
// build the opcode table (static but it doesn't hurt to regenerate it)
for (auto & elem : s_opcode_table_source)
s_opcode_table[elem.opcode] = elem.func;
// create the log // create the log
if (device.machine().options().drc_log_native()) if (device.machine().options().drc_log_native())
{ {
@ -1401,7 +1387,6 @@ void drcbe_x86::generate(drcuml_block &block, const instruction *instlist, uint3
for (int inum = 0; inum < numinst; inum++) for (int inum = 0; inum < numinst; inum++)
{ {
const instruction &inst = instlist[inum]; const instruction &inst = instlist[inum];
assert(inst.opcode() < std::size(s_opcode_table));
// must remain in scope until output // must remain in scope until output
std::string dasm; std::string dasm;
@ -1424,7 +1409,7 @@ void drcbe_x86::generate(drcuml_block &block, const instruction *instlist, uint3
} }
// generate code // generate code
(this->*s_opcode_table[inst.opcode()])(a, inst); generate_one(a, inst);
} }
// catch falling off the end of a block // catch falling off the end of a block
@ -1571,7 +1556,8 @@ void drcbe_x86::emit_mov_p32_r32(Assembler &a, be_parameter const &param, Gp con
} }
void drcbe_x86::alu_op_param(Assembler &a, Inst::Id const opcode, Operand const &dst, be_parameter const &param, std::function<bool(Assembler &a, Operand const &dst, be_parameter const &src)> optimize) template <typename T>
void drcbe_x86::alu_op_param(Assembler &a, Inst::Id const opcode, Operand const &dst, be_parameter const &param, T &&optimize)
{ {
if (param.is_immediate()) if (param.is_immediate())
{ {
@ -1599,7 +1585,8 @@ void drcbe_x86::alu_op_param(Assembler &a, Inst::Id const opcode, Operand const
a.emit(opcode, dst, Gpd(param.ireg())); // op dst,param a.emit(opcode, dst, Gpd(param.ireg())); // op dst,param
} }
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) template <typename T>
void drcbe_x86::shift_op_param(Assembler &a, Inst::Id const opcode, size_t opsize, Operand const &dst, be_parameter const &param, T &&optimize, bool update_flags)
{ {
if (param.is_immediate()) if (param.is_immediate())
{ {

View File

@ -155,7 +155,6 @@ enum
// set C in adds/addsi/subs/sums // set C in adds/addsi/subs/sums
#define SETCARRYS 0 #define SETCARRYS 0
#define MISSIONCRAFT_FLAGS 1
/* Registers */ /* Registers */

View File

@ -1860,14 +1860,11 @@ void hyperstone_device::generate_movi(drcuml_block &block, compiler_state &compi
UML_LABEL(block, no_exception); UML_LABEL(block, no_exception);
} }
UML_AND(block, I2, I2, ~(Z_MASK | N_MASK)); UML_AND(block, I2, I2, ~(Z_MASK | N_MASK | V_MASK));
if (!src) if (!src)
UML_OR(block, I2, I2, Z_MASK); UML_OR(block, I2, I2, Z_MASK);
else if (src & 0x80000000) else if (src & 0x80000000)
UML_OR(block, I2, I2, N_MASK); UML_OR(block, I2, I2, N_MASK);
#if MISSIONCRAFT_FLAGS
UML_AND(block, I2, I2, ~V_MASK);
#endif
if (DstGlobal) if (DstGlobal)
{ {
@ -2640,7 +2637,6 @@ void hyperstone_device::generate_rol(drcuml_block &block, compiler_state &compil
UML_AND(block, I1, I0, 0x1f); UML_AND(block, I1, I0, 0x1f);
} }
#ifdef MISSIONCRAFT_FLAGS
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK | V_MASK)); UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK | V_MASK));
UML_SUB(block, I4, 32, I1); UML_SUB(block, I4, 32, I1);
@ -2648,23 +2644,17 @@ void hyperstone_device::generate_rol(drcuml_block &block, compiler_state &compil
UML_TEST(block, I1, 0xffffffff); UML_TEST(block, I1, 0xffffffff);
UML_MOVc(block, uml::COND_Z, I4, 0); UML_MOVc(block, uml::COND_Z, I4, 0);
UML_MOV(block, I5, I4); UML_MOV(block, I5, I4);
#else
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
#endif
UML_ROL(block, I0, I0, I1); UML_ROL(block, I0, I0, I1);
#ifdef MISSIONCRAFT_FLAGS
UML_MOVc(block, uml::COND_NS, I4, 0); UML_MOVc(block, uml::COND_NS, I4, 0);
#endif
generate_update_nz(block, compiler, uml::I2); generate_update_nz(block, compiler, uml::I2);
#ifdef MISSIONCRAFT_FLAGS
UML_AND(block, I1, I5, I0); UML_AND(block, I1, I5, I0);
UML_ROLINS(block, I2, I1, C_SHIFT, C_MASK);
UML_XOR(block, I4, I4, I1); UML_XOR(block, I4, I4, I1);
UML_MOV(block, I1, V_MASK); UML_MOV(block, I1, V_MASK);
UML_MOVc(block, uml::COND_Z, I1, 0); UML_MOVc(block, uml::COND_Z, I1, 0);
UML_OR(block, I2, I2, I1); UML_OR(block, I2, I2, I1);
#endif
UML_MOV(block, DRC_SR, I2); UML_MOV(block, DRC_SR, I2);

View File

@ -857,15 +857,13 @@ void hyperstone_device::hyperstone_movi()
} }
else else
{ {
SR &= ~(Z_MASK | N_MASK); // manual says V and C are undefined - assume V is cleared
// Mission Craft seems to expect this behaviour
SR &= ~(Z_MASK | N_MASK | V_MASK);
if (imm == 0) if (imm == 0)
SR |= Z_MASK; SR |= Z_MASK;
SR |= SIGN_TO_N(imm); SR |= SIGN_TO_N(imm);
#if MISSIONCRAFT_FLAGS
SR &= ~V_MASK; // or V undefined ?
#endif
if (DstGlobal) if (DstGlobal)
{ {
const uint32_t dst_code = DST_CODE + (h ? 16 : 0); const uint32_t dst_code = DST_CODE + (h ? 16 : 0);
@ -1447,16 +1445,16 @@ void hyperstone_device::hyperstone_shl()
uint32_t src_code = SRC_CODE + fp; uint32_t src_code = SRC_CODE + fp;
uint32_t dst_code = DST_CODE + fp; uint32_t dst_code = DST_CODE + fp;
uint32_t n = m_core->local_regs[src_code & 0x3f] & 0x1f; const uint32_t n = m_core->local_regs[src_code & 0x3f] & 0x1f;
uint32_t base = m_core->local_regs[dst_code & 0x3f]; /* registers offset by frame pointer */ const uint32_t base = m_core->local_regs[dst_code & 0x3f];
uint32_t mask = n ? 0xffffffff << (32 - n) : 0; const uint32_t mask = n ? (0xffffffff << (32 - n)) : 0;
SR &= ~(C_MASK | V_MASK | Z_MASK | N_MASK); SR &= ~(C_MASK | V_MASK | Z_MASK | N_MASK);
SR |= (n)?(((base<<(n-1))&0x80000000)?1:0):0; SR |= (n && ((base << (n - 1)) & 0x80000000)) ? C_MASK : 0;
uint32_t ret = base << n; const uint32_t ret = base << n;
if (((base & mask) && (!(ret & 0x80000000))) || (((base & mask) ^ mask) && (ret & 0x80000000))) if (!(ret & 0x80000000) ? (base & mask) : ((base & mask) ^ mask))
SR |= V_MASK; SR |= V_MASK;
if (ret == 0) if (ret == 0)
@ -1483,32 +1481,28 @@ void hyperstone_device::hyperstone_testlz()
void hyperstone_device::hyperstone_rol() void hyperstone_device::hyperstone_rol()
{ {
// manual says V and C are undefined - assume they work like SHL
// Mission Craft seems to at least expect the V flag to work like this
check_delay_pc(); check_delay_pc();
const uint32_t fp = GET_FP; const uint32_t fp = GET_FP;
const uint32_t dst_code = (DST_CODE + fp) & 0x3f; const uint32_t dst_code = (DST_CODE + fp) & 0x3f;
uint32_t n = m_core->local_regs[(SRC_CODE + fp) & 0x3f] & 0x1f; const uint32_t n = m_core->local_regs[(SRC_CODE + fp) & 0x3f] & 0x1f;
uint32_t val = m_core->local_regs[dst_code]; const uint32_t mask = n ? (~uint32_t(0) >> (32 - n)) : 0;
#ifdef MISSIONCRAFT_FLAGS uint32_t val = m_core->local_regs[dst_code];
const uint32_t base = val;
const uint32_t mask = (uint32_t)(0xffffffff00000000ULL >> n);
#endif
val = rotl_32(val, n); val = rotl_32(val, n);
#ifdef MISSIONCRAFT_FLAGS
SR &= ~(V_MASK | Z_MASK | C_MASK | N_MASK); SR &= ~(V_MASK | Z_MASK | C_MASK | N_MASK);
if (((base & mask) && (!(val & 0x80000000))) || (((base & mask) ^ mask) && (val & 0x80000000))) if (!(val & 0x80000000) ? (val & mask) : ((val & mask) ^ mask))
SR |= V_MASK; SR |= V_MASK;
#else
SR &= ~(Z_MASK | C_MASK | N_MASK);
#endif
if (val == 0) if (val == 0)
SR |= Z_MASK; SR |= Z_MASK;
SR |= SIGN_TO_N(val); SR |= SIGN_TO_N(val);
if (n && (val & 1))
SR |= C_MASK;
m_core->local_regs[dst_code] = val; m_core->local_regs[dst_code] = val;
@ -2097,30 +2091,27 @@ void hyperstone_device::hyperstone_shli()
check_delay_pc(); check_delay_pc();
const uint32_t dst_code = DstGlobal ? DST_CODE : ((DST_CODE + GET_FP) & 0x3f); const uint32_t dst_code = DstGlobal ? DST_CODE : ((DST_CODE + GET_FP) & 0x3f);
uint32_t val = (DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code];
const uint32_t n = HiN ? HI_N_VALUE : LO_N_VALUE; const uint32_t n = HiN ? HI_N_VALUE : LO_N_VALUE;
const uint32_t base = (DstGlobal ? m_core->global_regs : m_core->local_regs)[dst_code];
const uint32_t mask = n ? (0xffffffff << (32 - n)) : 0;
SR &= ~(C_MASK | V_MASK | Z_MASK | N_MASK); SR &= ~(C_MASK | V_MASK | Z_MASK | N_MASK);
if (HiN || n) SR |= (n && ((base << (n - 1)) & 0x80000000)) ? C_MASK : 0;
{ const uint32_t ret = base << n;
SR |= (val & (0x80000000 >> (n - 1))) ? 1 : 0;
}
uint32_t mask = n ? 0xffffffff << (32 - n) : 0; if (!(ret & 0x80000000) ? (base & mask) : ((base & mask) ^ mask))
uint32_t val2 = val << n;
if (((val & mask) && (!(val2 & 0x80000000))) || (((val & mask) ^ mask) && (val2 & 0x80000000)))
SR |= V_MASK; SR |= V_MASK;
if (val2 == 0) if (ret == 0)
SR |= Z_MASK; SR |= Z_MASK;
SR |= SIGN_TO_N(val2); SR |= SIGN_TO_N(ret);
if (DstGlobal) if (DstGlobal)
set_global_register(dst_code, val2); set_global_register(dst_code, ret);
else else
m_core->local_regs[dst_code] = val2; m_core->local_regs[dst_code] = ret;
m_core->icount -= m_core->clock_cycles_1; m_core->icount -= m_core->clock_cycles_1;
} }