cpu/e132xs: Don't generate code to handle a delayed branch inline.

* Also avoid an redundant load when checking if trace is active.
* Reduces generated native instruction count by about 24% on x86-64 and
  gives an overall performance improvement of about 3.5% in -bench
  scores.
This commit is contained in:
Vas Crabb 2025-03-24 03:33:04 +11:00
parent d0b681c51e
commit 91d9b3cb02
3 changed files with 53 additions and 89 deletions

View File

@ -215,6 +215,7 @@ hyperstone_device::hyperstone_device(const machine_config &mconfig, const char *
, m_nocode(nullptr)
, m_interrupt_checks(nullptr)
, m_out_of_cycles(nullptr)
, m_delay_taken(nullptr)
, m_mem_read8(nullptr)
, m_mem_write8(nullptr)
, m_mem_read16(nullptr)

View File

@ -454,6 +454,7 @@ private:
uml::code_handle *m_nocode;
uml::code_handle *m_interrupt_checks;
uml::code_handle *m_out_of_cycles;
uml::code_handle *m_delay_taken;
uml::code_handle *m_mem_read8;
uml::code_handle *m_mem_write8;
@ -484,12 +485,10 @@ private:
void code_compile_block(offs_t pc);
//void load_fast_iregs(drcuml_block &block);
//void save_fast_iregs(drcuml_block &block);
void static_generate_entry_point();
void static_generate_nocode_handler();
void static_generate_out_of_cycles();
void static_generate_exception(uint32_t exception, const char *name);
void static_generate_helpers(drcuml_block &block, uml::code_label &label);
void static_generate_memory_accessor(int size, int iswrite, bool isio, const char *name, uml::code_handle *&handleptr);
void static_generate_interrupt_checks();
void static_generate_exception(uint32_t exception, const char *name);
void static_generate_interrupt_checks(drcuml_block &block, uml::code_label &label);
void generate_interrupt_checks(drcuml_block &block, uml::code_label &labelnum, bool with_timer, int take_int, int take_timer);
void generate_branch(drcuml_block &block, uml::parameter targetpc, const opcode_desc *desc, bool update_cycles = true);
void generate_update_cycles(drcuml_block &block, bool check_interrupts = true);

View File

@ -150,11 +150,13 @@ void hyperstone_device::code_flush_cache()
try
{
/* generate the entry point and out-of-cycles handlers */
static_generate_entry_point();
static_generate_nocode_handler();
static_generate_out_of_cycles();
static_generate_interrupt_checks();
{
// generate the entry point and out-of-cycles handlers
drcuml_block &block(m_drcuml->begin_block(512));
uml::code_label label = 1;
static_generate_helpers(block, label);
block.end();
}
static_generate_exception(EXCEPTION_IO2, "io2");
static_generate_exception(EXCEPTION_IO1, "io1");
@ -398,20 +400,15 @@ void hyperstone_device::static_generate_exception(uint32_t exception, const char
void hyperstone_device::static_generate_interrupt_checks()
void hyperstone_device::static_generate_interrupt_checks(drcuml_block &block, uml::code_label &label)
{
/* begin generating */
drcuml_block &block(m_drcuml->begin_block(512));
alloc_handle(*m_drcuml, m_interrupt_checks, "int_checks");
UML_HANDLE(block, *m_interrupt_checks);
uml::code_label labelnum = 1;
const int timer_int_pending = labelnum++;
const int take_int = labelnum++;
const int take_timer = labelnum++;
const int dispatch_int = labelnum++;
const int done_int = labelnum++;
const int timer_int_pending = label++;
const int take_int = label++;
const int take_timer = label++;
const int dispatch_int = label++;
const int done_int = label++;
UML_CMP(block, mem(&m_core->intblock), 0);
UML_JMPc(block, uml::COND_G, done_int);
@ -426,11 +423,11 @@ void hyperstone_device::static_generate_interrupt_checks()
UML_TEST(block, I0, 0x7f);
UML_JMPc(block, uml::COND_Z, done_int);
generate_interrupt_checks(block, labelnum, false, take_int, take_timer);
generate_interrupt_checks(block, label, false, take_int, take_timer);
UML_JMP(block, done_int);
UML_LABEL(block, timer_int_pending);
generate_interrupt_checks(block, labelnum, true, take_int, take_timer);
generate_interrupt_checks(block, label, true, take_int, take_timer);
UML_JMP(block, done_int);
UML_LABEL(block, take_int);
@ -442,81 +439,53 @@ void hyperstone_device::static_generate_interrupt_checks()
UML_MOV(block, I0, TRAPNO_TIMER);
UML_LABEL(block, dispatch_int);
generate_trap_exception_or_int<IS_INT>(block, labelnum, uml::I0);
generate_trap_exception_or_int<IS_INT>(block, label, uml::I0);
UML_LABEL(block, done_int);
UML_RET(block);
block.end();
}
/*-------------------------------------------------
generate_entry_point - generate a
static entry point
generate_entry_helpers - generate helper
stubs and functions
-------------------------------------------------*/
void hyperstone_device::static_generate_entry_point()
void hyperstone_device::static_generate_helpers(drcuml_block &block, uml::code_label &label)
{
/* begin generating */
drcuml_block &block(m_drcuml->begin_block(20));
/* forward references */
alloc_handle(*m_drcuml, m_nocode, "nocode");
// forward references
alloc_handle(*m_drcuml, m_entry, "entry");
UML_HANDLE(block, *m_entry);
/* load fast integer registers */
//load_fast_iregs(block);
/* generate a hash jump via the current mode and PC */
UML_HASHJMP(block, 0, mem(&m_core->global_regs[0]), *m_nocode);
block.end();
}
/*-------------------------------------------------
static_generate_nocode_handler - generate an
exception handler for "out of code"
-------------------------------------------------*/
void hyperstone_device::static_generate_nocode_handler()
{
/* begin generating */
drcuml_block &block(m_drcuml->begin_block(10));
/* generate a hash jump via the current mode and PC */
alloc_handle(*m_drcuml, m_nocode, "nocode");
alloc_handle(*m_drcuml, m_out_of_cycles, "out_of_cycles");
alloc_handle(*m_drcuml, m_delay_taken, "delay_taken");
alloc_handle(*m_drcuml, m_interrupt_checks, "int_checks");
// static entry point
UML_HANDLE(block, *m_entry);
//load_fast_iregs(block);
UML_HASHJMP(block, 0, mem(&m_core->global_regs[0]), *m_nocode);
// exception handler for "out of code"
UML_HANDLE(block, *m_nocode);
UML_GETEXP(block, I0);
UML_MOV(block, mem(&PC), I0);
//save_fast_iregs(block);
UML_EXIT(block, EXECUTE_MISSING_CODE);
block.end();
}
/*-------------------------------------------------
static_generate_out_of_cycles - generate an
out of cycles exception handler
-------------------------------------------------*/
void hyperstone_device::static_generate_out_of_cycles()
{
/* begin generating */
drcuml_block &block(m_drcuml->begin_block(10));
/* generate a hash jump via the current mode and PC */
alloc_handle(*m_drcuml, m_out_of_cycles, "out_of_cycles");
// out of cycles exception handler
UML_HANDLE(block, *m_out_of_cycles);
//save_fast_iregs(block);
UML_EXIT(block, EXECUTE_OUT_OF_CYCLES);
block.end();
// delayed branch taken
UML_HANDLE(block, *m_delay_taken);
UML_MOV(block, mem(&m_core->delay_slot_taken), 0);
generate_update_cycles(block);
UML_HASHJMP(block, 0, DRC_PC, *m_nocode);
static_generate_interrupt_checks(block, label);
}
/*------------------------------------------------------------------
static_generate_memory_accessor
------------------------------------------------------------------*/
@ -817,14 +786,12 @@ void hyperstone_device::generate_branch(drcuml_block &block, uml::parameter targ
void hyperstone_device::generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
offs_t expc;
/* add an entry for the log */
if (m_drcuml->logging() && !(desc->flags & OPFLAG_VIRTUAL_NOOP))
log_add_disasm_comment(block, desc->pc, desc->opptr.w[0]);
/* set the PC map variable */
expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? desc->pc - 3 : desc->pc;
const offs_t expc = (desc->flags & OPFLAG_IN_DELAY_SLOT) ? (desc->pc - 3) : desc->pc;
UML_MAPVAR(block, MAPVAR_PC, expc);
#if E132XS_LOG_DRC_REGS
@ -1118,20 +1085,17 @@ bool hyperstone_device::generate_opcode(drcuml_block &block, compiler_state &com
case 0xff: generate_trap_op(block, compiler, desc); break;
}
UML_ROLINS(block, DRC_SR, ((desc->length >> 1) << ILC_SHIFT), 0, ILC_MASK);
UML_MOV(block, I0, DRC_SR);
UML_ROLINS(block, I0, (desc->length >> 1) << ILC_SHIFT, 0, ILC_MASK);
UML_MOV(block, DRC_SR, I0);
int no_delay_taken = compiler.m_labelnum++;
UML_TEST(block, mem(&m_core->delay_slot_taken), ~0);
UML_JMPc(block, uml::COND_Z, no_delay_taken);
UML_MOV(block, mem(&m_core->delay_slot_taken), 0);
generate_update_cycles(block);
UML_HASHJMP(block, 0, DRC_PC, *m_nocode);
UML_LABEL(block, no_delay_taken);
UML_TEST(block, mem(&m_core->delay_slot_taken), ~uint32_t(0));
UML_CALLHc(block, uml::COND_NZ, *m_delay_taken);
int done;
UML_AND(block, I0, DRC_SR, (T_MASK | P_MASK));
const int done = compiler.m_labelnum++;
UML_AND(block, I0, I0, (T_MASK | P_MASK));
UML_CMP(block, I0, (T_MASK | P_MASK));
UML_JMPc(block, uml::COND_NE, done = compiler.m_labelnum++);
UML_JMPc(block, uml::COND_NE, done);
UML_TEST(block, mem(&m_core->delay_slot), 1);
UML_EXHc(block, uml::COND_E, *m_exception[EXCEPTION_TRACE], 0);