mirror of
https://github.com/holub/mame
synced 2025-10-07 09:25:34 +03:00
added interrupt handling
This commit is contained in:
parent
ba0057dfc0
commit
215e9a8be9
@ -10,7 +10,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "m58846.h"
|
#include "m58846.h"
|
||||||
#include "debugger.h"
|
//#include "debugger.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -50,6 +50,9 @@ offs_t m58846_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *o
|
|||||||
void m58846_device::device_start()
|
void m58846_device::device_start()
|
||||||
{
|
{
|
||||||
melps4_cpu_device::device_start();
|
melps4_cpu_device::device_start();
|
||||||
|
|
||||||
|
m_timer[0] = timer_alloc(0);
|
||||||
|
m_timer[1] = timer_alloc(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -61,6 +64,52 @@ void m58846_device::device_start()
|
|||||||
void m58846_device::device_reset()
|
void m58846_device::device_reset()
|
||||||
{
|
{
|
||||||
melps4_cpu_device::device_reset();
|
melps4_cpu_device::device_reset();
|
||||||
|
|
||||||
|
// timer 1 runs continuously
|
||||||
|
reset_timer1();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// timers
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void m58846_device::reset_timer1()
|
||||||
|
{
|
||||||
|
// reset 7-bit prescaler
|
||||||
|
attotime base = attotime::from_ticks(6 * 128, unscaled_clock());
|
||||||
|
m_timer[0]->adjust(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
void m58846_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||||
|
{
|
||||||
|
switch (id)
|
||||||
|
{
|
||||||
|
// timer 1
|
||||||
|
case 0:
|
||||||
|
m_irqflag[1] = true;
|
||||||
|
m_possible_irq = true;
|
||||||
|
reset_timer1();
|
||||||
|
break;
|
||||||
|
|
||||||
|
// timer 2
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert_always(FALSE, "Unknown id in m58846_device::device_timer");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void m58846_device::write_v(UINT8 data)
|
||||||
|
{
|
||||||
|
// d0: enable timer 1 irq
|
||||||
|
m_tmr_irq_enabled[0] = (data & 1) ? true : false;
|
||||||
|
m_possible_irq = true;
|
||||||
|
|
||||||
|
m_v = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,6 +29,13 @@ protected:
|
|||||||
|
|
||||||
// device_disasm_interface overrides
|
// device_disasm_interface overrides
|
||||||
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
|
virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options);
|
||||||
|
|
||||||
|
// timers
|
||||||
|
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||||
|
virtual void write_v(UINT8 data);
|
||||||
|
|
||||||
|
emu_timer *m_timer[2];
|
||||||
|
void reset_timer1();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,12 +46,15 @@ void melps4_cpu_device::state_string_export(const device_state_entry &entry, std
|
|||||||
{
|
{
|
||||||
// obviously not from a single flags register, letters are made up
|
// obviously not from a single flags register, letters are made up
|
||||||
case STATE_GENFLAGS:
|
case STATE_GENFLAGS:
|
||||||
strprintf(str, "%c%c%c%c%c",
|
strprintf(str, "%c%c%c%c%c %c%c%c",
|
||||||
m_intp ? 'P':'p',
|
m_intp ? 'P':'p',
|
||||||
m_inte ? 'I':'i',
|
m_inte ? 'I':'i',
|
||||||
m_sm ? 'S':'s',
|
m_sm ? 'S':'s',
|
||||||
m_cps ? 'D':'d',
|
m_cps ? 'D':'d',
|
||||||
m_cy ? 'C':'c'
|
m_cy ? 'C':'c',
|
||||||
|
m_irqflag[0] ? 'X':'.', // exf
|
||||||
|
m_irqflag[1] ? '1':'.', // 1f
|
||||||
|
m_irqflag[2] ? '2':'.' // 2f
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -111,7 +114,11 @@ void melps4_cpu_device::device_start()
|
|||||||
m_skip = false;
|
m_skip = false;
|
||||||
m_inte = 0;
|
m_inte = 0;
|
||||||
m_intp = 1;
|
m_intp = 1;
|
||||||
|
m_irqflag[0] = m_irqflag[1] = m_irqflag[2] = false;
|
||||||
|
m_tmr_irq_enabled[0] = m_tmr_irq_enabled[1] = false;
|
||||||
|
m_int_state = 0;
|
||||||
m_prohibit_irq = false;
|
m_prohibit_irq = false;
|
||||||
|
m_possible_irq = false;
|
||||||
|
|
||||||
m_a = 0;
|
m_a = 0;
|
||||||
m_b = 0;
|
m_b = 0;
|
||||||
@ -147,7 +154,11 @@ void melps4_cpu_device::device_start()
|
|||||||
save_item(NAME(m_skip));
|
save_item(NAME(m_skip));
|
||||||
save_item(NAME(m_inte));
|
save_item(NAME(m_inte));
|
||||||
save_item(NAME(m_intp));
|
save_item(NAME(m_intp));
|
||||||
|
save_item(NAME(m_irqflag));
|
||||||
|
save_item(NAME(m_tmr_irq_enabled));
|
||||||
|
save_item(NAME(m_int_state));
|
||||||
save_item(NAME(m_prohibit_irq));
|
save_item(NAME(m_prohibit_irq));
|
||||||
|
save_item(NAME(m_possible_irq));
|
||||||
|
|
||||||
save_item(NAME(m_a));
|
save_item(NAME(m_a));
|
||||||
save_item(NAME(m_b));
|
save_item(NAME(m_b));
|
||||||
@ -165,7 +176,7 @@ void melps4_cpu_device::device_start()
|
|||||||
|
|
||||||
// register state for debugger
|
// register state for debugger
|
||||||
state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow();
|
state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow();
|
||||||
state_add(STATE_GENFLAGS, "GENFLAGS", m_cy).formatstr("%5s").noshow();
|
state_add(STATE_GENFLAGS, "GENFLAGS", m_cy).formatstr("%9s").noshow();
|
||||||
|
|
||||||
state_add(MELPS4_PC, "PC", m_pc).formatstr("%04X");
|
state_add(MELPS4_PC, "PC", m_pc).formatstr("%04X");
|
||||||
state_add(MELPS4_A, "A", m_a).formatstr("%2d"); // show in decimal
|
state_add(MELPS4_A, "A", m_a).formatstr("%2d"); // show in decimal
|
||||||
@ -194,18 +205,20 @@ void melps4_cpu_device::device_reset()
|
|||||||
{
|
{
|
||||||
m_sm = m_sms = false;
|
m_sm = m_sms = false;
|
||||||
m_ba_flag = false;
|
m_ba_flag = false;
|
||||||
m_prohibit_irq = false;
|
|
||||||
|
|
||||||
m_skip = false;
|
m_skip = false;
|
||||||
m_op = m_prev_op = 0;
|
m_op = m_prev_op = 0;
|
||||||
m_pc = m_prev_pc = 0;
|
m_pc = m_prev_pc = 0;
|
||||||
m_inte = 0;
|
|
||||||
m_intp = 1;
|
|
||||||
op_lcps(); // CPS=0
|
op_lcps(); // CPS=0
|
||||||
|
|
||||||
m_v = 0;
|
// clear interrupts
|
||||||
m_w = 0;
|
m_inte = 0;
|
||||||
|
m_intp = 1;
|
||||||
|
write_v(0);
|
||||||
|
write_w(0);
|
||||||
|
m_irqflag[0] = m_irqflag[1] = m_irqflag[2] = false;
|
||||||
|
m_prohibit_irq = false;
|
||||||
|
m_possible_irq = false;
|
||||||
|
|
||||||
// clear ports
|
// clear ports
|
||||||
write_d_pin(MELPS4_PORTD_CLR, 0);
|
write_d_pin(MELPS4_PORTD_CLR, 0);
|
||||||
write_gen_port(MELPS4_PORTS, 0);
|
write_gen_port(MELPS4_PORTS, 0);
|
||||||
@ -291,6 +304,73 @@ void melps4_cpu_device::write_d_pin(int bit, int state)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//-------------------------------------------------
|
||||||
|
// interrupts
|
||||||
|
//-------------------------------------------------
|
||||||
|
|
||||||
|
void melps4_cpu_device::execute_set_input(int line, int state)
|
||||||
|
{
|
||||||
|
state = (state) ? 1 : 0;
|
||||||
|
|
||||||
|
switch (line)
|
||||||
|
{
|
||||||
|
// external interrupt
|
||||||
|
case MELPS4_INPUT_LINE_INT:
|
||||||
|
// irq on rising/falling edge
|
||||||
|
if (state != m_int_state && state == m_intp)
|
||||||
|
{
|
||||||
|
m_irqflag[0] = true;
|
||||||
|
m_possible_irq = true;
|
||||||
|
}
|
||||||
|
m_int_state = state;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// timer input pin
|
||||||
|
case MELPS4_INPUT_LINE_T:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void melps4_cpu_device::do_interrupt(int which)
|
||||||
|
{
|
||||||
|
m_inte = 0;
|
||||||
|
m_irqflag[which] = false;
|
||||||
|
|
||||||
|
m_icount--;
|
||||||
|
push_pc();
|
||||||
|
m_sms = m_sm;
|
||||||
|
m_sm = false;
|
||||||
|
m_op = 0; // fake nop
|
||||||
|
m_pc = m_int_page << 7 | (which * 2);
|
||||||
|
|
||||||
|
standard_irq_callback(which);
|
||||||
|
}
|
||||||
|
|
||||||
|
void melps4_cpu_device::check_interrupt()
|
||||||
|
{
|
||||||
|
if (!m_inte)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int which = 0;
|
||||||
|
|
||||||
|
// assume that lower irq vectors have higher priority
|
||||||
|
if (m_irqflag[0])
|
||||||
|
which = 0;
|
||||||
|
else if (m_irqflag[1] && m_tmr_irq_enabled[0])
|
||||||
|
which = 1;
|
||||||
|
else if (m_irqflag[2] && m_tmr_irq_enabled[1])
|
||||||
|
which = 2;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
do_interrupt(which);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// execute
|
// execute
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
@ -314,8 +394,14 @@ void melps4_cpu_device::execute_run()
|
|||||||
m_prev_op = m_op;
|
m_prev_op = m_op;
|
||||||
m_prev_pc = m_pc;
|
m_prev_pc = m_pc;
|
||||||
|
|
||||||
// irq is not accepted during skip or LXY, LA, EI, DI, RT/RTS/RTI or any branch
|
// Interrupts are not accepted during skips or LXY, LA, EI, DI, RT/RTS/RTI or any branch.
|
||||||
//..
|
// Documentation is conflicting here: older docs say that it is allowed during skips,
|
||||||
|
// newer docs specifically say when interrupts are prohibited.
|
||||||
|
if (m_possible_irq && !m_prohibit_irq && !m_skip)
|
||||||
|
{
|
||||||
|
m_possible_irq = false;
|
||||||
|
check_interrupt();
|
||||||
|
}
|
||||||
m_prohibit_irq = false;
|
m_prohibit_irq = false;
|
||||||
|
|
||||||
// fetch next opcode
|
// fetch next opcode
|
||||||
|
@ -60,6 +60,12 @@ enum
|
|||||||
MELPS4_PORTU
|
MELPS4_PORTU
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MELPS4_INPUT_LINE_INT = 0,
|
||||||
|
MELPS4_INPUT_LINE_T
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// pinout reference
|
// pinout reference
|
||||||
@ -142,8 +148,9 @@ protected:
|
|||||||
virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 6 - 1) / 6; } // 6 t-states per machine cycle
|
virtual UINT64 execute_clocks_to_cycles(UINT64 clocks) const { return (clocks + 6 - 1) / 6; } // 6 t-states per machine cycle
|
||||||
virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 6); } // "
|
virtual UINT64 execute_cycles_to_clocks(UINT64 cycles) const { return (cycles * 6); } // "
|
||||||
virtual UINT32 execute_min_cycles() const { return 1; }
|
virtual UINT32 execute_min_cycles() const { return 1; }
|
||||||
virtual UINT32 execute_max_cycles() const { return 1; }
|
virtual UINT32 execute_max_cycles() const { return 1+1; } // max opcode cycles + interrupt duration
|
||||||
virtual UINT32 execute_input_lines() const { return 3; } // up to 3 (some internal)
|
virtual UINT32 execute_input_lines() const { return 3; } // up to 3 (some internal)
|
||||||
|
virtual void execute_set_input(int line, int state);
|
||||||
virtual void execute_run();
|
virtual void execute_run();
|
||||||
virtual void execute_one();
|
virtual void execute_one();
|
||||||
|
|
||||||
@ -189,14 +196,18 @@ protected:
|
|||||||
UINT8 m_port_s; // "
|
UINT8 m_port_s; // "
|
||||||
UINT8 m_port_f; // "
|
UINT8 m_port_f; // "
|
||||||
|
|
||||||
bool m_sm, m_sms; // subroutine mode flag + stack
|
bool m_sm, m_sms; // subroutine mode flag + irq stack
|
||||||
bool m_ba_flag; // temp flag indicates BA opcode was executed
|
bool m_ba_flag; // temp flag indicates BA opcode was executed
|
||||||
UINT8 m_sp_param; // temp register holding SP opcode parameter
|
UINT8 m_sp_param; // temp register holding SP opcode parameter
|
||||||
UINT8 m_cps; // DP,CY or DP',CY' selected
|
UINT8 m_cps; // DP,CY or DP',CY' selected
|
||||||
bool m_skip; // skip next opcode
|
bool m_skip; // skip next opcode
|
||||||
UINT8 m_inte; // interrupt enable flag
|
UINT8 m_inte; // interrupt enable flag
|
||||||
UINT8 m_intp; // external interrupt polarity ('40 to '44)
|
int m_intp; // external interrupt polarity ('40 to '44)
|
||||||
|
bool m_irqflag[3]; // irq flags: exf, 1f, 2f (external, timer 1, timer 2)
|
||||||
|
bool m_tmr_irq_enabled[2];
|
||||||
|
int m_int_state; // INT pin state
|
||||||
bool m_prohibit_irq; // interrupt is prohibited during certain opcodes
|
bool m_prohibit_irq; // interrupt is prohibited during certain opcodes
|
||||||
|
bool m_possible_irq; // indicate that irq needs to be rechecked
|
||||||
|
|
||||||
// work registers (unless specified, each is 4-bit)
|
// work registers (unless specified, each is 4-bit)
|
||||||
UINT8 m_a; // accumulator
|
UINT8 m_a; // accumulator
|
||||||
@ -225,6 +236,11 @@ protected:
|
|||||||
devcb_write8 m_write_g;
|
devcb_write8 m_write_g;
|
||||||
devcb_write8 m_write_u;
|
devcb_write8 m_write_u;
|
||||||
devcb_write_line m_write_t;
|
devcb_write_line m_write_t;
|
||||||
|
|
||||||
|
virtual void write_v(UINT8 data) { m_v = data; }
|
||||||
|
virtual void write_w(UINT8 data) { m_w = data; }
|
||||||
|
virtual void do_interrupt(int which);
|
||||||
|
virtual void check_interrupt();
|
||||||
|
|
||||||
UINT8 read_gen_port(int port);
|
UINT8 read_gen_port(int port);
|
||||||
void write_gen_port(int port, UINT8 data);
|
void write_gen_port(int port, UINT8 data);
|
||||||
|
@ -419,25 +419,27 @@ void melps4_cpu_device::op_tab2()
|
|||||||
void melps4_cpu_device::op_tva()
|
void melps4_cpu_device::op_tva()
|
||||||
{
|
{
|
||||||
// TVA: transfer A to timer control V
|
// TVA: transfer A to timer control V
|
||||||
m_v = m_a;
|
write_v(m_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void melps4_cpu_device::op_twa()
|
void melps4_cpu_device::op_twa()
|
||||||
{
|
{
|
||||||
// TWA: transfer A to timer control W
|
// TWA: transfer A to timer control W
|
||||||
m_w = m_a;
|
write_w(m_a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void melps4_cpu_device::op_snz1()
|
void melps4_cpu_device::op_snz1()
|
||||||
{
|
{
|
||||||
// SNZ1: skip next on flag 1F
|
// SNZ1: skip next on flag 1F
|
||||||
op_illegal();
|
m_skip = m_irqflag[1];
|
||||||
|
m_irqflag[1] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void melps4_cpu_device::op_snz2()
|
void melps4_cpu_device::op_snz2()
|
||||||
{
|
{
|
||||||
// SNZ2: skip next on flag 2F
|
// SNZ2: skip next on flag 2F
|
||||||
op_illegal();
|
m_skip = m_irqflag[2];
|
||||||
|
m_irqflag[2] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -631,6 +633,7 @@ void melps4_cpu_device::op_ei()
|
|||||||
{
|
{
|
||||||
// EI: enable interrupt flag
|
// EI: enable interrupt flag
|
||||||
m_prohibit_irq = true;
|
m_prohibit_irq = true;
|
||||||
|
m_possible_irq = true;
|
||||||
m_inte = 1;
|
m_inte = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user