summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2025-03-18 01:50:44 +1100
committer Vas Crabb <vas@vastheman.com>2025-03-18 01:50:44 +1100
commitdaedf2ff31d0a77b0fef2f71ea8851164767ddb3 (patch)
tree25d2c1986f279b6ddb8abb785cb8744886fbc761 /src/devices
parentb5fafba307ba7acc2aea90681c71a3d43aa9cac3 (diff)
-cpu/drcbe*.cpp: Print an error message and abort when running off the end of a generated code block.
-cpu/drcbearm64.cpp: Don't emit code for UML NOP - the simplifier litters the code with these for elided operations. -frontend/mame/clifront.cpp: Added newline at end of -version output.
Diffstat (limited to 'src/devices')
-rw-r--r--src/devices/cpu/drcbearm64.cpp33
-rw-r--r--src/devices/cpu/drcbex64.cpp79
-rw-r--r--src/devices/cpu/drcbex86.cpp50
3 files changed, 140 insertions, 22 deletions
diff --git a/src/devices/cpu/drcbearm64.cpp b/src/devices/cpu/drcbearm64.cpp
index 8493e4b7106..24c7f54bc28 100644
--- a/src/devices/cpu/drcbearm64.cpp
+++ b/src/devices/cpu/drcbearm64.cpp
@@ -81,10 +81,14 @@ the location FP points to.
#include "debug/debugcpu.h"
#include "emuopts.h"
+#include "mfpresolve.h"
+
#include "asmjit/src/asmjit/asmjit.h"
#include "asmjit/src/asmjit/a64.h"
#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
#include <vector>
@@ -619,6 +623,8 @@ private:
void call_arm_addr(asmjit::a64::Assembler &a, const void *offs) const;
+ [[noreturn]] void end_of_block() const;
+
drc_hash_table m_hash;
drc_map_variables m_map;
FILE *m_log_asmjit;
@@ -627,6 +633,7 @@ private:
arm64_entry_point_func m_entry;
drccodeptr m_exit;
drccodeptr m_nocode;
+ drccodeptr m_endofblock;
uint8_t *m_baseptr;
@@ -1429,6 +1436,7 @@ drcbe_arm64::drcbe_arm64(drcuml_state &drcuml, device_t &device, drc_cache &cach
, m_entry(nullptr)
, m_exit(nullptr)
, m_nocode(nullptr)
+ , m_endofblock(nullptr)
, m_baseptr(cache.near() + 0x100)
, m_near(*(near_state *)cache.alloc_near(sizeof(m_near)))
{
@@ -1556,6 +1564,13 @@ void drcbe_arm64::reset()
a.bind(a.newNamedLabel("nocode_point"));
a.br(REG_PARAM1);
+ // generate an end-of-block handler point
+ m_endofblock = dst + a.offset();
+ a.bind(a.newNamedLabel("end_of_block_point"));
+ auto const [entrypoint, adjusted] = util::resolve_member_function(&drcbe_arm64::end_of_block, *this);
+ get_imm_relative(a, REG_PARAM1, adjusted);
+ call_arm_addr(a, (const void *)entrypoint);
+
// emit the generated code
emit(ch);
@@ -1640,7 +1655,10 @@ void drcbe_arm64::generate(drcuml_block &block, const instruction *instlist, uin
(this->*s_opcode_table[inst.opcode()])(a, inst);
}
- emit_str_mem(a, FLAGS_REG.w(), &m_near.emulated_flags);
+ // catch falling off the end of a block
+ if (logger.file())
+ a.setInlineComment("end of block");
+ a.b(m_endofblock);
// emit the generated code
if (!emit(ch))
@@ -1671,6 +1689,16 @@ void drcbe_arm64::get_info(drcbe_info &info) const noexcept
}
}
+
+[[noreturn]] void drcbe_arm64::end_of_block() const
+{
+ osd_printf_error("drcbe_arm64(%s): fell off the end of a generated code block!\n", m_device.tag());
+ std::fflush(stdout);
+ std::fflush(stderr);
+ std::abort();
+}
+
+
void drcbe_arm64::op_handle(a64::Assembler &a, const uml::instruction &inst)
{
assert_no_condition(inst);
@@ -1753,7 +1781,8 @@ void drcbe_arm64::op_mapvar(a64::Assembler &a, const uml::instruction &inst)
void drcbe_arm64::op_nop(a64::Assembler &a, const uml::instruction &inst)
{
- a.nop();
+ // nothing
+ //a.nop();
}
void drcbe_arm64::op_break(a64::Assembler &a, const uml::instruction &inst)
diff --git a/src/devices/cpu/drcbex64.cpp b/src/devices/cpu/drcbex64.cpp
index d246b2b6dc5..25541400028 100644
--- a/src/devices/cpu/drcbex64.cpp
+++ b/src/devices/cpu/drcbex64.cpp
@@ -122,7 +122,7 @@
R14 - maps to I5
R15 - maps to I6
- Registers (Linux/MacOS):
+ Registers (SysV)
RAX - scratch register
RBX - maps to I0
RCX - scratch register
@@ -146,7 +146,7 @@
Exit point:
Assumes exit value is in RAX.
- Top-level generated code frame:
+ Top-level generated code frame (Windows):
[rsp+0x00] - rcx home/scratch
[rsp+0x08] - rdx home/scratch
[rsp+0x10] - r8 home/scratch
@@ -162,6 +162,20 @@
[rsp+0x60] - saved rbx
[rsp+0x68] - ret
+ Top-level generated code frame (SysV):
+ [rsp+0x00] - rcx home/scratch
+ [rsp+0x08] - rdx home/scratch
+ [rsp+0x10] - r8 home/scratch
+ [rsp+0x18] - r9 home/scratch
+ [rsp+0x20] - scratch
+ [rsp+0x28] - saved r15
+ [rsp+0x30] - saved r14
+ [rsp+0x38] - saved r13
+ [rsp+0x40] - saved r12
+ [rsp+0x48] - saved rbp
+ [rsp+0x50] - saved rbx
+ [rsp+0x58] - ret
+
Generated code subroutine call frame:
[rsp+0x00] - rcx home/scratch
[rsp+0x08] - rdx home/scratch
@@ -179,11 +193,7 @@
- saved r14
- saved r13
- saved r12
- - saved rdi
- - saved rsi
- - saved rbp
- - saved rbx
- - ret
+ ...
***************************************************************************/
@@ -196,9 +206,13 @@
#include "debug/debugcpu.h"
#include "emuopts.h"
+#include "mfpresolve.h"
+
#include "asmjit/src/asmjit/asmjit.h"
#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
#include <vector>
@@ -451,6 +465,7 @@ private:
void smart_call_r64(asmjit::x86::Assembler &a, x86code *target, asmjit::x86::Gp const &reg);
void smart_call_m64(asmjit::x86::Assembler &a, x86code **target);
+ [[noreturn]] void end_of_block() const;
static void debug_log_hashjmp(offs_t pc, int mode);
static void debug_log_hashjmp_fail();
@@ -575,6 +590,7 @@ private:
x86_entry_point_func m_entry; // entry point
x86code * m_exit; // exit point
x86code * m_nocode; // nocode handler
+ x86code * m_endofblock; // end of block handler
// state to live in the near cache
struct near_state
@@ -944,6 +960,7 @@ drcbe_x64::drcbe_x64(drcuml_state &drcuml, device_t &device, drc_cache &cache, u
, m_entry(nullptr)
, m_exit(nullptr)
, m_nocode(nullptr)
+ , m_endofblock(nullptr)
, m_near(*(near_state *)cache.alloc_near(sizeof(m_near)))
{
// build up necessary arrays
@@ -1146,14 +1163,22 @@ void drcbe_x64::reset()
a.bind(a.newNamedLabel("nocode_point"));
a.jmp(Gpq(REG_PARAM1));
+ // generate an end-of-block handler point
+ m_endofblock = dst + a.offset();
+ a.bind(a.newNamedLabel("end_of_block_point"));
+ auto const [entrypoint, adjusted] = util::resolve_member_function(&drcbe_x64::end_of_block, *this);
+ mov_r64_imm(a, Gpq(REG_PARAM1), adjusted);
+ smart_call_r64(a, (x86code *)entrypoint, rax);
+
// emit the generated code
- size_t bytes = emit(ch);
+ const size_t bytes = emit(ch);
- if (m_log != nullptr)
+ if (m_log)
{
x86log_disasm_code_range(m_log, "entry_point", dst, m_exit);
x86log_disasm_code_range(m_log, "exit_point", m_exit, m_nocode);
- x86log_disasm_code_range(m_log, "nocode_point", m_nocode, dst + bytes);
+ x86log_disasm_code_range(m_log, "nocode_point", m_nocode, m_endofblock);
+ x86log_disasm_code_range(m_log, "end_of_block", m_endofblock, dst + bytes);
}
// reset our hash tables
@@ -1238,7 +1263,7 @@ void drcbe_x64::generate(drcuml_block &block, const instruction *instlist, uint3
std::string dasm;
// add a comment
- if (m_log != nullptr)
+ if (m_log)
{
dasm = inst.disasm(&m_drcuml);
@@ -1259,13 +1284,21 @@ void drcbe_x64::generate(drcuml_block &block, const instruction *instlist, uint3
(this->*s_opcode_table[inst.opcode()])(a, inst);
}
+ // catch falling off the end of a block
+ if (m_log)
+ {
+ x86log_add_comment(m_log, dst + a.offset(), "%s", "end of block");
+ a.setInlineComment("end of block");
+ }
+ a.jmp(imm(m_endofblock));
+
// emit the generated code
size_t const bytes = emit(ch);
if (!bytes)
block.abort();
// log it
- if (m_log != nullptr)
+ if (m_log)
x86log_disasm_code_range(m_log, (blockname.empty()) ? "Unknown block" : blockname.c_str(), dst, dst + bytes);
// tell all of our utility objects that the block is finished
@@ -1674,11 +1707,11 @@ void drcbe_x64::movsd_p64_r128(Assembler &a, be_parameter const &param, Xmm cons
{
assert(!param.is_immediate());
if (param.is_memory())
- a.movsd(MABS(param.memory(), 8), reg); // movsd [param],reg
+ a.movsd(MABS(param.memory(), 8), reg);
else if (param.is_float_register())
{
if (reg.id() != param.freg())
- a.movsd(Xmm(param.freg()), reg); // movsd param,reg
+ a.movsd(Xmm(param.freg()), reg);
}
}
@@ -1688,13 +1721,27 @@ void drcbe_x64::movsd_p64_r128(Assembler &a, be_parameter const &param, Xmm cons
//**************************************************************************
//-------------------------------------------------
+// end_of_block - function to catch falling off
+// the end of a generated code block
+//-------------------------------------------------
+
+[[noreturn]] void drcbe_x64::end_of_block() const
+{
+ osd_printf_error("drcbe_x64(%s): fell off the end of a generated code block!\n", m_device.tag());
+ std::fflush(stdout);
+ std::fflush(stderr);
+ std::abort();
+}
+
+
+//-------------------------------------------------
// debug_log_hashjmp - callback to handle
// logging of hashjmps
//-------------------------------------------------
void drcbe_x64::debug_log_hashjmp(offs_t pc, int mode)
{
- printf("mode=%d PC=%08X\n", mode, pc);
+ std::printf("mode=%d PC=%08X\n", mode, pc);
}
@@ -1705,7 +1752,7 @@ void drcbe_x64::debug_log_hashjmp(offs_t pc, int mode)
void drcbe_x64::debug_log_hashjmp_fail()
{
- printf(" (FAIL)\n");
+ std::printf(" (FAIL)\n");
}
diff --git a/src/devices/cpu/drcbex86.cpp b/src/devices/cpu/drcbex86.cpp
index 97813ba65e0..b3acf261860 100644
--- a/src/devices/cpu/drcbex86.cpp
+++ b/src/devices/cpu/drcbex86.cpp
@@ -91,9 +91,13 @@
#include "debug/debugcpu.h"
#include "emuopts.h"
+#include "mfpresolve.h"
+
#include "asmjit/src/asmjit/asmjit.h"
#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
namespace drc {
@@ -498,6 +502,7 @@ private:
bool can_skip_lower_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const &reglo);
bool can_skip_upper_load(asmjit::x86::Assembler &a, uint32_t *memref, asmjit::x86::Gp const &reghi);
+ [[noreturn]] void end_of_block() const;
static void debug_log_hashjmp(int mode, offs_t pc);
// code generators
@@ -636,6 +641,7 @@ private:
x86_entry_point_func m_entry; // entry point
x86code * m_exit; // exit point
x86code * m_nocode; // nocode handler
+ x86code * m_endofblock; // end of block handler
x86code * m_save; // save handler
x86code * m_restore; // restore handler
@@ -1027,6 +1033,7 @@ drcbe_x86::drcbe_x86(drcuml_state &drcuml, device_t &device, drc_cache &cache, u
, m_entry(nullptr)
, m_exit(nullptr)
, m_nocode(nullptr)
+ , m_endofblock(nullptr)
, m_save(nullptr)
, m_restore(nullptr)
, m_last_lower_reg(Gp())
@@ -1217,6 +1224,18 @@ void drcbe_x86::reset()
a.bind(a.newNamedLabel("nocode_point"));
a.ret(); // ret
+ // generate an end-of-block handler point
+ m_endofblock = dst + a.offset();
+ a.bind(a.newNamedLabel("end_of_block_point"));
+ auto const [entrypoint, adjusted] = util::resolve_member_function(&drcbe_x86::end_of_block, *this);
+ if (USE_THISCALL)
+ a.mov(ecx, imm(adjusted));
+ else
+ a.mov(dword_ptr(esp, 0), imm(adjusted));
+ a.call(imm(entrypoint));
+ if (USE_THISCALL)
+ a.sub(esp, 4);
+
// generate a save subroutine
m_save = dst + a.offset();
a.bind(a.newNamedLabel("save"));
@@ -1299,7 +1318,8 @@ void drcbe_x86::reset()
{
x86log_disasm_code_range(m_log, "entry_point", dst, m_exit);
x86log_disasm_code_range(m_log, "exit_point", m_exit, m_nocode);
- x86log_disasm_code_range(m_log, "nocode_point", m_nocode, m_save);
+ x86log_disasm_code_range(m_log, "nocode_point", m_nocode, m_endofblock);
+ x86log_disasm_code_range(m_log, "end_of_block", m_endofblock, m_save);
x86log_disasm_code_range(m_log, "save", m_save, m_restore);
x86log_disasm_code_range(m_log, "restore", m_restore, dst + bytes);
@@ -1387,7 +1407,7 @@ void drcbe_x86::generate(drcuml_block &block, const instruction *instlist, uint3
std::string dasm;
// add a comment
- if (m_log != nullptr)
+ if (m_log)
{
dasm = inst.disasm(&m_drcuml);
x86log_add_comment(m_log, dst + a.offset(), "%s", dasm.c_str());
@@ -1407,13 +1427,21 @@ void drcbe_x86::generate(drcuml_block &block, const instruction *instlist, uint3
(this->*s_opcode_table[inst.opcode()])(a, inst);
}
+ // catch falling off the end of a block
+ if (m_log)
+ {
+ x86log_add_comment(m_log, dst + a.offset(), "%s", "end of block");
+ a.setInlineComment("end of block");
+ }
+ a.jmp(imm(m_endofblock));
+
// emit the generated code
size_t const bytes = emit(ch);
if (!bytes)
block.abort();
// log it
- if (m_log != nullptr)
+ if (m_log)
x86log_disasm_code_range(m_log, (blockname.empty()) ? "Unknown block" : blockname.c_str(), dst, dst + bytes);
// tell all of our utility objects that the block is finished
@@ -2817,13 +2845,27 @@ void drcbe_x86::emit_fstp_p(Assembler &a, int size, be_parameter const &param)
//**************************************************************************
//-------------------------------------------------
+// end_of_block - function to catch falling off
+// the end of a generated code block
+//-------------------------------------------------
+
+[[noreturn]] void drcbe_x86::end_of_block() const
+{
+ osd_printf_error("drcbe_x86(%s): fell off the end of a generated code block!\n", m_device.tag());
+ std::fflush(stdout);
+ std::fflush(stderr);
+ std::abort();
+}
+
+
+//-------------------------------------------------
// debug_log_hashjmp - callback to handle
// logging of hashjmps
//-------------------------------------------------
void drcbe_x86::debug_log_hashjmp(int mode, offs_t pc)
{
- printf("mode=%d PC=%08X\n", mode, pc);
+ std::printf("mode=%d PC=%08X\n", mode, pc);
}