cpu/e132xs: Call debugger exception hook for TRAP instructions.

Also made cycle counts a bit more consistent between interpreter and
recompiler for exceptions and traps.
This commit is contained in:
Vas Crabb 2025-03-26 17:58:40 +11:00
parent 221f40f1b1
commit 9fd89a456e
4 changed files with 36 additions and 53 deletions

View File

@ -707,8 +707,11 @@ void hyperstone_device::hyperstone_br()
m_core->icount -= m_core->clock_cycles_2;
}
void hyperstone_device::execute_trap(uint32_t addr)
void hyperstone_device::execute_trap(uint8_t trapno)
{
debugger_exception_hook(int(unsigned(trapno)));
const uint32_t addr = get_trap_addr(trapno);
const uint8_t reg = GET_FP + GET_FL;
SET_ILC(m_instruction_length);
const uint32_t oldSR = SR;
@ -1424,18 +1427,17 @@ void hyperstone_device::hyperstone_trap()
check_delay_PC();
const uint8_t trapno = (m_op & 0xfc) >> 2;
const uint32_t addr = get_trap_addr(trapno);
const uint8_t code = ((m_op & 0x300) >> 6) | (m_op & 0x03);
if (trap_if_set[code])
{
if (SR & conditions[code])
execute_trap(addr);
execute_trap(trapno);
}
else
{
if (!(SR & conditions[code]))
execute_trap(addr);
execute_trap(trapno);
}
}

View File

@ -346,7 +346,7 @@ private:
void ignore_pcrel();
void hyperstone_br();
void execute_trap(uint32_t addr);
void execute_trap(uint8_t trapno);
void execute_int(uint32_t addr);
void execute_exception(uint8_t trapno);
void execute_software();
@ -475,7 +475,7 @@ private:
void static_generate_exception(drcuml_block &block, uml::code_label &label);
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 mode, uml::parameter targetpc, const opcode_desc *desc, bool update_cycles = true);
void generate_branch(drcuml_block &block, uml::parameter mode, uml::parameter targetpc, const opcode_desc *desc);
void generate_update_cycles(drcuml_block &block);
void generate_checksum_block(drcuml_block &block, compiler_state &compiler, const opcode_desc *seqhead, const opcode_desc *seqlast);
void generate_sequence_instruction(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);

View File

@ -327,44 +327,12 @@ static inline void alloc_handle(drcuml_state &drcuml, uml::code_handle *&handlep
void hyperstone_device::static_generate_exception(drcuml_block &block, uml::code_label &label)
{
/* add a global entry for this */
// add a global entry for this
alloc_handle(*m_drcuml, m_exception, "exception");
UML_HANDLE(block, *m_exception);
UML_GETEXP(block, I0); // I0 = exception code
if (machine().debug_flags & DEBUG_FLAG_ENABLED)
{
UML_MOV(block, mem(&m_core->arg0), I0); // let the debugger know
UML_CALLC(block, &c_funcs::debugger_exception_hook, this);
}
generate_get_trap_addr(block, label, uml::I0); // I0 = target PC
UML_MOV(block, I4, DRC_SR); // I4 = old SR
UML_MOV(block, I1, I4); // I1 = SR to be updated
UML_ROLAND(block, I3, I4, 32 - FP_SHIFT, 0x7f); // I3 = old FP
UML_ROLAND(block, I2, I4, 32 - FL_SHIFT, 0xf); // I2 = old FL
UML_MOVc(block, uml::COND_Z, I2, 16); // convert FL == 0 to 16
UML_ADD(block, I3, I3, I2); // I3 = updated FP
UML_SHL(block, I2, I3, FP_SHIFT); // I2 = updated FP:...
UML_OR(block, I2, I2, (2 << FL_SHIFT) | S_MASK | L_MASK); // I2 = updated FP:FL:..:S:..T:L:..:M:..
UML_ROLINS(block, I1, I2, 0, FP_MASK | FL_MASK | S_MASK | T_MASK | L_MASK | M_MASK);
UML_MOV(block, DRC_SR, I1); // store updated SR
UML_AND(block, I3, I3, 0x3f); // save old PC at updated (FP)^
UML_AND(block, I2, DRC_PC, ~uint32_t(1));
UML_ROLINS(block, I2, I4, 32 - S_SHIFT, 1);
UML_STORE(block, (void *)m_core->local_regs, I3, I2, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I3, I3, 1); // save old SR at updated (FP + 1)^
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I4, SIZE_DWORD, SCALE_x4);
UML_MOV(block, DRC_PC, I0); // branch to exception handler
UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), 2);
UML_CALLHc(block, uml::COND_S, *m_out_of_cycles);
UML_HASHJMP(block, 1, I0, *m_nocode); // T cleared and S set - mode will always be 1
UML_GETEXP(block, I0);
generate_trap_exception_or_int<IS_EXCEPTION>(block, label, uml::I0);
}
@ -728,17 +696,16 @@ void hyperstone_device::log_add_disasm_comment(drcuml_block &block, uint32_t pc,
generate_branch
------------------------------------------------------------------*/
void hyperstone_device::generate_branch(drcuml_block &block, uml::parameter mode, uml::parameter targetpc, const opcode_desc *desc, bool update_cycles)
void hyperstone_device::generate_branch(drcuml_block &block, uml::parameter mode, uml::parameter targetpc, const opcode_desc *desc)
{
// clobbers I0 and I1 if mode is BRANCH_TARGET_DYNAMIC
if (desc)
UML_ROLINS(block, DRC_SR, ((desc->length >> 1) << ILC_SHIFT) | P_MASK, 0, ILC_MASK | P_MASK);
if (update_cycles)
generate_update_cycles(block);
generate_update_cycles(block);
/* update the cycles and jump through the hash table to the target */
// update the cycles and jump through the hash table to the target
const uml::parameter pc = (targetpc != BRANCH_TARGET_DYNAMIC) ? targetpc : DRC_PC;
const uml::parameter m = (mode != BRANCH_TARGET_DYNAMIC) ? mode : uml::I0;
if (mode == BRANCH_TARGET_DYNAMIC)

View File

@ -471,11 +471,20 @@ void hyperstone_device::generate_update_flags_addsubs(drcuml_block &block, compi
template <hyperstone_device::trap_exception_or_int TYPE>
void hyperstone_device::generate_trap_exception_or_int(drcuml_block &block, uml::code_label &label, uml::parameter trapno)
{
// expects exception handler address in I0 and cycles in I7 (updated)
// expects cycles in I7 (updated)
// clobbers I0, I1, I2, I3 and I4
const uint32_t set_flags = (TYPE == IS_INT) ? (S_MASK | L_MASK | I_MASK) : (S_MASK | L_MASK);
const uint32_t clear_flags = T_MASK | M_MASK;
const uint32_t update_sr = FP_MASK | FL_MASK | set_flags | clear_flags;
UML_ADD(block, I7, I7, mem(&m_core->clock_cycles_2));
if ((TYPE != IS_INT) && (machine().debug_flags & DEBUG_FLAG_ENABLED))
{
UML_MOV(block, mem(&m_core->arg0), trapno); // let the debugger know
UML_CALLC(block, &c_funcs::debugger_exception_hook, this);
}
generate_get_trap_addr(block, label, trapno); // I0 = target PC
UML_MOV(block, I4, DRC_SR); // I4 = old SR
@ -487,9 +496,8 @@ void hyperstone_device::generate_trap_exception_or_int(drcuml_block &block, uml:
UML_ADD(block, I3, I3, I2); // I3 = updated FP
UML_SHL(block, I2, I3, FP_SHIFT); // I2 = updated FP:...
UML_OR(block, I2, I2, ((TYPE != IS_TRAP) ? 2 : 6) << FL_SHIFT); // I2 = updated FP:FL:...
UML_ROLINS(block, I1, I2, 0, FP_MASK | FL_MASK | M_MASK | T_MASK);// update FP and FL, clear M and T, set S and L, set I for INT
UML_OR(block, I1, I1, (TYPE == IS_INT) ? (S_MASK | L_MASK | I_MASK) : (S_MASK | L_MASK));
UML_OR(block, I2, I2, (((TYPE != IS_TRAP) ? 2 : 6) << FL_SHIFT) | set_flags);
UML_ROLINS(block, I1, I2, 0, update_sr); // update SR value
UML_MOV(block, DRC_SR, I1); // store updated SR
UML_AND(block, I3, I3, 0x3f); // save old PC at updated (FP)^
@ -500,8 +508,10 @@ void hyperstone_device::generate_trap_exception_or_int(drcuml_block &block, uml:
UML_AND(block, I3, I3, 0x3f);
UML_STORE(block, (void *)m_core->local_regs, I3, I4, SIZE_DWORD, SCALE_x4);
UML_ADD(block, I7, I7, mem(&m_core->clock_cycles_2)); // assume exception dispatch takes two cycles
UML_MOV(block, DRC_PC, I0); // branch to exception handler
generate_branch(block, 1, uml::I0, nullptr, true); // T cleared and S set - mode will always be 1
generate_branch(block, 1, uml::I0, nullptr); // T cleared and S set - mode will always be 1
}
void hyperstone_device::generate_int(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc, uint32_t addr)
@ -1003,6 +1013,7 @@ void hyperstone_device::generate_xm(drcuml_block &block, compiler_state &compile
UML_SHL(block, I0, I1, sub_type & 3);
// FIXME: exception before branch
generate_set_dst(block, compiler, desc, DST_GLOBAL, dst_code, uml::I0, uml::I3, true);
if (sub_type < 4)
@ -1102,6 +1113,7 @@ void hyperstone_device::generate_sums(drcuml_block &block, compiler_state &compi
generate_update_flags_addsubs(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
// FIXME: exception before branch
generate_set_dst(block, compiler, desc, DST_GLOBAL, dst_code, uml::I0, uml::I3, true);
generate_trap_on_overflow(block, compiler, desc, uml::I2);
}
@ -1290,6 +1302,7 @@ void hyperstone_device::generate_adds(drcuml_block &block, compiler_state &compi
generate_update_flags_addsubs(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
// FIXME: exception before branch
generate_set_dst(block, compiler, desc, DST_GLOBAL, dst_code, uml::I0, uml::I3, false);
generate_trap_on_overflow(block, compiler, desc, uml::I2);
}
@ -1403,6 +1416,7 @@ void hyperstone_device::generate_subs(drcuml_block &block, compiler_state &compi
generate_update_flags_addsubs(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
// FIXME: exception before branch
generate_set_dst(block, compiler, desc, DST_GLOBAL, dst_code, uml::I0, uml::I3, false);
generate_trap_on_overflow(block, compiler, desc, uml::I2);
}
@ -1493,6 +1507,7 @@ void hyperstone_device::generate_negs(drcuml_block &block, compiler_state &compi
generate_update_flags_addsubs(block, compiler, uml::I2);
UML_MOV(block, DRC_SR, I2);
// FIXME: exception before branch
generate_set_dst(block, compiler, desc, DST_GLOBAL, dst_code, uml::I0, uml::I3, true);
if (!SRC_GLOBAL || (src_code != SR_REGISTER)) // negating carry cannot result in overflow
@ -4086,12 +4101,11 @@ void hyperstone_device::generate_trap_op(drcuml_block &block, compiler_state &co
};
const uint16_t op = desc->opptr.w[0];
generate_check_delay_pc(block, compiler, desc);
const uint8_t trapno = (op & 0xfc) >> 2;
const uint8_t code = ((op & 0x300) >> 6) | (op & 0x03);
generate_check_delay_pc(block, compiler, desc);
UML_TEST(block, DRC_SR, conditions[code]);
const int skip_trap = compiler.m_labelnum++;