diff options
-rw-r--r-- | scripts/src/cpu.lua | 2 | ||||
-rw-r--r-- | src/devices/cpu/sparc/mb86901.cpp | 771 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparc.h | 53 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparcdasm.cpp | 23 | ||||
-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.cpp | 126 |
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 /* |