summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author hap <happppp@users.noreply.github.com>2015-05-30 22:51:54 +0200
committer hap <happppp@users.noreply.github.com>2015-05-30 22:51:54 +0200
commit1e170b1336c6e21b953fbdb81ddc8614541b680b (patch)
treee630847473aff5fd0bc56276e71f92fa4912c8ea /src
parent99855c456f44b989ec12b48da108ef03c217dd09 (diff)
added branch/call/return opcodes
Diffstat (limited to 'src')
-rw-r--r--src/emu/cpu/melps4/m58846.c2
-rw-r--r--src/emu/cpu/melps4/melps4.c32
-rw-r--r--src/emu/cpu/melps4/melps4.h16
-rw-r--r--src/emu/cpu/melps4/melps4op.inc64
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()