cpu/e132xs: Moved interrupt check to the beginning of instruction execution.

* Fixes interrupts not being serviced while tracing.
* Further improves recompiler performance.
* Fixes recompiler interrupt check function calling itself recursively.
* Also added debugger exception hook calls to interpreter and recompiler.
This commit is contained in:
Vas Crabb 2025-03-26 08:38:27 +11:00
parent add2015ce3
commit 213e1b5857
5 changed files with 271 additions and 328 deletions

View File

@ -37,7 +37,6 @@
- What actually happens on trying to load memory to PC or SR?
- Verify register wrapping with sregf/dregf on hardware
- Tracing doesn't work properly
Interrupts are not serviced while tracing
DRC does not generate trace exceptions on branch or return
- Interpreter does not implement privilege check on setting L flag
- DRC does not update ILC and P on some privilege error exceptions
@ -159,7 +158,7 @@ e116t_device::e116t_device(const machine_config &mconfig, const char *tag, devic
//-------------------------------------------------
e116xt_device::e116xt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: hyperstone_device(mconfig, tag, owner, clock, E116XT, 16, 16, address_map_constructor(FUNC(e116t_device::e116_8k_iram_map), this))
: hyperstone_device(mconfig, tag, owner, clock, E116XT, 16, 16, address_map_constructor(FUNC(e116xt_device::e116_8k_iram_map), this))
{
}
@ -750,8 +749,11 @@ void hyperstone_device::execute_int(uint32_t addr)
}
/* TODO: mask Parity Error and Extended Overflow exceptions */
void hyperstone_device::execute_exception(uint32_t addr)
void hyperstone_device::execute_exception(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;
@ -830,161 +832,100 @@ void hyperstone_device::execute_software()
template <hyperstone_device::is_timer TIMER>
void hyperstone_device::check_interrupts()
{
/* Interrupt-Lock flag isn't set */
if (GET_L || m_core->intblock > 0)
// Interrupt-Lock flag isn't set
if (GET_L)
return;
/* quick exit if nothing */
// quick exit if nothing
if (TIMER == NO_TIMER && (ISR & 0x7f) == 0)
return;
if (TIMER == NO_TIMER)
// IO3 is priority 5; state is in bit 6 of ISR; FCR bit 10 enables input and FCR bit 8 inhibits interrupt
if (IO3_LINE_STATE && (FCR & 0x00000500) == 0x00000400)
{
/* IO3 is priority 5; state is in bit 6 of ISR; FCR bit 10 enables input and FCR bit 8 inhibits interrupt */
if (IO3_LINE_STATE && (FCR & 0x00000500) == 0x00000400)
{
standard_irq_callback(IRQ_IO3, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_IO3));
return;
}
/* INT1 is priority 7; state is in bit 0 of ISR; FCR bit 28 inhibits interrupt */
if (INT1_LINE_STATE && (FCR & 0x10000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT1, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT1));
return;
}
/* INT2 is priority 9; state is in bit 1 of ISR; FCR bit 29 inhibits interrupt */
if (INT2_LINE_STATE && (FCR & 0x20000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT2, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT2));
return;
}
/* INT3 is priority 11; state is in bit 2 of ISR; FCR bit 30 inhibits interrupt */
if (INT3_LINE_STATE && (FCR & 0x40000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT3, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT3));
return;
}
/* INT4 is priority 13; state is in bit 3 of ISR; FCR bit 31 inhibits interrupt */
if (INT4_LINE_STATE && (FCR & 0x80000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT4, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT4));
return;
}
/* IO1 is priority 14; state is in bit 4 of ISR; FCR bit 2 enables input and FCR bit 0 inhibits interrupt */
if (IO1_LINE_STATE && (FCR & 0x00000005) == 0x00000004)
{
standard_irq_callback(IRQ_IO1, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_IO1));
return;
}
/* IO2 is priority 15; state is in bit 5 of ISR; FCR bit 6 enables input and FCR bit 4 inhibits interrupt */
if (IO2_LINE_STATE && (FCR & 0x00000050) == 0x00000040)
{
standard_irq_callback(IRQ_IO2, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_IO2));
return;
}
standard_irq_callback(IRQ_IO3, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_IO3));
return;
}
else
// timer int might be priority 6 if FCR bits 20-21 == 3; FCR bit 23 inhibits interrupt
if (TIMER && (FCR & 0x00b00000) == 0x00300000)
{
/* IO3 is priority 5; state is in bit 6 of ISR; FCR bit 10 enables input and FCR bit 8 inhibits interrupt */
if (IO3_LINE_STATE && (FCR & 0x00000500) == 0x00000400)
{
standard_irq_callback(IRQ_IO3, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_IO3));
return;
}
m_core->timer_int_pending = 0;
execute_int(get_trap_addr(TRAPNO_TIMER));
return;
}
/* timer int might be priority 6 if FCR bits 20-21 == 3; FCR bit 23 inhibits interrupt */
if (TIMER && (FCR & 0x00b00000) == 0x00300000)
{
m_core->timer_int_pending = 0;
execute_int(get_trap_addr(TRAPNO_TIMER));
return;
}
// INT1 is priority 7; state is in bit 0 of ISR; FCR bit 28 inhibits interrupt
if (INT1_LINE_STATE && (FCR & 0x10000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT1, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT1));
return;
}
/* INT1 is priority 7; state is in bit 0 of ISR; FCR bit 28 inhibits interrupt */
if (INT1_LINE_STATE && (FCR & 0x10000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT1, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT1));
return;
}
// timer int might be priority 8 if FCR bits 20-21 == 2; FCR bit 23 inhibits interrupt
if (TIMER && (FCR & 0x00b00000) == 0x00200000)
{
m_core->timer_int_pending = 0;
execute_int(get_trap_addr(TRAPNO_TIMER));
return;
}
/* timer int might be priority 8 if FCR bits 20-21 == 2; FCR bit 23 inhibits interrupt */
if (TIMER && (FCR & 0x00b00000) == 0x00200000)
{
m_core->timer_int_pending = 0;
execute_int(get_trap_addr(TRAPNO_TIMER));
return;
}
// INT2 is priority 9; state is in bit 1 of ISR; FCR bit 29 inhibits interrupt
if (INT2_LINE_STATE && (FCR & 0x20000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT2, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT2));
return;
}
/* INT2 is priority 9; state is in bit 1 of ISR; FCR bit 29 inhibits interrupt */
if (INT2_LINE_STATE && (FCR & 0x20000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT2, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT2));
return;
}
// timer int might be priority 10 if FCR bits 20-21 == 1; FCR bit 23 inhibits interrupt
if (TIMER && (FCR & 0x00b00000) == 0x00100000)
{
m_core->timer_int_pending = 0;
execute_int(get_trap_addr(TRAPNO_TIMER));
return;
}
/* timer int might be priority 10 if FCR bits 20-21 == 1; FCR bit 23 inhibits interrupt */
if (TIMER && (FCR & 0x00b00000) == 0x00100000)
{
m_core->timer_int_pending = 0;
execute_int(get_trap_addr(TRAPNO_TIMER));
return;
}
// INT3 is priority 11; state is in bit 2 of ISR; FCR bit 30 inhibits interrupt
if (INT3_LINE_STATE && (FCR & 0x40000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT3, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT3));
return;
}
/* INT3 is priority 11; state is in bit 2 of ISR; FCR bit 30 inhibits interrupt */
if (INT3_LINE_STATE && (FCR & 0x40000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT3, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT3));
return;
}
// timer int might be priority 12 if FCR bits 20-21 == 0; FCR bit 23 inhibits interrupt
if (TIMER && (FCR & 0x00b00000) == 0x00000000)
{
m_core->timer_int_pending = 0;
execute_int(get_trap_addr(TRAPNO_TIMER));
return;
}
/* timer int might be priority 12 if FCR bits 20-21 == 0; FCR bit 23 inhibits interrupt */
if (TIMER && (FCR & 0x00b00000) == 0x00000000)
{
m_core->timer_int_pending = 0;
execute_int(get_trap_addr(TRAPNO_TIMER));
return;
}
// INT4 is priority 13; state is in bit 3 of ISR; FCR bit 31 inhibits interrupt
if (INT4_LINE_STATE && (FCR & 0x80000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT4, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT4));
return;
}
/* INT4 is priority 13; state is in bit 3 of ISR; FCR bit 31 inhibits interrupt */
if (INT4_LINE_STATE && (FCR & 0x80000000) == 0x00000000)
{
standard_irq_callback(IRQ_INT4, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_INT4));
return;
}
// IO1 is priority 14; state is in bit 4 of ISR; FCR bit 2 enables input and FCR bit 0 inhibits interrupt
if (IO1_LINE_STATE && (FCR & 0x00000005) == 0x00000004)
{
standard_irq_callback(IRQ_IO1, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_IO1));
return;
}
/* IO1 is priority 14; state is in bit 4 of ISR; FCR bit 2 enables input and FCR bit 0 inhibits interrupt */
if (IO1_LINE_STATE && (FCR & 0x00000005) == 0x00000004)
{
standard_irq_callback(IRQ_IO1, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_IO1));
return;
}
/* IO2 is priority 15; state is in bit 5 of ISR; FCR bit 6 enables input and FCR bit 4 inhibits interrupt */
if (IO2_LINE_STATE && (FCR & 0x00000050) == 0x00000040)
{
standard_irq_callback(IRQ_IO2, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_IO2));
return;
}
// IO2 is priority 15; state is in bit 5 of ISR; FCR bit 6 enables input and FCR bit 4 inhibits interrupt
if (IO2_LINE_STATE && (FCR & 0x00000050) == 0x00000040)
{
standard_irq_callback(IRQ_IO2, m_core->global_regs[0]);
execute_int(get_trap_addr(TRAPNO_IO2));
return;
}
}
@ -1603,17 +1544,9 @@ void hyperstone_device::execute_run()
return;
}
if (m_core->intblock < 0)
m_core->intblock = 0;
if (!m_instruction_length_valid)
SET_ILC(get_instruction_length(m_pr16(PC)));
if (m_core->timer_int_pending)
check_interrupts<IS_TIMER>();
else
check_interrupts<NO_TIMER>();
while (m_core->icount > 0)
{
#if E132XS_LOG_INTERPRETER_REGS
@ -1622,6 +1555,15 @@ void hyperstone_device::execute_run()
debugger_instruction_hook(PC);
if (--m_core->intblock <= 0)
{
m_core->intblock = 0;
if (m_core->timer_int_pending)
check_interrupts<IS_TIMER>();
else
check_interrupts<NO_TIMER>();
}
OP = m_pr16(PC);
PC += 2;
@ -1898,19 +1840,7 @@ void hyperstone_device::execute_run()
}
if (GET_T && GET_P && !m_core->delay_slot) /* Not in a Delayed Branch instructions */
{
uint32_t addr = get_trap_addr(TRAPNO_TRACE_EXCEPTION);
execute_exception(addr);
}
if (--m_core->intblock <= 0)
{
m_core->intblock = 0;
if (m_core->timer_int_pending)
check_interrupts<IS_TIMER>();
else
check_interrupts<NO_TIMER>();
}
execute_exception(TRAPNO_TRACE_EXCEPTION);
}
}

View File

@ -118,27 +118,6 @@ class hyperstone_device : public cpu_device, public hyperstone_disassembler::con
public:
virtual ~hyperstone_device() override;
inline void ccfunc_unimplemented();
inline void ccfunc_print();
inline void ccfunc_total_cycles();
inline void ccfunc_standard_irq_callback();
#if E132XS_LOG_DRC_REGS || E132XS_LOG_INTERPRETER_REGS
void dump_registers();
#endif
void update_timer_prescale();
void compute_tr();
void adjust_timer_interrupt();
void e116_16k_iram_map(address_map &map) ATTR_COLD;
void e116_4k_iram_map(address_map &map) ATTR_COLD;
void e116_8k_iram_map(address_map &map) ATTR_COLD;
void e132_16k_iram_map(address_map &map) ATTR_COLD;
void e132_4k_iram_map(address_map &map) ATTR_COLD;
void e132_8k_iram_map(address_map &map) ATTR_COLD;
static uint32_t imm_length(uint16_t op);
protected:
// compilation boundaries -- how far back/forward does the analysis extend?
enum : u32
@ -277,28 +256,44 @@ protected:
hyperstone_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock,
const device_type type, uint32_t prg_data_width, uint32_t io_data_width, address_map_constructor internal_map);
// device-level overrides
// device_t implementation
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
virtual void device_stop() override ATTR_COLD;
// device_execute_interface overrides
// device_execute_interface implementation
virtual uint32_t execute_min_cycles() const noexcept override;
virtual uint32_t execute_max_cycles() const noexcept override;
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
// device_memory_interface overrides
// device_memory_interface implementation
virtual space_config_vector memory_space_config() const override;
// device_disasm_interface overrides
// device_disasm_interface implementation
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
virtual u8 get_fp() const override;
virtual bool get_h() const override;
// device_state_interface overrides
// device_state_interface implementation
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
#if E132XS_LOG_DRC_REGS || E132XS_LOG_INTERPRETER_REGS
void dump_registers();
#endif
void update_timer_prescale();
void compute_tr();
void adjust_timer_interrupt();
void e116_16k_iram_map(address_map &map) ATTR_COLD;
void e116_4k_iram_map(address_map &map) ATTR_COLD;
void e116_8k_iram_map(address_map &map) ATTR_COLD;
void e132_16k_iram_map(address_map &map) ATTR_COLD;
void e132_4k_iram_map(address_map &map) ATTR_COLD;
void e132_8k_iram_map(address_map &map) ATTR_COLD;
static uint32_t imm_length(uint16_t op);
// address spaces
const address_space_config m_program_config;
const address_space_config m_io_config;
@ -353,7 +348,7 @@ private:
void hyperstone_br();
void execute_trap(uint32_t addr);
void execute_int(uint32_t addr);
void execute_exception(uint32_t addr);
void execute_exception(uint8_t trapno);
void execute_software();
template <reg_bank DST_GLOBAL> uint64_t get_double_word(uint8_t dst_code, uint8_t dstf_code) const;
@ -467,6 +462,7 @@ private:
/* internal compiler state */
struct compiler_state;
struct c_funcs;
void execute_run_drc();
void flush_drc_cache();
@ -480,7 +476,7 @@ private:
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_update_cycles(drcuml_block &block, bool check_interrupts = true);
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);
void log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op);

View File

@ -18,6 +18,67 @@ struct hyperstone_device::compiler_state
};
/***************************************************************************
C FUNCTION CALLBACKS
***************************************************************************/
struct hyperstone_device::c_funcs
{
static void unimplemented(void *param)
{
auto &that = *reinterpret_cast<hyperstone_device *>(param);
fatalerror("PC=%08X: Unimplemented op %08X\n", that.PC, that.m_core->arg0);
}
static void print(void *param)
{
auto &that = *reinterpret_cast<hyperstone_device *>(param);
printf("%c: %08x\n", (char)that.m_core->arg0, that.m_core->arg1);
}
static void standard_irq_callback(void *param)
{
auto &that = *reinterpret_cast<hyperstone_device *>(param);
that.standard_irq_callback(that.m_core->arg0, that.m_core->global_regs[0]);
}
static void debugger_exception_hook(void *param)
{
auto &that = *reinterpret_cast<hyperstone_device *>(param);
that.debugger_exception_hook(int32_t(that.m_core->arg0));
}
static void adjust_timer_interrupt(void *param)
{
reinterpret_cast<hyperstone_device *>(param)->adjust_timer_interrupt();
}
static void compute_tr(void *param)
{
reinterpret_cast<hyperstone_device *>(param)->compute_tr();
}
static void update_timer_prescale(void *param)
{
reinterpret_cast<hyperstone_device *>(param)->update_timer_prescale();
}
#if E132XS_LOG_DRC_REGS || E132XS_LOG_INTERPRETER_REGS
static void dump_registers(void *param)
{
reinterpret_cast<hyperstone_device *>(param)->dump_registers();
}
#endif
static void total_cycles(void *param)
{
auto &that = *reinterpret_cast<hyperstone_device *>(param);
that.m_core->numcycles = that.total_cycles();
}
};
#define DRC_PC uml::mem(&m_core->global_regs[0])
#define DRC_SR uml::mem(&m_core->global_regs[1])
@ -49,84 +110,6 @@ void hyperstone_device::execute_run_drc()
}
/***************************************************************************
C FUNCTION CALLBACKS
***************************************************************************/
/*-------------------------------------------------
cfunc_unimplemented - handler for
unimplemented opcdes
-------------------------------------------------*/
inline void hyperstone_device::ccfunc_unimplemented()
{
fatalerror("PC=%08X: Unimplemented op %08X\n", PC, m_core->arg0);
}
inline void hyperstone_device::ccfunc_print()
{
printf("%c: %08x\n", (char)m_core->arg0, m_core->arg1);
}
inline void hyperstone_device::ccfunc_standard_irq_callback()
{
standard_irq_callback(m_core->arg0, m_core->global_regs[0]);
}
static void cfunc_unimplemented(void *param)
{
((hyperstone_device *)param)->ccfunc_unimplemented();
}
static void cfunc_adjust_timer_interrupt(void *param)
{
((hyperstone_device *)param)->adjust_timer_interrupt();
}
static void cfunc_compute_tr(void *param)
{
((hyperstone_device *)param)->compute_tr();
}
static void cfunc_update_timer_prescale(void *param)
{
((hyperstone_device *)param)->update_timer_prescale();
}
static void cfunc_standard_irq_callback(void *param)
{
((hyperstone_device *)param)->ccfunc_standard_irq_callback();
}
#if 0
static void cfunc_print(void *param)
{
((hyperstone_device *)param)->ccfunc_print();
}
#endif
#if E132XS_LOG_DRC_REGS
static void cfunc_dump_registers(void *param)
{
((hyperstone_device *)param)->dump_registers();
}
#endif
/*-------------------------------------------------
cfunc_total_cycles - compute the total number
of cycles executed so far
-------------------------------------------------*/
void hyperstone_device::ccfunc_total_cycles()
{
m_core->numcycles = total_cycles();
}
static void cfunc_total_cycles(void *param)
{
((hyperstone_device *)param)->ccfunc_total_cycles();
}
/***************************************************************************
CACHE MANAGEMENT
***************************************************************************/
@ -278,7 +261,6 @@ void hyperstone_device::code_compile_block(uint8_t mode, offs_t pc)
UML_LABEL(block, seqhead->pc | 0x80000000);
UML_MOV(block, I7, 0);
UML_CALLH(block, *m_interrupt_checks);
/* iterate over instructions in the sequence and compile them */
for (curdesc = seqhead; curdesc != seqlast->next(); curdesc = curdesc->next())
@ -350,6 +332,11 @@ void hyperstone_device::static_generate_exception(drcuml_block &block, uml::code
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
@ -392,8 +379,6 @@ void hyperstone_device::static_generate_interrupt_checks(drcuml_block &block, um
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);
UML_TEST(block, DRC_SR, L_MASK);
UML_JMPc(block, uml::COND_NZ, done_int);
@ -413,7 +398,7 @@ void hyperstone_device::static_generate_interrupt_checks(drcuml_block &block, um
UML_JMP(block, done_int);
UML_LABEL(block, take_int);
UML_CALLC(block, cfunc_standard_irq_callback, this);
UML_CALLC(block, &c_funcs::standard_irq_callback, this);
UML_JMP(block, dispatch_int);
UML_LABEL(block, take_timer);
@ -638,17 +623,8 @@ void hyperstone_device::generate_interrupt_checks(drcuml_block &block, uml::code
an exception if out
-------------------------------------------------*/
void hyperstone_device::generate_update_cycles(drcuml_block &block, bool check_interrupts)
void hyperstone_device::generate_update_cycles(drcuml_block &block)
{
// clobbers I0
UML_SUB(block, I0, mem(&m_core->intblock), 1);
UML_MOVc(block, uml::COND_S, I0, 0);
UML_MOV(block, mem(&m_core->intblock), I0);
if (check_interrupts)
UML_CALLH(block, *m_interrupt_checks);
UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I7);
UML_MOV(block, I7, 0);
UML_CALLHc(block, uml::COND_LE, *m_out_of_cycles);
@ -754,7 +730,7 @@ void hyperstone_device::log_add_disasm_comment(drcuml_block &block, uint32_t pc,
void hyperstone_device::generate_branch(drcuml_block &block, uml::parameter mode, uml::parameter targetpc, const opcode_desc *desc, bool update_cycles)
{
// clobbers I0, I1, I2, I3 and I4 if update_cycles is true
// 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);
@ -792,7 +768,7 @@ void hyperstone_device::generate_sequence_instruction(drcuml_block &block, compi
UML_MAPVAR(block, MAPVAR_PC, expc);
#if E132XS_LOG_DRC_REGS
UML_CALLC(block, cfunc_dump_registers, this);
UML_CALLC(block, &c_funcs::dump_registers, this);
#endif
// if we are debugging, call the debugger
@ -802,6 +778,12 @@ void hyperstone_device::generate_sequence_instruction(drcuml_block &block, compi
UML_DEBUG(block, desc->pc);
}
// check for pending interrupts
UML_SUB(block, I0, mem(&m_core->intblock), 1);
UML_MOVc(block, uml::COND_S, I0, 0);
UML_MOV(block, mem(&m_core->intblock), I0);
UML_CALLHc(block, uml::COND_LE, *m_interrupt_checks);
if (!(desc->flags & OPFLAG_VIRTUAL_NOOP))
{
// compile the instruction
@ -809,7 +791,7 @@ void hyperstone_device::generate_sequence_instruction(drcuml_block &block, compi
{
UML_MOV(block, DRC_PC, desc->pc);
UML_MOV(block, mem(&m_core->arg0), desc->opptr.w[0]);
UML_CALLC(block, cfunc_unimplemented, this);
UML_CALLC(block, &c_funcs::unimplemented, this);
}
}
}

View File

@ -157,10 +157,10 @@ void hyperstone_device::generate_set_global_register(drcuml_block &block, compil
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
UML_TEST(block, I5, 0x80000000);
UML_JMPc(block, uml::COND_NZ, skip_compute_tr);
UML_CALLC(block, cfunc_compute_tr, this);
UML_CALLC(block, cfunc_update_timer_prescale, this);
UML_CALLC(block, &c_funcs::compute_tr, this);
UML_CALLC(block, &c_funcs::update_timer_prescale, this);
UML_LABEL(block, skip_compute_tr);
UML_CALLC(block, cfunc_adjust_timer_interrupt, this);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
}
else if (dst_code == TCR_REGISTER)
{
@ -169,16 +169,16 @@ void hyperstone_device::generate_set_global_register(drcuml_block &block, compil
UML_CMP(block, I6, I5);
UML_JMPc(block, uml::COND_E, done);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
UML_CALLC(block, cfunc_adjust_timer_interrupt, this);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
UML_LABEL(block, done);
}
else if (dst_code == TR_REGISTER)
{
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
UML_MOV(block, mem(&m_core->tr_base_value), I5);
UML_CALLC(block, cfunc_total_cycles, this);
UML_CALLC(block, &c_funcs::total_cycles, this);
UML_DMOV(block, mem(&m_core->tr_base_cycles), mem(&m_core->numcycles));
UML_CALLC(block, cfunc_adjust_timer_interrupt, this);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
}
else if (dst_code == ISR_REGISTER)
{
@ -191,7 +191,7 @@ void hyperstone_device::generate_set_global_register(drcuml_block &block, compil
UML_XOR(block, I6, I6, I5);
UML_TEST(block, I6, 0x80000000);
UML_JMPc(block, uml::COND_Z, skip_adjust_timer);
UML_CALLC(block, cfunc_adjust_timer_interrupt, this);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
UML_LABEL(block, skip_adjust_timer);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), I5);
}
@ -291,10 +291,10 @@ void hyperstone_device::generate_set_global_register_high(drcuml_block &block, c
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
UML_TEST(block, src, 0x80000000);
UML_JMPc(block, uml::COND_NZ, skip_compute_tr);
UML_CALLC(block, cfunc_compute_tr, this);
UML_CALLC(block, cfunc_update_timer_prescale, this);
UML_CALLC(block, &c_funcs::compute_tr, this);
UML_CALLC(block, &c_funcs::update_timer_prescale, this);
UML_LABEL(block, skip_compute_tr);
UML_CALLC(block, cfunc_adjust_timer_interrupt, this);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
}
break;
case TCR_REGISTER: // G22 Timer Compare Register
@ -304,16 +304,16 @@ void hyperstone_device::generate_set_global_register_high(drcuml_block &block, c
UML_CMP(block, I6, src);
UML_JMPc(block, uml::COND_E, done);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
UML_CALLC(block, cfunc_adjust_timer_interrupt, this);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
UML_LABEL(block, done);
}
break;
case TR_REGISTER: // G23 Timer Register
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
UML_MOV(block, mem(&m_core->tr_base_value), src);
UML_CALLC(block, cfunc_total_cycles, this);
UML_CALLC(block, &c_funcs::total_cycles, this);
UML_DMOV(block, mem(&m_core->tr_base_cycles), mem(&m_core->numcycles));
UML_CALLC(block, cfunc_adjust_timer_interrupt, this);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
break;
case ISR_REGISTER: // G25 Input Status Register (read-only)
break;
@ -324,7 +324,7 @@ void hyperstone_device::generate_set_global_register_high(drcuml_block &block, c
UML_XOR(block, I6, I6, src);
UML_TEST(block, I6, 0x80000000);
UML_JMPc(block, uml::COND_Z, skip_adjust_timer);
UML_CALLC(block, cfunc_adjust_timer_interrupt, this);
UML_CALLC(block, &c_funcs::adjust_timer_interrupt, this);
UML_LABEL(block, skip_adjust_timer);
UML_MOV(block, mem(&m_core->global_regs[dst_code]), src);
}
@ -387,7 +387,19 @@ void hyperstone_device::generate_set_dst(drcuml_block &block, compiler_state &co
if (code == PC_REGISTER)
{
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
if (src.is_int_register() && (desc->targetpc == BRANCH_TARGET_DYNAMIC))
{
UML_AND(block, src, src, ~uint32_t(1));
generate_branch(block, compiler.m_mode, src, desc);
}
else if (src.is_immediate() && (desc->targetpc == BRANCH_TARGET_DYNAMIC))
{
generate_branch(block, compiler.m_mode, src.immediate() & ~uint32_t(1), desc);
}
else
{
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
}
}
}
else
@ -489,7 +501,7 @@ void hyperstone_device::generate_trap_exception_or_int(drcuml_block &block, uml:
UML_STORE(block, (void *)m_core->local_regs, I3, I4, SIZE_DWORD, SCALE_x4);
UML_MOV(block, DRC_PC, I0); // branch to exception handler
generate_branch(block, 1, DRC_PC, nullptr, true); // T cleared and S set - mode will always be 1
generate_branch(block, 1, uml::I0, nullptr, true); // 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)
@ -581,7 +593,7 @@ void hyperstone_device::generate_software(drcuml_block &block, compiler_state &c
UML_ROLINS(block, I0, I4, FP_SHIFT, FP_MASK); // SET_FP(reg)
UML_MOV(block, DRC_SR, I0);
generate_branch(block, compiler.m_mode & 0x1, desc->targetpc, desc); // T cleared - only keep S in bit zero of mode
generate_branch(block, compiler.m_mode & 0x1, uml::I5, desc); // T cleared - only keep S in bit zero of mode
}
@ -1138,7 +1150,7 @@ void hyperstone_device::generate_get_global_register(drcuml_block &block, compil
UML_CMP(block, mem(&m_core->icount), I2);
UML_MOVc(block, uml::COND_BE, I2, 0);
UML_SUB(block, mem(&m_core->icount), mem(&m_core->icount), I2);
UML_CALLC(block, cfunc_compute_tr, this);
UML_CALLC(block, &c_funcs::compute_tr, this);
UML_MOV(block, I5, mem(&m_core->tr_result));
UML_JMP(block, done);
@ -1207,7 +1219,8 @@ void hyperstone_device::generate_mov(drcuml_block &block, compiler_state &compil
if (dst_code == PC_REGISTER)
{
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
UML_AND(block, I5, I5, ~uint32_t(1));
generate_branch(block, compiler.m_mode, uml::I5, desc);
}
UML_JMP(block, done);
@ -1637,7 +1650,7 @@ void hyperstone_device::generate_movi(drcuml_block &block, compiler_state &compi
if (dst_code == PC_REGISTER)
{
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
generate_branch(block, compiler.m_mode, src & ~uint32_t(1), desc);
}
UML_JMP(block, done);
@ -2584,7 +2597,10 @@ void hyperstone_device::generate_ldxx1(drcuml_block &block, compiler_state &comp
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == PC_REGISTER)
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler.m_mode, uml::I1, desc);
}
}
else
{
@ -2603,7 +2619,10 @@ void hyperstone_device::generate_ldxx1(drcuml_block &block, compiler_state &comp
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == PC_REGISTER)
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler.m_mode, uml::I1, desc);
}
}
else
{
@ -2624,8 +2643,11 @@ void hyperstone_device::generate_ldxx1(drcuml_block &block, compiler_state &comp
if (SRC_GLOBAL)
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == 0)
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
if (src_code == PC_REGISTER)
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler.m_mode, uml::I1, desc);
}
}
else
{
@ -2651,7 +2673,10 @@ void hyperstone_device::generate_ldxx1(drcuml_block &block, compiler_state &comp
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == PC_REGISTER)
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler.m_mode, uml::I1, desc);
}
}
else
{
@ -2668,7 +2693,10 @@ void hyperstone_device::generate_ldxx1(drcuml_block &block, compiler_state &comp
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == PC_REGISTER)
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler.m_mode, uml::I1, desc);
}
}
else
{
@ -2701,7 +2729,10 @@ void hyperstone_device::generate_ldxx1(drcuml_block &block, compiler_state &comp
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == 0)
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler.m_mode, uml::I1, desc);
}
}
else
{
@ -2720,7 +2751,10 @@ void hyperstone_device::generate_ldxx1(drcuml_block &block, compiler_state &comp
{
generate_set_global_register_low(block, compiler, src_code, uml::I1);
if (src_code == PC_REGISTER)
generate_branch(block, compiler.m_mode, desc->targetpc, desc);
{
UML_AND(block, I1, I1, ~uint32_t(1));
generate_branch(block, compiler.m_mode, uml::I1, desc);
}
}
else
{
@ -4029,11 +4063,12 @@ void hyperstone_device::generate_call(drcuml_block &block, compiler_state &compi
UML_ROLINS(block, DRC_SR, 6, FL_SHIFT, FL_MASK);
UML_AND(block, DRC_SR, DRC_SR, ~M_MASK);
UML_ADD(block, DRC_PC, I2, extra_s & ~1);
UML_ADD(block, I2, I2, extra_s & ~uint32_t(1));
UML_MOV(block, DRC_PC, I2);
UML_MOV(block, mem(&m_core->intblock), 2);
generate_branch(block, compiler.m_mode, desc->targetpc, nullptr);
generate_branch(block, compiler.m_mode, uml::I2, nullptr);
//TODO: add interrupt locks, errors, ....
}

View File

@ -37,13 +37,13 @@ void hyperstone_device::hyperstone_chk()
if (SRC_GLOBAL && (src_code == SR_REGISTER))
{
if (dreg == 0)
execute_exception(get_trap_addr(TRAPNO_RANGE_ERROR));
execute_exception(TRAPNO_RANGE_ERROR);
}
else
{
const uint32_t sreg = (SRC_GLOBAL ? m_core->global_regs : m_core->local_regs)[src_code];
if ((SRC_GLOBAL && (src_code == PC_REGISTER)) ? (dreg >= sreg) : (dreg > sreg))
execute_exception(get_trap_addr(TRAPNO_RANGE_ERROR));
execute_exception(TRAPNO_RANGE_ERROR);
}
m_core->icount -= m_core->clock_cycles_1;
@ -81,7 +81,7 @@ void hyperstone_device::hyperstone_movd()
const uint32_t new_s = SR & S_MASK;
const uint32_t new_l = SR & L_MASK;
if ((!old_s && new_s) || (!new_s && !old_l && new_l))
execute_exception(get_trap_addr(TRAPNO_PRIVILEGE_ERROR));
execute_exception(TRAPNO_PRIVILEGE_ERROR);
for (int difference = util::sext(GET_FP - ((SP & 0x1fc) >> 2), 7); difference < 0; difference++)
{
@ -157,7 +157,7 @@ void hyperstone_device::hyperstone_divsu()
//Z -> undefined
//N -> undefined
SR |= V_MASK;
execute_exception(get_trap_addr(TRAPNO_RANGE_ERROR));
execute_exception(TRAPNO_RANGE_ERROR);
}
else
{
@ -214,7 +214,7 @@ void hyperstone_device::hyperstone_xm()
if (sub_type < 4)
{
if ((SRC_GLOBAL && ((src_code == PC_REGISTER)) ? (sreg >= extra_u) : (sreg > extra_u)))
execute_exception(get_trap_addr(TRAPNO_RANGE_ERROR));
execute_exception(TRAPNO_RANGE_ERROR);
}
m_core->icount -= m_core->clock_cycles_1;
@ -304,7 +304,7 @@ void hyperstone_device::hyperstone_sums()
m_core->icount -= m_core->clock_cycles_1;
if ((SR & V_MASK) && src_code != SR_REGISTER)
execute_exception(get_trap_addr(TRAPNO_RANGE_ERROR));
execute_exception(TRAPNO_RANGE_ERROR);
}
@ -347,7 +347,7 @@ void hyperstone_device::hyperstone_mov()
SR &= ~H_MASK;
if (DST_GLOBAL && h && !(SR & S_MASK))
{
execute_exception(get_trap_addr(TRAPNO_PRIVILEGE_ERROR));
execute_exception(TRAPNO_PRIVILEGE_ERROR);
}
else
{
@ -449,7 +449,7 @@ void hyperstone_device::hyperstone_adds()
m_core->icount -= m_core->clock_cycles_1;
if (SR & V_MASK)
execute_exception(get_trap_addr(TRAPNO_RANGE_ERROR));
execute_exception(TRAPNO_RANGE_ERROR);
}
@ -667,7 +667,7 @@ void hyperstone_device::hyperstone_subs()
m_core->icount -= m_core->clock_cycles_1;
if (SR & V_MASK)
execute_exception(get_trap_addr(TRAPNO_RANGE_ERROR));
execute_exception(TRAPNO_RANGE_ERROR);
}
@ -802,7 +802,7 @@ void hyperstone_device::hyperstone_negs()
m_core->icount -= m_core->clock_cycles_1;
if (GET_V)
execute_exception(get_trap_addr(TRAPNO_RANGE_ERROR));
execute_exception(TRAPNO_RANGE_ERROR);
}
@ -854,7 +854,7 @@ void hyperstone_device::hyperstone_movi()
SR &= ~H_MASK;
if (DST_GLOBAL && h && !(SR & S_MASK))
{
execute_exception(get_trap_addr(TRAPNO_PRIVILEGE_ERROR));
execute_exception(TRAPNO_PRIVILEGE_ERROR);
}
else
{
@ -981,7 +981,7 @@ void hyperstone_device::hyperstone_addsi()
m_core->icount -= m_core->clock_cycles_1;
if (SR & V_MASK)
execute_exception(get_trap_addr(TRAPNO_RANGE_ERROR));
execute_exception(TRAPNO_RANGE_ERROR);
}
@ -2559,7 +2559,7 @@ void hyperstone_device::hyperstone_frame()
while (difference < 0);
if (tmp_flag)
execute_exception(get_trap_addr(TRAPNO_FRAME_ERROR));
execute_exception(TRAPNO_FRAME_ERROR);
}
// TODO: More than 1 cycle!