-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.
This commit is contained in:
Vas Crabb 2025-03-18 01:50:44 +11:00
parent b5fafba307
commit daedf2ff31
4 changed files with 142 additions and 24 deletions

View File

@ -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)

View File

@ -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));
// emit the generated code
size_t bytes = emit(ch);
// 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);
if (m_log != nullptr)
// emit the generated code
const size_t bytes = emit(ch);
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);
}
}
@ -1687,6 +1720,20 @@ void drcbe_x64::movsd_p64_r128(Assembler &a, be_parameter const &param, Xmm cons
// DEBUG HELPERS
//**************************************************************************
//-------------------------------------------------
// 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
@ -1694,7 +1741,7 @@ void drcbe_x64::movsd_p64_r128(Assembler &a, be_parameter const &param, Xmm cons
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");
}

View File

@ -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
@ -2816,6 +2844,20 @@ void drcbe_x86::emit_fstp_p(Assembler &a, int size, be_parameter const &param)
// DEBUG HELPERS
//**************************************************************************
//-------------------------------------------------
// 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
@ -2823,7 +2865,7 @@ void drcbe_x86::emit_fstp_p(Assembler &a, int size, be_parameter const &param)
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);
}

View File

@ -1539,7 +1539,7 @@ void cli_frontend::verifysoftlist(const std::vector<std::string> &args)
void cli_frontend::version(const std::vector<std::string> &args)
{
osd_printf_info("%s", emulator_info::get_build_version());
osd_printf_info("%s\n", emulator_info::get_build_version());
}