diff options
Diffstat (limited to 'src/emu/cpu/melps4/melps4.c')
-rw-r--r-- | src/emu/cpu/melps4/melps4.c | 256 |
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(); } } |