summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/score/score.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/score/score.cpp')
-rw-r--r--src/devices/cpu/score/score.cpp1351
1 files changed, 1351 insertions, 0 deletions
diff --git a/src/devices/cpu/score/score.cpp b/src/devices/cpu/score/score.cpp
new file mode 100644
index 00000000000..a8e3dd210fc
--- /dev/null
+++ b/src/devices/cpu/score/score.cpp
@@ -0,0 +1,1351 @@
+// license:BSD-3-Clause
+// copyright-holders:Sandro Ronco
+/******************************************************************************
+
+ Sunplus Technology S+core
+ by Sandro Ronco
+
+******************************************************************************/
+
+#include "emu.h"
+#include "debugger.h"
+#include "score.h"
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+const device_type SCORE7 = &device_creator<score7_cpu_device>;
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+#include "scorem.h"
+
+
+//**************************************************************************
+// Opcodes Tables
+//**************************************************************************
+
+const score7_cpu_device::op_handler score7_cpu_device::s_opcode32_table[4*8] =
+{
+ &score7_cpu_device::op_specialform, &score7_cpu_device::op_iform1, &score7_cpu_device::op_jump , &score7_cpu_device::op_rixform1, &score7_cpu_device::op_branch, &score7_cpu_device::op_iform2, &score7_cpu_device::op_crform, &score7_cpu_device::op_rixform2,
+ &score7_cpu_device::op_addri , &score7_cpu_device::op_undef , &score7_cpu_device::op_undef, &score7_cpu_device::op_undef , &score7_cpu_device::op_andri , &score7_cpu_device::op_orri , &score7_cpu_device::op_undef , &score7_cpu_device::op_undef ,
+ &score7_cpu_device::op_lw , &score7_cpu_device::op_lh , &score7_cpu_device::op_lhu , &score7_cpu_device::op_lb , &score7_cpu_device::op_sw , &score7_cpu_device::op_sh , &score7_cpu_device::op_lbu , &score7_cpu_device::op_sb ,
+ &score7_cpu_device::op_cache , &score7_cpu_device::op_undef , &score7_cpu_device::op_undef, &score7_cpu_device::op_undef , &score7_cpu_device::op_cenew , &score7_cpu_device::op_undef , &score7_cpu_device::op_undef , &score7_cpu_device::op_undef
+};
+
+const score7_cpu_device::op_handler score7_cpu_device::s_opcode16_table[8] =
+{
+ &score7_cpu_device::op_rform1, &score7_cpu_device::op_undef, &score7_cpu_device::op_rform2, &score7_cpu_device::op_jform, &score7_cpu_device::op_branch16, &score7_cpu_device::op_ldiu, &score7_cpu_device::op_iform1a, &score7_cpu_device::op_iform1b
+};
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// score7_cpu_device - constructor
+//-------------------------------------------------
+
+score7_cpu_device::score7_cpu_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : cpu_device(mconfig, SCORE7, "S+core 7", tag, owner, clock, "score7", __FILE__),
+ m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0),
+ m_pc(0),
+ m_ppc(0)
+{
+ memset(m_gpr, 0x00, sizeof(m_gpr));
+ memset(m_cr, 0x00, sizeof(m_cr));
+ memset(m_sr, 0x00, sizeof(m_sr));
+ memset(m_ce, 0x00, sizeof(m_ce));
+}
+
+//-------------------------------------------------
+// device_start - start up the device
+//-------------------------------------------------
+
+void score7_cpu_device::device_start()
+{
+ // find address spaces
+ m_program = &space(AS_PROGRAM);
+ m_direct = &m_program->direct();
+
+ // set our instruction counter
+ m_icountptr = &m_icount;
+
+ // register state for debugger
+ state_add(SCORE_PC , "PC" , m_pc).callimport().callexport().formatstr("%08X");
+
+ std::string tmp_string;
+
+ for(int i=0; i<0x20; i++)
+ state_add(SCORE_GPR + i, strformat(tmp_string, "r%d", i).c_str(), m_gpr[i]).callimport().callexport().formatstr("%08X");
+
+ for(int i=0; i<0x20; i++)
+ state_add(SCORE_CR + i, strformat(tmp_string, "cr%d", i).c_str(), m_cr[i]).callimport().callexport().formatstr("%08X");
+
+ for(int i=0; i<3; i++)
+ state_add(SCORE_SR + i, strformat(tmp_string, "sr%d", i).c_str(), m_sr[i]).callimport().callexport().formatstr("%08X");
+
+ state_add(SCORE_CEH, "ceh", REG_CEH).callimport().callexport().formatstr("%08X");
+ state_add(SCORE_CEL, "cel", REG_CEL).callimport().callexport().formatstr("%08X");
+
+ state_add(STATE_GENPC, "curpc", m_pc).callimport().callexport().formatstr("%08X").noshow();
+ state_add(STATE_GENPCBASE, "curpcbase", m_ppc).callimport().callexport().formatstr("%8X").noshow();
+ state_add(STATE_GENFLAGS, "GENFLAGS", m_ppc).formatstr("%5s").noshow();
+
+ // save state
+ save_item(NAME(m_pc));
+ save_item(NAME(m_ppc));
+ save_item(NAME(m_op));
+ save_item(NAME(m_gpr));
+ save_item(NAME(m_cr));
+ save_item(NAME(m_sr));
+ save_item(NAME(m_ce));
+ save_item(NAME(m_pending_interrupt));
+}
+
+
+//-------------------------------------------------
+// device_reset - reset up the device
+//-------------------------------------------------
+
+void score7_cpu_device::device_reset()
+{
+ // GPR are undefined at reset
+ memset(m_gpr,0, sizeof(m_gpr));
+ memset(m_cr, 0, sizeof(m_cr));
+ memset(m_sr, 0, sizeof(m_sr));
+ memset(m_ce, 0, sizeof(m_ce));
+ memset(m_pending_interrupt, 0, sizeof(m_pending_interrupt));
+
+ REG_EXCPVEC = m_pc = 0x9f000000;
+}
+
+
+//-------------------------------------------------
+// state_string_export - export state as a string
+// for the debugger
+//-------------------------------------------------
+
+void score7_cpu_device::state_string_export(const device_state_entry &entry, std::string &str)
+{
+ switch (entry.index())
+ {
+ case STATE_GENFLAGS:
+ strprintf(str, "%s%s%s%s%s",
+ REG_CR & FLAG_V ? "V" : ".",
+ REG_CR & FLAG_C ? "C" : ".",
+ REG_CR & FLAG_Z ? "Z" : ".",
+ REG_CR & FLAG_N ? "N" : ".",
+ REG_CR & FLAG_T ? "T" : "."
+ );
+ break;
+ }
+}
+
+
+//-------------------------------------------------
+// memory_space_config - return the configuration
+// of the specified address space, or NULL if
+// the space doesn't exist
+//-------------------------------------------------
+
+const address_space_config * score7_cpu_device::memory_space_config(address_spacenum spacenum) const
+{
+ return (spacenum == AS_PROGRAM) ? &m_program_config: NULL;
+}
+
+
+//-------------------------------------------------
+// execute - execute for the provided number of
+// cycles
+//-------------------------------------------------
+
+void score7_cpu_device::execute_run()
+{
+ do
+ {
+ debugger_instruction_hook(this, m_pc);
+
+ m_ppc = m_pc;
+
+ check_irq();
+
+ UINT32 op = fetch();
+
+ switch(((op>>30) & 2) | ((op>>15) & 1))
+ {
+ case 0: // 16-bit + 16-bit instruction
+ m_op = ((m_pc & 0x02) ? (op >> 16) : op) & 0x7fff;
+ m_pc += 2;
+ (this->*s_opcode16_table[(m_op >> 12) & 0x07])();
+ break;
+ case 1: // undefined parity bit
+ m_pc += 4;
+ gen_exception(EXCEPTION_P_EL);
+ break;
+ case 2: // parallel conditional execution
+ m_op = (GET_T ? op: (op >> 16)) & 0x7fff;
+ m_pc += 4;
+ (this->*s_opcode16_table[(m_op >> 12) & 0x07])();
+ break;
+ case 3: // 32-bit instruction
+ m_op = (op & 0x7fff) | ((op >> 1) & 0x3fff8000);
+ m_pc += 4;
+ (this->*s_opcode32_table[(m_op >> 25) & 0x01f])();
+ break;
+ }
+
+ m_icount -= 3; // FIXME: if available use correct cycles per instructions
+ }
+ while (m_icount > 0);
+}
+
+
+//-------------------------------------------------
+// execute_set_input
+//-------------------------------------------------
+
+void score7_cpu_device::execute_set_input(int inputnum, int state)
+{
+ switch (inputnum)
+ {
+ case 0:
+ if(state)
+ {
+ int vector = standard_irq_callback(0);
+ if (vector > 0 && vector < 64)
+ {
+ if((REG_PSR & 0x01) && state)
+ m_pending_interrupt[vector] = true;
+ }
+ }
+ break;
+ }
+}
+
+//**************************************************************************
+// HELPERS
+//**************************************************************************
+
+
+bool score7_cpu_device::check_condition_branch(UINT8 bc)
+{
+ if ((bc & 0x0f) == 14) // CNT>0, CNT--
+ {
+ if (REG_CNT > 0)
+ {
+ REG_CNT--;
+ return true;
+ }
+ return false;
+ }
+ else
+ return check_condition(bc);
+}
+
+bool score7_cpu_device::check_condition(UINT8 bc)
+{
+ switch(bc & 0x0f)
+ {
+ case 0: return GET_C; // carry set
+ case 1: return !GET_C; // carry clear
+ case 2: return GET_C && !GET_Z; // C & ~Z
+ case 3: return !GET_C || GET_Z; // ~C | Z
+ case 4: return GET_Z; // Z
+ case 5: return !GET_Z; // ~Z
+ case 6: return !GET_Z && (GET_N == GET_V); // (Z = 0) & (N = V)
+ case 7: return GET_Z || (GET_N != GET_V); // (Z = 1) | (N != V)
+ case 8: return (GET_N == GET_V); // N = V
+ case 9: return (GET_N != GET_V); // N != V
+ case 10: return GET_N; // N
+ case 11: return !GET_N; // ~N
+ case 12: return GET_V; // overflow V
+ case 13: return !GET_V; // no overflow ~V
+ case 14: return REG_CNT > 0; // CNT>0
+ case 15: return true; // always
+ }
+
+ return false;
+}
+
+INT32 score7_cpu_device::sign_extend(UINT32 data, UINT8 len)
+{
+ data &= (1 << len) - 1;
+ UINT32 sign = 1 << (len - 1);
+ return (data ^ sign) - sign;
+}
+
+UINT32 score7_cpu_device::fetch()
+{
+ return m_direct->read_dword(m_pc & ~3);
+}
+
+UINT8 score7_cpu_device::read_byte(offs_t offset)
+{
+ return m_program->read_byte(offset);
+}
+
+UINT16 score7_cpu_device::read_word(offs_t offset)
+{
+ return m_program->read_word(offset & ~1);
+}
+
+UINT32 score7_cpu_device::read_dword(offs_t offset)
+{
+ return m_program->read_dword(offset & ~3);
+}
+
+void score7_cpu_device::write_byte(offs_t offset, UINT8 data)
+{
+ m_program->write_byte(offset, data);
+}
+
+void score7_cpu_device::write_word(offs_t offset, UINT16 data)
+{
+ m_program->write_word(offset & ~1, data);
+}
+
+void score7_cpu_device::write_dword(offs_t offset, UINT32 data)
+{
+ m_program->write_dword(offset & ~3, data);
+}
+
+void score7_cpu_device::check_irq()
+{
+ if(REG_PSR & 0x01)
+ {
+ for (int i=63; i>0; i--)
+ {
+ if (m_pending_interrupt[i])
+ {
+ m_pending_interrupt[i] = false;
+ debugger_interrupt_hook(this, i);
+ gen_exception(EXCEPTION_INTERRUPT, i);
+ return;
+ }
+ }
+ }
+}
+
+void score7_cpu_device::gen_exception(int cause, UINT32 param)
+{
+ debugger_exception_hook(this, cause);
+
+ REG_ECR = (REG_ECR & ~0x0000001f) | (cause & 0x1f); // set exception cause
+ REG_PSR = (REG_PSR & ~0x0000000f) | ((REG_PSR << 2) & 0x0c); // push status bits
+ REG_CR = (REG_CR & ~0x000003ff) | ((REG_CR << 5) & 0x3e0); // push flag bits
+ REG_EPC = m_ppc & 0xfffffffe; // set return address
+
+ switch(cause)
+ {
+ case EXCEPTION_P_EL:
+ REG_EMA = REG_EPC;
+ // intentional fallthrough
+ case EXCEPTION_NMI:
+ case EXCEPTION_CEE:
+ case EXCEPTION_SYSCALL:
+ case EXCEPTION_TRAP:
+ case EXCEPTION_RI:
+ m_pc = (REG_EXCPVEC & 0xffff0000) + 0x200;
+ break;
+
+ case EXCEPTION_SWI:
+ case EXCEPTION_INTERRUPT:
+ REG_ECR = (REG_ECR & ~0x00fc0000) | ((param & 0x3f) << 18); // set irq source
+ m_pc = (REG_EXCPVEC & 0xffff0000) + 0x200 + (param << (REG_EXCPVEC & 1 ? 4 : 2));
+ break;
+
+ case EXCEPTION_ADEL_INSTRUCTION:
+ case EXCEPTION_BUSEL_INSTRUCTION:
+ case EXCEPTION_CCU:
+ case EXCEPTION_ADEL_DATA:
+ case EXCEPTION_ADES_DATA:
+ case EXCEPTION_CPE:
+ case EXCEPTION_BUSEL_DATA:
+ fatalerror("unhandled exception: %d 0x%08x (PC=0x%08x)\n", cause, param, m_ppc);
+ }
+}
+
+
+//**************************************************************************
+// 32-bit opcodes
+//**************************************************************************
+
+void score7_cpu_device::op_specialform()
+{
+ UINT8 ra = GET_S_RA(m_op);
+ UINT8 rb = GET_S_RB(m_op);
+ UINT8 rd = GET_S_RD(m_op);
+ UINT8 cu = GET_S_CU(m_op);
+ UINT32 r;
+
+ switch(GET_S_FUNC6(m_op))
+ {
+ case 0x00: // nop
+ break;
+ case 0x01: // syscall
+ gen_exception(EXCEPTION_SYSCALL);
+ break;
+ case 0x02: // trap
+ if (check_condition(rb))
+ gen_exception(EXCEPTION_TRAP);
+ break;
+ case 0x03: // sdbbp
+ unemulated_op("sdbbp");
+ break;
+ case 0x04: // br
+ if (check_condition_branch(rb))
+ {
+ if (GET_S_LK(m_op))
+ REG_LNK = m_pc;
+
+ m_pc = m_gpr[ra];
+ }
+ break;
+ case 0x05: // pflush
+ unemulated_op("pflush");
+ break;
+ case 0x08: // add
+ r = m_gpr[ra] + m_gpr[rb];
+ if (cu)
+ {
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_ADD(m_gpr[ra], m_gpr[rb], r);
+ CHECK_C_ADD(m_gpr[ra], m_gpr[rb]);
+ }
+ m_gpr[rd] = r;
+ break;
+ case 0x09: // addc
+ r = m_gpr[ra] + m_gpr[rb] + GET_C;
+ if (cu)
+ {
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_ADD(m_gpr[ra] + GET_C, m_gpr[rb], r);
+ CHECK_C_ADD(m_gpr[ra] + GET_C, m_gpr[rb]);
+ }
+ m_gpr[rd] = r;
+ break;
+ case 0x0a: // sub
+ r = m_gpr[ra] - m_gpr[rb];
+ if (cu)
+ {
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_SUB(m_gpr[ra], m_gpr[rb], r);
+ CHECK_C_SUB(m_gpr[ra], m_gpr[rb]);
+ }
+ m_gpr[rd] = r;
+ break;
+ case 0x0b: // subc
+ r = m_gpr[ra] - m_gpr[rb] - (GET_C ^ 1);
+ if (cu)
+ {
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_SUB(m_gpr[ra] - (GET_C ^ 1), m_gpr[rb], r);
+ CHECK_C_SUB(m_gpr[ra] - (GET_C ^ 1), m_gpr[rb]);
+ }
+ m_gpr[rd] = r;
+ break;
+ case 0x0c: // cmp
+ if (cu)
+ {
+ r = m_gpr[ra] - m_gpr[rb];
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_SUB(m_gpr[ra], m_gpr[rb], r);
+ CHECK_C_SUB(m_gpr[ra], m_gpr[rb]);
+ switch(rd & 0x03)
+ {
+ case 0: SET_T(GET_Z); break;
+ case 1: SET_T(GET_N); break;
+ }
+ }
+ break;
+ case 0x0d: // cmpz
+ if (cu)
+ {
+ r = m_gpr[ra] - 0;
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_SUB(m_gpr[ra], 0, r);
+ CHECK_C_SUB(m_gpr[ra], 0);
+ switch(rd & 0x03)
+ {
+ case 0: SET_T(GET_Z); break;
+ case 1: SET_T(GET_N); break;
+ }
+ }
+ break;
+ case 0x0f: // neg
+ r = 0 - m_gpr[rb];
+ if (cu)
+ {
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_SUB(0, m_gpr[rb], r);
+ CHECK_C_SUB(0, m_gpr[rb]);
+ }
+ m_gpr[rd] = r;
+ break;
+ case 0x10: // and
+ m_gpr[rd] = m_gpr[ra] & m_gpr[rb];
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+ break;
+ case 0x11: // or
+ m_gpr[rd] = m_gpr[ra] | m_gpr[rb];
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+ break;
+ case 0x12: // not
+ r = ~m_gpr[ra];
+ if (cu)
+ {
+ CHECK_Z(r);
+ CHECK_N(r);
+ }
+ m_gpr[rd] = r;
+ break;
+ case 0x13: // xor
+ m_gpr[rd] = m_gpr[ra] ^ m_gpr[rb];
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+ break;
+ case 0x14: // bitclr
+ m_gpr[rd] = m_gpr[ra] & ~(1 << rb);
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+ break;
+ case 0x15: // bitset
+ m_gpr[rd] = m_gpr[ra] | (1 << rb);
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+ break;
+ case 0x16: // bittst
+ if (cu)
+ {
+ r = m_gpr[ra] & (1 << rb);
+ CHECK_N(m_gpr[ra]);
+ CHECK_Z(r);
+ }
+ break;
+ case 0x17: // bittgl
+ m_gpr[rd] = m_gpr[ra] ^ (1 << rb);
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+ break;
+ case 0x18: // sll
+ m_gpr[rd] = m_gpr[ra] << (m_gpr[rb] & 0x1f);
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ SET_C(BIT(m_gpr[ra], 32 - (m_gpr[rb] & 0x1f)));
+ }
+ break;
+ case 0x1a: // srl
+ m_gpr[rd] = m_gpr[ra] >> (m_gpr[rb] & 0x1f);
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ SET_C(BIT(m_gpr[ra], (m_gpr[rb] & 0x1f) - 1));
+ }
+ break;
+ case 0x1b: // sra
+ m_gpr[rd] = sign_extend(m_gpr[ra] >> (m_gpr[rb] & 0x1f), 32 - (m_gpr[rb] & 0x1f));
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ SET_C(BIT(m_gpr[ra], (m_gpr[rb] & 0x1f) - 1));
+ }
+ break;
+ case 0x1c: // ror
+ unemulated_op("ror");
+ break;
+ case 0x1d: // rorc
+ unemulated_op("rorc");
+ break;
+ case 0x1e: // rol
+ unemulated_op("rol");
+ break;
+ case 0x1f: // rolc
+ unemulated_op("rolc");
+ break;
+ case 0x20: // mul
+ {
+ INT64 a = (INT32)m_gpr[ra];
+ INT64 b = (INT32)m_gpr[rb];
+ UINT64 d = a * b;
+ REG_CEL = d & 0xffffffff;
+ REG_CEH = (d >> 32) & 0xffffffff;
+ break;
+ }
+ case 0x21: // mulu
+ {
+ UINT64 a = (UINT32)m_gpr[ra];
+ UINT64 b = (UINT32)m_gpr[rb];
+ UINT64 d = a * b;
+ REG_CEL = d & 0xffffffff;
+ REG_CEH = (d >> 32) & 0xffffffff;
+ break;
+ }
+ case 0x22: // div
+ if (m_gpr[rb])
+ {
+ INT32 a = (INT32)m_gpr[ra];
+ INT32 b = (INT32)m_gpr[rb];
+ REG_CEL = a / b;
+ REG_CEH = a % b;
+ }
+ else
+ {
+ gen_exception(EXCEPTION_CEE); // divide by zero exception
+ }
+ break;
+ case 0x23: // divu
+ if (m_gpr[rb])
+ {
+ UINT32 a = (UINT32)m_gpr[ra];
+ UINT32 b = (UINT32)m_gpr[rb];
+ REG_CEL = a / b;
+ REG_CEH = a % b;
+ }
+ else
+ {
+ gen_exception(EXCEPTION_CEE); // divide by zero exception
+ }
+ break;
+ case 0x24: // mfce
+ switch(rb & 3)
+ {
+ case 1: m_gpr[rd] = REG_CEL; break;
+ case 2: m_gpr[rd] = REG_CEH; break;
+ case 3: m_gpr[rd] = REG_CEH; m_gpr[ra] = REG_CEL; break;
+ }
+ break;
+ case 0x25: // mtce
+ switch(rb & 3)
+ {
+ case 1: REG_CEL = m_gpr[rd]; break;
+ case 2: REG_CEH = m_gpr[rd]; break;
+ case 3: REG_CEH = m_gpr[rd]; REG_CEL = m_gpr[ra]; break;
+ }
+ break;
+ case 0x28: // mfsr
+ if (rb < 3)
+ m_gpr[rd] = m_sr[rb];
+ break;
+ case 0x29: // mtsr
+ if (rb < 3)
+ m_sr[rb] = m_gpr[ra];
+ break;
+ case 0x2a: // t
+ SET_T(check_condition(rb));
+ break;
+ case 0x2b: // mv
+ if ((rb & 0x0f) != 14 && check_condition(rb))
+ m_gpr[rd] = m_gpr[ra];
+ break;
+ case 0x2c: // extsb
+ case 0x2d: // extsh
+ m_gpr[rd] = sign_extend(m_gpr[ra], (GET_S_FUNC6(m_op) & 1) ? 16 : 8);
+ if (cu)
+ {
+ CHECK_N(m_gpr[rd]);
+ CHECK_Z(m_gpr[rd]); // undefined
+ }
+ break;
+ case 0x2e: // extzb
+ case 0x2f: // extzh
+ m_gpr[rd] = m_gpr[ra] & ((GET_S_FUNC6(m_op) & 1) ? 0xffff : 0x00ff);
+ if (cu)
+ {
+ CHECK_N(m_gpr[rd]);
+ CHECK_Z(m_gpr[rd]); // undefined
+ }
+ break;
+ case 0x30: // lcb
+ unemulated_op("lcb");
+ break;
+ case 0x31: // lcw
+ unemulated_op("lcw");
+ break;
+ case 0x33: // lce
+ unemulated_op("lce");
+ break;
+ case 0x34: // scb
+ unemulated_op("scb");
+ break;
+ case 0x35: // scw
+ unemulated_op("scw");
+ break;
+ case 0x37: // sce
+ unemulated_op("sce");
+ break;
+ case 0x38: // slli
+ m_gpr[rd] = m_gpr[ra] << rb;
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ SET_C(BIT(m_gpr[ra], 32 - rb));
+ }
+ break;
+ case 0x3a: // srli
+ m_gpr[rd] = m_gpr[ra] >> rb;
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ SET_C(BIT(m_gpr[ra], rb - 1));
+ }
+ break;
+ case 0x3b: // srai
+ m_gpr[rd] = sign_extend(m_gpr[ra] >> rb, 32 - rb);
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ SET_C(BIT(m_gpr[ra], rb - 1));
+ }
+ break;
+ case 0x3c: // rori
+ unemulated_op("rori");
+ break;
+ case 0x3d: // roric
+ unemulated_op("roric");
+ break;
+ case 0x3e: // roli
+ unemulated_op("roli");
+ break;
+ case 0x3f: // rolic
+ unemulated_op("rolic");
+ break;
+ default:
+ op_undef();
+ }
+}
+
+void score7_cpu_device::op_iform1()
+{
+ UINT8 rd = GET_I_RD(m_op);
+ UINT32 imm16 = GET_I_IMM16(m_op);
+ INT32 simm16 = sign_extend(imm16, 16);
+ UINT8 cu = GET_I_CU(m_op);
+ UINT32 r;
+
+ switch(GET_I_FUNC3(m_op))
+ {
+ case 0: // addi
+ r = m_gpr[rd] + simm16;
+ if (cu)
+ {
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_ADD(m_gpr[rd], (UINT32)simm16, r);
+ CHECK_C_ADD(m_gpr[rd], (UINT32)simm16);
+ }
+ m_gpr[rd] = r;
+ break;
+ case 2: // cmpi
+ if (cu)
+ {
+ r = m_gpr[rd] - simm16;
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_SUB(m_gpr[rd], (UINT32)simm16, r);
+ CHECK_C_SUB(m_gpr[rd], (UINT32)simm16);
+ }
+ break;
+ case 4: // andi
+ m_gpr[rd] = m_gpr[rd] & imm16;
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+ break;
+ case 5: // ori
+ m_gpr[rd] = m_gpr[rd] | imm16;
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+ break;
+ case 6: // ldi
+ m_gpr[rd] = simm16;
+ break;
+ default:
+ op_undef();
+ }
+}
+
+void score7_cpu_device::op_jump()
+{
+ if(GET_J_LK(m_op))
+ REG_LNK = m_pc;
+
+ m_pc = (m_ppc & 0xfe000000) | (GET_J_DISP24(m_op) << 1);
+}
+
+void score7_cpu_device::op_rixform1()
+{
+ UINT8 ra = GET_RIX_RA(m_op);
+ UINT8 rd = GET_RIX_RD(m_op);
+
+ // pre-increment
+ m_gpr[ra] += sign_extend(GET_RIX_IMM12(m_op), 12);
+
+ switch(GET_RIX_FUNC3(m_op))
+ {
+ case 0: // lw
+ m_gpr[rd] = read_dword(m_gpr[ra]);
+ break;
+ case 1: // lh
+ m_gpr[rd] = sign_extend(read_word(m_gpr[ra]), 16);
+ break;
+ case 2: // lhu
+ m_gpr[rd] = read_word(m_gpr[ra]);
+ break;
+ case 3: // lb
+ m_gpr[rd] = sign_extend(read_byte(m_gpr[ra]), 8);
+ break;
+ case 4: // sw
+ write_dword(m_gpr[ra], m_gpr[rd]);
+ break;
+ case 5: // sh
+ write_word(m_gpr[ra], m_gpr[rd] & 0xffff);
+ break;
+ case 6: // lbu
+ m_gpr[rd] = read_byte(m_gpr[ra]);
+ break;
+ case 7: // sb
+ write_byte(m_gpr[ra], m_gpr[rd] & 0xff);
+ break;
+ }
+}
+
+void score7_cpu_device::op_branch()
+{
+ if (check_condition_branch(GET_BC_BC(m_op)))
+ {
+ INT32 disp = sign_extend(GET_BC_DISP19(m_op), 19) << 1;
+ if (GET_BC_LK(m_op))
+ REG_LNK = m_pc;
+
+ m_pc = m_ppc + disp;
+ }
+}
+
+void score7_cpu_device::op_iform2()
+{
+ UINT8 rd = GET_I_RD(m_op);
+ UINT32 imm16 = GET_I_IMM16(m_op) << 16;
+ INT32 simm16 = (INT32)imm16;
+ UINT8 cu = GET_I_CU(m_op);
+ UINT32 r;
+
+ switch(GET_I_FUNC3(m_op))
+ {
+ case 0: // addis
+ r = m_gpr[rd] + simm16;
+ if (cu)
+ {
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_ADD(m_gpr[rd], imm16, r);
+ CHECK_C_ADD(m_gpr[rd], imm16);
+ }
+ m_gpr[rd] = r;
+ break;
+ case 2: // cmpis
+ if (cu)
+ {
+ r = m_gpr[rd] - simm16;
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_SUB(m_gpr[rd], imm16, r);
+ CHECK_C_SUB(m_gpr[rd], imm16);
+ }
+ break;
+ case 4: // andis
+ m_gpr[rd] = m_gpr[rd] & imm16;
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+ break;
+ case 5: // oris
+ m_gpr[rd] = m_gpr[rd] | imm16;
+ if (cu)
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+ break;
+ case 6: // ldis
+ m_gpr[rd] = imm16;
+ break;
+ default:
+ op_undef();
+ }
+
+}
+
+void score7_cpu_device::op_crform()
+{
+ if ((REG_PSR & 0x08) && !(REG_PSR & 0x10000000))
+ return;
+
+ UINT8 cr = GET_CR_CR(m_op);
+ UINT8 rd = GET_CR_RD(m_op);
+
+ switch(GET_CR_OP(m_op))
+ {
+ case 0x00: // mtcr
+ m_cr[cr] = m_gpr[rd];
+ break;
+ case 0x01: // mfcr
+ m_gpr[rd] = m_cr[cr];
+ break;
+ case 0x84: // rte
+ REG_PSR = (REG_PSR & ~ 0x03) | ((REG_PSR >> 2) & 0x03);
+ REG_CR = (REG_CR & ~0x1f) | ((REG_CR >> 5) & 0x1f);
+ m_pc = REG_EPC;
+ break;
+ default:
+ if ((GET_CR_OP(m_op) & 0xc0) == 0)
+ fatalerror("%s: unemulated Coprocessor 0x%x (PC=0x%08x)\n", tag(), GET_CR_OP(m_op) & 0x07, m_ppc);
+ else
+ op_undef();
+ }
+}
+
+void score7_cpu_device::op_rixform2()
+{
+ UINT8 ra = GET_RIX_RA(m_op);
+ UINT8 rd = GET_RIX_RD(m_op);
+
+ switch(GET_RIX_FUNC3(m_op))
+ {
+ case 0: // lw
+ m_gpr[rd] = read_dword(m_gpr[ra]);
+ break;
+ case 1: // lh
+ m_gpr[rd] = sign_extend(read_word(m_gpr[ra]), 16);
+ break;
+ case 2: // lhu
+ m_gpr[rd] = read_word(m_gpr[ra]);
+ break;
+ case 3: // lb
+ m_gpr[rd] = sign_extend(read_byte(m_gpr[ra]), 8);
+ break;
+ case 4: // sw
+ write_dword(m_gpr[ra], m_gpr[rd]);
+ break;
+ case 5: // sh
+ write_word(m_gpr[ra], m_gpr[rd] & 0xffff);
+ break;
+ case 6: // lbu
+ m_gpr[rd] = read_byte(m_gpr[ra]);
+ break;
+ case 7: // sb
+ write_byte(m_gpr[ra], m_gpr[rd] & 0xff);
+ break;
+ }
+
+ // post-increment
+ m_gpr[ra] += sign_extend(GET_RIX_IMM12(m_op), 12);
+}
+
+void score7_cpu_device::op_addri()
+{
+ UINT8 ra = GET_RI_RA(m_op);
+ UINT8 rd = GET_RI_RD(m_op);
+ INT32 simm14 = sign_extend(GET_RI_IMM14(m_op), 14);
+ UINT8 cu = GET_RI_CU(m_op);
+
+ UINT32 r = m_gpr[ra] + simm14;
+ if (cu)
+ {
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_ADD(m_gpr[ra], (UINT32)simm14, r);
+ CHECK_C_ADD(m_gpr[ra], (UINT32)simm14);
+ }
+ m_gpr[rd] = r;
+}
+
+void score7_cpu_device::op_andri()
+{
+ UINT8 ra = GET_RI_RA(m_op);
+ UINT8 rd = GET_RI_RD(m_op);
+ UINT32 imm14 = GET_RI_IMM14(m_op);
+
+ m_gpr[rd] = m_gpr[ra] & imm14;
+
+ if (GET_RI_CU(m_op))
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+}
+
+void score7_cpu_device::op_orri()
+{
+ UINT8 ra = GET_RI_RA(m_op);
+ UINT8 rd = GET_RI_RD(m_op);
+ UINT32 imm14 = GET_RI_IMM14(m_op);
+
+ m_gpr[rd] = m_gpr[ra] | imm14;
+
+ if (GET_RI_CU(m_op))
+ {
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ }
+}
+
+void score7_cpu_device::op_lw()
+{
+ UINT8 rd = GET_LS_RD(m_op);
+ UINT8 ra = GET_LS_RA(m_op);
+ INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15);
+
+ m_gpr[rd] = read_dword(m_gpr[ra] + simm15);
+}
+
+void score7_cpu_device::op_lh()
+{
+ UINT8 rd = GET_LS_RD(m_op);
+ UINT8 ra = GET_LS_RA(m_op);
+ INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15);
+
+ m_gpr[rd] = sign_extend(read_word(m_gpr[ra] + simm15), 16);
+}
+
+void score7_cpu_device::op_lhu()
+{
+ UINT8 rd = GET_LS_RD(m_op);
+ UINT8 ra = GET_LS_RA(m_op);
+ INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15);
+
+ m_gpr[rd] = read_word(m_gpr[ra] + simm15);
+}
+
+void score7_cpu_device::op_lb()
+{
+ UINT8 rd = GET_LS_RD(m_op);
+ UINT8 ra = GET_LS_RA(m_op);
+ INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15);
+
+ m_gpr[rd] = sign_extend(read_byte(m_gpr[ra] + simm15), 8);
+}
+
+void score7_cpu_device::op_sw()
+{
+ UINT8 rd = GET_LS_RD(m_op);
+ UINT8 ra = GET_LS_RA(m_op);
+ INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15);
+
+ write_dword(m_gpr[ra] + simm15, m_gpr[rd]);
+}
+
+void score7_cpu_device::op_sh()
+{
+ UINT8 rd = GET_LS_RD(m_op);
+ UINT8 ra = GET_LS_RA(m_op);
+ INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15);
+
+ write_word(m_gpr[ra] + simm15, m_gpr[rd] & 0xffff);
+}
+
+void score7_cpu_device::op_lbu()
+{
+ UINT8 rd = GET_LS_RD(m_op);
+ UINT8 ra = GET_LS_RA(m_op);
+ INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15);
+
+ m_gpr[rd] = read_byte(m_gpr[ra] + simm15);
+}
+
+void score7_cpu_device::op_sb()
+{
+ UINT8 rd = GET_LS_RD(m_op);
+ UINT8 ra = GET_LS_RA(m_op);
+ INT32 simm15 = sign_extend(GET_LS_IMM15(m_op), 15);
+
+ write_byte(m_gpr[ra] + simm15, m_gpr[rd] & 0xff);
+}
+
+void score7_cpu_device::op_cache()
+{
+ //unemulated_op("CACHE");
+}
+
+void score7_cpu_device::op_cenew()
+{
+ unemulated_op("CENew");
+}
+
+
+//**************************************************************************
+// 16-bit opcodes
+//**************************************************************************
+
+void score7_cpu_device::op_rform1()
+{
+ UINT8 rd = GET_R_RD(m_op);
+ UINT8 ra = GET_R_RA(m_op);
+
+ switch(GET_R_FUNC4(m_op))
+ {
+ case 0x00: // nop!
+ break;
+ case 0x01: // mlfh!
+ m_gpr[rd] = m_gpr[0x10 + ra];
+ break;
+ case 0x02: // mhfl!
+ m_gpr[0x10 + rd] = m_gpr[ra];
+ break;
+ case 0x03: // mv!
+ m_gpr[rd] = m_gpr[ra];
+ break;
+ case 0x04: // br!
+ if (check_condition_branch(rd))
+ m_pc = m_gpr[ra];
+ break;
+ case 0x05: // t!
+ SET_T(check_condition(rd));
+ break;
+ case 0x0c: // brl!
+ if (check_condition_branch(rd))
+ {
+ REG_LNK = m_pc;
+ m_pc = m_gpr[ra];
+ }
+ break;
+ default:
+ op_undef();
+ }
+}
+
+void score7_cpu_device::op_rform2()
+{
+ UINT8 rd = GET_R_RD(m_op);
+ UINT8 ra = GET_R_RA(m_op);
+ UINT32 r;
+
+ switch(GET_R_FUNC4(m_op))
+ {
+ case 0x00: // add!
+ r = m_gpr[rd] + m_gpr[ra];
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_ADD(m_gpr[rd], m_gpr[ra], r);
+ CHECK_C_ADD(m_gpr[rd], m_gpr[ra]);
+ m_gpr[rd] = r;
+ break;
+ case 0x01: // sub!
+ r = m_gpr[rd] - m_gpr[ra];
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_SUB(m_gpr[rd], m_gpr[ra], r);
+ CHECK_C_SUB(m_gpr[rd], m_gpr[ra]);
+ m_gpr[rd] = r;
+ break;
+ case 0x02: // neg!
+ m_gpr[rd] = 0 - m_gpr[ra];
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ CHECK_V_SUB(0, m_gpr[ra], m_gpr[rd]);
+ CHECK_C_SUB(0, m_gpr[ra]);
+ break;
+ case 0x03: // cmp!
+ r = m_gpr[rd] - m_gpr[ra];
+ CHECK_Z(r);
+ CHECK_N(r);
+ CHECK_V_SUB(m_gpr[rd], m_gpr[ra], r);
+ CHECK_C_SUB(m_gpr[rd], m_gpr[ra]);
+ break;
+ case 0x04: // and!
+ m_gpr[rd] &= m_gpr[ra];
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ break;
+ case 0x05: // or!
+ m_gpr[rd] |= m_gpr[ra];
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ break;
+ case 0x06: // not!
+ m_gpr[rd] = ~m_gpr[ra];
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ break;
+ case 0x07: // xor!
+ m_gpr[rd] ^= m_gpr[ra];
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ break;
+ case 0x08: // lw!
+ m_gpr[rd] = read_dword(m_gpr[ra]);
+ break;
+ case 0x09: // lh!
+ m_gpr[rd] = sign_extend(read_word(m_gpr[ra]), 16);
+ break;
+ case 0x0a: // pop!
+ m_gpr[GET_P_RDG(m_op)] = read_dword(m_gpr[GET_P_RAG(m_op)]);
+ m_gpr[GET_P_RAG(m_op)] += 0x04;
+ break;
+ case 0x0b: // lbu!
+ m_gpr[rd] = read_byte(m_gpr[ra]);
+ break;
+ case 0x0c: // sw!
+ write_dword(m_gpr[ra], m_gpr[rd]);
+ break;
+ case 0x0d: // sh!
+ write_word(m_gpr[ra], m_gpr[rd] & 0xffff);
+ break;
+ case 0x0e: // push
+ m_gpr[GET_P_RAG(m_op)] -= 0x04;
+ write_dword(m_gpr[GET_P_RAG(m_op)], m_gpr[GET_P_RDG(m_op)]);
+ break;
+ case 0x0f: // sb!
+ write_byte(m_gpr[ra], m_gpr[rd] & 0xff);
+ break;
+ }
+}
+
+void score7_cpu_device::op_jform()
+{
+ if(GET_J_LK(m_op))
+ REG_LNK = m_pc;
+
+ m_pc = (m_ppc & 0xfffff000) | (GET_J_DISP11(m_op) << 1);
+}
+
+void score7_cpu_device::op_branch16()
+{
+ if(check_condition_branch(GET_BX_EC(m_op)))
+ m_pc = m_ppc + (sign_extend(GET_BX_DISP8(m_op), 8) << 1);
+}
+
+void score7_cpu_device::op_ldiu()
+{
+ m_gpr[GET_I2_RD(m_op)] = GET_I2_IMM8(m_op);
+}
+
+void score7_cpu_device::op_iform1a()
+{
+ UINT8 rd = GET_I16_RD(m_op);
+ UINT8 imm5 = GET_I16_IMM5(m_op);
+
+ switch(GET_I16_FUNC3(m_op))
+ {
+ case 0x00: // addei!
+ unemulated_op("addei!");
+ break;
+ case 0x01: // slli!
+ m_gpr[rd] <<= imm5;
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ break;
+ case 0x02: // sdbbp!
+ unemulated_op("sdbbp!");
+ break;
+ case 0x03: // srli!
+ m_gpr[rd] >>= imm5;
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ break;
+ case 0x04: // bitclr!
+ m_gpr[rd] &= ~(1 << imm5);
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ break;
+ case 0x05: // bitset!
+ m_gpr[rd] |= (1 << imm5);
+ CHECK_Z(m_gpr[rd]);
+ CHECK_N(m_gpr[rd]);
+ break;
+ case 0x06: // bittst!
+ CHECK_N(m_gpr[rd]);
+ CHECK_Z(m_gpr[rd] & (1 << imm5));
+ break;
+ default:
+ op_undef();
+ }
+}
+
+void score7_cpu_device::op_iform1b()
+{
+ UINT8 rd = GET_I16_RD(m_op);
+ UINT16 imm5 = GET_I16_IMM5(m_op);
+
+ switch(GET_I16_FUNC3(m_op))
+ {
+ case 0x00: // lwp!
+ m_gpr[rd] = read_dword(REG_BP + (imm5<<2));
+ break;
+ case 0x01: // lhp!
+ m_gpr[rd] = sign_extend(read_word(REG_BP + (imm5<<1)), 16);
+ break;
+ case 0x03: // lbup!
+ m_gpr[rd] = read_byte(REG_BP + imm5);
+ break;
+ case 0x04: // swp!
+ write_dword(REG_BP + (imm5<<2), m_gpr[rd]);
+ break;
+ case 0x05: // shp!
+ write_word(REG_BP + (imm5<<1), m_gpr[rd] & 0xffff);
+ break;
+ case 0x07: // sbp!
+ write_byte(REG_BP + imm5, m_gpr[rd] & 0xff);
+ break;
+ default:
+ op_undef();
+ }
+}
+
+void score7_cpu_device::op_undef()
+{
+ logerror("%s: undefined instruction 0x%x (PC=0x%08x)\n", tag(), m_op, m_ppc);
+ gen_exception(EXCEPTION_RI);
+}
+
+void score7_cpu_device::unemulated_op(const char * op)
+{
+ fatalerror("%s: unemulated %s (PC=0x%08x)\n", tag(), op, m_ppc);
+}