diff options
author | 2015-05-30 22:51:54 +0200 | |
---|---|---|
committer | 2015-05-30 22:51:54 +0200 | |
commit | 1e170b1336c6e21b953fbdb81ddc8614541b680b (patch) | |
tree | e630847473aff5fd0bc56276e71f92fa4912c8ea /src/emu/cpu | |
parent | 99855c456f44b989ec12b48da108ef03c217dd09 (diff) |
added branch/call/return opcodes
Diffstat (limited to 'src/emu/cpu')
-rw-r--r-- | src/emu/cpu/melps4/m58846.c | 2 | ||||
-rw-r--r-- | src/emu/cpu/melps4/melps4.c | 32 | ||||
-rw-r--r-- | src/emu/cpu/melps4/melps4.h | 16 | ||||
-rw-r--r-- | src/emu/cpu/melps4/melps4op.inc | 64 |
4 files changed, 96 insertions, 18 deletions
diff --git a/src/emu/cpu/melps4/m58846.c b/src/emu/cpu/melps4/m58846.c index e4842d28a6a..bcc50e06ca3 100644 --- a/src/emu/cpu/melps4/m58846.c +++ b/src/emu/cpu/melps4/m58846.c @@ -52,7 +52,7 @@ void m58846_device::device_start() melps4_cpu_device::device_start(); // set fixed state - m_bm_page = 2; + m_sm_page = 2; m_int_page = 1; } diff --git a/src/emu/cpu/melps4/melps4.c b/src/emu/cpu/melps4/melps4.c index b9172f7745d..342147892b3 100644 --- a/src/emu/cpu/melps4/melps4.c +++ b/src/emu/cpu/melps4/melps4.c @@ -44,9 +44,10 @@ 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", m_intp ? 'P':'p', m_inte ? 'I':'i', + m_sm ? 'S':'s', m_cps ? 'D':'d', m_cy ? 'C':'c' ); @@ -83,10 +84,14 @@ void melps4_cpu_device::device_start() m_prev_op = 0; m_bitmask = 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_prohibit_irq = false; m_a = 0; m_b = 0; @@ -110,10 +115,15 @@ void melps4_cpu_device::device_start() save_item(NAME(m_prev_op)); save_item(NAME(m_bitmask)); + 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_prohibit_irq)); save_item(NAME(m_a)); save_item(NAME(m_b)); @@ -131,7 +141,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("%5s").noshow(); state_add(MELPS4_PC, "PC", m_pc).formatstr("%04X"); state_add(MELPS4_A, "A", m_a).formatstr("%2d"); // show in decimal @@ -158,6 +168,11 @@ void melps4_cpu_device::device_start() void melps4_cpu_device::device_reset() { + m_sm = m_sms = false; + m_ba_flag = false; + m_prohibit_irq = false; + + m_skip = false; m_op = m_prev_op = 0; m_pc = m_prev_pc = 0; m_inte = 0; @@ -192,6 +207,10 @@ void melps4_cpu_device::execute_run() // remember previous state m_prev_op = m_op; m_prev_pc = m_pc; + + // irq is not accepted during skip or LXY, LA, EI, DI, RT/RTS/RTI or any branch + //.. + m_prohibit_irq = false; // fetch next opcode debugger_instruction_hook(this, m_pc); @@ -201,6 +220,13 @@ 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; + } + else + execute_one(); } } diff --git a/src/emu/cpu/melps4/melps4.h b/src/emu/cpu/melps4/melps4.h index d8b9380f7d7..ba6c18f4695 100644 --- a/src/emu/cpu/melps4/melps4.h +++ b/src/emu/cpu/melps4/melps4.h @@ -52,9 +52,11 @@ public: , m_prgwidth(prgwidth) , m_datawidth(datawidth) , m_stack_levels(3) - , m_bm_page(14) + , m_sm_page(14) , m_int_page(12) , m_xami_mask(0xf) + , m_sp_mask(0x7<<4) + , m_ba_op(0x01) { } protected: @@ -86,29 +88,35 @@ protected: int m_icount; - // fixed settings or mask options + // fixed settings or mask options that differ between MCU type int m_prgwidth; // number of bits and bitmask for ROM/RAM size int m_datawidth; // " int m_prgmask; // " int m_datamask; // " UINT8 m_stack_levels; // 3 levels on MELPS 4, 12 levels on MELPS 41/42 - UINT8 m_bm_page; // short BM default page: 14 on '40 to '44, 2 on '45,'46, 0 on '47 + UINT8 m_sm_page; // subroutine default page: 14 on '40 to '44, 2 on '45,'46, 0 on '47 UINT8 m_int_page; // interrupt routine page: 12 on '40 to '44, 1 on '45,'46, 2 on '47 UINT8 m_xami_mask; // mask option for XAMI opcode on '40,'41,'45 (0xf for others) + UINT16 m_sp_mask; // SP opcode location(middle 4 bits): 7 on '40 to '46, 3 on '47 + UINT16 m_ba_op; // BA opcode location: 1 on '40 to '46, N/A on '47 // internal state, misc regs UINT16 m_pc; // program counter (11 or 10-bit) UINT16 m_prev_pc; - UINT16 m_stack[12]; // callstack + UINT16 m_stack[12]; // callstack (SK0-SKx, same size as PC) UINT16 m_op; UINT16 m_prev_op; UINT8 m_bitmask; // opcode bit argument + bool m_sm, m_sms; // subroutine mode flag + stack + bool m_ba_flag; // temp flag indicates BA opcode was executed + UINT8 m_sp_param; // temp register holding SP opcode parameter UINT8 m_cps; // DP,CY or DP',CY' selected bool m_skip; // skip next opcode UINT8 m_inte; // interrupt enable flag UINT8 m_intp; // external interrupt polarity ('40 to '44) + bool m_prohibit_irq; // interrupt is prohibited during certain opcodes // work registers (unless specified, each is 4-bit) UINT8 m_a; // accumulator diff --git a/src/emu/cpu/melps4/melps4op.inc b/src/emu/cpu/melps4/melps4op.inc index 296a5b1a39a..5d2f6d38a94 100644 --- a/src/emu/cpu/melps4/melps4op.inc +++ b/src/emu/cpu/melps4/melps4op.inc @@ -19,10 +19,16 @@ inline void melps4_cpu_device::ram_w(UINT8 data) void melps4_cpu_device::pop_pc() { + m_pc = m_stack[0]; + for (int i = 0; i < m_stack_levels-1; i++) + m_stack[i] = m_stack[i+1]; } void melps4_cpu_device::push_pc() { + for (int i = m_stack_levels-1; i >= 1; i--) + m_stack[i] = m_stack[i-1]; + m_stack[0] = m_pc; } @@ -82,6 +88,7 @@ void melps4_cpu_device::op_tax() void melps4_cpu_device::op_lxy() { // LXY x,y: load immediate into X,Y, skip any next LXY + m_prohibit_irq = true; if ((m_op & ~0x3f) != (m_prev_op & ~0x3f)) { m_x = m_op >> 4 & 3; @@ -181,6 +188,7 @@ void melps4_cpu_device::op_xami() void melps4_cpu_device::op_la() { // LA n: load immediate into A, skip any next LA + m_prohibit_irq = true; if ((m_op & ~0xf) != (m_prev_op & ~0xf)) m_a = m_op & 0xf; } @@ -437,26 +445,57 @@ void melps4_cpu_device::op_snz2() void melps4_cpu_device::op_ba() { - // BA: x - op_illegal(); + // BA: indicate next branch is indirect + m_prohibit_irq = true; + m_ba_flag = true; } void melps4_cpu_device::op_sp() { - // SP: set page - op_illegal(); + // SP: set page for next branch + // note: mnemonic is guessed, manual names it BL or BML + m_prohibit_irq = true; + m_sp_param = m_op & 0xf; } void melps4_cpu_device::op_b() { - // B xy: branch in current page - op_illegal(); + // B xy: branch + m_prohibit_irq = true; + + // determine new page: + // - short call: subroutine page + // - short jump: current page, or sub. page + 1 when in sub. mode + // - long jump/call(B/BM preceded by SP): temp SP register + UINT8 page = m_pc >> 7; + if ((m_prev_op & ~0xf) == m_sp_mask) + { + m_sm = false; + page = m_sp_param; + } + else if (m_sm) + page = m_sm_page | (m_op >> 7 & 1); + + m_pc = page << 7 | (m_op & 0x7f); + + // if BA opcode was executed, set PC low 4 bits to A + if (m_ba_flag) + { + m_ba_flag = false; + m_pc = (m_pc & ~0xf) | m_a; + } } void melps4_cpu_device::op_bm() { - // BM xy call subroutine on page 14 - op_illegal(); + // BM xy call subroutine + // don't push stack on short calls when in subroutine mode + if (!m_sm || (m_prev_op & ~0xf) == m_sp_mask) + push_pc(); + + // set subroutine mode - it is reset after long jump/call or return + m_sm = true; + op_b(); } @@ -465,7 +504,9 @@ void melps4_cpu_device::op_bm() void melps4_cpu_device::op_rt() { // RT: return from subroutine - op_illegal(); + m_prohibit_irq = true; + m_sm = false; + pop_pc(); } void melps4_cpu_device::op_rts() @@ -478,7 +519,8 @@ void melps4_cpu_device::op_rts() void melps4_cpu_device::op_rti() { // RTI: return from interrupt routine - op_illegal(); + op_rt(); + m_sm = m_sms; } @@ -587,12 +629,14 @@ void melps4_cpu_device::op_ei() { // EI: enable interrupt flag m_inte = 1; + m_prohibit_irq = true; } void melps4_cpu_device::op_di() { // DI: disable interrupt flag m_inte = 0; + m_prohibit_irq = true; } void melps4_cpu_device::op_inth() |