summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--scripts/src/cpu.lua2
-rw-r--r--src/devices/cpu/sparc/mb86901.cpp771
-rw-r--r--src/devices/cpu/sparc/sparc.h53
-rw-r--r--src/devices/cpu/sparc/sparcdasm.cpp23
-rw-r--r--src/devices/cpu/sparc/sparcdefs.h (renamed from src/devices/cpu/sparc/mb86901defs.h)43
-rw-r--r--src/mame/drivers/sun4.cpp126
6 files changed, 972 insertions, 46 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua
index 695d0659bd1..daec3987605 100644
--- a/scripts/src/cpu.lua
+++ b/scripts/src/cpu.lua
@@ -2378,7 +2378,7 @@ end
if (CPUS["MB86901"]~=null) then
files {
MAME_DIR .. "src/devices/cpu/sparc/mb86901.cpp",
- MAME_DIR .. "src/devices/cpu/sparc/mb86901defs.h",
+ MAME_DIR .. "src/devices/cpu/sparc/sparcdefs.h",
MAME_DIR .. "src/devices/cpu/sparc/sparc.h",
}
end
diff --git a/src/devices/cpu/sparc/mb86901.cpp b/src/devices/cpu/sparc/mb86901.cpp
index bf60a91f088..9d96afa71b9 100644
--- a/src/devices/cpu/sparc/mb86901.cpp
+++ b/src/devices/cpu/sparc/mb86901.cpp
@@ -7,12 +7,19 @@
// electrically and functionally, and implement
// the integer instructions in a SPARC v7
// compatible instruction set.
+//
+// To-Do:
+// - Traps
+// - Ops: Ticc, FBFcc, RETT, LDF, STF, SPARCv8 ops
+// - FPU support
+// - Coprocessor support
+//
//================================================================
#include "emu.h"
#include "debugger.h"
#include "sparc.h"
-#include "mb86901defs.h"
+#include "sparcdefs.h"
CPU_DISASSEMBLE( sparc );
@@ -25,15 +32,33 @@ const int mb86901_device::WINDOW_COUNT = 7;
//-------------------------------------------------
mb86901_device::mb86901_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : cpu_device(mconfig, MB86901, "Fujitsu MB86901", tag, owner, clock, "mb86901", __FILE__),
- m_program_config("program", ENDIANNESS_BIG, 32, 32)
+ : cpu_device(mconfig, MB86901, "Fujitsu MB86901", tag, owner, clock, "mb86901", __FILE__)
+ , m_as8_config("user_insn", ENDIANNESS_BIG, 32, 32)
+ , m_as9_config("supr_insn", ENDIANNESS_BIG, 32, 32)
+ , m_as10_config("user_data", ENDIANNESS_BIG, 32, 32)
+ , m_as11_config("supr_data", ENDIANNESS_BIG, 32, 32)
{
}
void mb86901_device::device_start()
{
- m_program = &space(AS_PROGRAM);
+ memset(m_dbgregs, 0, 24 * sizeof(UINT32));
+
+ m_user_insn = &space(AS_USER_INSN);
+ m_super_insn = &space(AS_SUPER_INSN);
+ m_user_data = &space(AS_USER_DATA);
+ m_super_data = &space(AS_SUPER_DATA);
+
+ for (int i = 0; i < 256; i++)
+ {
+ m_spaces[i] = m_super_insn;
+ }
+ m_spaces[0] = m_super_insn;
+ m_spaces[8] = m_user_insn;
+ m_spaces[9] = m_super_insn;
+ m_spaces[10] = m_user_data;
+ m_spaces[11] = m_super_data;
// register our state for the debugger
state_add(STATE_GENPC, "GENPC", m_pc).noshow();
@@ -44,7 +69,7 @@ void mb86901_device::device_start()
state_add(SPARC_WIM, "WIM", m_wim).formatstr("%08X");
state_add(SPARC_TBR, "TBR", m_tbr).formatstr("%08X");
state_add(SPARC_Y, "Y", m_y).formatstr("%08X");
- state_add(SPARC_ICC, "icc", m_icc).callexport().formatstr("%4s");
+ state_add(SPARC_ICC, "icc", m_icc).formatstr("%4s");
state_add(SPARC_CWP, "CWP", m_cwp).formatstr("%2d");
char regname[3] = "g0";
for (int i = 0; i < 8; i++)
@@ -56,20 +81,20 @@ void mb86901_device::device_start()
for (int i = 0; i < 8; i++)
{
regname[1] = 0x30 + i;
- state_add(SPARC_O0 + i, regname, m_r[8 + i]).callexport().formatstr("%08X");
+ state_add(SPARC_O0 + i, regname, m_dbgregs[i]).formatstr("%08X");
}
regname[0] = 'l';
for (int i = 0; i < 8; i++)
{
regname[1] = 0x30 + i;
- state_add(SPARC_O0 + i, regname, m_r[16 + i]).callexport().formatstr("%08X");
+ state_add(SPARC_L0 + i, regname, m_dbgregs[8+i]).formatstr("%08X");
}
regname[0] = 'i';
for (int i = 0; i < 8; i++)
{
regname[1] = 0x30 + i;
- state_add(SPARC_O0 + i, regname, m_r[24 + i]).callexport().formatstr("%08X");
+ state_add(SPARC_I0 + i, regname, m_dbgregs[16+i]).formatstr("%08X");
}
state_add(SPARC_EC, "EC", m_ec).formatstr("%1d");
@@ -79,12 +104,11 @@ void mb86901_device::device_start()
state_add(SPARC_S, "S", m_s).formatstr("%1d");
state_add(SPARC_PS, "PS", m_ps).formatstr("%1d");
-
- regname[0] = 'r';
+ char rname[5];
for (int i = 0; i < 120; i++)
{
- regname[1] = 0x30 + i;
- state_add(SPARC_R0 + i, regname, m_r[i]).formatstr("%08X");
+ sprintf(rname, "r%d", i);
+ state_add(SPARC_R0 + i, rname, m_r[i]).formatstr("%08X");
}
// register with the savestate system
@@ -116,8 +140,8 @@ void mb86901_device::device_stop()
void mb86901_device::device_reset()
{
- m_pc = 0;
- m_npc = 0x00000004;
+ PC = 0;
+ nPC = 4;
memset(m_r, 0, sizeof(UINT32) * 120);
m_wim = 0;
@@ -135,7 +159,15 @@ void mb86901_device::device_reset()
m_et = true; // double-check this
m_cwp = 0;
+ m_insn_asi = 9;
+ m_data_asi = 11;
+
MAKE_PSR;
+ for (int i = 0; i < 8; i++)
+ {
+ m_regs[i] = m_r + i;
+ }
+ update_gpr_pointers();
}
@@ -147,11 +179,98 @@ void mb86901_device::device_reset()
const address_space_config *mb86901_device::memory_space_config(address_spacenum spacenum) const
{
- if (spacenum == AS_PROGRAM)
+ switch (spacenum)
{
- return &m_program_config;
+ case AS_USER_INSN:
+ return &m_as8_config;
+ break;
+ case AS_SUPER_INSN:
+ return &m_as9_config;
+ break;
+ case AS_USER_DATA:
+ return &m_as10_config;
+ break;
+ case AS_SUPER_DATA:
+ return &m_as11_config;
+ break;
+ default:
+ return nullptr;
}
- return nullptr;
+}
+
+//-------------------------------------------------
+// read_byte - read an 8-bit value from a given
+// address space
+//-------------------------------------------------
+
+UINT32 mb86901_device::read_byte(UINT8 asi, UINT32 address)
+{
+ m_asi = asi;
+ // TODO: check for traps
+ return LOAD_UBA(asi, address);
+}
+
+INT32 mb86901_device::read_signed_byte(UINT8 asi, UINT32 address)
+{
+ m_asi = asi;
+ // TODO: check for traps
+ return LOAD_SBA(asi, address);
+}
+
+UINT32 mb86901_device::read_half(UINT8 asi, UINT32 address)
+{
+ m_asi = asi;
+ // TODO: check for traps
+ return LOAD_UHA(asi, address);
+}
+
+INT32 mb86901_device::read_signed_half(UINT8 asi, UINT32 address)
+{
+ m_asi = asi;
+ // TODO: check for traps
+ return LOAD_SHA(asi, address);
+}
+
+UINT32 mb86901_device::read_word(UINT8 asi, UINT32 address)
+{
+ m_asi = asi;
+ // TODO: check for traps
+ return LOAD_WA(asi, address);
+}
+
+UINT64 mb86901_device::read_doubleword(UINT8 asi, UINT32 address)
+{
+ m_asi = asi;
+ // TODO: check for traps
+ return LOAD_DA(asi, address);
+}
+
+void mb86901_device::write_byte(UINT8 asi, UINT32 address, UINT8 data)
+{
+ m_asi = asi;
+ // TODO: check for traps
+ STORE_BA(asi, address, data);
+}
+
+void mb86901_device::write_half(UINT8 asi, UINT32 address, UINT16 data)
+{
+ m_asi = asi;
+ // TODO: check for traps
+ STORE_HA(asi, address, data);
+}
+
+void mb86901_device::write_word(UINT8 asi, UINT32 address, UINT32 data)
+{
+ m_asi = asi;
+ // TODO: check for traps
+ STORE_WA(asi, address, data);
+}
+
+void mb86901_device::write_doubleword(UINT8 asi, UINT32 address, UINT64 data)
+{
+ m_asi = asi;
+ // TODO: check for traps
+ STORE_DA(asi, address, data);
}
@@ -162,20 +281,20 @@ const address_space_config *mb86901_device::memory_space_config(address_spacenum
void mb86901_device::state_string_export(const device_state_entry &entry, std::string &str) const
{
- const int total_window_regs = WINDOW_COUNT * 16;
switch (entry.index())
{
case STATE_GENFLAGS:
+ case SPARC_ICC:
str = string_format("%c%c%c%c", ICC_N_SET ? 'n' : ' ', ICC_Z_SET ? 'z' : ' ', ICC_V_SET ? 'v' : ' ', ICC_C_SET ? 'c' : ' ');
break;
case SPARC_O0: case SPARC_O1: case SPARC_O2: case SPARC_O3: case SPARC_O4: case SPARC_O5: case SPARC_O6: case SPARC_O7:
- str = string_format("%08X", m_r[8 + m_cwp * 16 + (entry.index() - SPARC_O0)]);
+ str = string_format("%08X", m_dbgregs[entry.index() - SPARC_O0]);
break;
case SPARC_L0: case SPARC_L1: case SPARC_L2: case SPARC_L3: case SPARC_L4: case SPARC_L5: case SPARC_L6: case SPARC_L7:
- str = string_format("%08X", m_r[8 + (8 + (m_cwp * 16 + (entry.index() - SPARC_L0)) % total_window_regs)]);
+ str = string_format("%08X", m_dbgregs[8 + (entry.index() - SPARC_L0)]);
break;
case SPARC_I0: case SPARC_I1: case SPARC_I2: case SPARC_I3: case SPARC_I4: case SPARC_I5: case SPARC_I6: case SPARC_I7:
- str = string_format("%08X", m_r[8 + (16 + (m_cwp * 16 + (entry.index() - SPARC_I0)) % total_window_regs)]);
+ str = string_format("%08X", m_dbgregs[16 + (entry.index() - SPARC_I0)]);
break;
}
}
@@ -263,23 +382,623 @@ void mb86901_device::execute_set_input(int inputnum, int state)
//-------------------------------------------------
+// save_restore_update_cwp - update cwp after
+// a save or restore opcode with no trap taken
+//-------------------------------------------------
+
+void mb86901_device::save_restore_update_cwp(UINT32 op, UINT8 new_cwp)
+{
+ UINT32 arg1 = RS1REG;
+ UINT32 arg2 = USEIMM ? SIMM13 : RS2REG;
+
+ m_cwp = new_cwp;
+ MAKE_PSR;
+ update_gpr_pointers();
+
+ SET_RDREG(arg1 + arg2);
+}
+
+//-------------------------------------------------
+// execute_group2 - execute an opcode in group 2,
+// mostly ALU ops
+//-------------------------------------------------
+
+bool mb86901_device::execute_group2(UINT32 op)
+{
+ UINT32 arg1 = RS1REG;
+ UINT32 arg2 = USEIMM ? SIMM13 : RS2REG;
+
+ switch (OP3)
+ {
+ case 0: // add
+ SET_RDREG(arg1 + arg2);
+ break;
+ case 1: // and
+ SET_RDREG(arg1 & arg2);
+ break;
+ case 2: // or
+ SET_RDREG(arg1 | arg2);
+ break;
+ case 3: // xor
+ SET_RDREG(arg1 ^ arg2);
+ break;
+ case 4: // sub
+ SET_RDREG(arg1 - arg2);
+ break;
+ case 5: // andn
+ SET_RDREG(arg1 & ~arg2);
+ break;
+ case 6: // orn
+ SET_RDREG(arg1 | ~arg2);
+ break;
+ case 7: // xnor
+ SET_RDREG(arg1 ^ ~arg2);
+ break;
+ case 8: // addx
+ SET_RDREG(arg1 + arg2 + (ICC_C_SET ? 1 : 0));
+ break;
+ case 10: // umul, SPARCv8
+ break;
+ case 11: // smul, SPARCv8
+ break;
+ case 12: // subx
+ SET_RDREG(arg1 - arg2 - (ICC_C_SET ? 1 : 0));
+ break;
+ case 14: // udiv, SPARCv8
+ break;
+ case 15: // sdiv, SPARCv8
+ break;
+ case 16: // addcc
+ {
+ UINT32 result = arg1 + arg2;
+ TEST_ICC_NZ(result);
+ if ((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000))
+ SET_ICC_V_FLAG;
+ if (result < arg1 || result < arg2)
+ SET_ICC_C_FLAG;
+ SET_RDREG(result);
+ break;
+ }
+ case 17: // andcc
+ {
+ UINT32 result = arg1 & arg2;
+ TEST_ICC_NZ(result);
+ SET_RDREG(result);
+ break;
+ }
+ case 18: // orcc
+ {
+ UINT32 result = arg1 | arg2;
+ TEST_ICC_NZ(result);
+ SET_RDREG(result);
+ break;
+ }
+ case 19: // xorcc
+ {
+ UINT32 result = arg1 ^ arg2;
+ TEST_ICC_NZ(result);
+ SET_RDREG(result);
+ break;
+ }
+ case 20: // subcc
+ {
+ UINT32 result = arg1 - arg2;
+ TEST_ICC_NZ(result);
+ if ((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000))
+ SET_ICC_V_FLAG;
+ if (result > arg1)
+ SET_ICC_C_FLAG;
+ SET_RDREG(result);
+ break;
+ }
+ case 21: // andncc
+ {
+ UINT32 result = arg1 & ~arg2;
+ TEST_ICC_NZ(result);
+ SET_RDREG(result);
+ break;
+ }
+ case 22: // orncc
+ {
+ UINT32 result = arg1 | ~arg2;
+ TEST_ICC_NZ(result);
+ SET_RDREG(result);
+ break;
+ }
+ case 23: // xnorcc
+ {
+ UINT32 result = arg1 ^ ~arg2;
+ TEST_ICC_NZ(result);
+ SET_RDREG(result);
+ break;
+ }
+ case 24: // addxcc
+ {
+ UINT32 c = (ICC_C_SET ? 1 : 0);
+ UINT32 argt = arg2 + c;
+ UINT32 result = arg1 + argt;
+ TEST_ICC_NZ(result);
+ if (((arg1 & 0x80000000) == (argt & 0x80000000) && (arg1 & 0x80000000) != (result & 0x80000000)) || (c != 0 && arg2 == 0x7fffffff))
+ SET_ICC_V_FLAG;
+ if (result < arg1 || result < arg2 || (result == arg1 && arg2 != 0))
+ SET_ICC_C_FLAG;
+ SET_RDREG(result);
+ break;
+ }
+ case 26: // umulcc, SPARCv8
+ break;
+ case 27: // smulcc, SPARCv8
+ break;
+ case 28: // subxcc
+ {
+ UINT32 c = (ICC_C_SET ? 1 : 0);
+ UINT32 argt = arg2 - c;
+ UINT32 result = arg1 - argt;
+ TEST_ICC_NZ(result);
+ if (((arg1 & 0x80000000) == (argt & 0x80000000) && (arg1 & 0x80000000) != (result & 0x80000000)) || (c != 0 && arg2 == 0x80000000))
+ SET_ICC_V_FLAG;
+ if (result > arg1 || (result == arg1 && arg2 != 0))
+ SET_ICC_C_FLAG;
+ SET_RDREG(result);
+ break;
+ }
+ case 30: // udivcc, SPARCv8
+ break;
+ case 31: // sdivcc, SPARCv8
+ break;
+ case 32: // taddcc
+ {
+ UINT32 result = arg1 + arg2;
+ TEST_ICC_NZ(result);
+ if (((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) || ((arg1 & 3) != 0) || ((arg2 & 3) != 0))
+ SET_ICC_V_FLAG;
+ if (result < arg1 || result < arg2)
+ SET_ICC_C_FLAG;
+ SET_RDREG(result);
+ break;
+ }
+ case 33: // tsubcc
+ {
+ UINT32 result = arg1 - arg2;
+ TEST_ICC_NZ(result);
+ if (((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) || ((arg1 & 3) != 0) || ((arg2 & 3) != 0))
+ SET_ICC_V_FLAG;
+ if (result > arg1)
+ SET_ICC_C_FLAG;
+ SET_RDREG(result);
+ break;
+ }
+ case 34: // taddcctv
+ {
+ UINT32 result = arg1 + arg2;
+ bool v = ((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) || ((arg1 & 3) != 0) || ((arg2 & 3) != 0);
+ if (v)
+ {
+ // TODO: trap
+ }
+ else
+ {
+ TEST_ICC_NZ(result);
+ if (result < arg1 || result < arg2)
+ SET_ICC_C_FLAG;
+ SET_RDREG(result);
+ }
+ break;
+ }
+ case 35: // tsubcctv
+ {
+ UINT32 result = arg1 - arg2;
+ bool v = ((arg1 & 0x80000000) == (arg2 & 0x80000000) && (arg2 & 0x80000000) != (result & 0x80000000)) || ((arg1 & 3) != 0) || ((arg2 & 3) != 0);
+ if (v)
+ {
+ // TODO: trap
+ }
+ else
+ {
+ TEST_ICC_NZ(result);
+ if (result > arg1)
+ SET_ICC_C_FLAG;
+ SET_RDREG(result);
+ }
+ break;
+ }
+ case 36: // mulscc
+ break;
+ case 37: // sll
+ SET_RDREG(arg1 << arg2);
+ break;
+ case 38: // srl
+ SET_RDREG(arg1 >> arg2);
+ break;
+ case 39: // sra
+ SET_RDREG(INT32(arg1) >> arg2);
+ break;
+ case 40: // rdy
+ if (RS1 == 0)
+ { // rd y
+ SET_RDREG(m_y);
+ }
+ else if (RS1 == 15 && RD == 0)
+ { // stbar, SPARCv8
+ }
+ else
+ { // rd asr, SPARCv8
+ }
+ break;
+ case 41: // rd psr
+ // TODO: check privilege
+ SET_RDREG(m_psr);
+ break;
+ case 42: // rd wim
+ // TODO: check privilege
+ SET_RDREG(m_wim);
+ break;
+ case 43: // rd tbr
+ // TODO: check privilege
+ SET_RDREG(m_tbr);
+ break;
+ case 48:
+ if (RD == 0)
+ { // wr y
+ m_y = arg1 ^ arg2;
+ }
+ else
+ { // wr asr, SPARCv8
+ }
+ break;
+ case 49: // wr psr
+ // TODO: check privilege
+ m_psr = (arg1 ^ arg2) & ~PSR_ZERO_MASK;
+ BREAK_PSR;
+ break;
+ case 50: // wr wim
+ // TODO: check privilege
+ m_wim = (arg1 ^ arg2) & 0x7f;
+ break;
+ case 51: // wr tbr
+ // TODO: check privilege
+ m_tbr = (arg1 ^ arg2) & 0xfffff000;
+ break;
+ case 52: // FPop1
+ break;
+ case 53: // FPop2
+ break;
+ case 56: // jmpl
+ {
+ UINT32 addr = ADDRESS;
+ m_icount--;
+ if (addr & 3)
+ {
+ // mem_address_not_aligned trap
+ }
+ else
+ {
+ SET_RDREG(PC);
+ PC = nPC;
+ nPC = addr;
+ return false;
+ }
+ break;
+ }
+ case 57: // rett
+ break;
+ case 58: // ticc
+ break;
+ case 59:
+ if (RD == 0)
+ { // flush, SPARCv8
+ }
+ break;
+ case 60: // save
+ {
+ UINT8 new_cwp = ((m_cwp + WINDOW_COUNT) - 1) % WINDOW_COUNT;
+ if (m_wim & (1 << new_cwp))
+ {
+ // TODO: generate window_overflow trap
+ }
+ else
+ {
+ save_restore_update_cwp(op, new_cwp);
+ }
+ break;
+ }
+ case 61: // restore
+ {
+ UINT8 new_cwp = (m_cwp + 1) % WINDOW_COUNT;
+ if (m_wim & (1 << new_cwp))
+ {
+ // TODO: generate window_underflow trap
+ }
+ else
+ {
+ save_restore_update_cwp(op, new_cwp);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
+
+
+
+//-------------------------------------------------
+// update_gpr_pointers - cache pointers to
+// the registers in our current window
+//-------------------------------------------------
+
+void mb86901_device::update_gpr_pointers()
+{
+ for (int i = 0; i < 8; i++)
+ {
+ m_regs[ 8 + i] = &m_r[8 + (( 0 + m_cwp * 16 + i) % (WINDOW_COUNT * 16))];
+ m_regs[16 + i] = &m_r[8 + (( 8 + m_cwp * 16 + i) % (WINDOW_COUNT * 16))];
+ m_regs[24 + i] = &m_r[8 + ((16 + m_cwp * 16 + i) % (WINDOW_COUNT * 16))];
+ }
+}
+
+
+//-------------------------------------------------
+// execute_group3 - execute an opcode in group 3
+// (load/store)
+//-------------------------------------------------
+
+void mb86901_device::execute_group3(UINT32 op)
+{
+ static const int ldst_cycles[64] = {
+ 1, 1, 1, 2, 2, 2, 2, 3,
+ 0, 1, 1, 0, 0, 3, 0, 0,
+ 1, 1, 1, 2, 2, 2, 2, 3,
+ 0, 1, 1, 0, 0, 3, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ switch (OP3)
+ {
+ case 0: // ld
+ SET_RDREG(read_word(m_s ? 10 : 11, ADDRESS));
+ break;
+ case 1: // ldub
+ SET_RDREG(read_byte(m_s ? 10 : 11, ADDRESS));
+ break;
+ case 2: // lduh
+ SET_RDREG(read_half(m_s ? 10 : 11, ADDRESS));
+ break;
+ case 3: // ldd
+ SET_RDREG(read_word(m_s ? 10 : 11, ADDRESS));
+ REG(RD+1) = read_word(m_s ? 10 : 11, ADDRESS+4);
+ break;
+ case 4: // st
+ write_word(m_s ? 10 : 11, ADDRESS, RDREG);
+ break;
+ case 5: // stb
+ write_byte(m_s ? 10 : 11, ADDRESS, UINT8(RDREG));
+ break;
+ case 6: // sth
+ write_word(m_s ? 10 : 11, ADDRESS, UINT16(RDREG));
+ break;
+ case 7: // std
+ // TODO: trap if RD is odd
+ write_word(m_s ? 10 : 11, ADDRESS, RDREG);
+ write_word(m_s ? 10 : 11, ADDRESS, REG(RD+1));
+ break;
+ case 9: // ldsb
+ SET_RDREG(read_signed_byte(m_s ? 10 : 11, ADDRESS));
+ break;
+ case 10: // lsdh
+ SET_RDREG(read_signed_half(m_s ? 10 : 11, ADDRESS));
+ break;
+ case 13: // ldstub
+ SET_RDREG(read_byte(m_s ? 10 : 11, ADDRESS));
+ write_byte(m_s ? 10 : 11, ADDRESS, 0xff);
+ break;
+ case 15: // swap, SPARCv8
+ break;
+ case 16: // lda
+ SET_RDREG(read_word(ASI, ADDRESS));
+ break;
+ case 17: // lduba
+ SET_RDREG(read_byte(ASI, ADDRESS));
+ break;
+ case 18: // lduha
+ SET_RDREG(read_half(ASI, ADDRESS));
+ break;
+ case 19: // ldda
+ SET_RDREG(read_word(ASI, ADDRESS));
+ REG(RD+1) = read_word(ASI, ADDRESS+4);
+ break;
+ case 20: // sta
+ write_word(ASI, ADDRESS, RDREG);
+ break;
+ case 21: // stba
+ write_byte(ASI, ADDRESS, UINT8(RDREG));
+ break;
+ case 22: // stha
+ write_half(ASI, ADDRESS, UINT16(RDREG));
+ break;
+ case 23: // stda
+ // TODO: trap if RD is odd
+ write_word(ASI, ADDRESS, RDREG);
+ write_word(ASI, ADDRESS+4, REG(RD+1));
+ break;
+ case 25: // ldsba
+ SET_RDREG(read_signed_byte(ASI, ADDRESS));
+ break;
+ case 26: // ldsha
+ SET_RDREG(read_signed_half(ASI, ADDRESS));
+ break;
+ case 29: // ldstuba
+ SET_RDREG(read_byte(ASI, ADDRESS));
+ write_byte(ASI, ADDRESS, 0xff);
+ break;
+ case 31: // swapa, SPARCv8
+ break;
+ case 32: // ld fpr
+ break;
+ case 33: // ld fsr
+ break;
+ case 35: // ldd fpr
+ break;
+ case 36: // st fpr
+ break;
+ case 37: // st fsr
+ break;
+ case 38: // std fq, SPARCv8
+ break;
+ case 39: // std fpr
+ break;
+ case 40: // ld cpr, SPARCv8
+ break;
+ case 41: // ld csr, SPARCv8
+ break;
+ case 43: // ldd cpr, SPARCv8
+ break;
+ case 44: // st cpr, SPARCv8
+ break;
+ case 45: // st csr, SPARCv8
+ break;
+ case 46: // std cq, SPARCv8
+ break;
+ case 47: // std cpr, SPARCv8
+ break;
+ }
+
+ m_icount -= ldst_cycles[OP3];
+}
+
+
+//-------------------------------------------------
+// execute_bicc - execute a branch opcode
+//-------------------------------------------------
+
+bool mb86901_device::execute_bicc(UINT32 op)
+{
+ bool branch_taken = false;
+ bool n = ICC_N_SET;
+ bool z = ICC_Z_SET;
+ bool v = ICC_V_SET;
+ bool c = ICC_C_SET;
+
+ switch(COND & 7) // COND & 8
+ { // 0 8
+ case 0: branch_taken = false; break; // bn ba
+ case 1: branch_taken = z; break; // bz bne
+ case 2: branch_taken = z | (n ^ z); break; // ble bg
+ case 3: branch_taken = n ^ z; break; // bl bge
+ case 4: branch_taken = c | z; break; // bleu bgu
+ case 5: branch_taken = c; break; // bcs bcc
+ case 6: branch_taken = n; break; // bneg bpos
+ case 7: branch_taken = v; break; // bvs bvc
+ }
+
+ if (COND & 8)
+ branch_taken = !branch_taken;
+
+ if (branch_taken)
+ {
+ UINT32 brpc = PC + DISP22;
+ PC = nPC;
+ nPC = brpc;
+ return false;
+ }
+ else
+ {
+ m_icount--;
+ }
+
+ if (ANNUL && (!branch_taken || COND == 8))
+ {
+ PC = nPC;
+ nPC = PC + 4;
+ m_icount -= 1;
+ return false;
+ }
+
+ return true;
+}
+
+//-------------------------------------------------
// execute_run - execute a timeslice's worth of
// opcodes
//-------------------------------------------------
void mb86901_device::execute_run()
{
+ bool debug = machine().debug_flags & DEBUG_FLAG_ENABLED;
+
while (m_icount > 0)
{
debugger_instruction_hook(this, m_pc);
- //UINT32 op = read_word(m_pc);
-
- // TODO
+ UINT32 op = GET_OPCODE;
+
+ bool update_npc = true;
+
+ switch (OP)
+ {
+ case 0: // Bicc, SETHI, FBfcc
+ switch (OP2)
+ {
+ case 0: // unimp
+ break;
+ case 2: // branch on integer condition codes
+ update_npc = execute_bicc(op);
+ break;
+ case 4: // sethi
+ SET_RDREG(IMM22);
+ break;
+ case 6: // branch on floating-point condition codes
+ break;
+ case 7: // branch on coprocessor condition codes, SPARCv8
+ break;
+ default:
+ break;
+ }
+ break;
+ case 1: // call
+ {
+ UINT32 pc = PC;
+ UINT32 callpc = PC + DISP30;
+ PC = nPC;
+ nPC = callpc;
- m_pc = m_npc;
- m_npc += 4;
+ REG(15) = pc;
+ update_npc = false;
+ break;
+ }
+ case 2:
+ update_npc = execute_group2(op);
+ break;
+ case 3: // loads, stores
+ execute_group3(op);
+ break;
+ default:
+ break;
+ }
+
+ REG(0) = 0;
+
+ if (update_npc)
+ {
+ PC = nPC;
+ nPC = PC + 4;
+ }
+
+ if (debug)
+ {
+ for (int i = 0; i < 8; i++)
+ {
+ m_dbgregs[i] = *m_regs[8 + i];
+ m_dbgregs[8 + i] = *m_regs[16 + i];
+ m_dbgregs[16 + i] = *m_regs[24 + i];
+ }
+ }
--m_icount;
}
}
diff --git a/src/devices/cpu/sparc/sparc.h b/src/devices/cpu/sparc/sparc.h
index 592879a63b1..5e963e18df9 100644
--- a/src/devices/cpu/sparc/sparc.h
+++ b/src/devices/cpu/sparc/sparc.h
@@ -9,6 +9,11 @@
#ifndef __SPARC_H__
#define __SPARC_H__
+#define AS_USER_INSN AS_0
+#define AS_SUPER_INSN AS_1
+#define AS_USER_DATA AS_2
+#define AS_SUPER_DATA AS_3
+
class mb86901_device : public cpu_device
{
public:
@@ -37,17 +42,33 @@ public:
// device_state_interface overrides
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
+ UINT8 fetch_asi() { return m_asi; }
+ UINT32 pc() { return m_pc; }
+
protected:
+ void update_gpr_pointers();
+ void save_restore_update_cwp(UINT32 op, UINT8 new_cwp);
+ bool execute_group2(UINT32 op);
+ void execute_group3(UINT32 op);
+ bool execute_bicc(UINT32 op);
+
// address spaces
- const address_space_config m_program_config;
+ const address_space_config m_as8_config;
+ const address_space_config m_as9_config;
+ const address_space_config m_as10_config;
+ const address_space_config m_as11_config;
// memory access
- UINT8 read_byte(UINT32 address);
- UINT16 read_half(UINT32 address);
- UINT32 read_word(UINT32 address);
- void write_byte(UINT32 address, UINT8 data);
- void write_half(UINT32 address, UINT16 data);
- void write_word(UINT32 address, UINT32 data);
+ UINT32 read_byte(UINT8 asi, UINT32 address);
+ INT32 read_signed_byte(UINT8 asi, UINT32 address);
+ UINT32 read_half(UINT8 asi, UINT32 address);
+ INT32 read_signed_half(UINT8 asi, UINT32 address);
+ UINT32 read_word(UINT8 asi, UINT32 address);
+ UINT64 read_doubleword(UINT8 asi, UINT32 address);
+ void write_byte(UINT8 asi, UINT32 address, UINT8 data);
+ void write_half(UINT8 asi, UINT32 address, UINT16 data);
+ void write_word(UINT8 asi, UINT32 address, UINT32 data);
+ void write_doubleword(UINT8 asi, UINT32 address, UINT64 data);
// general-purpose registers
UINT32 m_r[120];
@@ -72,11 +93,27 @@ protected:
bool m_et; // enable traps
UINT8 m_cwp; // current window pointer
+ // register windowing helpers
+ UINT32* m_regs[32];
+
+ // addressing helpers
+ UINT8 m_insn_asi;
+ UINT8 m_data_asi;
+ UINT8 m_asi;
+
// other internal states
+ UINT32 m_nextnpc;
int m_icount;
+ // debugger helpers
+ UINT32 m_dbgregs[24];
+
// address spaces
- address_space *m_program;
+ address_space *m_user_insn;
+ address_space *m_super_insn;
+ address_space *m_user_data;
+ address_space *m_super_data;
+ address_space *m_spaces[256];
// processor configuration
static const int WINDOW_COUNT;
diff --git a/src/devices/cpu/sparc/sparcdasm.cpp b/src/devices/cpu/sparc/sparcdasm.cpp
index 0b9a07f86e3..62bd2fa42a4 100644
--- a/src/devices/cpu/sparc/sparcdasm.cpp
+++ b/src/devices/cpu/sparc/sparcdasm.cpp
@@ -5,7 +5,7 @@
*/
#include "emu.h"
-#include "mb86901defs.h"
+#include "sparcdefs.h"
static void print(char *output, const char *fmt, ...)
{
@@ -354,9 +354,24 @@ offs_t sparc_dasm(char *buffer, offs_t pc, UINT32 op)
else
print(buffer, "wr %s,%d,%%asr%d", regnames[RS1], SIMM13, RD);
break;
- case 49: print(buffer, "wr %s,%d,%%psr", regnames[RS1], SIMM13); break;
- case 50: print(buffer, "wr %s,%d,%%wim", regnames[RS1], SIMM13); break;
- case 51: print(buffer, "wr %s,%d,%%tbr", regnames[RS1], SIMM13); break;
+ case 49:
+ if (RS1 == 0)
+ print(buffer, "wr %d,%%psr", SIMM13);
+ else
+ print(buffer, "wr %s,%d,%%psr", regnames[RS1], SIMM13);
+ break;
+ case 50:
+ if (RS1 == 0)
+ print(buffer, "wr %d,%%wim", SIMM13);
+ else
+ print(buffer, "wr %s,%d,%%wim", regnames[RS1], SIMM13);
+ break;
+ case 51:
+ if (RS1 == 0)
+ print(buffer, "wr %d,%%tbr", SIMM13);
+ else
+ print(buffer, "wr %s,%d,%%tbr", regnames[RS1], SIMM13);
+ break;
case 52: // FPop1
sparc_dasm_fpop1(buffer, op);
break;
diff --git a/src/devices/cpu/sparc/mb86901defs.h b/src/devices/cpu/sparc/sparcdefs.h
index 843f91861c8..a4ff4b94dc0 100644
--- a/src/devices/cpu/sparc/mb86901defs.h
+++ b/src/devices/cpu/sparc/sparcdefs.h
@@ -12,6 +12,30 @@
#ifndef __MB86901_DEFS_H__
#define __MB86901_DEFS_H__
+#define GET_OPCODE 0; { m_asi = m_insn_asi; op = m_spaces[m_insn_asi]->read_dword(m_pc); }
+
+#define LOAD_SBA(asi,addr) (((INT32)m_spaces[asi]->read_byte(addr) << 24) >> 24)
+#define LOAD_UBA(asi,addr) m_spaces[asi]->read_byte(addr)
+#define LOAD_SHA(asi,addr) (((INT32)m_spaces[asi]->read_word(addr) << 16) >> 16)
+#define LOAD_UHA(asi,addr) m_spaces[asi]->read_word(addr)
+#define LOAD_WA(asi,addr) m_spaces[asi]->read_dword(addr)
+#define LOAD_DA(asi,addr) (((UINT64)m_spaces[asi]->read_dword(addr) << 32) | m_spaces[asi]->read_dword(addr+4))
+#define STORE_BA(asi,addr,data) { m_spaces[asi]->write_byte(addr,data); }
+#define STORE_HA(asi,addr,data) { m_spaces[asi]->write_word(addr,data); }
+#define STORE_WA(asi,addr,data) { m_spaces[asi]->write_dword(addr,data); }
+#define STORE_DA(asi,addr,data) { m_spaces[asi]->write_dword(addr,(UINT32)(data >> 32)); m_spaces[asi]->write_dword(addr+4,(UINT32)data); }
+
+#define LOAD_SB(addr) { m_asi = m_data_asi; LOAD_SBA(m_data_asi,addr); }
+#define LOAD_UB(addr) { m_asi = m_data_asi; LOAD_UBA(m_data_asi,addr); }
+#define LOAD_SH(addr) { m_asi = m_data_asi; LOAD_SHA(m_data_asi,addr); }
+#define LOAD_UH(addr) { m_asi = m_data_asi; LOAD_UHA(m_data_asi,addr); }
+#define LOAD_W(addr) { m_asi = m_data_asi; LOAD_WA(m_data_asi,addr); }
+#define LOAD_D(addr) { m_asi = m_data_asi; LOAD_DA(m_data_asi,addr); }
+#define STORE_B(addr,data) { m_asi = m_data_asi; STORE_BA(m_data_asi,addr); }
+#define STORE_H(addr,data) { m_asi = m_data_asi; STORE_HA(m_data_asi,addr); }
+#define STORE_W(addr,data) { m_asi = m_data_asi; STORE_WA(m_data_asi,addr); }
+#define STORE_D(addr,data) { m_asi = m_data_asi; STORE_DA(m_data_asi,addr); }
+
#define PSR_CWP_MASK 0x0000001f
#define PSR_ET_SHIFT 5
#define PSR_ET_MASK 0x00000020
@@ -26,6 +50,7 @@
#define PSR_EC_SHIFT 13
#define PSR_EC_MASK 0x00002000
#define PSR_ICC_SHIFT 20
+#define PSR_RES_MASK 0x000fc000
#define PSR_ICC_MASK 0x00f00000
#define PSR_N_MASK 0x00800000
#define PSR_Z_MASK 0x00400000
@@ -37,6 +62,7 @@
#define PSR_IMPL_SHIFT 28
#define PSR_IMPL_MASK 0xf0000000
#define PSR_IMPL 0
+#define PSR_ZERO_MASK (PSR_IMPL_MASK | PSR_VER_MASK | PSR_RES_MASK)
#define ICC_N_SET (m_psr & PSR_N_MASK)
#define ICC_N_CLEAR (!ICC_N_SET)
@@ -58,7 +84,13 @@
#define SET_ICC_C_FLAG do { m_psr |= PSR_C_MASK; } while(0);
#define CLEAR_ICC_C_FLAG do { m_psr &= ~PSR_C_MASK; } while(0);
+#define CLEAR_ICC do { m_psr &= ~PSR_ICC_MASK; } while(0);
+
+#define TEST_ICC_NZ(x) do { m_psr &= ~PSR_ICC_MASK; m_psr |= (x & 0x80000000) ? PSR_N_MASK : 0; m_psr |= (x == 0) ? PSR_Z_MASK : 0; } while (0);
+
#define MAKE_PSR do { m_psr = (m_impl << PSR_IMPL_SHIFT) | (m_ver << PSR_VER_SHIFT) | (m_icc << PSR_ICC_SHIFT) | (m_ec ? PSR_EC_MASK : 0) | (m_ef ? PSR_EF_MASK : 0) | (m_pil << PSR_PIL_SHIFT) | (m_s ? PSR_S_MASK : 0) | (m_ps ? PSR_PS_MASK : 0) | (m_et ? PSR_ET_MASK : 0) | m_cwp; } while(0);
+#define BREAK_PSR do { m_icc = (m_psr & PSR_ICC_MASK) >> PSR_ICC_SHIFT; m_ec = m_psr & PSR_EC_MASK; m_ef = m_psr & PSR_EF_MASK; m_pil = (m_psr & PSR_PIL_MASK) >> PSR_PIL_SHIFT; m_s = m_psr & PSR_S_MASK; m_ps = m_psr & PSR_PS_MASK; m_et = m_psr & PSR_ET_MASK; m_cwp = m_psr & PSR_CWP_MASK; } while(0);
+#define MAKE_ICC do { m_icc = (m_psr & PSR_ICC_MASK) >> PSR_ICC_SHIFT; } while(0);
#define IS_SUPERVISOR (m_psr & PSR_S_MASK)
#define IS_USER (!IS_SUPERVISOR)
@@ -75,6 +107,7 @@
#define SIMM13 (((INT32)(op << 19)) >> 19)
#define IMM7 (op & 0x7f)
+#define OPIMM (op & 0x00002000)
#define USEIMM ((op >> 13) & 1)
#define COND ((op >> 25) & 15)
@@ -85,4 +118,14 @@
#define RS1 ((op >> 14) & 31)
#define RS2 (op & 31)
+#define REG(x) *m_regs[x]
+#define RDREG *m_regs[RD]
+#define RS1REG *m_regs[RS1]
+#define RS2REG *m_regs[RS2]
+#define SET_RDREG(x) if(RD) { RDREG = x; }
+#define ADDRESS (OPIMM ? (RS1REG + SIMM13) : (RS1REG + RS2REG))
+
+#define PC m_pc
+#define nPC m_npc
+
#endif // __MB86901_DEFS_H__ \ No newline at end of file
diff --git a/src/mame/drivers/sun4.cpp b/src/mame/drivers/sun4.cpp
index 7be91666afa..b9c956a8b04 100644
--- a/src/mame/drivers/sun4.cpp
+++ b/src/mame/drivers/sun4.cpp
@@ -388,20 +388,125 @@
#include "emu.h"
#include "cpu/sparc/sparc.h"
+#define ENA_NOTBOOT 0x80
+#define ENA_SDVMA 0x20
+#define ENA_CACHE 0x10
+#define ENA_RESET 0x04
+#define ENA_DIAG 0x01
class sun4_state : public driver_device
{
public:
sun4_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag) ,
- m_maincpu(*this, "maincpu") { }
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_rom(*this, "user1")
+ , m_rom_ptr(nullptr)
+ , m_system_enable(0)
+ {
+ }
virtual void machine_reset() override;
- required_device<cpu_device> m_maincpu;
+ virtual void machine_start() override;
+
+ DECLARE_READ32_MEMBER( sun4_mmu_r );
+ DECLARE_WRITE32_MEMBER( sun4_mmu_w );
+
+protected:
+
+ required_device<mb86901_device> m_maincpu;
+ required_memory_region m_rom;
+ UINT32 *m_rom_ptr;
+ UINT32 m_context;
+ UINT32 m_system_enable;
};
-static ADDRESS_MAP_START(sun4_mem, AS_PROGRAM, 32, sun4_state)
- AM_RANGE(0x00000000, 0x0007ffff) AM_ROM AM_REGION("user1", 0)
+READ32_MEMBER( sun4_state::sun4_mmu_r )
+{
+ UINT8 asi = m_maincpu->fetch_asi();
+
+ if (asi == 2 && !space.debugger_access())
+ {
+ switch (offset >> 26)
+ {
+ case 3: // context reg
+ return m_context;
+
+ case 4: // system enable reg
+ return m_system_enable;
+
+ case 6: // bus error register
+ return 0;
+
+ case 8: // (d-)cache tags
+ printf("sun4: read dcache tags @ %x, PC = %x\n", offset, m_maincpu->pc());
+ return 0xffffffff;
+
+ case 9: // (d-)cache data
+ printf("sun4: read dcache data @ %x, PC = %x\n", offset, m_maincpu->pc());
+ return 0xffffffff;
+
+ case 0: // IDPROM - TODO: SPARCstation-1 does not have an ID prom and a timeout should occur.
+ default:
+ return 0;
+ }
+ }
+
+ if (!(m_system_enable & ENA_NOTBOOT))
+ {
+ return m_rom_ptr[offset & 0x1ffff];
+ }
+
+ return 0;
+}
+
+WRITE32_MEMBER( sun4_state::sun4_mmu_w )
+{
+ UINT8 asi = m_maincpu->fetch_asi();
+
+ if (asi == 2)
+ {
+ switch (offset >> 26)
+ {
+ case 3: // context reg
+ m_context = (UINT8)data;
+ return;
+
+ case 4: // system enable reg
+ m_system_enable = (UINT8)data;
+ return;
+
+ case 8: // cache tags3
+ printf("sun4: %08x to cache tags @ %x, PC = %x\n", data, offset, m_maincpu->pc());
+ return;
+
+ case 9: // cache data
+ printf("sun4: %08x to cache data @ %x, PC = %x\n", data, offset, m_maincpu->pc());
+ return;
+
+ case 0: // IDPROM
+ default:
+ return;
+ }
+ }
+}
+
+static ADDRESS_MAP_START(sun4_asi8, AS_USER_INSN, 32, sun4_state)
+ AM_RANGE(0x00000000, 0xefffffff) AM_READWRITE( sun4_mmu_r, sun4_mmu_w )
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(sun4_asi9, AS_SUPER_INSN, 32, sun4_state)
+ AM_RANGE(0x00000000, 0xefffffff) AM_READWRITE( sun4_mmu_r, sun4_mmu_w )
+ AM_RANGE(0xffe80000, 0xffefffff) AM_ROM AM_REGION("user1", 0)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(sun4_asi10, AS_USER_DATA, 32, sun4_state)
+ AM_RANGE(0x00000000, 0xefffffff) AM_READWRITE( sun4_mmu_r, sun4_mmu_w )
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(sun4_asi11, AS_SUPER_DATA, 32, sun4_state)
+ AM_RANGE(0x00000000, 0xefffffff) AM_READWRITE( sun4_mmu_r, sun4_mmu_w )
+ AM_RANGE(0xffe80000, 0xffefffff) AM_ROM AM_REGION("user1", 0)
ADDRESS_MAP_END
/* Input ports */
@@ -413,11 +518,18 @@ void sun4_state::machine_reset()
{
}
+void sun4_state::machine_start()
+{
+ m_rom_ptr = (UINT32 *)m_rom->base();
+}
static MACHINE_CONFIG_START( sun4, sun4_state )
/* basic machine hardware */
- MCFG_CPU_ADD("maincpu", MB86901, 16670000) // SPARC32 on real system
- MCFG_CPU_PROGRAM_MAP(sun4_mem)
+ MCFG_CPU_ADD("maincpu", MB86901, 16670000)
+ MCFG_DEVICE_ADDRESS_MAP(AS_USER_INSN, sun4_asi8)
+ MCFG_DEVICE_ADDRESS_MAP(AS_SUPER_INSN, sun4_asi9)
+ MCFG_DEVICE_ADDRESS_MAP(AS_USER_DATA, sun4_asi10)
+ MCFG_DEVICE_ADDRESS_MAP(AS_SUPER_DATA, sun4_asi11)
MACHINE_CONFIG_END
/*