hmcs400: add standby/stop mode

This commit is contained in:
hap 2024-09-20 19:36:47 +02:00
parent e5f4ac1f3a
commit 1c03b83957
5 changed files with 60 additions and 40 deletions

View file

@ -458,7 +458,7 @@ void hmcs45_cpu_device::write_r(u8 index, u8 data)
// interrupt/timer
//-------------------------------------------------
void hmcs40_cpu_device::do_interrupt()
void hmcs40_cpu_device::take_interrupt()
{
push_stack();
m_ie = 0;
@ -576,7 +576,7 @@ void hmcs40_cpu_device::execute_run()
// check/handle interrupt
if (m_ie && (m_iri || m_irt) && !m_block_int)
do_interrupt();
take_interrupt();
m_block_int = false;
// fetch next opcode

View file

@ -202,7 +202,7 @@ protected:
void cycle();
void increment_tc();
void do_interrupt();
void take_interrupt();
// opcode handlers
void op_illegal();

View file

@ -166,8 +166,6 @@ hd614089_device::hd614089_device(const machine_config &mconfig, const char *tag,
void hmcs400_cpu_device::device_start()
{
assert(HMCS400_INPUT_LINE_INT0 == 0 && HMCS400_INPUT_LINE_INT1 == 1);
m_program = &space(AS_PROGRAM);
m_data = &space(AS_DATA);
@ -188,6 +186,8 @@ void hmcs400_cpu_device::device_start()
m_spy = 0;
m_st = 0;
m_ca = 0;
m_standby = false;
m_stop = false;
memset(m_r, 0, sizeof(m_r));
memset(m_r_mask, 0, sizeof(m_r_mask));
@ -219,6 +219,8 @@ void hmcs400_cpu_device::device_start()
save_item(NAME(m_spy));
save_item(NAME(m_st));
save_item(NAME(m_ca));
save_item(NAME(m_standby));
save_item(NAME(m_stop));
save_item(NAME(m_r));
save_item(NAME(m_r_mask));
@ -262,6 +264,8 @@ void hmcs400_cpu_device::device_reset()
m_pc = 0;
m_sp = 0x3ff;
m_st = 1;
m_standby = false;
m_stop = false;
// clear peripherals
m_irq_flags = 0xaaa8; // IM=1, IF=0, IE=0
@ -535,29 +539,37 @@ void hmcs400_cpu_device::pmr_w(offs_t offset, u8 data, u8 mem_mask)
write_r(3, m_r[3]);
}
void hmcs400_cpu_device::take_interrupt(int irq)
{
cycle();
cycle();
push_stack();
m_irq_flags &= ~1;
standard_irq_callback(irq, m_pc);
u8 vector = irq * 2 + 2;
m_prev_pc = m_pc = vector;
}
void hmcs400_cpu_device::check_interrupts()
{
// irq priority and vectors are in the same order as the irq control flags
u16 irq = m_irq_flags;
// irq priority is in the same order as the irq control flags
u16 irq = m_irq_flags >> 2;
for (int i = 0; i < 7; i++)
{
irq >>= 2;
// do irq when IF=1 and IM=0
// pending irq when IF=1 and IM=0
if ((irq & 3) == 1)
{
cycle();
cycle();
push_stack();
m_irq_flags &= ~1;
if (m_irq_flags & 1)
take_interrupt(i);
standard_irq_callback(i, m_pc);
m_pc = i * 2 + 2;
m_prev_pc = m_pc;
m_standby = false;
return;
}
irq >>= 2;
}
}
@ -578,24 +590,16 @@ void hmcs400_cpu_device::execute_set_input(int line, int state)
{
state = state ? 1 : 0;
switch (line)
{
case HMCS400_INPUT_LINE_INT0: case HMCS400_INPUT_LINE_INT1:
{
// active-low, irq on falling edge
state ^= 1;
bool irq = (m_int_line[line] && !state);
m_int_line[line] = state;
if (line != 0 && line != 1)
return;
if (irq)
ext_int_edge(line);
// active-low, irq on falling edge
state ^= 1;
bool irq = (m_int_line[line] && !state);
m_int_line[line] = state;
break;
}
default:
break;
}
if (irq && !m_stop)
ext_int_edge(line);
}
@ -615,7 +619,7 @@ void hmcs400_cpu_device::tm_w(offs_t offset, u8 data, u8 mem_mask)
{ 0x400, 0x100, 0x40, 0x10, 4, 2, 1, 0 }
};
m_timer_mode[offset] = data;
m_timer_mode[offset] = data & 0xf;
m_timer_div[offset] = div[offset][data & 7];
}
@ -705,13 +709,24 @@ u16 hmcs400_cpu_device::fetch()
void hmcs400_cpu_device::execute_run()
{
// in stop mode, the internal clock is not running
if (m_stop)
{
m_icount = 0;
return;
}
while (m_icount > 0)
{
m_prev_pc = m_pc;
check_interrupts();
// check/handle interrupts
if (m_irq_flags & 1)
check_interrupts();
// in standby mode, opcode execution is halted
if (m_standby)
{
cycle();
continue;
}
// fetch next opcode
debugger_instruction_hook(m_pc);

View file

@ -138,6 +138,8 @@ protected:
u8 m_spy; // 4-bit SPY register
u8 m_st; // status flag
u8 m_ca; // carry flag
bool m_standby; // standby mode (SBY opcode)
bool m_stop; // stop mode (STOP opcode)
u8 m_r[10]; // R outputs state
u8 m_r_mask[10];
@ -183,6 +185,7 @@ protected:
u8 tcbu_r(offs_t offset, u8 mem_mask);
void ext_int_edge(int line);
void take_interrupt(int irq);
void check_interrupts();
void clock_timer(int timer);
void clock_prescaler();

View file

@ -676,11 +676,13 @@ void hmcs400_cpu_device::op_sts()
void hmcs400_cpu_device::op_sby()
{
// SBY: Standby Mode
op_todo();
m_standby = true;
}
void hmcs400_cpu_device::op_stop()
{
// STOP: Stop Mode
op_todo();
m_stop = true;
if (m_icount > 0)
m_icount = 0;
}