diff --git a/src/devices/cpu/drcbearm64.cpp b/src/devices/cpu/drcbearm64.cpp index cfcdbaad897..21ae7c17d55 100644 --- a/src/devices/cpu/drcbearm64.cpp +++ b/src/devices/cpu/drcbearm64.cpp @@ -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 void op_add(asmjit::a64::Assembler &a, const uml::instruction &inst); - template 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 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 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 void op_add(a64::Assembler &a, const uml::instruction &inst); + template 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 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 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 void op_float_alu(asmjit::a64::Assembler &a, const uml::instruction &inst); - template 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 void op_float_alu(a64::Assembler &a, const uml::instruction &inst); + template 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 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 }, // ADD dst,src1,src2[,f] - { uml::OP_ADDC, &drcbe_arm64::op_add }, // ADDC dst,src1,src2[,f] - { uml::OP_SUB, &drcbe_arm64::op_sub }, // SUB dst,src1,src2[,f] - { uml::OP_SUBB, &drcbe_arm64::op_sub }, // 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 }, // DIVU dst,edst,src1,src2[,f] - { uml::OP_DIVS, &drcbe_arm64::op_div }, // 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 }, // SHL dst,src,count[,f] - { uml::OP_SHR, &drcbe_arm64::op_shift }, // SHR dst,src,count[,f] - { uml::OP_SAR, &drcbe_arm64::op_shift }, // 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 }, // 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(a, inst); break; // ADD dst,src1,src2[,f] + case uml::OP_ADDC: op_add(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_sub(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(a, inst); break; // DIVU dst,edst,src1,src2[,f] + case uml::OP_DIVS: op_div(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(a, inst); break; // SHL dst,src,count[,f] + case uml::OP_SHR: op_shift(a, inst); break; // SHR dst,src,count[,f] + case uml::OP_SAR: op_shift(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(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 }, // FADD dst,src1,src2 - { uml::OP_FSUB, &drcbe_arm64::op_float_alu }, // FSUB dst,src1,src2 - { uml::OP_FCMP, &drcbe_arm64::op_fcmp }, // FCMP src1,src2 - { uml::OP_FMUL, &drcbe_arm64::op_float_alu }, // FMUL dst,src1,src2 - { uml::OP_FDIV, &drcbe_arm64::op_float_alu }, // FDIV dst,src1,src2 - { uml::OP_FNEG, &drcbe_arm64::op_float_alu2 }, // FNEG dst,src1 - { uml::OP_FABS, &drcbe_arm64::op_float_alu2 }, // FABS dst,src1 - { uml::OP_FSQRT, &drcbe_arm64::op_float_alu2 }, // FSQRT dst,src1 - { uml::OP_FRECIP, &drcbe_arm64::op_float_alu2 }, // FRECIP dst,src1 - { uml::OP_FRSQRT, &drcbe_arm64::op_float_alu2 }, // 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(a, inst); break; // FADD dst,src1,src2 + case uml::OP_FSUB: op_float_alu(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(a, inst); break; // FMUL dst,src1,src2 + case uml::OP_FDIV: op_float_alu (a, inst); break; // FDIV dst,src1,src2 + case uml::OP_FNEG: op_float_alu2(a, inst); break; // FNEG dst,src1 + case uml::OP_FABS: op_float_alu2(a, inst); break; // FABS dst,src1 + case uml::OP_FSQRT: op_float_alu2(a, inst); break; // FSQRT dst,src1 + case uml::OP_FRECIP: op_float_alu2(a, inst); break; // FRECIP dst,src1 + case uml::OP_FRSQRT: op_float_alu2(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 diff --git a/src/devices/cpu/drcbex64.cpp b/src/devices/cpu/drcbex64.cpp index f95a3700804..c5bf514f14e 100644 --- a/src/devices/cpu/drcbex64.cpp +++ b/src/devices/cpu/drcbex64.cpp @@ -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 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 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 - 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 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 }, // SHL dst,src,count[,f] - { uml::OP_SHR, &drcbe_x64::op_shift }, // SHR dst,src,count[,f] - { uml::OP_SAR, &drcbe_x64::op_shift }, // SAR dst,src,count[,f] - { uml::OP_ROL, &drcbe_x64::op_shift }, // ROL dst,src,count[,f] - { uml::OP_ROLC, &drcbe_x64::op_shift }, // ROLC dst,src,count[,f] - { uml::OP_ROR, &drcbe_x64::op_shift }, // ROR dst,src,count[,f] - { uml::OP_RORC, &drcbe_x64::op_shift }, // 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(a, inst); break; // SHL dst,src,count[,f] + case uml::OP_SHR: op_shift(a, inst); break; // SHR dst,src,count[,f] + case uml::OP_SAR: op_shift(a, inst); break; // SAR dst,src,count[,f] + case uml::OP_ROL: op_shift(a, inst); break; // ROL dst,src,count[,f] + case uml::OP_ROLC: op_shift(a, inst); break; // ROLC dst,src,count[,f] + case uml::OP_ROR: op_shift(a, inst); break; // ROR dst,src,count[,f] + case uml::OP_RORC: op_shift(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); } } diff --git a/src/devices/cpu/drcbex86.cpp b/src/devices/cpu/drcbex86.cpp index 724da1cd125..0814e1725f3 100644 --- a/src/devices/cpu/drcbex86.cpp +++ b/src/devices/cpu/drcbex86.cpp @@ -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 T select_register(T defreg, be_parameter const &checkparam) const; template 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 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 optimize, bool update_flags); + template 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 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 optimize) +template +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 optimize, bool update_flags) +template +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()) { diff --git a/src/devices/cpu/e132xs/32xsdefs.h b/src/devices/cpu/e132xs/32xsdefs.h index 9117d8ddb0b..fd2e30781ea 100644 --- a/src/devices/cpu/e132xs/32xsdefs.h +++ b/src/devices/cpu/e132xs/32xsdefs.h @@ -155,7 +155,6 @@ enum // set C in adds/addsi/subs/sums #define SETCARRYS 0 -#define MISSIONCRAFT_FLAGS 1 /* Registers */ diff --git a/src/devices/cpu/e132xs/e132xsdrc_ops.hxx b/src/devices/cpu/e132xs/e132xsdrc_ops.hxx index 3bba381da1e..577febd0a8e 100644 --- a/src/devices/cpu/e132xs/e132xsdrc_ops.hxx +++ b/src/devices/cpu/e132xs/e132xsdrc_ops.hxx @@ -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); diff --git a/src/devices/cpu/e132xs/e132xsop.hxx b/src/devices/cpu/e132xs/e132xsop.hxx index 25848e55796..6660fada73d 100644 --- a/src/devices/cpu/e132xs/e132xsop.hxx +++ b/src/devices/cpu/e132xs/e132xsop.hxx @@ -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; }