summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/cpu/melps4/melps4.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/cpu/melps4/melps4.c')
-rw-r--r--src/emu/cpu/melps4/melps4.c256
1 files changed, 245 insertions, 11 deletions
diff --git a/src/emu/cpu/melps4/melps4.c b/src/emu/cpu/melps4/melps4.c
index b9172f7745d..b7390eaccf5 100644
--- a/src/emu/cpu/melps4/melps4.c
+++ b/src/emu/cpu/melps4/melps4.c
@@ -23,19 +23,23 @@
*M58496: 72-pin QFP CMOS, 2Kx10 ROM, 128x4 internal + 256x4 external RAM, 1 timer, low-power
*M58497: almost same as M58496
- MELPS 760 subfamily has more differences, document them when needed.
+ MELPS 760 family has more differences, document them when needed.
+ MELPS 720 family as well
References:
- - 1982 Mitsubishi LSI Data Book
+ - 1980 and 1982 Mitsubishi LSI Data Books
+ - M34550Mx-XXXFP datasheet (this one is MELPS 720 family)
+
+ TODO:
+ - need more drivers that use this, to be sure that emulation is accurate
+ - add output PLA
*/
#include "melps4.h"
#include "debugger.h"
-#include "melps4op.inc"
-
// disasm
void melps4_cpu_device::state_string_export(const device_state_entry &entry, std::string &str)
@@ -44,11 +48,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
case STATE_GENFLAGS:
- strprintf(str, "%c%c%c%c",
+ strprintf(str, "%c%c%c%c%c %c%c%c",
m_intp ? 'P':'p',
m_inte ? 'I':'i',
+ m_sm ? 'S':'s',
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;
@@ -74,6 +82,20 @@ void melps4_cpu_device::device_start()
m_data = &space(AS_DATA);
m_prgmask = (1 << m_prgwidth) - 1;
m_datamask = (1 << m_datawidth) - 1;
+ m_d_mask = (1 << m_d_pins) - 1;
+
+ // resolve callbacks
+ m_read_k.resolve_safe(0);
+ m_read_d.resolve_safe(0);
+ m_read_s.resolve_safe(0);
+ m_read_f.resolve_safe(0);
+
+ m_write_d.resolve_safe();
+ m_write_s.resolve_safe();
+ m_write_f.resolve_safe();
+ m_write_g.resolve_safe();
+ m_write_u.resolve_safe();
+ m_write_t.resolve_safe();
// zerofill
m_pc = 0;
@@ -83,10 +105,27 @@ void melps4_cpu_device::device_start()
m_prev_op = 0;
m_bitmask = 0;
+ m_port_d = 0;
+ m_port_s = 0;
+ m_port_f = 0;
+ m_port_t = 0;
+
+ m_sm = m_sms = false;
+ m_ba_flag = false;
+ m_sp_param = 0;
m_cps = 0;
m_skip = false;
m_inte = 0;
m_intp = 1;
+ m_irqflag[0] = m_irqflag[1] = m_irqflag[2] = false;
+ m_int_state = 0;
+ m_t_in_state = 0;
+ m_prohibit_irq = false;
+ m_possible_irq = false;
+
+ memset(m_tmr_count, 0, sizeof(m_tmr_count));
+ m_tmr_reload = 0;
+ m_tmr_irq_enabled[0] = m_tmr_irq_enabled[1] = false;
m_a = 0;
m_b = 0;
@@ -110,10 +149,28 @@ void melps4_cpu_device::device_start()
save_item(NAME(m_prev_op));
save_item(NAME(m_bitmask));
+ save_item(NAME(m_port_d));
+ save_item(NAME(m_port_s));
+ save_item(NAME(m_port_f));
+ save_item(NAME(m_port_t));
+
+ save_item(NAME(m_sm));
+ save_item(NAME(m_sms));
+ save_item(NAME(m_ba_flag));
+ save_item(NAME(m_sp_param));
save_item(NAME(m_cps));
save_item(NAME(m_skip));
save_item(NAME(m_inte));
save_item(NAME(m_intp));
+ save_item(NAME(m_irqflag));
+ save_item(NAME(m_int_state));
+ save_item(NAME(m_t_in_state));
+ save_item(NAME(m_prohibit_irq));
+ save_item(NAME(m_possible_irq));
+
+ save_item(NAME(m_tmr_count));
+ save_item(NAME(m_tmr_reload));
+ save_item(NAME(m_tmr_irq_enabled));
save_item(NAME(m_a));
save_item(NAME(m_b));
@@ -131,7 +188,7 @@ void melps4_cpu_device::device_start()
// register state for debugger
state_add(STATE_GENPC, "curpc", m_pc).formatstr("%04X").noshow();
- state_add(STATE_GENFLAGS, "GENFLAGS", m_cy).formatstr("%4s").noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_cy).formatstr("%9s").noshow();
state_add(MELPS4_PC, "PC", m_pc).formatstr("%04X");
state_add(MELPS4_A, "A", m_a).formatstr("%2d"); // show in decimal
@@ -158,14 +215,171 @@ void melps4_cpu_device::device_start()
void melps4_cpu_device::device_reset()
{
+ m_sm = m_sms = false;
+ m_ba_flag = false;
+ m_skip = false;
m_op = m_prev_op = 0;
m_pc = m_prev_pc = 0;
+ op_lcps(); // CPS=0
+
+ // clear interrupts
m_inte = 0;
m_intp = 1;
- op_lcps(); // CPS=0
+ 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
+ write_d_pin(MELPS4_PORTD_CLR, 0);
+ write_gen_port(MELPS4_PORTS, 0);
+ write_gen_port(MELPS4_PORTF, 0);
+ write_gen_port(MELPS4_PORTG, 0);
+ write_gen_port(MELPS4_PORTU, 0);
+ m_write_t(0); m_port_t = 0;
+}
- m_v = 0;
- m_w = 0;
+
+
+//-------------------------------------------------
+// i/o handling
+//-------------------------------------------------
+
+UINT8 melps4_cpu_device::read_gen_port(int port)
+{
+ // input generic port
+ switch (port)
+ {
+ case MELPS4_PORTS:
+ return m_port_s | m_read_s(port, 0xff);
+ case MELPS4_PORTF:
+ return m_port_f | (m_read_f(port, 0xff) & 0xf);
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void melps4_cpu_device::write_gen_port(int port, UINT8 data)
+{
+ // output generic port
+ switch (port)
+ {
+ case MELPS4_PORTS:
+ m_port_s = data;
+ m_write_s(port, data, 0xff);
+ break;
+ case MELPS4_PORTF:
+ m_port_f = data & 0xf;
+ m_write_f(port, data & 0xf, 0xff);
+ break;
+ case MELPS4_PORTG:
+ m_write_g(port, data & 0xf, 0xff);
+ break;
+ case MELPS4_PORTU:
+ m_write_u(port, data & 1, 0xff);
+ break;
+
+ default:
+ break;
+ }
+}
+
+int melps4_cpu_device::read_d_pin(int bit)
+{
+ // read port D, return state of selected pin
+ bit &= 0xf;
+ UINT16 d = (m_port_d | m_read_d(bit, 0xffff)) & m_d_mask;
+ return d >> bit & 1;
+}
+
+void melps4_cpu_device::write_d_pin(int bit, int state)
+{
+ // clear all port D pins
+ if (bit == MELPS4_PORTD_CLR)
+ {
+ m_port_d = 0;
+ m_write_d(bit, 0, 0xffff);
+ }
+
+ // set/reset one port D pin
+ else
+ {
+ bit &= 0xf;
+ m_port_d = ((m_port_d & (~(1 << bit))) | (state << bit)) & m_d_mask;
+ m_write_d(bit, m_port_d, 0xffff);
+ }
+}
+
+
+
+//-------------------------------------------------
+// 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:
+ write_t_in(state);
+ 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);
}
@@ -193,6 +407,16 @@ void melps4_cpu_device::execute_run()
m_prev_op = m_op;
m_prev_pc = m_pc;
+ // 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;
+
// fetch next opcode
debugger_instruction_hook(this, m_pc);
m_icount--;
@@ -201,6 +425,16 @@ void melps4_cpu_device::execute_run()
m_pc = (m_pc & ~0x7f) | ((m_pc + 1) & 0x7f); // stays in the same page
// handle opcode if it's not skipped
- execute_one();
+ if (m_skip)
+ {
+ // if it's a long jump, skip next one as well
+ if (m_op != m_ba_op && (m_op & ~0xf) != m_sp_mask)
+ {
+ m_skip = false;
+ m_op = 0; // fake nop
+ }
+ }
+ else
+ execute_one();
}
}