mirror of
https://github.com/holub/mame
synced 2025-04-17 22:13:04 +03:00
DRC cleanup and minor optimisation: [Windy Fairy, Vas Crabb]
* Build all native back-ends if any native back-end is enabled so errors caused by changing interfaces can be found faster. * cpu/drcbeut.cpp: Moved resolved member function stuff to a place where it can be shared by back-ends. * cpu/drcbearm64.cpp: Use ubfx instruction to extract unordered flag. * cpu/drcbearm64.cpp, cpu/drcbex64.cpp: Bypass trampolines when calling get map variable value and debugger instruction hook functions. * cpu/drcbearm64.cpp: Moved some internal helpers that don't need to be members to anonymous namespace. * cpu/drcbearm64.cpp: Added a comment with some info to help when debugging generated code. * cpu/drcbec.cpp: Put code in the drc namespace.
This commit is contained in:
parent
8cfc62f24d
commit
26d8e47c00
@ -1959,13 +1959,6 @@ project "asmjit"
|
||||
end
|
||||
end
|
||||
|
||||
if (_OPTIONS["PLATFORM"]=="arm64") then
|
||||
configuration { }
|
||||
defines {
|
||||
"ASMJIT_NO_X86",
|
||||
}
|
||||
end
|
||||
|
||||
files {
|
||||
MAME_DIR .. "3rdparty/asmjit/src/asmjit/a64.h",
|
||||
MAME_DIR .. "3rdparty/asmjit/src/asmjit/arm.h",
|
||||
|
@ -42,19 +42,14 @@ if (CPU_INCLUDE_DRC) then
|
||||
MAME_DIR .. "src/devices/cpu/drcumlsh.h",
|
||||
}
|
||||
if not _OPTIONS["FORCE_DRC_C_BACKEND"] then
|
||||
if (_OPTIONS["PLATFORM"]=="arm64") then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/cpu/drcbearm64.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/drcbearm64.h",
|
||||
}
|
||||
else
|
||||
files {
|
||||
MAME_DIR .. "src/devices/cpu/drcbex64.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/drcbex64.h",
|
||||
MAME_DIR .. "src/devices/cpu/drcbex86.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/drcbex86.h",
|
||||
}
|
||||
end
|
||||
files {
|
||||
MAME_DIR .. "src/devices/cpu/drcbearm64.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/drcbearm64.h",
|
||||
MAME_DIR .. "src/devices/cpu/drcbex64.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/drcbex64.h",
|
||||
MAME_DIR .. "src/devices/cpu/drcbex86.cpp",
|
||||
MAME_DIR .. "src/devices/cpu/drcbex86.h",
|
||||
}
|
||||
end
|
||||
|
||||
if _OPTIONS["targetos"]=="macosx" and _OPTIONS["gcc"]~=nil then
|
||||
|
@ -1,5 +1,76 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:windyfairy
|
||||
/***************************************************************************
|
||||
|
||||
Register use:
|
||||
|
||||
r0 first function parameter/return value
|
||||
r1 second function parameter
|
||||
r2 third function parameter
|
||||
r3 fourth function parameter
|
||||
r4
|
||||
r5
|
||||
r6
|
||||
r7
|
||||
r8
|
||||
r9 temporary for intermediate values
|
||||
r10 temporary for intermediate values
|
||||
r11 temporary for intermediate values
|
||||
r12 scratch register used by helper functions
|
||||
r13 scratch register used by helper functions
|
||||
r14 scratch register used for address calculation
|
||||
r15 temporary used in opcode functions
|
||||
r16
|
||||
r17
|
||||
r18
|
||||
r19 UML register I0
|
||||
r20 UML register I1
|
||||
r21 UML register I2
|
||||
r22 UML register I3
|
||||
r23 UML register I4
|
||||
r24 UML register I5
|
||||
r35 UML register I6
|
||||
r26 UML register I7
|
||||
r27 near cache pointer
|
||||
r28 emulated flags
|
||||
r29 base generated code frame pointer
|
||||
r30 link register
|
||||
sp stack pointer
|
||||
|
||||
|
||||
Stack layout in top-level generated code frame:
|
||||
|
||||
FP -> SP + 0x00 previous FP
|
||||
SP + 0x08 top-level return address
|
||||
SP + 0x10 saved non-volatile registers
|
||||
SP + 0x18 ...
|
||||
|
||||
Stack layout in nested generated code subroutine call frame:
|
||||
|
||||
SP -> SP + 0x00 previous FP
|
||||
SP + 0x08 return address
|
||||
...
|
||||
FP - 0x10 previous FP
|
||||
FP - 0x08 return address
|
||||
FP -> FP + 0x00 previous FP
|
||||
FP + 0x08 top-level return address
|
||||
|
||||
The frame pointer (FP or x29) is only updated by the top-level generated
|
||||
code entry point. Generated code subroutines (called using CALLH, EXH or
|
||||
on a failed HASHJMP) push FP and LR onto the stack but do not update FP.
|
||||
All the saved FP values will be identical.
|
||||
|
||||
A native debugger following the FP chain will see any number of nested
|
||||
generated code subroutine call frames as a single stack frame. The return
|
||||
addresses and duplicate saved FP values for the generated code subroutine
|
||||
calls will appear as the local variable area of the frame.
|
||||
|
||||
You can calculate the generated code subroutine call depth as
|
||||
(FP - SP) / 0x10. You can see the return addresses for the generated code
|
||||
subroutine calls at SP + 0x08, SP + 0x18, SP + 0x28, etc. until reaching
|
||||
the location FP points to.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "drcbearm64.h"
|
||||
@ -8,8 +79,6 @@
|
||||
#include "emuopts.h"
|
||||
#include "uml.h"
|
||||
|
||||
#include "mfpresolve.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
@ -44,12 +113,12 @@ const a64::Gp TEMP_REG3 = a64::x11;
|
||||
const a64::Gp SCRATCH_REG1 = a64::x12;
|
||||
const a64::Gp SCRATCH_REG2 = a64::x13;
|
||||
|
||||
// Only to be used in an opcode level function. Should not be used in helper functions
|
||||
const a64::Gp FUNC_SCRATCH_REG = a64::x15;
|
||||
|
||||
// Temporary memory calculation register, should not be used outside of functions that calculate memory addresses
|
||||
const a64::Gp MEM_SCRATCH_REG = a64::x14;
|
||||
|
||||
// Only to be used in an opcode level function. Should not be used in helper functions
|
||||
const a64::Gp FUNC_SCRATCH_REG = a64::x15;
|
||||
|
||||
const a64::Vec TEMPF_REG1 = a64::d16;
|
||||
const a64::Vec TEMPF_REG2 = a64::d17;
|
||||
const a64::Vec TEMPF_REG3 = a64::d18;
|
||||
@ -124,6 +193,111 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// helper functions
|
||||
|
||||
a64::Vec select_register(a64::Vec const ®, uint32_t regsize)
|
||||
{
|
||||
if (regsize == 4)
|
||||
return reg.s();
|
||||
return reg.d();
|
||||
}
|
||||
|
||||
a64::Gp select_register(a64::Gp const ®, uint32_t regsize)
|
||||
{
|
||||
if (regsize == 4)
|
||||
return reg.w();
|
||||
return reg.x();
|
||||
}
|
||||
|
||||
bool is_valid_immediate_mask(uint64_t val, size_t bytes)
|
||||
{
|
||||
// all zeros and all ones aren't allowed, and disallow any value with bits outside of the max bit range
|
||||
if (val == 0 || val == make_bitmask<uint64_t>(bytes * 8))
|
||||
return false;
|
||||
|
||||
uint32_t head = 64 - count_leading_zeros_64(val);
|
||||
if (head >= (bytes * 8))
|
||||
return false;
|
||||
|
||||
uint32_t tail = 0;
|
||||
while (tail < head)
|
||||
{
|
||||
if (BIT(val, tail))
|
||||
break;
|
||||
tail++;
|
||||
}
|
||||
|
||||
return population_count_64(val) == head - tail;
|
||||
}
|
||||
|
||||
bool is_valid_immediate(uint64_t val, size_t bits)
|
||||
{
|
||||
assert(bits < 64);
|
||||
return val < (uint64_t(1) << bits);
|
||||
}
|
||||
|
||||
bool is_valid_immediate_signed(int64_t val, size_t bits)
|
||||
{
|
||||
return util::sext(val, bits) == val;
|
||||
}
|
||||
|
||||
bool emit_add_optimized(a64::Assembler &a, const a64::Gp &dst, const a64::Gp &src, int64_t val)
|
||||
{
|
||||
// If the bottom 12 bits are 0s then an optimized form can be used if the remaining bits are <= 12
|
||||
if (is_valid_immediate(val, 12) || ((val & 0xfff) == 0 && is_valid_immediate(val >> 12, 12)))
|
||||
{
|
||||
a.add(dst, src, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool emit_sub_optimized(a64::Assembler &a, const a64::Gp &dst, const a64::Gp &src, int64_t val)
|
||||
{
|
||||
if (val < 0)
|
||||
val = -val;
|
||||
|
||||
// If the bottom 12 bits are 0s then an optimized form can be used if the remaining bits are <= 12
|
||||
if (is_valid_immediate(val, 12) || ((val & 0xfff) == 0 && is_valid_immediate(val >> 12, 12)))
|
||||
{
|
||||
a.sub(dst, src, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
arm::Mem get_mem_absolute(a64::Assembler &a, const void *ptr)
|
||||
{
|
||||
const uint64_t codeoffs = a.code()->baseAddress() + a.offset();
|
||||
const int64_t reloffs = codeoffs - (int64_t)ptr;
|
||||
if (is_valid_immediate_signed(reloffs, 21))
|
||||
{
|
||||
a.adr(MEM_SCRATCH_REG, ptr);
|
||||
return arm::Mem(MEM_SCRATCH_REG);
|
||||
}
|
||||
|
||||
const uint64_t pagebase = codeoffs & ~make_bitmask<uint64_t>(12);
|
||||
const int64_t pagerel = (int64_t)ptr - pagebase;
|
||||
if (is_valid_immediate_signed(pagerel, 33))
|
||||
{
|
||||
const uint64_t targetpage = (uint64_t)ptr & ~make_bitmask<uint64_t>(12);
|
||||
const uint64_t pageoffs = (uint64_t)ptr & util::make_bitmask<uint64_t>(12);
|
||||
|
||||
a.adrp(MEM_SCRATCH_REG, targetpage);
|
||||
|
||||
if (is_valid_immediate_signed(pageoffs, 9))
|
||||
return arm::Mem(MEM_SCRATCH_REG, pageoffs);
|
||||
else if (emit_add_optimized(a, MEM_SCRATCH_REG, MEM_SCRATCH_REG, pageoffs))
|
||||
return arm::Mem(MEM_SCRATCH_REG);
|
||||
}
|
||||
|
||||
a.mov(MEM_SCRATCH_REG, ptr);
|
||||
return arm::Mem(MEM_SCRATCH_REG);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
@ -161,67 +335,67 @@ const drcbe_arm64::opcode_table_entry drcbe_arm64::s_opcode_table_source[] =
|
||||
{ uml::OP_RESTORE, &drcbe_arm64::op_restore }, // 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<a64::Inst::kIdAdds> }, // ADD dst,src1,src2[,f]
|
||||
{ uml::OP_ADDC, &drcbe_arm64::op_add<a64::Inst::kIdAdcs> }, // ADDC dst,src1,src2[,f]
|
||||
{ uml::OP_SUB, &drcbe_arm64::op_sub<a64::Inst::kIdSubs> }, // SUB dst,src1,src2[,f]
|
||||
{ uml::OP_SUBB, &drcbe_arm64::op_sub<a64::Inst::kIdSbcs> }, // SUBB dst,src1,src2[,f]
|
||||
{ uml::OP_CMP, &drcbe_arm64::op_cmp }, // CMP src1,src2[,f]
|
||||
{ uml::OP_MULU, &drcbe_arm64::op_mulu }, // MULU dst,edst,src1,src2[,f]
|
||||
{ uml::OP_MULULW, &drcbe_arm64::op_mululw }, // MULULW dst,src1,src2[,f]
|
||||
{ uml::OP_MULS, &drcbe_arm64::op_muls }, // MULS dst,edst,src1,src2[,f]
|
||||
{ uml::OP_MULSLW, &drcbe_arm64::op_mulslw }, // MULSLW dst,src1,src2[,f]
|
||||
{ uml::OP_DIVU, &drcbe_arm64::op_div<a64::Inst::kIdUdiv> }, // DIVU dst,edst,src1,src2[,f]
|
||||
{ uml::OP_DIVS, &drcbe_arm64::op_div<a64::Inst::kIdSdiv> }, // DIVS dst,edst,src1,src2[,f]
|
||||
{ uml::OP_AND, &drcbe_arm64::op_and }, // AND dst,src1,src2[,f]
|
||||
{ uml::OP_TEST, &drcbe_arm64::op_test }, // TEST src1,src2[,f]
|
||||
{ uml::OP_OR, &drcbe_arm64::op_or }, // OR dst,src1,src2[,f]
|
||||
{ uml::OP_XOR, &drcbe_arm64::op_xor }, // XOR dst,src1,src2[,f]
|
||||
{ uml::OP_LZCNT, &drcbe_arm64::op_lzcnt }, // LZCNT dst,src[,f]
|
||||
{ uml::OP_TZCNT, &drcbe_arm64::op_tzcnt }, // TZCNT dst,src[,f]
|
||||
{ uml::OP_BSWAP, &drcbe_arm64::op_bswap }, // BSWAP dst,src
|
||||
{ uml::OP_SHL, &drcbe_arm64::op_shift<a64::Inst::kIdLsl> }, // SHL dst,src,count[,f]
|
||||
{ uml::OP_SHR, &drcbe_arm64::op_shift<a64::Inst::kIdLsr> }, // SHR dst,src,count[,f]
|
||||
{ uml::OP_SAR, &drcbe_arm64::op_shift<a64::Inst::kIdAsr> }, // SAR dst,src,count[,f]
|
||||
{ uml::OP_ROL, &drcbe_arm64::op_rol }, // ROL dst,src,count[,f]
|
||||
{ uml::OP_ROLC, &drcbe_arm64::op_rolc }, // ROLC dst,src,count[,f]
|
||||
{ uml::OP_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<a64::Inst::kIdAdds> }, // ADD dst,src1,src2[,f]
|
||||
{ uml::OP_ADDC, &drcbe_arm64::op_add<a64::Inst::kIdAdcs> }, // ADDC dst,src1,src2[,f]
|
||||
{ uml::OP_SUB, &drcbe_arm64::op_sub<a64::Inst::kIdSubs> }, // SUB dst,src1,src2[,f]
|
||||
{ uml::OP_SUBB, &drcbe_arm64::op_sub<a64::Inst::kIdSbcs> }, // SUBB dst,src1,src2[,f]
|
||||
{ uml::OP_CMP, &drcbe_arm64::op_cmp }, // CMP src1,src2[,f]
|
||||
{ uml::OP_MULU, &drcbe_arm64::op_mulu }, // MULU dst,edst,src1,src2[,f]
|
||||
{ uml::OP_MULULW, &drcbe_arm64::op_mululw }, // MULULW dst,src1,src2[,f]
|
||||
{ uml::OP_MULS, &drcbe_arm64::op_muls }, // MULS dst,edst,src1,src2[,f]
|
||||
{ uml::OP_MULSLW, &drcbe_arm64::op_mulslw }, // MULSLW dst,src1,src2[,f]
|
||||
{ uml::OP_DIVU, &drcbe_arm64::op_div<a64::Inst::kIdUdiv> }, // DIVU dst,edst,src1,src2[,f]
|
||||
{ uml::OP_DIVS, &drcbe_arm64::op_div<a64::Inst::kIdSdiv> }, // DIVS dst,edst,src1,src2[,f]
|
||||
{ uml::OP_AND, &drcbe_arm64::op_and }, // AND dst,src1,src2[,f]
|
||||
{ uml::OP_TEST, &drcbe_arm64::op_test }, // TEST src1,src2[,f]
|
||||
{ uml::OP_OR, &drcbe_arm64::op_or }, // OR dst,src1,src2[,f]
|
||||
{ uml::OP_XOR, &drcbe_arm64::op_xor }, // XOR dst,src1,src2[,f]
|
||||
{ uml::OP_LZCNT, &drcbe_arm64::op_lzcnt }, // LZCNT dst,src[,f]
|
||||
{ uml::OP_TZCNT, &drcbe_arm64::op_tzcnt }, // TZCNT dst,src[,f]
|
||||
{ uml::OP_BSWAP, &drcbe_arm64::op_bswap }, // BSWAP dst,src
|
||||
{ uml::OP_SHL, &drcbe_arm64::op_shift<a64::Inst::kIdLsl> }, // SHL dst,src,count[,f]
|
||||
{ uml::OP_SHR, &drcbe_arm64::op_shift<a64::Inst::kIdLsr> }, // SHR dst,src,count[,f]
|
||||
{ uml::OP_SAR, &drcbe_arm64::op_shift<a64::Inst::kIdAsr> }, // SAR dst,src,count[,f]
|
||||
{ uml::OP_ROL, &drcbe_arm64::op_rol }, // ROL dst,src,count[,f]
|
||||
{ uml::OP_ROLC, &drcbe_arm64::op_rolc }, // ROLC dst,src,count[,f]
|
||||
{ uml::OP_ROR, &drcbe_arm64::op_shift<a64::Inst::kIdRor> }, // ROR dst,src,count[,f]
|
||||
{ uml::OP_RORC, &drcbe_arm64::op_rorc }, // RORC dst,src,count[,f]
|
||||
{ uml::OP_RORC, &drcbe_arm64::op_rorc }, // RORC dst,src,count[,f]
|
||||
|
||||
// Floating Point Operations
|
||||
{ uml::OP_FLOAD, &drcbe_arm64::op_fload }, // FLOAD dst,base,index
|
||||
{ uml::OP_FSTORE, &drcbe_arm64::op_fstore }, // FSTORE base,index,src
|
||||
{ uml::OP_FREAD, &drcbe_arm64::op_fread }, // FREAD dst,space,src1
|
||||
{ uml::OP_FWRITE, &drcbe_arm64::op_fwrite }, // FWRITE space,dst,src1
|
||||
{ uml::OP_FMOV, &drcbe_arm64::op_fmov }, // FMOV dst,src1[,c]
|
||||
{ uml::OP_FTOINT, &drcbe_arm64::op_ftoint }, // FTOINT dst,src1,size,round
|
||||
{ uml::OP_FFRINT, &drcbe_arm64::op_ffrint }, // FFRINT dst,src1,size
|
||||
{ uml::OP_FFRFLT, &drcbe_arm64::op_ffrflt }, // FFRFLT dst,src1,size
|
||||
{ uml::OP_FRNDS, &drcbe_arm64::op_frnds }, // FRNDS dst,src1
|
||||
{ uml::OP_FADD, &drcbe_arm64::op_float_alu<a64::Inst::kIdFadd_v> }, // FADD dst,src1,src2
|
||||
{ uml::OP_FSUB, &drcbe_arm64::op_float_alu<a64::Inst::kIdFsub_v> }, // FSUB dst,src1,src2
|
||||
{ uml::OP_FCMP, &drcbe_arm64::op_fcmp }, // FCMP src1,src2
|
||||
{ uml::OP_FMUL, &drcbe_arm64::op_float_alu<a64::Inst::kIdFmul_v> }, // FMUL dst,src1,src2
|
||||
{ uml::OP_FDIV, &drcbe_arm64::op_float_alu<a64::Inst::kIdFdiv_v> }, // FDIV dst,src1,src2
|
||||
{ uml::OP_FNEG, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFneg_v> }, // FNEG dst,src1
|
||||
{ uml::OP_FABS, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFabs_v> }, // FABS dst,src1
|
||||
{ uml::OP_FSQRT, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFsqrt_v> }, // FSQRT dst,src1
|
||||
{ uml::OP_FRECIP, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFrecpe_v> }, // FRECIP dst,src1
|
||||
{ uml::OP_FRSQRT, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFrsqrte_v> }, // FRSQRT dst,src1
|
||||
{ uml::OP_FCOPYI, &drcbe_arm64::op_fcopyi }, // FCOPYI dst,src
|
||||
{ uml::OP_ICOPYF, &drcbe_arm64::op_icopyf } // ICOPYF dst,src
|
||||
{ uml::OP_FLOAD, &drcbe_arm64::op_fload }, // FLOAD dst,base,index
|
||||
{ uml::OP_FSTORE, &drcbe_arm64::op_fstore }, // FSTORE base,index,src
|
||||
{ uml::OP_FREAD, &drcbe_arm64::op_fread }, // FREAD dst,space,src1
|
||||
{ uml::OP_FWRITE, &drcbe_arm64::op_fwrite }, // FWRITE space,dst,src1
|
||||
{ uml::OP_FMOV, &drcbe_arm64::op_fmov }, // FMOV dst,src1[,c]
|
||||
{ uml::OP_FTOINT, &drcbe_arm64::op_ftoint }, // FTOINT dst,src1,size,round
|
||||
{ uml::OP_FFRINT, &drcbe_arm64::op_ffrint }, // FFRINT dst,src1,size
|
||||
{ uml::OP_FFRFLT, &drcbe_arm64::op_ffrflt }, // FFRFLT dst,src1,size
|
||||
{ uml::OP_FRNDS, &drcbe_arm64::op_frnds }, // FRNDS dst,src1
|
||||
{ uml::OP_FADD, &drcbe_arm64::op_float_alu<a64::Inst::kIdFadd_v> }, // FADD dst,src1,src2
|
||||
{ uml::OP_FSUB, &drcbe_arm64::op_float_alu<a64::Inst::kIdFsub_v> }, // FSUB dst,src1,src2
|
||||
{ uml::OP_FCMP, &drcbe_arm64::op_fcmp }, // FCMP src1,src2
|
||||
{ uml::OP_FMUL, &drcbe_arm64::op_float_alu<a64::Inst::kIdFmul_v> }, // FMUL dst,src1,src2
|
||||
{ uml::OP_FDIV, &drcbe_arm64::op_float_alu<a64::Inst::kIdFdiv_v> }, // FDIV dst,src1,src2
|
||||
{ uml::OP_FNEG, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFneg_v> }, // FNEG dst,src1
|
||||
{ uml::OP_FABS, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFabs_v> }, // FABS dst,src1
|
||||
{ uml::OP_FSQRT, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFsqrt_v> }, // FSQRT dst,src1
|
||||
{ uml::OP_FRECIP, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFrecpe_v> }, // FRECIP dst,src1
|
||||
{ uml::OP_FRSQRT, &drcbe_arm64::op_float_alu2<a64::Inst::kIdFrsqrte_v> }, // FRSQRT dst,src1
|
||||
{ uml::OP_FCOPYI, &drcbe_arm64::op_fcopyi }, // FCOPYI dst,src
|
||||
{ uml::OP_ICOPYF, &drcbe_arm64::op_icopyf } // ICOPYF dst,src
|
||||
};
|
||||
|
||||
drcbe_arm64::be_parameter::be_parameter(drcbe_arm64 &drcbe, const parameter ¶m, uint32_t allowed)
|
||||
@ -300,108 +474,6 @@ a64::Gp drcbe_arm64::be_parameter::select_register(a64::Gp const ®, uint32_t
|
||||
return reg.x();
|
||||
}
|
||||
|
||||
a64::Vec drcbe_arm64::select_register(a64::Vec const ®, uint32_t regsize) const
|
||||
{
|
||||
if (regsize == 4)
|
||||
return reg.s();
|
||||
return reg.d();
|
||||
}
|
||||
|
||||
a64::Gp drcbe_arm64::select_register(a64::Gp const ®, uint32_t regsize) const
|
||||
{
|
||||
if (regsize == 4)
|
||||
return reg.w();
|
||||
return reg.x();
|
||||
}
|
||||
|
||||
bool drcbe_arm64::is_valid_immediate_mask(uint64_t val, size_t bytes)
|
||||
{
|
||||
// all zeros and all ones aren't allowed, and disallow any value with bits outside of the max bit range
|
||||
if (val == 0 || val == make_bitmask<uint64_t>(bytes * 8))
|
||||
return false;
|
||||
|
||||
uint32_t head = 64 - count_leading_zeros_64(val);
|
||||
if (head >= (bytes * 8))
|
||||
return false;
|
||||
|
||||
uint32_t tail = 0;
|
||||
while (tail < head)
|
||||
{
|
||||
if (BIT(val, tail))
|
||||
break;
|
||||
tail++;
|
||||
}
|
||||
|
||||
return population_count_64(val) == head - tail;
|
||||
}
|
||||
|
||||
bool drcbe_arm64::is_valid_immediate(uint64_t val, size_t bits)
|
||||
{
|
||||
assert(bits < 64);
|
||||
return val < (uint64_t(1) << bits);
|
||||
}
|
||||
|
||||
bool drcbe_arm64::is_valid_immediate_signed(int64_t val, size_t bits)
|
||||
{
|
||||
return util::sext(val, bits) == val;
|
||||
}
|
||||
|
||||
arm::Mem drcbe_arm64::get_mem_absolute(a64::Assembler &a, const void *ptr) const
|
||||
{
|
||||
const uint64_t codeoffs = a.code()->baseAddress() + a.offset();
|
||||
const int64_t reloffs = codeoffs - (int64_t)ptr;
|
||||
if (is_valid_immediate_signed(reloffs, 21))
|
||||
{
|
||||
a.adr(MEM_SCRATCH_REG, ptr);
|
||||
return arm::Mem(MEM_SCRATCH_REG);
|
||||
}
|
||||
|
||||
const uint64_t pagebase = codeoffs & ~make_bitmask<uint64_t>(12);
|
||||
const int64_t pagerel = (int64_t)ptr - pagebase;
|
||||
if (is_valid_immediate_signed(pagerel, 33))
|
||||
{
|
||||
const uint64_t targetpage = (uint64_t)ptr & ~make_bitmask<uint64_t>(12);
|
||||
const uint64_t pageoffs = (uint64_t)ptr & util::make_bitmask<uint64_t>(12);
|
||||
|
||||
a.adrp(MEM_SCRATCH_REG, targetpage);
|
||||
|
||||
if (is_valid_immediate_signed(pageoffs, 9))
|
||||
return arm::Mem(MEM_SCRATCH_REG, pageoffs);
|
||||
else if (emit_add_optimized(a, MEM_SCRATCH_REG, MEM_SCRATCH_REG, pageoffs))
|
||||
return arm::Mem(MEM_SCRATCH_REG);
|
||||
}
|
||||
|
||||
a.mov(MEM_SCRATCH_REG, ptr);
|
||||
return arm::Mem(MEM_SCRATCH_REG);
|
||||
}
|
||||
|
||||
bool drcbe_arm64::emit_add_optimized(a64::Assembler &a, const a64::Gp &dst, const a64::Gp &src, int64_t val) const
|
||||
{
|
||||
// If the bottom 12 bits are 0s then an optimized form can be used if the remaining bits are <= 12
|
||||
if (is_valid_immediate(val, 12) || ((val & 0xfff) == 0 && is_valid_immediate(val >> 12, 12)))
|
||||
{
|
||||
a.add(dst, src, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool drcbe_arm64::emit_sub_optimized(a64::Assembler &a, const a64::Gp &dst, const a64::Gp &src, int64_t val) const
|
||||
{
|
||||
if (val < 0)
|
||||
val = -val;
|
||||
|
||||
// If the bottom 12 bits are 0s then an optimized form can be used if the remaining bits are <= 12
|
||||
if (is_valid_immediate(val, 12) || ((val & 0xfff) == 0 && is_valid_immediate(val >> 12, 12)))
|
||||
{
|
||||
a.sub(dst, src, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void drcbe_arm64::get_imm_relative(a64::Assembler &a, const a64::Gp ®, const uint64_t ptr) const
|
||||
{
|
||||
// If a value can be expressed relative to the base register then it's worth using it instead of a mov
|
||||
@ -765,7 +837,7 @@ void drcbe_arm64::store_unordered(a64::Assembler &a) const
|
||||
|
||||
void drcbe_arm64::get_unordered(a64::Assembler &a, const a64::Gp ®) const
|
||||
{
|
||||
get_shifted_bit(a, reg.x(), FLAGS_REG, 1, 4);
|
||||
a.ubfx(reg.x(), FLAGS_REG, 4, 1);
|
||||
}
|
||||
|
||||
void drcbe_arm64::store_carry_reg(a64::Assembler &a, const a64::Gp ®) const
|
||||
@ -802,12 +874,6 @@ void drcbe_arm64::load_carry(a64::Assembler &a, bool inverted) const
|
||||
a.msr(a64::Predicate::SysReg::kNZCV, SCRATCH_REG1);
|
||||
}
|
||||
|
||||
void drcbe_arm64::get_shifted_bit(a64::Assembler &a, const a64::Gp &dst, const a64::Gp &src, uint32_t bits, uint32_t shift) const
|
||||
{
|
||||
a.lsr(dst.x(), src.x(), shift);
|
||||
a.and_(dst.x(), dst.x(), bits);
|
||||
}
|
||||
|
||||
void drcbe_arm64::calculate_carry_shift_left(a64::Assembler &a, const a64::Gp ®, const a64::Gp &shift, int maxBits) const
|
||||
{
|
||||
Label calc = a.newLabel();
|
||||
@ -890,11 +956,6 @@ drcbe_arm64::drcbe_arm64(drcuml_state &drcuml, device_t &device, drc_cache &cach
|
||||
, m_baseptr(cache.near() + 0x80)
|
||||
, m_near(*(near_state *)cache.alloc_near(sizeof(m_near)))
|
||||
{
|
||||
// get pointers to C functions we need to call
|
||||
using debugger_hook_func = void (*)(device_debug *, offs_t);
|
||||
static const debugger_hook_func debugger_inst_hook = [] (device_debug *dbg, offs_t pc) { dbg->instruction_hook(pc); };
|
||||
m_near.debug_cpu_instruction_hook = (uint8_t *)debugger_inst_hook;
|
||||
m_near.drcmap_get_value = (uint8_t *)&drc_map_variables::static_get_value;
|
||||
m_near.emulated_flags = 0;
|
||||
|
||||
// build the opcode table (static but it doesn't hurt to regenerate it)
|
||||
@ -907,38 +968,18 @@ drcbe_arm64::drcbe_arm64(drcuml_state &drcuml, device_t &device, drc_cache &cach
|
||||
m_log_asmjit = fopen(std::string("drcbearm64_asmjit_").append(device.shortname()).append(".asm").c_str(), "w");
|
||||
}
|
||||
|
||||
// resolve the actual addresses of the address space handlers
|
||||
auto const resolve_accessor =
|
||||
[] (resolved_handler &handler, address_space &space, auto accessor)
|
||||
{
|
||||
auto const [entrypoint, adjusted] = util::resolve_member_function(accessor, space);
|
||||
handler.func = reinterpret_cast<uint8_t *>(entrypoint);
|
||||
handler.obj = adjusted;
|
||||
};
|
||||
|
||||
// resolve the actual addresses of member functions we need to call
|
||||
m_drcmap_get_value.set(m_map, &drc_map_variables::get_value);
|
||||
if (!m_drcmap_get_value)
|
||||
{
|
||||
m_drcmap_get_value.obj = uintptr_t(&m_map);
|
||||
m_drcmap_get_value.func = reinterpret_cast<uint8_t *>(uintptr_t(&drc_map_variables::static_get_value));
|
||||
}
|
||||
m_resolved_accessors.resize(m_space.size());
|
||||
for (int space = 0; m_space.size() > space; ++space)
|
||||
{
|
||||
if (m_space[space])
|
||||
{
|
||||
resolve_accessor(m_resolved_accessors[space].read_byte, *m_space[space], static_cast<u8 (address_space::*)(offs_t) >(&address_space::read_byte));
|
||||
resolve_accessor(m_resolved_accessors[space].read_byte_masked, *m_space[space], static_cast<u8 (address_space::*)(offs_t, u8) >(&address_space::read_byte));
|
||||
resolve_accessor(m_resolved_accessors[space].read_word, *m_space[space], static_cast<u16 (address_space::*)(offs_t) >(&address_space::read_word));
|
||||
resolve_accessor(m_resolved_accessors[space].read_word_masked, *m_space[space], static_cast<u16 (address_space::*)(offs_t, u16)>(&address_space::read_word));
|
||||
resolve_accessor(m_resolved_accessors[space].read_dword, *m_space[space], static_cast<u32 (address_space::*)(offs_t) >(&address_space::read_dword));
|
||||
resolve_accessor(m_resolved_accessors[space].read_dword_masked, *m_space[space], static_cast<u32 (address_space::*)(offs_t, u32)>(&address_space::read_dword));
|
||||
resolve_accessor(m_resolved_accessors[space].read_qword, *m_space[space], static_cast<u64 (address_space::*)(offs_t) >(&address_space::read_qword));
|
||||
resolve_accessor(m_resolved_accessors[space].read_qword_masked, *m_space[space], static_cast<u64 (address_space::*)(offs_t, u64)>(&address_space::read_qword));
|
||||
|
||||
resolve_accessor(m_resolved_accessors[space].write_byte, *m_space[space], static_cast<void (address_space::*)(offs_t, u8) >(&address_space::write_byte));
|
||||
resolve_accessor(m_resolved_accessors[space].write_byte_masked, *m_space[space], static_cast<void (address_space::*)(offs_t, u8, u8) >(&address_space::write_byte));
|
||||
resolve_accessor(m_resolved_accessors[space].write_word, *m_space[space], static_cast<void (address_space::*)(offs_t, u16) >(&address_space::write_word));
|
||||
resolve_accessor(m_resolved_accessors[space].write_word_masked, *m_space[space], static_cast<void (address_space::*)(offs_t, u16, u16)>(&address_space::write_word));
|
||||
resolve_accessor(m_resolved_accessors[space].write_dword, *m_space[space], static_cast<void (address_space::*)(offs_t, u32) >(&address_space::write_dword));
|
||||
resolve_accessor(m_resolved_accessors[space].write_dword_masked, *m_space[space], static_cast<void (address_space::*)(offs_t, u32, u32)>(&address_space::write_dword));
|
||||
resolve_accessor(m_resolved_accessors[space].write_qword, *m_space[space], static_cast<void (address_space::*)(offs_t, u64) >(&address_space::write_qword));
|
||||
resolve_accessor(m_resolved_accessors[space].write_qword_masked, *m_space[space], static_cast<void (address_space::*)(offs_t, u64, u64)>(&address_space::write_qword));
|
||||
}
|
||||
m_resolved_accessors[space].set(*m_space[space]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1048,6 +1089,19 @@ int drcbe_arm64::execute(code_handle &entry)
|
||||
|
||||
void drcbe_arm64::generate(drcuml_block &block, const instruction *instlist, uint32_t numinst)
|
||||
{
|
||||
// do this here because device.debug() isn't initialised at construction time
|
||||
if (!m_debug_cpu_instruction_hook && (m_device.machine().debug_flags & DEBUG_FLAG_ENABLED))
|
||||
{
|
||||
m_debug_cpu_instruction_hook.set(*m_device.debug(), &device_debug::instruction_hook);
|
||||
if (!m_debug_cpu_instruction_hook)
|
||||
{
|
||||
m_debug_cpu_instruction_hook.obj = uintptr_t(m_device.debug());
|
||||
using debugger_hook_func = void (*)(device_debug *, offs_t);
|
||||
static const auto debugger_inst_hook = [] (device_debug *dbg, offs_t pc) { dbg->instruction_hook(pc); };
|
||||
m_debug_cpu_instruction_hook.func = reinterpret_cast<uint8_t *>(uintptr_t(debugger_hook_func(debugger_inst_hook)));
|
||||
}
|
||||
}
|
||||
|
||||
// tell all of our utility objects that a block is beginning
|
||||
m_hash.block_begin(block, instlist, numinst);
|
||||
m_map.block_begin(block);
|
||||
@ -1233,11 +1287,10 @@ void drcbe_arm64::op_debug(a64::Assembler &a, const uml::instruction &inst)
|
||||
emit_ldr_mem(a, temp, &m_device.machine().debug_flags);
|
||||
a.tbz(temp, 1, skip); // DEBUG_FLAG_CALL_HOOK
|
||||
|
||||
get_imm_relative(a, REG_PARAM1, (uintptr_t)m_device.debug());
|
||||
get_imm_relative(a, REG_PARAM1, m_debug_cpu_instruction_hook.obj);
|
||||
mov_reg_param(a, 4, REG_PARAM2, pcp);
|
||||
|
||||
emit_ldr_mem(a, TEMP_REG2, &m_near.debug_cpu_instruction_hook);
|
||||
a.blr(TEMP_REG2);
|
||||
call_arm_addr(a, m_debug_cpu_instruction_hook.func);
|
||||
|
||||
a.bind(skip);
|
||||
}
|
||||
@ -1556,13 +1609,11 @@ void drcbe_arm64::op_recover(a64::Assembler &a, const uml::instruction &inst)
|
||||
|
||||
be_parameter dstp(*this, inst.param(0), PTYPE_MR);
|
||||
|
||||
get_imm_relative(a, REG_PARAM1, (uintptr_t)&m_map);
|
||||
get_imm_relative(a, REG_PARAM1, m_drcmap_get_value.obj);
|
||||
a.ldr(REG_PARAM2, arm::Mem(a64::x29, -8)); // saved LR (x30) from first level CALLH/EXH or failed hash jump
|
||||
a.mov(REG_PARAM3, inst.param(1).mapvar());
|
||||
|
||||
emit_ldr_mem(a, TEMP_REG1, &m_near.drcmap_get_value);
|
||||
|
||||
a.blr(TEMP_REG1);
|
||||
call_arm_addr(a, m_drcmap_get_value.func);
|
||||
|
||||
mov_param_reg(a, inst.size(), dstp, REG_PARAM1);
|
||||
}
|
||||
@ -2007,7 +2058,7 @@ void drcbe_arm64::op_read(a64::Assembler &a, const uml::instruction &inst)
|
||||
|
||||
if (spacesizep.size() == SIZE_BYTE)
|
||||
{
|
||||
if (resolved.read_byte.func)
|
||||
if (resolved.read_byte)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.read_byte.obj);
|
||||
call_arm_addr(a, resolved.read_byte.func);
|
||||
@ -2021,7 +2072,7 @@ void drcbe_arm64::op_read(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_WORD)
|
||||
{
|
||||
if (resolved.read_word.func)
|
||||
if (resolved.read_word)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.read_word.obj);
|
||||
call_arm_addr(a, resolved.read_word.func);
|
||||
@ -2035,7 +2086,7 @@ void drcbe_arm64::op_read(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_DWORD)
|
||||
{
|
||||
if (resolved.read_dword.func)
|
||||
if (resolved.read_dword)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.read_dword.obj);
|
||||
call_arm_addr(a, resolved.read_dword.func);
|
||||
@ -2049,7 +2100,7 @@ void drcbe_arm64::op_read(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_QWORD)
|
||||
{
|
||||
if (resolved.read_qword.func)
|
||||
if (resolved.read_qword)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.read_qword.obj);
|
||||
call_arm_addr(a, resolved.read_qword.func);
|
||||
@ -2085,7 +2136,7 @@ void drcbe_arm64::op_readm(a64::Assembler &a, const uml::instruction &inst)
|
||||
|
||||
if (spacesizep.size() == SIZE_BYTE)
|
||||
{
|
||||
if (resolved.read_byte_masked.func)
|
||||
if (resolved.read_byte_masked)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.read_byte_masked.obj);
|
||||
call_arm_addr(a, resolved.read_byte_masked.func);
|
||||
@ -2099,7 +2150,7 @@ void drcbe_arm64::op_readm(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_WORD)
|
||||
{
|
||||
if (resolved.read_word_masked.func)
|
||||
if (resolved.read_word_masked)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.read_word_masked.obj);
|
||||
call_arm_addr(a, resolved.read_word_masked.func);
|
||||
@ -2113,7 +2164,7 @@ void drcbe_arm64::op_readm(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_DWORD)
|
||||
{
|
||||
if (resolved.read_dword_masked.func)
|
||||
if (resolved.read_dword_masked)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.read_dword_masked.obj);
|
||||
call_arm_addr(a, resolved.read_dword_masked.func);
|
||||
@ -2127,7 +2178,7 @@ void drcbe_arm64::op_readm(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_QWORD)
|
||||
{
|
||||
if (resolved.read_qword_masked.func)
|
||||
if (resolved.read_qword_masked)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.read_qword_masked.obj);
|
||||
call_arm_addr(a, resolved.read_qword_masked.func);
|
||||
@ -2162,7 +2213,7 @@ void drcbe_arm64::op_write(a64::Assembler &a, const uml::instruction &inst)
|
||||
|
||||
if (spacesizep.size() == SIZE_BYTE)
|
||||
{
|
||||
if (resolved.write_byte.func)
|
||||
if (resolved.write_byte)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.write_byte.obj);
|
||||
call_arm_addr(a, resolved.write_byte.func);
|
||||
@ -2176,7 +2227,7 @@ void drcbe_arm64::op_write(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_WORD)
|
||||
{
|
||||
if (resolved.write_word.func)
|
||||
if (resolved.write_word)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.write_word.obj);
|
||||
call_arm_addr(a, resolved.write_word.func);
|
||||
@ -2190,7 +2241,7 @@ void drcbe_arm64::op_write(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_DWORD)
|
||||
{
|
||||
if (resolved.write_dword.func)
|
||||
if (resolved.write_dword)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.write_dword.obj);
|
||||
call_arm_addr(a, resolved.write_dword.func);
|
||||
@ -2204,7 +2255,7 @@ void drcbe_arm64::op_write(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_QWORD)
|
||||
{
|
||||
if (resolved.write_qword.func)
|
||||
if (resolved.write_qword)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.write_qword.obj);
|
||||
call_arm_addr(a, resolved.write_qword.func);
|
||||
@ -2240,7 +2291,7 @@ void drcbe_arm64::op_writem(a64::Assembler &a, const uml::instruction &inst)
|
||||
|
||||
if (spacesizep.size() == SIZE_BYTE)
|
||||
{
|
||||
if (resolved.write_byte_masked.func)
|
||||
if (resolved.write_byte_masked)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.write_byte_masked.obj);
|
||||
call_arm_addr(a, resolved.write_byte_masked.func);
|
||||
@ -2254,7 +2305,7 @@ void drcbe_arm64::op_writem(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_WORD)
|
||||
{
|
||||
if (resolved.write_word_masked.func)
|
||||
if (resolved.write_word_masked)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.write_word_masked.obj);
|
||||
call_arm_addr(a, resolved.write_word_masked.func);
|
||||
@ -2268,7 +2319,7 @@ void drcbe_arm64::op_writem(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_DWORD)
|
||||
{
|
||||
if (resolved.write_dword_masked.func)
|
||||
if (resolved.write_dword_masked)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.write_dword_masked.obj);
|
||||
call_arm_addr(a, resolved.write_dword_masked.func);
|
||||
@ -2282,7 +2333,7 @@ void drcbe_arm64::op_writem(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_QWORD)
|
||||
{
|
||||
if (resolved.write_qword_masked.func)
|
||||
if (resolved.write_qword_masked)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.write_qword_masked.obj);
|
||||
call_arm_addr(a, resolved.write_qword_masked.func);
|
||||
@ -2676,12 +2727,12 @@ void drcbe_arm64::op_rolins(a64::Assembler &a, const uml::instruction &inst)
|
||||
|
||||
if (is_right_aligned || is_contiguous)
|
||||
{
|
||||
uint32_t rot = 0;
|
||||
uint32_t lsb = 0;
|
||||
|
||||
dst = can_use_dst_reg ? dstp.select_register(SCRATCH_REG1, inst.size()) : select_register(SCRATCH_REG1, inst.size());
|
||||
mov_reg_param(a, inst.size(), dst, dstp);
|
||||
|
||||
uint32_t rot = 0;
|
||||
uint32_t lsb = 0;
|
||||
|
||||
if (is_right_aligned)
|
||||
{
|
||||
// Optimize a contiguous right-aligned mask
|
||||
@ -2707,10 +2758,6 @@ void drcbe_arm64::op_rolins(a64::Assembler &a, const uml::instruction &inst)
|
||||
result = rotr_64(srcp.immediate(), rot);
|
||||
|
||||
a.mov(src, result);
|
||||
|
||||
a.bfi(dst, src, lsb, pop);
|
||||
|
||||
optimized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -2718,11 +2765,11 @@ void drcbe_arm64::op_rolins(a64::Assembler &a, const uml::instruction &inst)
|
||||
|
||||
if (rot > 0)
|
||||
a.ror(src, src, rot);
|
||||
|
||||
a.bfi(dst, src, lsb, pop);
|
||||
|
||||
optimized = true;
|
||||
}
|
||||
|
||||
a.bfi(dst, src, lsb, pop);
|
||||
|
||||
optimized = true;
|
||||
}
|
||||
else if (srcp.is_immediate())
|
||||
{
|
||||
@ -3881,7 +3928,7 @@ void drcbe_arm64::op_fread(a64::Assembler &a, const uml::instruction &inst)
|
||||
|
||||
if (inst.size() == 4)
|
||||
{
|
||||
if (resolved.read_dword.func)
|
||||
if (resolved.read_dword)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.read_dword.obj);
|
||||
call_arm_addr(a, resolved.read_dword.func);
|
||||
@ -3897,7 +3944,7 @@ void drcbe_arm64::op_fread(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (inst.size() == 8)
|
||||
{
|
||||
if (resolved.read_qword.func)
|
||||
if (resolved.read_qword)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.read_qword.obj);
|
||||
call_arm_addr(a, resolved.read_qword.func);
|
||||
@ -3935,7 +3982,7 @@ void drcbe_arm64::op_fwrite(a64::Assembler &a, const uml::instruction &inst)
|
||||
|
||||
if (inst.size() == 4)
|
||||
{
|
||||
if (resolved.write_dword.func)
|
||||
if (resolved.write_dword)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.write_dword.obj);
|
||||
call_arm_addr(a, resolved.write_dword.func);
|
||||
@ -3949,7 +3996,7 @@ void drcbe_arm64::op_fwrite(a64::Assembler &a, const uml::instruction &inst)
|
||||
}
|
||||
else if (inst.size() == 8)
|
||||
{
|
||||
if (resolved.write_qword.func)
|
||||
if (resolved.write_qword)
|
||||
{
|
||||
get_imm_relative(a, REG_PARAM1, resolved.write_qword.obj);
|
||||
call_arm_addr(a, resolved.write_qword.func);
|
||||
|
@ -167,19 +167,8 @@ private:
|
||||
|
||||
|
||||
// helper functions
|
||||
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;
|
||||
|
||||
static bool is_valid_immediate(uint64_t val, size_t bits);
|
||||
static bool is_valid_immediate_signed(int64_t val, size_t bits);
|
||||
static bool is_valid_immediate_mask(uint64_t val, size_t bytes);
|
||||
|
||||
asmjit::arm::Mem get_mem_absolute(asmjit::a64::Assembler &a, const void *ptr) const;
|
||||
void get_imm_relative(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const uint64_t ptr) const;
|
||||
|
||||
bool emit_add_optimized(asmjit::a64::Assembler &a, const asmjit::a64::Gp &dst, const asmjit::a64::Gp &src, int64_t val) const;
|
||||
bool emit_sub_optimized(asmjit::a64::Assembler &a, const asmjit::a64::Gp &dst, const asmjit::a64::Gp &src, int64_t val) const;
|
||||
|
||||
void emit_ldr_str_base_mem(asmjit::a64::Assembler &a, asmjit::a64::Inst::Id opcode, const asmjit::a64::Reg ®, 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;
|
||||
@ -203,8 +192,6 @@ private:
|
||||
void get_unordered(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®) const;
|
||||
void check_unordered_condition(asmjit::a64::Assembler &a, uml::condition_t cond, asmjit::Label condition_met, bool not_equal) const;
|
||||
|
||||
void get_shifted_bit(asmjit::a64::Assembler &a, const asmjit::a64::Gp &dst, const asmjit::a64::Gp &src, uint32_t bits, uint32_t shift) const;
|
||||
|
||||
void calculate_carry_shift_left(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const asmjit::a64::Gp &shift, int maxBits) const;
|
||||
void calculate_carry_shift_left_imm(asmjit::a64::Assembler &a, const asmjit::a64::Gp ®, const int shift, int maxBits) const;
|
||||
|
||||
@ -238,9 +225,6 @@ private:
|
||||
|
||||
struct near_state
|
||||
{
|
||||
void *debug_cpu_instruction_hook;
|
||||
void *drcmap_get_value;
|
||||
|
||||
uint32_t emulated_flags;
|
||||
};
|
||||
near_state &m_near;
|
||||
@ -254,33 +238,12 @@ private:
|
||||
static const opcode_table_entry s_opcode_table_source[];
|
||||
static opcode_generate_func s_opcode_table[uml::OP_MAX];
|
||||
|
||||
struct resolved_handler { uintptr_t obj = 0; void *func = nullptr; };
|
||||
struct resolved_accessors
|
||||
{
|
||||
|
||||
resolved_handler read_byte;
|
||||
resolved_handler read_byte_masked;
|
||||
resolved_handler read_word;
|
||||
resolved_handler read_word_masked;
|
||||
resolved_handler read_dword;
|
||||
resolved_handler read_dword_masked;
|
||||
resolved_handler read_qword;
|
||||
resolved_handler read_qword_masked;
|
||||
|
||||
resolved_handler write_byte;
|
||||
resolved_handler write_byte_masked;
|
||||
resolved_handler write_word;
|
||||
resolved_handler write_word_masked;
|
||||
resolved_handler write_dword;
|
||||
resolved_handler write_dword_masked;
|
||||
resolved_handler write_qword;
|
||||
resolved_handler write_qword_masked;
|
||||
};
|
||||
using resolved_accessors_vector = std::vector<resolved_accessors>;
|
||||
resolved_accessors_vector m_resolved_accessors;
|
||||
resolved_member_function m_debug_cpu_instruction_hook;
|
||||
resolved_member_function m_drcmap_get_value;
|
||||
resolved_memory_accessors_vector m_resolved_accessors;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace drc
|
||||
|
||||
using drc::drcbe_arm64;
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace drc {
|
||||
|
||||
using namespace uml;
|
||||
|
||||
|
||||
@ -2436,3 +2438,5 @@ uint64_t drcbe_c::tzcount64(uint64_t value)
|
||||
}
|
||||
return 64;
|
||||
}
|
||||
|
||||
} // namespace drc
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "drcbeut.h"
|
||||
|
||||
|
||||
namespace drc {
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
@ -57,5 +58,8 @@ private:
|
||||
static uint64_t s_immediate_zero;
|
||||
};
|
||||
|
||||
} // namespace drc
|
||||
|
||||
using drc::drcbe_c;
|
||||
|
||||
#endif // MAME_CPU_DRCBEC_H
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "emu.h"
|
||||
#include "drcbeut.h"
|
||||
|
||||
namespace drc {
|
||||
|
||||
using namespace uml;
|
||||
|
||||
|
||||
@ -30,19 +32,19 @@ using namespace uml;
|
||||
// drc_hash_table - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
drc_hash_table::drc_hash_table(drc_cache &cache, uint32_t modes, uint8_t addrbits, uint8_t ignorebits)
|
||||
: m_cache(cache),
|
||||
m_modes(modes),
|
||||
m_nocodeptr(nullptr),
|
||||
m_l1bits((addrbits - ignorebits) / 2),
|
||||
m_l2bits((addrbits - ignorebits) - m_l1bits),
|
||||
m_l1shift(ignorebits + m_l2bits),
|
||||
m_l2shift(ignorebits),
|
||||
m_l1mask((1 << m_l1bits) - 1),
|
||||
m_l2mask((1 << m_l2bits) - 1),
|
||||
m_base(reinterpret_cast<drccodeptr ***>(cache.alloc(modes * sizeof(**m_base)))),
|
||||
m_emptyl1(nullptr),
|
||||
m_emptyl2(nullptr)
|
||||
drc_hash_table::drc_hash_table(drc_cache &cache, uint32_t modes, uint8_t addrbits, uint8_t ignorebits) :
|
||||
m_cache(cache),
|
||||
m_modes(modes),
|
||||
m_nocodeptr(nullptr),
|
||||
m_l1bits((addrbits - ignorebits) / 2),
|
||||
m_l2bits((addrbits - ignorebits) - m_l1bits),
|
||||
m_l1shift(ignorebits + m_l2bits),
|
||||
m_l2shift(ignorebits),
|
||||
m_l1mask((1 << m_l1bits) - 1),
|
||||
m_l2mask((1 << m_l2bits) - 1),
|
||||
m_base(reinterpret_cast<drccodeptr ***>(cache.alloc(modes * sizeof(**m_base)))),
|
||||
m_emptyl1(nullptr),
|
||||
m_emptyl2(nullptr)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
@ -577,3 +579,36 @@ void drc_label_list::oob_callback(drccodeptr *codeptr, void *param1, void *param
|
||||
label_fixup *fixup = reinterpret_cast<label_fixup *>(param1);
|
||||
fixup->m_callback(param2, fixup->m_label->m_codeptr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// RESOLVED MEMORY ACCESSORS
|
||||
//**************************************************************************
|
||||
|
||||
//-------------------------------------------------
|
||||
// set - bind to address space
|
||||
//-------------------------------------------------
|
||||
|
||||
void resolved_memory_accessors::set(address_space &space) noexcept
|
||||
{
|
||||
read_byte .set(space, static_cast<u8 (address_space::*)(offs_t) >(&address_space::read_byte));
|
||||
read_byte_masked .set(space, static_cast<u8 (address_space::*)(offs_t, u8) >(&address_space::read_byte));
|
||||
read_word .set(space, static_cast<u16 (address_space::*)(offs_t) >(&address_space::read_word));
|
||||
read_word_masked .set(space, static_cast<u16 (address_space::*)(offs_t, u16)>(&address_space::read_word));
|
||||
read_dword .set(space, static_cast<u32 (address_space::*)(offs_t) >(&address_space::read_dword));
|
||||
read_dword_masked .set(space, static_cast<u32 (address_space::*)(offs_t, u32)>(&address_space::read_dword));
|
||||
read_qword .set(space, static_cast<u64 (address_space::*)(offs_t) >(&address_space::read_qword));
|
||||
read_qword_masked .set(space, static_cast<u64 (address_space::*)(offs_t, u64)>(&address_space::read_qword));
|
||||
|
||||
write_byte .set(space, static_cast<void (address_space::*)(offs_t, u8) >(&address_space::write_byte));
|
||||
write_byte_masked .set(space, static_cast<void (address_space::*)(offs_t, u8, u8) >(&address_space::write_byte));
|
||||
write_word .set(space, static_cast<void (address_space::*)(offs_t, u16) >(&address_space::write_word));
|
||||
write_word_masked .set(space, static_cast<void (address_space::*)(offs_t, u16, u16)>(&address_space::write_word));
|
||||
write_dword .set(space, static_cast<void (address_space::*)(offs_t, u32) >(&address_space::write_dword));
|
||||
write_dword_masked .set(space, static_cast<void (address_space::*)(offs_t, u32, u32)>(&address_space::write_dword));
|
||||
write_qword .set(space, static_cast<void (address_space::*)(offs_t, u64) >(&address_space::write_qword));
|
||||
write_qword_masked .set(space, static_cast<void (address_space::*)(offs_t, u64, u64)>(&address_space::write_qword));
|
||||
}
|
||||
|
||||
} // namespace drc
|
||||
|
@ -15,6 +15,13 @@
|
||||
|
||||
#include "drcuml.h"
|
||||
|
||||
#include "mfpresolve.h"
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace drc {
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
@ -55,14 +62,14 @@ public:
|
||||
private:
|
||||
// internal state
|
||||
drc_cache & m_cache; // cache where allocations come from
|
||||
uint32_t m_modes; // number of modes supported
|
||||
uint32_t m_modes; // number of modes supported
|
||||
|
||||
drccodeptr m_nocodeptr; // pointer to code which will handle missing entries
|
||||
|
||||
uint8_t m_l1bits; // bits worth of entries in l1 hash tables
|
||||
uint8_t m_l2bits; // bits worth of entries in l2 hash tables
|
||||
uint8_t m_l1shift; // shift to apply to the PC to get the l1 hash entry
|
||||
uint8_t m_l2shift; // shift to apply to the PC to get the l2 hash entry
|
||||
uint8_t m_l1bits; // bits worth of entries in l1 hash tables
|
||||
uint8_t m_l2bits; // bits worth of entries in l2 hash tables
|
||||
uint8_t m_l1shift; // shift to apply to the PC to get the l1 hash entry
|
||||
uint8_t m_l2shift; // shift to apply to the PC to get the l2 hash entry
|
||||
offs_t m_l1mask; // mask to apply after shifting
|
||||
offs_t m_l2mask; // mask to apply after shifting
|
||||
|
||||
@ -97,8 +104,8 @@ public:
|
||||
private:
|
||||
// internal state
|
||||
drc_cache & m_cache; // pointer to the cache
|
||||
uint64_t m_uniquevalue; // unique value used to find the table
|
||||
uint32_t m_mapvalue[uml::MAPVAR_END - uml::MAPVAR_M0]; // array of current values
|
||||
uint64_t m_uniquevalue; // unique value used to find the table
|
||||
uint32_t m_mapvalue[uml::MAPVAR_END - uml::MAPVAR_M0]; // array of current values
|
||||
|
||||
// list of entries
|
||||
struct map_entry
|
||||
@ -106,8 +113,8 @@ private:
|
||||
map_entry *next() const { return m_next; }
|
||||
map_entry * m_next; // pointer to next map entry
|
||||
drccodeptr m_codeptr; // pointer to the relevant code
|
||||
uint32_t m_mapvar; // map variable id
|
||||
uint32_t m_newval; // value of the variable starting at codeptr
|
||||
uint32_t m_mapvar; // map variable id
|
||||
uint32_t m_newval; // value of the variable starting at codeptr
|
||||
};
|
||||
simple_list<map_entry> m_entry_list; // list of entries
|
||||
};
|
||||
@ -163,4 +170,56 @@ private:
|
||||
};
|
||||
|
||||
|
||||
// ======================> resolved_member_function
|
||||
|
||||
struct resolved_member_function
|
||||
{
|
||||
uintptr_t obj = uintptr_t(nullptr);
|
||||
uint8_t *func = nullptr;
|
||||
|
||||
explicit operator bool() const noexcept
|
||||
{
|
||||
return bool(func);
|
||||
}
|
||||
|
||||
template <typename C, typename F>
|
||||
void set(C &&instance, F &&mfp) noexcept
|
||||
{
|
||||
auto const [entrypoint, adjusted] = util::resolve_member_function(std::forward<F>(mfp), std::forward<C>(instance));
|
||||
obj = adjusted;
|
||||
func = reinterpret_cast<uint8_t *>(entrypoint);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// ======================> resolved_memory_accessors
|
||||
|
||||
struct resolved_memory_accessors
|
||||
{
|
||||
resolved_member_function read_byte;
|
||||
resolved_member_function read_byte_masked;
|
||||
resolved_member_function read_word;
|
||||
resolved_member_function read_word_masked;
|
||||
resolved_member_function read_dword;
|
||||
resolved_member_function read_dword_masked;
|
||||
resolved_member_function read_qword;
|
||||
resolved_member_function read_qword_masked;
|
||||
|
||||
resolved_member_function write_byte;
|
||||
resolved_member_function write_byte_masked;
|
||||
resolved_member_function write_word;
|
||||
resolved_member_function write_word_masked;
|
||||
resolved_member_function write_dword;
|
||||
resolved_member_function write_dword_masked;
|
||||
resolved_member_function write_qword;
|
||||
resolved_member_function write_qword_masked;
|
||||
|
||||
void set(address_space &space) noexcept;
|
||||
};
|
||||
|
||||
using resolved_memory_accessors_vector = std::vector<resolved_memory_accessors>;
|
||||
|
||||
} // namespace drc
|
||||
|
||||
|
||||
#endif // MAME_CPU_DRCBEUT_H
|
||||
|
@ -172,8 +172,6 @@
|
||||
#include "debug/debugcpu.h"
|
||||
#include "emuopts.h"
|
||||
|
||||
#include "mfpresolve.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
@ -660,15 +658,11 @@ drcbe_x64::drcbe_x64(drcuml_state &drcuml, device_t &device, drc_cache &cache, u
|
||||
m_absmask64[0] = m_absmask64[1] = 0x7fffffffffffffffU;
|
||||
|
||||
// get pointers to C functions we need to call
|
||||
using debugger_hook_func = void (*)(device_debug *, offs_t);
|
||||
static const debugger_hook_func debugger_inst_hook = [] (device_debug *dbg, offs_t pc) { dbg->instruction_hook(pc); }; // TODO: kill trampoline if possible
|
||||
m_near.debug_cpu_instruction_hook = (x86code *)debugger_inst_hook;
|
||||
if (LOG_HASHJMPS)
|
||||
{
|
||||
m_near.debug_log_hashjmp = (x86code *)debug_log_hashjmp;
|
||||
m_near.debug_log_hashjmp_fail = (x86code *)debug_log_hashjmp_fail;
|
||||
}
|
||||
m_near.drcmap_get_value = (x86code *)&drc_map_variables::static_get_value;
|
||||
|
||||
// build the flags map
|
||||
for (int entry = 0; entry < std::size(m_near.flagsmap); entry++)
|
||||
@ -692,37 +686,18 @@ drcbe_x64::drcbe_x64(drcuml_state &drcuml, device_t &device, drc_cache &cache, u
|
||||
m_near.flagsunmap[entry] = flags;
|
||||
}
|
||||
|
||||
// resolve the actual addresses of the address space handlers
|
||||
auto const resolve_accessor =
|
||||
[] (resolved_handler &handler, address_space &space, auto accessor)
|
||||
{
|
||||
auto const [entrypoint, adjusted] = util::resolve_member_function(accessor, space);
|
||||
handler.func = reinterpret_cast<x86code *>(entrypoint);
|
||||
handler.obj = adjusted;
|
||||
};
|
||||
// resolve the actual addresses of member functions we need to call
|
||||
m_drcmap_get_value.set(m_map, &drc_map_variables::get_value);
|
||||
if (!m_drcmap_get_value)
|
||||
{
|
||||
m_drcmap_get_value.obj = uintptr_t(&m_map);
|
||||
m_drcmap_get_value.func = reinterpret_cast<uint8_t *>(uintptr_t(&drc_map_variables::static_get_value));
|
||||
}
|
||||
m_resolved_accessors.resize(m_space.size());
|
||||
for (int space = 0; m_space.size() > space; ++space)
|
||||
{
|
||||
if (m_space[space])
|
||||
{
|
||||
resolve_accessor(m_resolved_accessors[space].read_byte, *m_space[space], static_cast<u8 (address_space::*)(offs_t) >(&address_space::read_byte));
|
||||
resolve_accessor(m_resolved_accessors[space].read_byte_masked, *m_space[space], static_cast<u8 (address_space::*)(offs_t, u8) >(&address_space::read_byte));
|
||||
resolve_accessor(m_resolved_accessors[space].read_word, *m_space[space], static_cast<u16 (address_space::*)(offs_t) >(&address_space::read_word));
|
||||
resolve_accessor(m_resolved_accessors[space].read_word_masked, *m_space[space], static_cast<u16 (address_space::*)(offs_t, u16)>(&address_space::read_word));
|
||||
resolve_accessor(m_resolved_accessors[space].read_dword, *m_space[space], static_cast<u32 (address_space::*)(offs_t) >(&address_space::read_dword));
|
||||
resolve_accessor(m_resolved_accessors[space].read_dword_masked, *m_space[space], static_cast<u32 (address_space::*)(offs_t, u32)>(&address_space::read_dword));
|
||||
resolve_accessor(m_resolved_accessors[space].read_qword, *m_space[space], static_cast<u64 (address_space::*)(offs_t) >(&address_space::read_qword));
|
||||
resolve_accessor(m_resolved_accessors[space].read_qword_masked, *m_space[space], static_cast<u64 (address_space::*)(offs_t, u64)>(&address_space::read_qword));
|
||||
|
||||
resolve_accessor(m_resolved_accessors[space].write_byte, *m_space[space], static_cast<void (address_space::*)(offs_t, u8) >(&address_space::write_byte));
|
||||
resolve_accessor(m_resolved_accessors[space].write_byte_masked, *m_space[space], static_cast<void (address_space::*)(offs_t, u8, u8) >(&address_space::write_byte));
|
||||
resolve_accessor(m_resolved_accessors[space].write_word, *m_space[space], static_cast<void (address_space::*)(offs_t, u16) >(&address_space::write_word));
|
||||
resolve_accessor(m_resolved_accessors[space].write_word_masked, *m_space[space], static_cast<void (address_space::*)(offs_t, u16, u16)>(&address_space::write_word));
|
||||
resolve_accessor(m_resolved_accessors[space].write_dword, *m_space[space], static_cast<void (address_space::*)(offs_t, u32) >(&address_space::write_dword));
|
||||
resolve_accessor(m_resolved_accessors[space].write_dword_masked, *m_space[space], static_cast<void (address_space::*)(offs_t, u32, u32)>(&address_space::write_dword));
|
||||
resolve_accessor(m_resolved_accessors[space].write_qword, *m_space[space], static_cast<void (address_space::*)(offs_t, u64) >(&address_space::write_qword));
|
||||
resolve_accessor(m_resolved_accessors[space].write_qword_masked, *m_space[space], static_cast<void (address_space::*)(offs_t, u64, u64)>(&address_space::write_qword));
|
||||
}
|
||||
m_resolved_accessors[space].set(*m_space[space]);
|
||||
}
|
||||
|
||||
// build the opcode table (static but it doesn't hurt to regenerate it)
|
||||
@ -892,6 +867,19 @@ int drcbe_x64::execute(code_handle &entry)
|
||||
|
||||
void drcbe_x64::generate(drcuml_block &block, const instruction *instlist, uint32_t numinst)
|
||||
{
|
||||
// do this here because device.debug() isn't initialised at construction time
|
||||
if (!m_debug_cpu_instruction_hook && (m_device.machine().debug_flags & DEBUG_FLAG_ENABLED))
|
||||
{
|
||||
m_debug_cpu_instruction_hook.set(*m_device.debug(), &device_debug::instruction_hook);
|
||||
if (!m_debug_cpu_instruction_hook)
|
||||
{
|
||||
m_debug_cpu_instruction_hook.obj = uintptr_t(m_device.debug());
|
||||
using debugger_hook_func = void (*)(device_debug *, offs_t);
|
||||
static const auto debugger_inst_hook = [] (device_debug *dbg, offs_t pc) { dbg->instruction_hook(pc); };
|
||||
m_debug_cpu_instruction_hook.func = reinterpret_cast<uint8_t *>(uintptr_t(debugger_hook_func(debugger_inst_hook)));
|
||||
}
|
||||
}
|
||||
|
||||
// tell all of our utility objects that a block is beginning
|
||||
m_hash.block_begin(block, instlist, numinst);
|
||||
m_map.block_begin(block);
|
||||
@ -1556,9 +1544,9 @@ void drcbe_x64::op_debug(Assembler &a, const instruction &inst)
|
||||
a.short_().jz(skip);
|
||||
|
||||
// push the parameter
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), (uintptr_t)m_device.debug()); // mov param1,device.debug
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), m_debug_cpu_instruction_hook.obj); // mov param1,device.debug
|
||||
mov_reg_param(a, Gpd(REG_PARAM2), pcp); // mov param2,pcp
|
||||
smart_call_m64(a, &m_near.debug_cpu_instruction_hook); // call debug_cpu_instruction_hook
|
||||
smart_call_r64(a, m_debug_cpu_instruction_hook.func, rax); // call debug_cpu_instruction_hook
|
||||
|
||||
a.bind(skip);
|
||||
}
|
||||
@ -1861,10 +1849,10 @@ void drcbe_x64::op_recover(Assembler &a, const instruction &inst)
|
||||
// call the recovery code
|
||||
a.mov(rax, MABS(&m_near.stacksave)); // mov rax,stacksave
|
||||
a.mov(rax, ptr(rax, -8)); // mov rax,[rax-8]
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), (uintptr_t)&m_map); // mov param1,m_map
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), m_drcmap_get_value.obj); // mov param1,m_map
|
||||
a.lea(Gpq(REG_PARAM2), ptr(rax, -1)); // lea param2,[rax-1]
|
||||
mov_r64_imm(a, Gpq(REG_PARAM3), inst.param(1).mapvar()); // mov param3,param[1].value
|
||||
smart_call_m64(a, &m_near.drcmap_get_value); // call drcmap_get_value
|
||||
smart_call_r64(a, m_drcmap_get_value.func, rax); // call drcmap_get_value
|
||||
mov_param_reg(a, dstp, eax); // mov dstp,eax
|
||||
}
|
||||
|
||||
@ -2523,7 +2511,7 @@ void drcbe_x64::op_read(Assembler &a, const instruction &inst)
|
||||
mov_reg_param(a, Gpd(REG_PARAM2), addrp); // mov param2,addrp
|
||||
if (spacesizep.size() == SIZE_BYTE)
|
||||
{
|
||||
if (resolved.read_byte.func)
|
||||
if (resolved.read_byte)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.read_byte.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.read_byte.func, rax); // call read_byte
|
||||
@ -2537,7 +2525,7 @@ void drcbe_x64::op_read(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_WORD)
|
||||
{
|
||||
if (resolved.read_word.func)
|
||||
if (resolved.read_word)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.read_word.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.read_word.func, rax); // call read_word
|
||||
@ -2551,7 +2539,7 @@ void drcbe_x64::op_read(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_DWORD)
|
||||
{
|
||||
if (resolved.read_dword.func)
|
||||
if (resolved.read_dword)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.read_dword.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.read_dword.func, rax); // call read_dword
|
||||
@ -2566,7 +2554,7 @@ void drcbe_x64::op_read(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_QWORD)
|
||||
{
|
||||
if (resolved.read_qword.func)
|
||||
if (resolved.read_qword)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.read_qword.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.read_qword.func, rax); // call read_qword
|
||||
@ -2619,7 +2607,7 @@ void drcbe_x64::op_readm(Assembler &a, const instruction &inst)
|
||||
mov_reg_param(a, Gpq(REG_PARAM3), maskp); // mov param3,maskp
|
||||
if (spacesizep.size() == SIZE_BYTE)
|
||||
{
|
||||
if (resolved.read_byte_masked.func)
|
||||
if (resolved.read_byte_masked)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.read_byte_masked.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.read_byte_masked.func, rax); // call read_byte_masked
|
||||
@ -2633,7 +2621,7 @@ void drcbe_x64::op_readm(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_WORD)
|
||||
{
|
||||
if (resolved.read_word_masked.func)
|
||||
if (resolved.read_word_masked)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.read_word_masked.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.read_word_masked.func, rax); // call read_word_masked
|
||||
@ -2647,7 +2635,7 @@ void drcbe_x64::op_readm(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_DWORD)
|
||||
{
|
||||
if (resolved.read_dword_masked.func)
|
||||
if (resolved.read_dword_masked)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.read_dword_masked.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.read_dword_masked.func, rax); // call read_dword_masked
|
||||
@ -2662,7 +2650,7 @@ void drcbe_x64::op_readm(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_QWORD)
|
||||
{
|
||||
if (resolved.read_qword_masked.func)
|
||||
if (resolved.read_qword_masked)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.read_qword_masked.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.read_qword_masked.func, rax); // call read_qword_masked
|
||||
@ -2711,7 +2699,7 @@ void drcbe_x64::op_write(Assembler &a, const instruction &inst)
|
||||
mov_reg_param(a, Gpq(REG_PARAM3), srcp); // mov param3,srcp
|
||||
if (spacesizep.size() == SIZE_BYTE)
|
||||
{
|
||||
if (resolved.write_byte.func)
|
||||
if (resolved.write_byte)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.write_byte.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.write_byte.func, rax); // call write_byte
|
||||
@ -2724,7 +2712,7 @@ void drcbe_x64::op_write(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_WORD)
|
||||
{
|
||||
if (resolved.write_word.func)
|
||||
if (resolved.write_word)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.write_word.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.write_word.func, rax); // call write_word
|
||||
@ -2737,7 +2725,7 @@ void drcbe_x64::op_write(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_DWORD)
|
||||
{
|
||||
if (resolved.write_dword.func)
|
||||
if (resolved.write_dword)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.write_dword.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.write_dword.func, rax); // call write_dword
|
||||
@ -2750,7 +2738,7 @@ void drcbe_x64::op_write(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_QWORD)
|
||||
{
|
||||
if (resolved.write_qword.func)
|
||||
if (resolved.write_qword)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.write_qword.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.write_qword.func, rax); // call write_qword
|
||||
@ -2798,7 +2786,7 @@ void drcbe_x64::op_writem(Assembler &a, const instruction &inst)
|
||||
}
|
||||
if (spacesizep.size() == SIZE_BYTE)
|
||||
{
|
||||
if (resolved.write_byte.func)
|
||||
if (resolved.write_byte)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.write_byte_masked.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.write_byte_masked.func, rax); // call write_byte_masked
|
||||
@ -2811,7 +2799,7 @@ void drcbe_x64::op_writem(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_WORD)
|
||||
{
|
||||
if (resolved.write_word.func)
|
||||
if (resolved.write_word)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.write_word_masked.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.write_word_masked.func, rax); // call write_word_masked
|
||||
@ -2824,7 +2812,7 @@ void drcbe_x64::op_writem(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_DWORD)
|
||||
{
|
||||
if (resolved.write_word.func)
|
||||
if (resolved.write_word)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.write_dword_masked.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.write_dword_masked.func, rax); // call write_dword_masked
|
||||
@ -2837,7 +2825,7 @@ void drcbe_x64::op_writem(Assembler &a, const instruction &inst)
|
||||
}
|
||||
else if (spacesizep.size() == SIZE_QWORD)
|
||||
{
|
||||
if (resolved.write_word.func)
|
||||
if (resolved.write_word)
|
||||
{
|
||||
mov_r64_imm(a, Gpq(REG_PARAM1), resolved.write_qword_masked.obj); // mov param1,space
|
||||
smart_call_r64(a, resolved.write_qword_masked.func, rax); // call write_qword_masked
|
||||
|
@ -251,10 +251,8 @@ private:
|
||||
// state to live in the near cache
|
||||
struct near_state
|
||||
{
|
||||
x86code * debug_cpu_instruction_hook;// debugger callback
|
||||
x86code * debug_log_hashjmp; // hashjmp debugging
|
||||
x86code * debug_log_hashjmp_fail; // hashjmp debugging
|
||||
x86code * drcmap_get_value; // map lookup helper
|
||||
|
||||
uint32_t ssemode; // saved SSE mode
|
||||
uint32_t ssemodesave; // temporary location for saving
|
||||
@ -270,30 +268,9 @@ private:
|
||||
near_state & m_near;
|
||||
|
||||
// resolved memory handler functions
|
||||
struct resolved_handler { uintptr_t obj = 0; x86code *func = nullptr; };
|
||||
struct resolved_accessors
|
||||
{
|
||||
|
||||
resolved_handler read_byte;
|
||||
resolved_handler read_byte_masked;
|
||||
resolved_handler read_word;
|
||||
resolved_handler read_word_masked;
|
||||
resolved_handler read_dword;
|
||||
resolved_handler read_dword_masked;
|
||||
resolved_handler read_qword;
|
||||
resolved_handler read_qword_masked;
|
||||
|
||||
resolved_handler write_byte;
|
||||
resolved_handler write_byte_masked;
|
||||
resolved_handler write_word;
|
||||
resolved_handler write_word_masked;
|
||||
resolved_handler write_dword;
|
||||
resolved_handler write_dword_masked;
|
||||
resolved_handler write_qword;
|
||||
resolved_handler write_qword_masked;
|
||||
};
|
||||
using resolved_accessors_vector = std::vector<resolved_accessors>;
|
||||
resolved_accessors_vector m_resolved_accessors;
|
||||
resolved_member_function m_debug_cpu_instruction_hook;
|
||||
resolved_member_function m_drcmap_get_value;
|
||||
resolved_memory_accessors_vector m_resolved_accessors;
|
||||
|
||||
// globals
|
||||
using opcode_generate_func = void (drcbe_x64::*)(asmjit::x86::Assembler &, const uml::instruction &);
|
||||
|
Loading…
Reference in New Issue
Block a user