mirror of
https://github.com/holub/mame
synced 2025-04-09 18:17:44 +03:00
-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:
parent
9a2b909a9e
commit
b1c09f02b4
@ -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 ®, uint32_t regsize) const;
|
||||
asmjit::a64::Gp select_register(asmjit::a64::Gp const ®, 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 ®, uint32_t regsize) const;
|
||||
a64::Gp select_register(a64::Gp const ®, 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 ®, const uint64_t ptr) const;
|
||||
void get_imm_relative(a64::Assembler &a, const a64::Gp ®, const uint64_t ptr) const;
|
||||
|
||||
void emit_ldr_str_base_mem(asmjit::a64::Assembler &a, asmjit::a64::Inst::Id opcode, const asmjit::a64::Reg ®, int max_shift, const void *ptr) const;
|
||||
void emit_ldr_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldrb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldrh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldrsb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldrsh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldrsw_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const void *ptr) const;
|
||||
void emit_str_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const void *ptr) const;
|
||||
void emit_strb_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const void *ptr) const;
|
||||
void emit_strh_mem(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldr_str_base_mem(a64::Assembler &a, a64::Inst::Id opcode, const a64::Reg ®, int max_shift, const void *ptr) const;
|
||||
void emit_ldr_mem(a64::Assembler &a, const a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldrb_mem(a64::Assembler &a, const a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldrh_mem(a64::Assembler &a, const a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldrsb_mem(a64::Assembler &a, const a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldrsh_mem(a64::Assembler &a, const a64::Gp ®, const void *ptr) const;
|
||||
void emit_ldrsw_mem(a64::Assembler &a, const a64::Gp ®, const void *ptr) const;
|
||||
void emit_str_mem(a64::Assembler &a, const a64::Gp ®, const void *ptr) const;
|
||||
void emit_strb_mem(a64::Assembler &a, const a64::Gp ®, const void *ptr) const;
|
||||
void emit_strh_mem(a64::Assembler &a, const a64::Gp ®, const void *ptr) const;
|
||||
|
||||
void emit_float_ldr_mem(asmjit::a64::Assembler &a, const asmjit::a64::Vec ®, const void *ptr) const;
|
||||
void emit_float_str_mem(asmjit::a64::Assembler &a, const asmjit::a64::Vec ®, const void *ptr) const;
|
||||
void emit_float_ldr_mem(a64::Assembler &a, const a64::Vec ®, const void *ptr) const;
|
||||
void emit_float_str_mem(a64::Assembler &a, const a64::Vec ®, 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 ®, const asmjit::a64::Gp &shift, int maxBits);
|
||||
void calculate_carry_shift_left_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const int shift, int maxBits);
|
||||
void calculate_carry_shift_left(a64::Assembler &a, const a64::Gp ®, const a64::Gp &shift, int maxBits);
|
||||
void calculate_carry_shift_left_imm(a64::Assembler &a, const a64::Gp ®, const int shift, int maxBits);
|
||||
|
||||
void calculate_carry_shift_right(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const asmjit::a64::Gp &shift);
|
||||
void calculate_carry_shift_right_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const int shift);
|
||||
void calculate_carry_shift_right(a64::Assembler &a, const a64::Gp ®, const a64::Gp &shift);
|
||||
void calculate_carry_shift_right_imm(a64::Assembler &a, const a64::Gp ®, 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 ¶m, 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
|
||||
|
@ -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 ®, int32_t &offset);
|
||||
void smart_call_r64(asmjit::x86::Assembler &a, x86code *target, asmjit::x86::Gp const ®) 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 ®, int32_t &offset);
|
||||
void smart_call_r64(Assembler &a, x86code *target, Gp const ®) 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 ¶m, T &&optimize);
|
||||
void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const ¶m) { 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 ¶m, u8 update_flags);
|
||||
void alu_op_param(Assembler &a, Inst::Id const opcode, Operand const &dst, be_parameter const ¶m, T &&optimize);
|
||||
void alu_op_param(Assembler &a, Inst::Id const opcode, Operand const &dst, be_parameter const ¶m) { 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 ¶m, u8 update_flags);
|
||||
|
||||
// parameter helpers
|
||||
void mov_reg_param(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®, be_parameter const ¶m, bool const keepflags = false);
|
||||
void mov_param_reg(asmjit::x86::Assembler &a, be_parameter const ¶m, asmjit::x86::Gp const ®);
|
||||
void mov_mem_param(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref, be_parameter const ¶m);
|
||||
void mov_reg_param(Assembler &a, Gp const ®, be_parameter const ¶m, bool const keepflags = false);
|
||||
void mov_param_reg(Assembler &a, be_parameter const ¶m, Gp const ®);
|
||||
void mov_mem_param(Assembler &a, Mem const &memref, be_parameter const ¶m);
|
||||
|
||||
// special-case move helpers
|
||||
void movsx_r64_p32(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®, be_parameter const ¶m);
|
||||
void mov_r64_imm(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®, uint64_t const imm) const;
|
||||
void movsx_r64_p32(Assembler &a, Gp const ®, be_parameter const ¶m);
|
||||
void mov_r64_imm(Assembler &a, Gp const ®, uint64_t const imm) const;
|
||||
|
||||
// floating-point helpers
|
||||
void movss_r128_p32(asmjit::x86::Assembler &a, asmjit::x86::Xmm const ®, be_parameter const ¶m);
|
||||
void movss_p32_r128(asmjit::x86::Assembler &a, be_parameter const ¶m, asmjit::x86::Xmm const ®);
|
||||
void movsd_r128_p64(asmjit::x86::Assembler &a, asmjit::x86::Xmm const ®, be_parameter const ¶m);
|
||||
void movsd_p64_r128(asmjit::x86::Assembler &a, be_parameter const ¶m, asmjit::x86::Xmm const ®);
|
||||
void movss_r128_p32(Assembler &a, Xmm const ®, be_parameter const ¶m);
|
||||
void movss_p32_r128(Assembler &a, be_parameter const ¶m, Xmm const ®);
|
||||
void movsd_r128_p64(Assembler &a, Xmm const ®, be_parameter const ¶m);
|
||||
void movsd_p64_r128(Assembler &a, be_parameter const ¶m, Xmm const ®);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 ¶m, asmjit::x86::Gp const ®lo);
|
||||
void set_last_upper_reg(asmjit::x86::Assembler &a, be_parameter const ¶m, asmjit::x86::Gp const ®hi);
|
||||
bool can_skip_lower_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const ®lo);
|
||||
bool can_skip_upper_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const ®hi);
|
||||
void set_last_lower_reg(Assembler &a, be_parameter const ¶m, Gp const ®lo);
|
||||
void set_last_upper_reg(Assembler &a, be_parameter const ¶m, Gp const ®hi);
|
||||
bool can_skip_lower_load(Assembler &a, uint32_t *memref, Gp const ®lo);
|
||||
bool can_skip_upper_load(Assembler &a, uint32_t *memref, Gp const ®hi);
|
||||
|
||||
[[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 ®, be_parameter const ¶m);
|
||||
void emit_mov_r32_p32_keepflags(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®, be_parameter const ¶m);
|
||||
void emit_mov_m32_p32(asmjit::x86::Assembler &a, asmjit::x86::Mem memref, be_parameter const ¶m);
|
||||
void emit_mov_p32_r32(asmjit::x86::Assembler &a, be_parameter const ¶m, asmjit::x86::Gp const ®);
|
||||
void emit_mov_r32_p32(Assembler &a, Gp const ®, be_parameter const ¶m);
|
||||
void emit_mov_r32_p32_keepflags(Assembler &a, Gp const ®, be_parameter const ¶m);
|
||||
void emit_mov_m32_p32(Assembler &a, Mem memref, be_parameter const ¶m);
|
||||
void emit_mov_p32_r32(Assembler &a, be_parameter const ¶m, Gp const ®);
|
||||
|
||||
void alu_op_param(asmjit::x86::Assembler &a, asmjit::x86::Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const ¶m, 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 ¶m, 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 ¶m, T &&optimize);
|
||||
void alu_op_param(Assembler &a, Inst::Id const opcode, asmjit::Operand const &dst, be_parameter const ¶m) { 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 ¶m, T &&optimize, bool update_flags);
|
||||
|
||||
// 64-bit code emission helpers
|
||||
void emit_mov_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m);
|
||||
void emit_mov_r64_p64_keepflags(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m);
|
||||
void emit_mov_m64_p64(asmjit::x86::Assembler &a, asmjit::x86::Mem const &memref, be_parameter const ¶m);
|
||||
void emit_mov_p64_r64(asmjit::x86::Assembler &a, be_parameter const ¶m, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi);
|
||||
void emit_and_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m, 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 ¶m, const uml::instruction &inst);
|
||||
void emit_or_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m, 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 ¶m, const uml::instruction &inst);
|
||||
void emit_xor_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m, 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 ¶m, const uml::instruction &inst);
|
||||
void emit_shl_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_shr_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_sar_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_rol_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_ror_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_rcl_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_rcr_r64_p64(asmjit::x86::Assembler &a, asmjit::x86::Gp const ®lo, asmjit::x86::Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_mov_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m);
|
||||
void emit_mov_r64_p64_keepflags(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m);
|
||||
void emit_mov_m64_p64(Assembler &a, Mem const &memref, be_parameter const ¶m);
|
||||
void emit_mov_p64_r64(Assembler &a, be_parameter const ¶m, Gp const ®lo, Gp const ®hi);
|
||||
void emit_and_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_and_m64_p64(Assembler &a, Mem const &memref_lo, Mem const &memref_hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_or_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_or_m64_p64(Assembler &a, Mem const &memref_lo, Mem const &memref_hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_xor_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_xor_m64_p64(Assembler &a, Mem const &memref_lo, Mem const &memref_hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_shl_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_shr_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_sar_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_rol_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_ror_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_rcl_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m, const uml::instruction &inst);
|
||||
void emit_rcr_r64_p64(Assembler &a, Gp const ®lo, Gp const ®hi, be_parameter const ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, bool const saveflags);
|
||||
|
||||
// floating-point code emission helpers
|
||||
void emit_fld_p(asmjit::x86::Assembler &a, int size, be_parameter const ¶m);
|
||||
void emit_fstp_p(asmjit::x86::Assembler &a, int size, be_parameter const ¶m);
|
||||
void emit_fld_p(Assembler &a, int size, be_parameter const ¶m);
|
||||
void emit_fstp_p(Assembler &a, int size, be_parameter const ¶m);
|
||||
|
||||
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 ¶m, Gp con
|
||||
}
|
||||
|
||||
|
||||
void drcbe_x86::alu_op_param(Assembler &a, Inst::Id const opcode, Operand const &dst, be_parameter const ¶m, 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 ¶m, 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 ¶m, 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 ¶m, T &&optimize, bool update_flags)
|
||||
{
|
||||
if (param.is_immediate())
|
||||
{
|
||||
|
@ -155,7 +155,6 @@ enum
|
||||
|
||||
// set C in adds/addsi/subs/sums
|
||||
#define SETCARRYS 0
|
||||
#define MISSIONCRAFT_FLAGS 1
|
||||
|
||||
/* Registers */
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user