summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author David Haywood <mamehaze@gmail.com>2019-05-01 00:04:54 +0100
committer ajrhacker <ajrhacker@users.noreply.github.com>2019-04-30 19:04:53 -0400
commitf8656d9246057c3d266f1a898169e9cd700f4746 (patch)
tree0b64e0af5bcea886251e2c87678a696a5a359d0e /src
parentdcfacd8df665ced82c57f7ac83a4e0fe54752c8b (diff)
TV Game Work (progress towards smartfp and wrlshunt) (#4956)
* unsp refactoring / tv game work (nw) * unsp refactoring / tv game work (nw) * srcclean (nw) * more ops (nw) * (nw) * (nw) * guesses (nw) * more guesses (nw) * (nw)
Diffstat (limited to 'src')
-rw-r--r--src/devices/cpu/unsp/unsp.cpp726
-rw-r--r--src/devices/cpu/unsp/unsp.h127
-rw-r--r--src/devices/cpu/unsp/unsp_extended.cpp206
-rw-r--r--src/devices/cpu/unsp/unsp_exxx.cpp161
-rw-r--r--src/devices/cpu/unsp/unsp_fxxx.cpp431
-rw-r--r--src/devices/cpu/unsp/unsp_jumps.cpp160
-rw-r--r--src/devices/cpu/unsp/unsp_other.cpp347
-rw-r--r--src/devices/cpu/unsp/unspdasm.cpp452
-rw-r--r--src/devices/cpu/unsp/unspdasm.h67
-rw-r--r--src/devices/cpu/unsp/unspdasm_extended.cpp193
-rw-r--r--src/devices/cpu/unsp/unspdasm_exxx.cpp117
-rw-r--r--src/devices/cpu/unsp/unspdasm_fxxx.cpp371
-rw-r--r--src/devices/cpu/unsp/unspdasm_jumps.cpp41
-rw-r--r--src/devices/cpu/unsp/unspdasm_other.cpp235
-rw-r--r--src/devices/cpu/unsp/unspdrc.cpp15
-rw-r--r--src/devices/machine/sunplus_gcm394.cpp61
-rw-r--r--src/devices/machine/sunplus_gcm394.h3
-rw-r--r--src/mame/drivers/clickstart.cpp4
-rw-r--r--src/mame/drivers/sunplus_gcm394.cpp7
19 files changed, 2653 insertions, 1071 deletions
diff --git a/src/devices/cpu/unsp/unsp.cpp b/src/devices/cpu/unsp/unsp.cpp
index bec95cafe71..410d8b60396 100644
--- a/src/devices/cpu/unsp/unsp.cpp
+++ b/src/devices/cpu/unsp/unsp.cpp
@@ -1,5 +1,5 @@
// license:GPL-2.0+
-// copyright-holders:Segher Boessenkool,Ryan Holtz
+// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood
/*****************************************************************************
SunPlus µ'nSP emulator
@@ -10,6 +10,10 @@
Ported to MAME framework by Ryan Holtz
+ Notes:
+
+ R3 and R4 together are 'MR' with R4 being the upper part of the 32-bit reg
+
*****************************************************************************/
#include "emu.h"
@@ -18,11 +22,12 @@
#include "debugger.h"
-#include "unspdefs.h"
#include "unspdasm.h"
-DEFINE_DEVICE_TYPE(UNSP, unsp_device, "unsp", "SunPlus u'nSP")
-DEFINE_DEVICE_TYPE(UNSP_NEWER, unsp_newer_device, "unsp_newer", "SunPlus u'nSP (newer)") // found on GCM394 die, has extra instructions
+DEFINE_DEVICE_TYPE(UNSP, unsp_device, "unsp", "SunPlus u'nSP (ISA 1.0)")
+DEFINE_DEVICE_TYPE(UNSP_11, unsp_11_device, "unsp_11", "SunPlus u'nSP (ISA 1.1)")
+DEFINE_DEVICE_TYPE(UNSP_12, unsp_12_device, "unsp_12", "SunPlus u'nSP (ISA 1.2)") // found on GCM394 die, has extra instructions
+DEFINE_DEVICE_TYPE(UNSP_20, unsp_20_device, "unsp_20", "SunPlus u'nSP (ISA 2.0)")
/* size of the execution code cache */
#define CACHE_SIZE (64 * 1024 * 1024)
@@ -56,13 +61,71 @@ unsp_device::unsp_device(const machine_config& mconfig, device_type type, const
unsp_device::unsp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: unsp_device(mconfig, UNSP, tag, owner, clock)
{
+ m_iso = 10;
+}
+
+unsp_11_device::unsp_11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : unsp_device(mconfig, UNSP_11, tag, owner, clock)
+{
+ m_iso = 11;
+}
+
+unsp_11_device::unsp_11_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock)
+ : unsp_device(mconfig, type, tag, owner, clock)
+{
+ m_iso = 11;
+}
+
+
+unsp_12_device::unsp_12_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : unsp_11_device(mconfig, UNSP_12, tag, owner, clock)
+{
+ m_iso = 12;
+}
+
+unsp_12_device::unsp_12_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock)
+ : unsp_11_device(mconfig, type, tag, owner, clock)
+{
+ m_iso = 12;
}
-unsp_newer_device::unsp_newer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : unsp_device(mconfig, UNSP_NEWER, tag, owner, clock)
+unsp_20_device::unsp_20_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : unsp_12_device(mconfig, UNSP_20, tag, owner, clock)
{
+ m_iso = 20;
}
+// these are just for logging, can be removed once all ops are implemented
+char const* const unsp_device::regs[] =
+{
+ "sp", "r1", "r2", "r3", "r4", "bp", "sr", "pc"
+};
+
+char const* const unsp_device::bitops[] =
+{
+ "tstb", "setb", "clrb", "invb"
+};
+
+char const* const unsp_device::lsft[] =
+{
+ "asr", "asror", "lsl", "lslor", "lsr", "lsror", "rol", "ror"
+};
+
+char const* const unsp_device::extregs[] =
+{
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+};
+
+char const* const unsp_device::aluops[] =
+{
+ "add","adc","sub","sbc","cmp","(invalid)","neg","--","xor","load","or","and","test","store","(invalid)","(invalid)"
+};
+
+char const* const unsp_device::forms[] =
+{
+ "[%s]", "[%s--]", "[%s++]", "[++%s]"
+};
+
device_memory_interface::space_config_vector unsp_device::memory_space_config() const
{
@@ -76,9 +139,14 @@ std::unique_ptr<util::disasm_interface> unsp_device::create_disassembler()
return std::make_unique<unsp_disassembler>();
}
-std::unique_ptr<util::disasm_interface> unsp_newer_device::create_disassembler()
+std::unique_ptr<util::disasm_interface> unsp_12_device::create_disassembler()
+{
+ return std::make_unique<unsp_12_disassembler>();
+}
+
+std::unique_ptr<util::disasm_interface> unsp_20_device::create_disassembler()
{
- return std::make_unique<unsp_newer_disassembler>();
+ return std::make_unique<unsp_12_disassembler>();
}
void unsp_device::unimplemented_opcode(uint16_t op)
@@ -86,30 +154,24 @@ void unsp_device::unimplemented_opcode(uint16_t op)
fatalerror("UNSP: unknown opcode %04x at %04x\n", op, UNSP_LPC);
}
-/*****************************************************************************/
-
-uint16_t unsp_device::read16(uint32_t address)
+void unsp_device::unimplemented_opcode(uint16_t op, uint16_t ximm)
{
- return m_program->read_word(address);
+ fatalerror("UNSP: unknown opcode %04x %04x at %04x\n", op, ximm, UNSP_LPC);
}
-void unsp_device::write16(uint32_t address, uint16_t data)
+
+void unsp_device::unimplemented_opcode(uint16_t op, uint16_t ximm, uint16_t ximm_2)
{
-#if UNSP_LOG_REGS
- log_write(address, data);
-#endif
- m_program->write_word(address, data);
+ fatalerror("UNSP: unknown opcode %04x %04x %04x at %04x\n", op, ximm, ximm_2, UNSP_LPC);
}
-/*****************************************************************************/
-
void unsp_device::device_start()
{
m_core = (internal_unsp_state *)m_cache.alloc_near(sizeof(internal_unsp_state));
memset(m_core, 0, sizeof(internal_unsp_state));
#if ENABLE_UNSP_DRC
- m_enable_drc = allow_drc();
+ m_enable_drc = allow_drc() && (m_iso < 12);
#else
m_enable_drc = false;
#endif
@@ -306,7 +368,7 @@ uint16_t unsp_device::pop(uint32_t *reg)
return (uint16_t)read16(*reg);
}
-void unsp_device::trigger_fiq()
+inline void unsp_device::trigger_fiq()
{
if (!m_core->m_enable_fiq || m_core->m_fiq || m_core->m_irq)
{
@@ -324,7 +386,7 @@ void unsp_device::trigger_fiq()
m_core->m_r[REG_SR] = 0;
}
-void unsp_device::trigger_irq(int line)
+inline void unsp_device::trigger_irq(int line)
{
if (!m_core->m_enable_irq || m_core->m_irq || m_core->m_fiq)
return;
@@ -361,631 +423,23 @@ void unsp_device::check_irqs()
trigger_irq(highest_irq - 1);
}
-void unsp_device::add_lpc(const int32_t offset)
-{
- const uint32_t new_lpc = UNSP_LPC + offset;
- m_core->m_r[REG_PC] = (uint16_t)new_lpc;
- m_core->m_r[REG_SR] &= 0xffc0;
- m_core->m_r[REG_SR] |= (new_lpc >> 16) & 0x3f;
-}
-
-void unsp_device::execute_f_group(const uint16_t op)
-{
- unimplemented_opcode(op);
-}
-
-void unsp_newer_device::execute_f_group(const uint16_t op)
-{
- logerror("UNSP: unknown extended opcode %04x at %04x\n", op, UNSP_LPC);
-}
-
inline void unsp_device::execute_one(const uint16_t op)
{
- uint32_t lres = 0;
- uint16_t r0 = 0;
- uint16_t r1 = 0;
- uint32_t r2 = 0;
-
const uint16_t op0 = (op >> 12) & 15;
const uint16_t opa = (op >> 9) & 7;
const uint16_t op1 = (op >> 6) & 7;
- const uint16_t opn = (op >> 3) & 7;
- const uint16_t opb = op & 7;
- const uint8_t lower_op = (op1 << 4) | op0;
+ if (op0 == 0xf)
+ return execute_fxxx_group(op);
if(op0 < 0xf && opa == 0x7 && op1 < 2)
- {
- const uint32_t opimm = op & 0x3f;
- switch(op0)
- {
- case 0: // JB
- if(!(m_core->m_r[REG_SR] & UNSP_C))
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 1: // JAE
- if(m_core->m_r[REG_SR] & UNSP_C)
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 2: // JGE
- if(!(m_core->m_r[REG_SR] & UNSP_S))
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 3: // JL
- if(m_core->m_r[REG_SR] & UNSP_S)
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 4: // JNE
- if(!(m_core->m_r[REG_SR] & UNSP_Z))
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 5: // JE
- if(m_core->m_r[REG_SR] & UNSP_Z)
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 6: // JPL
- if(!(m_core->m_r[REG_SR] & UNSP_N))
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 7: // JMI
- if(m_core->m_r[REG_SR] & UNSP_N)
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 8: // JBE
- if((m_core->m_r[REG_SR] & (UNSP_Z | UNSP_C)) != UNSP_C) // branch if (!UNSP_Z && !UNSP_C) || UNSP_Z
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 9: // JA
- if((m_core->m_r[REG_SR] & (UNSP_Z | UNSP_C)) == UNSP_C) // branch if !UNSP_Z && UNSP_C
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 10: // JLE
- if(m_core->m_r[REG_SR] & (UNSP_Z | UNSP_S))
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 11: // JG
- if(!(m_core->m_r[REG_SR] & (UNSP_Z | UNSP_S)))
- {
- m_core->m_icount -= 4;
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- }
- else
- {
- m_core->m_icount -= 2;
- }
- return;
- case 14: // JMP
- add_lpc((op1 == 0) ? opimm : (0 - opimm));
- m_core->m_icount -= 4;
- return;
- default:
- unimplemented_opcode(op);
- return;
- }
- }
- else if (lower_op == 0x2d) // Push
- {
- r0 = opn;
- r1 = opa;
- m_core->m_icount -= 4 + 2 * r0;
+ return execute_jumps(op);
- while (r0--)
- {
- push(m_core->m_r[r1--], &m_core->m_r[opb]);
- }
- return;
- }
- else if (lower_op == 0x29)
- {
- if (op == 0x9a98) // reti
- {
- m_core->m_icount -= 8;
- m_core->m_r[REG_SR] = pop(&m_core->m_r[REG_SP]);
- m_core->m_r[REG_PC] = pop(&m_core->m_r[REG_SP]);
-
- if(m_core->m_fiq)
- {
- m_core->m_fiq = 0;
- m_core->m_saved_sb[2] = m_core->m_sb;
- m_core->m_sb = m_core->m_saved_sb[m_core->m_irq ? 1 : 0];
- }
- else if(m_core->m_irq)
- {
- m_core->m_irq = 0;
- m_core->m_saved_sb[1] = m_core->m_sb;
- m_core->m_sb = m_core->m_saved_sb[0];
- }
- m_core->m_curirq = 0;
- check_irqs();
- return;
- }
- else // pop
- {
- r0 = opn;
- r1 = opa;
- m_core->m_icount -= 4 + 2 * r0;
-
- while (r0--)
- {
- m_core->m_r[++r1] = pop(&m_core->m_r[opb]);
- }
- return;
- }
- }
- else if (op0 == 0xf)
- {
- switch (op1)
- {
- case 0x00: // Multiply, Unsigned * Signed
- if(opn == 1 && opa != 7)
- {
- m_core->m_icount -= 12;
- lres = m_core->m_r[opa] * m_core->m_r[opb];
- if(m_core->m_r[opb] & 0x8000)
- {
- lres -= m_core->m_r[opa] << 16;
- }
- m_core->m_r[REG_R4] = lres >> 16;
- m_core->m_r[REG_R3] = (uint16_t)lres;
- }
- else
- {
- unimplemented_opcode(op);
- }
- return;
-
- case 0x01: // Call
- if(!(opa & 1))
- {
- m_core->m_icount -= 9;
- r1 = read16(UNSP_LPC);
- add_lpc(1);
- push(m_core->m_r[REG_PC], &m_core->m_r[REG_SP]);
- push(m_core->m_r[REG_SR], &m_core->m_r[REG_SP]);
- m_core->m_r[REG_PC] = r1;
- m_core->m_r[REG_SR] &= 0xffc0;
- m_core->m_r[REG_SR] |= op & 0x3f;
- }
- else
- {
- unimplemented_opcode(op);
- }
- return;
-
- case 0x02: // Far Jump
- if (opa == 7)
- {
- m_core->m_icount -= 5;
- m_core->m_r[REG_PC] = read16(UNSP_LPC);
- m_core->m_r[REG_SR] &= 0xffc0;
- m_core->m_r[REG_SR] |= op & 0x3f;
- }
- else
- {
- unimplemented_opcode(op);
- }
- return;
-
- case 0x04: // Multiply, Signed * Signed
- if(opn == 1 && opa != 7)
- {
- m_core->m_icount -= 12;
- lres = m_core->m_r[opa] * m_core->m_r[opb];
- if(m_core->m_r[opb] & 0x8000)
- {
- lres -= m_core->m_r[opa] << 16;
- }
- if(m_core->m_r[opa] & 0x8000)
- {
- lres -= m_core->m_r[opb] << 16;
- }
- m_core->m_r[REG_R4] = lres >> 16;
- m_core->m_r[REG_R3] = (uint16_t)lres;
- }
- else
- {
- unimplemented_opcode(op);
- }
- return;
-
- case 0x05: // Interrupt flags
- m_core->m_icount -= 2;
- switch(op & 0x3f)
- {
- case 0:
- m_core->m_enable_irq = 0;
- m_core->m_enable_fiq = 0;
- break;
- case 1:
- m_core->m_enable_irq = 1;
- m_core->m_enable_fiq = 0;
- break;
- case 2:
- m_core->m_enable_irq = 0;
- m_core->m_enable_fiq = 1;
- break;
- case 3:
- m_core->m_enable_irq = 1;
- m_core->m_enable_fiq = 1;
- break;
- case 8: // irq off
- m_core->m_enable_irq = 0;
- break;
- case 9: // irq on
- m_core->m_enable_irq = 1;
- break;
- case 12: // fiq off
- m_core->m_enable_fiq = 0;
- break;
- case 14: // fiq on
- m_core->m_enable_fiq = 1;
- break;
- case 37: // nop
- break;
- default:
- unimplemented_opcode(op);
- break;
- }
- return;
-
- default:
- unimplemented_opcode(op);
- return;
- }
- }
-
- // At this point, we should be dealing solely with ALU ops.
-
- r0 = m_core->m_r[opa];
-
- switch (op1)
- {
- case 0x00: // r, [bp+imm6]
- m_core->m_icount -= 6;
+ if (op0 == 0xe)
+ return execute_exxx_group(op);
- r2 = (uint16_t)(m_core->m_r[REG_BP] + (op & 0x3f));
- if (op0 != 0x0d)
- r1 = read16(r2);
- break;
-
- case 0x01: // r, imm6
- m_core->m_icount -= 2;
-
- r1 = op & 0x3f;
- break;
-
- case 0x03: // Indirect
- {
- m_core->m_icount -= (opa == 7 ? 7 : 6);
-
- const uint8_t lsbits = opn & 3;
- if (opn & 4)
- {
- switch (lsbits)
- {
- case 0: // r, [<ds:>r]
- r2 = UNSP_LREG_I(opb);
- if (op0 != 0x0d)
- r1 = read16(r2);
- break;
-
- case 1: // r, [<ds:>r--]
- r2 = UNSP_LREG_I(opb);
- if (op0 != 0x0d)
- r1 = read16(r2);
- m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] - 1);
- if (m_core->m_r[opb] == 0xffff)
- m_core->m_r[REG_SR] -= 0x0400;
- break;
- case 2: // r, [<ds:>r++]
- r2 = UNSP_LREG_I(opb);
- if (op0 != 0x0d)
- r1 = read16(r2);
- m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] + 1);
- if (m_core->m_r[opb] == 0x0000)
- m_core->m_r[REG_SR] += 0x0400;
- break;
- case 3: // r, [<ds:>++r]
- m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] + 1);
- if (m_core->m_r[opb] == 0x0000)
- m_core->m_r[REG_SR] += 0x0400;
- r2 = UNSP_LREG_I(opb);
- if (op0 != 0x0d)
- r1 = read16(r2);
- break;
- default:
- break;
- }
- }
- else
- {
- switch (lsbits)
- {
- case 0: // r, [r]
- r2 = m_core->m_r[opb];
- if (op0 != 0x0d)
- r1 = read16(r2);
- break;
- case 1: // r, [r--]
- r2 = m_core->m_r[opb];
- if (op0 != 0x0d)
- r1 = read16(r2);
- m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] - 1);
- break;
- case 2: // r, [r++]
- r2 = m_core->m_r[opb];
- if (op0 != 0x0d)
- r1 = read16(r2);
- m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] + 1);
- break;
- case 3: // r, [++r]
- m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] + 1);
- r2 = m_core->m_r[opb];
- if (op0 != 0x0d)
- r1 = read16(r2);
- break;
- default:
- break;
- }
- }
- break;
- }
-
- case 0x04: // 16-bit ops
- switch (opn)
- {
- case 0x00: // r
- m_core->m_icount -= (opa == 7 ? 5 : 3);
- r1 = m_core->m_r[opb];
- break;
-
- case 0x01: // imm16
- m_core->m_icount -= (opa == 7 ? 5 : 4);
- r0 = m_core->m_r[opb];
- r1 = read16(UNSP_LPC);
- add_lpc(1);
- break;
-
- case 0x02: // [imm16]
- m_core->m_icount -= (opa == 7 ? 8 : 7);
- r0 = m_core->m_r[opb];
- r2 = read16(UNSP_LPC);
- add_lpc(1);
-
- if (op0 != 0x0d)
- {
- r1 = read16(r2);
- }
- break;
-
- case 0x03: // store [imm16], r
- m_core->m_icount -= (opa == 7 ? 8 : 7);
- r1 = r0;
- r0 = m_core->m_r[opb];
- r2 = read16(UNSP_LPC);
- add_lpc(1);
- break;
-
- default: // Shifted ops
- {
- m_core->m_icount -= (opa == 7 ? 5 : 3);
- uint32_t shift = (m_core->m_r[opb] << 4) | m_core->m_sb;
- if (shift & 0x80000)
- shift |= 0xf00000;
- shift >>= (opn - 3);
- m_core->m_sb = shift & 0x0f;
- r1 = (uint16_t)(shift >> 4);
- break;
- }
- }
- break;
-
- case 0x05: // More shifted ops
- m_core->m_icount -= (opa == 7 ? 5 : 3);
-
- if (opn & 4) // Shift right
- {
- const uint32_t shift = ((m_core->m_r[opb] << 4) | m_core->m_sb) >> (opn - 3);
- m_core->m_sb = shift & 0x0f;
- r1 = (uint16_t)(shift >> 4);
- }
- else // Shift left
- {
- const uint32_t shift = ((m_core->m_sb << 16) | m_core->m_r[opb]) << (opn + 1);
- m_core->m_sb = (shift >> 16) & 0x0f;
- r1 = (uint16_t)shift;
- }
- break;
-
- case 0x06: // Rotated ops
- {
- m_core->m_icount -= (opa == 7 ? 5 : 3);
-
- uint32_t shift = (((m_core->m_sb << 16) | m_core->m_r[opb]) << 4) | m_core->m_sb;
- if (opn & 4) // Rotate right
- {
- shift >>= (opn - 3);
- m_core->m_sb = shift & 0x0f;
- }
- else
- {
- shift <<= (opn + 1);
- m_core->m_sb = (shift >> 20) & 0x0f;
- }
- r1 = (uint16_t)(shift >> 4);
- break;
- }
-
- case 0x07: // Direct 8
- m_core->m_icount -= (opa == 7 ? 6 : 5);
- r2 = op & 0x3f;
- r1 = read16(r2);
- break;
-
- default:
- break;
- }
-
- switch (op0)
- {
- case 0x00: // Add
- {
- lres = r0 + r1;
- if (opa != 7)
- update_nzsc(lres, r0, r1);
- break;
- }
- case 0x01: // Add w/ carry
- {
- uint32_t c = (m_core->m_r[REG_SR] & UNSP_C) ? 1 : 0;
- lres = r0 + r1 + c;
- if (opa != 7)
- update_nzsc(lres, r0, r1);
- break;
- }
- case 0x02: // Subtract
- lres = r0 + (uint16_t)(~r1) + uint32_t(1);
- if (opa != 7)
- update_nzsc(lres, r0, ~r1);
- break;
- case 0x03: // Subtract w/ carry
- {
- uint32_t c = (m_core->m_r[REG_SR] & UNSP_C) ? 1 : 0;
- lres = r0 + (uint16_t)(~r1) + c;
- if (opa != 7)
- update_nzsc(lres, r0, ~r1);
- break;
- }
- case 0x04: // Compare
- lres = r0 + (uint16_t)(~r1) + uint32_t(1);
- if (opa != 7)
- update_nzsc(lres, r0, ~r1);
- return;
- case 0x06: // Negate
- lres = -r1;
- if (opa != 7)
- update_nz(lres);
- break;
- case 0x08: // XOR
- lres = r0 ^ r1;
- if (opa != 7)
- update_nz(lres);
- break;
- case 0x09: // Load
- lres = r1;
- if (opa != 7)
- update_nz(lres);
- break;
- case 0x0a: // OR
- lres = r0 | r1;
- if (opa != 7)
- update_nz(lres);
- break;
- case 0x0b: // AND
- lres = r0 & r1;
- if (opa != 7)
- update_nz(lres);
- break;
- case 0x0c: // Test
- lres = r0 & r1;
- if (opa != 7)
- update_nz(lres);
- return;
- case 0x0d: // Store
- write16(r2, r0);
- return;
-
- case 0x0f: // extended opcodes
- execute_f_group(op);
- return;
-
- default:
- unimplemented_opcode(op);
- return;
- }
-
- if (op1 == 0x04 && opn == 0x03) // store [imm16], r
- write16(r2, lres);
- else
- m_core->m_r[opa] = (uint16_t)lres;
+ execute_remaining(op);
}
void unsp_device::execute_run()
diff --git a/src/devices/cpu/unsp/unsp.h b/src/devices/cpu/unsp/unsp.h
index 5bbc92d35b5..0a9583e8fa4 100644
--- a/src/devices/cpu/unsp/unsp.h
+++ b/src/devices/cpu/unsp/unsp.h
@@ -1,5 +1,5 @@
// license:GPL-2.0+
-// copyright-holders:Segher Boessenkool,Ryan Holtz
+// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood
/*****************************************************************************
SunPlus µ'nSP emulator
@@ -20,6 +20,7 @@
#include "cpu/drcfe.h"
#include "cpu/drcuml.h"
#include "cpu/drcumlsh.h"
+#include "unspdefs.h"
/***************************************************************************
CONSTANTS
@@ -91,7 +92,7 @@ class unsp_device : public cpu_device
public:
// construction/destruction
- unsp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ unsp_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock);
unsp_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock);
// HACK: IRQ line state can only be modified directly by hardware on-board the SPG SoC itself.
@@ -132,9 +133,9 @@ protected:
virtual space_config_vector memory_space_config() const override;
// device_state_interface overrides
- virtual void state_import(const device_state_entry &entry) override;
- virtual void state_export(const device_state_entry &entry) override;
- virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
+ virtual void state_import(const device_state_entry& entry) override;
+ virtual void state_export(const device_state_entry& entry) override;
+ virtual void state_string_export(const device_state_entry& entry, std::string& str) const override;
// device_disasm_interface overrides
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
@@ -154,8 +155,8 @@ protected:
/* internal compiler state */
struct compiler_state
{
- compiler_state(compiler_state const &) = delete;
- compiler_state &operator=(compiler_state const &) = delete;
+ compiler_state(compiler_state const&) = delete;
+ compiler_state& operator=(compiler_state const&) = delete;
uint32_t m_cycles; /* accumulated cycles */
uml::code_label m_labelnum; /* index for local labels */
@@ -181,7 +182,53 @@ protected:
};
/* core state */
- internal_unsp_state *m_core;
+ internal_unsp_state* m_core;
+
+protected:
+ uint16_t read16(uint32_t address) { return m_program->read_word(address); }
+
+ void write16(uint32_t address, uint16_t data)
+ {
+ #if UNSP_LOG_REGS
+ log_write(address, data);
+ #endif
+ m_program->write_word(address, data);
+ }
+
+ void add_lpc(const int32_t offset)
+ {
+ const uint32_t new_lpc = UNSP_LPC + offset;
+ m_core->m_r[REG_PC] = (uint16_t)new_lpc;
+ m_core->m_r[REG_SR] &= 0xffc0;
+ m_core->m_r[REG_SR] |= (new_lpc >> 16) & 0x3f;
+ }
+
+ void execute_fxxx_000_group(uint16_t op);
+ void execute_fxxx_001_group(uint16_t op);
+ void execute_fxxx_010_group(uint16_t op);
+ void execute_fxxx_011_group(uint16_t op);
+ virtual void execute_fxxx_101_group(uint16_t op);
+ void execute_fxxx_110_group(uint16_t op);
+ void execute_fxxx_111_group(uint16_t op);
+ void execute_fxxx_group(uint16_t op);;
+ void execute_fxxx_100_group(uint16_t op);
+ virtual void execute_extended_group(uint16_t op);
+ virtual void execute_exxx_group(uint16_t op);
+ void unimplemented_opcode(uint16_t op);
+ void unimplemented_opcode(uint16_t op, uint16_t ximm);
+ void unimplemented_opcode(uint16_t op, uint16_t ximm, uint16_t ximm_2);
+
+ int m_iso;
+
+ static char const *const regs[];
+ static char const *const extregs[];
+ static char const *const bitops[];
+ static char const *const lsft[];
+ static char const *const aluops[];
+ static char const *const forms[];
+
+ void push(uint32_t value, uint32_t *reg);
+ uint16_t pop(uint32_t *reg);
private:
// compilation boundaries -- how far back/forward does the analysis extend?
@@ -202,10 +249,12 @@ private:
EXECUTE_RESET_CACHE = 3
};
- void add_lpc(const int32_t offset);
- virtual void execute_f_group(const uint16_t op);
- inline void execute_one(const uint16_t op);
+ void execute_jumps(const uint16_t op);
+ void execute_remaining(const uint16_t op);
+ void execute_one(const uint16_t op);
+
+
address_space_config m_program_config;
address_space *m_program;
@@ -217,16 +266,11 @@ private:
uint32_t m_log_ops;
#endif
- void unimplemented_opcode(uint16_t op);
- inline uint16_t read16(uint32_t address);
- inline void write16(uint32_t address, uint16_t data);
- inline void update_nz(uint32_t value);
- inline void update_nzsc(uint32_t value, uint16_t r0, uint16_t r1);
- inline void push(uint32_t value, uint32_t *reg);
- inline uint16_t pop(uint32_t *reg);
+ void update_nz(uint32_t value);
+ void update_nzsc(uint32_t value, uint16_t r0, uint16_t r1);
inline void trigger_fiq();
inline void trigger_irq(int line);
- inline void check_irqs();
+ void check_irqs();
drc_cache m_cache;
std::unique_ptr<drcuml_state> m_drcuml;
@@ -247,8 +291,6 @@ private:
bool m_enable_drc;
-
-
void execute_run_drc();
void flush_drc_cache();
void code_flush_cache();
@@ -272,7 +314,6 @@ private:
void generate_update_nzsc(drcuml_block &block);
void generate_update_nz(drcuml_block &block);
void log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op);
- virtual bool generate_f_group_opcode(drcuml_block& block, compiler_state& compiler, const opcode_desc* desc);
bool generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
#if UNSP_LOG_REGS
@@ -280,20 +321,50 @@ private:
#endif
};
-class unsp_newer_device : public unsp_device
+
+class unsp_11_device : public unsp_device
+{
+public:
+ // construction/destruction
+ unsp_11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ unsp_11_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock);
+
+private:
+};
+
+class unsp_12_device : public unsp_11_device
+{
+public:
+ // construction/destruction
+ unsp_12_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ unsp_12_device(const machine_config& mconfig, device_type type, const char* tag, device_t* owner, uint32_t clock);
+
+private:
+ virtual void execute_fxxx_101_group(uint16_t op) override;
+ virtual void execute_exxx_group(uint16_t op) override;
+
+ virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
+};
+
+class unsp_20_device : public unsp_12_device
{
public:
// construction/destruction
- unsp_newer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ unsp_20_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
private:
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
- virtual void execute_f_group(const uint16_t op) override;
- virtual bool generate_f_group_opcode(drcuml_block& block, compiler_state& compiler, const opcode_desc* desc) override;
+ virtual void execute_extended_group(uint16_t op) override;
+
+private:
};
-DECLARE_DEVICE_TYPE(UNSP, unsp_device)
-DECLARE_DEVICE_TYPE(UNSP_NEWER, unsp_newer_device)
+
+DECLARE_DEVICE_TYPE(UNSP, unsp_device)
+DECLARE_DEVICE_TYPE(UNSP_11, unsp_11_device)
+DECLARE_DEVICE_TYPE(UNSP_12, unsp_12_device)
+DECLARE_DEVICE_TYPE(UNSP_20, unsp_20_device)
+
#endif // MAME_CPU_UNSP_UNSP_H
diff --git a/src/devices/cpu/unsp/unsp_extended.cpp b/src/devices/cpu/unsp/unsp_extended.cpp
new file mode 100644
index 00000000000..fa9c3d5a713
--- /dev/null
+++ b/src/devices/cpu/unsp/unsp_extended.cpp
@@ -0,0 +1,206 @@
+// license:GPL-2.0+
+// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood
+
+#include "emu.h"
+#include "unsp.h"
+#include "unspfe.h"
+
+#include "debugger.h"
+
+#include "unspdasm.h"
+
+void unsp_device::execute_extended_group(uint16_t op)
+{
+ // shouldn't get here anyway
+ logerror("<UNKNOWN EXTENDED>\n");
+ unimplemented_opcode(op);
+ return;
+}
+
+void unsp_20_device::execute_extended_group(uint16_t op)
+{
+ uint16_t ximm = read16(UNSP_LPC);
+ add_lpc(1);
+
+ switch ((ximm & 0x01f0) >> 4)
+ {
+ case 0x00: case 0x10:
+ {
+ // Ext Register Ra = Ra op Rb
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t ra = (op & 0x0e00) >> 9;
+ ra |= (op & 0x0100) >> 5;
+
+ logerror("(Ext) %s = %s %s %s\n", (ra & 0x8) ? extregs[ra & 0x7] : regs[ra & 0x7]
+ , (ra & 0x8) ? extregs[ra & 0x7] : regs[ra & 0x7]
+ , aluops[aluop]
+ , (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]);
+
+ unimplemented_opcode(op, ximm);
+ return;
+ }
+ case 0x02:
+ {
+ // Ext Push/Pop
+ if (op & 0x8000)
+ {
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t size = (op & 0x7000) >> 12;
+ uint8_t rx = (op & 0x0e00) >> 9;
+
+ if (rx+1 >= size && rx < size+7)
+ logerror("(Ext) push %s, %s to [%s]\n",
+ extregs[rx+1-size], extregs[rx], (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]);
+ else
+ logerror("(Ext) push <BAD>\n");
+
+ unimplemented_opcode(op, ximm);
+ }
+ else
+ {
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t size = (op & 0x7000) >> 12;
+ uint8_t rx = (op & 0x0e00) >> 9;
+
+ if (rx+1 < 8 && rx+size < 8)
+ logerror("(Ext) pop %s, %s from [%s]\n",
+ extregs[rx+1], extregs[rx+size], (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]);
+ else
+ logerror("(Ext) pop <BAD>\n");
+
+ unimplemented_opcode(op, ximm);
+ }
+ return;
+ }
+ case 0x04: case 0x14:
+ {
+ uint16_t ximm_2 = read16(UNSP_LPC);
+ add_lpc(1);
+
+ // Ra=Rb op IMM16
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t ra = (op & 0x0e00) >> 9;
+ ra |= (op & 0x0100) >> 5;
+
+ logerror("(Ext) %s = %s %s %04x\n", (ra & 0x8) ? extregs[ra & 0x7] : regs[ra & 0x7]
+ , (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]
+ , aluops[aluop]
+ , ximm_2);
+
+ unimplemented_opcode(op, ximm, ximm_2);
+ return;
+ }
+
+ case 0x06:
+ case 0x16:
+ {
+ uint16_t ximm_2 = read16(UNSP_LPC);
+ add_lpc(1);
+
+ // Ra=Rb op [A16]
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t ra = (op & 0x0e00) >> 9;
+ ra |= (op & 0x0100) >> 5;
+
+ logerror("(Ext) %s = %s %s [%04x]\n", (ra & 0x8) ? extregs[ra & 0x7] : regs[ra & 0x7]
+ , (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]
+ , aluops[aluop]
+ , ximm_2);
+
+ unimplemented_opcode(op, ximm, ximm_2);
+ return;
+ }
+
+ case 0x07:
+ case 0x17:
+ {
+ uint16_t ximm_2 = read16(UNSP_LPC);
+ add_lpc(1);
+
+ //[A16] = Ra op Rb
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t ra = (op & 0x0e00) >> 9;
+ ra |= (op & 0x0100) >> 5;
+
+ logerror("(Ext) [0x4x] = %s %s %s\n", ximm_2
+ , (ra & 0x8) ? extregs[ra & 0x7] : regs[ra & 0x7]
+ , aluops[aluop]
+ , (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]);
+
+ unimplemented_opcode(op, ximm, ximm_2);
+ return;
+ }
+
+ case 0x08: case 0x09:
+ {
+ // Ext Indirect Rx=Rx op [Ry@]
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t ry = (op & 0x0007) >> 0;
+ uint8_t form = (op & 0x0018) >> 3;
+ uint8_t rx = (op & 0x0e00) >> 9;
+
+ logerror("(Ext) %s=%s %s", extregs[rx], extregs[rx], aluops[aluop]);
+ logerror(forms[form], extregs[ry]);
+ logerror("\n");
+ unimplemented_opcode(op, ximm);
+ return;
+ }
+ case 0x0a: case 0x0b:
+ {
+ // Ext DS_Indirect Rx=Rx op ds:[Ry@]
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t ry = (op & 0x0007) >> 0;
+ uint8_t form = (op & 0x0018) >> 3;
+ uint8_t rx = (op & 0x0e00) >> 9;
+
+ logerror("(Ext) %s=%s %s ds:", extregs[rx], extregs[rx], aluops[aluop]);
+ logerror(forms[form], extregs[ry]);
+ logerror("\n");
+ unimplemented_opcode(op, ximm);
+ return;
+ }
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ {
+ // Ext IM6 Rx=Rx op IM6
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rx = (op & 0x0e00) >> 9;
+ uint8_t imm6 = (op & 0x003f) >> 0;
+
+ logerror("(Ext) %s=%s %s %02x\n", extregs[rx], extregs[rx], aluops[aluop], imm6 );
+ unimplemented_opcode(op, ximm);
+ return;
+ }
+
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ {
+ // Ext Base+Disp6 Rx=Rx op [BP+IM6]
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rx = (op & 0x0e00) >> 9;
+ uint8_t imm6 = (op & 0x003f) >> 0;
+
+ logerror("(Ext) %s=%s %s [BP+%02x]\n", extregs[rx], extregs[rx], aluops[aluop], imm6 );
+ unimplemented_opcode(op, ximm);
+ return;
+ }
+
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ {
+ // Ext A6 Rx=Rx op [A6]
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rx = (op & 0x0e00) >> 9;
+ uint8_t a6 = (op & 0x003f) >> 0;
+
+ logerror("(Ext) %s=%s %s [%02x]\n", extregs[rx], extregs[rx], aluops[aluop], a6 );
+ unimplemented_opcode(op, ximm);
+ return;
+ }
+ }
+
+ // illegal?
+ unimplemented_opcode(op, ximm);
+ return;
+}
diff --git a/src/devices/cpu/unsp/unsp_exxx.cpp b/src/devices/cpu/unsp/unsp_exxx.cpp
new file mode 100644
index 00000000000..ddbc32bc570
--- /dev/null
+++ b/src/devices/cpu/unsp/unsp_exxx.cpp
@@ -0,0 +1,161 @@
+// license:GPL-2.0+
+// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood
+
+#include "emu.h"
+#include "unsp.h"
+#include "unspfe.h"
+
+#include "debugger.h"
+
+#include "unspdasm.h"
+
+void unsp_device::execute_exxx_group(uint16_t op)
+{
+ // several exxx opcodes have already been decoded as jumps by the time we get here
+ //logerror("<DUNNO>\n");
+ unimplemented_opcode(op);
+ return;
+}
+
+void unsp_12_device::execute_exxx_group(uint16_t op)
+{
+ // several exxx opcodes have already been decoded as jumps by the time we get here
+
+ // Register BITOP BITOP Rd,Rs 1 1 1 0 r r r 0 0 0 b b 0 r r r
+ // Register BITOP BITOP Rd,offset 1 1 1 0 r r r 0 0 1 b b o o o o
+ // Memory BITOP BITOP [Rd], offset 1 1 1 0 r r r 1 1 0 b b o o o o
+ // Memory BITOP BITOP ds:[Rd], offset 1 1 1 0 r r r 1 1 1 b b o o o o
+ // Memory BITOP BITOP [Rd], Rs 1 1 1 0 r r r 1 0 0 b b 0 r r r
+ // Memory BITOP BITOP ds:[Rd], Rs 1 1 1 0 r r r 1 0 1 b b 0 r r r
+
+ if (((op & 0xf1c8) == 0xe000))
+ {
+ // Register BITOP BITOP Rd,Rs
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t rs = (op & 0x0007) >> 0;
+ logerror("%s %s,%s\n", bitops[bitop], regs[rd], regs[rs]);
+ unimplemented_opcode(op);
+ return;
+ }
+ else if (((op & 0xf1c0) == 0xe040))
+ {
+ // Register BITOP BITOP Rd,offset
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t offset = (op & 0x000f) >> 0;
+
+ switch (bitop)
+ {
+ case 0x00:
+ fatalerror("UNSP: unknown opcode tstb Rd,offset (%04x) at %04x\n", op, UNSP_LPC);
+ return;
+
+ case 0x01: // setb
+ m_core->m_r[rd] |= (1 << offset);
+ return;
+
+ case 0x02: // clrb
+ m_core->m_r[rd] &= ~(1 << offset);
+ return;
+
+ case 0x03:
+ fatalerror("UNSP: unknown opcode invb Rd,offset (%04x) at %04x\n", op, UNSP_LPC);
+ return;
+ }
+ return;
+ }
+ else if (((op & 0xf1c0) == 0xe180))
+ {
+ // Memory BITOP BITOP [Rd], offset
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t offset = (op & 0x000f) >> 0;
+ logerror("%s [%s],%d\n", bitops[bitop], regs[rd], offset);
+ unimplemented_opcode(op);
+ return;
+ }
+ else if (((op & 0xf1c0) == 0xe1c0))
+ {
+ // Memory BITOP BITOP ds:[Rd], offset
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t offset = (op & 0x000f) >> 0;
+ logerror("%s ds:[%s],%d\n", bitops[bitop], regs[rd], offset);
+ unimplemented_opcode(op);
+ return;
+ }
+ else if (((op & 0xf1c8) == 0xe100))
+ {
+ // Memory BITOP BITOP [Rd], Rs
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t rs = (op & 0x0007) >> 0;
+ logerror("%s [%s],%s\n", bitops[bitop], regs[rd], regs[rs]);
+ unimplemented_opcode(op);
+ return;
+ }
+ else if (((op & 0xf1c8) == 0xe140))
+ {
+ // Memory BITOP BITOP ds:[Rd], Rs
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t rs = (op & 0x0007) >> 0;
+ logerror("%s ds:[%s],%s\n", bitops[bitop], regs[rd], regs[rs]);
+ unimplemented_opcode(op);
+ return;
+ }
+ else if (((op & 0xf0f8) == 0xe008))
+ {
+ // MUL operations
+ // MUL 1 1 1 0* r r r S* 0 0 0 0 1 r r r (* = sign bit, fixed here)
+ /*
+ print_mul(stream, op); // MUL uu or MUL su (invalid?)
+ */
+
+ if (op & 0x0100)
+ {
+ logerror("MUL su\n");
+ fatalerror("UNSP: unknown opcode MUL su (invalid?) (%04x) at %04x\n", op, UNSP_LPC);
+ return;
+ }
+ else
+ {
+ uint32_t lres = 0;
+ const uint16_t opa = (op >> 9) & 7;
+ const uint16_t opb = op & 7;
+
+ m_core->m_icount -= 12; // unknown
+ lres = m_core->m_r[opa] * m_core->m_r[opb];
+ m_core->m_r[REG_R4] = lres >> 16;
+ m_core->m_r[REG_R3] = (uint16_t)lres;
+ return;
+ }
+ return;
+ }
+ else if (((op & 0xf080) == 0xe080))
+ {
+ // MULS 1 1 1 0* r r r S* 1 s s s s r r r (* = sign bit, fixed here)
+ /*
+ // MULS uu or MULS su (invalid?)
+ print_muls(stream, op);
+ */
+ logerror("MULS uu or su\n");
+ unimplemented_opcode(op);
+ return;
+ }
+ else if (((op & 0xf188) == 0xe108))
+ {
+ // 16 bit Shift 1 1 1 0 r r r 1 0 l l l 1 r r r
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t shift = (op & 0x0070) >> 4;
+ uint8_t rs = (op & 0x0007) >> 0;
+ logerror("%s = %s %s %s\n", regs[rd], regs[rd], lsft[shift], regs[rs]);
+ unimplemented_opcode(op);
+ return;
+ }
+
+ logerror("<DUNNO>\n");
+ unimplemented_opcode(op);
+ return;
+}
diff --git a/src/devices/cpu/unsp/unsp_fxxx.cpp b/src/devices/cpu/unsp/unsp_fxxx.cpp
new file mode 100644
index 00000000000..c63b02c4ad0
--- /dev/null
+++ b/src/devices/cpu/unsp/unsp_fxxx.cpp
@@ -0,0 +1,431 @@
+// license:GPL-2.0+
+// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood
+
+#include "emu.h"
+#include "unsp.h"
+#include "unspfe.h"
+
+#include "debugger.h"
+
+#include "unspdasm.h"
+
+inline void unsp_device::execute_fxxx_000_group(uint16_t op)
+{
+ // | | |
+ // DS16 1 1 1 1 1 1 1 0 0 0 i i i i i i
+ // DS Reg 1 1 1 1 - - - 0 0 0 1 0 w r r r
+ // FR Reg 1 1 1 1 - - - 0 0 0 1 1 w r r r
+
+ if (((op & 0xffc0) == 0xfe00) && m_iso >= 12)
+ {
+ // ds = imm6
+ int imm = op & 0x003f;
+ set_ds(imm);
+ return;
+ }
+ else if (((op & 0xf1f8) == 0xf020) && m_iso >= 12)
+ {
+ // rx = ds
+ int r = op & 0x7;
+ m_core->m_r[r] = get_ds();
+ return;
+ }
+ else if (((op & 0xf1f8) == 0xf028) && m_iso >= 12)
+ {
+ // ds = rx
+ int r = op & 0x7;
+ set_ds(m_core->m_r[r]);
+ return;
+ }
+ else if (((op & 0xf1f8) == 0xf030) && m_iso >= 12)
+ {
+ int r = op & 0x7;
+ logerror("%s = fr\n", regs[r]);
+ unimplemented_opcode(op);
+ return;
+ }
+ else if (((op & 0xf1f8) == 0xf038) && m_iso >= 12)
+ {
+ int r = op & 0x7;
+ logerror("fr = %s\n", regs[r]);
+ unimplemented_opcode(op);
+ return;
+ }
+
+ // everything else falls through to the multiply
+
+ // signed * unsigned
+ // MUL 1 1 1 1* r r r 0* 0 0 0 0 1 r r r (** = sign bits, fixed here)
+ const uint16_t opa = (op >> 9) & 7;
+ const uint16_t opb = op & 7;
+ m_core->m_icount -= 12;
+ uint32_t lres = m_core->m_r[opa] * m_core->m_r[opb];
+ if (m_core->m_r[opb] & 0x8000)
+ {
+ lres -= m_core->m_r[opa] << 16;
+ }
+ m_core->m_r[REG_R4] = lres >> 16;
+ m_core->m_r[REG_R3] = (uint16_t)lres;
+
+ return;
+}
+
+inline void unsp_device::execute_fxxx_001_group(uint16_t op)
+{
+ // | | |
+ // CALL16 1 1 1 1 - - 0 0 0 1 a a a a a a (+imm16)
+
+ if ((op & 0xf3c0) == 0xf040)
+ {
+ m_core->m_icount -= 9;
+ uint16_t r1 = read16(UNSP_LPC);
+ add_lpc(1);
+ push(m_core->m_r[REG_PC], &m_core->m_r[REG_SP]);
+ push(m_core->m_r[REG_SR], &m_core->m_r[REG_SP]);
+ m_core->m_r[REG_PC] = r1;
+ m_core->m_r[REG_SR] &= 0xffc0;
+ m_core->m_r[REG_SR] |= op & 0x3f;
+ return;
+ }
+ // MEM bitop 1 1 1 1 - D 1 0 0 1 b b o o o o (+imm16) ( BITOP {ds:}[A16],offset )
+ else if (((op & 0xf3c0) == 0xf240) && m_iso >= 20)
+ {
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t offset = (op & 0x000f) >> 0;
+ uint8_t d = (op & 0x0400) >> 10;
+
+ if (d)
+ {
+ logerror("%s ds:[$04x],%d\n", bitops[bitop], offset);
+ unimplemented_opcode(op);
+ }
+ else
+ {
+ logerror("%s [$04x],%d\n", bitops[bitop], offset);
+ unimplemented_opcode(op);
+ }
+
+ return;
+ }
+
+ logerror("<DUNNO>\n");
+ unimplemented_opcode(op);
+ return;
+}
+
+inline void unsp_device::execute_fxxx_010_group(uint16_t op)
+{
+ // | | |
+ // JMPF 1 1 1 1 1 1 1 0 1 0 a a a a a a (+imm16)
+
+ if ((op & 0xffc0) == 0xfe80) // apparently 1.2 and above, but jak_capb needs it and otherwise seems 1.0 / 1.1?
+ {
+ m_core->m_icount -= 5;
+ m_core->m_r[REG_PC] = read16(UNSP_LPC);
+ m_core->m_r[REG_SR] &= 0xffc0;
+ m_core->m_r[REG_SR] |= op & 0x3f;
+ return;
+ }
+
+ // signed * unsigned (size 16,1,2,3,4,5,6,7)
+ // MULS 1 1 1 1* r r r 0* 1 0*s s s r r r (1* = sign bit, 0* = sign bit 0* = upper size bit)
+
+ // MULS us with upper size bit not set
+ logerror("MULS us\n");
+ unimplemented_opcode(op);
+ return;
+}
+
+inline void unsp_device::execute_fxxx_011_group(uint16_t op)
+{
+ // | | |
+ // JMPR 1 1 1 1 1 1 1 0 1 1 - - - - - -
+ if (((op & 0xffc0) == 0xfec0) && m_iso >= 12)
+ {
+ logerror("goto mr\n");
+ unimplemented_opcode(op);
+ return;
+ }
+
+ // signed * unsigned (size 8,9,10,11,12,13,14,15)
+ // MULS 1 1 1 1* r r r 0* 1 1*s s s r r r (1* = sign bit, 0* = sign bit 1* = upper size bit)
+
+ // MULS us with upper size bit set
+ logerror("MULS us\n");
+ unimplemented_opcode(op);
+
+ return;
+}
+
+inline void unsp_device::execute_fxxx_100_group(uint16_t op)
+{
+ // | | |
+ // signed * signed
+ // MUL 1 1 1 1* r r r 1* 0 0 0 0 1 r r r (** = sign bits, fixed here)
+
+ if ((op & 0xf1f8) == 0xf108)
+ {
+ uint32_t lres = 0;
+
+ const uint16_t opa = (op >> 9) & 7;
+ const uint16_t opb = op & 7;
+
+ m_core->m_icount -= 12;
+ lres = m_core->m_r[opa] * m_core->m_r[opb];
+ if (m_core->m_r[opb] & 0x8000)
+ {
+ lres -= m_core->m_r[opa] << 16;
+ }
+ if (m_core->m_r[opa] & 0x8000)
+ {
+ lres -= m_core->m_r[opb] << 16;
+ }
+ m_core->m_r[REG_R4] = lres >> 16;
+ m_core->m_r[REG_R3] = (uint16_t)lres;
+ return;
+ }
+
+ logerror("<DUNNO>\n");
+ unimplemented_opcode(op);
+ return;
+}
+
+
+inline void unsp_12_device::execute_fxxx_101_group(uint16_t op)
+{
+ // FIR_MOV 1 1 1 1 - - - 1 0 1 0 0 0 1 0 f
+ // Fraction 1 1 1 1 - - - 1 0 1 0 0 0 1 1 f
+ // SECBANK 1 1 1 1 - - - 1 0 1 0 0 1 0 1 S
+ // NESTMODE 1 1 1 1 - - - 1 0 1 0 0 1 1 N 1
+ // CALLR 1 1 1 1 - - - 1 0 1 1 - - 0 0 1
+ // DIVS 1 1 1 1 - - - 1 0 1 1 - - 0 1 0
+ // DIVQ 1 1 1 1 - - - 1 0 1 1 - - 0 1 1
+ // EXP 1 1 1 1 - - - 1 0 1 1 - - 1 0 0
+
+ switch (op)
+ {
+ case 0xf146: case 0xf346: case 0xf546: case 0xf746: case 0xf946: case 0xfb46: case 0xfd46: case 0xff46:
+ logerror("fraction off\n");
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf147: case 0xf347: case 0xf547: case 0xf747: case 0xf947: case 0xfb47: case 0xfd47: case 0xff47:
+ logerror("fraction on\n");
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf14a: case 0xf34a: case 0xf54a: case 0xf74a: case 0xf94a: case 0xfb4a: case 0xfd4a: case 0xff4a:
+ logerror("secbank off\n");
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf14b: case 0xf34b: case 0xf54b: case 0xf74b: case 0xf94b: case 0xfb4b: case 0xfd4b: case 0xff4b:
+ logerror("secbank on\n");
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf14d: case 0xf34d: case 0xf54d: case 0xf74d: case 0xf94d: case 0xfb4d: case 0xfd4d: case 0xff4d:
+ logerror("irqnest off\n");
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf14f: case 0xf34f: case 0xf54f: case 0xf74f: case 0xf94f: case 0xfb4f: case 0xfd4f: case 0xff4f:
+ logerror("irqnest on\n");
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf144: case 0xf344: case 0xf544: case 0xf744: case 0xf944: case 0xfb44: case 0xfd44: case 0xff44:
+ logerror("fir_mov on\n");
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf145: case 0xf345: case 0xf545: case 0xf745: case 0xf945: case 0xfb45: case 0xfd45: case 0xff45:
+ logerror("fir_mov off\n");
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf161: case 0xf361: case 0xf561: case 0xf761: case 0xf961: case 0xfb61: case 0xfd61: case 0xff61:
+ case 0xf169: case 0xf369: case 0xf569: case 0xf769: case 0xf969: case 0xfb69: case 0xfd69: case 0xff69:
+ case 0xf171: case 0xf371: case 0xf571: case 0xf771: case 0xf971: case 0xfb71: case 0xfd71: case 0xff71:
+ case 0xf179: case 0xf379: case 0xf579: case 0xf779: case 0xf979: case 0xfb79: case 0xfd79: case 0xff79:
+ {
+ m_core->m_icount -= 1; // unknown count
+ uint32_t addr = m_core->m_r[REG_R3] | ((m_core->m_r[REG_R4] & 0x3f) << 16);
+ add_lpc(1);
+ push(m_core->m_r[REG_PC], &m_core->m_r[REG_SP]);
+ push(m_core->m_r[REG_SR], &m_core->m_r[REG_SP]);
+ m_core->m_r[REG_PC] = addr & 0x0000ffff;
+ m_core->m_r[REG_SR] &= 0xffc0;
+ m_core->m_r[REG_SR] |= ((addr & 0x003f0000) >> 16);
+ return;
+ }
+
+ case 0xf162: case 0xf362: case 0xf562: case 0xf762: case 0xf962: case 0xfb62: case 0xfd62: case 0xff62:
+ case 0xf16a: case 0xf36a: case 0xf56a: case 0xf76a: case 0xf96a: case 0xfb6a: case 0xfd6a: case 0xff6a:
+ case 0xf172: case 0xf372: case 0xf572: case 0xf772: case 0xf972: case 0xfb72: case 0xfd72: case 0xff72:
+ case 0xf17a: case 0xf37a: case 0xf57a: case 0xf77a: case 0xf97a: case 0xfb7a: case 0xfd7a: case 0xff7a:
+ logerror("divs mr, r2\n");
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf163: case 0xf363: case 0xf563: case 0xf763: case 0xf963: case 0xfb63: case 0xfd63: case 0xff63:
+ case 0xf16b: case 0xf36b: case 0xf56b: case 0xf76b: case 0xf96b: case 0xfb6b: case 0xfd6b: case 0xff6b:
+ case 0xf173: case 0xf373: case 0xf573: case 0xf773: case 0xf973: case 0xfb73: case 0xfd73: case 0xff73:
+ case 0xf17b: case 0xf37b: case 0xf57b: case 0xf77b: case 0xf97b: case 0xfb7b: case 0xfd7b: case 0xff7b:
+ logerror("divq mr, r2\n");
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf164: case 0xf364: case 0xf564: case 0xf764: case 0xf964: case 0xfb64: case 0xfd64: case 0xff64:
+ case 0xf16c: case 0xf36c: case 0xf56c: case 0xf76c: case 0xf96c: case 0xfb6c: case 0xfd6c: case 0xff6c:
+ case 0xf174: case 0xf374: case 0xf574: case 0xf774: case 0xf974: case 0xfb74: case 0xfd74: case 0xff74:
+ case 0xf17c: case 0xf37c: case 0xf57c: case 0xf77c: case 0xf97c: case 0xfb7c: case 0xfd7c: case 0xff7c:
+ //unimplemented_opcode(op);
+ // what is this, sign extend / sign expand / zero expand? it doesn't seem to be exponent
+ logerror("r2 = exp r4 (with r2 = %04x r4 = %04x)\n", m_core->m_r[REG_R2], m_core->m_r[REG_R4]);
+ m_core->m_r[REG_R2] = 0x0001; // WRONG!!
+ return;
+
+
+ default:
+ return unsp_device::execute_fxxx_101_group(op);
+ }
+}
+
+
+inline void unsp_device::execute_fxxx_101_group(uint16_t op)
+{
+ // | | |
+ // INT SET 1 1 1 1 - - - 1 0 1 0 0 0 0 F I
+ // BREAK 1 1 1 1 - - - 1 0 1 1 - - 0 0 0
+ // NOP 1 1 1 1 - - - 1 0 1 1 - - 1 0 1
+
+ // IRQ 1 1 1 1 - - - 1 0 1 0 0 1 0 0 I
+ // FIRQ 1 1 1 1 - - - 1 0 1 0 0 1 1 F 0
+
+ m_core->m_icount -= 2;
+
+ switch (op)
+ {
+ case 0xf140: case 0xf340: case 0xf540: case 0xf740: case 0xf940: case 0xfb40: case 0xfd40: case 0xff40:
+ m_core->m_enable_irq = 0;
+ m_core->m_enable_fiq = 0;
+ return;
+
+ case 0xf141: case 0xf341: case 0xf541: case 0xf741: case 0xf941: case 0xfb41: case 0xfd41: case 0xff41:
+ m_core->m_enable_irq = 1;
+ m_core->m_enable_fiq = 0;
+ return;
+
+ case 0xf142: case 0xf342: case 0xf542: case 0xf742: case 0xf942: case 0xfb42: case 0xfd42: case 0xff42:
+ m_core->m_enable_irq = 0;
+ m_core->m_enable_fiq = 1;
+ return;
+
+ case 0xf143: case 0xf343: case 0xf543: case 0xf743: case 0xf943: case 0xfb43: case 0xfd43: case 0xff43:
+ m_core->m_enable_irq = 1;
+ m_core->m_enable_fiq = 1;
+ return;
+
+ case 0xf160: case 0xf360: case 0xf560: case 0xf760: case 0xf960: case 0xfb60: case 0xfd60: case 0xff60:
+ case 0xf168: case 0xf368: case 0xf568: case 0xf768: case 0xf968: case 0xfb68: case 0xfd68: case 0xff68:
+ case 0xf170: case 0xf370: case 0xf570: case 0xf770: case 0xf970: case 0xfb70: case 0xfd70: case 0xff70:
+ case 0xf178: case 0xf378: case 0xf578: case 0xf778: case 0xf978: case 0xfb78: case 0xfd78: case 0xff78:
+ unimplemented_opcode(op);
+ return;
+
+ case 0xf165: case 0xf365: case 0xf565: case 0xf765: case 0xf965: case 0xfb65: case 0xfd65: case 0xff65:
+ case 0xf16d: case 0xf36d: case 0xf56d: case 0xf76d: case 0xf96d: case 0xfb6d: case 0xfd6d: case 0xff6d:
+ case 0xf175: case 0xf375: case 0xf575: case 0xf775: case 0xf975: case 0xfb75: case 0xfd75: case 0xff75:
+ case 0xf17d: case 0xf37d: case 0xf57d: case 0xf77d: case 0xf97d: case 0xfb7d: case 0xfd7d: case 0xff7d:
+ // nothing
+ return;
+
+ // these are in code that otherwise seems like ISA1.0 / 1.1 (jak_disf for example) but spec says it's only in ISA 1.2?
+ case 0xf148: case 0xf348: case 0xf548: case 0xf748: case 0xf948: case 0xfb48: case 0xfd48: case 0xff48:
+ m_core->m_enable_irq = 0;
+ return;
+
+ case 0xf149: case 0xf349: case 0xf549: case 0xf749: case 0xf949: case 0xfb49: case 0xfd49: case 0xff49:
+ m_core->m_enable_irq = 1;
+ return;
+
+ case 0xf14c: case 0xf34c: case 0xf54c: case 0xf74c: case 0xf94c: case 0xfb4c: case 0xfd4c: case 0xff4c:
+ m_core->m_enable_fiq = 0;
+ return;
+
+ case 0xf14e: case 0xf34e: case 0xf54e: case 0xf74e: case 0xf94e: case 0xfb4e: case 0xfd4e: case 0xff4e:
+ m_core->m_enable_fiq = 1;
+ return;
+
+ default:
+ unimplemented_opcode(op);
+ return;
+ }
+
+ return;
+}
+
+
+inline void unsp_device::execute_fxxx_110_group(uint16_t op)
+{
+ //uint32_t len = 1;
+ // | | |
+ // signed * signed (size 16,1,2,3,4,5,6,7)
+ // MULS 1 1 1 1* r r r 1* 1 0*s s s r r r (1* = sign bit, 1* = sign bit 0* = upper size bit)
+
+ // MULS ss with upper size bit not set
+ unimplemented_opcode(op);
+ //return;
+}
+
+inline void unsp_device::execute_fxxx_111_group(uint16_t op)
+{
+ //uint32_t len = 1;
+ // | | |
+ // EXTOP 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 (+16 bit imm)
+ if ((op == 0xffc0) && m_iso >= 20)
+ {
+ return execute_extended_group(op);
+ }
+
+ // signed * signed (size 8,9,10,11,12,13,14,15)
+ // MULS 1 1 1 1* r r r 1* 1 1*s s s r r r (1* = sign bit, 1* = sign bit 1* = upper size bit)
+
+ // MULS ss with upper size bit set.
+ unimplemented_opcode(op);
+ //return;
+}
+
+void unsp_device::execute_fxxx_group(uint16_t op)
+{
+ switch ((op & 0x01c0) >> 6)
+ {
+ case 0x0:
+ return execute_fxxx_000_group(op);
+
+ case 0x1:
+ return execute_fxxx_001_group(op);
+
+ case 0x2:
+ return execute_fxxx_010_group(op);
+
+ case 0x3:
+ return execute_fxxx_011_group(op);
+
+ case 0x4:
+ return execute_fxxx_100_group(op);
+
+ case 0x5:
+ return execute_fxxx_101_group(op);
+
+ case 0x6:
+ return execute_fxxx_110_group(op);
+
+ case 0x7:
+ return execute_fxxx_111_group(op);
+
+ }
+
+ return;
+}
diff --git a/src/devices/cpu/unsp/unsp_jumps.cpp b/src/devices/cpu/unsp/unsp_jumps.cpp
new file mode 100644
index 00000000000..aa32f934ca5
--- /dev/null
+++ b/src/devices/cpu/unsp/unsp_jumps.cpp
@@ -0,0 +1,160 @@
+// license:GPL-2.0+
+// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood
+
+#include "emu.h"
+#include "unsp.h"
+#include "unspfe.h"
+
+#include "debugger.h"
+
+#include "unspdasm.h"
+
+void unsp_device::execute_jumps(const uint16_t op)
+{
+ const uint16_t op0 = (op >> 12) & 15;
+ const uint16_t op1 = (op >> 6) & 7;
+ const uint32_t opimm = op & 0x3f;
+
+ switch (op0)
+ {
+ case 0: // JB
+ if (!(m_core->m_r[REG_SR] & UNSP_C))
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 1: // JAE
+ if (m_core->m_r[REG_SR] & UNSP_C)
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 2: // JGE
+ if (!(m_core->m_r[REG_SR] & UNSP_S))
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 3: // JL
+ if (m_core->m_r[REG_SR] & UNSP_S)
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 4: // JNE
+ if (!(m_core->m_r[REG_SR] & UNSP_Z))
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 5: // JE
+ if (m_core->m_r[REG_SR] & UNSP_Z)
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 6: // JPL
+ if (!(m_core->m_r[REG_SR] & UNSP_N))
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 7: // JMI
+ if (m_core->m_r[REG_SR] & UNSP_N)
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 8: // JBE
+ if ((m_core->m_r[REG_SR] & (UNSP_Z | UNSP_C)) != UNSP_C) // branch if (!UNSP_Z && !UNSP_C) || UNSP_Z
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 9: // JA
+ if ((m_core->m_r[REG_SR] & (UNSP_Z | UNSP_C)) == UNSP_C) // branch if !UNSP_Z && UNSP_C
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 10: // JLE
+ if (m_core->m_r[REG_SR] & (UNSP_Z | UNSP_S))
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 11: // JG
+ if (!(m_core->m_r[REG_SR] & (UNSP_Z | UNSP_S)))
+ {
+ m_core->m_icount -= 4;
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ }
+ else
+ {
+ m_core->m_icount -= 2;
+ }
+ return;
+ case 14: // JMP
+ add_lpc((op1 == 0) ? opimm : (0 - opimm));
+ m_core->m_icount -= 4;
+ return;
+ default:
+ unimplemented_opcode(op);
+ return;
+ }
+}
diff --git a/src/devices/cpu/unsp/unsp_other.cpp b/src/devices/cpu/unsp/unsp_other.cpp
new file mode 100644
index 00000000000..9e9fb984cb4
--- /dev/null
+++ b/src/devices/cpu/unsp/unsp_other.cpp
@@ -0,0 +1,347 @@
+// license:GPL-2.0+
+// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood
+
+#include "emu.h"
+#include "unsp.h"
+#include "unspfe.h"
+
+#include "debugger.h"
+
+#include "unspdasm.h"
+
+void unsp_device::execute_remaining(const uint16_t op)
+{
+ uint32_t lres = 0;
+ uint16_t r0 = 0;
+ uint16_t r1 = 0;
+ uint32_t r2 = 0;
+
+ const uint16_t op0 = (op >> 12) & 15;
+ const uint16_t opa = (op >> 9) & 7;
+ const uint16_t op1 = (op >> 6) & 7;
+ const uint16_t opn = (op >> 3) & 7;
+ const uint16_t opb = op & 7;
+
+ const uint8_t lower_op = (op1 << 4) | op0;
+
+ if (lower_op == 0x2d) // Push
+ {
+ r0 = opn;
+ r1 = opa;
+ m_core->m_icount -= 4 + 2 * r0;
+
+ while (r0--)
+ {
+ push(m_core->m_r[r1--], &m_core->m_r[opb]);
+ }
+ return;
+ }
+ else if (lower_op == 0x29)
+ {
+ if (op == 0x9a98) // reti
+ {
+ m_core->m_icount -= 8;
+ m_core->m_r[REG_SR] = pop(&m_core->m_r[REG_SP]);
+ m_core->m_r[REG_PC] = pop(&m_core->m_r[REG_SP]);
+
+ if (m_core->m_fiq)
+ {
+ m_core->m_fiq = 0;
+ m_core->m_saved_sb[2] = m_core->m_sb;
+ m_core->m_sb = m_core->m_saved_sb[m_core->m_irq ? 1 : 0];
+ }
+ else if (m_core->m_irq)
+ {
+ m_core->m_irq = 0;
+ m_core->m_saved_sb[1] = m_core->m_sb;
+ m_core->m_sb = m_core->m_saved_sb[0];
+ }
+ m_core->m_curirq = 0;
+ check_irqs();
+ return;
+ }
+ else // pop
+ {
+ r0 = opn;
+ r1 = opa;
+ m_core->m_icount -= 4 + 2 * r0;
+
+ while (r0--)
+ {
+ m_core->m_r[++r1] = pop(&m_core->m_r[opb]);
+ }
+ return;
+ }
+ }
+
+ // At this point, we should be dealing solely with ALU ops.
+
+ r0 = m_core->m_r[opa];
+
+ switch (op1)
+ {
+ case 0x00: // r, [bp+imm6]
+ m_core->m_icount -= 6;
+
+ r2 = (uint16_t)(m_core->m_r[REG_BP] + (op & 0x3f));
+ if (op0 != 0x0d)
+ r1 = read16(r2);
+ break;
+
+ case 0x01: // r, imm6
+ m_core->m_icount -= 2;
+
+ r1 = op & 0x3f;
+ break;
+
+ case 0x03: // Indirect
+ {
+ m_core->m_icount -= (opa == 7 ? 7 : 6);
+
+ const uint8_t lsbits = opn & 3;
+ if (opn & 4)
+ {
+ switch (lsbits)
+ {
+ case 0: // r, [<ds:>r]
+ r2 = UNSP_LREG_I(opb);
+ if (op0 != 0x0d)
+ r1 = read16(r2);
+ break;
+
+ case 1: // r, [<ds:>r--]
+ r2 = UNSP_LREG_I(opb);
+ if (op0 != 0x0d)
+ r1 = read16(r2);
+ m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] - 1);
+ if (m_core->m_r[opb] == 0xffff)
+ m_core->m_r[REG_SR] -= 0x0400;
+ break;
+ case 2: // r, [<ds:>r++]
+ r2 = UNSP_LREG_I(opb);
+ if (op0 != 0x0d)
+ r1 = read16(r2);
+ m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] + 1);
+ if (m_core->m_r[opb] == 0x0000)
+ m_core->m_r[REG_SR] += 0x0400;
+ break;
+ case 3: // r, [<ds:>++r]
+ m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] + 1);
+ if (m_core->m_r[opb] == 0x0000)
+ m_core->m_r[REG_SR] += 0x0400;
+ r2 = UNSP_LREG_I(opb);
+ if (op0 != 0x0d)
+ r1 = read16(r2);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (lsbits)
+ {
+ case 0: // r, [r]
+ r2 = m_core->m_r[opb];
+ if (op0 != 0x0d)
+ r1 = read16(r2);
+ break;
+ case 1: // r, [r--]
+ r2 = m_core->m_r[opb];
+ if (op0 != 0x0d)
+ r1 = read16(r2);
+ m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] - 1);
+ break;
+ case 2: // r, [r++]
+ r2 = m_core->m_r[opb];
+ if (op0 != 0x0d)
+ r1 = read16(r2);
+ m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] + 1);
+ break;
+ case 3: // r, [++r]
+ m_core->m_r[opb] = (uint16_t)(m_core->m_r[opb] + 1);
+ r2 = m_core->m_r[opb];
+ if (op0 != 0x0d)
+ r1 = read16(r2);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ case 0x04: // 16-bit ops
+ switch (opn)
+ {
+ case 0x00: // r
+ m_core->m_icount -= (opa == 7 ? 5 : 3);
+ r1 = m_core->m_r[opb];
+ break;
+
+ case 0x01: // imm16
+ m_core->m_icount -= (opa == 7 ? 5 : 4);
+ r0 = m_core->m_r[opb];
+ r1 = read16(UNSP_LPC);
+ add_lpc(1);
+ break;
+
+ case 0x02: // [imm16]
+ m_core->m_icount -= (opa == 7 ? 8 : 7);
+ r0 = m_core->m_r[opb];
+ r2 = read16(UNSP_LPC);
+ add_lpc(1);
+
+ if (op0 != 0x0d)
+ {
+ r1 = read16(r2);
+ }
+ break;
+
+ case 0x03: // store [imm16], r
+ m_core->m_icount -= (opa == 7 ? 8 : 7);
+ r1 = r0;
+ r0 = m_core->m_r[opb];
+ r2 = read16(UNSP_LPC);
+ add_lpc(1);
+ break;
+
+ default: // Shifted ops
+ {
+ m_core->m_icount -= (opa == 7 ? 5 : 3);
+ uint32_t shift = (m_core->m_r[opb] << 4) | m_core->m_sb;
+ if (shift & 0x80000)
+ shift |= 0xf00000;
+ shift >>= (opn - 3);
+ m_core->m_sb = shift & 0x0f;
+ r1 = (uint16_t)(shift >> 4);
+ break;
+ }
+ }
+ break;
+
+ case 0x05: // More shifted ops
+ m_core->m_icount -= (opa == 7 ? 5 : 3);
+
+ if (opn & 4) // Shift right
+ {
+ const uint32_t shift = ((m_core->m_r[opb] << 4) | m_core->m_sb) >> (opn - 3);
+ m_core->m_sb = shift & 0x0f;
+ r1 = (uint16_t)(shift >> 4);
+ }
+ else // Shift left
+ {
+ const uint32_t shift = ((m_core->m_sb << 16) | m_core->m_r[opb]) << (opn + 1);
+ m_core->m_sb = (shift >> 16) & 0x0f;
+ r1 = (uint16_t)shift;
+ }
+ break;
+
+ case 0x06: // Rotated ops
+ {
+ m_core->m_icount -= (opa == 7 ? 5 : 3);
+
+ uint32_t shift = (((m_core->m_sb << 16) | m_core->m_r[opb]) << 4) | m_core->m_sb;
+ if (opn & 4) // Rotate right
+ {
+ shift >>= (opn - 3);
+ m_core->m_sb = shift & 0x0f;
+ }
+ else
+ {
+ shift <<= (opn + 1);
+ m_core->m_sb = (shift >> 20) & 0x0f;
+ }
+ r1 = (uint16_t)(shift >> 4);
+ break;
+ }
+
+ case 0x07: // Direct 8
+ m_core->m_icount -= (opa == 7 ? 6 : 5);
+ r2 = op & 0x3f;
+ r1 = read16(r2);
+ break;
+
+ default:
+ break;
+ }
+
+ switch (op0)
+ {
+ case 0x00: // Add
+ {
+ lres = r0 + r1;
+ if (opa != 7)
+ update_nzsc(lres, r0, r1);
+ break;
+ }
+ case 0x01: // Add w/ carry
+ {
+ uint32_t c = (m_core->m_r[REG_SR] & UNSP_C) ? 1 : 0;
+ lres = r0 + r1 + c;
+ if (opa != 7)
+ update_nzsc(lres, r0, r1);
+ break;
+ }
+ case 0x02: // Subtract
+ lres = r0 + (uint16_t)(~r1) + uint32_t(1);
+ if (opa != 7)
+ update_nzsc(lres, r0, ~r1);
+ break;
+ case 0x03: // Subtract w/ carry
+ {
+ uint32_t c = (m_core->m_r[REG_SR] & UNSP_C) ? 1 : 0;
+ lres = r0 + (uint16_t)(~r1) + c;
+ if (opa != 7)
+ update_nzsc(lres, r0, ~r1);
+ break;
+ }
+ case 0x04: // Compare
+ lres = r0 + (uint16_t)(~r1) + uint32_t(1);
+ if (opa != 7)
+ update_nzsc(lres, r0, ~r1);
+ return;
+ case 0x06: // Negate
+ lres = -r1;
+ if (opa != 7)
+ update_nz(lres);
+ break;
+ case 0x08: // XOR
+ lres = r0 ^ r1;
+ if (opa != 7)
+ update_nz(lres);
+ break;
+ case 0x09: // Load
+ lres = r1;
+ if (opa != 7)
+ update_nz(lres);
+ break;
+ case 0x0a: // OR
+ lres = r0 | r1;
+ if (opa != 7)
+ update_nz(lres);
+ break;
+ case 0x0b: // AND
+ lres = r0 & r1;
+ if (opa != 7)
+ update_nz(lres);
+ break;
+ case 0x0c: // Test
+ lres = r0 & r1;
+ if (opa != 7)
+ update_nz(lres);
+ return;
+ case 0x0d: // Store
+ write16(r2, r0);
+ return;
+
+ default:
+ unimplemented_opcode(op);
+ return;
+ }
+
+ if (op1 == 0x04 && opn == 0x03) // store [imm16], r
+ write16(r2, lres);
+ else
+ m_core->m_r[opa] = (uint16_t)lres;
+}
diff --git a/src/devices/cpu/unsp/unspdasm.cpp b/src/devices/cpu/unsp/unspdasm.cpp
index a69379b555b..3b52b519af3 100644
--- a/src/devices/cpu/unsp/unspdasm.cpp
+++ b/src/devices/cpu/unsp/unspdasm.cpp
@@ -1,5 +1,5 @@
// license:GPL-2.0+
-// copyright-holders:Segher Boessenkool
+// copyright-holders:Segher Boessenkool, David Haywood
/*****************************************************************************
SunPlus µ'nSP disassembler
@@ -13,18 +13,42 @@
#include "emu.h"
#include "unspdasm.h"
-char const *const unsp_disassembler::regs[] =
+char const* const unsp_disassembler::regs[] =
{
"sp", "r1", "r2", "r3", "r4", "bp", "sr", "pc"
};
-char const *const unsp_disassembler::jumps[] =
+char const* const unsp_disassembler::bitops[] =
{
- "jb", "jae", "jge", "jl", "jne", "je", "jpl", "jmi",
- "jbe", "ja", "jle", "jg", "jvc", "jvs", "jmp", "<inv>"
+ "tstb", "setb", "clrb", "invb"
};
-#define UNSP_DASM_OK (len | SUPPORTED)
+char const* const unsp_disassembler::signmodes[] =
+{
+ "uu", "us", "su?", "ss" // su? might be invalid
+};
+
+char const* const unsp_disassembler::lsft[] =
+{
+ "asr", "asror", "lsl", "lslor", "lsr", "lsror", "rol", "ror"
+};
+
+char const* const unsp_disassembler::extregs[] =
+{
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+};
+
+
+// TODO: use alu_op_start-like formatting
+char const* const unsp_disassembler::aluops[] =
+{
+ "add","adc","sub","sbc","cmp","(invalid)","neg","--","xor","load","or","and","test","store","(invalid)","(invalid)"
+};
+
+char const* const unsp_disassembler::forms[] =
+{
+ "[%s]", "[%s--]", "[%s++]", "[++%s]"
+};
u32 unsp_disassembler::opcode_alignment() const
{
@@ -57,6 +81,38 @@ void unsp_disassembler::print_alu_op3(std::ostream &stream, uint8_t op0, uint8_t
util::stream_format(stream, alu_op3[op0], regs[opB]);
}
+void unsp_disassembler::print_mul(std::ostream& stream, uint16_t op)
+{
+ int rs = (op & 0x0007) >> 0;
+ // (op & 0x0078) >> 3; fixed 0001
+ // (op & 0x0080) >> 7; fixed 0
+ int srd = (op & 0x0100) >> 8;
+ int rd = (op & 0x0e00) >> 9;
+ int srs = (op & 0x1000) >> 12;
+ // (op & 0xe000) >> 13; fixed 111
+
+ int sign = (srs << 1) | srd;
+
+ util::stream_format(stream, "MR = %s*%s, %s", regs[rd], regs[rs], signmodes[sign] );
+}
+
+void unsp_disassembler::print_muls(std::ostream& stream, uint16_t op)
+{
+ int rs = (op & 0x0007) >> 0;
+ int size = (op & 0x0078) >> 3;
+ // (op & 0x0080) >> 7; fixed 1
+ int srd = (op & 0x0100) >> 8;
+ int rd = (op & 0x0e00) >> 9;
+ int srs = (op & 0x1000) >> 12;
+ // (op & 0xe000) >> 13; fixed 111
+
+ int sign = (srs << 1) | srd;
+ if (size == 0) size = 16;
+
+ util::stream_format(stream, "MR = [%s]*[%s], %s, %d", regs[rd], regs[rs], signmodes[sign], size );
+}
+
+
void unsp_disassembler::print_alu_op_end(std::ostream &stream, uint8_t op0)
{
if (op0 == 1 || op0 == 3)
@@ -65,78 +121,16 @@ void unsp_disassembler::print_alu_op_end(std::ostream &stream, uint8_t op0)
void unsp_disassembler::print_indirect_op(std::ostream &stream, uint8_t opN, uint8_t opB)
{
- static const char* const forms[] = { "[%s]", "[%s--]", "[%s++]", "[++%s]" };
-
if (opN & 4)
util::stream_format(stream, "ds:");
util::stream_format(stream, forms[opN & 3], regs[opB]);
}
-offs_t unsp_disassembler::disassemble_f_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, uint8_t opN, uint8_t opA, uint8_t opB, uint32_t len)
-{
- switch (opN)
- {
- case 1:
- if (opA == 7)
- {
- util::stream_format(stream, "<DUNNO f group>");
- return UNSP_DASM_OK;
- }
- util::stream_format(stream, "mr = %s*%s, us", regs[opA], regs[opB]);
- return UNSP_DASM_OK;
- default:
- util::stream_format(stream, "<DUNNO f group>");
- return UNSP_DASM_OK;
- }
-}
-
-offs_t unsp_newer_disassembler::disassemble_f_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, uint8_t opN, uint8_t opA, uint8_t opB, uint32_t len)
-{
- // these are new opcodes on the later core
-
- switch (opN)
- {
- case 1:
- if (opA == 7)
- {
- util::stream_format(stream, "<EXTENDED f group>");
- return UNSP_DASM_OK;
- }
- util::stream_format(stream, "mr = %s*%s, us", regs[opA], regs[opB]);
- return UNSP_DASM_OK;
- default:
- util::stream_format(stream, "<EXTENDED f group>");
- return UNSP_DASM_OK;
- }
-}
-
-offs_t unsp_disassembler::disassemble(std::ostream &stream, offs_t pc, uint16_t op, uint16_t ximm)
+offs_t unsp_disassembler::disassemble_code(std::ostream &stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer &opcodes)
{
- // the top four bits are the alu op or the branch condition, or E or F
- uint8_t op0 = (op >> 12);
-
- // the next three are usually the destination register
- uint8_t opA = (op >> 9) & 7;
-
- // and the next three the addressing mode
- uint8_t op1 = (op >> 6) & 7;
-
- // the next three can be anything
- uint8_t opN = (op >> 3) & 7;
-
- // and the last three usually the second register (source register)
- uint8_t opB = op & 7;
-
- // the last six sometimes are a single immediate number
- uint8_t opimm = op & 63;
-
uint32_t len = 1;
- if ((op0 < 14 && op1 == 4 && (opN == 1 || opN == 2 || opN == 3)) || (op0 == 15 && (op1 == 1 || op1 == 2)))
- {
- len = 2;
- }
// all-zero and all-one are invalid insns:
if (op == 0 || op == 0xffff)
@@ -145,325 +139,29 @@ offs_t unsp_disassembler::disassemble(std::ostream &stream, offs_t pc, uint16_t
return UNSP_DASM_OK;
}
- // first, check for the conditional branch insns
- if (op0 < 15 && opA == 7 && op1 == 0)
- {
- util::stream_format(stream, "%s %04x", jumps[op0], pc+1+opimm);
- return UNSP_DASM_OK;
- }
- if (op0 < 15 && opA == 7 && op1 == 1)
- {
- util::stream_format(stream, "%s %04x", jumps[op0], pc+1-opimm);
- return UNSP_DASM_OK;
- }
-
- switch ((op1 << 4) | op0)
- {
- case 0x05: case 0x15: case 0x25: case 0x35:
- case 0x45: case 0x55: case 0x65: case 0x75:
- case 0x85: case 0x95: case 0xa5: case 0xb5:
- case 0xc5: case 0xd5:
- case 0x07: case 0x17: case 0x27: case 0x37:
- case 0x47: case 0x57: case 0x67: case 0x77:
- case 0x87: case 0x97: case 0xa7: case 0xb7:
- case 0xc7: case 0xd7:
- case 0x1d: case 0x5d: case 0x6d:
- case 0x20: case 0x21: case 0x22: case 0x23:
- case 0x24: case 0x26: case 0x28: case 0x2a:
- case 0x2b: case 0x2c:
- util::stream_format(stream, "<BAD>");
- return UNSP_DASM_OK;
-
-
- // alu, base+displacement
- case 0x00: case 0x01: case 0x02: case 0x03:
- case 0x04: case 0x06: case 0x08: case 0x09:
- case 0x0a: case 0x0b: case 0x0c:
- print_alu_op_start(stream, op0, opA);
- util::stream_format(stream, "[bp+%02x]", opimm);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
- case 0x0d:
- util::stream_format(stream, "[bp+%02x] = %s", opimm, regs[opA]);
- return UNSP_DASM_OK;
-
-
- // alu, 6-bit immediate
- case 0x10: case 0x11: case 0x12: case 0x13:
- case 0x14: case 0x16: case 0x18: case 0x19:
- case 0x1a: case 0x1b: case 0x1c:
- print_alu_op_start(stream, op0, opA);
- util::stream_format(stream, "%02x", opimm);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
-
-
- // pop insns
- case 0x29:
- if (op == 0x9a90)
- util::stream_format(stream, "retf");
- else if (op == 0x9a98)
- util::stream_format(stream, "reti");
- else if (opA+1 < 8 && opA+opN < 8)
- util::stream_format(stream, "pop %s, %s from [%s]",
- regs[opA+1], regs[opA+opN], regs[opB]);
- else
- util::stream_format(stream, "<BAD>");
- return UNSP_DASM_OK;
-
-
- // push insns
- case 0x2d:
- if (opA+1 >= opN && opA < opN+7)
- util::stream_format(stream, "push %s, %s to [%s]",
- regs[opA+1-opN], regs[opA], regs[opB]);
- else
- util::stream_format(stream, "<BAD>");
- return UNSP_DASM_OK;
-
-
- // alu, indirect memory
- case 0x30: case 0x31: case 0x32: case 0x33:
- case 0x34: case 0x36: case 0x38: case 0x39:
- case 0x3a: case 0x3b: case 0x3c:
- print_alu_op_start(stream, op0, opA);
- print_indirect_op(stream, opN, opB);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
- case 0x3d:
- print_indirect_op(stream, opN, opB);
- util::stream_format(stream, " = %s", regs[opA]);
- return UNSP_DASM_OK;
-
-
- case 0x40: case 0x41: case 0x42: case 0x43:
- case 0x44: case 0x46: case 0x48: case 0x49:
- case 0x4a: case 0x4b: case 0x4c:
- switch (opN)
- {
- // alu, register
- case 0:
- print_alu_op_start(stream, op0, opA);
- util::stream_format(stream, "%s", regs[opB]);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
-
- // alu, 16-bit immediate
- case 1:
- if ((op0 == 4 || op0 == 12 || op0 == 6 || op0 == 9) && opA != opB)
- {
- util::stream_format(stream, "<BAD>");
- return UNSP_DASM_OK;
- }
- if (op0 != 4 && op0 != 12)
- util::stream_format(stream, "%s = ", regs[opA]);
- print_alu_op3(stream, op0, opB);
- util::stream_format(stream, "%04x", ximm);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
-
- // alu, direct memory
- case 2:
- if ((op0 == 4 || op0 == 12 || op0 == 6 || op0 == 9) && opA != opB)
- {
- util::stream_format(stream, "<BAD>");
- return UNSP_DASM_OK;
- }
- if (op0 != 4 && op0 != 12)
- util::stream_format(stream, "%s = ", regs[opA]);
- print_alu_op3(stream, op0, opB);
- util::stream_format(stream, "[%04x]", ximm);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
-
- // alu, direct memory
- case 3:
- if (op0 == 4 || op0 == 12)
- {
- util::stream_format(stream, "<BAD>");
- return UNSP_DASM_OK;
- }
- if ((op0 == 6 || op0 == 9) && opA != opB)
- {
- util::stream_format(stream, "<BAD>");
- return UNSP_DASM_OK;
- }
- util::stream_format(stream, "[%04x] = ", ximm);
- print_alu_op3(stream, op0, opB);
- util::stream_format(stream, "%s", regs[opA]);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
-
- // alu, with shift
- default:
- print_alu_op_start(stream, op0, opA);
- util::stream_format(stream, "%s asr %x", regs[opB], (opN & 3) + 1);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
- }
-
- case 0x4d:
- switch (opN)
- {
- // alu, direct memory
- case 3:
- if (opA != opB)
- {
- util::stream_format(stream, "<BAD>");
- return UNSP_DASM_OK;
- }
- util::stream_format(stream, "[%04x] = %s", ximm, regs[opB]);
- return UNSP_DASM_OK;
- default:
- util::stream_format(stream, "<BAD>");
- return UNSP_DASM_OK;
- }
-
-
- // alu, with shift
- case 0x50: case 0x51: case 0x52: case 0x53:
- case 0x54: case 0x56: case 0x58: case 0x59:
- case 0x5a: case 0x5b: case 0x5c:
- print_alu_op_start(stream, op0, opA);
- if ((opN & 4) == 0)
- util::stream_format(stream, "%s lsl %x", regs[opB], (opN & 3) + 1);
- else
- util::stream_format(stream, "%s lsr %x", regs[opB], (opN & 3) + 1);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
-
-
- // alu, with shift
- case 0x60: case 0x61: case 0x62: case 0x63:
- case 0x64: case 0x66: case 0x68: case 0x69:
- case 0x6a: case 0x6b: case 0x6c:
- print_alu_op_start(stream, op0, opA);
- if ((opN & 4) == 0)
- util::stream_format(stream, "%s rol %x", regs[opB], (opN & 3) + 1);
- else
- util::stream_format(stream, "%s ror %x", regs[opB], (opN & 3) + 1);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
-
+ uint8_t op0 = (op >> 12);
- // alu, direct memory
- case 0x70: case 0x71: case 0x72: case 0x73:
- case 0x74: case 0x76: case 0x78: case 0x79:
- case 0x7a: case 0x7b: case 0x7c:
- print_alu_op_start(stream, op0, opA);
- util::stream_format(stream, "[%02x]", opimm);
- print_alu_op_end(stream, op0);
- return UNSP_DASM_OK;
- case 0x7d:
- util::stream_format(stream, "[%02x] = %s", opimm, regs[opA]);
- return UNSP_DASM_OK;
+ if (op0 == 0xf)
+ return disassemble_fxxx_group(stream, pc, op, ximm, opcodes);
+ uint8_t opA = (op >> 9) & 7;
+ uint8_t op1 = (op >> 6) & 7;
- case 0x1f:
- if (opA == 0)
- {
- util::stream_format(stream, "call %04x", (opimm << 16) | ximm);
- return UNSP_DASM_OK;
- }
- util::stream_format(stream, "<DUNNO>");
- return UNSP_DASM_OK;
+ if (op0 < 15 && opA == 7 && op1 < 2)
+ return disassemble_jumps(stream, pc, op);
- case 0x2f: case 0x3f: case 0x6f: case 0x7f:
- if (opA == 7 && op1 == 2)
- {
- util::stream_format(stream, "goto %04x", (opimm << 16) | ximm);
- return UNSP_DASM_OK;
- }
- if (opA == 7 && op1 == 3)
- {
- util::stream_format(stream, "<DUNNO>");
- return UNSP_DASM_OK;
- }
- util::stream_format(stream, "<DUNNO>");
- return UNSP_DASM_OK;
+ if (op0 == 0xe)
+ return disassemble_exxx_group(stream, pc, op, ximm);
+ return disassemble_remaining(stream, pc, op, ximm, opcodes);
+}
- case 0x0f:
- return disassemble_f_group(stream, pc, op, ximm, opN, opA, opB, len);
-
- case 0x4f:
- switch (opN)
- {
- case 1:
- if (opA == 7)
- {
- util::stream_format(stream, "<DUNNO>");
- return UNSP_DASM_OK;
- }
- util::stream_format(stream, "mr = %s*%s", regs[opA], regs[opB]);
- return UNSP_DASM_OK;
- default:
- util::stream_format(stream, "<DUNNO>");
- return UNSP_DASM_OK;
- }
-
- case 0x5f:
- if (opA != 0)
- {
- util::stream_format(stream, "<DUNNO>");
- return UNSP_DASM_OK;
- }
- switch (opimm)
- {
- case 0x00:
- util::stream_format(stream, "int off");
- return UNSP_DASM_OK;
- case 0x01:
- util::stream_format(stream, "int irq");
- return UNSP_DASM_OK;
- case 0x02:
- util::stream_format(stream, "int fiq");
- return UNSP_DASM_OK;
- case 0x03:
- util::stream_format(stream, "int fiq,irq");
- return UNSP_DASM_OK;
- case 0x04:
- util::stream_format(stream, "fir_mov on");
- return UNSP_DASM_OK;
- case 0x05:
- util::stream_format(stream, "fir_mov off");
- return UNSP_DASM_OK;
- case 0x08:
- util::stream_format(stream, "irq off");
- return UNSP_DASM_OK;
- case 0x09:
- util::stream_format(stream, "irq on");
- return UNSP_DASM_OK;
- case 0x0c:
- util::stream_format(stream, "fiq off");
- return UNSP_DASM_OK;
- case 0x0e:
- util::stream_format(stream, "fiq on");
- return UNSP_DASM_OK;
- case 0x25:
- util::stream_format(stream, "nop");
- return UNSP_DASM_OK;
- default:
- util::stream_format(stream, "<DUNNO>");
- return UNSP_DASM_OK;
- }
-
- case 0x0e: case 0x1e: case 0x2e: case 0x3e:
- case 0x4e: case 0x5e: case 0x6e: case 0x7e:
- util::stream_format(stream, "<DUNNO>");
- return UNSP_DASM_OK;
- default:
- util::stream_format(stream, "<UNHANDLED>");
- return UNSP_DASM_OK;
- }
- return UNSP_DASM_OK;
-}
offs_t unsp_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
{
uint16_t op = opcodes.r16(pc);
uint16_t imm16 = opcodes.r16(pc+1);
- return disassemble(stream, pc, op, imm16);
+ return disassemble_code(stream, pc, op, imm16, opcodes);
}
diff --git a/src/devices/cpu/unsp/unspdasm.h b/src/devices/cpu/unsp/unspdasm.h
index cd896b03ea7..32d73605b76 100644
--- a/src/devices/cpu/unsp/unspdasm.h
+++ b/src/devices/cpu/unsp/unspdasm.h
@@ -1,5 +1,5 @@
// license:GPL-2.0
-// copyright-holders:Segher Boessenkool
+// copyright-holders:Segher Boessenkool, David Haywood
/*****************************************************************************
SunPlus µ'nSP disassembler
@@ -15,39 +15,88 @@
#pragma once
+#define UNSP_DASM_OK (len | SUPPORTED)
+
class unsp_disassembler : public util::disasm_interface
{
public:
- unsp_disassembler() = default;
+ unsp_disassembler()
+ {
+ m_iso = 10;
+ }
+
virtual ~unsp_disassembler() = default;
virtual u32 opcode_alignment() const override;
virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
- offs_t disassemble(std::ostream &stream, offs_t pc, uint16_t op, uint16_t imm16);
+ offs_t disassemble_code(std::ostream &stream, offs_t pc, uint16_t op, uint16_t imm16, const data_buffer& opcodes);
protected:
- virtual offs_t disassemble_f_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, uint8_t opN, uint8_t opA, uint8_t opB, uint32_t len);
+ offs_t disassemble_fxxx_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer& opcodes);
+ offs_t disassemble_jumps(std::ostream& stream, offs_t pc, const uint16_t op);
+ offs_t disassemble_remaining(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer& opcodes);
+
+ offs_t disassemble_fxxx_000_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm);
+ offs_t disassemble_fxxx_001_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm);
+ offs_t disassemble_fxxx_010_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm);
+ offs_t disassemble_fxxx_011_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm);
+ offs_t disassemble_fxxx_100_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm);
+ virtual offs_t disassemble_fxxx_101_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm);
+ offs_t disassemble_fxxx_110_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm);
+ offs_t disassemble_fxxx_111_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer& opcodes);
+
+ virtual offs_t disassemble_exxx_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm);
+ virtual offs_t disassemble_extended_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer& opcodes);
static char const *const regs[];
+ static char const *const extregs[];
static char const *const jumps[];
+ static char const *const bitops[];
+ static char const *const signmodes[];
+ static char const *const lsft[];
+ static char const *const aluops[];
+ static char const *const forms[];
-private:
+ int m_iso;
+
+protected:
void print_alu_op_start(std::ostream &stream, uint8_t op0, uint8_t opA);
void print_alu_op3(std::ostream &stream, uint8_t op0, uint8_t opB);
void print_alu_op_end(std::ostream &stream, uint8_t op0);
void print_indirect_op(std::ostream &stream, uint8_t opN, uint8_t opB);
+ void print_muls(std::ostream& stream, uint16_t op);
+ void print_mul(std::ostream& stream, uint16_t op);
};
-class unsp_newer_disassembler : public unsp_disassembler
+class unsp_12_disassembler : public unsp_disassembler
{
public:
- unsp_newer_disassembler() = default;
- virtual ~unsp_newer_disassembler() = default;
+ unsp_12_disassembler()
+ {
+ m_iso = 12;
+ }
+
+ virtual ~unsp_12_disassembler() = default;
+
+private:
+ virtual offs_t disassemble_fxxx_101_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm) override;
+ virtual offs_t disassemble_exxx_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm) override;
+};
+
+class unsp_20_disassembler : public unsp_12_disassembler
+{
+public:
+ unsp_20_disassembler()
+ {
+ m_iso = 20;
+ }
+
+ virtual ~unsp_20_disassembler() = default;
private:
- virtual offs_t disassemble_f_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, uint8_t opN, uint8_t opA, uint8_t opB, uint32_t len) override;
+ virtual offs_t disassemble_extended_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer& opcodes) override;
};
diff --git a/src/devices/cpu/unsp/unspdasm_extended.cpp b/src/devices/cpu/unsp/unspdasm_extended.cpp
new file mode 100644
index 00000000000..a64f726c332
--- /dev/null
+++ b/src/devices/cpu/unsp/unspdasm_extended.cpp
@@ -0,0 +1,193 @@
+// license:GPL-2.0+
+// copyright-holders:Segher Boessenkool, David Haywood
+/*****************************************************************************
+
+ SunPlus µ'nSP disassembler
+
+ Copyright 2008-2017 Segher Boessenkool <segher@kernel.crashing.org>
+ Licensed under the terms of the GNU GPL, version 2
+ http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+*****************************************************************************/
+
+#include "emu.h"
+#include "unspdasm.h"
+
+offs_t unsp_disassembler::disassemble_extended_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer& opcodes)
+{
+ // shouldn't get here anyway
+ int len = 1;
+ util::stream_format(stream, "<UNKNOWN EXTENDED>");
+ return UNSP_DASM_OK;
+}
+
+offs_t unsp_20_disassembler::disassemble_extended_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm,const data_buffer &opcodes)
+{
+ uint32_t len = 2;
+
+ switch ((ximm & 0x01f0) >> 4)
+ {
+ case 0x00: case 0x10:
+ {
+ // Ext Register Ra = Ra op Rb
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t ra = (op & 0x0e00) >> 9;
+ ra |= (op & 0x0100) >> 5;
+
+ util::stream_format(stream, "(Ext) %s = %s %s %s", (ra & 0x8) ? extregs[ra & 0x7] : regs[ra & 0x7]
+ , (ra & 0x8) ? extregs[ra & 0x7] : regs[ra & 0x7]
+ , aluops[aluop]
+ , (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]);
+ return UNSP_DASM_OK;
+ }
+ case 0x02:
+ {
+ // Ext Push/Pop
+ if (op & 0x8000)
+ {
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t size = (op & 0x7000) >> 12;
+ uint8_t rx = (op & 0x0e00) >> 9;
+
+ if (rx+1 >= size && rx < size+7)
+ util::stream_format(stream, "(Ext) push %s, %s to [%s]",
+ extregs[rx+1-size], extregs[rx], (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]);
+ else
+ util::stream_format(stream, "(Ext) push <BAD>");
+ }
+ else
+ {
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t size = (op & 0x7000) >> 12;
+ uint8_t rx = (op & 0x0e00) >> 9;
+
+ if (rx+1 < 8 && rx+size < 8)
+ util::stream_format(stream, "(Ext) pop %s, %s from [%s]",
+ extregs[rx+1], extregs[rx+size], (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]);
+ else
+ util::stream_format(stream, "(Ext) pop <BAD>");
+ }
+ return UNSP_DASM_OK;
+ }
+ case 0x04: case 0x14:
+ {
+ // Ra=Rb op IMM16
+ len = 3;
+ uint16_t imm16_2 = opcodes.r16(pc + 2);
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t ra = (op & 0x0e00) >> 9;
+ ra |= (op & 0x0100) >> 5;
+
+ util::stream_format(stream, "(Ext) %s = %s %s %04x", (ra & 0x8) ? extregs[ra & 0x7] : regs[ra & 0x7]
+ , (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]
+ , aluops[aluop]
+ , imm16_2);
+ return UNSP_DASM_OK;
+ }
+
+ case 0x06:
+ case 0x16:
+ {
+ // Ra=Rb op [A16]
+ len = 3;
+ uint16_t imm16_2 = opcodes.r16(pc + 2);
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t ra = (op & 0x0e00) >> 9;
+ ra |= (op & 0x0100) >> 5;
+
+ util::stream_format(stream, "(Ext) %s = %s %s [%04x]", (ra & 0x8) ? extregs[ra & 0x7] : regs[ra & 0x7]
+ , (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]
+ , aluops[aluop]
+ , imm16_2);
+ return UNSP_DASM_OK;
+ }
+
+ case 0x07:
+ case 0x17:
+ {
+ //[A16] = Ra op Rb
+ len = 3;
+ uint16_t imm16_2 = opcodes.r16(pc + 2);
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rb = (op & 0x000f) >> 0;
+ uint8_t ra = (op & 0x0e00) >> 9;
+ ra |= (op & 0x0100) >> 5;
+
+ util::stream_format(stream, "(Ext) [0x4x] = %s %s %s", imm16_2
+ , (ra & 0x8) ? extregs[ra & 0x7] : regs[ra & 0x7]
+ , aluops[aluop]
+ , (rb & 0x8) ? extregs[rb & 0x7] : regs[rb & 0x7]);
+ return UNSP_DASM_OK;
+ }
+
+ case 0x08: case 0x09:
+ {
+ // Ext Indirect Rx=Rx op [Ry@]
+
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t ry = (op & 0x0007) >> 0;
+ uint8_t form = (op & 0x0018) >> 3;
+ uint8_t rx = (op & 0x0e00) >> 9;
+
+ util::stream_format(stream, "(Ext) %s=%s %s", extregs[rx], extregs[rx], aluops[aluop]);
+ util::stream_format(stream, forms[form], extregs[ry]);
+
+ return UNSP_DASM_OK;
+ }
+ case 0x0a: case 0x0b:
+ {
+ // Ext DS_Indirect Rx=Rx op ds:[Ry@]
+
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t ry = (op & 0x0007) >> 0;
+ uint8_t form = (op & 0x0018) >> 3;
+ uint8_t rx = (op & 0x0e00) >> 9;
+
+ util::stream_format(stream, "(Ext) %s=%s %s ds:", extregs[rx], extregs[rx], aluops[aluop]);
+ util::stream_format(stream, forms[form], extregs[ry]);
+
+ return UNSP_DASM_OK;
+ }
+ case 0x18: case 0x19: case 0x1a: case 0x1b:
+ {
+ // Ext IM6 Rx=Rx op IM6
+
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rx = (op & 0x0e00) >> 9;
+ uint8_t imm6 = (op & 0x003f) >> 0;
+
+ util::stream_format(stream, "(Ext) %s=%s %s %02x", extregs[rx], extregs[rx], aluops[aluop], imm6 );
+ return UNSP_DASM_OK;
+ }
+
+ case 0x0c: case 0x0d: case 0x0e: case 0x0f:
+ {
+ // Ext Base+Disp6 Rx=Rx op [BP+IM6]
+
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rx = (op & 0x0e00) >> 9;
+ uint8_t imm6 = (op & 0x003f) >> 0;
+
+ util::stream_format(stream, "(Ext) %s=%s %s [BP+%02x]", extregs[rx], extregs[rx], aluops[aluop], imm6 );
+ return UNSP_DASM_OK;
+ }
+
+ case 0x1c: case 0x1d: case 0x1e: case 0x1f:
+ {
+ // Ext A6 Rx=Rx op [A6]
+
+ uint8_t aluop = (op & 0xf000) >> 12;
+ uint8_t rx = (op & 0x0e00) >> 9;
+ uint8_t a6 = (op & 0x003f) >> 0;
+
+ util::stream_format(stream, "(Ext) %s=%s %s [%02x]", extregs[rx], extregs[rx], aluops[aluop], a6 );
+ return UNSP_DASM_OK;
+ }
+ }
+
+ util::stream_format(stream, "<UNKNOWN EXTENDED>");
+ return UNSP_DASM_OK;
+}
diff --git a/src/devices/cpu/unsp/unspdasm_exxx.cpp b/src/devices/cpu/unsp/unspdasm_exxx.cpp
new file mode 100644
index 00000000000..43c494cc0a5
--- /dev/null
+++ b/src/devices/cpu/unsp/unspdasm_exxx.cpp
@@ -0,0 +1,117 @@
+// license:GPL-2.0+
+// copyright-holders:Segher Boessenkool, David Haywood
+/*****************************************************************************
+
+ SunPlus µ'nSP disassembler
+
+ Copyright 2008-2017 Segher Boessenkool <segher@kernel.crashing.org>
+ Licensed under the terms of the GNU GPL, version 2
+ http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+*****************************************************************************/
+
+#include "emu.h"
+#include "unspdasm.h"
+
+offs_t unsp_disassembler::disassemble_exxx_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm)
+{
+ uint32_t len = 1;
+ // several exxx opcodes have already been decoded as jumps by the time we get here
+ util::stream_format(stream, "<DUNNO>");
+ return UNSP_DASM_OK;
+}
+
+offs_t unsp_12_disassembler::disassemble_exxx_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm)
+{
+ uint32_t len = 1;
+ // several exxx opcodes have already been decoded as jumps by the time we get here
+
+ // Register BITOP BITOP Rd,Rs 1 1 1 0 r r r 0 0 0 b b 0 r r r
+ // Register BITOP BITOP Rd,offset 1 1 1 0 r r r 0 0 1 b b o o o o
+ // Memory BITOP BITOP [Rd], offset 1 1 1 0 r r r 1 1 0 b b o o o o
+ // Memory BITOP BITOP ds:[Rd], offset 1 1 1 0 r r r 1 1 1 b b o o o o
+ // Memory BITOP BITOP [Rd], Rs 1 1 1 0 r r r 1 0 0 b b 0 r r r
+ // Memory BITOP BITOP ds:[Rd], Rs 1 1 1 0 r r r 1 0 1 b b 0 r r r
+
+ if (((op & 0xf1c8) == 0xe000))
+ {
+ // Register BITOP BITOP Rd,Rs
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t rs = (op & 0x0007) >> 0;
+ util::stream_format(stream, "%s %s,%s", bitops[bitop], regs[rd], regs[rs]);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf1c0) == 0xe040))
+ {
+ // Register BITOP BITOP Rd,offset
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t offset = (op & 0x000f) >> 0;
+ util::stream_format(stream, "%s %s,%d", bitops[bitop], regs[rd], offset);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf1c0) == 0xe180))
+ {
+ // Memory BITOP BITOP [Rd], offset
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t offset = (op & 0x000f) >> 0;
+ util::stream_format(stream, "%s [%s],%d", bitops[bitop], regs[rd], offset);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf1c0) == 0xe1c0))
+ {
+ // Memory BITOP BITOP ds:[Rd], offset
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t offset = (op & 0x000f) >> 0;
+ util::stream_format(stream, "%s ds:[%s],%d", bitops[bitop], regs[rd], offset);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf1c8) == 0xe100))
+ {
+ // Memory BITOP BITOP [Rd], Rs
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t rs = (op & 0x0007) >> 0;
+ util::stream_format(stream, "%s [%s],%s", bitops[bitop], regs[rd], regs[rs]);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf1c8) == 0xe140))
+ {
+ // Memory BITOP BITOP ds:[Rd], Rs
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t rs = (op & 0x0007) >> 0;
+ util::stream_format(stream, "%s ds:[%s],%s", bitops[bitop], regs[rd], regs[rs]);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf0f8) == 0xe008))
+ {
+ // MUL operations
+ // MUL 1 1 1 0* r r r S* 0 0 0 0 1 r r r (* = sign bit, fixed here)
+ print_mul(stream, op); // MUL uu or MUL su (invalid?)
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf080) == 0xe080))
+ {
+ // MULS 1 1 1 0* r r r S* 1 s s s s r r r (* = sign bit, fixed here)
+
+ // MULS uu or MULS su (invalid?)
+ print_muls(stream, op);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf188) == 0xe108))
+ {
+ // 16 bit Shift 1 1 1 0 r r r 1 0 l l l 1 r r r
+ uint8_t rd = (op & 0x0e00) >> 9;
+ uint8_t shift = (op & 0x0070) >> 4;
+ uint8_t rs = (op & 0x0007) >> 0;
+ util::stream_format(stream, "%s = %s %s %s", regs[rd], regs[rd], lsft[shift], regs[rs]);
+ return UNSP_DASM_OK;
+ }
+
+ util::stream_format(stream, "<DUNNO>");
+ return UNSP_DASM_OK;
+}
diff --git a/src/devices/cpu/unsp/unspdasm_fxxx.cpp b/src/devices/cpu/unsp/unspdasm_fxxx.cpp
new file mode 100644
index 00000000000..55ace86f178
--- /dev/null
+++ b/src/devices/cpu/unsp/unspdasm_fxxx.cpp
@@ -0,0 +1,371 @@
+// license:GPL-2.0+
+// copyright-holders:Segher Boessenkool, David Haywood
+/*****************************************************************************
+
+ SunPlus µ'nSP disassembler
+
+ Copyright 2008-2017 Segher Boessenkool <segher@kernel.crashing.org>
+ Licensed under the terms of the GNU GPL, version 2
+ http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+*****************************************************************************/
+
+#include "emu.h"
+#include "unspdasm.h"
+
+offs_t unsp_disassembler::disassemble_fxxx_000_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm)
+{
+ // | | |
+ // DS16 1 1 1 1 1 1 1 0 0 0 i i i i i i
+ // DS Reg 1 1 1 1 - - - 0 0 0 1 0 w r r r
+ // FR Reg 1 1 1 1 - - - 0 0 0 1 1 w r r r
+ uint32_t len = 1;
+
+ if (((op & 0xffc0) == 0xfe00) && m_iso >= 12)
+ {
+ int imm = op & 0x003f;
+ util::stream_format(stream, "ds = %02x", imm);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf1f8) == 0xf020) && m_iso >= 12)
+ {
+ int r = op & 0x7;
+ util::stream_format(stream, "%s = ds", regs[r]);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf1f8) == 0xf028) && m_iso >= 12)
+ {
+ int r = op & 0x7;
+ util::stream_format(stream, "ds = %s", regs[r]);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf1f8) == 0xf030) && m_iso >= 12)
+ {
+ int r = op & 0x7;
+ util::stream_format(stream, "%s = fr", regs[r]);
+ return UNSP_DASM_OK;
+ }
+ else if (((op & 0xf1f8) == 0xf038) && m_iso >= 12)
+ {
+ int r = op & 0x7;
+ util::stream_format(stream, "fr = %s", regs[r]);
+ return UNSP_DASM_OK;
+ }
+
+ // everything else falls through to the multiply
+
+ // signed * unsigned
+ // MUL 1 1 1 1* r r r 0* 0 0 0 0 1 r r r (** = sign bits, fixed here)
+ print_mul(stream, op); // MUL us
+ return UNSP_DASM_OK;
+}
+
+offs_t unsp_disassembler::disassemble_fxxx_001_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm)
+{
+ // | | |
+ // CALL16 1 1 1 1 - - 0 0 0 1 a a a a a a (+imm16)
+
+ uint32_t len = 1;
+
+ if ((op & 0xf3c0) == 0xf040)
+ {
+ len = 2;
+ uint8_t opimm = op & 0x3f;
+ util::stream_format(stream, "call %06x", (opimm << 16) | ximm);
+ return UNSP_DASM_OK;
+ }
+ // MEM bitop 1 1 1 1 - D 1 0 0 1 b b o o o o (+imm16) ( BITOP {ds:}[A16],offset )
+ else if (((op & 0xf3c0) == 0xf240) && m_iso >= 20)
+ {
+ len = 2;
+ uint8_t bitop = (op & 0x0030) >> 4;
+ uint8_t offset = (op & 0x000f) >> 0;
+ uint8_t d = (op & 0x0400) >> 10;
+
+ if (d)
+ util::stream_format(stream, "%s ds:[$04x],%d", bitops[bitop], offset);
+ else
+ util::stream_format(stream, "%s [$04x],%d", bitops[bitop], offset);
+
+ return UNSP_DASM_OK;
+ }
+
+ util::stream_format(stream, "<DUNNO>");
+ return UNSP_DASM_OK;
+}
+
+offs_t unsp_disassembler::disassemble_fxxx_010_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm)
+{
+ uint32_t len = 1;
+ // | | |
+ // JMPF 1 1 1 1 1 1 1 0 1 0 a a a a a a (+imm16)
+
+ if ((op & 0xffc0) == 0xfe80) // apparently 1.2 and above, but jak_capb needs it and otherwise seems 1.0 / 1.1?
+ {
+ len = 2;
+ uint8_t opimm = op & 0x3f;
+ util::stream_format(stream, "goto %06x", (opimm << 16) | ximm);
+ return UNSP_DASM_OK;
+ }
+
+ // signed * unsigned (size 16,1,2,3,4,5,6,7)
+ // MULS 1 1 1 1* r r r 0* 1 0*s s s r r r (1* = sign bit, 0* = sign bit 0* = upper size bit)
+
+ // MULS us with upper size bit not set
+ print_muls(stream, op);
+ return UNSP_DASM_OK;
+}
+
+offs_t unsp_disassembler::disassemble_fxxx_011_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm)
+{
+ uint32_t len = 1;
+ // | | |
+ // JMPR 1 1 1 1 1 1 1 0 1 1 - - - - - -
+ if (((op & 0xffc0) == 0xfec0) && m_iso >= 12)
+ {
+ util::stream_format(stream, "goto mr");
+ return UNSP_DASM_OK;
+ }
+
+ // signed * unsigned (size 8,9,10,11,12,13,14,15)
+ // MULS 1 1 1 1* r r r 0* 1 1*s s s r r r (1* = sign bit, 0* = sign bit 1* = upper size bit)
+
+ // MULS us with upper size bit set
+ print_muls(stream, op);
+
+ return UNSP_DASM_OK;
+}
+
+offs_t unsp_disassembler::disassemble_fxxx_100_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm)
+{
+ uint32_t len = 1;
+ // | | |
+ // signed * signed
+ // MUL 1 1 1 1* r r r 1* 0 0 0 0 1 r r r (** = sign bits, fixed here)
+
+ if ((op & 0xf1f8) == 0xf108)
+ {
+ print_mul(stream, op); // MUL ss
+ return UNSP_DASM_OK;
+ }
+
+ util::stream_format(stream, "<DUNNO>");
+ return UNSP_DASM_OK;
+}
+
+
+offs_t unsp_12_disassembler::disassemble_fxxx_101_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm)
+{
+ // IRQ 1 1 1 1 - - - 1 0 1 0 0 1 0 0 I
+ // FIRQ 1 1 1 1 - - - 1 0 1 0 0 1 1 F 0
+ // FIR_MOV 1 1 1 1 - - - 1 0 1 0 0 0 1 0 f
+ // Fraction 1 1 1 1 - - - 1 0 1 0 0 0 1 1 f
+ // SECBANK 1 1 1 1 - - - 1 0 1 0 0 1 0 1 S
+ // NESTMODE 1 1 1 1 - - - 1 0 1 0 0 1 1 N 1
+ // CALLR 1 1 1 1 - - - 1 0 1 1 - - 0 0 1
+ // DIVS 1 1 1 1 - - - 1 0 1 1 - - 0 1 0
+ // DIVQ 1 1 1 1 - - - 1 0 1 1 - - 0 1 1
+ // EXP 1 1 1 1 - - - 1 0 1 1 - - 1 0 0
+
+ uint32_t len = 1;
+
+ switch (op)
+ {
+ case 0xf146: case 0xf346: case 0xf546: case 0xf746: case 0xf946: case 0xfb46: case 0xfd46: case 0xff46:
+ util::stream_format(stream, "fraction off");
+ return UNSP_DASM_OK;
+
+ case 0xf147: case 0xf347: case 0xf547: case 0xf747: case 0xf947: case 0xfb47: case 0xfd47: case 0xff47:
+ util::stream_format(stream, "fraction on");
+ return UNSP_DASM_OK;
+
+ case 0xf14a: case 0xf34a: case 0xf54a: case 0xf74a: case 0xf94a: case 0xfb4a: case 0xfd4a: case 0xff4a:
+ util::stream_format(stream, "secbank off");
+ return UNSP_DASM_OK;
+
+ case 0xf14b: case 0xf34b: case 0xf54b: case 0xf74b: case 0xf94b: case 0xfb4b: case 0xfd4b: case 0xff4b:
+ util::stream_format(stream, "secbank on");
+ return UNSP_DASM_OK;
+
+ case 0xf14d: case 0xf34d: case 0xf54d: case 0xf74d: case 0xf94d: case 0xfb4d: case 0xfd4d: case 0xff4d:
+ util::stream_format(stream, "irqnest off");
+ return UNSP_DASM_OK;
+
+ case 0xf14f: case 0xf34f: case 0xf54f: case 0xf74f: case 0xf94f: case 0xfb4f: case 0xfd4f: case 0xff4f:
+ util::stream_format(stream, "irqnest on");
+ return UNSP_DASM_OK;
+
+ case 0xf144: case 0xf344: case 0xf544: case 0xf744: case 0xf944: case 0xfb44: case 0xfd44: case 0xff44:
+ util::stream_format(stream, "fir_mov on");
+ return UNSP_DASM_OK;
+
+ case 0xf145: case 0xf345: case 0xf545: case 0xf745: case 0xf945: case 0xfb45: case 0xfd45: case 0xff45:
+ util::stream_format(stream, "fir_mov off");
+ return UNSP_DASM_OK;
+
+ case 0xf161: case 0xf361: case 0xf561: case 0xf761: case 0xf961: case 0xfb61: case 0xfd61: case 0xff61:
+ case 0xf169: case 0xf369: case 0xf569: case 0xf769: case 0xf969: case 0xfb69: case 0xfd69: case 0xff69:
+ case 0xf171: case 0xf371: case 0xf571: case 0xf771: case 0xf971: case 0xfb71: case 0xfd71: case 0xff71:
+ case 0xf179: case 0xf379: case 0xf579: case 0xf779: case 0xf979: case 0xfb79: case 0xfd79: case 0xff79:
+ util::stream_format(stream, "call mr");
+ return UNSP_DASM_OK;
+
+ case 0xf162: case 0xf362: case 0xf562: case 0xf762: case 0xf962: case 0xfb62: case 0xfd62: case 0xff62:
+ case 0xf16a: case 0xf36a: case 0xf56a: case 0xf76a: case 0xf96a: case 0xfb6a: case 0xfd6a: case 0xff6a:
+ case 0xf172: case 0xf372: case 0xf572: case 0xf772: case 0xf972: case 0xfb72: case 0xfd72: case 0xff72:
+ case 0xf17a: case 0xf37a: case 0xf57a: case 0xf77a: case 0xf97a: case 0xfb7a: case 0xfd7a: case 0xff7a:
+ util::stream_format(stream, "divs mr, r2");
+ return UNSP_DASM_OK;
+
+ case 0xf163: case 0xf363: case 0xf563: case 0xf763: case 0xf963: case 0xfb63: case 0xfd63: case 0xff63:
+ case 0xf16b: case 0xf36b: case 0xf56b: case 0xf76b: case 0xf96b: case 0xfb6b: case 0xfd6b: case 0xff6b:
+ case 0xf173: case 0xf373: case 0xf573: case 0xf773: case 0xf973: case 0xfb73: case 0xfd73: case 0xff73:
+ case 0xf17b: case 0xf37b: case 0xf57b: case 0xf77b: case 0xf97b: case 0xfb7b: case 0xfd7b: case 0xff7b:
+ util::stream_format(stream, "divq mr, r2");
+ return UNSP_DASM_OK;
+
+ case 0xf164: case 0xf364: case 0xf564: case 0xf764: case 0xf964: case 0xfb64: case 0xfd64: case 0xff64:
+ case 0xf16c: case 0xf36c: case 0xf56c: case 0xf76c: case 0xf96c: case 0xfb6c: case 0xfd6c: case 0xff6c:
+ case 0xf174: case 0xf374: case 0xf574: case 0xf774: case 0xf974: case 0xfb74: case 0xfd74: case 0xff74:
+ case 0xf17c: case 0xf37c: case 0xf57c: case 0xf77c: case 0xf97c: case 0xfb7c: case 0xfd7c: case 0xff7c:
+ util::stream_format(stream, "r2 = exp r4");
+ return UNSP_DASM_OK;
+
+
+ default:
+ return unsp_disassembler::disassemble_fxxx_101_group(stream, pc, op, ximm);
+ }
+}
+
+
+offs_t unsp_disassembler::disassemble_fxxx_101_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm)
+{
+ // | | |
+ // INT SET 1 1 1 1 - - - 1 0 1 0 0 0 0 F I
+ // BREAK 1 1 1 1 - - - 1 0 1 1 - - 0 0 0
+ // NOP 1 1 1 1 - - - 1 0 1 1 - - 1 0 1
+
+ uint32_t len = 1;
+
+ switch (op)
+ {
+ case 0xf140: case 0xf340: case 0xf540: case 0xf740: case 0xf940: case 0xfb40: case 0xfd40: case 0xff40:
+ util::stream_format(stream, "int off");
+ return UNSP_DASM_OK;
+
+ case 0xf141: case 0xf341: case 0xf541: case 0xf741: case 0xf941: case 0xfb41: case 0xfd41: case 0xff41:
+ util::stream_format(stream, "int irq");
+ return UNSP_DASM_OK;
+
+ case 0xf142: case 0xf342: case 0xf542: case 0xf742: case 0xf942: case 0xfb42: case 0xfd42: case 0xff42:
+ util::stream_format(stream, "int fiq");
+ return UNSP_DASM_OK;
+
+ case 0xf143: case 0xf343: case 0xf543: case 0xf743: case 0xf943: case 0xfb43: case 0xfd43: case 0xff43:
+ util::stream_format(stream, "int fiq,irq");
+ return UNSP_DASM_OK;
+
+ case 0xf160: case 0xf360: case 0xf560: case 0xf760: case 0xf960: case 0xfb60: case 0xfd60: case 0xff60:
+ case 0xf168: case 0xf368: case 0xf568: case 0xf768: case 0xf968: case 0xfb68: case 0xfd68: case 0xff68:
+ case 0xf170: case 0xf370: case 0xf570: case 0xf770: case 0xf970: case 0xfb70: case 0xfd70: case 0xff70:
+ case 0xf178: case 0xf378: case 0xf578: case 0xf778: case 0xf978: case 0xfb78: case 0xfd78: case 0xff78:
+ util::stream_format(stream, "break");
+ return UNSP_DASM_OK;
+
+ case 0xf165: case 0xf365: case 0xf565: case 0xf765: case 0xf965: case 0xfb65: case 0xfd65: case 0xff65:
+ case 0xf16d: case 0xf36d: case 0xf56d: case 0xf76d: case 0xf96d: case 0xfb6d: case 0xfd6d: case 0xff6d:
+ case 0xf175: case 0xf375: case 0xf575: case 0xf775: case 0xf975: case 0xfb75: case 0xfd75: case 0xff75:
+ case 0xf17d: case 0xf37d: case 0xf57d: case 0xf77d: case 0xf97d: case 0xfb7d: case 0xfd7d: case 0xff7d:
+ util::stream_format(stream, "nop");
+ return UNSP_DASM_OK;
+
+ // these are in code that otherwise seems like ISA1.0 / 1.1 (jak_disf for example) but spec says it's only in ISA 1.2?
+ case 0xf148: case 0xf348: case 0xf548: case 0xf748: case 0xf948: case 0xfb48: case 0xfd48: case 0xff48:
+ util::stream_format(stream, "irq off");
+ return UNSP_DASM_OK;
+
+ case 0xf149: case 0xf349: case 0xf549: case 0xf749: case 0xf949: case 0xfb49: case 0xfd49: case 0xff49:
+ util::stream_format(stream, "irq on");
+ return UNSP_DASM_OK;
+
+ case 0xf14c: case 0xf34c: case 0xf54c: case 0xf74c: case 0xf94c: case 0xfb4c: case 0xfd4c: case 0xff4c:
+ util::stream_format(stream, "fiq off");
+ return UNSP_DASM_OK;
+
+ case 0xf14e: case 0xf34e: case 0xf54e: case 0xf74e: case 0xf94e: case 0xfb4e: case 0xfd4e: case 0xff4e:
+ util::stream_format(stream, "fiq on");
+ return UNSP_DASM_OK;
+
+ default:
+ util::stream_format(stream, "<UNDEFINED>");
+ return UNSP_DASM_OK;
+ }
+
+ return UNSP_DASM_OK;
+}
+
+offs_t unsp_disassembler::disassemble_fxxx_110_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm)
+{
+ uint32_t len = 1;
+ // | | |
+ // signed * signed (size 16,1,2,3,4,5,6,7)
+ // MULS 1 1 1 1* r r r 1* 1 0*s s s r r r (1* = sign bit, 1* = sign bit 0* = upper size bit)
+
+ // MULS ss with upper size bit not set
+ print_muls(stream, op);
+ return UNSP_DASM_OK;
+}
+
+offs_t unsp_disassembler::disassemble_fxxx_111_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm,const data_buffer &opcodes)
+{
+ uint32_t len = 1;
+ // | | |
+ // EXTOP 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 (+16 bit imm)
+ if ((op == 0xffc0) && m_iso >= 20)
+ {
+ return disassemble_extended_group(stream, pc, op, ximm, opcodes);
+ }
+
+ // signed * signed (size 8,9,10,11,12,13,14,15)
+ // MULS 1 1 1 1* r r r 1* 1 1*s s s r r r (1* = sign bit, 1* = sign bit 1* = upper size bit)
+
+ // MULS ss with upper size bit set.
+ print_muls(stream, op);
+ return UNSP_DASM_OK;
+}
+
+
+offs_t unsp_disassembler::disassemble_fxxx_group(std::ostream &stream, offs_t pc, uint16_t op, uint16_t ximm,const data_buffer &opcodes)
+{
+ uint32_t len = 1;
+
+ switch ((op & 0x01c0) >> 6)
+ {
+ case 0x0:
+ return disassemble_fxxx_000_group(stream, pc, op, ximm);
+
+ case 0x1:
+ return disassemble_fxxx_001_group(stream, pc, op, ximm);
+
+ case 0x2:
+ return disassemble_fxxx_010_group(stream, pc, op, ximm);
+
+ case 0x3:
+ return disassemble_fxxx_011_group(stream, pc, op, ximm);
+
+ case 0x4:
+ return disassemble_fxxx_100_group(stream, pc, op, ximm);
+
+ case 0x5:
+ return disassemble_fxxx_101_group(stream, pc, op, ximm);
+
+ case 0x6:
+ return disassemble_fxxx_110_group(stream, pc, op, ximm);
+
+ case 0x7:
+ return disassemble_fxxx_111_group(stream, pc, op, ximm, opcodes);
+
+ }
+
+ return UNSP_DASM_OK;
+}
diff --git a/src/devices/cpu/unsp/unspdasm_jumps.cpp b/src/devices/cpu/unsp/unspdasm_jumps.cpp
new file mode 100644
index 00000000000..09c96692285
--- /dev/null
+++ b/src/devices/cpu/unsp/unspdasm_jumps.cpp
@@ -0,0 +1,41 @@
+// license:GPL-2.0+
+// copyright-holders:Segher Boessenkool, David Haywood
+/*****************************************************************************
+
+ SunPlus µ'nSP disassembler
+
+ Copyright 2008-2017 Segher Boessenkool <segher@kernel.crashing.org>
+ Licensed under the terms of the GNU GPL, version 2
+ http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+*****************************************************************************/
+
+#include "emu.h"
+#include "unspdasm.h"
+
+char const* const unsp_disassembler::jumps[] =
+{
+ "jb", "jae", "jge", "jl", "jne", "je", "jpl", "jmi",
+ "jbe", "ja", "jle", "jg", "jvc", "jvs", "jmp", "<inv>"
+};
+
+offs_t unsp_disassembler::disassemble_jumps(std::ostream &stream, offs_t pc, const uint16_t op)
+{
+ uint32_t len = 1;
+ const uint16_t op0 = (op >> 12) & 15;
+ const uint16_t op1 = (op >> 6) & 7;
+ const uint32_t opimm = op & 0x3f;
+
+ if (op1 == 0)
+ {
+ util::stream_format(stream, "%s %04x", jumps[op0], pc + 1 + opimm);
+ return UNSP_DASM_OK;
+ }
+ else if (op1 == 1)
+ {
+ util::stream_format(stream, "%s %04x", jumps[op0], pc + 1 - opimm);
+ return UNSP_DASM_OK;
+ }
+
+ return UNSP_DASM_OK;
+}
diff --git a/src/devices/cpu/unsp/unspdasm_other.cpp b/src/devices/cpu/unsp/unspdasm_other.cpp
new file mode 100644
index 00000000000..b639b97e25c
--- /dev/null
+++ b/src/devices/cpu/unsp/unspdasm_other.cpp
@@ -0,0 +1,235 @@
+// license:GPL-2.0+
+// copyright-holders:Segher Boessenkool, David Haywood
+/*****************************************************************************
+
+ SunPlus µ'nSP disassembler
+
+ Copyright 2008-2017 Segher Boessenkool <segher@kernel.crashing.org>
+ Licensed under the terms of the GNU GPL, version 2
+ http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
+
+*****************************************************************************/
+
+#include "emu.h"
+#include "unspdasm.h"
+
+offs_t unsp_disassembler::disassemble_remaining(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer& opcodes)
+{
+ uint32_t len = 1;
+ uint8_t op0 = (op >> 12);
+ uint8_t opA = (op >> 9) & 7;
+ uint8_t op1 = (op >> 6) & 7;
+ uint8_t opN = (op >> 3) & 7;
+ uint8_t opB = op & 7;
+ uint8_t opimm = op & 63;
+
+ switch ((op1 << 4) | op0)
+ {
+ case 0x05: case 0x15: case 0x25: case 0x35:
+ case 0x45: case 0x55: case 0x65: case 0x75:
+ case 0x85: case 0x95: case 0xa5: case 0xb5:
+ case 0xc5: case 0xd5:
+ case 0x07: case 0x17: case 0x27: case 0x37:
+ case 0x47: case 0x57: case 0x67: case 0x77:
+ case 0x87: case 0x97: case 0xa7: case 0xb7:
+ case 0xc7: case 0xd7:
+ case 0x1d: case 0x5d: case 0x6d:
+ case 0x20: case 0x21: case 0x22: case 0x23:
+ case 0x24: case 0x26: case 0x28: case 0x2a:
+ case 0x2b: case 0x2c:
+ util::stream_format(stream, "<BAD>");
+ return UNSP_DASM_OK;
+
+
+ // alu, base+displacement
+ case 0x00: case 0x01: case 0x02: case 0x03:
+ case 0x04: case 0x06: case 0x08: case 0x09:
+ case 0x0a: case 0x0b: case 0x0c:
+ print_alu_op_start(stream, op0, opA);
+ util::stream_format(stream, "[bp+%02x]", opimm);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+ case 0x0d:
+ util::stream_format(stream, "[bp+%02x] = %s", opimm, regs[opA]);
+ return UNSP_DASM_OK;
+
+
+ // alu, 6-bit immediate
+ case 0x10: case 0x11: case 0x12: case 0x13:
+ case 0x14: case 0x16: case 0x18: case 0x19:
+ case 0x1a: case 0x1b: case 0x1c:
+ print_alu_op_start(stream, op0, opA);
+ util::stream_format(stream, "%02x", opimm);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+
+
+ // pop insns
+ case 0x29:
+ if (op == 0x9a90)
+ util::stream_format(stream, "retf");
+ else if (op == 0x9a98)
+ util::stream_format(stream, "reti");
+ else if (opA + 1 < 8 && opA + opN < 8)
+ util::stream_format(stream, "pop %s, %s from [%s]",
+ regs[opA + 1], regs[opA + opN], regs[opB]);
+ else
+ util::stream_format(stream, "<BAD>");
+ return UNSP_DASM_OK;
+
+
+ // push insns
+ case 0x2d:
+ if (opA + 1 >= opN && opA < opN + 7)
+ util::stream_format(stream, "push %s, %s to [%s]",
+ regs[opA + 1 - opN], regs[opA], regs[opB]);
+ else
+ util::stream_format(stream, "<BAD>");
+ return UNSP_DASM_OK;
+
+
+ // alu, indirect memory
+ case 0x30: case 0x31: case 0x32: case 0x33:
+ case 0x34: case 0x36: case 0x38: case 0x39:
+ case 0x3a: case 0x3b: case 0x3c:
+ print_alu_op_start(stream, op0, opA);
+ print_indirect_op(stream, opN, opB);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+ case 0x3d:
+ print_indirect_op(stream, opN, opB);
+ util::stream_format(stream, " = %s", regs[opA]);
+ return UNSP_DASM_OK;
+
+
+ case 0x40: case 0x41: case 0x42: case 0x43:
+ case 0x44: case 0x46: case 0x48: case 0x49:
+ case 0x4a: case 0x4b: case 0x4c:
+ switch (opN)
+ {
+ // alu, register
+ case 0:
+ print_alu_op_start(stream, op0, opA);
+ util::stream_format(stream, "%s", regs[opB]);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+
+ // alu, 16-bit immediate
+ case 1:
+ if ((op0 == 4 || op0 == 12 || op0 == 6 || op0 == 9) && opA != opB)
+ {
+ util::stream_format(stream, "<BAD>");
+ return UNSP_DASM_OK;
+ }
+ if (op0 != 4 && op0 != 12)
+ util::stream_format(stream, "%s = ", regs[opA]);
+ print_alu_op3(stream, op0, opB);
+ len = 2;
+ util::stream_format(stream, "%04x", ximm);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+
+ // alu, direct memory
+ case 2:
+ if ((op0 == 4 || op0 == 12 || op0 == 6 || op0 == 9) && opA != opB)
+ {
+ util::stream_format(stream, "<BAD>");
+ return UNSP_DASM_OK;
+ }
+ if (op0 != 4 && op0 != 12)
+ util::stream_format(stream, "%s = ", regs[opA]);
+ print_alu_op3(stream, op0, opB);
+ len = 2;
+ util::stream_format(stream, "[%04x]", ximm);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+
+ // alu, direct memory
+ case 3:
+ if (op0 == 4 || op0 == 12)
+ {
+ util::stream_format(stream, "<BAD>");
+ return UNSP_DASM_OK;
+ }
+ if ((op0 == 6 || op0 == 9) && opA != opB)
+ {
+ util::stream_format(stream, "<BAD>");
+ return UNSP_DASM_OK;
+ }
+ len = 2;
+ util::stream_format(stream, "[%04x] = ", ximm);
+ print_alu_op3(stream, op0, opB);
+ util::stream_format(stream, "%s", regs[opA]);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+
+ // alu, with shift
+ default:
+ print_alu_op_start(stream, op0, opA);
+ util::stream_format(stream, "%s asr %x", regs[opB], (opN & 3) + 1);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+ }
+
+ case 0x4d:
+ switch (opN)
+ {
+ // alu, direct memory
+ case 3:
+ if (opA != opB)
+ {
+ util::stream_format(stream, "<BAD>");
+ return UNSP_DASM_OK;
+ }
+ len = 2;
+ util::stream_format(stream, "[%04x] = %s", ximm, regs[opB]);
+ return UNSP_DASM_OK;
+ default:
+ util::stream_format(stream, "<BAD>");
+ return UNSP_DASM_OK;
+ }
+
+
+ // alu, with shift
+ case 0x50: case 0x51: case 0x52: case 0x53:
+ case 0x54: case 0x56: case 0x58: case 0x59:
+ case 0x5a: case 0x5b: case 0x5c:
+ print_alu_op_start(stream, op0, opA);
+ if ((opN & 4) == 0)
+ util::stream_format(stream, "%s lsl %x", regs[opB], (opN & 3) + 1);
+ else
+ util::stream_format(stream, "%s lsr %x", regs[opB], (opN & 3) + 1);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+
+
+ // alu, with shift
+ case 0x60: case 0x61: case 0x62: case 0x63:
+ case 0x64: case 0x66: case 0x68: case 0x69:
+ case 0x6a: case 0x6b: case 0x6c:
+ print_alu_op_start(stream, op0, opA);
+ if ((opN & 4) == 0)
+ util::stream_format(stream, "%s rol %x", regs[opB], (opN & 3) + 1);
+ else
+ util::stream_format(stream, "%s ror %x", regs[opB], (opN & 3) + 1);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+
+
+ // alu, direct memory
+ case 0x70: case 0x71: case 0x72: case 0x73:
+ case 0x74: case 0x76: case 0x78: case 0x79:
+ case 0x7a: case 0x7b: case 0x7c:
+ print_alu_op_start(stream, op0, opA);
+ util::stream_format(stream, "[%02x]", opimm);
+ print_alu_op_end(stream, op0);
+ return UNSP_DASM_OK;
+ case 0x7d:
+ util::stream_format(stream, "[%02x] = %s", opimm, regs[opA]);
+ return UNSP_DASM_OK;
+
+ default:
+ util::stream_format(stream, "<UNHANDLED>");
+ return UNSP_DASM_OK;
+ }
+}
diff --git a/src/devices/cpu/unsp/unspdrc.cpp b/src/devices/cpu/unsp/unspdrc.cpp
index f2f8f409ee8..a34d20f8a7e 100644
--- a/src/devices/cpu/unsp/unspdrc.cpp
+++ b/src/devices/cpu/unsp/unspdrc.cpp
@@ -677,18 +677,6 @@ void unsp_device::generate_update_nz(drcuml_block &block)
single opcode
------------------------------------------------------------------*/
-bool unsp_device::generate_f_group_opcode(drcuml_block& block, compiler_state& compiler, const opcode_desc* desc)
-{
- return false;
-}
-
-bool unsp_newer_device::generate_f_group_opcode(drcuml_block& block, compiler_state& compiler, const opcode_desc* desc)
-{
- // TODO: handle the extended opcodes
- return true;
-}
-
-
bool unsp_device::generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
{
uint32_t op = (uint32_t)desc->opptr.w[0];
@@ -1310,9 +1298,6 @@ bool unsp_device::generate_opcode(drcuml_block &block, compiler_state &compiler,
UML_CALLH(block, *m_mem_write);
return true;
- case 0x0f: // Extended
- return generate_f_group_opcode(block, compiler, desc);
-
default:
return false;
}
diff --git a/src/devices/machine/sunplus_gcm394.cpp b/src/devices/machine/sunplus_gcm394.cpp
index 74b5774bf13..d73ac892aa1 100644
--- a/src/devices/machine/sunplus_gcm394.cpp
+++ b/src/devices/machine/sunplus_gcm394.cpp
@@ -18,19 +18,70 @@ sunplus_gcm394_device::sunplus_gcm394_device(const machine_config &mconfig, cons
READ16_MEMBER(sunplus_gcm394_base_device::unk_r)
{
+ switch (offset)
+ {
+
+ case 0x80f:
+ logerror("%s:sunplus_gcm394_base_device::unk_r @ 0x%04x\n", machine().describe_context(), offset + 0x7000);
+ return 0x0002;
+
+ case 0x8fb:
+ logerror("%s:sunplus_gcm394_base_device::unk_r @ 0x%04x\n", machine().describe_context(), offset + 0x7000);
+ m_78fb ^= 0x0100; // status flag for something?
+ return m_78fb;
+
+ case 0xabf:
+ logerror("%s:sunplus_gcm394_base_device::unk_r @ 0x%04x\n", machine().describe_context(), offset + 0x7000);
+ return 0x0001;
+
+ }
+
logerror("%s:sunplus_gcm394_base_device::unk_r @ 0x%04x\n", machine().describe_context(), offset + 0x7000);
- return 0x00;
+ return 0x0000;
}
WRITE16_MEMBER(sunplus_gcm394_base_device::unk_w)
{
- logerror("%s:sunplus_gcm394_base_device::unk_w @ 0x%04x (data 0x%04x)\n", machine().describe_context(), offset + 0x7000, data);
+
+ switch (offset)
+ {
+
+ case 0xa80:
+ case 0xa81:
+ case 0xa82:
+ case 0xa83:
+ case 0xa84:
+ case 0xa85:
+ case 0xa86:
+ m_dma_params[offset - 0xa80] = data;
+ break;
+
+ case 0xabf:
+ logerror("%s:possible DMA operation @ 0x%04x (trigger %04x) with params unk:%04x unk:%04x source:%04x length:%04x unk:%04x unk:%04x unk:%04x\n", machine().describe_context(), offset + 0x7000, data, m_dma_params[0], m_dma_params[1], m_dma_params[2], m_dma_params[3], m_dma_params[4], m_dma_params[5], m_dma_params[6]);
+ break;
+
+ default:
+ logerror("%s:sunplus_gcm394_base_device::unk_w @ 0x%04x (data 0x%04x)\n", machine().describe_context(), offset + 0x7000, data);
+ break;
+ }
}
void sunplus_gcm394_base_device::map(address_map &map)
{
map(0x000000, 0x006fff).ram();
map(0x007000, 0x007fff).rw(FUNC(sunplus_gcm394_base_device::unk_r), FUNC(sunplus_gcm394_base_device::unk_w));
+
+ map(0x007300, 0x0073ff).ram();
+ map(0x007400, 0x0074ff).ram();
+ map(0x007500, 0x0075ff).ram();
+ map(0x007600, 0x0076ff).ram();
+ map(0x007700, 0x0077ff).ram();
+
+ map(0x007c00, 0x007cff).ram();
+ map(0x007d00, 0x007dff).ram();
+ map(0x007e00, 0x007eff).ram();
+ map(0x007f00, 0x007fff).ram();
+
}
void sunplus_gcm394_base_device::device_start()
@@ -39,6 +90,12 @@ void sunplus_gcm394_base_device::device_start()
void sunplus_gcm394_base_device::device_reset()
{
+ m_78fb = 0x0000;
+
+ for (int i = 0; i < 7; i++)
+ {
+ m_dma_params[i] = 0x0000;
+ }
}
void sunplus_gcm394_device::device_add_mconfig(machine_config &config)
diff --git a/src/devices/machine/sunplus_gcm394.h b/src/devices/machine/sunplus_gcm394.h
index 9da9db77a5e..8aee6d07847 100644
--- a/src/devices/machine/sunplus_gcm394.h
+++ b/src/devices/machine/sunplus_gcm394.h
@@ -38,6 +38,9 @@ protected:
required_device<unsp_device> m_cpu;
required_device<screen_device> m_screen;
+ uint16_t m_78fb;
+ uint16_t m_dma_params[7];
+
private:
DECLARE_READ16_MEMBER(unk_r);
DECLARE_WRITE16_MEMBER(unk_w);
diff --git a/src/mame/drivers/clickstart.cpp b/src/mame/drivers/clickstart.cpp
index d880e901af7..bc2e948d9dc 100644
--- a/src/mame/drivers/clickstart.cpp
+++ b/src/mame/drivers/clickstart.cpp
@@ -5,8 +5,8 @@
Leapfrog Clickstart Emulation
Die markings show "SunPlus QL8041C" ( known as Sunplus SPG2?? )
- The keyboard has a "SunPlus PU6583" MCU under a glob, and the
- mouse optical sensor is a N2163, probably from Agilent.
+ The keyboard has a "SunPlus PU6583" MCU under a glob, and the
+ mouse optical sensor is a N2163, probably from Agilent.
Status:
diff --git a/src/mame/drivers/sunplus_gcm394.cpp b/src/mame/drivers/sunplus_gcm394.cpp
index e8d9ac2e788..4bfafc3225a 100644
--- a/src/mame/drivers/sunplus_gcm394.cpp
+++ b/src/mame/drivers/sunplus_gcm394.cpp
@@ -57,7 +57,7 @@ void gcm394_game_state::base(machine_config &config)
{
GCM394(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen);
- UNSP_NEWER(config, m_maincpu, XTAL(27'000'000));
+ UNSP_12(config, m_maincpu, XTAL(27'000'000));
m_maincpu->set_addrmap(AS_PROGRAM, &gcm394_game_state::mem_map_4m);
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
@@ -99,8 +99,11 @@ void gcm394_game_state::machine_reset()
void gcm394_game_state::mem_map_4m(address_map &map)
{
- map(0x000000, 0x3fffff).bankr("cartbank");
+ map(0x000000, 0x01ffff).bankr("cartbank");
map(0x000000, 0x007fff).m(m_spg, FUNC(sunplus_gcm394_device::map));
+
+ // smartfp really expects the ROM at 0 to map here, so maybe this is how the newer SoC works
+ map(0x020000, 0x3fffff).bankr("cartbank");
}
static INPUT_PORTS_START( gcm394 )