diff options
Diffstat (limited to 'src/devices/cpu/sparc')
-rw-r--r-- | src/devices/cpu/sparc/sparc.cpp (renamed from src/devices/cpu/sparc/mb86901.cpp) | 3281 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparc.h | 245 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparc_intf.h | 2 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparcdasm.cpp | 126 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparcdasm.h | 14 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparcdefs.h | 129 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparcv8ops.ipp | 293 | ||||
-rw-r--r-- | src/devices/cpu/sparc/ss1fcode.ipp | 8 |
8 files changed, 2256 insertions, 1842 deletions
diff --git a/src/devices/cpu/sparc/mb86901.cpp b/src/devices/cpu/sparc/sparc.cpp index 809df3db8f3..9bdd1bfbad5 100644 --- a/src/devices/cpu/sparc/mb86901.cpp +++ b/src/devices/cpu/sparc/sparc.cpp @@ -2,11 +2,8 @@ // copyright-holders:Ryan Holtz //================================================================ // -// mb86901.cpp - Emulation for the Fujitsu MB86901 / LSI L64801 -// processors. Both chips are identical both -// electrically and functionally, and implement -// the integer instructions in a SPARC v7 -// compatible instruction set. +// sparc.cpp - Emulation for the SPARCv7/v8 line of +// processors. // // Notes: // - The CPU core implementation has been simplified @@ -16,10 +13,10 @@ // ever be. // // To-Do: -// - Ops: FBFcc, LDF, STF // - Test: SPARCv8 ops are untested -// - FPU support +// - Extended-precision FPU support // - Coprocessor support +// - Finish SPARClite peripherals // //================================================================ @@ -27,34 +24,145 @@ #include "sparc.h" #include "sparcdefs.h" -#include "debugger.h" - - -DEFINE_DEVICE_TYPE(MB86901, mb86901_device, "mb86901", "Fujitsu MB86901") - -const int mb86901_device::NWINDOWS = 7; +#include "softfloat3/source/include/softfloat.h" + +#define LOG_BIU_CTRL (1U << 1) +#define LOG_LOCK_CTRL (1U << 2) +#define LOG_LOCK_CTRL_SAVE (1U << 3) +#define LOG_CACHE_STATUS (1U << 4) +#define LOG_RESTORE_LOCK_CTRL (1U << 5) +#define LOG_SYSTEM_CTRL (1U << 6) +#define LOG_SAME_PAGE_MASK (1U << 7) +#define LOG_ADDR_RANGE (1U << 8) +#define LOG_ADDR_MASK (1U << 9) +#define LOG_WAIT_STATE (1U << 10) +#define LOG_TIMER (1U << 11) +#define LOG_TIMER_PRELOAD (1U << 12) +#define LOG_UNMAPPED (1U << 13) +#define LOG_ICACHE_LOCK (1U << 14) +#define LOG_ICACHE_TAG (1U << 15) +#define LOG_ICACHE_DATA (1U << 16) +#define LOG_DCACHE_LOCK (1U << 17) +#define LOG_DCACHE_TAG (1U << 18) +#define LOG_DCACHE_DATA (1U << 19) + +#define VERBOSE (0) +#include "logmacro.h" + +DEFINE_DEVICE_TYPE(SPARCV7, sparcv7_device, "sparcv7", "Sun SPARC v7") +DEFINE_DEVICE_TYPE(SPARCV8, sparcv8_device, "sparcv8", "Sun SPARC v8") +DEFINE_DEVICE_TYPE(MB86930, mb86930_device, "mb86930", "Fujitsu MB86930 'SPARClite'") #if LOG_FCODES #include "ss1fcode.ipp" #endif -#if SPARCV8 -#include "sparcv8ops.ipp" -#endif +namespace +{ +const sparc_disassembler::asi_desc_map::value_type mb86930_asi_desc[] = +{ + { 0x01, { nullptr, "Control Registers" } }, + { 0x02, { nullptr, "Instruction Cache Lock" } }, + { 0x03, { nullptr, "Data Cache Lock" } }, + { 0x08, { nullptr, "User Instruction" } }, + { 0x09, { nullptr, "Supervisor Instruction" } }, + { 0x0a, { nullptr, "User Data" } }, + { 0x0b, { nullptr, "Supervisor Data" } }, + { 0x0c, { nullptr, "Instruction Cache Tag RAM" } }, + { 0x0d, { nullptr, "Instruction Cache Data RAM" } }, + { 0x0e, { nullptr, "Data Cache Tag RAM" } }, + { 0x0f, { nullptr, "Data Cache Data RAM" } } +}; +} // anonymous namespace + +const char *const sparc_base_device::DEFAULT_ASI_NAMES[16] = +{ + "asi0", "asi1", "asi2", "asi3", "asi4", "asi5", "asi6", "asi7", + "asi8", "asi9", "asi10", "asi11", "asi12", "asi13", "asi14", "asi15" +}; //------------------------------------------------- -// mb86901_device - constructor +// sparc_base_device - constructor //------------------------------------------------- -mb86901_device::mb86901_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : cpu_device(mconfig, MB86901, tag, owner, clock) +sparc_base_device::sparc_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : cpu_device(mconfig, type, tag, owner, clock) , m_mmu(*this, finder_base::DUMMY_TAG) { - m_default_config = address_space_config("program", ENDIANNESS_BIG, 32, 32); + m_debugger_config = address_space_config("debug", ENDIANNESS_BIG, 32, 32); + + if (type != MB86930) + { + for (int i = 0; i < 0x10; i++) + { + m_asi_config[i] = address_space_config(DEFAULT_ASI_NAMES[i], ENDIANNESS_BIG, 32, 32); + } + } +} + + +//------------------------------------------------- +// sparcv7_device - constructors +//------------------------------------------------- + +sparcv7_device::sparcv7_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : sparcv7_device(mconfig, SPARCV7, tag, owner, clock) +{ +} + +sparcv7_device::sparcv7_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : sparc_base_device(mconfig, type, tag, owner, clock) +{ +} + + +//------------------------------------------------- +// sparcv8_device - constructor +//------------------------------------------------- + +sparcv8_device::sparcv8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : sparcv8_device(mconfig, SPARCV8, tag, owner, clock) +{ } -void mb86901_device::device_start() +sparcv8_device::sparcv8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : sparc_base_device(mconfig, type, tag, owner, clock) +{ +} + + +//------------------------------------------------- +// mb86930_device - constructor +//------------------------------------------------- + +mb86930_device::mb86930_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : sparcv8_device(mconfig, MB86930, tag, owner, clock) + , m_cs_r(*this, 0) + , m_cs_w(*this) +{ + m_asi_config[0x00] = address_space_config("debugger", ENDIANNESS_BIG, 32, 32); + m_asi_config[0x01] = address_space_config("system_control", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::control_map), this)); + m_asi_config[0x02] = address_space_config("icache_lock", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::icache_lock_map), this)); + m_asi_config[0x03] = address_space_config("dcache_lock", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::dcache_lock_map), this)); + m_asi_config[0x04] = address_space_config("asi4", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::mmu_map<4>), this)); + m_asi_config[0x05] = address_space_config("asi5", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::mmu_map<5>), this)); + m_asi_config[0x06] = address_space_config("asi6", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::mmu_map<6>), this)); + m_asi_config[0x07] = address_space_config("asi7", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::mmu_map<7>), this)); + m_asi_config[0x08] = address_space_config("user_insn", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::mmu_map<8>), this)); + m_asi_config[0x09] = address_space_config("super_insn", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::mmu_map<9>), this)); + m_asi_config[0x0a] = address_space_config("user_data", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::mmu_map<10>), this)); + m_asi_config[0x0b] = address_space_config("super_data", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::mmu_map<11>), this)); + m_asi_config[0x0c] = address_space_config("icache_tag", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::icache_tag_map), this)); + m_asi_config[0x0d] = address_space_config("icache_data", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::icache_data_map), this)); + m_asi_config[0x0e] = address_space_config("dcache_tag", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::dcache_tag_map), this)); + m_asi_config[0x0f] = address_space_config("dcache_data", ENDIANNESS_BIG, 32, 32, 0, address_map_constructor(FUNC(mb86930_device::dcache_data_map), this)); + + add_asi_desc([](sparc_disassembler *dasm) { dasm->add_asi_desc(mb86930_asi_desc); }); +} + + +void sparc_base_device::device_start() { #if LOG_FCODES m_ss1_fcode_table.clear(); @@ -138,8 +246,13 @@ void mb86901_device::device_start() m_log_fcodes = false; #endif + NWINDOWS = 7; + PSR = 0; + m_ver = 0; + m_impl = 0; + m_bp_reset_in = false; - m_bp_fpu_present = false; + m_bp_fpu_present = true; m_bp_cp_present = false; m_pb_error = false; m_pb_block_ldst_byte = false; @@ -147,13 +260,22 @@ void mb86901_device::device_start() m_bp_irl = 0; m_irq_state = 0; - memset(m_dbgregs, 0, 24 * sizeof(uint32_t)); + for (int i = 0; i < 0x20; i++) + { + if (i > 0 && i < 0x10) + { + continue; + } + space(i).specific(m_asi[i]); + } + + std::fill_n(m_dbgregs, std::size(m_dbgregs), 0); - memset(m_illegal_instruction_asr, 0, 32 * sizeof(bool)); - memset(m_privileged_asr, 1, 32 * sizeof(bool)); + std::fill_n(m_illegal_instruction_asr, std::size(m_illegal_instruction_asr), false); + std::fill_n(m_privileged_asr, std::size(m_privileged_asr), true); m_privileged_asr[0] = false; - memset(m_alu_setcc, 0, 64 * sizeof(bool)); + std::fill_n(m_alu_setcc, std::size(m_alu_setcc), false); m_alu_setcc[OP3_ADDCC] = true; m_alu_setcc[OP3_ANDCC] = true; m_alu_setcc[OP3_ORCC] = true; @@ -169,14 +291,8 @@ void mb86901_device::device_start() m_alu_setcc[OP3_TADDCCTV] = true; m_alu_setcc[OP3_TSUBCCTV] = true; m_alu_setcc[OP3_MULSCC] = true; -#if SPARCV8 - m_alu_setcc[OP3_UMULCC] = true; - m_alu_setcc[OP3_SMULCC] = true; - m_alu_setcc[OP3_UDIVCC] = true; - m_alu_setcc[OP3_SDIVCC] = true; -#endif - memset(m_alu_op3_assigned, 0, 64 * sizeof(bool)); + std::fill_n(m_alu_op3_assigned, std::size(m_alu_op3_assigned), false); m_alu_op3_assigned[OP3_ADD] = true; m_alu_op3_assigned[OP3_AND] = true; m_alu_op3_assigned[OP3_OR] = true; @@ -223,18 +339,8 @@ void mb86901_device::device_start() m_alu_op3_assigned[OP3_IFLUSH] = true; m_alu_op3_assigned[OP3_SAVE] = true; m_alu_op3_assigned[OP3_RESTORE] = true; -#if SPARCV8 - m_alu_op3_assigned[OP3_UMUL] = true; - m_alu_op3_assigned[OP3_SMUL] = true; - m_alu_op3_assigned[OP3_UDIV] = true; - m_alu_op3_assigned[OP3_SDIV] = true; - m_alu_op3_assigned[OP3_UMULCC] = true; - m_alu_op3_assigned[OP3_SMULCC] = true; - m_alu_op3_assigned[OP3_UDIVCC] = true; - m_alu_op3_assigned[OP3_SDIVCC] = true; -#endif - memset(m_ldst_op3_assigned, 0, 64 * sizeof(bool)); + std::fill_n(m_ldst_op3_assigned, std::size(m_ldst_op3_assigned), false); m_ldst_op3_assigned[OP3_LD] = true; m_ldst_op3_assigned[OP3_LDUB] = true; m_ldst_op3_assigned[OP3_LDUH] = true; @@ -264,17 +370,6 @@ void mb86901_device::device_start() m_ldst_op3_assigned[OP3_STFSR] = true; m_ldst_op3_assigned[OP3_STDFQ] = true; m_ldst_op3_assigned[OP3_STDFPR] = true; -#if SPARCV8 - m_ldst_op3_assigned[OP3_SWAP] = true; - m_ldst_op3_assigned[OP3_SWAPA] = true; - m_ldst_op3_assigned[OP3_LDCPR] = true; - m_ldst_op3_assigned[OP3_LDCSR] = true; - m_ldst_op3_assigned[OP3_LDDCPR] = true; - m_ldst_op3_assigned[OP3_STCPR] = true; - m_ldst_op3_assigned[OP3_STCSR] = true; - m_ldst_op3_assigned[OP3_STDCQ] = true; - m_ldst_op3_assigned[OP3_STDCPR] = true; -#endif // register our state for the debugger state_add(STATE_GENPC, "GENPC", m_pc).noshow(); @@ -289,31 +384,18 @@ void mb86901_device::device_start() state_add(SPARC_ANNUL, "ANNUL", m_no_annul).formatstr("%01u"); 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++) - { - regname[1] = 0x30 + i; - state_add(SPARC_G0 + i, regname, m_r[i]).formatstr("%08X"); - } - regname[0] = 'o'; + state_add(SPARC_G0 + i, util::string_format("g%d", i).c_str(), m_r[i]).formatstr("%08X"); + for (int i = 0; i < 8; i++) - { - regname[1] = 0x30 + i; - state_add(SPARC_O0 + i, regname, m_dbgregs[i]).formatstr("%08X"); - } + state_add(SPARC_O0 + i, util::string_format("o%d", i).c_str(), m_dbgregs[i]).formatstr("%08X"); - regname[0] = 'l'; for (int i = 0; i < 8; i++) - { - regname[1] = 0x30 + i; - state_add(SPARC_L0 + i, regname, m_dbgregs[8+i]).formatstr("%08X"); - } - regname[0] = 'i'; + state_add(SPARC_L0 + i, util::string_format("l%d", i).c_str(), m_dbgregs[8+i]).formatstr("%08X"); + for (int i = 0; i < 8; i++) - { - regname[1] = 0x30 + i; - state_add(SPARC_I0 + i, regname, m_dbgregs[16+i]).formatstr("%08X"); - } + state_add(SPARC_I0 + i, util::string_format("i%d", i).c_str(), m_dbgregs[16+i]).formatstr("%08X"); state_add(SPARC_EC, "EC", m_ec).formatstr("%1u"); state_add(SPARC_EF, "EF", m_ef).formatstr("%1u"); @@ -321,13 +403,13 @@ void mb86901_device::device_start() state_add(SPARC_PIL, "PIL", m_pil).formatstr("%2d"); state_add(SPARC_S, "S", m_s).formatstr("%1u"); state_add(SPARC_PS, "PS", m_ps).formatstr("%1u"); + state_add(SPARC_FSR, "FSR", m_fsr).formatstr("%08X"); - char rname[5]; - for (int i = 0; i < 120; i++) - { - sprintf(rname, "r%d", i); - state_add(SPARC_R0 + i, rname, m_r[i]).formatstr("%08X"); - } + for (int i = 0; i < 32; i++) + state_add(SPARC_F0 + i, util::string_format("f%d", i).c_str(), m_fpr[i]); + + for (int i = 0; i < 136; i++) + state_add(SPARC_R0 + i, util::string_format("r%d", i).c_str(), m_r[i]).formatstr("%08X"); save_item(NAME(m_r)); save_item(NAME(m_fpr)); @@ -355,17 +437,14 @@ void mb86901_device::device_start() save_item(NAME(m_illegal_instruction)); save_item(NAME(m_mem_address_not_aligned)); save_item(NAME(m_fp_disabled)); - save_item(NAME(m_fp_exception)); save_item(NAME(m_cp_disabled)); + save_item(NAME(m_fp_exception)); + save_item(NAME(m_fp_exception_pending)); + save_item(NAME(m_fpr_pending)); + save_item(NAME(m_pending_fpr)); save_item(NAME(m_cp_exception)); - save_item(NAME(m_unimplemented_FLUSH)); - save_item(NAME(m_r_register_access_error)); - save_item(NAME(m_instruction_access_error)); save_item(NAME(m_instruction_access_exception)); - save_item(NAME(m_data_access_error)); - save_item(NAME(m_data_store_error)); save_item(NAME(m_data_access_exception)); - save_item(NAME(m_division_by_zero)); save_item(NAME(m_trap_instruction)); save_item(NAME(m_window_underflow)); save_item(NAME(m_window_overflow)); @@ -389,13 +468,12 @@ void mb86901_device::device_start() save_item(NAME(m_alu_op3_assigned)); save_item(NAME(m_ldst_op3_assigned)); save_item(NAME(m_alu_setcc)); + save_item(NAME(m_nwindows)); save_item(NAME(m_privileged_asr)); save_item(NAME(m_illegal_instruction_asr)); save_item(NAME(m_mae)); save_item(NAME(m_no_annul)); save_item(NAME(m_hold_bus)); - save_item(NAME(m_icount)); - save_item(NAME(m_stashed_icount)); save_item(NAME(m_insn_space)); save_item(NAME(m_data_space)); @@ -413,58 +491,67 @@ void mb86901_device::device_start() } -void mb86901_device::device_stop() +void sparc_base_device::device_resolve_objects() { + if (m_mmu.found()) + m_mmu->set_host(this); } -void mb86901_device::device_resolve_objects() +void sparc_base_device::device_reset() { - m_mmu->set_host(this); -} - -void mb86901_device::device_reset() -{ - m_trap = 0; + m_trap = false; m_tt = 0; m_ticc_trap_type = 0; - m_privileged_instruction = 0; - m_illegal_instruction = 0; - m_mem_address_not_aligned = 0; - m_fp_disabled = 0; - m_cp_disabled = 0; - m_instruction_access_exception = 0; - m_trap_instruction = 0; - m_window_underflow = 0; - m_window_overflow = 0; - m_tag_overflow = 0; - m_reset_mode = 1; - m_reset_trap = 0; - m_execute_mode = 0; - m_error_mode = 0; + m_interrupt_level = 0; + m_privileged_instruction = false; + m_illegal_instruction = false; + m_mem_address_not_aligned = false; + m_fp_disabled = false; + m_cp_disabled = false; + m_fp_exception = false; + m_fp_exception_pending = false; + m_fpr_pending = 0; + m_pending_fpr = std::size(m_fpr); + m_cp_exception = false; + m_instruction_access_exception = false; + m_data_access_exception = false; + m_trap_instruction = false; + m_window_underflow = false; + m_window_overflow = false; + m_tag_overflow = false; + m_reset_mode = true; + m_reset_trap = false; + m_execute_mode = false; + m_error_mode = false; m_fpu_sequence_err = 0; m_cp_sequence_err = 0; m_bp_irl = 0; m_irq_state = 0; - m_stashed_icount = -1; - MAE = false; HOLD_BUS = false; m_no_annul = true; PC = 0; nPC = 4; - memset(m_r, 0, sizeof(uint32_t) * 120); - memset(m_fpr, 0, sizeof(uint32_t) * 32); + std::fill_n(m_r, std::size(m_r), 0); + std::fill_n(m_fpr, std::size(m_fpr), 0); WIM = 0; TBR = 0; Y = 0; - PSR = PSR_S_MASK | PSR_PS_MASK; + PSR = (PSR & PSR_ZERO_MASK) | (PSR_S_MASK | PSR_PS_MASK); m_s = true; + m_ps = true; m_data_space = 11; + m_pil = 0; + m_et = false; + m_icc = 0; + m_ec = false; + m_ef = false; + m_cwp = 0; for (int i = 0; i < 8; i++) { @@ -481,59 +568,540 @@ void mb86901_device::device_reset() #endif } +void sparcv8_device::device_start() +{ + sparc_base_device::device_start(); + + save_item(NAME(m_unimplemented_FLUSH)); + save_item(NAME(m_r_register_access_error)); + save_item(NAME(m_instruction_access_error)); + save_item(NAME(m_data_access_error)); + save_item(NAME(m_data_store_error)); + save_item(NAME(m_division_by_zero)); + + m_alu_setcc[OP3_UMULCC] = true; + m_alu_setcc[OP3_SMULCC] = true; + m_alu_setcc[OP3_UDIVCC] = true; + m_alu_setcc[OP3_SDIVCC] = true; + + m_alu_op3_assigned[OP3_UMUL] = true; + m_alu_op3_assigned[OP3_SMUL] = true; + m_alu_op3_assigned[OP3_UDIV] = true; + m_alu_op3_assigned[OP3_SDIV] = true; + m_alu_op3_assigned[OP3_UMULCC] = true; + m_alu_op3_assigned[OP3_SMULCC] = true; + m_alu_op3_assigned[OP3_UDIVCC] = true; + m_alu_op3_assigned[OP3_SDIVCC] = true; + + m_ldst_op3_assigned[OP3_SWAP] = true; + m_ldst_op3_assigned[OP3_SWAPA] = true; + m_ldst_op3_assigned[OP3_LDCPR] = true; + m_ldst_op3_assigned[OP3_LDCSR] = true; + m_ldst_op3_assigned[OP3_LDDCPR] = true; + m_ldst_op3_assigned[OP3_STCPR] = true; + m_ldst_op3_assigned[OP3_STCSR] = true; + m_ldst_op3_assigned[OP3_STDCQ] = true; + m_ldst_op3_assigned[OP3_STDCPR] = true; +} + +void sparcv8_device::device_reset() +{ + sparc_base_device::device_reset(); + + m_unimplemented_FLUSH = 0; + m_r_register_access_error = 0; + m_instruction_access_error = 0; + m_data_access_error = 0; + m_data_store_error = 0; + m_division_by_zero = 0; +} + //------------------------------------------------- -// device_post_load - update register pointers -// after loading a savestate +// mb86930_device - initializers //------------------------------------------------- -void mb86901_device::device_post_load() +void mb86930_device::device_start() { - update_gpr_pointers(); + sparcv8_device::device_start(); + + NWINDOWS = 8; + PSR |= 2 << PSR_VER_SHIFT; + m_ver = 2; + + m_bp_cp_present = false; + m_bp_fpu_present = false; + + m_alu_setcc[OP3_DIVSCC] = true; + + m_alu_op3_assigned[OP3_DIVSCC] = true; + m_alu_op3_assigned[OP3_SCAN] = true; + + save_item(NAME(m_ssctrl)); + save_item(NAME(m_spmr)); + save_item(NAME(m_spmr_mask)); + save_item(NAME(m_arsr)); + save_item(NAME(m_amr)); + save_item(NAME(m_wssr)); + save_item(NAME(m_last_masked_addr)); + + std::fill_n(&m_arsr[0], 6, 0); + std::fill_n(&m_amr[0], 6, 0); +} + +void mb86930_device::device_reset() +{ + sparcv8_device::device_reset(); + + m_ssctrl = 0x08; + m_spmr = 0; + m_spmr_mask = ~0ULL; + m_last_masked_addr = 0ULL; + + std::fill_n(&m_wssr[0], 3, 0); + m_wssr[0] = 0x1ffd << 6; + + m_arsr[0] = (9 << 23); + m_amr[0] = (0x1f << 1); + + update_addr_masks(); + update_wait_states(); } //------------------------------------------------- -// memory_space_config - return the configuration -// of the specified address space, or nullptr if -// the space doesn't exist +// mb86930_device - internal maps //------------------------------------------------- -device_memory_interface::space_config_vector mb86901_device::memory_space_config() const +void mb86930_device::control_map(address_map &map) { - space_config_vector config_vector; - config_vector.push_back(std::make_pair(AS_PROGRAM, &m_default_config)); - return config_vector; + map(0x00000000, 0x00000003).rw(FUNC(mb86930_device::biu_ctrl_r), FUNC(mb86930_device::biu_ctrl_w)); + map(0x00000004, 0x00000007).rw(FUNC(mb86930_device::lock_ctrl_r), FUNC(mb86930_device::lock_ctrl_w)); + map(0x00000008, 0x0000000b).rw(FUNC(mb86930_device::lock_ctrl_save_r), FUNC(mb86930_device::lock_ctrl_save_w)); + map(0x0000000c, 0x0000000f).rw(FUNC(mb86930_device::cache_status_r), FUNC(mb86930_device::cache_status_w)); + map(0x00000010, 0x00000013).rw(FUNC(mb86930_device::restore_lock_ctrl_r), FUNC(mb86930_device::restore_lock_ctrl_w)); + map(0x00000080, 0x00000083).rw(FUNC(mb86930_device::system_support_ctrl_r), FUNC(mb86930_device::system_support_ctrl_w)); + map(0x00000120, 0x00000123).rw(FUNC(mb86930_device::same_page_mask_r), FUNC(mb86930_device::same_page_mask_w)); + map(0x00000124, 0x00000137).rw(FUNC(mb86930_device::addr_range_spec_r), FUNC(mb86930_device::addr_range_spec_w)); + map(0x00000140, 0x00000157).rw(FUNC(mb86930_device::addr_mask_r), FUNC(mb86930_device::addr_mask_w)); + map(0x00000160, 0x0000016b).rw(FUNC(mb86930_device::wait_specifier_r), FUNC(mb86930_device::wait_specifier_w)); + map(0x00000174, 0x00000177).rw(FUNC(mb86930_device::timer_r), FUNC(mb86930_device::timer_w)); + map(0x00000178, 0x0000017b).rw(FUNC(mb86930_device::timer_preload_r), FUNC(mb86930_device::timer_preload_w)); +} + +void mb86930_device::icache_lock_map(address_map &map) +{ + map(0x00000000, 0xffffffff).rw(FUNC(mb86930_device::icache_lock_r), FUNC(mb86930_device::icache_lock_w)); +} + +void mb86930_device::dcache_lock_map(address_map &map) +{ + map(0x00000000, 0xffffffff).rw(FUNC(mb86930_device::dcache_lock_r), FUNC(mb86930_device::dcache_lock_w)); +} + +void mb86930_device::icache_tag_map(address_map &map) +{ + map(0x00000000, 0xffffffff).rw(FUNC(mb86930_device::icache_tag_r), FUNC(mb86930_device::icache_tag_w)); +} + +void mb86930_device::icache_data_map(address_map &map) +{ + map(0x00000000, 0xffffffff).rw(FUNC(mb86930_device::icache_data_r), FUNC(mb86930_device::icache_data_w)); +} + +void mb86930_device::dcache_tag_map(address_map &map) +{ + map(0x00000000, 0xffffffff).rw(FUNC(mb86930_device::dcache_tag_r), FUNC(mb86930_device::dcache_tag_w)); +} + +void mb86930_device::dcache_data_map(address_map &map) +{ + map(0x00000000, 0xffffffff).rw(FUNC(mb86930_device::dcache_data_r), FUNC(mb86930_device::dcache_data_w)); +} + + +//------------------------------------------------- +// mb86930_device - cache control (TODO) +//------------------------------------------------- + +uint32_t mb86930_device::icache_lock_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_ICACHE_LOCK, "%s: icache_lock_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::icache_lock_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_ICACHE_LOCK, "%s: icache_lock_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::dcache_lock_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_DCACHE_LOCK, "%s: dcache_lock_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::dcache_lock_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_DCACHE_LOCK, "%s: dcache_lock_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::icache_tag_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_ICACHE_TAG, "%s: icache_tag_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::icache_tag_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_ICACHE_TAG, "%s: icache_tag_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::icache_data_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_ICACHE_DATA, "%s: icache_data_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::icache_data_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_ICACHE_DATA, "%s: icache_data_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::dcache_tag_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_DCACHE_TAG, "%s: dcache_tag_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::dcache_tag_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_DCACHE_TAG, "%s: dcache_tag_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::dcache_data_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_DCACHE_DATA, "%s: dcache_data_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::dcache_data_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_DCACHE_DATA, "%s: dcache_data_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +//------------------------------------------------- +// mb86930_device - MMU map and handlers +//------------------------------------------------- + +template <uint8_t Asi> +void mb86930_device::mmu_map(address_map &map) +{ + map(0x00000000, 0xffffffff).rw(FUNC(mb86930_device::mmu_r<Asi>), FUNC(mb86930_device::mmu_w<Asi>)); +} + +template <uint8_t Asi> +uint32_t mb86930_device::mmu_r(offs_t offset, uint32_t mem_mask) +{ + const uint64_t full_addr = ((uint64_t)Asi << 30) | offset; + + const uint64_t masked_addr = full_addr & m_spmr_mask; + const bool is_same_page = (masked_addr == m_last_masked_addr); + m_last_masked_addr = masked_addr; + + for (int cs = 0; cs < 6; cs++) + { + if ((full_addr & m_full_masks[cs]) == m_full_ranges[cs]) + { + m_icount -= is_same_page ? m_same_page_waits[cs] : m_other_page_waits[cs]; + return m_cs_r[cs](offset, mem_mask); + } + } + LOGMASKED(LOG_UNMAPPED, "%s: mmu_r, unmapped access: ASI %d, address %08x & %08x\n", machine().describe_context(), Asi, offset << 2, mem_mask); + return 0; +} + +template <uint8_t Asi> void mb86930_device::mmu_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + const uint64_t full_addr = ((uint64_t)Asi << 30) | offset; + + const uint64_t masked_addr = full_addr & m_spmr_mask; + const bool is_same_page = (masked_addr == m_last_masked_addr); + m_last_masked_addr = masked_addr; + + for (int cs = 0; cs < 6; cs++) + { + if ((full_addr & m_full_masks[cs]) == m_full_ranges[cs]) + { + m_icount -= is_same_page ? m_same_page_waits[cs] : m_other_page_waits[cs]; + m_cs_w[cs](offset, data, mem_mask); + return; + } + } + LOGMASKED(LOG_UNMAPPED, "%s: mmu_w, unmapped access: ASI %d, address %08x = %08x & %08x\n", machine().describe_context(), Asi, offset << 2, data, mem_mask); +} + + +//------------------------------------------------- +// mb86930_device - system control handlers +//------------------------------------------------- + +void mb86930_device::update_addr_masks() +{ + for (int i = 0; i < 6; i++) + { + m_full_masks[i] = ~(((uint64_t)m_amr[i] << 7) | 0xff); + m_full_ranges[i] = ((uint64_t)m_arsr[i] << 7) & m_full_masks[i]; + } +} + +void mb86930_device::update_wait_states() +{ + for (int i = 0; i < 6; i++) + { + const uint8_t shift = (i & 1) ? 19 : 6; + const bool enable = bool(BIT(m_wssr[i >> 1], shift + 2)); + const bool single = bool(BIT(m_wssr[i >> 1], shift + 1)); + //const bool override = bool(BIT(m_wssr[i >> 1], shift + 0)); + + if (BIT(m_ssctrl, 3) && !single && enable) + { + const uint8_t count1 = ((m_wssr[i >> 1] >> (shift + 8)) & 0x1f) + 1; + const uint8_t count2 = ((m_wssr[i >> 1] >> (shift + 3)) & 0x1f) + 1; + m_other_page_waits[i] = count1; + m_same_page_waits[i] = BIT(m_ssctrl, 5) ? count2 : count1; + } + else + { + m_other_page_waits[i] = 0; + m_same_page_waits[i] = 0; + } + } +} + +uint32_t mb86930_device::biu_ctrl_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_BIU_CTRL, "%s: biu_ctrl_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::biu_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_BIU_CTRL, "%s: biu_ctrl_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::lock_ctrl_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_LOCK_CTRL, "%s: lock_ctrl_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::lock_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_LOCK_CTRL, "%s: lock_ctrl_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::lock_ctrl_save_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_LOCK_CTRL_SAVE, "%s: lock_ctrl_save_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::lock_ctrl_save_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_LOCK_CTRL_SAVE, "%s: lock_ctrl_save_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::cache_status_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_CACHE_STATUS, "%s: cache_status_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::cache_status_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_CACHE_STATUS, "%s: cache_status_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::restore_lock_ctrl_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_RESTORE_LOCK_CTRL, "%s: restore_lock_ctrl_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::restore_lock_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_RESTORE_LOCK_CTRL, "%s: restore_lock_ctrl_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::system_support_ctrl_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = m_ssctrl; + LOGMASKED(LOG_SYSTEM_CTRL, "%s: system_ctrl_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::system_support_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_SYSTEM_CTRL, "%s: system_ctrl_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); + COMBINE_DATA(&m_ssctrl); + update_wait_states(); +} + + +uint32_t mb86930_device::same_page_mask_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = m_spmr; + LOGMASKED(LOG_SAME_PAGE_MASK, "%s: same_page_mask_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::same_page_mask_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_SAME_PAGE_MASK, "%s: same_page_mask_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); + COMBINE_DATA(&m_spmr); + m_spmr_mask = ~(((uint64_t)m_spmr << 7) | 0xff); +} + + +uint32_t mb86930_device::addr_range_spec_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = m_arsr[offset + 1]; + LOGMASKED(LOG_ADDR_RANGE, "%s: addr_range_spec_r[%d]: %08x & %08x\n", machine().describe_context(), offset + 1, data, mem_mask); + return data; +} + +void mb86930_device::addr_range_spec_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_ADDR_RANGE, "%s: addr_range_spec_w[%d]: %08x & %08x\n", machine().describe_context(), offset + 1, data, mem_mask); + COMBINE_DATA(&m_arsr[offset + 1]); + update_addr_masks(); +} + + +uint32_t mb86930_device::addr_mask_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = m_amr[offset]; + LOGMASKED(LOG_ADDR_MASK, "%s: addr_mask_r[%d]: %08x & %08x\n", machine().describe_context(), offset, data, mem_mask); + return data; +} + +void mb86930_device::addr_mask_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_ADDR_MASK, "%s: addr_mask_w[%d]: %08x & %08x\n", machine().describe_context(), offset, data, mem_mask); + COMBINE_DATA(&m_amr[offset]); + update_addr_masks(); +} + + +uint32_t mb86930_device::wait_specifier_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = m_wssr[offset]; + LOGMASKED(LOG_WAIT_STATE, "%s: wait_state_r[%d]: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::wait_specifier_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_WAIT_STATE, "%s: wait_state_w[%d]: %08x & %08x\n", machine().describe_context(), offset, data, mem_mask); + COMBINE_DATA(&m_wssr[offset]); + update_wait_states(); +} + + +uint32_t mb86930_device::timer_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_TIMER, "%s: timer_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::timer_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_TIMER, "%s: timer_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); +} + + +uint32_t mb86930_device::timer_preload_r(offs_t offset, uint32_t mem_mask) +{ + uint32_t data = 0; + LOGMASKED(LOG_TIMER_PRELOAD, "%s: timer_preload_r: %08x & %08x\n", machine().describe_context(), data, mem_mask); + return data; +} + +void mb86930_device::timer_preload_w(offs_t offset, uint32_t data, uint32_t mem_mask) +{ + LOGMASKED(LOG_TIMER_PRELOAD, "%s: timer_preload_w: %08x & %08x\n", machine().describe_context(), data, mem_mask); } //------------------------------------------------- -// read_sized_word - read a value from a given -// address space and address, shifting the data -// that is read into the appropriate location of -// a 32-bit word in a big-endian system. +// device_post_load - update register pointers +// after loading a savestate //------------------------------------------------- -uint32_t mb86901_device::read_sized_word(const uint8_t asi, const uint32_t address, const uint32_t mem_mask) +void sparc_base_device::device_post_load() +{ + update_gpr_pointers(); +} + +void mb86930_device::device_post_load() { - assert(asi < 0x20); // We do not currently support ASIs outside the range used by actual Sun machines. - return m_mmu->read_asi(asi, address >> 2, mem_mask); + sparcv8_device::device_post_load(); + update_addr_masks(); + update_wait_states(); } //------------------------------------------------- -// write_sized_word - write a value to a given -// address space and address, shifting the data -// that is written into the least significant -// bits as appropriate in order to write the -// value to a memory system with separate data -// size handlers +// memory_space_config - return the configuration +// of the specified address space, or nullptr if +// the space doesn't exist //------------------------------------------------- -void mb86901_device::write_sized_word(const uint8_t asi, const uint32_t address, const uint32_t data, const uint32_t mem_mask) +device_memory_interface::space_config_vector sparc_base_device::memory_space_config() const { - assert(asi < 0x20); // We do not currently support ASIs outside the range used by actual Sun machines. - m_mmu->write_asi(asi, address >> 2, data, mem_mask); + space_config_vector config_vector; + config_vector.push_back(std::make_pair(0, &m_debugger_config)); + for (int i = 0; i < 0x10; i++) + { + config_vector.push_back(std::make_pair(0x10 + i, &m_asi_config[i])); + } + return config_vector; +} + +inline uint32_t sparc_base_device::read_word(const uint8_t asi, const uint32_t address, const uint32_t mem_mask) +{ + assert(asi < 0x10); // We do not currently support ASIs outside the range used by actual Sun machines. + return m_asi[asi | 0x10].read_dword(address, mem_mask); +} + +inline void sparc_base_device::write_word(const uint8_t asi, const uint32_t address, const uint32_t data, const uint32_t mem_mask) +{ + assert(asi < 0x10); // We do not currently support ASIs outside the range used by actual Sun machines. + return m_asi[asi | 0x10].write_dword(address, data, mem_mask); } @@ -542,7 +1110,7 @@ void mb86901_device::write_sized_word(const uint8_t asi, const uint32_t address, // for the debugger //------------------------------------------------- -void mb86901_device::state_string_export(const device_state_entry &entry, std::string &str) const +void sparc_base_device::state_string_export(const device_state_entry &entry, std::string &str) const { switch (entry.index()) { @@ -592,13 +1160,29 @@ void mb86901_device::state_string_export(const device_state_entry &entry, std::s // helper function //------------------------------------------------- -std::unique_ptr<util::disasm_interface> mb86901_device::create_disassembler() +std::unique_ptr<util::disasm_interface> sparc_base_device::create_disassembler() +{ + auto dasm = std::make_unique<sparc_disassembler>(static_cast<sparc_disassembler::config const *>(this), sparc_disassembler::v7); + if (m_asi_desc_adder) + m_asi_desc_adder(dasm.get()); + return std::move(dasm); +} + +std::unique_ptr<util::disasm_interface> sparcv8_device::create_disassembler() { - auto dasm = std::make_unique<sparc_disassembler>(static_cast<sparc_disassembler::config const *>(this), 7); - m_asi_desc_adder(dasm.get()); + auto dasm = std::make_unique<sparc_disassembler>(static_cast<sparc_disassembler::config const *>(this), sparc_disassembler::v8); + if (m_asi_desc_adder) + m_asi_desc_adder(dasm.get()); return std::move(dasm); } +std::unique_ptr<util::disasm_interface> mb86930_device::create_disassembler() +{ + auto dasm = std::make_unique<sparc_disassembler>(static_cast<sparc_disassembler::config const *>(this), sparc_disassembler::sparclite); + if (m_asi_desc_adder) + m_asi_desc_adder(dasm.get()); + return std::move(dasm); +} //************************************************************************** // CORE EXECUTION LOOP @@ -609,7 +1193,7 @@ std::unique_ptr<util::disasm_interface> mb86901_device::create_disassembler() // cycles it takes for one instruction to execute //------------------------------------------------- -uint32_t mb86901_device::execute_min_cycles() const +uint32_t sparc_base_device::execute_min_cycles() const noexcept { return 1; } @@ -620,29 +1204,18 @@ uint32_t mb86901_device::execute_min_cycles() const // cycles it takes for one instruction to execute //------------------------------------------------- -uint32_t mb86901_device::execute_max_cycles() const +uint32_t sparc_base_device::execute_max_cycles() const noexcept { return 4; } //------------------------------------------------- -// execute_input_lines - return the number of -// input/interrupt lines -//------------------------------------------------- - -uint32_t mb86901_device::execute_input_lines() const -{ - return 16; -} - - -//------------------------------------------------- // execute_set_input - set the state of an input // line during execution //------------------------------------------------- -void mb86901_device::execute_set_input(int inputnum, int state) +void sparc_base_device::execute_set_input(int inputnum, int state) { switch (inputnum) { @@ -699,30 +1272,10 @@ void mb86901_device::execute_set_input(int inputnum, int state) // execute_add - execute an add-type opcode //------------------------------------------------- -void mb86901_device::execute_add(uint32_t op) +void sparc_base_device::execute_add(uint32_t op) { - /* The SPARC Instruction Manual: Version 8, page 173, "Appendix C - ISP Descriptions - Add Instructions" (SPARCv8.pdf, pg. 170) - - operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); - - if (ADD or ADDcc) then - result <- r[rs1] + operand2; - else if (ADDX or ADDXcc) then - result <= r[rs1] + operand2 + C; - next; + // The SPARC Instruction Manual: Version 8, page 173, "Appendix C - ISP Descriptions - Add Instructions" (SPARCv8.pdf, pg. 170) - if (rd != 0) then - r[rd] <- result; - - if (ADDcc or ADDXcc) then ( - N <- result<31>; - Z <- if (result = 0) then 1 else 0; - V <- (r[rs1]<31> and operand2<31> and (not result<31>)) or - ((not r[rs1]<31>) and (not operand2<31>) and result<31>); - C <- (r[rs1]<31> and operand2<31>) or - ((not result<31>) and (r[rs1]<31> or operand2<31>)) - ); - */ uint32_t rs1 = RS1REG; uint32_t operand2 = USEIMM ? SIMM13 : RS2REG; @@ -756,33 +1309,10 @@ void mb86901_device::execute_add(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_taddcc(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 173, "Appendix C - ISP Descriptions - Tagged Add Instructions" (SPARCv8.pdf, pg. 170) - - operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); - - result <- r[rs1] + operand2; - next; - - temp_V <- (r[rs1]<31> and operand2<31> and (not result<31>)) or - ((not r[rs1]<31>) and (not operand2<31>) and result<31>) or - (r[rs1]<1:0> != 0 or operand2<1:0> != 0); - next; - - if (TADDccTV and (temp_V = 1)) then ( - trap <- 1; - tag_overflow <- 1 - ) else ( - N <- result<31>; - Z <- if (result = 0) then 1 else 0; - V <- temp_V; - C <- (r[rs1]<31> and operand2<31>) or - ((not result<31>) and (r[rs1]<31> or operand2<31>)); - if (rd != 0) then - r[rd] <- result; - ); - */ +void sparc_base_device::execute_taddcc(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 173, "Appendix C - ISP Descriptions - Tagged Add Instructions" (SPARCv8.pdf, pg. 170) + uint32_t rs1 = RS1REG; uint32_t operand2 = USEIMM ? SIMM13 : RS2REG; @@ -796,8 +1326,6 @@ void mb86901_device::execute_taddcc(uint32_t op) { m_trap = 1; m_tag_overflow = true; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -821,30 +1349,10 @@ void mb86901_device::execute_taddcc(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_sub(uint32_t op) +void sparc_base_device::execute_sub(uint32_t op) { - /* The SPARC Instruction Manual: Version 8, page 174, "Appendix C - ISP Descriptions - Subtract Instructions" (SPARCv8.pdf, pg. 171) - - operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); - - if (SUB or SUBcc) then - result <- r[rs1] - operand2; - else if (SUBX or SUBXcc) then - result <= r[rs1] - operand2 - C; - next; + // The SPARC Instruction Manual: Version 8, page 174, "Appendix C - ISP Descriptions - Subtract Instructions" (SPARCv8.pdf, pg. 171) - if (rd != 0) then - r[rd] <- result; - - if (SUBcc or SUBXcc) then ( - N <- result<31>; - Z <- if (result = 0) then 1 else 0; - V <- (r[rs1]<31> and (not operand2<31>) and (not result<31>)) or - ((not r[rs1]<31>) and operand2<31> and result<31>); - C <- ((not r[rs1]<31>) and operand2<31>) or - (result<31> and ((not r[rs1]<31>) or operand2<31>)) - ); - */ uint32_t rs1 = RS1REG; uint32_t operand2 = USEIMM ? SIMM13 : RS2REG; @@ -878,33 +1386,9 @@ void mb86901_device::execute_sub(uint32_t op) // opcode //-------------------------------------------------- -void mb86901_device::execute_tsubcc(uint32_t op) +void sparc_base_device::execute_tsubcc(uint32_t op) { - /* The SPARC Instruction Manual: Version 8, page 174, "Appendix C - ISP Descriptions - Tagged Subtract Instructions" (SPARCv8.pdf, pg. 171) - - operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); - - result <- r[rs1] - operand2; - next; - - temp_V <- (r[rs1]<31> and (not operand2<31>) and (not result<31>)) or - ((not r[rs1]<31>) and operand2<31> and result<31>) or - (r[rs1]<1:0> != 0 or operand2<1:0> != 0); - next; - - if (TSUBccTV and (temp_V = 1)) then ( - trap <- 1; - tag_overflow <- 1 - ) else ( - N <- result<31>; - Z <- if (result = 0) then 1 else 0; - V <- temp_V; - C <- ((not r[rs1]<31>) and operand2<31>) or - (result<31> and ((not r[rs1]<31>) or operand2<31>)); - if (rd != 0) then - r[rd] <- result; - ); - */ + // The SPARC Instruction Manual: Version 8, page 174, "Appendix C - ISP Descriptions - Tagged Subtract Instructions" (SPARCv8.pdf, pg. 171) uint32_t rs1 = RS1REG; uint32_t operand2 = USEIMM ? SIMM13 : RS2REG; @@ -919,8 +1403,6 @@ void mb86901_device::execute_tsubcc(uint32_t op) { m_trap = 1; m_tag_overflow = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -939,30 +1421,10 @@ void mb86901_device::execute_tsubcc(uint32_t op) } -/* The SPARC Instruction Manual: Version 8, page 172, "Appendix C - ISP Descriptions - Logical Instructions" (SPARCv8.pdf, pg. 169) - -operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); - -if ( AND or ANDcc) then result <- r[rs1] and operand2 -if (ANDN or ANDNcc) then result <- r[rs1] and not operand2 -if ( OR or ORcc) then result <- r[rs1] or operand2 -if ( ORN or ORNcc) then result <- r[rs1] or not operand2 -if ( XOR or XORcc) then result <- r[rs1] xor operand2 -if (XNOR or XNORcc) then result <- r[rs1] xor not operand2; -next; - -if (rd != 0) then r[rd] <- result; +// The SPARC Instruction Manual: Version 8, page 172, "Appendix C - ISP Descriptions - Logical Instructions" (SPARCv8.pdf, pg. 169) -if (ANDcccc or ANDNcc or ORcc or ORNcc or XORcc or XNORcc) then ( - N <- result<31>; - Z <- if (result = 0) then 1 else 0; - V <- 0 - C <- 0 -); -*/ - -template <mb86901_device::set_cc SETCC> -void mb86901_device::execute_and(const uint32_t op) +template <sparc_base_device::set_cc SETCC> +void sparc_base_device::execute_and(const uint32_t op) { const uint32_t result = RS1REG & (USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -979,8 +1441,8 @@ void mb86901_device::execute_and(const uint32_t op) nPC = nPC + 4; } -template <mb86901_device::set_cc SETCC> -void mb86901_device::execute_or(const uint32_t op) +template <sparc_base_device::set_cc SETCC> +void sparc_base_device::execute_or(const uint32_t op) { const uint32_t result = RS1REG | (USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -997,8 +1459,8 @@ void mb86901_device::execute_or(const uint32_t op) nPC = nPC + 4; } -template <mb86901_device::set_cc SETCC> -void mb86901_device::execute_xor(const uint32_t op) +template <sparc_base_device::set_cc SETCC> +void sparc_base_device::execute_xor(const uint32_t op) { const uint32_t result = RS1REG ^ (USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -1015,8 +1477,8 @@ void mb86901_device::execute_xor(const uint32_t op) nPC = nPC + 4; } -template <mb86901_device::set_cc SETCC> -void mb86901_device::execute_andn(const uint32_t op) +template <sparc_base_device::set_cc SETCC> +void sparc_base_device::execute_andn(const uint32_t op) { const uint32_t result = RS1REG & ~(USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -1033,8 +1495,8 @@ void mb86901_device::execute_andn(const uint32_t op) nPC = nPC + 4; } -template <mb86901_device::set_cc SETCC> -void mb86901_device::execute_orn(const uint32_t op) +template <sparc_base_device::set_cc SETCC> +void sparc_base_device::execute_orn(const uint32_t op) { const uint32_t result = RS1REG | ~(USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -1051,8 +1513,8 @@ void mb86901_device::execute_orn(const uint32_t op) nPC = nPC + 4; } -template <mb86901_device::set_cc SETCC> -void mb86901_device::execute_xnor(const uint32_t op) +template <sparc_base_device::set_cc SETCC> +void sparc_base_device::execute_xnor(const uint32_t op) { const uint32_t result = RS1REG ^ ~(USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -1074,19 +1536,10 @@ void mb86901_device::execute_xnor(const uint32_t op) // sll/srl/sra //------------------------------------------------- -void mb86901_device::execute_shift(uint32_t op) +void sparc_base_device::execute_shift(uint32_t op) { - /* The SPARC Instruction Manual: Version 8, page 172, "Appendix C - ISP Descriptions - Shift Instructions" (SPARCv8.pdf, pg. 169) - - shift_count := if (i = 0) then r[rs2]<4:0> else shcnt; + // The SPARC Instruction Manual: Version 8, page 172, "Appendix C - ISP Descriptions - Shift Instructions" (SPARCv8.pdf, pg. 169) - if (SLL and (rd != 0) ) then - r[rd] <- shift_left_logical(r[rs1], shift_count) - else if (SRL and (rd != 0) ) then - r[rd] <- shift_right_logical(r[rs1], shift_count) - else if (SRA and (rd != 0) ) then - r[rd] <- shift_right_arithmetic(r[rs1], shift_count) - */ uint32_t shift_count = USEIMM ? (SIMM13 & 31) : (RS2REG & 31); if (RDBITS) @@ -1108,31 +1561,10 @@ void mb86901_device::execute_shift(uint32_t op) // execute_mulscc - execute a multiply step opcode //-------------------------------------------------- -void mb86901_device::execute_mulscc(uint32_t op) +void sparc_base_device::execute_mulscc(uint32_t op) { - /* The SPARC Instruction Manual: Version 8, page 175, "Appendix C - ISP Descriptions - Multiply Step Instruction" (SPARCv8.pdf, pg. 172) - - operand1 := (N xor V) [] (r[rs1]<31:1>); - - operand2 := ( - if (Y<0> = 0) then 0 - else if (i = 0) then r[rs2] else sign_extend(simm13) - ); + // The SPARC Instruction Manual: Version 8, page 175, "Appendix C - ISP Descriptions - Multiply Step Instruction" (SPARCv8.pdf, pg. 172) - result <- operand1 + operand2; - Y <- r[rs1]<0> [] Y<31:1>; - next; - - if (rd != 0) then ( - r[rd] <- result; - ) - N <- result<31>; - Z <- if (result = 0) then 1 else 0; - V <- (operand1<31> and operand2<31> and (not result<31>)) or - ((not operand1<31>) and (not operand2<31>) and result<31>); - C <- (operand1<31> and operand2<31>) or - ((not result<31>) and (operand1<31> or operand2<31>)) - */ uint32_t operand1 = ((ICC_N != ICC_V) ? 0x80000000 : 0) | (RS1REG >> 1); uint32_t operand2 = (Y & 1) ? (USEIMM ? SIMM13 : RS2REG) : 0; @@ -1161,40 +1593,28 @@ void mb86901_device::execute_mulscc(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_rdsr(uint32_t op) +void sparc_base_device::execute_rdsr(uint32_t op) { - /* The SPARC Instruction Manual: Version 8, page 182, "Appendix C - ISP Descriptions - Read State Register Instructions" (SPARCv8.pdf, pg. 179) + // The SPARC Instruction Manual: Version 8, page 182, "Appendix C - ISP Descriptions - Read State Register Instructions" (SPARCv8.pdf, pg. 179) - if ((RDPSR or RDWIM or RDBTR - or (RDASR and (privileged_ASR(rs1) = 1))) and (S = 0)) then ( - trap <- 1; - privileged_instruction <- 1; - else if (illegal_instruction_ASR(rs1) = 1) then ( - trap <- 1; - illegal_instruction <- 1 - else if (rd != 0) then ( - if (RDY) then r[rd] <- Y - else if (RDASR) then r[rd] <- ASR[rs1] - else if (RDPSR) then r[rd] <- PSR - else if (RDWIM) then r[rd] <- WIM - else if (RDTBR) then r[rd] <- TBR; - ); - */ + if (RDASR && RS1 == 15 && RD == 0) + { + // Store Barrier instruction - not implemented, as stores are always consistent in the context of MAME + PC = nPC; + nPC = nPC + 4; + return; + } - if (((WRPSR || WRWIM || WRTBR) || (WRASR && m_privileged_asr[RS1])) && IS_USER) + if (((RDPSR || RDWIM || RDTBR) || (RDASR && m_privileged_asr[RS1])) && IS_USER) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if (m_illegal_instruction_asr[RS1]) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -1227,51 +1647,10 @@ void mb86901_device::execute_rdsr(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_wrsr(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 183, "Appendix C - ISP Descriptions - Write State Register Instructions" (SPARCv8.pdf, pg. 180) - - operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); - result := r[rs1] xor operand2; - - if (WRY) then ( - Y'''' <- result - ) else if (WRASR) then ( - if ( (privileged_ASR(rd) = 1) and (S = 0) ) then ( - trap <- 1; - privileged_instruction <- 1 - ) else if (illegal_instruction_ASR(rd) = 1) then ( - trap <- 1; - illegal_instruction <- 1 - ) else ( - ASR[rd]'''' <- result - ) - ) else if (WRPSR) then ( - if (S = 0) then ( - trap <- 1; - privileged_instruction <- 1 - ) else if (result<4:0> >= NWINDOWS) then ( - trap <- 1; - illegal_instruction <- 1 - ) else ( - PSR'''' <- result - ) - ) else if (WRWIM) then ( - if (S = 0) then ( - trap <- 1; - privileged_instruction <- 1 - ) else ( - WIM'''' <- result - ) - ) else if (WRBTR) then ( - if (S = 0) then ( - trap <- 1; - privileged_instruction <- 1 - ) else ( - WIM'''' <- result - ) - ); - */ +void sparc_base_device::execute_wrsr(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 183, "Appendix C - ISP Descriptions - Write State Register Instructions" (SPARCv8.pdf, pg. 180) + uint32_t operand2 = USEIMM ? SIMM13 : RS2REG; uint32_t result = RS1REG ^ operand2; @@ -1288,16 +1667,12 @@ void mb86901_device::execute_wrsr(uint32_t op) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if (m_illegal_instruction_asr[RD]) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else @@ -1313,20 +1688,16 @@ void mb86901_device::execute_wrsr(uint32_t op) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if ((result & 31) >= NWINDOWS) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - PSR = result &~ PSR_ZERO_MASK; + PSR = (PSR & PSR_ZERO_MASK) | (result & ~PSR_ZERO_MASK); update_gpr_pointers(); m_et = PSR & PSR_ET_MASK; @@ -1341,6 +1712,12 @@ void mb86901_device::execute_wrsr(uint32_t op) m_data_space = 10; } + if (m_et && (m_bp_irl == 15 || m_bp_irl > m_pil) && m_interrupt_level == 0) + { + m_trap = 1; + m_interrupt_level = m_bp_irl; + } + PC = nPC; nPC = nPC + 4; } @@ -1350,8 +1727,6 @@ void mb86901_device::execute_wrsr(uint32_t op) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -1365,8 +1740,6 @@ void mb86901_device::execute_wrsr(uint32_t op) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -1382,43 +1755,9 @@ void mb86901_device::execute_wrsr(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_rett(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 181, "Appendix C - ISP Descriptions - Return from Trap Instructions" (SPARCv8.pdf, pg. 178) - - new_cwp <- (CWP + 1) modulo NWINDOWS; - address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); - next; - if (ET = 1) then ( - trap <- 1; - if (S = 0) then privileged_instruction <- 1 - else if (S != 0) then illegal_instruction <- 1 - ) else if (S = 0) then ( - trap <- 1; - privileged_instruction <- 1 - tt <- 00000011; { trap type for privileged_instruction } - execute_mode <- 0; - error_mode = 1 - ) else if ((WIM and (1 << new_cwp)) != 0) then ( - trap <- 1; - window_underflow <- 1; - tt <- 00000110; { trap type for window_underflow } - execute_mode = 0; - error_mode = 1 - ) else if (address<1:0> != 0) then ( - trap = 1; - mem_address_not_aligned = 1; - tt = 7; { trap type for mem_address_not_aligned } - execute_mode = 0; - error_mode = 1 - ) else ( - ET <- 1; - PC <- nPC; - nPC <- address; - CWP <- new_cwp; - S <- PS - ) - */ +void sparc_base_device::execute_rett(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 181, "Appendix C - ISP Descriptions - Return from Trap Instructions" (SPARCv8.pdf, pg. 178) uint8_t new_cwp = ((PSR & PSR_CWP_MASK) + 1) % NWINDOWS; uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -1433,8 +1772,6 @@ void mb86901_device::execute_rett(uint32_t op) { m_illegal_instruction = 1; } - m_stashed_icount = m_icount; - m_icount = 0; return; } else if (IS_USER) @@ -1444,8 +1781,6 @@ void mb86901_device::execute_rett(uint32_t op) m_tt = 3; m_execute_mode = 0; m_error_mode = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if ((WIM & (1 << new_cwp)) != 0) @@ -1455,8 +1790,6 @@ void mb86901_device::execute_rett(uint32_t op) m_tt = 6; m_execute_mode = 0; m_error_mode = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if (address & 3) @@ -1466,8 +1799,6 @@ void mb86901_device::execute_rett(uint32_t op) m_tt = 7; m_execute_mode = 0; m_error_mode = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -1493,6 +1824,12 @@ void mb86901_device::execute_rett(uint32_t op) } update_gpr_pointers(); + + if (m_et && (m_bp_irl == 15 || m_bp_irl > m_pil) && m_interrupt_level == 0) + { + m_trap = 1; + m_interrupt_level = m_bp_irl; + } } @@ -1502,37 +1839,9 @@ void mb86901_device::execute_rett(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_saverestore(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 177, "Appendix C - ISP Descriptions - SAVE and RESTORE Instructions" (SPARCv8.pdf, pg. 174) - - operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); - - if (SAVE) then ( - new_cwp <- (CWP - 1) modulo NWINDOWS; - next; - if ((WIM and (1 << new_cwp)) != 0) then ( - trap <- 1; - window_overflow <- 1 - ) else ( - result <- r[rs1] + operand2; { operands from old window } - CWP <- new_cwp - ) - ) else if (RESTORE) then ( - new_cwp <- (CWP + 1) modulo NWINDOWS; - next; - if ((WIM and (1 << new_cwp)) != 0) then ( - trap <- 1; - window_overflow <- 1 - ) else ( - result <- r[rs1] + operand2; { operands from old window } - CWP <- new_cwp - ) - ); - next; - if ((trap = 0) and (rd != 0)) then - r[rd] <- result { destination in new window } - */ +void sparc_base_device::execute_saverestore(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 177, "Appendix C - ISP Descriptions - SAVE and RESTORE Instructions" (SPARCv8.pdf, pg. 174) uint32_t rs1 = RS1REG; uint32_t operand2 = USEIMM ? SIMM13 : RS2REG; @@ -1545,8 +1854,6 @@ void mb86901_device::execute_saverestore(uint32_t op) { m_trap = 1; m_window_overflow = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -1561,8 +1868,6 @@ void mb86901_device::execute_saverestore(uint32_t op) { m_trap = 1; m_window_underflow = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -1585,21 +1890,9 @@ void mb86901_device::execute_saverestore(uint32_t op) // execute_jmpl - execute a jump and link opcode //------------------------------------------------- -void mb86901_device::execute_jmpl(uint32_t op) +void sparc_base_device::execute_jmpl(uint32_t op) { - /* The SPARC Instruction Manual: Version 8, page 180, "Appendix C - ISP Descriptions - SAVE and RESTORE Instructions" (SPARCv8.pdf, pg. 177) - - jump_address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); - next; - if (jump_address<1:0> != 0) then ( - trap <- 1; - mem_address_not_aligned <- 1 - ) else ( - if (rd != 0) then r[rd] <- PC; - PC <- nPC; - nPC <- jump_address - ) - */ + // The SPARC Instruction Manual: Version 8, page 180, "Appendix C - ISP Descriptions - SAVE and RESTORE Instructions" (SPARCv8.pdf, pg. 177) uint32_t jump_address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -1607,8 +1900,6 @@ void mb86901_device::execute_jmpl(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; } else { @@ -1625,7 +1916,7 @@ void mb86901_device::execute_jmpl(uint32_t op) // mostly ALU ops //------------------------------------------------- -inline void mb86901_device::execute_group2(uint32_t op) +inline void sparc_base_device::execute_group2(uint32_t op) { switch (OP3) { @@ -1718,11 +2009,8 @@ inline void mb86901_device::execute_group2(uint32_t op) case OP3_FPOP2: if (!(PSR & PSR_EF_MASK) || !m_bp_fpu_present) { - //printf("fpop @ %08x: %08x\n", PC, op); m_trap = 1; m_fp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; } complete_fp_execution(op); return; @@ -1750,49 +2038,108 @@ inline void mb86901_device::execute_group2(uint32_t op) execute_saverestore(op); break; -#if SPARCV8 + default: + if (!execute_extra_group2(op)) + { + logerror("illegal instruction at %08x: %08x\n", PC, op); + m_trap = 1; + m_illegal_instruction = 1; + } + break; + } +} + + +//------------------------------------------------- +// update_extra_group2 - execute a group2 +// instruction belonging to a newer SPARC version +// than v7, or which can be overridden from v7 +//------------------------------------------------- + +bool sparcv7_device::execute_extra_group2(uint32_t op) +{ + switch (OP3) + { + default: + return false; + } +} + +bool sparcv8_device::execute_extra_group2(uint32_t op) +{ + switch (OP3) + { case OP3_UMUL: case OP3_SMUL: case OP3_UMULCC: case OP3_SMULCC: execute_mul(op); - break; + return true; case OP3_UDIV: case OP3_SDIV: case OP3_UDIVCC: case OP3_SDIVCC: execute_div(op); - break; + return true; case OP3_CPOP1: case OP3_CPOP2: - logerror("fpop @ %08x: %08x\n", PC, op); + logerror("cpop @ %08x: %08x\n", PC, op); m_trap = 1; m_cp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; - return; -#endif + return true; default: - logerror("illegal instruction at %08x: %08x\n", PC, op); - m_trap = 1; - m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; - break; + return false; } } +void mb86930_device::execute_divscc(uint32_t op) +{ + fatalerror("Not yet supported: divscc at %08x\n", PC); + /*const bool n_flag = (PSR & PSR_N_MASK); + const bool v_flag = (PSR & PSR_V_MASK); + const bool true_sign = n_flag ^ v_flag; + const uint64_t dividend = ((uint64_t)m_y << 32) | RS1REG; + const uint32_t remainder = m_y << 1; + const uint32_t divisor = (USEIMM ? SIMM13 : RS2REG);*/ +} + +void mb86930_device::execute_scan(uint32_t op) +{ + fatalerror("Not yet supported: scan at %08x\n", PC); +} + +bool mb86930_device::execute_extra_group2(uint32_t op) +{ + switch (OP3) + { + case OP3_DIVSCC: + execute_divscc(op); + return true; + + case OP3_SCAN: + execute_scan(op); + return true; + case OP3_UMUL: + case OP3_SMUL: + case OP3_UMULCC: + case OP3_SMULCC: + return sparcv8_device::execute_extra_group2(op); + + default: + return false; + } +} //------------------------------------------------- // update_gpr_pointers - cache pointers to // the registers in our current window //------------------------------------------------- -void mb86901_device::update_gpr_pointers() +void sparc_base_device::update_gpr_pointers() { int cwp = PSR & PSR_CWP_MASK; for (int i = 0; i < 8; i++) @@ -1808,141 +2155,20 @@ void mb86901_device::update_gpr_pointers() // execute_store - execute a store-type opcode //------------------------------------------------- -void mb86901_device::execute_store(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 165, "Appendix C - ISP Descriptions - Store Instructions" (SPARCv8.pdf, pg. 162) - - if ( (S = 0) and (STDA or STA or STHA or STBA or STDFQ or STDCQ) ) then ( - trap <- 1; - privileged_instruction <- 1 - ) else if ((i = 1) and (STDA or STA or STHA or STBA)) then ( - trap <- 1; - illegal_instruction <- 1 - ); - next; - if (trap = 0) then ( - if (STD or ST or STH or STB or STF or STDF or STFSR or STDFQ or STCSR or STC or STDC or STDCQ) then ( - address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); - addr_space <- (if (S = 0) then 10 else 11) - ) else if (STDA or STA or STHA or STBA) then ( - address <- r[rs1] + r[rs2]; - addr_space <- asi - ); - if ((STF or STDF or STFSR or STDFQ) and - ((EF = 0) or (bp_FPU_present = 0)) ) then ( - trap <- 1; - fp_disabled <- 1; - ); - if ((STC or STDC or STCSR or STDCQ) and - ((EC = 0) or (bp_CP_present = 0)) ) then ( - trap <- 1; - cp_disabled <- 1; - ) - ); - next; - if (trap = 0) then ( - if ((STH or STHA) and (address<0> != 0)) then ( - trap <- 1; - mem_address_not_aligned <- 1 - ) else if ((ST or STA or STF or STFSR or STC or STCSR) and (address<1:0> != 0)) then ( - trap <- 1; - mem_address_not_aligned <- 1 - ) else if ((STD or STDA or STDF or STDFQ or STDC or STDCQ) and (address<2:0> != 0)) then ( - trap <- 1; - mem_address_not_aligned <- 1 - ) else ( - if (STDFQ and ((implementation has no floating-point queue) or (FSR.qne = 0))) then ( - trap <- 1; - fp_exception <- 1; - ftt <- sequence_error; - ); - if (STDCQ and ((implementation has no coprocessor queue)) then ( - trap <- 1; - cp_exception <- 1; - { possibly additional implementation-dependent actions } - ); - if (STDF and (rd<0> != 0)) then ( - trap <- 1; - fp_exception <- 1; - ftt <- invalid_fp_register; - ) - ) - ); - next; - if (trap = 0) then ( - if (STF) then ( byte_mask <- 1111; data0 <- f[rd] ) - else if (STC) then ( byte_mask <- 1111; data0 <- implementation_dependent_value ) - else if (STDF) then ( byte_mask <- 1111; data0 <- f[rd & 0x1e] ) - else if (STDC) then ( byte_mask <- 1111; data0 <- implementation_dependent_value ) - else if (STD or STDA) then ( byte_mask <- 1111; data0 <- r[rd & 0x1e] ) - else if (STDFQ) then ( byte_mask <- 1111; data0 <- implementation_dependent_value ) - else if (STDCQ) then ( byte_mask <- 1111; data0 <- implementation_dependent_value ) - else if (STFSR) then ( - while ((FSR.qne = 1) and (trap = 0)) ( - // wait for pending floating-point instructions to complete - ) - next; - byte_mask <- 1111; data0 <- FSR - ) else if (STCSR) then ( - { implementation-dependent actions } - byte_mask <- 1111; data0 <- CSR - ) else if (ST or STA) then ( byte_mask <- 1111; data0 = r[rd] ) - else if (STH or STHA) then ( - if (address<1:0> = 0) then ( - byte_mask <- 1100; data0 <- shift_left_logical(r[rd], 16) ) - else if (address<1:0> = 2) then ( - byte_mask <- 0011; data0 <- r[rd] ) - ) else if (STB or STBA) then ( - if (address<1:0> = 0) then ( - byte_mask <- 1000; data0 <- shift_left_logical(r[rd], 24) ) - ) else if (address<1:0> = 1) then ( - byte_mask <- 0100; data0 <- shift_left_logical(r[rd], 16) ) - ) else if (address<1:0> = 2) then ( - byte_mask <- 0010; data0 <- shift_left_logical(r[rd], 8) ) - ) else if (address<1:0> = 3) then ( - byte_mask <- 0001; data0 <- r[rd] ) - ) - ); - ); - next; - if (trap = 0) then ( - MAE <- memory_write(addr_space, address, byte_mask, data1); - next; - if (MAE = 1) then ( - trap <- 1; - data_access_exception <- 1 - ) - ); - if ((trap = 0) and (STD or STDA or STDF or STDC or STDFQ or STDCQ)) then ( - if (STD or STDA) then ( data1 <- r[rd or 00001] ) - else if (STDF) then ( data1 <- f[rd or 00001] ) - else if (STDC) then ( data1 <- implementation_dependent_value } - else if (STDFQ) then ( data1 <- implementation_dependent_value } - else if (STDCQ) then ( data1 <- implementation_dependent_value } - next; - MAE <- memory_write(addr_space, address + 4, 1111, data1); - next; - if (MAE = 1) then ( { MAE = 1 only due to a "non-resumable machine-check error" } - trap <- 1; - data_access_exception <- 1 - ) - ); - */ +void sparc_base_device::execute_store(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 165, "Appendix C - ISP Descriptions - Store Instructions" (SPARCv8.pdf, pg. 162) if (IS_USER && (STDA || STA || STHA || STBA || STDFQ || STDCQ)) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - else if (USEIMM && (STDA || STA || STHA || STBA)) + else if ((USEIMM && (STDA || STA || STHA || STBA)) || ((STD || STDA) && (RD & 1))) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -1962,24 +2188,18 @@ void mb86901_device::execute_store(uint32_t op) { m_trap = 1; m_fp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } if ((STC || STDC || STCSR || STDCQ) && (!(PSR & PSR_EC_MASK) || !m_bp_cp_present)) { m_trap = 1; m_cp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } if ((STH || STHA) && ((address & 1) != 0)) { m_trap = 1; - m_stashed_icount = m_icount; - m_icount = 0; m_mem_address_not_aligned = 1; return; } @@ -1987,27 +2207,18 @@ void mb86901_device::execute_store(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if ((STD || STDA || STDF || STDFQ || STDC || STDCQ) && ((address & 7) != 0)) { - m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; + m_trap = 1; return; } if (STDFQ) { // assume no floating-point queue for now - m_trap = 1; - m_fp_exception = 1; - m_ftt = m_fpu_sequence_err; - m_stashed_icount = m_icount; - m_icount = 0; return; } if (STDCQ) @@ -2015,27 +2226,20 @@ void mb86901_device::execute_store(uint32_t op) // assume no coprocessor queue for now m_trap = 1; m_cp_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; // { possibly additional implementation-dependent actions } return; } - if (STDF && ((RD & 1) != 0)) - { - m_trap = 1; - m_fp_exception = 1; - m_ftt = 0xff; - m_stashed_icount = m_icount; - m_icount = 0; - return; - } uint32_t data0 = 0; + uint32_t data1 = 0; //uint8_t byte_mask; if (STF) { //byte_mask = 15; - data0 = FREG(RD); + if (get_fpr32(data0, RD)) + { + return; + } } else if (STC) { @@ -2045,7 +2249,14 @@ void mb86901_device::execute_store(uint32_t op) else if (STDF) { //byte_mask = 15; - data0 = FREG(RD & 0x1e); + if (get_fpr32(data0, RD & 0x1e)) + { + return; + } + if (get_fpr32(data1, RD | 1)) + { + return; + } } else if (STDC) { @@ -2056,16 +2267,19 @@ void mb86901_device::execute_store(uint32_t op) { //byte_mask = 15; data0 = REG(RD & 0x1e); + data1 = REG(RD | 1); } else if (STDFQ) { //byte_mask = 15; data0 = 0; + data1 = 0; } else if (STDCQ) { //byte_mask = 15; data0 = 0; + data1 = 0; } else if (STFSR) { @@ -2126,47 +2340,21 @@ void mb86901_device::execute_store(uint32_t op) static const uint32_t mask16[4] = { 0xffff0000, 0x00000000, 0x0000ffff, 0x00000000 }; static const uint32_t mask8[4] = { 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff }; - m_mmu->write_asi(addr_space, address >> 2, data0, (ST || STA || STD || STDA || STF || STDF || STDFQ || STFSR || STC || STDC || STDCQ || STCSR) ? 0xffffffff : ((STH || STHA) ? mask16[address & 2] : mask8[address & 3])); + write_word(addr_space, address, data0, (ST || STA || STD || STDA || STF || STDF || STDFQ || STFSR || STC || STDC || STDCQ || STCSR) ? 0xffffffff : ((STH || STHA) ? mask16[address & 2] : mask8[address & 3])); if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } if (STD || STDA || STDF || STDC || STDFQ || STDCQ) { - uint32_t data1 = 0; - if (STD || STDA) - { - data1 = REG(RD | 1); - } - else if (STDF) - { - data1 = FREG(RD | 1); - } - else if (STDC) - { - data1 = 0; - } - else if (STDFQ) - { - data1 = 0; - } - else if (STDCQ) - { - data1 = 0; - } - - m_mmu->write_asi(addr_space, (address + 4) >> 2, data1, 0xffffffff); + write_word(addr_space, address + 4, data1); if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } } @@ -2175,139 +2363,43 @@ void mb86901_device::execute_store(uint32_t op) nPC = nPC + 4; } -/* The SPARC Instruction Manual: Version 8, page 163, "Appendix C - ISP Descriptions - C.9. Instruction Defintions - Load Instructions" (SPARCv8.pdf, pg. 160) - -if (LDD or LD or LDSH or LDUH or LDSB or LDUB or LDDF or LDF or LDFSR or LDDC or LDC or LDCSR) then ( - address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); - addr_space <- (if (S = 0) then 10 else 11) -) else if (LDDA or LDA or LDSHA or LDUHA or LDSBA or LDUBA) then ( - if (S = 0) then ( - trap <- 1; - privileged_instruction <- 1 - ) else if (i = 1) then ( - trap <- 1; - illegal_instruction <- 1 - ) else ( - address <- r[rs1] + r[rs2]; - addr_space <- asi - ) -) -next; -if (trap = 0) then ( - if ( (LDF or LDDF or LDFSR) and ((EF = 0) or (bp_FPU_present = 0)) then ( - trap <- 1; - fp_disabled <- 1 - ) else if ( (LDC or LDDC or LDCSR) and ((EC = 0) or (bp_CP_present = 0)) then ( - trap <- 1; - cp_disabled <- 1 - ) else if ( ( (LDD or LDDA or LDDF or LDDC) and (address<2:0> != 0)) or - ((LD or LDA or LDF or LDFSR or LDC or LDCSR) and (address<1:0> != 0)) or - ((LDSH or LDSHA or LDUH or LDUHA) and address<0> != 0) ) then ( - trap <- 1; - mem_address_not_aligned <- 1 - ) else if (LDDF and (rd<0> != 0)) then ( - trap <- 1; - fp_exception <- 1; - ftt <- invalid_fpr_register - ) else if ((LDF or LDDF or LDFSR) and (an FPU sequence error is detected)) then ( - trap <- 1; - fp_exception <- 1; - ftt <- sequence_error - ) else if ((LDC or LDDC or LDCSR) and (a CP sequence error is detected)) then ( - trap <- 1; - cp_exception <- 1; - { possibly additional implementation-dependent actions } - ) -); -next; -if (trap = 0) then { - (data, MAE) <- memory_read(addr_space, address); - next; - if (MAE = 1) then ( - trap <- 1; - data_access_exception <- 1; - ) else ( - if (LDSB or LDSBA or LDUB or LDUBA) then ( - if (address<1:0> = 0) then byte <- data<31:24> - else if (address<1:0> = 1) then byte <- data<23:16> - else if (address<1:0> = 2) then byte <- data<15: 8> - else if (address<1:0> = 3) then byte <- data< 7: 0> - next; - if (LDSB or LDSBA) then - word0 <- sign_extend_byte(byte) - else - word0 <- zero_extend_byte(byte) - ) else if (LDSH or LDSHA or LDUH or LDUHA) then ( - if (address<1:0> = 0) then halfword <- data<31:16> - else if (address<1:0> = 2) then halfword <- data<15: 0> - next; - if (LDSH or LDSHA) then - word0 <- sign_extend_halfword(halfword) - else - word0 <- zero_extend_halfword(halfword) - ) else - word0 <- data - ) -); -next; -if (trap = 0) then ( - if ( (rd != 0) and (LD or LDA or LDSH or LDSHA - or LDUHA or LDUH or LDSB or LDSBA or LDUB or LDUBA) ) then - r[rd] <- word0 - else if (LDF) then f[rd] <- word0 - else if (LDC) then { implementation-dependent actions } - else if (LDFSR) then FSR <- word0 - else if (LDCSR) then CSR <- word0 - else if (LDD or LDDA) then r[rd and 11110] <- word0 - else if (LDDF) then f[rd and 11110] <- word0 - else if (LDDC) then { implementation-dependent actions } -); -next; -if (((trap = 0) and (LDD or LDDA or LDDF or LDDC)) then ( - (word1, MAE) <- memory_read(addr_space, address + 4); - next; - if (MAE = 1) then ( { MAE = 1 only due to a "non-resumable machine-check error" } - trap <- 1; - data_access_exception <- 1 ) - else if (LDD or LDDA) then r[rd or 1] <- word1 - else if (LDDF) then f[rd or 1] <- word1 - else if (LDDC) then { implementation-dependent actions } -); -*/ - -inline void mb86901_device::execute_ldd(uint32_t op) +// The SPARC Instruction Manual: Version 8, page 163, "Appendix C - ISP Descriptions - C.9. Instruction Defintions - Load Instructions" (SPARCv8.pdf, pg. 160) + +inline void sparc_base_device::execute_ldd(uint32_t op) { + if (RD & 1) + { + m_trap = 1; + m_illegal_instruction = 1; + return; + } + const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); if (address & 7) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; + return; } - const uint32_t data = m_mmu->read_asi(m_data_space, address >> 2, 0xffffffff); + const uint32_t data = read_word(m_data_space, address); if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } if (RDBITS) RDREG = data; - const uint32_t word1 = m_mmu->read_asi(m_data_space, (address + 4) >> 2, 0xffffffff); + const uint32_t word1 = read_word(m_data_space, address + 4); if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2317,7 +2409,7 @@ inline void mb86901_device::execute_ldd(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ld(uint32_t op) +inline void sparc_base_device::execute_ld(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2325,19 +2417,15 @@ inline void mb86901_device::execute_ld(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - const uint32_t data = m_mmu->read_asi(m_data_space, address >> 2, 0xffffffff); + const uint32_t data = read_word(m_data_space, address); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2348,7 +2436,7 @@ inline void mb86901_device::execute_ld(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldsh(uint32_t op) +inline void sparc_base_device::execute_ldsh(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2356,20 +2444,16 @@ inline void mb86901_device::execute_ldsh(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } static const uint32_t mask16[4] = { 0xffff0000, 0x00000000, 0x0000ffff, 0x00000000 }; - const uint32_t data = m_mmu->read_asi(m_data_space, address >> 2, mask16[address & 2]); + const uint32_t data = read_word(m_data_space, address, mask16[address & 2]); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2383,7 +2467,7 @@ inline void mb86901_device::execute_ldsh(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_lduh(uint32_t op) +inline void sparc_base_device::execute_lduh(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2391,20 +2475,16 @@ inline void mb86901_device::execute_lduh(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } static const uint32_t mask16[4] = { 0xffff0000, 0x00000000, 0x0000ffff, 0x00000000 }; - const uint32_t data = m_mmu->read_asi(m_data_space, address >> 2, mask16[address & 2]); + const uint32_t data = read_word(m_data_space, address, mask16[address & 2]); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2418,19 +2498,17 @@ inline void mb86901_device::execute_lduh(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldsb(uint32_t op) +inline void sparc_base_device::execute_ldsb(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); static const uint32_t mask8[4] = { 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff }; - const uint32_t data = m_mmu->read_asi(m_data_space, address >> 2, mask8[address & 3]); + const uint32_t data = read_word(m_data_space, address, mask8[address & 3]); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2446,20 +2524,18 @@ inline void mb86901_device::execute_ldsb(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldub(uint32_t op) +inline void sparc_base_device::execute_ldub(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); static const uint32_t mask8[4] = { 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff }; const uint32_t byte_idx = address & 3; - const uint32_t data = m_mmu->read_asi(m_data_space, address >> 2, mask8[byte_idx]); + const uint32_t data = read_word(m_data_space, address, mask8[byte_idx]); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2473,7 +2549,7 @@ inline void mb86901_device::execute_ldub(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_lddfpr(uint32_t op) +inline void sparc_base_device::execute_lddfpr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2481,8 +2557,6 @@ inline void mb86901_device::execute_lddfpr(uint32_t op) { m_trap = 1; m_fp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2490,61 +2564,44 @@ inline void mb86901_device::execute_lddfpr(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - if (RD & 1) + const uint32_t data = read_word(m_data_space, address); + + if (m_mae) { m_trap = 1; - m_fp_exception = 1; - m_ftt = 0xff; - m_stashed_icount = m_icount; - m_icount = 0; + m_data_access_exception = 1; return; } - if (m_fpu_sequence_err) + if (m_pending_fpr == (RD & 0x1e)) { - m_trap = 1; - m_fp_exception = 1; - m_ftt = m_fpu_sequence_err; - m_stashed_icount = m_icount; - m_icount = 0; return; } - const uint32_t data = m_mmu->read_asi(m_data_space, address >> 2, 0xffffffff); - - if (m_mae) + const uint32_t word1 = read_word(m_data_space, address + 4); + if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - FREG(RD & 0x1e) = data; - - const uint32_t word1 = m_mmu->read_asi(m_data_space, (address + 4) >> 2, 0xffffffff); - if (MAE) + if (m_pending_fpr == (RD | 1)) { - m_trap = 1; - m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } + FREG(RD & 0x1e) = data; FREG(RD | 1) = word1; PC = nPC; nPC = nPC + 4; } -inline void mb86901_device::execute_ldfpr(uint32_t op) +inline void sparc_base_device::execute_ldfpr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2552,8 +2609,6 @@ inline void mb86901_device::execute_ldfpr(uint32_t op) { m_trap = 1; m_fp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2561,29 +2616,20 @@ inline void mb86901_device::execute_ldfpr(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - if (m_fpu_sequence_err) + const uint32_t data = read_word(m_data_space, address); + + if (m_mae) { m_trap = 1; - m_fp_exception = 1; - m_ftt = m_fpu_sequence_err; - m_stashed_icount = m_icount; - m_icount = 0; + m_data_access_exception = 1; return; } - const uint32_t data = m_mmu->read_asi(m_data_space, address >> 2, 0xffffffff); - - if (m_mae) + if (m_pending_fpr == RD) { - m_trap = 1; - m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2593,7 +2639,7 @@ inline void mb86901_device::execute_ldfpr(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldfsr(uint32_t op) +inline void sparc_base_device::execute_ldfsr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2601,8 +2647,6 @@ inline void mb86901_device::execute_ldfsr(uint32_t op) { m_trap = 1; m_fp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2610,39 +2654,33 @@ inline void mb86901_device::execute_ldfsr(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - if (m_fpu_sequence_err) - { - m_trap = 1; - m_fp_exception = 1; - m_ftt = m_fpu_sequence_err; - m_stashed_icount = m_icount; - m_icount = 0; - return; - } - - const uint32_t data = m_mmu->read_asi(m_data_space, address >> 2, 0xffffffff); + const uint32_t data = read_word(m_data_space, address); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - FSR = data; + FSR = (data & ~FSR_RESV_MASK) | FSR_VER; + + switch (FSR & FSR_RD_MASK) + { + case FSR_RD_NEAR: softfloat_roundingMode = softfloat_round_near_even; break; + case FSR_RD_ZERO: softfloat_roundingMode = softfloat_round_minMag; break; + case FSR_RD_UP: softfloat_roundingMode = softfloat_round_max; break; + case FSR_RD_DOWN: softfloat_roundingMode = softfloat_round_min; break; + } PC = nPC; nPC = nPC + 4; } -inline void mb86901_device::execute_lddcpr(uint32_t op) +inline void sparc_base_device::execute_lddcpr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2650,8 +2688,6 @@ inline void mb86901_device::execute_lddcpr(uint32_t op) { m_trap = 1; m_cp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2659,8 +2695,6 @@ inline void mb86901_device::execute_lddcpr(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2668,31 +2702,25 @@ inline void mb86901_device::execute_lddcpr(uint32_t op) { m_trap = 1; m_cp_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; // possibly additional implementation-dependent actions return; } - m_mmu->read_asi(m_data_space, address >> 2, 0xffffffff); + read_word(m_data_space, address); if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } // implementation-dependent actions - m_mmu->read_asi(m_data_space, (address + 4) >> 2, 0xffffffff); + read_word(m_data_space, address + 4); if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2702,7 +2730,7 @@ inline void mb86901_device::execute_lddcpr(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldcpr(uint32_t op) +inline void sparc_base_device::execute_ldcpr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2710,8 +2738,6 @@ inline void mb86901_device::execute_ldcpr(uint32_t op) { m_trap = 1; m_cp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2719,8 +2745,6 @@ inline void mb86901_device::execute_ldcpr(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2728,20 +2752,16 @@ inline void mb86901_device::execute_ldcpr(uint32_t op) { m_trap = 1; m_cp_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; // possibly additional implementation-dependent actions return; } - m_mmu->read_asi(m_data_space, address >> 2, 0xffffffff); + read_word(m_data_space, address); if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2751,7 +2771,7 @@ inline void mb86901_device::execute_ldcpr(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldcsr(uint32_t op) +inline void sparc_base_device::execute_ldcsr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2759,8 +2779,6 @@ inline void mb86901_device::execute_ldcsr(uint32_t op) { m_trap = 1; m_cp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2768,8 +2786,6 @@ inline void mb86901_device::execute_ldcsr(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2777,20 +2793,16 @@ inline void mb86901_device::execute_ldcsr(uint32_t op) { m_trap = 1; m_cp_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; // possibly additional implementation-dependent actions return; } - m_mmu->read_asi(m_data_space, address >> 2, 0xffffffff); + read_word(m_data_space, address); if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2800,22 +2812,18 @@ inline void mb86901_device::execute_ldcsr(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldda(uint32_t op) +inline void sparc_base_device::execute_ldda(uint32_t op) { if (IS_USER) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - else if (USEIMM) + else if (USEIMM || (RD & 1)) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2826,32 +2834,26 @@ inline void mb86901_device::execute_ldda(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - const uint32_t data = m_mmu->read_asi(addr_space, address >> 2, 0xffffffff); + const uint32_t data = read_word(addr_space, address); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } if (RDBITS) RDREG = data; - uint32_t word1 = m_mmu->read_asi(addr_space, (address + 4) >> 2, 0xffffffff); + uint32_t word1 = read_word(addr_space, address + 4); if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2861,22 +2863,18 @@ inline void mb86901_device::execute_ldda(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_lda(uint32_t op) +inline void sparc_base_device::execute_lda(uint32_t op) { if (IS_USER) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if (USEIMM) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2886,19 +2884,15 @@ inline void mb86901_device::execute_lda(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - const uint32_t data = m_mmu->read_asi(ASI, address >> 2, 0xffffffff); + const uint32_t data = read_word(ASI, address); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2909,22 +2903,18 @@ inline void mb86901_device::execute_lda(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldsha(uint32_t op) +inline void sparc_base_device::execute_ldsha(uint32_t op) { if (IS_USER) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if (USEIMM) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2934,20 +2924,16 @@ inline void mb86901_device::execute_ldsha(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } static const uint32_t mask16[4] = { 0xffff0000, 0x00000000, 0x0000ffff, 0x00000000 }; - const uint32_t data = m_mmu->read_asi(ASI, address >> 2, mask16[address & 2]); + const uint32_t data = read_word(ASI, address, mask16[address & 2]); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2961,22 +2947,18 @@ inline void mb86901_device::execute_ldsha(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_lduha(uint32_t op) +inline void sparc_base_device::execute_lduha(uint32_t op) { if (IS_USER) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if (USEIMM) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -2985,20 +2967,16 @@ inline void mb86901_device::execute_lduha(uint32_t op) { m_trap = 1; m_mem_address_not_aligned = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } static const uint32_t mask16[4] = { 0xffff0000, 0x00000000, 0x0000ffff, 0x00000000 }; - const uint32_t data = m_mmu->read_asi(ASI, address >> 2, mask16[address & 2]); + const uint32_t data = read_word(ASI, address, mask16[address & 2]); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -3012,35 +2990,29 @@ inline void mb86901_device::execute_lduha(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldsba(uint32_t op) +inline void sparc_base_device::execute_ldsba(uint32_t op) { if (IS_USER) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if (USEIMM) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } static const uint32_t mask8[4] = { 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff }; const uint32_t address = RS1REG + RS2REG; - const uint32_t data = m_mmu->read_asi(ASI, address >> 2, mask8[address & 3]); + const uint32_t data = read_word(ASI, address, mask8[address & 3]); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -3056,35 +3028,29 @@ inline void mb86901_device::execute_ldsba(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_lduba(uint32_t op) +inline void sparc_base_device::execute_lduba(uint32_t op) { if (IS_USER) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if (USEIMM) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } static const uint32_t mask8[4] = { 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff }; const uint32_t address = RS1REG + RS2REG; - const uint32_t data = m_mmu->read_asi(ASI, address >> 2, mask8[address & 3]); + const uint32_t data = read_word(ASI, address, mask8[address & 3]); if (m_mae) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -3106,66 +3072,9 @@ inline void mb86901_device::execute_lduba(uint32_t op) // instruction //------------------------------------------------- -void mb86901_device::execute_ldstub(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 169, "Appendix C - ISP Descriptions - Atomic Load-Store Unsigned Byte Instructions" (SPARCv8.pdf, pg. 166) - - if (LDSTUB) then ( - address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); - addr_space <- (if (S = 0) then 10 else 11) - } else if (LDSTUBA) then ( - if (S = 0) then ( - trap <- 1; - privileged_instruction <- 1 - ) else if (i = 1) then ( - trap <- 1; - illegal_instruction <- 1 - ) else ( - address <- r[rs1] + r[rs2]; - addr_space <- asi - ) - ); - next; - if (trap = 0) then ( - while ( (pb_block_ldst_byte = 1) or (pb_block_ldst_word = 1) ) then ( - { wait for lock(s) to be lifted } - { an implementation actually need only block when another LDSTUB or SWAP - is pending on the same byte in memory as the one addressed by this LDSTUB } - }; - next; - pb_block_ldst_byte <- 1; - next; - (data, MAE) <- memory_read(addr_space, address); - next; - if (MAE = 1) then ( - trap <- 1; - data_access_exception <- 1 - ) - ) - next; - if (trap = 0) then ( - if (address<1:0> = 0) then ( byte_mask <- 1000 ) - else if (address<1:0> = 1) then ( byte_mask <- 0100 ) - else if (address<1:0> = 2) then ( byte_mask <- 0010 ) - else if (address<1:0> = 3) then ( byte_mask <- 0001 ) - ; - next; - MAE <- memory_write(addr_space, address, byte_mask, FFFFFFFF); - next; - pb_block_ldst_byte <- 0; - if (MAE = 1) then ( { MAE = 1 only due to a "non-resumable machine-check error" } - trap <- 1; - data_access_exception <- 1 - ) else ( - if (address<1:0> = 0) then word <- zero_extend_byte(data<31:24>) - else if (address<1:0> = 1) then word <- zero_extend_byte(data<23:24>) - else if (address<1:0> = 2) then word <- zero_extend_byte(data<15: 8>) - else if (address<1:0> = 3) then word <- zero_extend_byte(data< 7: 0>) - next; - if (rd != 0) then r[rd] <- word - ) - ); - */ +void sparc_base_device::execute_ldstub(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 169, "Appendix C - ISP Descriptions - Atomic Load-Store Unsigned Byte Instructions" (SPARCv8.pdf, pg. 166) uint32_t address = 0; uint8_t addr_space = 0; @@ -3180,49 +3089,41 @@ void mb86901_device::execute_ldstub(uint32_t op) { m_trap = 1; m_privileged_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else if (USEIMM) { m_trap = 1; m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } else { address = RS1REG + RS2REG; addr_space = ASI; - return; } } - uint32_t data(0); - while (m_pb_block_ldst_byte || m_pb_block_ldst_word) - { + //while (m_pb_block_ldst_byte || m_pb_block_ldst_word) + //{ // { wait for lock(s) to be lifted } // { an implementation actually need only block when another LDSTUB or SWAP // is pending on the same byte in memory as the one addressed by this LDSTUB } - } + //} m_pb_block_ldst_byte = 1; static const uint32_t mask8[4] = { 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff }; - data = m_mmu->read_asi(addr_space, address >> 2, mask8[address & 3]); + uint32_t data = read_word(addr_space, address, mask8[address & 3]); if (MAE) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } - m_mmu->write_asi(addr_space, address >> 2, 0xffffffff, mask8[address & 3]); + write_word(addr_space, address, 0xffffffff, mask8[address & 3]); m_pb_block_ldst_byte = 0; @@ -3230,8 +3131,6 @@ void mb86901_device::execute_ldstub(uint32_t op) { m_trap = 1; m_data_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } @@ -3265,7 +3164,7 @@ void mb86901_device::execute_ldstub(uint32_t op) // (load/store) //------------------------------------------------- -inline void mb86901_device::execute_group3(uint32_t op) +inline void sparc_base_device::execute_group3(uint32_t op) { static const int ldst_cycles[64] = { 1, 1, 1, 2, 2, 2, 2, 3, @@ -3359,26 +3258,119 @@ inline void mb86901_device::execute_group3(uint32_t op) execute_ldstub(op); break; -#if SPARCV8 + default: + if (!execute_extra_group3(op)) + { + logerror("illegal instruction at %08x: %08x\n", PC, op); + m_trap = 1; + m_illegal_instruction = 1; + } + break; + } + + if (MAE) + m_icount--; + else + m_icount -= ldst_cycles[OP3]; +} + + +//------------------------------------------------- +// update_extra_group3 - execute a group3 +// instruction belonging to a newer SPARC version +// than v7 +//------------------------------------------------- + +bool sparcv7_device::execute_extra_group3(uint32_t op) +{ + return false; +} + +bool sparcv8_device::execute_extra_group3(uint32_t op) +{ + switch (OP3) + { case OP3_SWAP: case OP3_SWAPA: execute_swap(op); - break; -#endif + return true; default: - logerror("illegal instruction at %08x: %08x\n", PC, op); - m_trap = 1; - m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; - break; + return false; } +} - if (MAE /*|| HOLD_BUS*/) - m_icount--; + +//------------------------------------------------- +// evaluate_fp_condition - evaluate a given fp +// condition code +//------------------------------------------------- + +bool sparc_base_device::evaluate_fp_condition(uint32_t op) +{ + // COND & 8 + // 0 8 + // fbn fba + // fbne fbe + // fblg fbue + // fbul fbge + // fbl fbuge + // fbug fble + // fbg fbule + // fbu fbo + + static const uint32_t EQ_BIT = (1 << (FSR_FCC_EQ >> FSR_FCC_SHIFT)); + static const uint32_t LT_BIT = (1 << (FSR_FCC_LT >> FSR_FCC_SHIFT)); + static const uint32_t GT_BIT = (1 << (FSR_FCC_GT >> FSR_FCC_SHIFT)); + static const uint32_t UO_BIT = (1 << (FSR_FCC_UO >> FSR_FCC_SHIFT)); + const uint32_t fcc_bit = 1 << ((m_fsr & FSR_FCC_MASK) >> FSR_FCC_SHIFT); + + switch(COND) + { + case 0: return false; + case 1: return fcc_bit & (LT_BIT | GT_BIT | UO_BIT); + case 2: return fcc_bit & (LT_BIT | GT_BIT); + case 3: return fcc_bit & (LT_BIT | UO_BIT); + case 4: return fcc_bit & (LT_BIT); + case 5: return fcc_bit & (GT_BIT | UO_BIT); + case 6: return fcc_bit & (GT_BIT); + case 7: return fcc_bit & (UO_BIT); + + case 8: return true; + case 9: return fcc_bit & (EQ_BIT); + case 10: return fcc_bit & (EQ_BIT | UO_BIT); + case 11: return fcc_bit & (EQ_BIT | GT_BIT); + case 12: return fcc_bit & (EQ_BIT | GT_BIT | UO_BIT); + case 13: return fcc_bit & (EQ_BIT | LT_BIT); + case 14: return fcc_bit & (EQ_BIT | LT_BIT | UO_BIT); + case 15: return fcc_bit & (EQ_BIT | LT_BIT | GT_BIT); + } + + return false; +} + + +//------------------------------------------------- +// execute_fbfcc - execute an fp branch opcode +//------------------------------------------------- + +void sparc_base_device::execute_fbfcc(uint32_t op) +{ + bool branch_taken = evaluate_fp_condition(op); + uint32_t pc = PC; + PC = nPC; + if (branch_taken) + { + nPC = pc + DISP22; + if (COND == COND_BA && ANNUL) + m_no_annul = false; + } else - m_icount -= ldst_cycles[OP3]; + { + nPC = nPC + 4; + if (ANNUL) + m_no_annul = false; + } } @@ -3387,7 +3379,7 @@ inline void mb86901_device::execute_group3(uint32_t op) // condition code //------------------------------------------------- -bool mb86901_device::evaluate_condition(uint32_t op) +bool sparc_base_device::evaluate_condition(uint32_t op) { // COND & 8 // 0 8 @@ -3429,39 +3421,9 @@ bool mb86901_device::evaluate_condition(uint32_t op) // execute_bicc - execute a branch opcode //------------------------------------------------- -void mb86901_device::execute_bicc(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 178, "Appendix C - ISP Descriptions - Branch on Integer Condition Instructions" (SPARCv8.pdf, pg. 175) - - eval_icc := ( - if (BNE) then (if (Z = 0) then 1 else 0); - if (BE) then (if (Z = 1) then 1 else 0); - if (BG) then (if ((Z or (N xor V)) = 0) then 1 else 0); - if (BLE) then (if ((Z or (N xor V)) = 1) then 1 else 0); - if (BGE) then (if ((N xor V) = 0) then 1 else 0); - if (BL) then (if ((N xor V) = 1) then 1 else 0); - if (BGU) then (if ((C = 0) and (Z = 0)) then 1 else 0); - if (BLEU) then (if ((C = 1) or (Z = 1)) then 1 else 0); - if (BCC) then (if (C = 0) then 1 else 0); - if (BCS) then (if (C = 1) then 1 else 0); - if (BPOS) then (if (N = 0) then 1 else 0); - if (BNEG) then (if (N = 1) then 1 else 0); - if (BVC) then (if (V = 0) then 1 else 0); - if (BVS) then (if (V = 1) then 1 else 0); - if (BA) then 1; - if (BN) then 0; - ) - PC <- nPC; - if (eval_icc = 1) then ( - nPC <- PC + sign_extend(disp22[]00); - if (BA and (a = 1)) then - annul <- 1 { only for annulling Branch-Always } - ) else ( - nPC <- nPC + 4; - if (a = 1) then - annul <- 1 { only for annulling branches other than BA } - ) - */ +void sparc_base_device::execute_bicc(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 178, "Appendix C - ISP Descriptions - Branch on Integer Condition Instructions" (SPARCv8.pdf, pg. 175) bool branch_taken = evaluate_condition(op); uint32_t pc = PC; @@ -3485,42 +3447,9 @@ void mb86901_device::execute_bicc(uint32_t op) // execute_ticc - execute a conditional trap //------------------------------------------------- -void mb86901_device::execute_ticc(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 182, "Appendix C - ISP Descriptions - Trap on Integer Condition Instructions" (SPARCv8.pdf, pg. 179) - - trap_eval_icc := ( - if (TNE) then (if (Z = 0) then 1 else 0); - if (TE) then (if (Z = 1) then 1 else 0); - if (TG) then (if ((Z or (N xor V)) = 0) then 1 else 0); - if (TLE) then (if ((Z or (N xor V)) = 1) then 1 else 0); - if (TGE) then (if ((N xor V) = 0) then 1 else 0); - if (TL) then (if ((N xor V) = 1) then 1 else 0); - if (TGU) then (if ((C = 0) and (Z = 0)) then 1 else 0); - if (TLEU) then (if ((C = 1) or (Z = 1)) then 1 else 0); - if (TCC) then (if (C = 0) then 1 else 0); - if (TCS) then (if (C = 1) then 1 else 0); - if (TPOS) then (if (N = 0) then 1 else 0); - if (TNEG) then (if (N = 1) then 1 else 0); - if (TVC) then (if (V = 0) then 1 else 0); - if (TVS) then (if (V = 1) then 1 else 0); - if (TA) then 1; - if (TN) then 0; - ) - - trap_number := r[rs1] + (if (i = 0) then r[rs2] else sign_extend(software_trap#)); - - if (Ticc) then ( - if (trap_eval_icc = 1) then ( - trap <- 1; - trap_instruction <- 1; - ticc_trap_type <- trap_number<6:0> - ) else ( - PC <- nPC; - nPC <- nPC + 4; - ) - ); - */ +void sparc_base_device::execute_ticc(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 182, "Appendix C - ISP Descriptions - Trap on Integer Condition Instructions" (SPARCv8.pdf, pg. 179) bool trap_eval_icc = evaluate_condition(op); @@ -3533,8 +3462,6 @@ void mb86901_device::execute_ticc(uint32_t op) m_trap = 1; m_trap_instruction = 1; m_ticc_trap_type = trap_number & 0x7f; - m_stashed_icount = m_icount; - m_icount = 0; } else { @@ -3551,7 +3478,7 @@ void mb86901_device::execute_ticc(uint32_t op) // additional functions from taking them //------------------------------------------------- -void mb86901_device::select_trap() +void sparc_base_device::select_trap() { if (!m_trap) return; @@ -3565,10 +3492,74 @@ void mb86901_device::select_trap() { m_execute_mode = 0; m_error_mode = 1; - m_stashed_icount = m_icount; m_icount = 0; } - else if (m_data_store_error) + else + { + update_tt(); + } + + TBR = (TBR & 0xfffff000) | (m_tt << 4); + m_trap = 0; + m_instruction_access_exception = 0; + m_illegal_instruction = 0; + m_privileged_instruction = 0; + m_fp_disabled = 0; + m_fp_exception = 0; + m_cp_disabled = 0; + m_window_overflow = 0; + m_window_underflow = 0; + m_mem_address_not_aligned = 0; + m_cp_exception = 0; + m_data_access_exception = 0; + m_tag_overflow = 0; + m_trap_instruction = 0; + m_interrupt_level = 0; + m_mae = 0; +} + + +//------------------------------------------------- +// update_tt - determine TT register contents +// based on trap priority +//------------------------------------------------- + +void sparcv7_device::update_tt() +{ + if (m_instruction_access_exception) + m_tt = 0x01; + else if (m_privileged_instruction) + m_tt = 0x03; + else if (m_illegal_instruction) + m_tt = 0x02; + else if (m_fp_disabled) + m_tt = 0x04; + else if (m_cp_disabled) + m_tt = 0x24; + else if (m_window_overflow) + m_tt = 0x05; + else if (m_window_underflow) + m_tt = 0x06; + else if (m_mem_address_not_aligned) + m_tt = 0x07; + else if (m_fp_exception) + m_tt = 0x08; + else if (m_cp_exception) + m_tt = 0x28; + else if (m_data_access_exception) + m_tt = 0x09; + else if (m_tag_overflow) + m_tt = 0x0a; + else if (m_trap_instruction) + m_tt = 0x80 | m_ticc_trap_type; + else if (m_interrupt_level > 0) + m_tt = 0x10 | m_interrupt_level; +} + + +void sparcv8_device::update_tt() +{ + if (m_data_store_error) m_tt = 0x2b; else if (m_instruction_access_error) m_tt = 0x21; @@ -3609,24 +3600,12 @@ void mb86901_device::select_trap() else if (m_interrupt_level > 0) m_tt = 0x10 | m_interrupt_level; - TBR = (TBR & 0xfffff000) | (m_tt << 4); - m_trap = 0; - m_instruction_access_exception = 0; - m_illegal_instruction = 0; - m_privileged_instruction = 0; - m_fp_disabled = 0; - m_cp_disabled = 0; - m_window_overflow = 0; - m_window_underflow = 0; - m_mem_address_not_aligned = 0; - m_fp_exception = 0; - m_cp_exception = 0; - m_data_access_exception = 0; - m_tag_overflow = 0; + m_unimplemented_FLUSH = 0; + m_r_register_access_error = 0; + m_instruction_access_error = 0; + m_data_access_error = 0; + m_data_store_error = 0; m_division_by_zero = 0; - m_trap_instruction = 0; - m_interrupt_level = 0; - m_mae = 0; } @@ -3636,86 +3615,9 @@ void mb86901_device::select_trap() // instructions, if any. //------------------------------------------------- -void mb86901_device::execute_trap() -{ - /* The SPARC Instruction Manual: Version 8, page 161, "Appendix C - C.8. Traps" (SPARCv8.pdf, pg. 158) - - select_trap; { see below } - next; - - if (error_mode = 0) then ( - ET <- 0; - PS <- S; - CWP <- (CWP - 1) modulo NWINDOWS; - - next; - if (annul = 0) then ( - r[17] <- PC; - r[18] <- nPC; - ) else { annul != 0) } ( - r[17] <- nPC; - r[18] <- nPC + 4; - annul <- 0; - ) - - next; - S <- 1; - if (reset_trap = 0) then ( - PC <- TBR; - nPC <- TBR + 4; - ) else { reset_trap = 1 } ( - PC <- 0; - nPC <- 4; - reset_trap <- 0; - ) - ); - - select_trap := ( - if (reset_trap = 1) then { ignore ET, and leave tt unchanged } - else if (ET = 0) then ( - execute_mode <- 0; - error_mode <- 1 ) - else if (data_store_error = 1) then tt <- 00101011 - else if (instruction_access_error = 1) then tt <- 00100001 - else if (r_register_access_error = 1) then tt <- 00100000 - else if (instruction_access_exception = 1) then tt <- 00000001 - else if (privileged_instruction = 1) then tt <- 00000011 - else if (illegal_instruction = 1) then tt <- 00000010 - else if (fp_disabled = 1) then tt <- 00000100 - else if (cp_disabled = 1) then tt <- 00100100 - else if (unimplemented_FLUSH = 1) then tt <- 00100101 - else if (window_overflow = 1) then tt <- 00000101 - else if (window_underflow = 1) then tt <- 00000110 - else if (mem_address_not_aligned = 1) then tt <- 00000111 - else if (fp_exception = 1) then tt <- 00001000 - else if (cp_exception = 1) then tt <- 00101000 - else if (data_access_error = 1) then tt <- 00101001 - else if (data_access_exception = 1) then tt <- 00001001 - else if (tag_overflow = 1) then tt <- 00001010 - else if (division_by_zero = 1) then tt <- 00101010 - else if (trap_instruction = 1) then tt <- 1[]ticc_trap_type - else if (interrupt_level > 0) then tt <- 0001[]interrupt_level; - - next; - - trap <- 0; - instruction_access_exception <- 0; - illegal_instruction <- 0; - privileged_instruction <- 0; - fp_disabled <- 0; - cp_disabled <- 0; - window_overflow <- 0; - window_underflow <- 0; - mem_address_not_aligned <- 0; - fp_exception <- 0; - cp_exception <- 0; - data_access_exception <- 0; - tag_overflow <- 0; - division_by_zero <- 0; - trap_instruction <- 0; - interrupt_level <- 0; - ); - */ +void sparc_base_device::execute_trap() +{ + // The SPARC Instruction Manual: Version 8, page 161, "Appendix C - C.8. Traps" (SPARCv8.pdf, pg. 158) if (!m_trap) { @@ -3778,33 +3680,9 @@ void mb86901_device::execute_trap() // single fetched instruction. //------------------------------------------------- -/* The SPARC Instruction Manual: Version 8, page 159, "Appendix C - ISP Descriptions - C.6. Instruction Dispatch" (SPARCv8.pdf, pg. 156) - -illegal_IU_instr :- ( - if ( ( (op == 00) and (op2 == 000) ) { UNIMP instruction } - or - ( ((op=11) or (op=10)) and (op3=unassigned) ) - then 1 else 0 - -if (illegal_IU_instr = 1) then ( - trap <- 1 - illegal_instruction <- 1 -); -if ((FPop1 or FPop2 or FBfcc) and ((EF = 0) or (bp_FPU_present = 0))) then ( - trap <- 1; - fp_disabled <- 1 -); -if (CPop1 or CPop2 or CBccc) and ((EC = 0) or (bp_CP_present = 0))) then ( - trap <- 1; - cp_disabled <- 1 -); -next; -if (trap = 0) then ( - { code for specific instruction, defined below } -); -*/ - -inline void mb86901_device::dispatch_instruction(uint32_t op) +// The SPARC Instruction Manual: Version 8, page 159, "Appendix C - ISP Descriptions - C.6. Instruction Dispatch" (SPARCv8.pdf, pg. 156) + +inline void sparc_base_device::dispatch_instruction(uint32_t op) { const uint8_t op_type = OP; switch (op_type) @@ -3818,44 +3696,28 @@ inline void mb86901_device::dispatch_instruction(uint32_t op) case OP2_BICC: // branch on integer condition codes execute_bicc(op); break; - case OP2_SETHI: // sethi - //SET_RDREG(IMM22); - *m_regs[RD] = op << 10; - m_r[0] = 0; + case OP2_SETHI: // sethi or nop + if (RDBITS) RDREG = op << 10; PC = nPC; nPC = nPC + 4; break; case OP2_FBFCC: // branch on floating-point condition codes if (!(PSR & PSR_EF_MASK) || !m_bp_fpu_present) { - logerror("fbfcc at %08x: %08x\n", PC, op); m_trap = 1; m_fp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } + execute_fbfcc(op); break; -#if SPARCV8 - case OP2_CBCCC: // branch on coprocessor condition codes, SPARCv8 - if (!(PSR & PSR_EC_MASK) || !m_bp_cp_present) + default: + if (!dispatch_extra_instruction(op)) { - logerror("cbccc @ %08x: %08x\n", PC, op); + logerror("illegal instruction at %08x: %08x\n", PC, op); m_trap = 1; - m_cp_disabled = 1; - m_stashed_icount = m_icount; - m_icount = 0; - return; + m_illegal_instruction = 1; } return; -#endif - default: - logerror("illegal instruction at %08x: %08x\n", PC, op); - m_trap = 1; - m_illegal_instruction = 1; - m_stashed_icount = m_icount; - m_icount = 0; - return; } break; @@ -3880,78 +3742,654 @@ inline void mb86901_device::dispatch_instruction(uint32_t op) } } +bool sparcv7_device::dispatch_extra_instruction(uint32_t op) +{ + return false; +} + +bool sparcv8_device::dispatch_extra_instruction(uint32_t op) +{ + const uint8_t op_type = OP; + switch (op_type) + { + case OP_TYPE0: // Bicc, SETHI, FBfcc + switch (OP2) + { + case OP2_CBCCC: // branch on coprocessor condition codes, SPARCv8 + if (!(PSR & PSR_EC_MASK) || !m_bp_cp_present) + { + logerror("cbccc @ %08x: %08x\n", PC, op); + m_trap = 1; + m_cp_disabled = 1; + return true; + } + return true; + default: + return false; + } + default: + return false; + } +} + +void sparc_base_device::check_fdiv_zero_exception() +{ + m_fsr |= FSR_CEXC_DZC; + if (m_fsr & FSR_TEM_DZM) + { + m_fsr = (m_fsr & ~FSR_FTT_MASK) | FSR_FTT_IEEE; + m_fp_exception_pending = true; + return; + } + m_fsr |= FSR_AEXC_DZA; +} + +bool sparc_base_device::check_fp_exceptions() +{ + if (softfloat_exceptionFlags & softfloat_flag_inexact) + m_fsr |= FSR_CEXC_NXC; + if (softfloat_exceptionFlags & softfloat_flag_underflow) + m_fsr |= FSR_CEXC_UFC; + if (softfloat_exceptionFlags & softfloat_flag_overflow) + m_fsr |= FSR_CEXC_OFC; + if (softfloat_exceptionFlags & softfloat_flag_invalid) + m_fsr |= FSR_CEXC_NVC; + + // accrue disabled exceptions + const uint32_t cexc = m_fsr & FSR_CEXC_MASK; + const uint32_t tem = (m_fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT; + m_fsr |= (~tem & cexc) << FSR_AEXC_SHIFT; + + // check if exception is enabled + if (tem & cexc) + { + m_fsr = (m_fsr & ~FSR_FTT_MASK) | FSR_FTT_IEEE; + m_fp_exception = 1; + return true; + } + return false; +} + +bool sparc_base_device::get_fpr32(uint32_t &data, const uint32_t rd) +{ + if (m_pending_fpr == rd) + { + return true; + } + data = FREG(rd); + return false; +} + +bool sparc_base_device::get_fpr64(uint64_t &data, const uint32_t rd) +{ + if (m_pending_fpr == rd || m_pending_fpr == (rd | 1)) + { + return true; + } + data = (uint64_t)FREG(rd) << 32; + data |= FREG(rd | 1); + return false; +} + +bool sparc_base_device::set_fpr32(const uint32_t rd, const uint32_t data) +{ + m_pending_fpr = rd; + if (softfloat_exceptionFlags && check_fp_exceptions()) + { + m_fp_exception_pending = true; + m_fpr[rd] = 0; + return true; + } + + m_fpr[rd] = data; + return false; +} + +bool sparc_base_device::set_fpr64(const uint32_t rd, const uint64_t data) +{ + m_pending_fpr = rd; + if (softfloat_exceptionFlags && check_fp_exceptions()) + { + m_fp_exception_pending = true; + m_fpr[rd] = 0; + m_fpr[rd + 1] = 0; + return true; + } + + m_fpr[rd] = (uint32_t)(data >> 32); + m_fpr[rd + 1] = (uint32_t)data; + return false; +} + //------------------------------------------------- // complete_fp_execution - completes execution // of a floating-point operation //------------------------------------------------- -void mb86901_device::complete_fp_execution(uint32_t /*op*/) +void sparc_base_device::complete_fp_execution(uint32_t op) { + softfloat_exceptionFlags = 0; + + uint32_t rs1 = 0; + uint32_t rs2 = 0; + uint64_t rd1 = 0; + uint64_t rd2 = 0; + + const uint32_t fpop = (op >> 5) & 0x1ff; + switch (fpop) + { + case FPOP_FMOVS: + if (RD == m_pending_fpr) return; + if (get_fpr32(rs2, RS2)) return; + m_fpr_pending = 4; + set_fpr32(RD, rs2); + break; + case FPOP_FNEGS: + { + if (RD == m_pending_fpr) return; + if (get_fpr32(rs2, RS2)) return; + m_fpr_pending = 4; + const float32_t fs2 = float32_t{ rs2 }; + set_fpr32(RD, f32_mul(fs2, i32_to_f32(-1)).v); + break; + } + case FPOP_FABSS: + { + if (RD == m_pending_fpr) return; + if (get_fpr32(rs2, RS2)) return; + m_fpr_pending = 4; + const float32_t fs2 = float32_t{ rs2 }; + if (f32_lt(fs2, float32_t{0})) + { + set_fpr32(RD, f32_mul(fs2, i32_to_f32(-1)).v); + } + else + { + set_fpr32(RD, rs2); + } + break; + } + case FPOP_FSQRTS: + { + if (RD == m_pending_fpr) return; + if (get_fpr32(rs2, RS2)) return; + m_fpr_pending = 62; + const float32_t fs2 = float32_t{ rs2 }; + set_fpr32(RD, f32_sqrt(fs2).v); + break; + } + case FPOP_FSQRTD: + { + if (RD == m_pending_fpr) return; + if (get_fpr64(rd2, RS2_D)) return; + m_fpr_pending = 120; + const float64_t fs2 = float64_t{ rd2 }; + set_fpr64(RD_D, f64_sqrt(fs2).v); + break; + } + case FPOP_FADDS: + { + if (RD == m_pending_fpr) return; + if (get_fpr32(rs1, RS1) || get_fpr32(rs2, RS2)) return; + m_fpr_pending = 8; + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + set_fpr32(RD, f32_add(fs1, fs2).v); + break; + } + case FPOP_FADDD: + { + if (RD == m_pending_fpr) return; + if (get_fpr64(rd1, RS1_D) || get_fpr64(rd2, RS2_D)) return; + m_fpr_pending = 8; + const float64_t fs1 = float64_t{ rd1 }; + const float64_t fs2 = float64_t{ rd2 }; + set_fpr64(RD_D, f64_add(fs1, fs2).v); + break; + } + case FPOP_FSUBS: + { + if (RD == m_pending_fpr) return; + if (get_fpr32(rs1, RS1) || get_fpr32(rs2, RS2)) return; + m_fpr_pending = 8; + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + set_fpr32(RD, f32_sub(fs1, fs2).v); + break; + } + case FPOP_FSUBD: + { + if (RD == m_pending_fpr) return; + if (get_fpr64(rd1, RS1_D) || get_fpr64(rd2, RS2_D)) return; + m_fpr_pending = 8; + const float64_t fs1 = float64_t{ rd1 }; + const float64_t fs2 = float64_t{ rd2 }; + set_fpr64(RD_D, f64_sub(fs1, fs2).v); + break; + } + case FPOP_FMULS: + { + if (RD == m_pending_fpr) return; + if (get_fpr32(rs1, RS1) || get_fpr32(rs2, RS2)) return; + m_fpr_pending = 8; + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + set_fpr32(RD, f32_mul(fs1, fs2).v); + break; + } + case FPOP_FMULD: + { + if (RD == m_pending_fpr) return; + if (get_fpr64(rd1, RS1_D) || get_fpr64(rd2, RS2_D)) return; + m_fpr_pending = 14; + const float64_t fs1 = float64_t{ rd1 }; + const float64_t fs2 = float64_t{ rd2 }; + set_fpr64(RD_D, f64_mul(fs1, fs2).v); + break; + } + case FPOP_FDIVS: + { + if (RD == m_pending_fpr) return; + if (get_fpr32(rs1, RS1) || get_fpr32(rs2, RS2)) return; + m_fpr_pending = 40; + if (rs2 == 0) + { + check_fdiv_zero_exception(); + m_pending_fpr = RD; + break; + } + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + set_fpr32(RD, f32_div(fs1, fs2).v); + break; + } + case FPOP_FDIVD: + { + if (RD == m_pending_fpr) return; + if (get_fpr64(rd1, RS1_D) || get_fpr64(rd2, RS2_D)) return; + m_fpr_pending = 68; + if (rd2 == 0) + { + check_fdiv_zero_exception(); + m_pending_fpr = RD; + break; + } + const float64_t fs1 = float64_t{ rd1 }; + const float64_t fs2 = float64_t{ rd2 }; + set_fpr64(RD_D, f64_div(fs1, fs2).v); + break; + } + case FPOP_FITOS: + { + if (RD == m_pending_fpr) return; + if (get_fpr32(rs2, RS2)) return; + m_fpr_pending = 16; + set_fpr32(RD, i32_to_f32(int32_t(rs2)).v); + break; + } + case FPOP_FDTOS: + { + if (RD == m_pending_fpr) return; + if (get_fpr64(rd2, RS2_D)) return; + m_fpr_pending = 8; + const float64_t fs2 = float64_t{ rd2 }; + set_fpr32(RD, f64_to_f32(fs2).v); + break; + } + case FPOP_FITOD: + { + if (RD_D == m_pending_fpr) return; + if (get_fpr32(rs2, RS2)) return; + m_fpr_pending = 8; + set_fpr64(RD_D, i32_to_f64(int32_t(rs2)).v); + break; + } + case FPOP_FSTOD: + { + if (RD_D == m_pending_fpr) return; + if (get_fpr32(rs2, RS2)) return; + m_fpr_pending = 8; + const float32_t fs = float32_t{ rs2 }; + set_fpr64(RD_D, f32_to_f64(fs).v); + break; + } + case FPOP_FSTOI: + { + if (RD == m_pending_fpr) return; + if (get_fpr32(rs2, RS2)) return; + m_fpr_pending = 16; // Guessed based on FITOS + const float32_t fs2 = float32_t{ rs2 }; + set_fpr32(RD, f32_to_i32(fs2, softfloat_roundingMode, true)); + break; + } + case FPOP_FDTOI: + { + if (RD == m_pending_fpr) return; + if (get_fpr64(rd2, RS2_D)) return; + m_fpr_pending = 8; // Guessed based on FITOD + const float64_t fs2 = float64_t{ rd2 }; + set_fpr32(RD, f64_to_i32(fs2, softfloat_roundingMode, true)); + break; + } + case FPOP_FCMPS: + { + if (get_fpr32(rs1, RS1) || get_fpr32(rs2, RS2)) return; + m_fpr_pending = 4; + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + bool equal = f32_eq(fs1, fs2); + if (softfloat_exceptionFlags & softfloat_flag_invalid) + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_UO; + else if (equal) + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_EQ; + else if (f32_lt(fs1, fs2)) + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_LT; + else + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_GT; + break; + } + case FPOP_FCMPD: + { + if (get_fpr64(rd1, RS1_D) || get_fpr64(rd2, RS2_D)) return; + m_fpr_pending = 4; + const float64_t fs1 = float64_t{ rd1 }; + const float64_t fs2 = float64_t{ rd2 }; + bool equal = f64_eq(fs1, fs2); + if (softfloat_exceptionFlags & softfloat_flag_invalid) + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_UO; + else if (equal) + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_EQ; + else if (f64_lt(fs1, fs2)) + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_LT; + else + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_GT; + break; + } + case FPOP_FCMPES: + { + if (get_fpr32(rs1, RS1) || get_fpr32(rs2, RS2)) return; + m_fpr_pending = 4; + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + bool equal = f32_eq(fs1, fs2); + if (softfloat_exceptionFlags & softfloat_flag_invalid) + { + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_UO; + m_fsr |= FSR_CEXC_NVC; + if (m_fsr & FSR_TEM_NVM) + { + m_fsr = (m_fsr & ~FSR_FTT_MASK) | FSR_FTT_IEEE; + m_fp_exception = 1; + break; + } + m_fsr |= FSR_AEXC_NVA; + } + else if (equal) + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_EQ; + else if (f32_lt(fs1, fs2)) + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_LT; + else + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_GT; + break; + } + case FPOP_FCMPED: + { + if (get_fpr64(rd1, RS1_D) || get_fpr64(rd2, RS2_D)) return; + m_fpr_pending = 4; + const float64_t fs1 = float64_t{ rd1 }; + const float64_t fs2 = float64_t{ rd2 }; + bool equal = f64_eq(fs1, fs2); + if (softfloat_exceptionFlags & softfloat_flag_invalid) + { + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_UO; + m_fsr |= FSR_CEXC_NVC; + if (m_fsr & FSR_TEM_NVM) + { + m_fsr = (m_fsr & ~FSR_FTT_MASK) | FSR_FTT_IEEE; + m_fp_exception = 1; + break; + } + m_fsr |= FSR_AEXC_NVA; + } + else if (equal) + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_EQ; + else if (f64_lt(fs1, fs2)) + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_LT; + else + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_GT; + break; + } + case FPOP_FSQRTX: + case FPOP_FADDX: + case FPOP_FSUBX: + case FPOP_FMULX: + case FPOP_FDIVX: + case FPOP_FXTOI: + case FPOP_FXTOS: + case FPOP_FXTOD: + case FPOP_FITOX: + case FPOP_FSTOX: + case FPOP_FDTOX: + case FPOP_FCMPX: + case FPOP_FCMPEX: + default: + m_fsr = (m_fsr & ~FSR_FTT_MASK) | FSR_FTT_UNIMP; + m_fp_exception = 1; + break; + } + + PC = nPC; + nPC = nPC + 4; } + +//------------------------------------------------- +// execute_swap - execute a swap instruction +//------------------------------------------------- + +void sparcv8_device::execute_swap(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 169, "Appendix C - ISP Descriptions - Atomic Load-Store Unsigned Byte Instructions" (SPARCv8.pdf, pg. 166) + + uint32_t address = 0; + uint8_t addr_space = 0; + if (SWAP) + { + address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + addr_space = (IS_USER ? 10 : 11); + } + else if (SWAPA) + { + if (IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + return; + } + else if (USEIMM) + { + m_trap = 1; + m_illegal_instruction = 1; + return; + } + else + { + address = RS1REG + RS2REG; + addr_space = ASI; + } + } + + if (address & 3) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + return; + } + + uint32_t word = 0; + uint32_t data = RDREG; + + //while (m_pb_block_ldst_byte || m_pb_block_ldst_word) + //{ + // { wait for lock(s) to be lifted } + // { an implementation actually need only block when another SWAP is pending on + // the same word in memory as the one addressed by this SWAP, or a LDSTUB is + // pending on any byte of the word in memory addressed by this SWAP } + //} + + m_pb_block_ldst_word = 1; + + word = read_word(addr_space, address); + + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + return; + } + + write_word(addr_space, address, data); + + m_pb_block_ldst_word = 0; + + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + return; + } + + if (RDBITS) + RDREG = word; + + PC = nPC; + nPC = nPC + 4; +} + + +//------------------------------------------------- +// execute_mul - execute a multiply opcode +//------------------------------------------------- + +void sparcv8_device::execute_mul(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 175, "Appendix C - ISP Descriptions - Multiply Instructions" (SPARCv8.pdf, pg. 172) + + uint32_t operand2 = (USEIMM ? SIMM13 : RS2REG); + + uint32_t result = 0; + if (UMUL || UMULCC) + { + uint64_t dresult = mulu_32x32(RS1REG, operand2); + Y = (uint32_t)(dresult >> 32); + result = (uint32_t)dresult; + } + else if (SMUL || SMULCC) + { + int64_t dresult = mul_32x32(RS1REG, operand2); + Y = (uint32_t)(dresult >> 32); + result = (uint32_t)dresult; + } + + if (RDBITS) + { + RDREG = result; + } + if (UMULCC || SMULCC) + { + CLEAR_ICC; + PSR |= BIT31(result) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + } + + PC = nPC; + nPC = nPC + 4; +} + + +//------------------------------------------------- +// execute_div - execute a divide opcode +//------------------------------------------------- + +void sparcv8_device::execute_div(uint32_t op) +{ + // The SPARC Instruction Manual: Version 8, page 176, "Appendix C - ISP Descriptions - Multiply Instructions" (SPARCv8.pdf, pg. 173) + + uint32_t operand2 = (USEIMM ? SIMM13 : RS2REG); + + if (operand2 == 0) + { + m_trap = 1; + m_division_by_zero = 1; + return; + } + else + { + uint32_t result = 0; + bool temp_v = false; + int64_t temp_64bit = 0; + if (UDIV || UDIVCC) + { + temp_64bit = int64_t(uint64_t((uint64_t(Y) << 32) | uint64_t(RS1REG)) / operand2); + + result = uint32_t(temp_64bit); + + temp_v = ((temp_64bit & 0xffffffff00000000ULL) == 0) ? false : true; + } + else if (SDIV || SDIVCC) + { + temp_64bit = int64_t(int64_t((uint64_t(Y) << 32) | uint64_t(RS1REG)) / operand2); + + result = uint32_t(temp_64bit); + + uint64_t shifted = uint64_t(temp_64bit) >> 31; + temp_v = (shifted == 0 || shifted == 0x1ffffffffULL) ? false : true; + } + + if (temp_v) + { + if (UDIV || UDIVCC) + { + result = 0xffffffff; + } + else if (SDIV || SDIVCC) + { + if (temp_64bit > 0) + result = 0x7fffffff; + else + result = 0x80000000; + } + } + + if (RDBITS) + RDREG = result; + + if (UDIVCC || SDIVCC) + { + CLEAR_ICC; + PSR |= BIT31(result) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= temp_v ? PSR_V_MASK : 0; + } + } + + PC = nPC; + nPC = nPC + 4; +} + + //------------------------------------------------- // execute_step - perform one step in execute // mode (versus error or reset modes) //------------------------------------------------- -inline void mb86901_device::execute_step() -{ - /* The SPARC Instruction Manual: Version 8, page 156, "Appendix C - ISP Descriptions - C.5. Processor States and Instruction Dispatch" (SPARCv8.pdf, pg. 153) - - if (bp_reset_in = 1) then ( - execute_mode <- 0; - reset_mode <- 1; - break { out of while (execute_mode = 1) loop } - ) else if ((ET = 1) and ((bp_IRL = 15) or (bp_IRL > PIL))) then ( - trap <- 1; - interrupt_level <- bp_IRL - ); - next; - - if (trap = 1) then execute_trap; { See Section C.8 } - - if (execute_mode = 1) then ( { execute_trap may have set execute_mode to 0 } - - { the following code emulates the delayed nature of the write-state-register instructions. - PSR <- PSR'; PSR' <- PSR''; PSR'' <- PSR'''; PSR''' <- PSR''''; - ASR <- ASR'; ASR' <- ASR''; ASR'' <- ASR'''; ASR''' <- ASR''''; - TBR <- TBR'; TBR' <- TBR''; TBR'' <- TBR'''; TBR''' <- TBR''''; - WIM <- WIM'; WIM' <- WIM''; WIM'' <- WIM'''; WIM''' <- WIM''''; - Y <- Y'; Y' <- Y''; Y'' <- Y'''; Y''' <- Y''''; - next; - - addr_space := (if (S = 0) then 8 else 9); - (instruction, MAE) <- memory_read(addr_space, PC); - next; - - if ( (MAE = 1) and (annul = 0) ) then ( - trap <- 1; - instruction_access_exception <- 1 - ) else ( - if (annul = 0) then ( - dispatch_instruction ; { See Section C.6 } - next; - if (FPop1 or FPop2) then ( - complete_fp_execution { See Section C.7 } - ) - next; - if ( (trap = 0) and - not (CALL or RETT or JMPL or Bicc or FBfcc or CBccc or Ticc) ) then ( - PC <- nPC; - nPC <- nPC + 4 - ) - ) else { annul != 0 } ( - annul <- 0; - PC <- nPC; - nPC <- nPC + 4 - ) - ) - ) - */ +inline void sparc_base_device::execute_step() +{ + // The SPARC Instruction Manual: Version 8, page 156, "Appendix C - ISP Descriptions - C.5. Processor States and Instruction Dispatch" (SPARCv8.pdf, pg. 153) // write-state-register delay not yet implemented - const uint32_t op = m_mmu->fetch_insn(m_s, PC >> 2); + const uint32_t op = read_word(8 + (IS_SUPERVISOR ? 1 : 0), PC); #if LOG_FCODES //if (m_log_fcodes) @@ -3966,11 +4404,25 @@ inline void mb86901_device::execute_step() { m_trap = 1; m_instruction_access_exception = 1; - m_stashed_icount = m_icount; - m_icount = 0; return; } dispatch_instruction(op); + + if (m_fpr_pending) + { + m_fpr_pending--; + if (!m_fpr_pending) + { + m_pending_fpr = std::size(m_fpr); + if (m_fp_exception_pending) + { + m_fp_exception_pending = false; + m_trap = 1; + m_fp_exception = 1; + return; + } + } + } } else { @@ -3985,29 +4437,14 @@ inline void mb86901_device::execute_step() // reset_step - step one cycle in reset mode //------------------------------------------------- -void mb86901_device::reset_step() +void sparc_base_device::reset_step() { - /* The SPARC Instruction Manual: Version 8, page 156, "Appendix C - ISP Descriptions - C.5. Processor States and Instruction Dispatch" (SPARCv8.pdf, pg. 153) - - while (reset_mode = 1) ( - if (bp_reset_in = 0) then ( - reset_mode <- 0; - execute_mode <- 1; - trap <- 1; - reset_trap <- 1; - ) - ); - */ + // The SPARC Instruction Manual: Version 8, page 156, "Appendix C - ISP Descriptions - C.5. Processor States and Instruction Dispatch" (SPARCv8.pdf, pg. 153) - if (!m_bp_reset_in) - { - m_reset_mode = 0; - m_execute_mode = 1; - m_trap = 1; - m_reset_trap = 1; - m_stashed_icount = m_icount; - m_icount = 0; - } + m_reset_mode = 0; + m_execute_mode = 1; + m_trap = 1; + m_reset_trap = 1; } @@ -4015,31 +4452,16 @@ void mb86901_device::reset_step() // error_step - step one cycle in error mode //------------------------------------------------- -void mb86901_device::error_step() +void sparc_base_device::error_step() { - /* The SPARC Instruction Manual: Version 8, page 157, "Appendix C - ISP Descriptions - C.5. Processor States and Instruction Dispatch" (SPARCv8.pdf, pg. 154) - - while (error_mode = 1) ( - if (bp_reset_in = 1) then ( - error_mode <- 0; - reset_mode <- 1; - pb_error <- 0 - ) - ); - */ + // The SPARC Instruction Manual: Version 8, page 157, "Appendix C - ISP Descriptions - C.5. Processor States and Instruction Dispatch" (SPARCv8.pdf, pg. 154) - if (m_bp_reset_in) - { - m_error_mode = 0; - m_reset_mode = 1; - m_pb_error = 0; - m_stashed_icount = m_icount; - m_icount = 0; - } + // waiting for SPARC_RESET + m_icount = 0; } -template <bool CHECK_DEBUG, mb86901_device::running_mode MODE> -void mb86901_device::run_loop() +template <bool CHECK_DEBUG, sparc_base_device::running_mode MODE> +void sparc_base_device::run_loop() { do { @@ -4049,19 +4471,22 @@ void mb86901_device::run_loop() continue; }*/ - if (CHECK_DEBUG) - debugger_instruction_hook(PC); - if (MODE == MODE_RESET) { + if (CHECK_DEBUG) + debugger_wait_hook(); reset_step(); } else if (MODE == MODE_ERROR) { + if (CHECK_DEBUG) + debugger_wait_hook(); error_step(); } else if (MODE == MODE_EXECUTE) { + if (CHECK_DEBUG) + debugger_instruction_hook(PC); execute_step(); } @@ -4075,7 +4500,7 @@ void mb86901_device::run_loop() } } --m_icount; - } while (m_icount >= 0); + } while (m_icount > 0 && !m_trap); } //------------------------------------------------- @@ -4083,16 +4508,20 @@ void mb86901_device::run_loop() // opcodes //------------------------------------------------- -void mb86901_device::execute_run() +void sparc_base_device::execute_run() { - bool debug = machine().debug_flags & DEBUG_FLAG_ENABLED; + const bool debug = debugger_enabled(); if (m_bp_reset_in) { + if (m_error_mode) + { + m_pb_error = 0; + } + m_execute_mode = 0; m_error_mode = 0; m_reset_mode = 1; - m_stashed_icount = m_icount; m_icount = 0; return; } @@ -4127,13 +4556,7 @@ void mb86901_device::execute_run() else run_loop<false, MODE_EXECUTE>(); } - - if (m_stashed_icount >= 0) - { - m_icount = m_stashed_icount; - m_stashed_icount = -1; - } - } while (m_icount >= 0); + } while (m_icount > 0); } @@ -4142,7 +4565,7 @@ void mb86901_device::execute_run() // disassembler //------------------------------------------------- -uint64_t mb86901_device::get_reg_r(unsigned index) const +uint64_t sparc_base_device::get_reg_r(unsigned index) const { return REG(index & 31); } @@ -4153,7 +4576,7 @@ uint64_t mb86901_device::get_reg_r(unsigned index) const // disassembler //------------------------------------------------- -uint64_t mb86901_device::get_translated_pc() const +uint64_t sparc_base_device::get_translated_pc() const { // FIXME: how do we apply translation to the address so it's in the same space the disassembler sees? return m_pc; @@ -4165,7 +4588,7 @@ uint64_t mb86901_device::get_translated_pc() const // disassembler //------------------------------------------------- -uint8_t mb86901_device::get_icc() const +uint8_t sparc_base_device::get_icc() const { return (m_psr & PSR_ICC_MASK) >> PSR_ICC_SHIFT; } @@ -4176,7 +4599,7 @@ uint8_t mb86901_device::get_icc() const // for disassembler //------------------------------------------------- -uint8_t mb86901_device::get_xcc() const +uint8_t sparc_base_device::get_xcc() const { // not present before SPARCv9 return 0; @@ -4188,7 +4611,7 @@ uint8_t mb86901_device::get_xcc() const // for disassembler //------------------------------------------------- -uint8_t mb86901_device::get_fcc(unsigned index) const +uint8_t sparc_base_device::get_fcc(unsigned index) const { // only one fcc instance before SPARCv9 return (m_fsr >> 10) & 3; diff --git a/src/devices/cpu/sparc/sparc.h b/src/devices/cpu/sparc/sparc.h index 488a9f38dfa..f61ddb30e5e 100644 --- a/src/devices/cpu/sparc/sparc.h +++ b/src/devices/cpu/sparc/sparc.h @@ -12,31 +12,28 @@ #include "sparcdasm.h" #include "sparc_intf.h" -#define SPARCV8 (1) #define LOG_FCODES (0) #if LOG_FCODES #include <map> #endif -class mb86901_device : public cpu_device, public sparc_mmu_host_interface, protected sparc_disassembler::config +class sparc_base_device : public cpu_device, public sparc_mmu_host_interface, protected sparc_disassembler::config { public: - mb86901_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + sparc_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); template <typename T> void set_mmu(T &&tag) { m_mmu.set_tag(std::forward<T>(tag)); } // device-level overrides - virtual void device_start() override; - virtual void device_reset() override; - virtual void device_stop() override; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; virtual void device_post_load() override; - virtual void device_resolve_objects() override; + virtual void device_resolve_objects() override ATTR_COLD; // device_execute_interface overrides - virtual uint32_t execute_min_cycles() const override; - virtual uint32_t execute_max_cycles() const override; - virtual uint32_t execute_input_lines() const override; + virtual uint32_t execute_min_cycles() const noexcept override; + virtual uint32_t execute_max_cycles() const noexcept override; virtual void execute_run() override; virtual void execute_set_input(int inputnum, int state) override; @@ -75,11 +72,8 @@ protected: void execute_rett(uint32_t op); void execute_saverestore(uint32_t op); void execute_jmpl(uint32_t op); -#if SPARCV8 - void execute_mul(uint32_t op); - void execute_div(uint32_t op); -#endif inline void execute_group2(uint32_t op); + virtual bool execute_extra_group2(uint32_t op) = 0; inline void execute_ldd(uint32_t op); inline void execute_ld(uint32_t op); @@ -102,10 +96,8 @@ protected: void execute_store(uint32_t op); void execute_ldstub(uint32_t op); -#if SPARCV8 - void execute_swap(uint32_t op); -#endif inline void execute_group3(uint32_t op); + virtual bool execute_extra_group3(uint32_t op) = 0; enum set_cc { @@ -122,12 +114,23 @@ protected: bool evaluate_condition(uint32_t op); inline void execute_bicc(uint32_t op); + bool evaluate_fp_condition(uint32_t op); + inline void execute_fbfcc(uint32_t op); void execute_ticc(uint32_t op); void select_trap(); void execute_trap(); + virtual void update_tt() = 0; + + void check_fdiv_zero_exception(); + bool check_fp_exceptions(); + bool get_fpr32(uint32_t &data, const uint32_t rd); + bool get_fpr64(uint64_t &data, const uint32_t rd); + bool set_fpr32(const uint32_t rd, const uint32_t data); + bool set_fpr64(const uint32_t rd, const uint64_t data); void complete_instruction_execution(uint32_t op); inline void dispatch_instruction(uint32_t op); + virtual bool dispatch_extra_instruction(uint32_t op) = 0; void complete_fp_execution(uint32_t /*op*/); inline void execute_step(); @@ -148,14 +151,16 @@ protected: void log_fcodes(); #endif - required_device<sparc_mmu_interface> m_mmu; + optional_device<sparc_mmu_interface> m_mmu; // address spaces - address_space_config m_default_config; + address_space_config m_debugger_config; + address_space_config m_asi_config[0x10]; + memory_access<32, 2, 0, ENDIANNESS_BIG>::specific m_asi[0x20]; // memory access - uint32_t read_sized_word(const uint8_t asi, const uint32_t address, const uint32_t mem_mask); - void write_sized_word(const uint8_t asi, const uint32_t address, const uint32_t data, const uint32_t mem_mask); + inline uint32_t read_word(const uint8_t asi, const uint32_t address, const uint32_t mem_mask = 0xffffffff); + inline void write_word(const uint8_t asi, const uint32_t address, const uint32_t data, const uint32_t mem_mask = 0xffffffff); // helpers for the disassembler virtual uint64_t get_reg_r(unsigned index) const override; @@ -165,7 +170,7 @@ protected: virtual uint8_t get_fcc(unsigned index) const override; // general-purpose registers - uint32_t m_r[120]; + uint32_t m_r[136]; // FPU registers uint32_t m_fpr[32]; @@ -198,17 +203,14 @@ protected: bool m_illegal_instruction; bool m_mem_address_not_aligned; bool m_fp_disabled; + bool m_cp_disabled; bool m_fp_exception; - bool m_cp_disabled; // SPARCv8 - bool m_cp_exception; // SPARCv8 - bool m_unimplemented_FLUSH; // SPARCv8 - bool m_r_register_access_error; // SPARCv8 - bool m_instruction_access_error; // SPARCv8 + bool m_fp_exception_pending; + uint32_t m_fpr_pending; + uint32_t m_pending_fpr; + bool m_cp_exception; bool m_instruction_access_exception; - bool m_data_access_error; // SPARCv8 - bool m_data_store_error; // SPARCv8 bool m_data_access_exception; - bool m_division_by_zero; // SPARCv8 bool m_trap_instruction; bool m_window_underflow; bool m_window_overflow; @@ -221,16 +223,16 @@ protected: uint8_t m_cp_sequence_err; // fields separated out from PSR (Processor State Register) - uint8_t m_impl; // implementation (always 0 in MB86901) - uint8_t m_ver; // version (always 0 in MB86901) - uint8_t m_icc; // integer condition codes + uint8_t m_impl; // implementation (always 0 in SPARCv7) + uint8_t m_ver; // version (always 0 in SPARCv7) + uint8_t m_icc; // integer condition codes bool m_ec; // enable coprocessor bool m_ef; // enable FPU - uint8_t m_pil; // processor interrupt level + uint8_t m_pil; // processor interrupt level bool m_s; // supervisor mode bool m_ps; // prior S state bool m_et; // enable traps - uint8_t m_cwp; // current window pointer + uint8_t m_cwp; // current window pointer bool m_alu_op3_assigned[64]; bool m_ldst_op3_assigned[64]; @@ -238,6 +240,7 @@ protected: // register windowing helpers uint32_t* m_regs[32]; + int m_nwindows; // other internal states bool m_privileged_asr[32]; @@ -246,7 +249,6 @@ protected: bool m_no_annul; bool m_hold_bus; int m_icount; - int m_stashed_icount; int m_insn_space; int m_data_space; @@ -263,14 +265,171 @@ protected: bool m_log_fcodes; #endif - // processor configuration - static const int NWINDOWS; - std::function<void (sparc_disassembler *)> m_asi_desc_adder; + static const char *const DEFAULT_ASI_NAMES[16]; +}; + +class sparcv7_device : public sparc_base_device +{ +public: + sparcv7_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + +protected: + sparcv7_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + +protected: + virtual bool execute_extra_group2(uint32_t op) override; + virtual bool execute_extra_group3(uint32_t op) override; + virtual bool dispatch_extra_instruction(uint32_t op) override; + virtual void update_tt() override; +}; + +class sparcv8_device : public sparc_base_device +{ +public: + sparcv8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // device_disasm_interface overrides + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + +protected: + sparcv8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + virtual bool execute_extra_group2(uint32_t op) override; + virtual bool execute_extra_group3(uint32_t op) override; + virtual bool dispatch_extra_instruction(uint32_t op) override; + virtual void update_tt() override; + +private: + void execute_mul(uint32_t op); + void execute_div(uint32_t op); + void execute_swap(uint32_t op); + + bool m_unimplemented_FLUSH; + bool m_r_register_access_error; + bool m_instruction_access_error; + bool m_data_access_error; + bool m_data_store_error; + bool m_division_by_zero; +}; + +class mb86930_device : public sparcv8_device +{ +public: + mb86930_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + // device_disasm_interface overrides + virtual std::unique_ptr<util::disasm_interface> create_disassembler() override; + + auto cs0_read_cb() { return m_cs_r[0].bind(); } + auto cs0_write_cb() { return m_cs_w[0].bind(); } + auto cs1_read_cb() { return m_cs_r[1].bind(); } + auto cs1_write_cb() { return m_cs_w[1].bind(); } + auto cs2_read_cb() { return m_cs_r[2].bind(); } + auto cs2_write_cb() { return m_cs_w[2].bind(); } + auto cs3_read_cb() { return m_cs_r[3].bind(); } + auto cs3_write_cb() { return m_cs_w[3].bind(); } + auto cs4_read_cb() { return m_cs_r[4].bind(); } + auto cs4_write_cb() { return m_cs_w[4].bind(); } + auto cs5_read_cb() { return m_cs_r[5].bind(); } + auto cs5_write_cb() { return m_cs_w[5].bind(); } + +protected: + // device-level overrides + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual void device_post_load() override; + + virtual bool execute_extra_group2(uint32_t op) override; + + void execute_divscc(uint32_t op); + void execute_scan(uint32_t op); + + uint32_t biu_ctrl_r(offs_t offset, uint32_t mem_mask); + void biu_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask); + + uint32_t lock_ctrl_r(offs_t offset, uint32_t mem_mask); + void lock_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask); + uint32_t lock_ctrl_save_r(offs_t offset, uint32_t mem_mask); + void lock_ctrl_save_w(offs_t offset, uint32_t data, uint32_t mem_mask); + uint32_t cache_status_r(offs_t offset, uint32_t mem_mask); + void cache_status_w(offs_t offset, uint32_t data, uint32_t mem_mask); + uint32_t restore_lock_ctrl_r(offs_t offset, uint32_t mem_mask); + void restore_lock_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask); + + uint32_t system_support_ctrl_r(offs_t offset, uint32_t mem_mask); + void system_support_ctrl_w(offs_t offset, uint32_t data, uint32_t mem_mask); + + uint32_t same_page_mask_r(offs_t offset, uint32_t mem_mask); + void same_page_mask_w(offs_t offset, uint32_t data, uint32_t mem_mask); + + uint32_t addr_range_spec_r(offs_t offset, uint32_t mem_mask); + void addr_range_spec_w(offs_t offset, uint32_t data, uint32_t mem_mask); + uint32_t addr_mask_r(offs_t offset, uint32_t mem_mask); + void addr_mask_w(offs_t offset, uint32_t data, uint32_t mem_mask); + + uint32_t wait_specifier_r(offs_t offset, uint32_t mem_mask); + void wait_specifier_w(offs_t offset, uint32_t data, uint32_t mem_mask); + + uint32_t timer_r(offs_t offset, uint32_t mem_mask); + void timer_w(offs_t offset, uint32_t data, uint32_t mem_mask); + uint32_t timer_preload_r(offs_t offset, uint32_t mem_mask); + void timer_preload_w(offs_t offset, uint32_t data, uint32_t mem_mask); + + template <uint8_t Asi> uint32_t mmu_r(offs_t offset, uint32_t mem_mask); + template <uint8_t Asi> void mmu_w(offs_t offset, uint32_t data, uint32_t mem_mask); + + uint32_t icache_lock_r(offs_t offset, uint32_t mem_mask); + void icache_lock_w(offs_t offset, uint32_t data, uint32_t mem_mask); + uint32_t dcache_lock_r(offs_t offset, uint32_t mem_mask); + void dcache_lock_w(offs_t offset, uint32_t data, uint32_t mem_mask); + + uint32_t icache_tag_r(offs_t offset, uint32_t mem_mask); + void icache_tag_w(offs_t offset, uint32_t data, uint32_t mem_mask); + uint32_t icache_data_r(offs_t offset, uint32_t mem_mask); + void icache_data_w(offs_t offset, uint32_t data, uint32_t mem_mask); + + u32 dcache_tag_r(offs_t offset, u32 mem_mask); + void dcache_tag_w(offs_t offset, u32 data, u32 mem_mask); + u32 dcache_data_r(offs_t offset, u32 mem_mask); + void dcache_data_w(offs_t offset, u32 data, u32 mem_mask); + + void control_map(address_map &map) ATTR_COLD; + void icache_lock_map(address_map &map) ATTR_COLD; + void dcache_lock_map(address_map &map) ATTR_COLD; + template <uint8_t Asi> void mmu_map(address_map &map) ATTR_COLD; + void icache_tag_map(address_map &map) ATTR_COLD; + void icache_data_map(address_map &map) ATTR_COLD; + void dcache_tag_map(address_map &map) ATTR_COLD; + void dcache_data_map(address_map &map) ATTR_COLD; + + void update_addr_masks(); + void update_wait_states(); + + devcb_read32::array<6> m_cs_r; + devcb_write32::array<6> m_cs_w; + + u32 m_ssctrl; + u32 m_spmr; + u64 m_spmr_mask; + u32 m_arsr[6]; + u32 m_amr[6]; + u64 m_full_masks[6]; + u64 m_full_ranges[6]; + u64 m_last_masked_addr; + int m_same_page_waits[6]; + int m_other_page_waits[6]; + + u32 m_wssr[3]; }; // device type definition -DECLARE_DEVICE_TYPE(MB86901, mb86901_device) +DECLARE_DEVICE_TYPE(SPARCV7, sparcv7_device) +DECLARE_DEVICE_TYPE(SPARCV8, sparcv8_device) +DECLARE_DEVICE_TYPE(MB86930, mb86930_device) enum { @@ -297,6 +456,12 @@ enum SPARC_S, SPARC_PS, + SPARC_FSR, + SPARC_F0, SPARC_F1, SPARC_F2, SPARC_F3, SPARC_F4, SPARC_F5, SPARC_F6, SPARC_F7, + SPARC_F8, SPARC_F9, SPARC_F10, SPARC_F11, SPARC_F12, SPARC_F13, SPARC_F14, SPARC_F15, + SPARC_F16, SPARC_F17, SPARC_F18, SPARC_F19, SPARC_F20, SPARC_F21, SPARC_F22, SPARC_F23, + SPARC_F24, SPARC_F25, SPARC_F26, SPARC_F27, SPARC_F28, SPARC_F29, SPARC_F30, SPARC_F31, + SPARC_R0, SPARC_R1, SPARC_R2, SPARC_R3, SPARC_R4, SPARC_R5, SPARC_R6, SPARC_R7, SPARC_R8, SPARC_R9, SPARC_R10, SPARC_R11, SPARC_R12, SPARC_R13, SPARC_R14, SPARC_R15, SPARC_R16, SPARC_R17, SPARC_R18, SPARC_R19, SPARC_R20, SPARC_R21, SPARC_R22, SPARC_R23, SPARC_R24, SPARC_R25, SPARC_R26, SPARC_R27, SPARC_R28, SPARC_R29, SPARC_R30, SPARC_R31, SPARC_R32, SPARC_R33, SPARC_R34, SPARC_R35, SPARC_R36, SPARC_R37, SPARC_R38, SPARC_R39, SPARC_R40, SPARC_R41, SPARC_R42, SPARC_R43, SPARC_R44, SPARC_R45, SPARC_R46, SPARC_R47, diff --git a/src/devices/cpu/sparc/sparc_intf.h b/src/devices/cpu/sparc/sparc_intf.h index b1fad3ad9a9..f84219be8fd 100644 --- a/src/devices/cpu/sparc/sparc_intf.h +++ b/src/devices/cpu/sparc/sparc_intf.h @@ -23,8 +23,6 @@ class sparc_mmu_interface public: virtual ~sparc_mmu_interface() { } virtual uint32_t fetch_insn(const bool supervisor, const uint32_t offset) = 0; - virtual uint32_t read_asi(uint8_t asi, uint32_t offset, uint32_t mem_mask) = 0; - virtual void write_asi(uint8_t asi, uint32_t offset, uint32_t data, uint32_t mem_mask) = 0; virtual void set_host(sparc_mmu_host_interface *host) = 0; }; diff --git a/src/devices/cpu/sparc/sparcdasm.cpp b/src/devices/cpu/sparc/sparcdasm.cpp index 584b5ab427a..c0a42cb0b79 100644 --- a/src/devices/cpu/sparc/sparcdasm.cpp +++ b/src/devices/cpu/sparc/sparcdasm.cpp @@ -13,9 +13,9 @@ namespace { - int32_t get_disp16(uint32_t op) { return DISP19; } + int32_t get_disp16(uint32_t op) { return DISP16; } int32_t get_disp19(uint32_t op) { return DISP19; } - int32_t get_disp22(uint32_t op) { return DISP19; } + int32_t get_disp22(uint32_t op) { return DISP22; } const char *bicc_comment(const sparc_disassembler::config *conf, bool use_cc, offs_t pc, uint32_t op) { @@ -176,6 +176,13 @@ const sparc_disassembler::int_op_desc_map::value_type sparc_disassembler::V7_INT { 0x3d, { false, "restore" } } }; +const sparc_disassembler::int_op_desc_map::value_type sparc_disassembler::SPARCLITE_INT_OP_DESC[] = { + { 0x0a, { false, "umul" } }, { 0x1a, { false, "umulcc" } }, + { 0x0b, { false, "smul" } }, { 0x1b, { false, "smulcc" } }, + { 0x1d, { false, "divscc" } }, + { 0x2c, { false, "scan" } } +}; + const sparc_disassembler::int_op_desc_map::value_type sparc_disassembler::V8_INT_OP_DESC[] = { { 0x0a, { false, "umul" } }, { 0x1a, { false, "umulcc" } }, { 0x0b, { false, "smul" } }, { 0x1b, { false, "smulcc" } }, @@ -570,7 +577,7 @@ const sparc_disassembler::vis_op_desc_map::value_type sparc_disassembler::VIS3B_ inline uint32_t sparc_disassembler::freg(uint32_t val, bool shift) const { - return (shift && (m_version >= 9)) ? ((val & 0x1e) | ((val << 5) & 0x20)) : val; + return (shift && (m_version >= v9)) ? ((val & 0x1e) | ((val << 5) & 0x20)) : val; } template <typename T> inline void sparc_disassembler::add_int_op_desc(const T &desc) @@ -610,24 +617,24 @@ inline void sparc_disassembler::pad_op_field(std::ostream &stream, std::streampo stream << ' '; } -sparc_disassembler::sparc_disassembler(const config *conf, unsigned version) +sparc_disassembler::sparc_disassembler(const config *conf, sparc_version version) : sparc_disassembler(conf, version, vis_none) { } -sparc_disassembler::sparc_disassembler(const config *conf, unsigned version, vis_level vis) +sparc_disassembler::sparc_disassembler(const config *conf, sparc_version version, vis_level vis) : m_version(version) , m_vis_level(vis) , m_op_field_width(9) , m_branch_desc{ EMPTY_BRANCH_DESC, - (version >= 9) ? BPCC_DESC : EMPTY_BRANCH_DESC, // branch on integer condition codes with prediction, SPARCv9 - BICC_DESC, // branch on integer condition codes - (version >= 9) ? BPR_DESC : EMPTY_BRANCH_DESC, // branch on integer register with prediction, SPARCv9 + (version >= v9) ? BPCC_DESC : EMPTY_BRANCH_DESC, // branch on integer condition codes with prediction, SPARCv9 + BICC_DESC, // branch on integer condition codes + (version >= v9) ? BPR_DESC : EMPTY_BRANCH_DESC, // branch on integer register with prediction, SPARCv9 EMPTY_BRANCH_DESC, - (version >= 9) ? FBPFCC_DESC : EMPTY_BRANCH_DESC, // branch on floating-point condition codes with prediction, SPARCv9 - FBFCC_DESC, // branch on floating-point condition codes - (version == 8) ? CBCCC_DESC : EMPTY_BRANCH_DESC // branch on coprocessor condition codes, SPARCv8 + (version >= v9) ? FBPFCC_DESC : EMPTY_BRANCH_DESC, // branch on floating-point condition codes with prediction, SPARCv9 + FBFCC_DESC, // branch on floating-point condition codes + (version == v8) ? CBCCC_DESC : EMPTY_BRANCH_DESC // branch on coprocessor condition codes, SPARCv8 } , m_int_op_desc(std::begin(V7_INT_OP_DESC), std::end(V7_INT_OP_DESC)) , m_state_reg_desc() @@ -638,12 +645,16 @@ sparc_disassembler::sparc_disassembler(const config *conf, unsigned version, vis , m_prftch_desc() , m_vis_op_desc() { - if (m_version >= 8) + if (m_version == sparclite) + { + add_int_op_desc(SPARCLITE_INT_OP_DESC); + } + else if (m_version >= v8) { add_int_op_desc(V8_INT_OP_DESC); } - if (m_version >= 9) + if (m_version >= v9) { m_op_field_width = 11; @@ -676,13 +687,17 @@ sparc_disassembler::sparc_disassembler(const config *conf, unsigned version, vis { case vis_3b: add_vis_op_desc(VIS3B_OP_DESC); + [[fallthrough]]; case vis_3: add_fpop1_desc(VIS3_FPOP1_DESC); add_vis_op_desc(VIS3_OP_DESC); + [[fallthrough]]; case vis_2p: add_asi_desc(VIS2P_ASI_DESC); + [[fallthrough]]; case vis_2: add_vis_op_desc(VIS2_OP_DESC); + [[fallthrough]]; case vis_1: m_op_field_width = std::max(m_op_field_width, 12); add_vis_op_desc(VIS1_OP_DESC); @@ -717,6 +732,7 @@ sparc_disassembler::sparc_disassembler(const config *conf, unsigned version, vis m_vis_op_desc.find(0x07c)->second.mnemonic = "ford"; m_vis_op_desc.find(0x07e)->second.mnemonic = "foned"; } + [[fallthrough]]; case vis_none: break; } @@ -740,7 +756,7 @@ offs_t sparc_disassembler::dasm(std::ostream &stream, offs_t pc, uint32_t op) co switch (OP2) { case 0: - util::stream_format(stream, "%-*s0x%06x", m_op_field_width, (m_version >= 9) ? "illtrap" : "unimp", CONST22); + util::stream_format(stream, "%-*s0x%06x", m_op_field_width, (m_version >= v9) ? "illtrap" : "unimp", CONST22); break; case 4: if (IMM22 == 0 && RD == 0) @@ -754,7 +770,7 @@ offs_t sparc_disassembler::dasm(std::ostream &stream, offs_t pc, uint32_t op) co return 4 | SUPPORTED; case 1: util::stream_format(stream, "%-*s%%pc%c0x%08x ! 0x%08x", m_op_field_width, "call", (DISP30 < 0) ? '-' : '+', std::abs(DISP30), pc + DISP30); - return 4 | SUPPORTED; + return 4 | STEP_OVER | step_over_extra(1) | SUPPORTED; case 2: switch (OP3) { @@ -857,14 +873,14 @@ offs_t sparc_disassembler::dasm(std::ostream &stream, offs_t pc, uint32_t op) co case 0x28: return dasm_read_state_reg(stream, pc, op); case 0x29: - if (m_version <= 8) + if (m_version < v9) { util::stream_format(stream, "%-*s%%psr,%s", m_op_field_width, "rd", REG_NAMES[RD]); return 4 | SUPPORTED; } break; case 0x2a: - if (m_version >= 9) + if (m_version >= v9) { if (V9_PRIV_REG_NAMES[RS1]) { @@ -879,7 +895,7 @@ offs_t sparc_disassembler::dasm(std::ostream &stream, offs_t pc, uint32_t op) co } break; case 0x2b: - if (m_version >= 9) + if (m_version >= v9) { if (!USEIMM) { @@ -896,7 +912,7 @@ offs_t sparc_disassembler::dasm(std::ostream &stream, offs_t pc, uint32_t op) co case 0x2c: return dasm_move_cond(stream, pc, op); case 0x2e: - if ((m_version >= 9) && (RS1 == 0)) + if ((m_version >= v9) && (RS1 == 0)) { if (USEIMM) util::stream_format(stream, "%-*s%d,%s", m_op_field_width, "popc", SIMM13, REG_NAMES[RD]); else util::stream_format(stream, "%-*s%s,%s", m_op_field_width, "popc", REG_NAMES[RS2], REG_NAMES[RD]); @@ -908,7 +924,7 @@ offs_t sparc_disassembler::dasm(std::ostream &stream, offs_t pc, uint32_t op) co case 0x30: return dasm_write_state_reg(stream, pc, op); case 0x31: - if (m_version >= 9) + if (m_version >= v9) { switch (RD) { @@ -936,7 +952,7 @@ offs_t sparc_disassembler::dasm(std::ostream &stream, offs_t pc, uint32_t op) co } break; case 0x32: - if (m_version >= 9) + if (m_version >= v9) { if (V9_PRIV_REG_NAMES[RD]) { @@ -963,7 +979,7 @@ offs_t sparc_disassembler::dasm(std::ostream &stream, offs_t pc, uint32_t op) co } break; case 0x33: - if (m_version <= 8) + if (m_version < v9) { if (RS1 == 0) { @@ -994,13 +1010,9 @@ offs_t sparc_disassembler::dasm(std::ostream &stream, offs_t pc, uint32_t op) co case 0x3a: return dasm_tcc(stream, pc, op); case 0x3b: - if (m_version >= 8) - { - util::stream_format(stream, "%-*s", m_op_field_width, "flush"); - dasm_address(stream, op); - return 4 | SUPPORTED; - } - break; + util::stream_format(stream, "%-*s", m_op_field_width, m_version >= v8 ? "flush" : "iflush"); + dasm_address(stream, op); + return 4 | SUPPORTED; case 0x3c: if (!USEIMM && (RS1 == RS2) && (RS2 == RD) && (RD == 0)) { @@ -1016,12 +1028,12 @@ offs_t sparc_disassembler::dasm(std::ostream &stream, offs_t pc, uint32_t op) co } break; case 0x3e: - if ((m_version >= 9) & ((op & 0x7ffff) == 0)) + if ((m_version >= v9) & ((op & 0x7ffff) == 0)) { switch (RD) { - case 0: util::stream_format(stream, "done"); return 4 | SUPPORTED; - case 1: util::stream_format(stream, "retry"); return 4 | SUPPORTED; + case 0: util::stream_format(stream, "done"); return 4 | STEP_OUT | SUPPORTED; + case 1: util::stream_format(stream, "retry"); return 4 | STEP_OUT | SUPPORTED; } } break; @@ -1072,7 +1084,7 @@ offs_t sparc_disassembler::dasm_invalid(std::ostream &stream, offs_t pc, uint32_ } else if ((OP == 2) && ((OP3 == 0x36) || (OP3 == 0x37))) { - if (m_version >= 9) + if (m_version >= v9) util::stream_format(stream, "IMPDEP%d impl-dep=%02x impl-dep=%05x", 1 + (OP3 & 1), RD, op & 0x7ffff); else util::stream_format(stream, "CPop%d opf=%03x rd=%d rs1=%d rs2=%d", 1 + (OP3 & 1), OPC, RD, RS1, RS2); @@ -1101,13 +1113,16 @@ offs_t sparc_disassembler::dasm_branch(std::ostream &stream, offs_t pc, uint32_t //const char * const comment(desc.get_comment ? desc.get_comment(m_config, desc.use_cc, pc, op) : nullptr); //if (comment) util::stream_format(stream, " - %s", comment); - return 4 | SUPPORTED; + if ((COND & 7) != 0) + return 4 | STEP_COND | step_over_extra(1) | SUPPORTED; + else + return 4 | SUPPORTED; // branch never or always } offs_t sparc_disassembler::dasm_shift(std::ostream &stream, offs_t pc, uint32_t op, const char *mnemonic, const char *mnemonicx, const char *mnemonicx0) const { - if ((m_version >= 9) && USEEXT) + if ((m_version >= v9) && USEEXT) { if (USEIMM) util::stream_format(stream, "%-*s%s,%d,%s", m_op_field_width, mnemonicx, REG_NAMES[RS1], SHCNT64, REG_NAMES[RD]); @@ -1137,9 +1152,9 @@ offs_t sparc_disassembler::dasm_read_state_reg(std::ostream &stream, offs_t pc, util::stream_format(stream, "%-*s%%y,%s", m_op_field_width, "rd", REG_NAMES[RD]); return 4 | SUPPORTED; } - else if ((m_version == 8) || ((m_version >= 9) && !USEIMM)) + else if ((m_version == v8) || (m_version == sparclite) || ((m_version >= v9) && !USEIMM)) { - if (!USEIMM && (RS1 == 15) && (RD == 0)) + if (!USEIMM && (RS1 == 15) && (RD == 0) && (m_version != sparclite)) { util::stream_format(stream, "stbar"); return 4 | SUPPORTED; @@ -1157,7 +1172,7 @@ offs_t sparc_disassembler::dasm_read_state_reg(std::ostream &stream, offs_t pc, } } } - else if ((m_version >= 9) && USEIMM && (RS1 == 15) && (RD == 0)) + else if ((m_version >= v9) && USEIMM && (RS1 == 15) && (RD == 0)) { util::stream_format(stream, "%-*s", m_op_field_width, "membar"); uint32_t mask(MMASK | (CMASK << 4)); @@ -1197,9 +1212,9 @@ offs_t sparc_disassembler::dasm_write_state_reg(std::ostream &stream, offs_t pc, } return 4 | SUPPORTED; } - else if (m_version >= 8) + else if (m_version >= v8) { - if ((m_version >= 9) && USEIMM && (RS1 == 0) && (RD == 15)) + if ((m_version >= v9) && USEIMM && (RS1 == 0) && (RD == 15)) { util::stream_format(stream, "%-*s%d", m_op_field_width, "sir", SIMM13); return 4 | SUPPORTED; @@ -1246,7 +1261,7 @@ offs_t sparc_disassembler::dasm_write_state_reg(std::ostream &stream, offs_t pc, offs_t sparc_disassembler::dasm_move_cond(std::ostream &stream, offs_t pc, uint32_t op) const { - if ((m_version < 9) || !MOVCC_CC_NAMES[MOVCC]) return dasm_invalid(stream, pc, op); + if ((m_version < v9) || !MOVCC_CC_NAMES[MOVCC]) return dasm_invalid(stream, pc, op); const std::streampos start_position(stream.tellp()); util::stream_format(stream, "mov%s", MOVCC_COND_NAMES[MOVCOND | ((MOVCC << 2) & 16)]); @@ -1261,7 +1276,7 @@ offs_t sparc_disassembler::dasm_move_cond(std::ostream &stream, offs_t pc, uint3 offs_t sparc_disassembler::dasm_move_reg_cond(std::ostream &stream, offs_t pc, uint32_t op) const { - if ((m_version < 9) || !MOVE_INT_COND_MNEMONICS[RCOND]) return dasm_invalid(stream, pc, op); + if ((m_version < v9) || !MOVE_INT_COND_MNEMONICS[RCOND]) return dasm_invalid(stream, pc, op); if (USEIMM) util::stream_format(stream, "%-*s%s,%d,%s", m_op_field_width, MOVE_INT_COND_MNEMONICS[RCOND], REG_NAMES[RS1], SIMM10, REG_NAMES[RD]); @@ -1288,7 +1303,7 @@ offs_t sparc_disassembler::dasm_fpop1(std::ostream &stream, offs_t pc, uint32_t offs_t sparc_disassembler::dasm_fpop2(std::ostream &stream, offs_t pc, uint32_t op) const { // Move Floating-Point Register on Condition - if ((m_version >= 9) && (((op >> 18) & 1) == 0) && MOVCC_CC_NAMES[OPFCC]) + if ((m_version >= v9) && (((op >> 18) & 1) == 0) && MOVCC_CC_NAMES[OPFCC]) { const char *mnemonic; bool shift; @@ -1312,7 +1327,7 @@ offs_t sparc_disassembler::dasm_fpop2(std::ostream &stream, offs_t pc, uint32_t const auto it(m_fpop2_desc.find(OPF)); if (it != m_fpop2_desc.end()) { - if (m_version >= 9) + if (m_version >= v9) { if (it->second.int_rs1) { @@ -1391,6 +1406,7 @@ offs_t sparc_disassembler::dasm_jmpl(std::ostream &stream, offs_t pc, uint32_t o if (USEIMM && (RD == 0) && ((RS1 == 15) || (RS1 == 31)) && (SIMM13 == 8)) { util::stream_format(stream, (RS1 == 31) ? "ret" : "retl"); + return 4 | STEP_OUT | step_over_extra(1) | SUPPORTED; } else { @@ -1398,16 +1414,19 @@ offs_t sparc_disassembler::dasm_jmpl(std::ostream &stream, offs_t pc, uint32_t o dasm_address(stream, op); if ((RD != 0) && (RD != 15)) util::stream_format(stream, ",%s", REG_NAMES[RD]); + if (RD != 0) + return 4 | STEP_OVER | step_over_extra(1) | SUPPORTED; + else + return 4 | SUPPORTED; } - return 4 | SUPPORTED; } offs_t sparc_disassembler::dasm_return(std::ostream &stream, offs_t pc, uint32_t op) const { - util::stream_format(stream, "%-*s", m_op_field_width, (m_version >= 9) ? "return" : "rett"); + util::stream_format(stream, "%-*s", m_op_field_width, (m_version >= v9) ? "return" : "rett"); dasm_address(stream, op); - return 4 | SUPPORTED; + return 4 | STEP_OUT | step_over_extra(1) | SUPPORTED; } @@ -1419,7 +1438,7 @@ offs_t sparc_disassembler::dasm_tcc(std::ostream &stream, offs_t pc, uint32_t op }; static const char *const cc_names[4] = { "%icc", nullptr, "%xcc", nullptr }; const char *const mnemonic(tcc_names[COND]); - if (m_version >= 9) + if (m_version >= v9) { const char *const cc(cc_names[TCCCC]); if (!cc) return dasm_invalid(stream, pc, op); @@ -1440,13 +1459,13 @@ offs_t sparc_disassembler::dasm_tcc(std::ostream &stream, offs_t pc, uint32_t op else if (RS2 == 0) util::stream_format(stream, "%s", REG_NAMES[RS1]); else util::stream_format(stream, "%s,%s", REG_NAMES[RS1], REG_NAMES[RS2]); } - return 4 | SUPPORTED; + return 4 | STEP_OVER | SUPPORTED; } offs_t sparc_disassembler::dasm_ldst(std::ostream &stream, offs_t pc, uint32_t op) const { - if (m_version >= 9) + if (m_version >= v9) { switch (OP3) { @@ -1463,6 +1482,7 @@ offs_t sparc_disassembler::dasm_ldst(std::ostream &stream, offs_t pc, uint32_t o util::stream_format(stream, "%-*s[", m_op_field_width, "ldx"); dasm_address(stream, op); util::stream_format(stream, "],%%efsr"); + return 4 | SUPPORTED; } break; case 0x25: // Store floating-point state register @@ -1529,8 +1549,8 @@ offs_t sparc_disassembler::dasm_ldst(std::ostream &stream, offs_t pc, uint32_t o dasm_address(stream, op); stream << ']'; return 4 | SUPPORTED; - case 0x26: // Store Floating-point deferred-trap Queue - case 0x36: // Store Coprocessor deferred-trap Queue + case 0x26: // Store Double Floating-point deferred-trap Queue + case 0x36: // Store Double Coprocessor deferred-trap Queue util::stream_format(stream, "%-*s%%%cq,[", m_op_field_width, "std", (OP3 == 0x36) ? 'c' : 'f'); dasm_address(stream, op); stream << ']'; @@ -1542,7 +1562,7 @@ offs_t sparc_disassembler::dasm_ldst(std::ostream &stream, offs_t pc, uint32_t o if (it == m_ldst_desc.end()) return dasm_invalid(stream, pc, op); - if (it->second.alternate && USEIMM && (m_version < 9)) + if (it->second.alternate && USEIMM && (m_version < v9)) return dasm_invalid(stream, pc, op); if (it->second.g0_synth && (RD == 0)) diff --git a/src/devices/cpu/sparc/sparcdasm.h b/src/devices/cpu/sparc/sparcdasm.h index f6f0e7bc27d..b92a2c283a3 100644 --- a/src/devices/cpu/sparc/sparcdasm.h +++ b/src/devices/cpu/sparc/sparcdasm.h @@ -4,8 +4,8 @@ SPARC disassembler */ -#ifndef MAME_DEVICES_CPU_SPARC_SPARC_DASM_H -#define MAME_DEVICES_CPU_SPARC_SPARC_DASM_H +#ifndef MAME_CPU_SPARC_SPARCDASM_H +#define MAME_CPU_SPARC_SPARCDASM_H #pragma once @@ -26,6 +26,7 @@ public: virtual uint8_t get_fcc(unsigned index) const = 0; // ?><= }; + enum sparc_version { v7, v8, sparclite, v9 }; enum vis_level { vis_none, vis_1, vis_2, vis_2p, vis_3, vis_3b }; struct asi_desc @@ -55,8 +56,8 @@ public: }; typedef std::map<uint8_t, prftch_desc> prftch_desc_map; - sparc_disassembler(const config *conf, unsigned version); - sparc_disassembler(const config *conf, unsigned version, vis_level vis); + sparc_disassembler(const config *conf, sparc_version version); + sparc_disassembler(const config *conf, sparc_version version, vis_level vis); template <typename T> void add_state_reg_desc(const T &desc) { @@ -215,6 +216,7 @@ private: static const branch_desc CBCCC_DESC; static const int_op_desc_map::value_type V7_INT_OP_DESC[]; static const int_op_desc_map::value_type V8_INT_OP_DESC[]; + static const int_op_desc_map::value_type SPARCLITE_INT_OP_DESC[]; static const int_op_desc_map::value_type V9_INT_OP_DESC[]; static const state_reg_desc_map::value_type V9_STATE_REG_DESC[]; static const char * const MOVCC_CC_NAMES[8]; @@ -239,7 +241,7 @@ private: static const vis_op_desc_map::value_type VIS3B_OP_DESC[]; //const config *m_config; - unsigned m_version; + sparc_version m_version; vis_level m_vis_level; int m_op_field_width; branch_desc m_branch_desc[8]; @@ -253,4 +255,4 @@ private: vis_op_desc_map m_vis_op_desc; }; -#endif // MAME_DEVICES_CPU_SPARC_SPARC_DASM_H +#endif // MAME_CPU_SPARC_SPARCDASM_H diff --git a/src/devices/cpu/sparc/sparcdefs.h b/src/devices/cpu/sparc/sparcdefs.h index f023da44679..19784b173a7 100644 --- a/src/devices/cpu/sparc/sparcdefs.h +++ b/src/devices/cpu/sparc/sparcdefs.h @@ -2,15 +2,15 @@ // copyright-holders:Ryan Holtz //================================================================ // -// mb86901defs.h - Helpful #defines for emulating the MB86901 -// series of SPARC processor. +// sparcdefs.h - Helpful #defines for emulating the MB86901 +// series of SPARC processor. // //================================================================ -#pragma once +#ifndef MAME_CPU_SPARC_SPARCDEFS_H +#define MAME_CPU_SPARC_SPARCDEFS_H -#ifndef __MB86901_DEFS_H__ -#define __MB86901_DEFS_H__ +#pragma once #define PSR_CWP_MASK 0x0000001f #define PSR_ET_SHIFT 5 @@ -85,6 +85,8 @@ #define WIM m_wim #define TBR m_tbr +#define NWINDOWS m_nwindows + #define OP_NS (op & 0xc0000000) #define OP (op >> 30) @@ -95,17 +97,17 @@ #define OPFLOW ((op >> 5) & 0x3f) #define DISP30 (int32_t(op << 2)) -#define DISP22 (int32_t(op << 10) >> 8) -#define DISP19 (int32_t(op << 13) >> 11) -#define DISP16 (int32_t(((op << 10) & 0xc0000000) | ((op << 16) & 0x3fff0000)) >> 14) +#define DISP22 util::sext(op << 2, 24) +#define DISP19 util::sext(op << 2, 21) +#define DISP16 util::sext((op & 0x300000) >> 4 | (op & 0x3fff) << 2, 18) #define IMM22 (op << 10) #define CONST22 (op & 0x3fffff) -#define SIMM13 (int32_t(op << 19) >> 19) -#define SIMM11 (int32_t(op << 21) >> 21) -#define SIMM10 (int32_t(op << 22) >> 22) -#define SIMM8 (int32_t(op << 24) >> 24) +#define SIMM13 util::sext(op, 13) +#define SIMM11 util::sext(op, 11) +#define SIMM10 util::sext(op, 10) +#define SIMM8 util::sext(op, 8) #define IMM7 (op & 0x7f) -#define SIMM7 (int32_t(op << 25) >> 25) +#define SIMM7 util::sext(op, 7) #define SHCNT32 (op & 31) #define SHCNT64 (op & 63) #define IAMODE (op & 0x7) @@ -127,9 +129,12 @@ #define CMASK ((op >> 4) & 7) #define RD ((op >> 25) & 31) +#define RD_D ((op >> 25) & 30) #define RDBITS (op & 0x3e000000) #define RS1 ((op >> 14) & 31) +#define RS1_D ((op >> 14) & 30) #define RS2 (op & 31) +#define RS2_D (op & 30) #define FREG(x) m_fpr[(x)] #define FDREG m_fpr[RD] @@ -139,7 +144,7 @@ #define RDREG *m_regs[RD] #define RS1REG *m_regs[RS1] #define RS2REG *m_regs[RS2] -#define SET_RDREG(x) do { if(RD) { RDREG = (x); } } while (0) +#define SET_RDREG(x) do { if(RDBITS) { RDREG = (x); } } while (0) #define ADDRESS (USEIMM ? (RS1REG + SIMM13) : (RS1REG + RS2REG)) #define PC m_pc @@ -197,6 +202,7 @@ #define OP3_UMULCC 26 #define OP3_SMULCC 27 #define OP3_SUBXCC 28 +#define OP3_DIVSCC 29 #define OP3_UDIVCC 30 #define OP3_SDIVCC 31 #define OP3_TADDCC 32 @@ -211,6 +217,7 @@ #define OP3_RDPSR 41 #define OP3_RDWIM 42 #define OP3_RDTBR 43 +#define OP3_SCAN 44 #define OP3_WRASR 48 #define OP3_WRPSR 49 #define OP3_WRWIM 50 @@ -386,4 +393,96 @@ #define SDIV (OP3 == OP3_SDIV) #define SDIVCC (OP3 == OP3_SDIVCC) -#endif // __MB86901_DEFS_H__ +#define FSR_CEXC_MASK 0x0000001f +#define FSR_CEXC_NXC 0x00000001 +#define FSR_CEXC_DZC 0x00000002 +#define FSR_CEXC_UFC 0x00000004 +#define FSR_CEXC_OFC 0x00000008 +#define FSR_CEXC_NVC 0x00000010 + +#define FSR_AEXC_SHIFT 5 +#define FSR_AEXC_MASK 0x000003e0 +#define FSR_AEXC_NXA 0x00000020 +#define FSR_AEXC_DZA 0x00000040 +#define FSR_AEXC_UFA 0x00000080 +#define FSR_AEXC_OFA 0x00000100 +#define FSR_AEXC_NVA 0x00000200 + +#define FSR_FCC_SHIFT 10 +#define FSR_FCC_MASK 0x00000c00 +#define FSR_FCC_EQ 0x00000000 +#define FSR_FCC_LT 0x00000400 +#define FSR_FCC_GT 0x00000800 +#define FSR_FCC_UO 0x00000c00 + +#define FSR_QNE 0x00002000 + +#define FSR_FTT_MASK 0x0001c000 +#define FSR_FTT_NONE 0x00000000 +#define FSR_FTT_IEEE 0x00004000 +#define FSR_FTT_UNFIN 0x00008000 +#define FSR_FTT_UNIMP 0x0000c000 +#define FSR_FTT_SEQ 0x00010000 + +#define FSR_VER 0x00020000 + +#define FSR_NS 0x00400000 + +#define FSR_TEM_SHIFT 23 +#define FSR_TEM_MASK 0x0f800000 +#define FSR_TEM_NXM 0x00800000 +#define FSR_TEM_DZM 0x01000000 +#define FSR_TEM_UFM 0x02000000 +#define FSR_TEM_OFM 0x04000000 +#define FSR_TEM_NVM 0x08000000 + +#define FSR_RD_SHIFT 30 +#define FSR_RD_MASK 0xc0000000 +#define FSR_RD_NEAR 0x00000000 +#define FSR_RD_ZERO 0x40000000 +#define FSR_RD_UP 0x80000000 +#define FSR_RD_DOWN 0xc0000000 + +#define FSR_RESV_MASK 0x30301000 + +// FPop1 +#define FPOP_FMOVS 0x001 +#define FPOP_FNEGS 0x005 +#define FPOP_FABSS 0x009 +#define FPOP_FSQRTS 0x029 +#define FPOP_FSQRTD 0x02a +#define FPOP_FSQRTX 0x02b +#define FPOP_FADDS 0x041 +#define FPOP_FADDD 0x042 +#define FPOP_FADDX 0x043 +#define FPOP_FSUBS 0x045 +#define FPOP_FSUBD 0x046 +#define FPOP_FSUBX 0x047 +#define FPOP_FMULS 0x049 +#define FPOP_FMULD 0x04a +#define FPOP_FMULX 0x04b +#define FPOP_FDIVS 0x04d +#define FPOP_FDIVD 0x04e +#define FPOP_FDIVX 0x04f +#define FPOP_FITOS 0x0c4 +#define FPOP_FDTOS 0x0c6 +#define FPOP_FXTOS 0x0c7 +#define FPOP_FITOD 0x0c8 +#define FPOP_FSTOD 0x0c9 +#define FPOP_FXTOD 0x0cb +#define FPOP_FITOX 0x0cc +#define FPOP_FSTOX 0x0cd +#define FPOP_FDTOX 0x0ce +#define FPOP_FSTOI 0x0d1 +#define FPOP_FDTOI 0x0d2 +#define FPOP_FXTOI 0x0d3 + +// FPop2 +#define FPOP_FCMPS 0x051 +#define FPOP_FCMPD 0x052 +#define FPOP_FCMPX 0x053 +#define FPOP_FCMPES 0x055 +#define FPOP_FCMPED 0x056 +#define FPOP_FCMPEX 0x057 + +#endif // MAME_CPU_SPARC_SPARCDEFS_H diff --git a/src/devices/cpu/sparc/sparcv8ops.ipp b/src/devices/cpu/sparc/sparcv8ops.ipp deleted file mode 100644 index b2611d694f2..00000000000 --- a/src/devices/cpu/sparc/sparcv8ops.ipp +++ /dev/null @@ -1,293 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Ryan Holtz -//================================================================ -// -// sparcv8ops.ipp - Emulation for SPARCv8-class instructions -// -//================================================================ - - -//------------------------------------------------- -// execute_swap - execute a swap instruction -//------------------------------------------------- - -void mb86901_device::execute_swap(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 169, "Appendix C - ISP Descriptions - Atomic Load-Store Unsigned Byte Instructions" (SPARCv8.pdf, pg. 166) - - if (SWAP) then ( - address <- r[rs1] + (if (i = 0) then r[rs2] else sign_extend(simm13)); - addr_space <- (if (S = 0) then 10 else 11) - ) else if (SWAPA) then ( - if (S = 0) then ( - trap <- 1; - privileged_instruction <- 1 - ) else if (i = 1) then ( - trap <- 1; - illegal_instruction <- 1 - ) else ( - address <- r[rs1] + r[rs1]; - addr_space <- asi - ) - ); - next; - if (trap = 0) then ( - temp <- r[rd]; - while ( (pb_block_ldst_byte = 1) or (pb_block_ldst_word = 1) ) ( - { wait for lock(s) to be lifted } - { an implementation actually need only block when another SWAP is pending on - the same word in memory as the one addressed by this SWAP, or a LDSTUB is - pending on any byte of the word in memory addressed by this SWAP } - ); - next; - pb_block_ldst_word <- 1; - next; - (word, MAE) <- memory_read(addr_space, address); - next; - if (MAE = 1) then ( - trap <- 1; - data_access_exception = 1 - ) - next; - if (trap = 0) then ( - MAE <- memory_write(addr_space, address, 1111, temp); - next; - pb_block_ldst_word <- 0; - if (MAE = 1) then ( { MAE = 1 only due to a "non-resumable machine-check error" } - trap <- 1; - data_access_exception <- 1 - ) else ( - if (rd != 0) then r[rd] <- word - ) - ); - */ - - uint32_t address = 0; - uint8_t addr_space = 0; - if (SWAP) - { - address = RS1REG + (USEIMM ? SIMM13 : RS2REG); - addr_space = (IS_USER ? 10 : 11); - } - else if (SWAPA) - { - if (IS_USER) - { - m_trap = 1; - m_privileged_instruction = 1; - } - else if (USEIMM) - { - m_trap = 1; - m_illegal_instruction = 1; - } - else - { - address = RS1REG + RS2REG; - addr_space = ASI; - } - } - - uint32_t word = 0; - uint32_t temp = 0; - if (!m_trap) - { - temp = RDREG; - while (m_pb_block_ldst_byte || m_pb_block_ldst_word) - { - // { wait for lock(s) to be lifted } - // { an implementation actually need only block when another SWAP is pending on - // the same word in memory as the one addressed by this SWAP, or a LDSTUB is - // pending on any byte of the word in memory addressed by this SWAP } - } - - m_pb_block_ldst_word = 1; - - word = read_sized_word(addr_space, address, 4); - - if (MAE) - { - m_trap = 1; - m_data_access_exception = 1; - } - } - if (!m_trap) - { - write_sized_word(addr_space, address, temp, 4); - - m_pb_block_ldst_word = 0; - if (MAE) - { - m_trap = 1; - m_data_access_exception = 1; - } - else - { - if (RD != 0) - RDREG = word; - } - } -} - - -//------------------------------------------------- -// execute_mul - execute a multiply opcode -//------------------------------------------------- - -void mb86901_device::execute_mul(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 175, "Appendix C - ISP Descriptions - Multiply Instructions" (SPARCv8.pdf, pg. 172) - - operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); - - if (UMUL or UMULScc) then (Y, result) <- multiply_unsigned(r[rs1], operand2) - else if (SMUL or SMULcc) then (Y, result) <- multiply_signed(r[rs1], operand2) - next; - if (rd != 0) then ( - r[rd] <- result; - ) - if (UMULcc or SMULcc) then ( - N <- result<31>; - Z <- if (result = 0) then 1 else 0; - V <- 0 - C <- 0 - ); - */ - - uint32_t operand2 = (USEIMM ? SIMM13 : RS2REG); - - uint32_t result = 0; - if (UMUL || UMULCC) - { - uint64_t dresult = (uint64_t)RS1REG * (uint64_t)operand2; - Y = (uint32_t)(dresult >> 32); - result = (uint32_t)dresult; - } - else if (SMUL || SMULCC) - { - int64_t dresult = (int64_t)(int32_t)RS1REG * (int64_t)(int32_t)operand2; - Y = (uint32_t)(dresult >> 32); - result = (uint32_t)dresult; - } - - if (RD != 0) - { - RDREG = result; - } - if (UMULCC || SMULCC) - { - CLEAR_ICC; - PSR |= BIT31(result) ? PSR_N_MASK : 0; - PSR |= (result == 0) ? PSR_Z_MASK : 0; - } -} - - -//------------------------------------------------- -// execute_div - execute a divide opcode -//------------------------------------------------- - -void mb86901_device::execute_div(uint32_t op) -{ - /* The SPARC Instruction Manual: Version 8, page 176, "Appendix C - ISP Descriptions - Multiply Instructions" (SPARCv8.pdf, pg. 173) - - operand2 := if (i = 0) then r[rs2] else sign_extend(simm13); - - next; - if (operand2 = 0) then ( - trap <- 1; - division_by_zero <- 1 - ) else ( - if (UDIV or UDIVcc) then ( - temp_64bit <- divide_unsigned(Y[]r[rs1], operand2); - next; - result <- temp_64bit<31:0>; - temp_V <- if (temp_64bit<63:32> = 0) then 0 else 1; - ) else if (SDIV or SDIVcc) then ( - temp_64bit <- divide_signed(Y[]r[rs1], operand2); - next; - result <- temp_64bit<31:0>; - temp_V <- if (temp_64bit<63:31> = 0) or - (temp_64bit<63:31> = (2^33 - 1)) ) then 0 else 1; - ) ; - next; - - if (temp_V) then ( - { result overflowed 32 bits; return largest appropriate integer } - if (UDIV or UDIVcc) then result <- 2^32 - 1; - else if (SDIV or SDIVcc) then ( - if (temp_64bit > 0) then result <- 2^31 - 1; - else result <- -2^31 - ) - ); - next; - - if (rd != 0) then ( - r[rd] <- result - ) ; - if (UDIVcc or SDIVcc) then ( - N <- result<31>; - Z <- if (result = 0) then 1 else 0; - V <- temp_V; - C <- 0 - ) - ); - */ - - uint32_t operand2 = (USEIMM ? SIMM13 : RS2REG); - - if (operand2 == 0) - { - m_trap = 1; - m_division_by_zero = 1; - } - else - { - uint32_t result = 0; - bool temp_v = false; - int64_t temp_64bit = 0; - if (UDIV || UDIVCC) - { - temp_64bit = int64_t(uint64_t((uint64_t(Y) << 32) | uint64_t(RS1REG)) / operand2); - - result = uint32_t(temp_64bit); - - temp_v = ((temp_64bit & 0xffffffff00000000) == 0) ? false : true; - } - else if (SDIV || SDIVCC) - { - temp_64bit = int64_t(int64_t((uint64_t(Y) << 32) | uint64_t(RS1REG)) / operand2); - - result = uint32_t(temp_64bit); - - uint64_t shifted = uint64_t(temp_64bit) >> 31; - temp_v = (shifted == 0 || shifted == 0x1ffffffff) ? false : true; - } - - if (temp_v) - { - if (UDIV || UDIVCC) - { - result = 0xffffffff; - } - else if (SDIV || SDIVCC) - { - if (temp_64bit > 0) - result = 0x7fffffff; - else - result = 0x80000000; - } - } - - if (RD != 0) - RDREG = result; - - if (UDIVCC || SDIVCC) - { - CLEAR_ICC; - PSR |= BIT31(result) ? PSR_N_MASK : 0; - PSR |= (result == 0) ? PSR_Z_MASK : 0; - PSR |= temp_v ? PSR_V_MASK : 0; - } - } -} diff --git a/src/devices/cpu/sparc/ss1fcode.ipp b/src/devices/cpu/sparc/ss1fcode.ipp index d9457742340..35b2cd7cd72 100644 --- a/src/devices/cpu/sparc/ss1fcode.ipp +++ b/src/devices/cpu/sparc/ss1fcode.ipp @@ -7,7 +7,7 @@ // //================================================================ -void mb86901_device::log_fcodes() +void sparc_base_device::log_fcodes() { if (PC != 0xffef0000 && PC != m_ss1_next_entry_point) return; @@ -23,7 +23,7 @@ void mb86901_device::log_fcodes() if (false)//opcode == 0x6304) { m_log_fcodes = true; - //machine().debugger().debug_break(); + //machine().debug_break(); } else if (!m_log_fcodes) { @@ -57,7 +57,7 @@ void mb86901_device::log_fcodes() } } -void mb86901_device::indent() +void sparc_base_device::indent() { uint32_t program_depth = (0xffeff000 - (REG(6) - 4)) / 4; @@ -71,7 +71,7 @@ void mb86901_device::indent() } } -void mb86901_device::disassemble_ss1_fcode(uint32_t r5, uint32_t opcode, uint32_t handler_base, uint32_t entry_point, uint32_t stack) +void sparc_base_device::disassemble_ss1_fcode(uint32_t r5, uint32_t opcode, uint32_t handler_base, uint32_t entry_point, uint32_t stack) { std::string opdesc = m_ss1_fcode_table[opcode]; if (opdesc.length() == 0) |