-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_cold_register() const { return m_coldreg; }
asmjit::a64::Vec get_register_float(uint32_t regsize) const;
asmjit::a64::Gp get_register_int(uint32_t regsize) const;
asmjit::a64::Vec select_register(asmjit::a64::Vec const &reg, uint32_t regsize) const;
asmjit::a64::Gp select_register(asmjit::a64::Gp const &reg, uint32_t regsize) const;
a64::Vec get_register_float(uint32_t regsize) const;
a64::Gp get_register_int(uint32_t regsize) const;
a64::Vec select_register(a64::Vec const &reg, uint32_t regsize) const;
a64::Gp select_register(a64::Gp const &reg, uint32_t regsize) const;
private:
static inline constexpr int REG_MAX = 30;
@ -481,13 +481,6 @@ private:
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
{
resolved_memory_accessors resolved;
@ -501,128 +494,130 @@ private:
using arm64_entry_point_func = uint32_t (*)(void *entry);
void op_handle(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_hash(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_label(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_comment(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_mapvar(asmjit::a64::Assembler &a, const uml::instruction &inst);
void generate_one(a64::Assembler &a, const uml::instruction &inst);
void op_nop(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_break(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_debug(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_exit(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_hashjmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_jmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_exh(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_callh(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_ret(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_callc(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_recover(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_handle(a64::Assembler &a, const uml::instruction &inst);
void op_hash(a64::Assembler &a, const uml::instruction &inst);
void op_label(a64::Assembler &a, const uml::instruction &inst);
void op_comment(a64::Assembler &a, const uml::instruction &inst);
void op_mapvar(a64::Assembler &a, const uml::instruction &inst);
void op_setfmod(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_getfmod(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_getexp(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_getflgs(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_setflgs(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_save(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_restore(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_nop(a64::Assembler &a, const uml::instruction &inst);
void op_break(a64::Assembler &a, const uml::instruction &inst);
void op_debug(a64::Assembler &a, const uml::instruction &inst);
void op_exit(a64::Assembler &a, const uml::instruction &inst);
void op_hashjmp(a64::Assembler &a, const uml::instruction &inst);
void op_jmp(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_loads(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_store(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_read(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_readm(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_write(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_writem(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_carry(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_set(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_mov(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_sext(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_roland(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_rolins(asmjit::a64::Assembler &a, const uml::instruction &inst);
template <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_setfmod(a64::Assembler &a, const uml::instruction &inst);
void op_getfmod(a64::Assembler &a, const uml::instruction &inst);
void op_getexp(a64::Assembler &a, const uml::instruction &inst);
void op_getflgs(a64::Assembler &a, const uml::instruction &inst);
void op_setflgs(a64::Assembler &a, const uml::instruction &inst);
void op_save(a64::Assembler &a, const uml::instruction &inst);
void op_restore(a64::Assembler &a, const uml::instruction &inst);
void op_fload(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_fstore(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_fread(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_fwrite(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_fmov(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_ftoint(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_ffrint(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_ffrflt(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_frnds(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_fcmp(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_fcopyi(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_icopyf(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_load(a64::Assembler &a, const uml::instruction &inst);
void op_loads(a64::Assembler &a, const uml::instruction &inst);
void op_store(a64::Assembler &a, const uml::instruction &inst);
void op_read(a64::Assembler &a, const uml::instruction &inst);
void op_readm(a64::Assembler &a, const uml::instruction &inst);
void op_write(a64::Assembler &a, const uml::instruction &inst);
void op_writem(a64::Assembler &a, const uml::instruction &inst);
void op_carry(a64::Assembler &a, const uml::instruction &inst);
void op_set(a64::Assembler &a, const uml::instruction &inst);
void op_mov(a64::Assembler &a, const uml::instruction &inst);
void op_sext(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);
template <asmjit::a64::Inst::Id Opcode> void op_float_alu2(asmjit::a64::Assembler &a, const uml::instruction &inst);
void op_fload(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
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_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
void emit_ldrb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
void emit_ldrh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
void emit_ldrsb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
void emit_ldrsh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
void emit_ldrsw_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
void emit_str_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
void emit_strb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
void emit_strh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const void *ptr) const;
void emit_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(a64::Assembler &a, const 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(a64::Assembler &a, const 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(a64::Assembler &a, const 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(a64::Assembler &a, const 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(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_str_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(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_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_narrow_memwrite(asmjit::a64::Assembler &a, const be_parameter &addrp, const parameter &spacesizep, const memory_accessors &accessors) 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(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 load_carry(asmjit::a64::Assembler &a, bool inverted = false);
void set_flags(asmjit::a64::Assembler &a);
void store_carry(a64::Assembler &a, bool inverted = false);
void load_carry(a64::Assembler &a, bool inverted = false);
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_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const int 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(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_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp &reg, const int shift);
void calculate_carry_shift_right(a64::Assembler &a, const a64::Gp &reg, const a64::Gp &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_param_param(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, const be_parameter &src) const;
void mov_float_param_reg(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, asmjit::a64::Vec const &src) const;
void mov_float_param_int_reg(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, asmjit::a64::Gp const &src) const;
void mov_float_reg_param(a64::Assembler &a, uint32_t regsize, a64::Vec const &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(a64::Assembler &a, uint32_t regsize, const be_parameter &dst, a64::Vec 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_param_reg(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, const asmjit::a64::Gp &src) const;
void mov_param_imm(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, uint64_t src) const;
void mov_param_param(asmjit::a64::Assembler &a, uint32_t regsize, const be_parameter &dst, const be_parameter &src) const;
void mov_mem_param(asmjit::a64::Assembler &a, uint32_t regsize, void *dst, const be_parameter &src) const;
void mov_reg_param(a64::Assembler &a, uint32_t regsize, const a64::Gp &dst, const be_parameter &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(a64::Assembler &a, uint32_t regsize, const be_parameter &dst, uint64_t 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(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;
@ -643,107 +638,107 @@ private:
resolved_member_function m_debug_cpu_instruction_hook;
resolved_member_function m_drcmap_get_value;
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];
const drcbe_arm64::opcode_table_entry drcbe_arm64::s_opcode_table_source[] =
inline void drcbe_arm64::generate_one(a64::Assembler &a, const uml::instruction &inst)
{
switch (inst.opcode())
{
// Compile-time opcodes
{ uml::OP_HANDLE, &drcbe_arm64::op_handle }, // HANDLE handle
{ uml::OP_HASH, &drcbe_arm64::op_hash }, // HASH mode,pc
{ uml::OP_LABEL, &drcbe_arm64::op_label }, // LABEL imm
{ uml::OP_COMMENT, &drcbe_arm64::op_comment }, // COMMENT string
{ uml::OP_MAPVAR, &drcbe_arm64::op_mapvar }, // MAPVAR mapvar,value
case uml::OP_HANDLE: op_handle(a, inst); break; // HANDLE handle
case uml::OP_HASH: op_hash(a, inst); break; // HASH mode,pc
case uml::OP_LABEL: op_label(a, inst); break; // LABEL imm
case uml::OP_COMMENT: op_comment(a, inst); break; // COMMENT string
case uml::OP_MAPVAR: op_mapvar(a, inst); break; // MAPVAR mapvar,value
// Control Flow Operations
{ uml::OP_NOP, &drcbe_arm64::op_nop }, // NOP
{ uml::OP_BREAK, &drcbe_arm64::op_break }, // BREAK
{ uml::OP_DEBUG, &drcbe_arm64::op_debug }, // DEBUG pc
{ uml::OP_EXIT, &drcbe_arm64::op_exit }, // EXIT src1[,c]
{ uml::OP_HASHJMP, &drcbe_arm64::op_hashjmp }, // HASHJMP mode,pc,handle
{ uml::OP_JMP, &drcbe_arm64::op_jmp }, // JMP imm[,c]
{ uml::OP_EXH, &drcbe_arm64::op_exh }, // EXH handle,param[,c]
{ uml::OP_CALLH, &drcbe_arm64::op_callh }, // CALLH handle[,c]
{ uml::OP_RET, &drcbe_arm64::op_ret }, // RET [c]
{ uml::OP_CALLC, &drcbe_arm64::op_callc }, // CALLC func,ptr[,c]
{ uml::OP_RECOVER, &drcbe_arm64::op_recover }, // RECOVER dst,mapvar
case uml::OP_NOP: op_nop(a, inst); break; // NOP
case uml::OP_BREAK: op_break(a, inst); break; // BREAK
case uml::OP_DEBUG: op_debug(a, inst); break; // DEBUG pc
case uml::OP_EXIT: op_exit(a, inst); break; // EXIT src1[,c]
case uml::OP_HASHJMP: op_hashjmp(a, inst); break; // HASHJMP mode,pc,handle
case uml::OP_JMP: op_jmp(a, inst); break; // JMP imm[,c]
case uml::OP_EXH: op_exh(a, inst); break; // EXH handle,param[,c]
case uml::OP_CALLH: op_callh(a, inst); break; // CALLH handle[,c]
case uml::OP_RET: op_ret(a, inst); break; // RET [c]
case uml::OP_CALLC: op_callc(a, inst); break; // CALLC func,ptr[,c]
case uml::OP_RECOVER: op_recover(a, inst); break; // RECOVER dst,mapvar
// Internal Register Operations
{ uml::OP_SETFMOD, &drcbe_arm64::op_setfmod }, // SETFMOD src
{ uml::OP_GETFMOD, &drcbe_arm64::op_getfmod }, // GETFMOD dst
{ uml::OP_GETEXP, &drcbe_arm64::op_getexp }, // GETEXP dst
{ uml::OP_GETFLGS, &drcbe_arm64::op_getflgs }, // GETFLGS dst[,f]
{ uml::OP_SETFLGS, &drcbe_arm64::op_setflgs }, // SETFLGS dst[,f]
{ uml::OP_SAVE, &drcbe_arm64::op_save }, // SAVE dst
{ uml::OP_RESTORE, &drcbe_arm64::op_restore }, // RESTORE dst
case uml::OP_SETFMOD: op_setfmod(a, inst); break; // SETFMOD src
case uml::OP_GETFMOD: op_getfmod(a, inst); break; // GETFMOD dst
case uml::OP_GETEXP: op_getexp(a, inst); break; // GETEXP dst
case uml::OP_GETFLGS: op_getflgs(a, inst); break; // GETFLGS dst[,f]
case uml::OP_SETFLGS: op_setflgs(a, inst); break; // SETFLGS dst[,f]
case uml::OP_SAVE: op_save(a, inst); break; // SAVE dst
case uml::OP_RESTORE: op_restore(a, inst); break; // RESTORE dst
// Integer Operations
{ uml::OP_LOAD, &drcbe_arm64::op_load }, // LOAD dst,base,index,size
{ uml::OP_LOADS, &drcbe_arm64::op_loads }, // LOADS dst,base,index,size
{ uml::OP_STORE, &drcbe_arm64::op_store }, // STORE base,index,src,size
{ uml::OP_READ, &drcbe_arm64::op_read }, // READ dst,src1,spacesize
{ uml::OP_READM, &drcbe_arm64::op_readm }, // READM dst,src1,mask,spacesize
{ uml::OP_WRITE, &drcbe_arm64::op_write }, // WRITE dst,src1,spacesize
{ uml::OP_WRITEM, &drcbe_arm64::op_writem }, // WRITEM dst,src1,spacesize
{ uml::OP_CARRY, &drcbe_arm64::op_carry }, // CARRY src,bitnum
{ uml::OP_SET, &drcbe_arm64::op_set }, // SET dst,c
{ uml::OP_MOV, &drcbe_arm64::op_mov }, // MOV dst,src[,c]
{ uml::OP_SEXT, &drcbe_arm64::op_sext }, // SEXT dst,src
{ uml::OP_ROLAND, &drcbe_arm64::op_roland }, // ROLAND dst,src1,src2,src3
{ uml::OP_ROLINS, &drcbe_arm64::op_rolins }, // ROLINS dst,src1,src2,src3
{ uml::OP_ADD, &drcbe_arm64::op_add<false> }, // ADD dst,src1,src2[,f]
{ uml::OP_ADDC, &drcbe_arm64::op_add<true> }, // ADDC dst,src1,src2[,f]
{ uml::OP_SUB, &drcbe_arm64::op_sub<false> }, // SUB dst,src1,src2[,f]
{ uml::OP_SUBB, &drcbe_arm64::op_sub<true> }, // SUBB dst,src1,src2[,f]
{ uml::OP_CMP, &drcbe_arm64::op_cmp }, // CMP src1,src2[,f]
{ uml::OP_MULU, &drcbe_arm64::op_mulu }, // MULU dst,edst,src1,src2[,f]
{ uml::OP_MULULW, &drcbe_arm64::op_mululw }, // MULULW dst,src1,src2[,f]
{ uml::OP_MULS, &drcbe_arm64::op_muls }, // MULS dst,edst,src1,src2[,f]
{ uml::OP_MULSLW, &drcbe_arm64::op_mulslw }, // MULSLW dst,src1,src2[,f]
{ uml::OP_DIVU, &drcbe_arm64::op_div<a64::Inst::kIdUdiv> }, // DIVU dst,edst,src1,src2[,f]
{ uml::OP_DIVS, &drcbe_arm64::op_div<a64::Inst::kIdSdiv> }, // DIVS dst,edst,src1,src2[,f]
{ uml::OP_AND, &drcbe_arm64::op_and }, // AND dst,src1,src2[,f]
{ uml::OP_TEST, &drcbe_arm64::op_test }, // TEST src1,src2[,f]
{ uml::OP_OR, &drcbe_arm64::op_or }, // OR dst,src1,src2[,f]
{ uml::OP_XOR, &drcbe_arm64::op_xor }, // XOR dst,src1,src2[,f]
{ uml::OP_LZCNT, &drcbe_arm64::op_lzcnt }, // LZCNT dst,src[,f]
{ uml::OP_TZCNT, &drcbe_arm64::op_tzcnt }, // TZCNT dst,src[,f]
{ uml::OP_BSWAP, &drcbe_arm64::op_bswap }, // BSWAP dst,src
{ uml::OP_SHL, &drcbe_arm64::op_shift<a64::Inst::kIdLsl> }, // SHL dst,src,count[,f]
{ uml::OP_SHR, &drcbe_arm64::op_shift<a64::Inst::kIdLsr> }, // SHR dst,src,count[,f]
{ uml::OP_SAR, &drcbe_arm64::op_shift<a64::Inst::kIdAsr> }, // SAR dst,src,count[,f]
{ uml::OP_ROL, &drcbe_arm64::op_rol }, // ROL dst,src,count[,f]
{ uml::OP_ROLC, &drcbe_arm64::op_rolc }, // ROLC dst,src,count[,f]
{ uml::OP_ROR, &drcbe_arm64::op_shift<a64::Inst::kIdRor> }, // ROR dst,src,count[,f]
{ uml::OP_RORC, &drcbe_arm64::op_rorc }, // RORC dst,src,count[,f]
case uml::OP_LOAD: op_load(a, inst); break; // LOAD dst,base,index,size
case uml::OP_LOADS: op_loads(a, inst); break; // LOADS dst,base,index,size
case uml::OP_STORE: op_store(a, inst); break; // STORE base,index,src,size
case uml::OP_READ: op_read(a, inst); break; // READ dst,src1,spacesize
case uml::OP_READM: op_readm(a, inst); break; // READM dst,src1,mask,spacesize
case uml::OP_WRITE: op_write(a, inst); break; // WRITE dst,src1,spacesize
case uml::OP_WRITEM: op_writem(a, inst); break; // WRITEM dst,src1,spacesize
case uml::OP_CARRY: op_carry(a, inst); break; // CARRY src,bitnum
case uml::OP_SET: op_set(a, inst); break; // SET dst,c
case uml::OP_MOV: op_mov(a, inst); break; // MOV dst,src[,c]
case uml::OP_SEXT: op_sext(a, inst); break; // SEXT dst,src
case uml::OP_ROLAND: op_roland(a, inst); break; // ROLAND dst,src1,src2,src3
case uml::OP_ROLINS: op_rolins(a, inst); break; // ROLINS dst,src1,src2,src3
case uml::OP_ADD: op_add<false>(a, inst); break; // ADD dst,src1,src2[,f]
case uml::OP_ADDC: op_add<true>(a, inst); break; // ADDC dst,src1,src2[,f]
case uml::OP_SUB: op_sub<false>(a, inst); break; // SUB dst,src1,src2[,f]
case uml::OP_SUBB: op_sub<true>(a, inst); break; // SUBB dst,src1,src2[,f]
case uml::OP_CMP: op_cmp(a, inst); break; // CMP src1,src2[,f]
case uml::OP_MULU: op_mulu(a, inst); break; // MULU dst,edst,src1,src2[,f]
case uml::OP_MULULW: op_mululw(a, inst); break; // MULULW dst,src1,src2[,f]
case uml::OP_MULS: op_muls(a, inst); break; // MULS dst,edst,src1,src2[,f]
case uml::OP_MULSLW: op_mulslw(a, inst); break; // MULSLW dst,src1,src2[,f]
case uml::OP_DIVU: op_div<a64::Inst::kIdUdiv>(a, inst); break; // DIVU dst,edst,src1,src2[,f]
case uml::OP_DIVS: op_div<a64::Inst::kIdSdiv>(a, inst); break; // DIVS dst,edst,src1,src2[,f]
case uml::OP_AND: op_and(a, inst); break; // AND dst,src1,src2[,f]
case uml::OP_TEST: op_test(a, inst); break; // TEST src1,src2[,f]
case uml::OP_OR: op_or(a, inst); break; // OR dst,src1,src2[,f]
case uml::OP_XOR: op_xor(a, inst); break; // XOR dst,src1,src2[,f]
case uml::OP_LZCNT: op_lzcnt(a, inst); break; // LZCNT dst,src[,f]
case uml::OP_TZCNT: op_tzcnt(a, inst); break; // TZCNT dst,src[,f]
case uml::OP_BSWAP: op_bswap(a, inst); break; // BSWAP dst,src
case uml::OP_SHL: op_shift<a64::Inst::kIdLsl>(a, inst); break; // SHL dst,src,count[,f]
case uml::OP_SHR: op_shift<a64::Inst::kIdLsr>(a, inst); break; // SHR dst,src,count[,f]
case uml::OP_SAR: op_shift<a64::Inst::kIdAsr>(a, inst); break; // SAR dst,src,count[,f]
case uml::OP_ROL: op_rol(a, inst); break; // ROL dst,src,count[,f]
case uml::OP_ROLC: op_rolc(a, inst); break; // ROLC dst,src,count[,f]
case uml::OP_ROR: op_shift<a64::Inst::kIdRor>(a, inst); break; // ROR dst,src,count[,f]
case uml::OP_RORC: op_rorc(a, inst); break; // RORC dst,src,count[,f]
// Floating Point Operations
{ uml::OP_FLOAD, &drcbe_arm64::op_fload }, // FLOAD dst,base,index
{ uml::OP_FSTORE, &drcbe_arm64::op_fstore }, // FSTORE base,index,src
{ uml::OP_FREAD, &drcbe_arm64::op_fread }, // FREAD dst,space,src1
{ uml::OP_FWRITE, &drcbe_arm64::op_fwrite }, // FWRITE space,dst,src1
{ uml::OP_FMOV, &drcbe_arm64::op_fmov }, // FMOV dst,src1[,c]
{ uml::OP_FTOINT, &drcbe_arm64::op_ftoint }, // FTOINT dst,src1,size,round
{ uml::OP_FFRINT, &drcbe_arm64::op_ffrint }, // FFRINT dst,src1,size
{ uml::OP_FFRFLT, &drcbe_arm64::op_ffrflt }, // FFRFLT dst,src1,size
{ uml::OP_FRNDS, &drcbe_arm64::op_frnds }, // FRNDS dst,src1
{ uml::OP_FADD, &drcbe_arm64::op_float_alu<a64::Inst::kIdFadd_v> }, // FADD dst,src1,src2
{ uml::OP_FSUB, &drcbe_arm64::op_float_alu<a64::Inst::kIdFsub_v> }, // FSUB dst,src1,src2
{ uml::OP_FCMP, &drcbe_arm64::op_fcmp }, // FCMP src1,src2
{ uml::OP_FMUL, &drcbe_arm64::op_float_alu<a64::Inst::kIdFmul_v> }, // FMUL dst,src1,src2
{ uml::OP_FDIV, &drcbe_arm64::op_float_alu<a64::Inst::kIdFdiv_v> }, // FDIV dst,src1,src2
{ uml::OP_FNEG, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFneg_v> }, // FNEG dst,src1
{ uml::OP_FABS, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFabs_v> }, // FABS dst,src1
{ uml::OP_FSQRT, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFsqrt_v> }, // FSQRT dst,src1
{ uml::OP_FRECIP, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFrecpe_v> }, // FRECIP dst,src1
{ uml::OP_FRSQRT, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFrsqrte_v> }, // FRSQRT dst,src1
{ uml::OP_FCOPYI, &drcbe_arm64::op_fcopyi }, // FCOPYI dst,src
{ uml::OP_ICOPYF, &drcbe_arm64::op_icopyf } // ICOPYF dst,src
case uml::OP_FLOAD: op_fload(a, inst); break; // FLOAD dst,base,index
case uml::OP_FSTORE: op_fstore(a, inst); break; // FSTORE base,index,src
case uml::OP_FREAD: op_fread(a, inst); break; // FREAD dst,space,src1
case uml::OP_FWRITE: op_fwrite(a, inst); break; // FWRITE space,dst,src1
case uml::OP_FMOV: op_fmov(a, inst); break; // FMOV dst,src1[,c]
case uml::OP_FTOINT: op_ftoint(a, inst); break; // FTOINT dst,src1,size,round
case uml::OP_FFRINT: op_ffrint(a, inst); break; // FFRINT dst,src1,size
case uml::OP_FFRFLT: op_ffrflt(a, inst); break; // FFRFLT dst,src1,size
case uml::OP_FRNDS: op_frnds(a, inst); break; // FRNDS dst,src1
case uml::OP_FADD: op_float_alu<a64::Inst::kIdFadd_v>(a, inst); break; // FADD dst,src1,src2
case uml::OP_FSUB: op_float_alu<a64::Inst::kIdFsub_v>(a, inst); break; // FSUB dst,src1,src2
case uml::OP_FCMP: op_fcmp(a, inst); break; // FCMP src1,src2
case uml::OP_FMUL: op_float_alu<a64::Inst::kIdFmul_v>(a, inst); break; // FMUL dst,src1,src2
case uml::OP_FDIV: op_float_alu<a64::Inst::kIdFdiv_v> (a, inst); break; // FDIV dst,src1,src2
case uml::OP_FNEG: op_float_alu2<a64::Inst::kIdFneg_v>(a, inst); break; // FNEG dst,src1
case uml::OP_FABS: op_float_alu2<a64::Inst::kIdFabs_v>(a, inst); break; // FABS dst,src1
case uml::OP_FSQRT: op_float_alu2<a64::Inst::kIdFsqrt_v>(a, inst); break; // FSQRT dst,src1
case uml::OP_FRECIP: op_float_alu2<a64::Inst::kIdFrecpe_v>(a, inst); break; // FRECIP dst,src1
case uml::OP_FRSQRT: op_float_alu2<a64::Inst::kIdFrsqrte_v>(a, inst); break; // FRSQRT dst,src1
case uml::OP_FCOPYI: op_fcopyi(a, inst); break; // FCOPYI 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)
@ -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;
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
}
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
@ -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
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;
// 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
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++)
{
const instruction &inst = instlist[inum];
assert(inst.opcode() < std::size(s_opcode_table));
// must remain in scope until output
std::string dasm;
@ -1683,7 +1673,7 @@ void drcbe_arm64::generate(drcuml_block &block, const instruction *instlist, uin
}
// generate code
(this->*s_opcode_table[inst.opcode()])(a, inst);
generate_one(a, inst);
}
// catch falling off the end of a block

View File

@ -16,8 +16,6 @@
* 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
(avoid initial move) if i0 is not needed going forward
@ -439,11 +437,11 @@ private:
bool is_cold_register() const { return m_coldreg; }
// helpers
asmjit::x86::Gp select_register(asmjit::x86::Gp defreg) const;
asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg) const;
asmjit::x86::Gp select_register(asmjit::x86::Gp defreg, be_parameter const &checkparam) const;
asmjit::x86::Gp select_register(asmjit::x86::Gp defreg, be_parameter const &checkparam, be_parameter const &checkparam2) const;
asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg, be_parameter const &checkparam) const;
Gp select_register(Gp defreg) const;
Xmm select_register(Xmm defreg) const;
Gp select_register(Gp defreg, be_parameter const &checkparam) const;
Gp select_register(Gp defreg, be_parameter const &checkparam, be_parameter const &checkparam2) const;
Xmm select_register(Xmm defreg, be_parameter const &checkparam) const;
private:
// HACK: leftover from x86emit
@ -487,138 +485,132 @@ private:
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
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; }
void normalize_commutative(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;
asmjit::x86::Gp get_base_register_and_offset(asmjit::x86::Assembler &a, void *target, asmjit::x86::Gp const &reg, int32_t &offset);
void smart_call_r64(asmjit::x86::Assembler &a, x86code *target, asmjit::x86::Gp const &reg) const;
void smart_call_m64(asmjit::x86::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;
Gp get_base_register_and_offset(Assembler &a, void *target, Gp const &reg, int32_t &offset);
void smart_call_r64(Assembler &a, x86code *target, Gp const &reg) const;
void smart_call_m64(Assembler &a, x86code **target) 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;
static void debug_log_hashjmp(offs_t pc, int mode);
static void debug_log_hashjmp_fail();
void generate_one(Assembler &a, const uml::instruction &inst);
// code generators
void op_handle(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_hash(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_label(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_comment(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mapvar(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_handle(Assembler &a, const uml::instruction &inst);
void op_hash(Assembler &a, const uml::instruction &inst);
void op_label(Assembler &a, const uml::instruction &inst);
void op_comment(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_break(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_debug(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_exit(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_hashjmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_jmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_exh(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_callh(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_ret(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_callc(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_recover(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_nop(Assembler &a, const uml::instruction &inst);
void op_break(Assembler &a, const uml::instruction &inst);
void op_debug(Assembler &a, const uml::instruction &inst);
void op_exit(Assembler &a, const uml::instruction &inst);
void op_hashjmp(Assembler &a, const uml::instruction &inst);
void op_jmp(Assembler &a, const uml::instruction &inst);
void op_exh(Assembler &a, const uml::instruction &inst);
void op_callh(Assembler &a, const uml::instruction &inst);
void op_ret(Assembler &a, const uml::instruction &inst);
void op_callc(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_getfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_getexp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_getflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_setflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_save(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_restore(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_setfmod(Assembler &a, const uml::instruction &inst);
void op_getfmod(Assembler &a, const uml::instruction &inst);
void op_getexp(Assembler &a, const uml::instruction &inst);
void op_getflgs(Assembler &a, const uml::instruction &inst);
void op_setflgs(Assembler &a, const uml::instruction &inst);
void op_save(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_loads(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_store(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_read(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_readm(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_write(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_writem(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_carry(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_set(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mov(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_sext(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_roland(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_rolins(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_add(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_addc(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_sub(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_subc(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_cmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mulu(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mululw(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_muls(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mulslw(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_divu(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_divs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_and(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_test(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_or(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_xor(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_lzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_tzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_bswap(asmjit::x86::Assembler &a, const uml::instruction &inst);
template <asmjit::x86::Inst::Id Opcode> void op_shift(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_load(Assembler &a, const uml::instruction &inst);
void op_loads(Assembler &a, const uml::instruction &inst);
void op_store(Assembler &a, const uml::instruction &inst);
void op_read(Assembler &a, const uml::instruction &inst);
void op_readm(Assembler &a, const uml::instruction &inst);
void op_write(Assembler &a, const uml::instruction &inst);
void op_writem(Assembler &a, const uml::instruction &inst);
void op_carry(Assembler &a, const uml::instruction &inst);
void op_set(Assembler &a, const uml::instruction &inst);
void op_mov(Assembler &a, const uml::instruction &inst);
void op_sext(Assembler &a, const uml::instruction &inst);
void op_roland(Assembler &a, const uml::instruction &inst);
void op_rolins(Assembler &a, const uml::instruction &inst);
void op_add(Assembler &a, const uml::instruction &inst);
void op_addc(Assembler &a, const uml::instruction &inst);
void op_sub(Assembler &a, const uml::instruction &inst);
void op_subc(Assembler &a, const uml::instruction &inst);
void op_cmp(Assembler &a, const uml::instruction &inst);
void op_mulu(Assembler &a, const uml::instruction &inst);
void op_mululw(Assembler &a, const uml::instruction &inst);
void op_muls(Assembler &a, const uml::instruction &inst);
void op_mulslw(Assembler &a, const uml::instruction &inst);
void op_divu(Assembler &a, const uml::instruction &inst);
void op_divs(Assembler &a, const uml::instruction &inst);
void op_and(Assembler &a, const uml::instruction &inst);
void op_test(Assembler &a, const uml::instruction &inst);
void op_or(Assembler &a, const uml::instruction &inst);
void op_xor(Assembler &a, const uml::instruction &inst);
void op_lzcnt(Assembler &a, const uml::instruction &inst);
void op_tzcnt(Assembler &a, const uml::instruction &inst);
void op_bswap(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_fstore(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fread(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fwrite(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fmov(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_ftoint(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_ffrint(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_ffrflt(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_frnds(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fadd(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fsub(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fcmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fmul(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fdiv(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fneg(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fabs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_frecip(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_frsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fcopyi(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_icopyf(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fload(Assembler &a, const uml::instruction &inst);
void op_fstore(Assembler &a, const uml::instruction &inst);
void op_fread(Assembler &a, const uml::instruction &inst);
void op_fwrite(Assembler &a, const uml::instruction &inst);
void op_fmov(Assembler &a, const uml::instruction &inst);
void op_ftoint(Assembler &a, const uml::instruction &inst);
void op_ffrint(Assembler &a, const uml::instruction &inst);
void op_ffrflt(Assembler &a, const uml::instruction &inst);
void op_frnds(Assembler &a, const uml::instruction &inst);
void op_fadd(Assembler &a, const uml::instruction &inst);
void op_fsub(Assembler &a, const uml::instruction &inst);
void op_fcmp(Assembler &a, const uml::instruction &inst);
void op_fmul(Assembler &a, const uml::instruction &inst);
void op_fdiv(Assembler &a, const uml::instruction &inst);
void op_fneg(Assembler &a, const uml::instruction &inst);
void op_fabs(Assembler &a, const uml::instruction &inst);
void op_fsqrt(Assembler &a, const uml::instruction &inst);
void op_frecip(Assembler &a, const uml::instruction &inst);
void op_frsqrt(Assembler &a, const uml::instruction &inst);
void op_fcopyi(Assembler &a, const uml::instruction &inst);
void op_icopyf(Assembler &a, const uml::instruction &inst);
// alu and shift operation helpers
static bool ones(u64 const value, unsigned const size) noexcept { return (size == 4) ? u32(value) == 0xffffffffU : value == 0xffffffff'ffffffffULL; }
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(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 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 alu_op_param(Assembler &a, Inst::Id const opcode, 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) { alu_op_param(a, opcode, dst, param, [] (Assembler &a, Operand const &dst, be_parameter const &src) { return false; }); }
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
void mov_reg_param(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param, bool const keepflags = false);
void mov_param_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reg);
void mov_mem_param(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref, be_parameter const &param);
void mov_reg_param(Assembler &a, Gp const &reg, be_parameter const &param, bool const keepflags = false);
void mov_param_reg(Assembler &a, be_parameter const &param, Gp const &reg);
void mov_mem_param(Assembler &a, Mem const &memref, be_parameter const &param);
// special-case move helpers
void movsx_r64_p32(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param);
void mov_r64_imm(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, uint64_t const imm) const;
void movsx_r64_p32(Assembler &a, Gp const &reg, be_parameter const &param);
void mov_r64_imm(Assembler &a, Gp const &reg, uint64_t const imm) const;
// floating-point helpers
void movss_r128_p32(asmjit::x86::Assembler &a, asmjit::x86::Xmm const &reg, be_parameter const &param);
void movss_p32_r128(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Xmm const &reg);
void movsd_r128_p64(asmjit::x86::Assembler &a, asmjit::x86::Xmm const &reg, be_parameter const &param);
void movsd_p64_r128(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Xmm const &reg);
void movss_r128_p32(Assembler &a, Xmm const &reg, be_parameter const &param);
void movss_p32_r128(Assembler &a, be_parameter const &param, Xmm const &reg);
void movsd_r128_p64(Assembler &a, Xmm const &reg, be_parameter const &param);
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_mul(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo, asmjit::x86::Gp const &hi);
void calculate_status_flags_mul_low(asmjit::x86::Assembler &a, uint32_t instsize, asmjit::x86::Gp const &lo);
void calculate_status_flags(Assembler &a, uint32_t instsize, Operand const &dst, u8 flags);
void calculate_status_flags_mul(Assembler &a, uint32_t instsize, Gp const &lo, Gp const &hi);
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
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_drcmap_get_value;
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
//**************************************************************************
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
{ uml::OP_HANDLE, &drcbe_x64::op_handle }, // HANDLE handle
{ uml::OP_HASH, &drcbe_x64::op_hash }, // HASH mode,pc
{ uml::OP_LABEL, &drcbe_x64::op_label }, // LABEL imm
{ uml::OP_COMMENT, &drcbe_x64::op_comment }, // COMMENT string
{ uml::OP_MAPVAR, &drcbe_x64::op_mapvar }, // MAPVAR mapvar,value
case uml::OP_HANDLE: op_handle(a, inst); break; // HANDLE handle
case uml::OP_HASH: op_hash(a, inst); break; // HASH mode,pc
case uml::OP_LABEL: op_label(a, inst); break; // LABEL imm
case uml::OP_COMMENT: op_comment(a, inst); break; // COMMENT string
case uml::OP_MAPVAR: op_mapvar(a, inst); break; // MAPVAR mapvar,value
// Control Flow Operations
{ uml::OP_NOP, &drcbe_x64::op_nop }, // NOP
{ uml::OP_BREAK, &drcbe_x64::op_break }, // BREAK
{ uml::OP_DEBUG, &drcbe_x64::op_debug }, // DEBUG pc
{ uml::OP_EXIT, &drcbe_x64::op_exit }, // EXIT src1[,c]
{ uml::OP_HASHJMP, &drcbe_x64::op_hashjmp }, // HASHJMP mode,pc,handle
{ uml::OP_JMP, &drcbe_x64::op_jmp }, // JMP imm[,c]
{ uml::OP_EXH, &drcbe_x64::op_exh }, // EXH handle,param[,c]
{ uml::OP_CALLH, &drcbe_x64::op_callh }, // CALLH handle[,c]
{ uml::OP_RET, &drcbe_x64::op_ret }, // RET [c]
{ uml::OP_CALLC, &drcbe_x64::op_callc }, // CALLC func,ptr[,c]
{ uml::OP_RECOVER, &drcbe_x64::op_recover }, // RECOVER dst,mapvar
case uml::OP_NOP: op_nop(a, inst); break; // NOP
case uml::OP_BREAK: op_break(a, inst); break; // BREAK
case uml::OP_DEBUG: op_debug(a, inst); break; // DEBUG pc
case uml::OP_EXIT: op_exit(a, inst); break; // EXIT src1[,c]
case uml::OP_HASHJMP: op_hashjmp(a, inst); break; // HASHJMP mode,pc,handle
case uml::OP_JMP: op_jmp(a, inst); break; // JMP imm[,c]
case uml::OP_EXH: op_exh(a, inst); break; // EXH handle,param[,c]
case uml::OP_CALLH: op_callh(a, inst); break; // CALLH handle[,c]
case uml::OP_RET: op_ret(a, inst); break; // RET [c]
case uml::OP_CALLC: op_callc(a, inst); break; // CALLC func,ptr[,c]
case uml::OP_RECOVER: op_recover(a, inst); break; // RECOVER dst,mapvar
// Internal Register Operations
{ uml::OP_SETFMOD, &drcbe_x64::op_setfmod }, // SETFMOD src
{ uml::OP_GETFMOD, &drcbe_x64::op_getfmod }, // GETFMOD dst
{ uml::OP_GETEXP, &drcbe_x64::op_getexp }, // GETEXP dst
{ uml::OP_GETFLGS, &drcbe_x64::op_getflgs }, // GETFLGS dst[,f]
{ uml::OP_SETFLGS, &drcbe_x64::op_setflgs }, // SETFLGS src
{ uml::OP_SAVE, &drcbe_x64::op_save }, // SAVE dst
{ uml::OP_RESTORE, &drcbe_x64::op_restore }, // RESTORE dst
case uml::OP_SETFMOD: op_setfmod(a, inst); break; // SETFMOD src
case uml::OP_GETFMOD: op_getfmod(a, inst); break; // GETFMOD dst
case uml::OP_GETEXP: op_getexp(a, inst); break; // GETEXP dst
case uml::OP_GETFLGS: op_getflgs(a, inst); break; // GETFLGS dst[,f]
case uml::OP_SETFLGS: op_setflgs(a, inst); break; // SETFLGS src
case uml::OP_SAVE: op_save(a, inst); break; // SAVE dst
case uml::OP_RESTORE: op_restore(a, inst); break; // RESTORE dst
// Integer Operations
{ uml::OP_LOAD, &drcbe_x64::op_load }, // LOAD dst,base,index,size
{ uml::OP_LOADS, &drcbe_x64::op_loads }, // LOADS dst,base,index,size
{ uml::OP_STORE, &drcbe_x64::op_store }, // STORE base,index,src,size
{ uml::OP_READ, &drcbe_x64::op_read }, // READ dst,src1,spacesize
{ uml::OP_READM, &drcbe_x64::op_readm }, // READM dst,src1,mask,spacesize
{ uml::OP_WRITE, &drcbe_x64::op_write }, // WRITE dst,src1,spacesize
{ uml::OP_WRITEM, &drcbe_x64::op_writem }, // WRITEM dst,src1,spacesize
{ uml::OP_CARRY, &drcbe_x64::op_carry }, // CARRY src,bitnum
{ uml::OP_SET, &drcbe_x64::op_set }, // SET dst,c
{ uml::OP_MOV, &drcbe_x64::op_mov }, // MOV dst,src[,c]
{ uml::OP_SEXT, &drcbe_x64::op_sext }, // SEXT dst,src
{ uml::OP_ROLAND, &drcbe_x64::op_roland }, // ROLAND dst,src1,src2,src3
{ uml::OP_ROLINS, &drcbe_x64::op_rolins }, // ROLINS dst,src1,src2,src3
{ uml::OP_ADD, &drcbe_x64::op_add }, // ADD dst,src1,src2[,f]
{ uml::OP_ADDC, &drcbe_x64::op_addc }, // ADDC dst,src1,src2[,f]
{ uml::OP_SUB, &drcbe_x64::op_sub }, // SUB dst,src1,src2[,f]
{ uml::OP_SUBB, &drcbe_x64::op_subc }, // SUBB dst,src1,src2[,f]
{ uml::OP_CMP, &drcbe_x64::op_cmp }, // CMP src1,src2[,f]
{ uml::OP_MULU, &drcbe_x64::op_mulu }, // MULU dst,edst,src1,src2[,f]
{ uml::OP_MULULW, &drcbe_x64::op_mululw }, // MULULW dst,src1,src2[,f]
{ uml::OP_MULS, &drcbe_x64::op_muls }, // MULS dst,edst,src1,src2[,f]
{ uml::OP_MULSLW, &drcbe_x64::op_mulslw }, // MULSLW dst,src1,src2[,f]
{ uml::OP_DIVU, &drcbe_x64::op_divu }, // DIVU dst,edst,src1,src2[,f]
{ uml::OP_DIVS, &drcbe_x64::op_divs }, // DIVS dst,edst,src1,src2[,f]
{ uml::OP_AND, &drcbe_x64::op_and }, // AND dst,src1,src2[,f]
{ uml::OP_TEST, &drcbe_x64::op_test }, // TEST src1,src2[,f]
{ uml::OP_OR, &drcbe_x64::op_or }, // OR dst,src1,src2[,f]
{ uml::OP_XOR, &drcbe_x64::op_xor }, // XOR dst,src1,src2[,f]
{ uml::OP_LZCNT, &drcbe_x64::op_lzcnt }, // LZCNT dst,src[,f]
{ uml::OP_TZCNT, &drcbe_x64::op_tzcnt }, // TZCNT dst,src[,f]
{ uml::OP_BSWAP, &drcbe_x64::op_bswap }, // BSWAP dst,src
{ uml::OP_SHL, &drcbe_x64::op_shift<Inst::kIdShl> }, // SHL dst,src,count[,f]
{ uml::OP_SHR, &drcbe_x64::op_shift<Inst::kIdShr> }, // SHR dst,src,count[,f]
{ uml::OP_SAR, &drcbe_x64::op_shift<Inst::kIdSar> }, // SAR dst,src,count[,f]
{ uml::OP_ROL, &drcbe_x64::op_shift<Inst::kIdRol> }, // ROL dst,src,count[,f]
{ uml::OP_ROLC, &drcbe_x64::op_shift<Inst::kIdRcl> }, // ROLC dst,src,count[,f]
{ uml::OP_ROR, &drcbe_x64::op_shift<Inst::kIdRor> }, // ROR dst,src,count[,f]
{ uml::OP_RORC, &drcbe_x64::op_shift<Inst::kIdRcr> }, // RORC dst,src,count[,f]
case uml::OP_LOAD: op_load(a, inst); break; // LOAD dst,base,index,size
case uml::OP_LOADS: op_loads(a, inst); break; // LOADS dst,base,index,size
case uml::OP_STORE: op_store(a, inst); break; // STORE base,index,src,size
case uml::OP_READ: op_read(a, inst); break; // READ dst,src1,spacesize
case uml::OP_READM: op_readm(a, inst); break; // READM dst,src1,mask,spacesize
case uml::OP_WRITE: op_write(a, inst); break; // WRITE dst,src1,spacesize
case uml::OP_WRITEM: op_writem(a, inst); break; // WRITEM dst,src1,spacesize
case uml::OP_CARRY: op_carry(a, inst); break; // CARRY src,bitnum
case uml::OP_SET: op_set(a, inst); break; // SET dst,c
case uml::OP_MOV: op_mov(a, inst); break; // MOV dst,src[,c]
case uml::OP_SEXT: op_sext(a, inst); break; // SEXT dst,src
case uml::OP_ROLAND: op_roland(a, inst); break; // ROLAND dst,src1,src2,src3
case uml::OP_ROLINS: op_rolins(a, inst); break; // ROLINS dst,src1,src2,src3
case uml::OP_ADD: op_add(a, inst); break; // ADD dst,src1,src2[,f]
case uml::OP_ADDC: op_addc(a, inst); break; // ADDC dst,src1,src2[,f]
case uml::OP_SUB: op_sub(a, inst); break; // SUB dst,src1,src2[,f]
case uml::OP_SUBB: op_subc(a, inst); break; // SUBB dst,src1,src2[,f]
case uml::OP_CMP: op_cmp(a, inst); break; // CMP src1,src2[,f]
case uml::OP_MULU: op_mulu(a, inst); break; // MULU dst,edst,src1,src2[,f]
case uml::OP_MULULW: op_mululw(a, inst); break; // MULULW dst,src1,src2[,f]
case uml::OP_MULS: op_muls(a, inst); break; // MULS dst,edst,src1,src2[,f]
case uml::OP_MULSLW: op_mulslw(a, inst); break; // MULSLW dst,src1,src2[,f]
case uml::OP_DIVU: op_divu(a, inst); break; // DIVU dst,edst,src1,src2[,f]
case uml::OP_DIVS: op_divs(a, inst); break; // DIVS dst,edst,src1,src2[,f]
case uml::OP_AND: op_and(a, inst); break; // AND dst,src1,src2[,f]
case uml::OP_TEST: op_test(a, inst); break; // TEST src1,src2[,f]
case uml::OP_OR: op_or(a, inst); break; // OR dst,src1,src2[,f]
case uml::OP_XOR: op_xor(a, inst); break; // XOR dst,src1,src2[,f]
case uml::OP_LZCNT: op_lzcnt(a, inst); break; // LZCNT dst,src[,f]
case uml::OP_TZCNT: op_tzcnt(a, inst); break; // TZCNT dst,src[,f]
case uml::OP_BSWAP: op_bswap(a, inst); break; // BSWAP dst,src
case uml::OP_SHL: op_shift<Inst::kIdShl>(a, inst); break; // SHL dst,src,count[,f]
case uml::OP_SHR: op_shift<Inst::kIdShr>(a, inst); break; // SHR dst,src,count[,f]
case uml::OP_SAR: op_shift<Inst::kIdSar>(a, inst); break; // SAR dst,src,count[,f]
case uml::OP_ROL: op_shift<Inst::kIdRol>(a, inst); break; // ROL dst,src,count[,f]
case uml::OP_ROLC: op_shift<Inst::kIdRcl>(a, inst); break; // ROLC dst,src,count[,f]
case uml::OP_ROR: op_shift<Inst::kIdRor>(a, inst); break; // ROR dst,src,count[,f]
case uml::OP_RORC: op_shift<Inst::kIdRcr>(a, inst); break; // RORC dst,src,count[,f]
// Floating Point Operations
{ uml::OP_FLOAD, &drcbe_x64::op_fload }, // FLOAD dst,base,index
{ uml::OP_FSTORE, &drcbe_x64::op_fstore }, // FSTORE base,index,src
{ uml::OP_FREAD, &drcbe_x64::op_fread }, // FREAD dst,space,src1
{ uml::OP_FWRITE, &drcbe_x64::op_fwrite }, // FWRITE space,dst,src1
{ uml::OP_FMOV, &drcbe_x64::op_fmov }, // FMOV dst,src1[,c]
{ uml::OP_FTOINT, &drcbe_x64::op_ftoint }, // FTOINT dst,src1,size,round
{ uml::OP_FFRINT, &drcbe_x64::op_ffrint }, // FFRINT dst,src1,size
{ uml::OP_FFRFLT, &drcbe_x64::op_ffrflt }, // FFRFLT dst,src1,size
{ uml::OP_FRNDS, &drcbe_x64::op_frnds }, // FRNDS dst,src1
{ uml::OP_FADD, &drcbe_x64::op_fadd }, // FADD dst,src1,src2
{ uml::OP_FSUB, &drcbe_x64::op_fsub }, // FSUB dst,src1,src2
{ uml::OP_FCMP, &drcbe_x64::op_fcmp }, // FCMP src1,src2
{ uml::OP_FMUL, &drcbe_x64::op_fmul }, // FMUL dst,src1,src2
{ uml::OP_FDIV, &drcbe_x64::op_fdiv }, // FDIV dst,src1,src2
{ uml::OP_FNEG, &drcbe_x64::op_fneg }, // FNEG dst,src1
{ uml::OP_FABS, &drcbe_x64::op_fabs }, // FABS dst,src1
{ uml::OP_FSQRT, &drcbe_x64::op_fsqrt }, // FSQRT dst,src1
{ uml::OP_FRECIP, &drcbe_x64::op_frecip }, // FRECIP dst,src1
{ uml::OP_FRSQRT, &drcbe_x64::op_frsqrt }, // FRSQRT dst,src1
{ uml::OP_FCOPYI, &drcbe_x64::op_fcopyi }, // FCOPYI dst,src
{ uml::OP_ICOPYF, &drcbe_x64::op_icopyf } // ICOPYF dst,src
case uml::OP_FLOAD: op_fload(a, inst); break; // FLOAD dst,base,index
case uml::OP_FSTORE: op_fstore(a, inst); break; // FSTORE base,index,src
case uml::OP_FREAD: op_fread(a, inst); break; // FREAD dst,space,src1
case uml::OP_FWRITE: op_fwrite(a, inst); break; // FWRITE space,dst,src1
case uml::OP_FMOV: op_fmov(a, inst); break; // FMOV dst,src1[,c]
case uml::OP_FTOINT: op_ftoint(a, inst); break; // FTOINT dst,src1,size,round
case uml::OP_FFRINT: op_ffrint(a, inst); break; // FFRINT dst,src1,size
case uml::OP_FFRFLT: op_ffrflt(a, inst); break; // FFRFLT dst,src1,size
case uml::OP_FRNDS: op_frnds(a, inst); break; // FRNDS dst,src1
case uml::OP_FADD: op_fadd(a, inst); break; // FADD dst,src1,src2
case uml::OP_FSUB: op_fsub(a, inst); break; // FSUB dst,src1,src2
case uml::OP_FCMP: op_fcmp(a, inst); break; // FCMP src1,src2
case uml::OP_FMUL: op_fmul(a, inst); break; // FMUL dst,src1,src2
case uml::OP_FDIV: op_fdiv(a, inst); break; // FDIV dst,src1,src2
case uml::OP_FNEG: op_fneg(a, inst); break; // FNEG dst,src1
case uml::OP_FABS: op_fabs(a, inst); break; // FABS dst,src1
case uml::OP_FSQRT: op_fsqrt(a, inst); break; // FSQRT dst,src1
case uml::OP_FRECIP: op_frecip(a, inst); break; // FRECIP dst,src1
case uml::OP_FRSQRT: op_frsqrt(a, inst); break; // FRSQRT dst,src1
case uml::OP_FCOPYI: op_fcopyi(a, inst); break; // FCOPYI 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
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++)
{
const instruction &inst = instlist[inum];
assert(inst.opcode() < std::size(s_opcode_table));
// must remain in scope until output
std::string dasm;
@ -1351,7 +1331,7 @@ void drcbe_x64::generate(drcuml_block &block, const instruction *instlist, uint3
}
// generate code
(this->*s_opcode_table[inst.opcode()])(a, inst);
generate_one(a, inst);
}
// 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 tempreg2 = r10;
@ -1548,7 +1528,7 @@ void drcbe_x64::calculate_status_flags_mul(Assembler &a, uint32_t instsize, asmj
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
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 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
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)
{
// 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 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
{
// 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
alu_op_param(a, Inst::kIdSub, dstreg, src2p, // sub dstreg,src2p
mov_reg_param(a, dstreg, src1p);
alu_op_param(a, Inst::kIdSub, dstreg, src2p,
[inst] (Assembler &a, Operand const &dst, be_parameter const &src)
{
// optimize zero case
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); }
// helpers
asmjit::x86::Gpd select_register(asmjit::x86::Gpd const &defreg) const;
asmjit::x86::Xmm select_register(asmjit::x86::Xmm defreg) const;
Gpd select_register(Gpd const &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, be_parameter const &checkparam2) const;
@ -491,142 +491,145 @@ private:
};
// 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 emit_combine_z_flags(asmjit::x86::Assembler &a);
void emit_combine_zs_flags(asmjit::x86::Assembler &a);
void emit_combine_z_shl_flags(asmjit::x86::Assembler &a);
void emit_combine_z_flags(Assembler &a);
void emit_combine_zs_flags(Assembler &a);
void emit_combine_z_shl_flags(Assembler &a);
void reset_last_upper_lower_reg();
void set_last_lower_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reglo);
void set_last_upper_reg(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reghi);
bool can_skip_lower_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const &reglo);
bool can_skip_upper_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const &reghi);
void set_last_lower_reg(Assembler &a, be_parameter const &param, Gp const &reglo);
void set_last_upper_reg(Assembler &a, be_parameter const &param, Gp const &reghi);
bool can_skip_lower_load(Assembler &a, uint32_t *memref, Gp const &reglo);
bool can_skip_upper_load(Assembler &a, uint32_t *memref, Gp const &reghi);
[[noreturn]] void end_of_block() const;
static void debug_log_hashjmp(int mode, offs_t pc);
void generate_one(Assembler &a, const uml::instruction &inst);
// code generators
void op_handle(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_hash(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_label(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_comment(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mapvar(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_handle(Assembler &a, const uml::instruction &inst);
void op_hash(Assembler &a, const uml::instruction &inst);
void op_label(Assembler &a, const uml::instruction &inst);
void op_comment(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_break(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_debug(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_exit(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_hashjmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_jmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_exh(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_callh(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_ret(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_callc(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_recover(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_nop(Assembler &a, const uml::instruction &inst);
void op_break(Assembler &a, const uml::instruction &inst);
void op_debug(Assembler &a, const uml::instruction &inst);
void op_exit(Assembler &a, const uml::instruction &inst);
void op_hashjmp(Assembler &a, const uml::instruction &inst);
void op_jmp(Assembler &a, const uml::instruction &inst);
void op_exh(Assembler &a, const uml::instruction &inst);
void op_callh(Assembler &a, const uml::instruction &inst);
void op_ret(Assembler &a, const uml::instruction &inst);
void op_callc(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_getfmod(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_getexp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_getflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_setflgs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_save(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_restore(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_setfmod(Assembler &a, const uml::instruction &inst);
void op_getfmod(Assembler &a, const uml::instruction &inst);
void op_getexp(Assembler &a, const uml::instruction &inst);
void op_getflgs(Assembler &a, const uml::instruction &inst);
void op_setflgs(Assembler &a, const uml::instruction &inst);
void op_save(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_loads(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_store(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_read(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_readm(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_write(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_writem(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_carry(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_set(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mov(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_sext(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_roland(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_rolins(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_add(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_addc(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_sub(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_subc(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_cmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mulu(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mululw(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_muls(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_mulslw(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_divu(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_divs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_and(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_test(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_or(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_xor(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_lzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_tzcnt(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_bswap(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_shl(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_shr(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_sar(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_ror(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_rol(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_rorc(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_rolc(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_load(Assembler &a, const uml::instruction &inst);
void op_loads(Assembler &a, const uml::instruction &inst);
void op_store(Assembler &a, const uml::instruction &inst);
void op_read(Assembler &a, const uml::instruction &inst);
void op_readm(Assembler &a, const uml::instruction &inst);
void op_write(Assembler &a, const uml::instruction &inst);
void op_writem(Assembler &a, const uml::instruction &inst);
void op_carry(Assembler &a, const uml::instruction &inst);
void op_set(Assembler &a, const uml::instruction &inst);
void op_mov(Assembler &a, const uml::instruction &inst);
void op_sext(Assembler &a, const uml::instruction &inst);
void op_roland(Assembler &a, const uml::instruction &inst);
void op_rolins(Assembler &a, const uml::instruction &inst);
void op_add(Assembler &a, const uml::instruction &inst);
void op_addc(Assembler &a, const uml::instruction &inst);
void op_sub(Assembler &a, const uml::instruction &inst);
void op_subc(Assembler &a, const uml::instruction &inst);
void op_cmp(Assembler &a, const uml::instruction &inst);
void op_mulu(Assembler &a, const uml::instruction &inst);
void op_mululw(Assembler &a, const uml::instruction &inst);
void op_muls(Assembler &a, const uml::instruction &inst);
void op_mulslw(Assembler &a, const uml::instruction &inst);
void op_divu(Assembler &a, const uml::instruction &inst);
void op_divs(Assembler &a, const uml::instruction &inst);
void op_and(Assembler &a, const uml::instruction &inst);
void op_test(Assembler &a, const uml::instruction &inst);
void op_or(Assembler &a, const uml::instruction &inst);
void op_xor(Assembler &a, const uml::instruction &inst);
void op_lzcnt(Assembler &a, const uml::instruction &inst);
void op_tzcnt(Assembler &a, const uml::instruction &inst);
void op_bswap(Assembler &a, const uml::instruction &inst);
void op_shl(Assembler &a, const uml::instruction &inst);
void op_shr(Assembler &a, const uml::instruction &inst);
void op_sar(Assembler &a, const uml::instruction &inst);
void op_ror(Assembler &a, const uml::instruction &inst);
void op_rol(Assembler &a, const uml::instruction &inst);
void op_rorc(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_fstore(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fread(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fwrite(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fmov(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_ftoint(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_ffrint(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_ffrflt(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_frnds(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fadd(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fsub(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fcmp(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fmul(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fdiv(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fneg(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fabs(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_frecip(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_frsqrt(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fcopyi(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_icopyf(asmjit::x86::Assembler &a, const uml::instruction &inst);
void op_fload(Assembler &a, const uml::instruction &inst);
void op_fstore(Assembler &a, const uml::instruction &inst);
void op_fread(Assembler &a, const uml::instruction &inst);
void op_fwrite(Assembler &a, const uml::instruction &inst);
void op_fmov(Assembler &a, const uml::instruction &inst);
void op_ftoint(Assembler &a, const uml::instruction &inst);
void op_ffrint(Assembler &a, const uml::instruction &inst);
void op_ffrflt(Assembler &a, const uml::instruction &inst);
void op_frnds(Assembler &a, const uml::instruction &inst);
void op_fadd(Assembler &a, const uml::instruction &inst);
void op_fsub(Assembler &a, const uml::instruction &inst);
void op_fcmp(Assembler &a, const uml::instruction &inst);
void op_fmul(Assembler &a, const uml::instruction &inst);
void op_fdiv(Assembler &a, const uml::instruction &inst);
void op_fneg(Assembler &a, const uml::instruction &inst);
void op_fabs(Assembler &a, const uml::instruction &inst);
void op_fsqrt(Assembler &a, const uml::instruction &inst);
void op_frecip(Assembler &a, const uml::instruction &inst);
void op_frsqrt(Assembler &a, const uml::instruction &inst);
void op_fcopyi(Assembler &a, const uml::instruction &inst);
void op_icopyf(Assembler &a, const uml::instruction &inst);
// 32-bit code emission helpers
void emit_mov_r32_p32(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param);
void emit_mov_r32_p32_keepflags(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reg, be_parameter const &param);
void emit_mov_m32_p32(asmjit::x86::Assembler &a, asmjit::x86::Mem memref, be_parameter const &param);
void emit_mov_p32_r32(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reg);
void emit_mov_r32_p32(Assembler &a, 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(Assembler &a, Mem memref, be_parameter const &param);
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; });
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);
template <typename T> void alu_op_param(Assembler &a, Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const &param, T &&optimize);
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
void emit_mov_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param);
void emit_mov_r64_p64_keepflags(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param);
void emit_mov_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref, be_parameter const &param);
void emit_mov_p64_r64(asmjit::x86::Assembler &a, be_parameter const &param, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi);
void emit_and_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
void emit_and_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref_lo, asmjit::x86::Mem const &memref_hi, be_parameter const &param, const uml::instruction &inst);
void emit_or_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
void emit_or_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref_lo, asmjit::x86::Mem const &memref_hi, be_parameter const &param, const uml::instruction &inst);
void emit_xor_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
void emit_xor_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref_lo, asmjit::x86::Mem const &memref_hi, be_parameter const &param, const uml::instruction &inst);
void emit_shl_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
void emit_shr_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
void emit_sar_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
void emit_rol_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
void emit_ror_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
void emit_rcl_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
void emit_rcr_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const &reglo, asmjit::x86::Gp const &reghi, be_parameter const &param, const uml::instruction &inst);
void emit_mov_r64_p64(Assembler &a, Gp const &reglo, 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(Assembler &a, Mem const &memref, be_parameter const &param);
void emit_mov_p64_r64(Assembler &a, be_parameter const &param, Gp const &reglo, Gp const &reghi);
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(Assembler &a, Mem const &memref_lo, Mem const &memref_hi, 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(Assembler &a, Mem const &memref_lo, Mem const &memref_hi, 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(Assembler &a, Mem const &memref_lo, Mem const &memref_hi, 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(Assembler &a, Gp const &reglo, 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(Assembler &a, Gp const &reglo, 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(Assembler &a, Gp const &reglo, 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(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, Gp const &lo, 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, Mem const &lo, Mem const &hi, be_parameter const &param, bool const saveflags);
// floating-point code emission helpers
void emit_fld_p(asmjit::x86::Assembler &a, int size, be_parameter const &param);
void emit_fstp_p(asmjit::x86::Assembler &a, int size, be_parameter const &param);
void emit_fld_p(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);
@ -647,10 +650,10 @@ private:
uint32_t * m_reglo[REG_MAX]; // pointer to low part of data for each register
uint32_t * m_reghi[REG_MAX]; // pointer to high part of data for each register
asmjit::x86::Gp m_last_lower_reg; // last register we stored a lower from
Gp m_last_lower_reg; // last register we stored a lower from
x86code * m_last_lower_pc; // PC after instruction where we last stored a lower register
uint32_t * m_last_lower_addr; // address where we last stored an lower register
asmjit::x86::Gp m_last_upper_reg; // last register we stored an upper from
Gp m_last_upper_reg; // last register we stored an upper from
x86code * m_last_upper_pc; // PC after instruction where we last stored an upper register
uint32_t * m_last_upper_addr; // address where we last stored an upper register
double m_fptemp; // temporary storage for floating point
@ -667,125 +670,112 @@ private:
resolved_member_function m_debug_cpu_instruction_hook;
resolved_member_function m_drcmap_get_value;
resolved_memory_accessors_vector m_memory_accessors;
// globals
typedef void (drcbe_x86::*opcode_generate_func)(asmjit::x86::Assembler &a, const uml::instruction &inst);
struct opcode_table_entry
{
uml::opcode_t opcode; // opcode in question
opcode_generate_func func; // function pointer to the work
};
static const opcode_table_entry s_opcode_table_source[];
static opcode_generate_func s_opcode_table[uml::OP_MAX];
};
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
drcbe_x86::opcode_generate_func drcbe_x86::s_opcode_table[OP_MAX];
//**************************************************************************
// 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
{ uml::OP_HANDLE, &drcbe_x86::op_handle }, // HANDLE handle
{ uml::OP_HASH, &drcbe_x86::op_hash }, // HASH mode,pc
{ uml::OP_LABEL, &drcbe_x86::op_label }, // LABEL imm
{ uml::OP_COMMENT, &drcbe_x86::op_comment }, // COMMENT string
{ uml::OP_MAPVAR, &drcbe_x86::op_mapvar }, // MAPVAR mapvar,value
case uml::OP_HANDLE: op_handle(a, inst); break; // HANDLE handle
case uml::OP_HASH: op_hash(a, inst); break; // HASH mode,pc
case uml::OP_LABEL: op_label(a, inst); break; // LABEL imm
case uml::OP_COMMENT: op_comment(a, inst); break; // COMMENT string
case uml::OP_MAPVAR: op_mapvar(a, inst); break; // MAPVAR mapvar,value
// Control Flow Operations
{ uml::OP_NOP, &drcbe_x86::op_nop }, // NOP
{ uml::OP_BREAK, &drcbe_x86::op_break }, // BREAK
{ uml::OP_DEBUG, &drcbe_x86::op_debug }, // DEBUG pc
{ uml::OP_EXIT, &drcbe_x86::op_exit }, // EXIT src1[,c]
{ uml::OP_HASHJMP, &drcbe_x86::op_hashjmp }, // HASHJMP mode,pc,handle
{ uml::OP_JMP, &drcbe_x86::op_jmp }, // JMP imm[,c]
{ uml::OP_EXH, &drcbe_x86::op_exh }, // EXH handle,param[,c]
{ uml::OP_CALLH, &drcbe_x86::op_callh }, // CALLH handle[,c]
{ uml::OP_RET, &drcbe_x86::op_ret }, // RET [c]
{ uml::OP_CALLC, &drcbe_x86::op_callc }, // CALLC func,ptr[,c]
{ uml::OP_RECOVER, &drcbe_x86::op_recover }, // RECOVER dst,mapvar
case uml::OP_NOP: op_nop(a, inst); break; // NOP
case uml::OP_BREAK: op_break(a, inst); break; // BREAK
case uml::OP_DEBUG: op_debug(a, inst); break; // DEBUG pc
case uml::OP_EXIT: op_exit(a, inst); break; // EXIT src1[,c]
case uml::OP_HASHJMP: op_hashjmp(a, inst); break; // HASHJMP mode,pc,handle
case uml::OP_JMP: op_jmp(a, inst); break; // JMP imm[,c]
case uml::OP_EXH: op_exh(a, inst); break; // EXH handle,param[,c]
case uml::OP_CALLH: op_callh(a, inst); break; // CALLH handle[,c]
case uml::OP_RET: op_ret(a, inst); break; // RET [c]
case uml::OP_CALLC: op_callc(a, inst); break; // CALLC func,ptr[,c]
case uml::OP_RECOVER: op_recover(a, inst); break; // RECOVER dst,mapvar
// Internal Register Operations
{ uml::OP_SETFMOD, &drcbe_x86::op_setfmod }, // SETFMOD src
{ uml::OP_GETFMOD, &drcbe_x86::op_getfmod }, // GETFMOD dst
{ uml::OP_GETEXP, &drcbe_x86::op_getexp }, // GETEXP dst
{ uml::OP_GETFLGS, &drcbe_x86::op_getflgs }, // GETFLGS dst[,f]
{ uml::OP_SETFLGS, &drcbe_x86::op_setflgs }, // GETFLGS src
{ uml::OP_SAVE, &drcbe_x86::op_save }, // SAVE dst
{ uml::OP_RESTORE, &drcbe_x86::op_restore }, // RESTORE dst
case uml::OP_SETFMOD: op_setfmod(a, inst); break; // SETFMOD src
case uml::OP_GETFMOD: op_getfmod(a, inst); break; // GETFMOD dst
case uml::OP_GETEXP: op_getexp(a, inst); break; // GETEXP dst
case uml::OP_GETFLGS: op_getflgs(a, inst); break; // GETFLGS dst[,f]
case uml::OP_SETFLGS: op_setflgs(a, inst); break; // GETFLGS src
case uml::OP_SAVE: op_save(a, inst); break; // SAVE dst
case uml::OP_RESTORE: op_restore(a, inst); break; // RESTORE dst
// Integer Operations
{ uml::OP_LOAD, &drcbe_x86::op_load }, // LOAD dst,base,index,size
{ uml::OP_LOADS, &drcbe_x86::op_loads }, // LOADS dst,base,index,size
{ uml::OP_STORE, &drcbe_x86::op_store }, // STORE base,index,src,size
{ uml::OP_READ, &drcbe_x86::op_read }, // READ dst,src1,spacesize
{ uml::OP_READM, &drcbe_x86::op_readm }, // READM dst,src1,mask,spacesize
{ uml::OP_WRITE, &drcbe_x86::op_write }, // WRITE dst,src1,spacesize
{ uml::OP_WRITEM, &drcbe_x86::op_writem }, // WRITEM dst,src1,spacesize
{ uml::OP_CARRY, &drcbe_x86::op_carry }, // CARRY src,bitnum
{ uml::OP_SET, &drcbe_x86::op_set }, // SET dst,c
{ uml::OP_MOV, &drcbe_x86::op_mov }, // MOV dst,src[,c]
{ uml::OP_SEXT, &drcbe_x86::op_sext }, // SEXT dst,src
{ uml::OP_ROLAND, &drcbe_x86::op_roland }, // ROLAND dst,src1,src2,src3
{ uml::OP_ROLINS, &drcbe_x86::op_rolins }, // ROLINS dst,src1,src2,src3
{ uml::OP_ADD, &drcbe_x86::op_add }, // ADD dst,src1,src2[,f]
{ uml::OP_ADDC, &drcbe_x86::op_addc }, // ADDC dst,src1,src2[,f]
{ uml::OP_SUB, &drcbe_x86::op_sub }, // SUB dst,src1,src2[,f]
{ uml::OP_SUBB, &drcbe_x86::op_subc }, // SUBB dst,src1,src2[,f]
{ uml::OP_CMP, &drcbe_x86::op_cmp }, // CMP src1,src2[,f]
{ uml::OP_MULU, &drcbe_x86::op_mulu }, // MULU dst,edst,src1,src2[,f]
{ uml::OP_MULULW, &drcbe_x86::op_mululw }, // MULULW dst,src1,src2[,f]
{ uml::OP_MULS, &drcbe_x86::op_muls }, // MULS dst,edst,src1,src2[,f]
{ uml::OP_MULSLW, &drcbe_x86::op_mulslw }, // MULSLW dst,src1,src2[,f]
{ uml::OP_DIVU, &drcbe_x86::op_divu }, // DIVU dst,edst,src1,src2[,f]
{ uml::OP_DIVS, &drcbe_x86::op_divs }, // DIVS dst,edst,src1,src2[,f]
{ uml::OP_AND, &drcbe_x86::op_and }, // AND dst,src1,src2[,f]
{ uml::OP_TEST, &drcbe_x86::op_test }, // TEST src1,src2[,f]
{ uml::OP_OR, &drcbe_x86::op_or }, // OR dst,src1,src2[,f]
{ uml::OP_XOR, &drcbe_x86::op_xor }, // XOR dst,src1,src2[,f]
{ uml::OP_LZCNT, &drcbe_x86::op_lzcnt }, // LZCNT dst,src[,f]
{ uml::OP_TZCNT, &drcbe_x86::op_tzcnt }, // TZCNT dst,src[,f]
{ uml::OP_BSWAP, &drcbe_x86::op_bswap }, // BSWAP dst,src
{ uml::OP_SHL, &drcbe_x86::op_shl }, // SHL dst,src,count[,f]
{ uml::OP_SHR, &drcbe_x86::op_shr }, // SHR dst,src,count[,f]
{ uml::OP_SAR, &drcbe_x86::op_sar }, // SAR dst,src,count[,f]
{ uml::OP_ROL, &drcbe_x86::op_rol }, // ROL dst,src,count[,f]
{ uml::OP_ROLC, &drcbe_x86::op_rolc }, // ROLC dst,src,count[,f]
{ uml::OP_ROR, &drcbe_x86::op_ror }, // ROR dst,src,count[,f]
{ uml::OP_RORC, &drcbe_x86::op_rorc }, // RORC dst,src,count[,f]
case uml::OP_LOAD: op_load(a, inst); break; // LOAD dst,base,index,size
case uml::OP_LOADS: op_loads(a, inst); break; // LOADS dst,base,index,size
case uml::OP_STORE: op_store(a, inst); break; // STORE base,index,src,size
case uml::OP_READ: op_read(a, inst); break; // READ dst,src1,spacesize
case uml::OP_READM: op_readm(a, inst); break; // READM dst,src1,mask,spacesize
case uml::OP_WRITE: op_write(a, inst); break; // WRITE dst,src1,spacesize
case uml::OP_WRITEM: op_writem(a, inst); break; // WRITEM dst,src1,spacesize
case uml::OP_CARRY: op_carry(a, inst); break; // CARRY src,bitnum
case uml::OP_SET: op_set(a, inst); break; // SET dst,c
case uml::OP_MOV: op_mov(a, inst); break; // MOV dst,src[,c]
case uml::OP_SEXT: op_sext(a, inst); break; // SEXT dst,src
case uml::OP_ROLAND: op_roland(a, inst); break; // ROLAND dst,src1,src2,src3
case uml::OP_ROLINS: op_rolins(a, inst); break; // ROLINS dst,src1,src2,src3
case uml::OP_ADD: op_add(a, inst); break; // ADD dst,src1,src2[,f]
case uml::OP_ADDC: op_addc(a, inst); break; // ADDC dst,src1,src2[,f]
case uml::OP_SUB: op_sub(a, inst); break; // SUB dst,src1,src2[,f]
case uml::OP_SUBB: op_subc(a, inst); break; // SUBB dst,src1,src2[,f]
case uml::OP_CMP: op_cmp(a, inst); break; // CMP src1,src2[,f]
case uml::OP_MULU: op_mulu(a, inst); break; // MULU dst,edst,src1,src2[,f]
case uml::OP_MULULW: op_mululw(a, inst); break; // MULULW dst,src1,src2[,f]
case uml::OP_MULS: op_muls(a, inst); break; // MULS dst,edst,src1,src2[,f]
case uml::OP_MULSLW: op_mulslw(a, inst); break; // MULSLW dst,src1,src2[,f]
case uml::OP_DIVU: op_divu(a, inst); break; // DIVU dst,edst,src1,src2[,f]
case uml::OP_DIVS: op_divs(a, inst); break; // DIVS dst,edst,src1,src2[,f]
case uml::OP_AND: op_and(a, inst); break; // AND dst,src1,src2[,f]
case uml::OP_TEST: op_test(a, inst); break; // TEST src1,src2[,f]
case uml::OP_OR: op_or(a, inst); break; // OR dst,src1,src2[,f]
case uml::OP_XOR: op_xor(a, inst); break; // XOR dst,src1,src2[,f]
case uml::OP_LZCNT: op_lzcnt(a, inst); break; // LZCNT dst,src[,f]
case uml::OP_TZCNT: op_tzcnt(a, inst); break; // TZCNT dst,src[,f]
case uml::OP_BSWAP: op_bswap(a, inst); break; // BSWAP dst,src
case uml::OP_SHL: op_shl(a, inst); break; // SHL dst,src,count[,f]
case uml::OP_SHR: op_shr(a, inst); break; // SHR dst,src,count[,f]
case uml::OP_SAR: op_sar(a, inst); break; // SAR dst,src,count[,f]
case uml::OP_ROL: op_rol(a, inst); break; // ROL dst,src,count[,f]
case uml::OP_ROLC: op_rolc(a, inst); break; // ROLC dst,src,count[,f]
case uml::OP_ROR: op_ror(a, inst); break; // ROR dst,src,count[,f]
case uml::OP_RORC: op_rorc(a, inst); break; // RORC dst,src,count[,f]
// Floating Point Operations
{ uml::OP_FLOAD, &drcbe_x86::op_fload }, // FLOAD dst,base,index
{ uml::OP_FSTORE, &drcbe_x86::op_fstore }, // FSTORE base,index,src
{ uml::OP_FREAD, &drcbe_x86::op_fread }, // FREAD dst,space,src1
{ uml::OP_FWRITE, &drcbe_x86::op_fwrite }, // FWRITE space,dst,src1
{ uml::OP_FMOV, &drcbe_x86::op_fmov }, // FMOV dst,src1[,c]
{ uml::OP_FTOINT, &drcbe_x86::op_ftoint }, // FTOINT dst,src1,size,round
{ uml::OP_FFRINT, &drcbe_x86::op_ffrint }, // FFRINT dst,src1,size
{ uml::OP_FFRFLT, &drcbe_x86::op_ffrflt }, // FFRFLT dst,src1,size
{ uml::OP_FRNDS, &drcbe_x86::op_frnds }, // FRNDS dst,src1
{ uml::OP_FADD, &drcbe_x86::op_fadd }, // FADD dst,src1,src2
{ uml::OP_FSUB, &drcbe_x86::op_fsub }, // FSUB dst,src1,src2
{ uml::OP_FCMP, &drcbe_x86::op_fcmp }, // FCMP src1,src2
{ uml::OP_FMUL, &drcbe_x86::op_fmul }, // FMUL dst,src1,src2
{ uml::OP_FDIV, &drcbe_x86::op_fdiv }, // FDIV dst,src1,src2
{ uml::OP_FNEG, &drcbe_x86::op_fneg }, // FNEG dst,src1
{ uml::OP_FABS, &drcbe_x86::op_fabs }, // FABS dst,src1
{ uml::OP_FSQRT, &drcbe_x86::op_fsqrt }, // FSQRT dst,src1
{ uml::OP_FRECIP, &drcbe_x86::op_frecip }, // FRECIP dst,src1
{ uml::OP_FRSQRT, &drcbe_x86::op_frsqrt }, // FRSQRT dst,src1
{ uml::OP_FCOPYI, &drcbe_x86::op_fcopyi }, // FCOPYI dst,src
{ uml::OP_ICOPYF, &drcbe_x86::op_icopyf }, // ICOPYF dst,src
case uml::OP_FLOAD: op_fload(a, inst); break; // FLOAD dst,base,index
case uml::OP_FSTORE: op_fstore(a, inst); break; // FSTORE base,index,src
case uml::OP_FREAD: op_fread(a, inst); break; // FREAD dst,space,src1
case uml::OP_FWRITE: op_fwrite(a, inst); break; // FWRITE space,dst,src1
case uml::OP_FMOV: op_fmov(a, inst); break; // FMOV dst,src1[,c]
case uml::OP_FTOINT: op_ftoint(a, inst); break; // FTOINT dst,src1,size,round
case uml::OP_FFRINT: op_ffrint(a, inst); break; // FFRINT dst,src1,size
case uml::OP_FFRFLT: op_ffrflt(a, inst); break; // FFRFLT dst,src1,size
case uml::OP_FRNDS: op_frnds(a, inst); break; // FRNDS dst,src1
case uml::OP_FADD: op_fadd(a, inst); break; // FADD dst,src1,src2
case uml::OP_FSUB: op_fsub(a, inst); break; // FSUB dst,src1,src2
case uml::OP_FCMP: op_fcmp(a, inst); break; // FCMP src1,src2
case uml::OP_FMUL: op_fmul(a, inst); break; // FMUL dst,src1,src2
case uml::OP_FDIV: op_fdiv(a, inst); break; // FDIV dst,src1,src2
case uml::OP_FNEG: op_fneg(a, inst); break; // FNEG dst,src1
case uml::OP_FABS: op_fabs(a, inst); break; // FABS dst,src1
case uml::OP_FSQRT: op_fsqrt(a, inst); break; // FSQRT dst,src1
case uml::OP_FRECIP: op_frecip(a, inst); break; // FRECIP dst,src1
case uml::OP_FRSQRT: op_frsqrt(a, inst); break; // FRSQRT dst,src1
case uml::OP_FCOPYI: op_fcopyi(a, inst); break; // FCOPYI 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]);
}
// 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
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++)
{
const instruction &inst = instlist[inum];
assert(inst.opcode() < std::size(s_opcode_table));
// must remain in scope until output
std::string dasm;
@ -1424,7 +1409,7 @@ void drcbe_x86::generate(drcuml_block &block, const instruction *instlist, uint3
}
// generate code
(this->*s_opcode_table[inst.opcode()])(a, inst);
generate_one(a, inst);
}
// 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())
{
@ -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
}
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())
{

View File

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

View File

@ -1860,14 +1860,11 @@ void hyperstone_device::generate_movi(drcuml_block &block, compiler_state &compi
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)
UML_OR(block, I2, I2, Z_MASK);
else if (src & 0x80000000)
UML_OR(block, I2, I2, N_MASK);
#if MISSIONCRAFT_FLAGS
UML_AND(block, I2, I2, ~V_MASK);
#endif
if (DstGlobal)
{
@ -2640,7 +2637,6 @@ void hyperstone_device::generate_rol(drcuml_block &block, compiler_state &compil
UML_AND(block, I1, I0, 0x1f);
}
#ifdef MISSIONCRAFT_FLAGS
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK | V_MASK));
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_MOVc(block, uml::COND_Z, I4, 0);
UML_MOV(block, I5, I4);
#else
UML_AND(block, I2, I2, ~(C_MASK | Z_MASK | N_MASK));
#endif
UML_ROL(block, I0, I0, I1);
#ifdef MISSIONCRAFT_FLAGS
UML_MOVc(block, uml::COND_NS, I4, 0);
#endif
generate_update_nz(block, compiler, uml::I2);
#ifdef MISSIONCRAFT_FLAGS
UML_AND(block, I1, I5, I0);
UML_ROLINS(block, I2, I1, C_SHIFT, C_MASK);
UML_XOR(block, I4, I4, I1);
UML_MOV(block, I1, V_MASK);
UML_MOVc(block, uml::COND_Z, I1, 0);
UML_OR(block, I2, I2, I1);
#endif
UML_MOV(block, DRC_SR, I2);

View File

@ -857,15 +857,13 @@ void hyperstone_device::hyperstone_movi()
}
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)
SR |= Z_MASK;
SR |= SIGN_TO_N(imm);
#if MISSIONCRAFT_FLAGS
SR &= ~V_MASK; // or V undefined ?
#endif
if (DstGlobal)
{
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 dst_code = DST_CODE + fp;
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 */
uint32_t mask = n ? 0xffffffff << (32 - n) : 0;
const uint32_t n = m_core->local_regs[src_code & 0x3f] & 0x1f;
const uint32_t base = m_core->local_regs[dst_code & 0x3f];
const uint32_t mask = n ? (0xffffffff << (32 - n)) : 0;
SR &= ~(C_MASK | V_MASK | Z_MASK | N_MASK);
SR |= (n)?(((base<<(n-1))&0x80000000)?1:0):0;
uint32_t ret = base << n;
SR |= (n && ((base << (n - 1)) & 0x80000000)) ? C_MASK : 0;
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;
if (ret == 0)
@ -1483,32 +1481,28 @@ void hyperstone_device::hyperstone_testlz()
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();
const uint32_t fp = GET_FP;
const uint32_t dst_code = (DST_CODE + fp) & 0x3f;
uint32_t n = m_core->local_regs[(SRC_CODE + fp) & 0x3f] & 0x1f;
uint32_t val = m_core->local_regs[dst_code];
const uint32_t n = m_core->local_regs[(SRC_CODE + fp) & 0x3f] & 0x1f;
const uint32_t mask = n ? (~uint32_t(0) >> (32 - n)) : 0;
#ifdef MISSIONCRAFT_FLAGS
const uint32_t base = val;
const uint32_t mask = (uint32_t)(0xffffffff00000000ULL >> n);
#endif
uint32_t val = m_core->local_regs[dst_code];
val = rotl_32(val, n);
#ifdef MISSIONCRAFT_FLAGS
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;
#else
SR &= ~(Z_MASK | C_MASK | N_MASK);
#endif
if (val == 0)
SR |= Z_MASK;
SR |= SIGN_TO_N(val);
if (n && (val & 1))
SR |= C_MASK;
m_core->local_regs[dst_code] = val;
@ -2097,30 +2091,27 @@ void hyperstone_device::hyperstone_shli()
check_delay_pc();
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);
if (HiN || n)
{
SR |= (val & (0x80000000 >> (n - 1))) ? 1 : 0;
}
SR |= (n && ((base << (n - 1)) & 0x80000000)) ? C_MASK : 0;
const uint32_t ret = base << n;
uint32_t mask = n ? 0xffffffff << (32 - n) : 0;
uint32_t val2 = val << n;
if (((val & mask) && (!(val2 & 0x80000000))) || (((val & mask) ^ mask) && (val2 & 0x80000000)))
if (!(ret & 0x80000000) ? (base & mask) : ((base & mask) ^ mask))
SR |= V_MASK;
if (val2 == 0)
if (ret == 0)
SR |= Z_MASK;
SR |= SIGN_TO_N(val2);
SR |= SIGN_TO_N(ret);
if (DstGlobal)
set_global_register(dst_code, val2);
set_global_register(dst_code, ret);
else
m_core->local_regs[dst_code] = val2;
m_core->local_regs[dst_code] = ret;
m_core->icount -= m_core->clock_cycles_1;
}