mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
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)
This commit is contained in:
parent
dcfacd8df6
commit
f8656d9246
@ -2159,6 +2159,11 @@ if (CPUS["UNSP"]~=null) then
|
|||||||
files {
|
files {
|
||||||
MAME_DIR .. "src/devices/cpu/unsp/unsp.cpp",
|
MAME_DIR .. "src/devices/cpu/unsp/unsp.cpp",
|
||||||
MAME_DIR .. "src/devices/cpu/unsp/unsp.h",
|
MAME_DIR .. "src/devices/cpu/unsp/unsp.h",
|
||||||
|
MAME_DIR .. "src/devices/cpu/unsp/unsp_extended.cpp",
|
||||||
|
MAME_DIR .. "src/devices/cpu/unsp/unsp_jumps.cpp",
|
||||||
|
MAME_DIR .. "src/devices/cpu/unsp/unsp_exxx.cpp",
|
||||||
|
MAME_DIR .. "src/devices/cpu/unsp/unsp_fxxx.cpp",
|
||||||
|
MAME_DIR .. "src/devices/cpu/unsp/unsp_other.cpp",
|
||||||
MAME_DIR .. "src/devices/cpu/unsp/unspdefs.h",
|
MAME_DIR .. "src/devices/cpu/unsp/unspdefs.h",
|
||||||
MAME_DIR .. "src/devices/cpu/unsp/unspdrc.cpp",
|
MAME_DIR .. "src/devices/cpu/unsp/unspdrc.cpp",
|
||||||
MAME_DIR .. "src/devices/cpu/unsp/unspfe.cpp",
|
MAME_DIR .. "src/devices/cpu/unsp/unspfe.cpp",
|
||||||
@ -2169,6 +2174,11 @@ end
|
|||||||
if (CPUS["UNSP"]~=null or _OPTIONS["with-tools"]) then
|
if (CPUS["UNSP"]~=null or _OPTIONS["with-tools"]) then
|
||||||
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/unsp/unspdasm.cpp")
|
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/unsp/unspdasm.cpp")
|
||||||
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/unsp/unspdasm.h")
|
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/unsp/unspdasm.h")
|
||||||
|
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/unsp/unspdasm_extended.cpp")
|
||||||
|
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/unsp/unspdasm_jumps.cpp")
|
||||||
|
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/unsp/unspdasm_exxx.cpp")
|
||||||
|
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/unsp/unspdasm_fxxx.cpp")
|
||||||
|
table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/unsp/unspdasm_other.cpp")
|
||||||
end
|
end
|
||||||
|
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// license:GPL-2.0+
|
// license:GPL-2.0+
|
||||||
// copyright-holders:Segher Boessenkool,Ryan Holtz
|
// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
SunPlus µ'nSP emulator
|
SunPlus µ'nSP emulator
|
||||||
@ -10,6 +10,10 @@
|
|||||||
|
|
||||||
Ported to MAME framework by Ryan Holtz
|
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"
|
#include "emu.h"
|
||||||
@ -18,11 +22,12 @@
|
|||||||
|
|
||||||
#include "debugger.h"
|
#include "debugger.h"
|
||||||
|
|
||||||
#include "unspdefs.h"
|
|
||||||
#include "unspdasm.h"
|
#include "unspdasm.h"
|
||||||
|
|
||||||
DEFINE_DEVICE_TYPE(UNSP, unsp_device, "unsp", "SunPlus u'nSP")
|
DEFINE_DEVICE_TYPE(UNSP, unsp_device, "unsp", "SunPlus u'nSP (ISA 1.0)")
|
||||||
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_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 */
|
/* size of the execution code cache */
|
||||||
#define CACHE_SIZE (64 * 1024 * 1024)
|
#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::unsp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||||
: unsp_device(mconfig, UNSP, tag, owner, clock)
|
: unsp_device(mconfig, UNSP, tag, owner, clock)
|
||||||
{
|
{
|
||||||
|
m_iso = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsp_newer_device::unsp_newer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
unsp_11_device::unsp_11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||||
: unsp_device(mconfig, UNSP_NEWER, tag, owner, 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_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
|
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>();
|
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_newer_disassembler>();
|
return std::make_unique<unsp_12_disassembler>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<util::disasm_interface> unsp_20_device::create_disassembler()
|
||||||
|
{
|
||||||
|
return std::make_unique<unsp_12_disassembler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void unsp_device::unimplemented_opcode(uint16_t op)
|
void unsp_device::unimplemented_opcode(uint16_t op)
|
||||||
@ -86,22 +154,16 @@ void unsp_device::unimplemented_opcode(uint16_t op)
|
|||||||
fatalerror("UNSP: unknown opcode %04x at %04x\n", op, UNSP_LPC);
|
fatalerror("UNSP: unknown opcode %04x at %04x\n", op, UNSP_LPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
void unsp_device::unimplemented_opcode(uint16_t op, uint16_t ximm)
|
||||||
|
|
||||||
uint16_t unsp_device::read16(uint32_t address)
|
|
||||||
{
|
{
|
||||||
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)
|
|
||||||
{
|
|
||||||
#if UNSP_LOG_REGS
|
|
||||||
log_write(address, data);
|
|
||||||
#endif
|
|
||||||
m_program->write_word(address, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
void unsp_device::unimplemented_opcode(uint16_t op, uint16_t ximm, uint16_t ximm_2)
|
||||||
|
{
|
||||||
|
fatalerror("UNSP: unknown opcode %04x %04x %04x at %04x\n", op, ximm, ximm_2, UNSP_LPC);
|
||||||
|
}
|
||||||
|
|
||||||
void unsp_device::device_start()
|
void unsp_device::device_start()
|
||||||
{
|
{
|
||||||
@ -109,7 +171,7 @@ void unsp_device::device_start()
|
|||||||
memset(m_core, 0, sizeof(internal_unsp_state));
|
memset(m_core, 0, sizeof(internal_unsp_state));
|
||||||
|
|
||||||
#if ENABLE_UNSP_DRC
|
#if ENABLE_UNSP_DRC
|
||||||
m_enable_drc = allow_drc();
|
m_enable_drc = allow_drc() && (m_iso < 12);
|
||||||
#else
|
#else
|
||||||
m_enable_drc = false;
|
m_enable_drc = false;
|
||||||
#endif
|
#endif
|
||||||
@ -306,7 +368,7 @@ uint16_t unsp_device::pop(uint32_t *reg)
|
|||||||
return (uint16_t)read16(*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)
|
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;
|
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)
|
if (!m_core->m_enable_irq || m_core->m_irq || m_core->m_fiq)
|
||||||
return;
|
return;
|
||||||
@ -361,631 +423,23 @@ void unsp_device::check_irqs()
|
|||||||
trigger_irq(highest_irq - 1);
|
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)
|
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 op0 = (op >> 12) & 15;
|
||||||
const uint16_t opa = (op >> 9) & 7;
|
const uint16_t opa = (op >> 9) & 7;
|
||||||
const uint16_t op1 = (op >> 6) & 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)
|
if(op0 < 0xf && opa == 0x7 && op1 < 2)
|
||||||
{
|
return execute_jumps(op);
|
||||||
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;
|
|
||||||
|
|
||||||
while (r0--)
|
if (op0 == 0xe)
|
||||||
{
|
return execute_exxx_group(op);
|
||||||
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)
|
execute_remaining(op);
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void unsp_device::execute_run()
|
void unsp_device::execute_run()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// license:GPL-2.0+
|
// license:GPL-2.0+
|
||||||
// copyright-holders:Segher Boessenkool,Ryan Holtz
|
// copyright-holders:Segher Boessenkool, Ryan Holtz, David Haywood
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
SunPlus µ'nSP emulator
|
SunPlus µ'nSP emulator
|
||||||
@ -20,6 +20,7 @@
|
|||||||
#include "cpu/drcfe.h"
|
#include "cpu/drcfe.h"
|
||||||
#include "cpu/drcuml.h"
|
#include "cpu/drcuml.h"
|
||||||
#include "cpu/drcumlsh.h"
|
#include "cpu/drcumlsh.h"
|
||||||
|
#include "unspdefs.h"
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
CONSTANTS
|
CONSTANTS
|
||||||
@ -91,7 +92,7 @@ class unsp_device : public cpu_device
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// construction/destruction
|
// 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);
|
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.
|
// 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;
|
virtual space_config_vector memory_space_config() const override;
|
||||||
|
|
||||||
// device_state_interface overrides
|
// device_state_interface overrides
|
||||||
virtual void state_import(const device_state_entry &entry) override;
|
virtual void state_import(const device_state_entry& entry) override;
|
||||||
virtual void state_export(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_string_export(const device_state_entry& entry, std::string& str) const override;
|
||||||
|
|
||||||
// device_disasm_interface overrides
|
// device_disasm_interface overrides
|
||||||
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
|
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
|
||||||
@ -154,8 +155,8 @@ protected:
|
|||||||
/* internal compiler state */
|
/* internal compiler state */
|
||||||
struct compiler_state
|
struct compiler_state
|
||||||
{
|
{
|
||||||
compiler_state(compiler_state const &) = delete;
|
compiler_state(compiler_state const&) = delete;
|
||||||
compiler_state &operator=(compiler_state const &) = delete;
|
compiler_state& operator=(compiler_state const&) = delete;
|
||||||
|
|
||||||
uint32_t m_cycles; /* accumulated cycles */
|
uint32_t m_cycles; /* accumulated cycles */
|
||||||
uml::code_label m_labelnum; /* index for local labels */
|
uml::code_label m_labelnum; /* index for local labels */
|
||||||
@ -181,7 +182,53 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* core state */
|
/* 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:
|
private:
|
||||||
// compilation boundaries -- how far back/forward does the analysis extend?
|
// compilation boundaries -- how far back/forward does the analysis extend?
|
||||||
@ -202,10 +249,12 @@ private:
|
|||||||
EXECUTE_RESET_CACHE = 3
|
EXECUTE_RESET_CACHE = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
void add_lpc(const int32_t offset);
|
|
||||||
|
|
||||||
virtual void execute_f_group(const uint16_t op);
|
void execute_jumps(const uint16_t op);
|
||||||
inline void execute_one(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_config m_program_config;
|
||||||
address_space *m_program;
|
address_space *m_program;
|
||||||
@ -217,16 +266,11 @@ private:
|
|||||||
uint32_t m_log_ops;
|
uint32_t m_log_ops;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void unimplemented_opcode(uint16_t op);
|
void update_nz(uint32_t value);
|
||||||
inline uint16_t read16(uint32_t address);
|
void update_nzsc(uint32_t value, uint16_t r0, uint16_t r1);
|
||||||
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);
|
|
||||||
inline void trigger_fiq();
|
inline void trigger_fiq();
|
||||||
inline void trigger_irq(int line);
|
inline void trigger_irq(int line);
|
||||||
inline void check_irqs();
|
void check_irqs();
|
||||||
|
|
||||||
drc_cache m_cache;
|
drc_cache m_cache;
|
||||||
std::unique_ptr<drcuml_state> m_drcuml;
|
std::unique_ptr<drcuml_state> m_drcuml;
|
||||||
@ -247,8 +291,6 @@ private:
|
|||||||
|
|
||||||
bool m_enable_drc;
|
bool m_enable_drc;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void execute_run_drc();
|
void execute_run_drc();
|
||||||
void flush_drc_cache();
|
void flush_drc_cache();
|
||||||
void code_flush_cache();
|
void code_flush_cache();
|
||||||
@ -272,7 +314,6 @@ private:
|
|||||||
void generate_update_nzsc(drcuml_block &block);
|
void generate_update_nzsc(drcuml_block &block);
|
||||||
void generate_update_nz(drcuml_block &block);
|
void generate_update_nz(drcuml_block &block);
|
||||||
void log_add_disasm_comment(drcuml_block &block, uint32_t pc, uint32_t op);
|
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);
|
bool generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc);
|
||||||
|
|
||||||
#if UNSP_LOG_REGS
|
#if UNSP_LOG_REGS
|
||||||
@ -280,20 +321,50 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class unsp_newer_device : public unsp_device
|
|
||||||
|
class unsp_11_device : public unsp_device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// construction/destruction
|
// construction/destruction
|
||||||
unsp_newer_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
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_20_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
|
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
|
||||||
virtual void execute_f_group(const uint16_t op) override;
|
virtual void execute_extended_group(uint16_t op) override;
|
||||||
virtual bool generate_f_group_opcode(drcuml_block& block, compiler_state& compiler, const opcode_desc* desc) override;
|
|
||||||
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DECLARE_DEVICE_TYPE(UNSP, unsp_device)
|
DECLARE_DEVICE_TYPE(UNSP, unsp_device)
|
||||||
DECLARE_DEVICE_TYPE(UNSP_NEWER, unsp_newer_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
|
#endif // MAME_CPU_UNSP_UNSP_H
|
||||||
|
206
src/devices/cpu/unsp/unsp_extended.cpp
Normal file
206
src/devices/cpu/unsp/unsp_extended.cpp
Normal file
@ -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;
|
||||||
|
}
|
161
src/devices/cpu/unsp/unsp_exxx.cpp
Normal file
161
src/devices/cpu/unsp/unsp_exxx.cpp
Normal file
@ -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;
|
||||||
|
}
|
431
src/devices/cpu/unsp/unsp_fxxx.cpp
Normal file
431
src/devices/cpu/unsp/unsp_fxxx.cpp
Normal file
@ -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;
|
||||||
|
}
|
160
src/devices/cpu/unsp/unsp_jumps.cpp
Normal file
160
src/devices/cpu/unsp/unsp_jumps.cpp
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
347
src/devices/cpu/unsp/unsp_other.cpp
Normal file
347
src/devices/cpu/unsp/unsp_other.cpp
Normal file
@ -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;
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
// license:GPL-2.0+
|
// license:GPL-2.0+
|
||||||
// copyright-holders:Segher Boessenkool
|
// copyright-holders:Segher Boessenkool, David Haywood
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
SunPlus µ'nSP disassembler
|
SunPlus µ'nSP disassembler
|
||||||
@ -13,18 +13,42 @@
|
|||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
#include "unspdasm.h"
|
#include "unspdasm.h"
|
||||||
|
|
||||||
char const *const unsp_disassembler::regs[] =
|
char const* const unsp_disassembler::regs[] =
|
||||||
{
|
{
|
||||||
"sp", "r1", "r2", "r3", "r4", "bp", "sr", "pc"
|
"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",
|
"tstb", "setb", "clrb", "invb"
|
||||||
"jbe", "ja", "jle", "jg", "jvc", "jvs", "jmp", "<inv>"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#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
|
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]);
|
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)
|
void unsp_disassembler::print_alu_op_end(std::ostream &stream, uint8_t op0)
|
||||||
{
|
{
|
||||||
if (op0 == 1 || op0 == 3)
|
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)
|
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)
|
if (opN & 4)
|
||||||
util::stream_format(stream, "ds:");
|
util::stream_format(stream, "ds:");
|
||||||
util::stream_format(stream, forms[opN & 3], regs[opB]);
|
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)
|
|
||||||
|
|
||||||
|
offs_t unsp_disassembler::disassemble_code(std::ostream &stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer &opcodes)
|
||||||
{
|
{
|
||||||
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)
|
|
||||||
{
|
|
||||||
// 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;
|
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:
|
// all-zero and all-one are invalid insns:
|
||||||
if (op == 0 || op == 0xffff)
|
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;
|
return UNSP_DASM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first, check for the conditional branch insns
|
uint8_t op0 = (op >> 12);
|
||||||
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)
|
if (op0 == 0xf)
|
||||||
{
|
return disassemble_fxxx_group(stream, pc, op, ximm, opcodes);
|
||||||
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;
|
|
||||||
|
|
||||||
|
uint8_t opA = (op >> 9) & 7;
|
||||||
|
uint8_t op1 = (op >> 6) & 7;
|
||||||
|
|
||||||
// alu, base+displacement
|
if (op0 < 15 && opA == 7 && op1 < 2)
|
||||||
case 0x00: case 0x01: case 0x02: case 0x03:
|
return disassemble_jumps(stream, pc, op);
|
||||||
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;
|
|
||||||
|
|
||||||
|
if (op0 == 0xe)
|
||||||
|
return disassemble_exxx_group(stream, pc, op, ximm);
|
||||||
|
|
||||||
// alu, 6-bit immediate
|
return disassemble_remaining(stream, pc, op, ximm, opcodes);
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
|
||||||
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 ¶ms)
|
offs_t unsp_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms)
|
||||||
{
|
{
|
||||||
uint16_t op = opcodes.r16(pc);
|
uint16_t op = opcodes.r16(pc);
|
||||||
uint16_t imm16 = opcodes.r16(pc+1);
|
uint16_t imm16 = opcodes.r16(pc+1);
|
||||||
|
|
||||||
return disassemble(stream, pc, op, imm16);
|
return disassemble_code(stream, pc, op, imm16, opcodes);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// license:GPL-2.0
|
// license:GPL-2.0
|
||||||
// copyright-holders:Segher Boessenkool
|
// copyright-holders:Segher Boessenkool, David Haywood
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
SunPlus µ'nSP disassembler
|
SunPlus µ'nSP disassembler
|
||||||
@ -15,39 +15,88 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define UNSP_DASM_OK (len | SUPPORTED)
|
||||||
|
|
||||||
class unsp_disassembler : public util::disasm_interface
|
class unsp_disassembler : public util::disasm_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
unsp_disassembler() = default;
|
unsp_disassembler()
|
||||||
|
{
|
||||||
|
m_iso = 10;
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~unsp_disassembler() = default;
|
virtual ~unsp_disassembler() = default;
|
||||||
|
|
||||||
virtual u32 opcode_alignment() const override;
|
virtual u32 opcode_alignment() const override;
|
||||||
virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) override;
|
virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms) 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:
|
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 regs[];
|
||||||
|
static char const *const extregs[];
|
||||||
static char const *const jumps[];
|
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_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_op3(std::ostream &stream, uint8_t op0, uint8_t opB);
|
||||||
void print_alu_op_end(std::ostream &stream, uint8_t op0);
|
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_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:
|
public:
|
||||||
unsp_newer_disassembler() = default;
|
unsp_12_disassembler()
|
||||||
virtual ~unsp_newer_disassembler() = default;
|
{
|
||||||
|
m_iso = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~unsp_12_disassembler() = default;
|
||||||
|
|
||||||
private:
|
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_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_extended_group(std::ostream& stream, offs_t pc, uint16_t op, uint16_t ximm, const data_buffer& opcodes) override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
193
src/devices/cpu/unsp/unspdasm_extended.cpp
Normal file
193
src/devices/cpu/unsp/unspdasm_extended.cpp
Normal file
@ -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;
|
||||||
|
}
|
117
src/devices/cpu/unsp/unspdasm_exxx.cpp
Normal file
117
src/devices/cpu/unsp/unspdasm_exxx.cpp
Normal file
@ -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;
|
||||||
|
}
|
371
src/devices/cpu/unsp/unspdasm_fxxx.cpp
Normal file
371
src/devices/cpu/unsp/unspdasm_fxxx.cpp
Normal file
@ -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;
|
||||||
|
}
|
41
src/devices/cpu/unsp/unspdasm_jumps.cpp
Normal file
41
src/devices/cpu/unsp/unspdasm_jumps.cpp
Normal file
@ -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;
|
||||||
|
}
|
235
src/devices/cpu/unsp/unspdasm_other.cpp
Normal file
235
src/devices/cpu/unsp/unspdasm_other.cpp
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -677,18 +677,6 @@ void unsp_device::generate_update_nz(drcuml_block &block)
|
|||||||
single opcode
|
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)
|
bool unsp_device::generate_opcode(drcuml_block &block, compiler_state &compiler, const opcode_desc *desc)
|
||||||
{
|
{
|
||||||
uint32_t op = (uint32_t)desc->opptr.w[0];
|
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);
|
UML_CALLH(block, *m_mem_write);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case 0x0f: // Extended
|
|
||||||
return generate_f_group_opcode(block, compiler, desc);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -18,19 +18,70 @@ sunplus_gcm394_device::sunplus_gcm394_device(const machine_config &mconfig, cons
|
|||||||
|
|
||||||
READ16_MEMBER(sunplus_gcm394_base_device::unk_r)
|
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);
|
logerror("%s:sunplus_gcm394_base_device::unk_r @ 0x%04x\n", machine().describe_context(), offset + 0x7000);
|
||||||
return 0x00;
|
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 0x0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
WRITE16_MEMBER(sunplus_gcm394_base_device::unk_w)
|
WRITE16_MEMBER(sunplus_gcm394_base_device::unk_w)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
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);
|
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)
|
void sunplus_gcm394_base_device::map(address_map &map)
|
||||||
{
|
{
|
||||||
map(0x000000, 0x006fff).ram();
|
map(0x000000, 0x006fff).ram();
|
||||||
map(0x007000, 0x007fff).rw(FUNC(sunplus_gcm394_base_device::unk_r), FUNC(sunplus_gcm394_base_device::unk_w));
|
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()
|
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()
|
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)
|
void sunplus_gcm394_device::device_add_mconfig(machine_config &config)
|
||||||
|
@ -38,6 +38,9 @@ protected:
|
|||||||
required_device<unsp_device> m_cpu;
|
required_device<unsp_device> m_cpu;
|
||||||
required_device<screen_device> m_screen;
|
required_device<screen_device> m_screen;
|
||||||
|
|
||||||
|
uint16_t m_78fb;
|
||||||
|
uint16_t m_dma_params[7];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_READ16_MEMBER(unk_r);
|
DECLARE_READ16_MEMBER(unk_r);
|
||||||
DECLARE_WRITE16_MEMBER(unk_w);
|
DECLARE_WRITE16_MEMBER(unk_w);
|
||||||
|
@ -57,7 +57,7 @@ void gcm394_game_state::base(machine_config &config)
|
|||||||
{
|
{
|
||||||
GCM394(config, m_spg, XTAL(27'000'000), m_maincpu, m_screen);
|
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);
|
m_maincpu->set_addrmap(AS_PROGRAM, &gcm394_game_state::mem_map_4m);
|
||||||
|
|
||||||
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
|
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)
|
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));
|
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 )
|
static INPUT_PORTS_START( gcm394 )
|
||||||
|
Loading…
Reference in New Issue
Block a user