diff options
author | 2019-11-18 17:30:38 +0100 | |
---|---|---|
committer | 2019-11-18 17:31:09 +0100 | |
commit | b54cb1804b4eff6f1e4be82a43e346c30d6755ab (patch) | |
tree | ba6ef819ed48a53cc0f194fafb5896f2ebb8b77b | |
parent | 0a0d0fd9b03b791767b1400f713d63aa1647fcba (diff) |
-sun4c_mmu.cpp: Made generic to support sun4 MMU mode, and cleaned up save state usage. [Ryan Holtz]
-sun4.cpp: Various changes: [Ryan Holtz]
* Split sun4 and sun4c hardware emulation into separate derived classes.
* Hooked up Sbus IRQs.
* Removed now-unnecessary duplicate MMU code.
-cgsix.cpp: Added VSync IRQ, cleaned up save state usage, and added THC MISC register. [Ryan Holtz]
-sparc.cpp: Renamed MB86901 to SPARCV7, and added a separate class for SPARCV8. [Ryan Holtz]
-bt45x.cpp: Made logmacro.h usage more consistent. [Ryan Holtz]
-rw-r--r-- | scripts/src/cpu.lua | 11 | ||||
-rw-r--r-- | scripts/target/mame/mess.lua | 2 | ||||
-rw-r--r-- | src/devices/bus/sbus/cgsix.cpp | 107 | ||||
-rw-r--r-- | src/devices/bus/sbus/cgsix.h | 35 | ||||
-rw-r--r-- | src/devices/bus/sbus/sbus.h | 2 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparc.cpp | 5046 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparc.h | 86 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparcdefs.h | 101 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparcv7v8.cpp (renamed from src/devices/cpu/sparc/mb86901.cpp) | 799 | ||||
-rw-r--r-- | src/devices/cpu/sparc/sparcv8ops.ipp | 293 | ||||
-rw-r--r-- | src/devices/cpu/sparc/ss1fcode.ipp | 6 | ||||
-rw-r--r-- | src/devices/machine/sun4c_mmu.cpp | 231 | ||||
-rw-r--r-- | src/devices/machine/sun4c_mmu.h | 70 | ||||
-rw-r--r-- | src/devices/video/bt45x.cpp | 44 | ||||
-rw-r--r-- | src/mame/drivers/sun4.cpp | 1004 |
15 files changed, 6411 insertions, 1426 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index adace721b56..f6f5c41a113 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -2772,21 +2772,20 @@ if (CPUS["ALTO2"]~=null or _OPTIONS["with-tools"]) then end ------------------------------------------ --- Sun SPARC, Fujitus MB86901 implementation ---@src/devices/cpu/sparc/sparc.h,CPUS["MB86901"] = true +-- Sun SPARCv7, SPARCv8 implementation +--@src/devices/cpu/sparc/sparc.h,CPUS["SPARC"] = true -------------------------------------------------- -if (CPUS["MB86901"]~=null) then +if (CPUS["SPARC"]~=null) then files { - MAME_DIR .. "src/devices/cpu/sparc/mb86901.cpp", - MAME_DIR .. "src/devices/cpu/sparc/sparcv8ops.ipp", + MAME_DIR .. "src/devices/cpu/sparc/sparc.cpp", MAME_DIR .. "src/devices/cpu/sparc/sparcdefs.h", MAME_DIR .. "src/devices/cpu/sparc/sparc_intf.h", MAME_DIR .. "src/devices/cpu/sparc/sparc.h", } end -if (CPUS["MB86901"]~=null or _OPTIONS["with-tools"]) then +if (CPUS["SPARC"]~=null or _OPTIONS["with-tools"]) then table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/sparc/sparcdasm.cpp") table.insert(disasm_files , MAME_DIR .. "src/devices/cpu/sparc/sparcdasm.h") end diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 55ea3fd1e2b..fb3f1aede1e 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -132,7 +132,7 @@ CPUS["E0C6200"] = true CPUS["MELPS4"] = true CPUS["HPHYBRID"] = true CPUS["SM510"] = true -CPUS["MB86901"] = true +CPUS["SPARC"] = true CPUS["NANOPROCESSOR"] = true CPUS["CLIPPER"] = true CPUS["CAPRICORN"] = true diff --git a/src/devices/bus/sbus/cgsix.cpp b/src/devices/bus/sbus/cgsix.cpp index 1b71bed21ae..1cdd99da2b0 100644 --- a/src/devices/bus/sbus/cgsix.cpp +++ b/src/devices/bus/sbus/cgsix.cpp @@ -21,6 +21,8 @@ void sbus_cgsix_device::base_map(address_map &map) map(0x00000000, 0x01ffffff).rw(FUNC(sbus_cgsix_device::unknown_r), FUNC(sbus_cgsix_device::unknown_w)); map(0x00000000, 0x00007fff).r(FUNC(sbus_cgsix_device::rom_r)); map(0x00200000, 0x0020000f).m(m_ramdac, FUNC(bt458_device::map)).umask32(0xff000000); + map(0x00300000, 0x00300fff).rw(FUNC(sbus_cgsix_device::fbc_r), FUNC(sbus_cgsix_device::fbc_w)); + map(0x00301818, 0x0030181b).rw(FUNC(sbus_cgsix_device::thc_misc_r), FUNC(sbus_cgsix_device::thc_misc_w)); map(0x003018fc, 0x003018ff).rw(FUNC(sbus_cgsix_device::cursor_address_r), FUNC(sbus_cgsix_device::cursor_address_w)); map(0x00301900, 0x003019ff).rw(FUNC(sbus_cgsix_device::cursor_ram_r), FUNC(sbus_cgsix_device::cursor_ram_w)); map(0x00700000, 0x00700fff).rw(FUNC(sbus_cgsix_device::fbc_r), FUNC(sbus_cgsix_device::fbc_w)); @@ -44,6 +46,8 @@ void sbus_cgsix_device::device_start() m_cursor_ram = std::make_unique<uint32_t[]>(32 * 2); save_pointer(NAME(m_cursor_ram), 32 * 2); + save_item(NAME(m_fbc.m_config)); + save_item(NAME(m_fbc.m_misc)); save_item(NAME(m_fbc.m_clip_check)); save_item(NAME(m_fbc.m_status)); save_item(NAME(m_fbc.m_draw_status)); @@ -149,29 +153,20 @@ void sbus_cgsix_device::device_start() save_item(NAME(m_fbc.m_vertex_count)); - for (int i = 0; i < 0x1000; i++) - { - save_item(NAME(m_fbc.m_prim_buf[i].m_absx), i); - save_item(NAME(m_fbc.m_prim_buf[i].m_absy), i); - save_item(NAME(m_fbc.m_prim_buf[i].m_absz), i); - save_item(NAME(m_fbc.m_prim_buf[i].m_relx), i); - save_item(NAME(m_fbc.m_prim_buf[i].m_rely), i); - save_item(NAME(m_fbc.m_prim_buf[i].m_relz), i); - save_item(NAME(m_fbc.m_prim_buf[i].m_r), i); - save_item(NAME(m_fbc.m_prim_buf[i].m_g), i); - save_item(NAME(m_fbc.m_prim_buf[i].m_b), i); - save_item(NAME(m_fbc.m_prim_buf[i].m_a), i); - } + m_fbc.m_prim_buf = std::make_unique<vertex[]>(0x1000); // Unknown size on hardware + save_pointer(NAME(reinterpret_cast<uint8_t*>(m_fbc.m_prim_buf.get())), sizeof(vertex) * 0x1000); save_item(NAME(m_fbc.m_curr_prim_type)); + save_item(NAME(m_thc_misc)); save_item(NAME(m_cursor_x)); save_item(NAME(m_cursor_y)); } void sbus_cgsix_device::device_reset() { - memset(&m_fbc, 0, sizeof(m_fbc)); + m_fbc.m_vertex_count = 0; + m_thc_misc = 0; } uint32_t sbus_cgsix_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect) @@ -255,7 +250,8 @@ uint8_t sbus_cgsix_device::perform_rasterop(uint8_t src, uint8_t dst, uint8_t ma const uint8_t s = src & mask; const uint8_t d = dst & mask; const uint32_t rop = rops[f | b]; - //logerror("f:%d b:%d s:%02x d:%02x rop:%d\n", f >> 1, b, s, d, rop); + //if (fbc_misc_data() == FBC_MISC_DATA_COLOR8) + //logerror("f:%d b:%d s:%02x d:%02x rop:%d\n", f >> 1, b, s, d, rop); uint8_t value = 0; switch (rop) @@ -280,17 +276,21 @@ uint8_t sbus_cgsix_device::perform_rasterop(uint8_t src, uint8_t dst, uint8_t ma } result |= value & mask; } + //if (fbc_misc_data() == FBC_MISC_DATA_COLOR8) + //logerror("result: %02x\n", result); return result; } void sbus_cgsix_device::handle_font_poke() { - if (fbc_misc_draw() != FBC_MISC_DRAW_RENDER) + if (fbc_misc_draw() > FBC_MISC_DRAW_RENDER) { logerror("handle_font_poke: Unsupported font draw mode %d, abandoning draw\n", fbc_misc_draw()); return; } + const bool color8 = (fbc_misc_data() == FBC_MISC_DATA_COLOR8); + uint32_t pixel_mask = fbc_get_pixel_mask(); uint8_t plane_mask = fbc_get_plane_mask(); @@ -300,13 +300,20 @@ void sbus_cgsix_device::handle_font_poke() const int width = (int)m_fbc.m_x1 - (int)m_fbc.m_x0; const uint32_t font = m_fbc.m_font; uint32_t x = m_fbc.m_x0; - logerror("Width: %d, bits %d to %d\n", width, 31, 31 - width); - for (int bit = 31; bit >= (31 - width) && x < 1152; bit--, x++) + //logerror("Width: %d, bits %d to %d\n", width, 31, 31 - width); + int step_size = color8 ? 8 : 1; + int start_bit = 32 - step_size; + + for (int bit = start_bit; bit >= (start_bit - width * step_size) && x < 1152; bit -= step_size, x++) { if (!BIT(pixel_mask, 31 - (x % 32))) continue; - const uint8_t src = BIT(font, bit) ? 0xff : 0x00; + uint8_t src = 0; + if (color8) + src = (font >> bit) & 0xff; + else + src = BIT(font, bit) ? 0xff : 0x00; const uint8_t dst = vram[BYTE4_XOR_BE(x)]; vram[BYTE4_XOR_BE(x)]= perform_rasterop(src, dst, plane_mask); } @@ -351,7 +358,7 @@ uint8_t sbus_cgsix_device::fbc_get_plane_mask() // NOTE: This is basically untested, and probably full of bugs! void sbus_cgsix_device::handle_draw_command() { - if (fbc_misc_draw() != FBC_MISC_DRAW_RENDER) + if (fbc_misc_draw() > FBC_MISC_DRAW_RENDER) { logerror("handle_draw_command: Unsupported draw mode %d, abandoning draw\n", fbc_misc_draw()); return; @@ -377,8 +384,8 @@ void sbus_cgsix_device::handle_draw_command() uint32_t vindex = 0; while (vindex < m_fbc.m_vertex_count) { - vertex_t &v0 = m_fbc.m_prim_buf[vindex++]; - vertex_t &v1 = m_fbc.m_prim_buf[vindex++]; + vertex &v0 = m_fbc.m_prim_buf[vindex++]; + vertex &v1 = m_fbc.m_prim_buf[vindex++]; for (uint32_t y = v0.m_absy; y <= v1.m_absy; y++) { @@ -454,6 +461,12 @@ READ32_MEMBER(sbus_cgsix_device::fbc_r) uint32_t ret = 0; switch (offset) { + case FBC_CONFIG: + { + const uint32_t data = (m_fbc.m_config & FBC_CONFIG_MASK) | FBC_CONFIG_FBID | FBC_CONFIG_VERSION; + logerror("%s: fbc_r: CONFIG (%08x & %08x)\n", machine().describe_context(), data, mem_mask); + return data; + } case FBC_MISC: logerror("fbc_r: MISC (%08x & %08x)\n", m_fbc.m_misc, mem_mask); return m_fbc.m_misc; @@ -780,6 +793,10 @@ WRITE32_MEMBER(sbus_cgsix_device::fbc_w) switch (offset) { + case FBC_CONFIG: + COMBINE_DATA(&m_fbc.m_config); + logerror("fbc_w: CONFIG = %08x & %08x)\n", data, mem_mask); + break; case FBC_MISC: COMBINE_DATA(&m_fbc.m_misc); logerror("fbc_w: MISC = %08x & %08x\n", data, mem_mask); @@ -1237,6 +1254,50 @@ WRITE32_MEMBER(sbus_cgsix_device::cursor_ram_w) COMBINE_DATA(&m_cursor_ram[offset]); } +READ32_MEMBER(sbus_cgsix_device::thc_misc_r) +{ + logerror("thc_misc_r: %08x & %08x\n", m_thc_misc | THC_MISC_REV, mem_mask); + return m_thc_misc | THC_MISC_REV; +} + +WRITE32_MEMBER(sbus_cgsix_device::thc_misc_w) +{ + logerror("thc_misc_w: %08x & %08x\n", data, mem_mask); + if (BIT(data, THC_MISC_IRQ_BIT) && BIT(m_thc_misc, THC_MISC_IRQ_BIT)) + { + data &= ~(1 << THC_MISC_IRQ_BIT); + lower_irq(4); + } + if (BIT(data, THC_MISC_IRQEN_BIT)) + { + data &= ~(1 << THC_MISC_IRQ_BIT); + } + + COMBINE_DATA(&m_thc_misc); + m_thc_misc &= THC_MISC_WRITE_MASK; +} + +WRITE_LINE_MEMBER(sbus_cgsix_device::vblank_w) +{ + int old_state = BIT(m_thc_misc, THC_MISC_VSYNC_BIT); + if (old_state != state) + { + if (state) + { + m_thc_misc |= 1 << THC_MISC_VSYNC_BIT; + if (BIT(m_thc_misc, THC_MISC_IRQEN_BIT)) + { + m_thc_misc |= 1 << THC_MISC_IRQ_BIT; + raise_irq(4); + } + } + else + { + m_thc_misc &= ~(1 << THC_MISC_VSYNC_BIT); + } + } +} + //------------------------------------------------- // TurboGX implementation //------------------------------------------------- @@ -1262,6 +1323,7 @@ void sbus_turbogx_device::device_add_mconfig(machine_config &config) SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_screen_update(FUNC(sbus_turbogx_device::screen_update)); m_screen->set_raw(105.561_MHz_XTAL, 1472, 0, 1152, 943, 0, 900); + m_screen->screen_vblank().set(FUNC(sbus_turbogx_device::vblank_w)); BT458(config, m_ramdac, 0); } @@ -1303,6 +1365,7 @@ void sbus_turbogxp_device::device_add_mconfig(machine_config &config) m_screen->set_size(1152, 900); m_screen->set_visarea(0, 1152-1, 0, 900-1); m_screen->set_refresh_hz(72); + m_screen->screen_vblank().set(FUNC(sbus_turbogxp_device::vblank_w)); BT467(config, m_ramdac, 0); } diff --git a/src/devices/bus/sbus/cgsix.h b/src/devices/bus/sbus/cgsix.h index abd1a33ec58..47423f1e724 100644 --- a/src/devices/bus/sbus/cgsix.h +++ b/src/devices/bus/sbus/cgsix.h @@ -44,10 +44,13 @@ protected: DECLARE_WRITE32_MEMBER(vram_w); DECLARE_READ32_MEMBER(fbc_r); DECLARE_WRITE32_MEMBER(fbc_w); + DECLARE_READ32_MEMBER(thc_misc_r); + DECLARE_WRITE32_MEMBER(thc_misc_w); DECLARE_READ32_MEMBER(cursor_address_r); DECLARE_WRITE32_MEMBER(cursor_address_w); DECLARE_READ32_MEMBER(cursor_ram_r); DECLARE_WRITE32_MEMBER(cursor_ram_w); + DECLARE_WRITE_LINE_MEMBER(vblank_w); uint32_t screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); uint8_t perform_rasterop(uint8_t src, uint8_t dst, uint8_t mask = 0xff); @@ -79,6 +82,27 @@ protected: enum { + THC_MISC_IRQ_BIT = 4, + THC_MISC_IRQEN_BIT = 5, + THC_MISC_CURRES_BIT = 6, + THC_MISC_SYNCEN_BIT = 7, + THC_MISC_VSYNC_BIT = 8, + THC_MISC_SYNC_BIT = 9, + THC_MISC_ENVID_BIT = 10, + THC_MISC_RESET_BIT = 12, + THC_MISC_REV = 0x00010000, + THC_MISC_WRITE_MASK = 0x000014ff + }; + + enum + { + FBC_CONFIG_FBID = 0x60000000, + FBC_CONFIG_VERSION = 0x00100000, + FBC_CONFIG_MASK = 0x000f3fff + }; + + enum + { FBC_MISC_INDEX_SHIFT = 4, FBC_MISC_INDEX_MOD_SHIFT = 6, FBC_MISC_BDISP_SHIFT = 7, @@ -233,6 +257,7 @@ protected: enum { + FBC_CONFIG = 0x000/4, FBC_MISC = 0x004/4, FBC_CLIP_CHECK = 0x008/4, @@ -339,7 +364,7 @@ protected: FBC_IRECT_A = 0x93c/4, }; - struct vertex_t + struct vertex { uint32_t m_absx; uint32_t m_absy; @@ -364,8 +389,9 @@ protected: PRIM_COUNT }; - struct fbc_t + struct fbc { + uint32_t m_config; uint32_t m_misc; uint32_t m_clip_check; uint32_t m_status; @@ -471,11 +497,12 @@ protected: uint32_t m_irect_b; uint32_t m_irect_a; - vertex_t m_prim_buf[0x1000]; // unknown size + std::unique_ptr<vertex[]> m_prim_buf; uint32_t m_vertex_count; uint32_t m_curr_prim_type; }; + uint32_t m_thc_misc; int16_t m_cursor_x; int16_t m_cursor_y; @@ -485,7 +512,7 @@ protected: required_device<screen_device> m_screen; required_device<bt458_device> m_ramdac; - fbc_t m_fbc; + fbc m_fbc; uint32_t m_vram_size; }; diff --git a/src/devices/bus/sbus/sbus.h b/src/devices/bus/sbus/sbus.h index fdd33ff1d6b..7dfe0da8866 100644 --- a/src/devices/bus/sbus/sbus.h +++ b/src/devices/bus/sbus/sbus.h @@ -103,7 +103,7 @@ protected: virtual void device_start() override; // internal state - required_device<mb86901_device> m_maincpu; + required_device<sparc_base_device> m_maincpu; required_device<address_map_bank_device> m_type1space; address_space *m_space; diff --git a/src/devices/cpu/sparc/sparc.cpp b/src/devices/cpu/sparc/sparc.cpp new file mode 100644 index 00000000000..cd6454ec651 --- /dev/null +++ b/src/devices/cpu/sparc/sparc.cpp @@ -0,0 +1,5046 @@ +// license:BSD-3-Clause +// copyright-holders:Ryan Holtz +//================================================================ +// +// sparc.cpp - Emulation for the SPARCv7/v8 line of +// processors. +// +// Notes: +// - The CPU core implementation has been simplified +// somewhat compared to the spec. In particular, bus +// holding on read/write accesses is disabled, as there +// is currently no use made of it, and it is unlikely to +// ever be. +// +// To-Do: +// - Test: SPARCv8 ops are untested +// - Extended-precision FPU support +// - Coprocessor support +// +//================================================================ + +#include "emu.h" +#include "sparc.h" +#include "sparcdefs.h" + +#include "debugger.h" + +#include "softfloat3/source/include/softfloat.h" + +DEFINE_DEVICE_TYPE(SPARCV7, sparcv7_device, "sparcv7", "Sun SPARC v7") +DEFINE_DEVICE_TYPE(SPARCV8, sparcv8_device, "sparcv8", "Sun SPARC v8") + +const int sparc_base_device::NWINDOWS = 7; + +#if LOG_FCODES +#include "ss1fcode.ipp" +#endif + + +//------------------------------------------------- +// sparc_base_device - constructor +//------------------------------------------------- + +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); +} + + +//------------------------------------------------- +// sparcv7_device - constructor +//------------------------------------------------- + +sparcv7_device::sparcv7_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : sparc_base_device(mconfig, SPARCV7, tag, owner, clock) +{ +} + + +//------------------------------------------------- +// sparcv8_device - constructor +//------------------------------------------------- + +sparcv8_device::sparcv8_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : sparc_base_device(mconfig, SPARCV8, tag, owner, clock) +{ +} + + +void sparc_base_device::device_start() +{ +#if LOG_FCODES + m_ss1_fcode_table.clear(); + FILE* input = fopen("names.txt", "rb"); + + if (input != NULL) + { + fseek(input, 0, SEEK_END); + size_t filesize = ftell(input); + fseek(input, 0, SEEK_SET); + + uint8_t *buf = new uint8_t[filesize]; + fread(buf, 1, filesize, input); + fclose(input); + + size_t pos = 0; + while (pos < filesize) + { + // eat newlines + while (pos < filesize && (buf[pos] == 0x0d || buf[pos] == 0x0a)) + pos++; + + if (pos >= filesize) + break; + + // get opcode + uint16_t opcode = 0; + for (int shift = 12; shift >= 0 && pos < filesize; shift -= 4) + { + uint8_t digit = buf[pos]; + if (digit >= 'a' && digit <= 'z') + { + digit &= ~0x20; + } + + if (digit >= '0' && digit <= '9') + { + opcode |= (digit - 0x30) << shift; + } + else if (digit >= 'A' && digit <= 'F') + { + opcode |= ((digit - 0x41) + 10) << shift; + } + pos++; + } + + if (pos >= filesize) + break; + + // skip " : " + pos += 3; + + if (pos >= filesize) + break; + + // read description up to the first space + std::string description; + while (buf[pos] != ' ' && pos < filesize) + { + description += char(buf[pos]); + pos++; + } + + if (pos >= filesize) + break; + + // skip everything else up to the trailing semicolon + while (buf[pos] != ';' && pos < filesize) + pos++; + + if (pos >= filesize) + break; + + if (buf[pos] == ';') + pos++; + + m_ss1_fcode_table[opcode] = description; + } + delete [] buf; + } + m_log_fcodes = false; +#endif + + m_bp_reset_in = false; + m_bp_fpu_present = true; + m_bp_cp_present = false; + m_pb_error = false; + m_pb_block_ldst_byte = false; + m_pb_block_ldst_word = false; + m_bp_irl = 0; + m_irq_state = 0; + + memset(m_dbgregs, 0, 24 * sizeof(uint32_t)); + + memset(m_illegal_instruction_asr, 0, 32 * sizeof(bool)); + memset(m_privileged_asr, 1, 32 * sizeof(bool)); + m_privileged_asr[0] = false; + + memset(m_alu_setcc, 0, 64 * sizeof(bool)); + m_alu_setcc[OP3_ADDCC] = true; + m_alu_setcc[OP3_ANDCC] = true; + m_alu_setcc[OP3_ORCC] = true; + m_alu_setcc[OP3_XORCC] = true; + m_alu_setcc[OP3_SUBCC] = true; + m_alu_setcc[OP3_ANDNCC] = true; + m_alu_setcc[OP3_ORNCC] = true; + m_alu_setcc[OP3_XNORCC] = true; + m_alu_setcc[OP3_ADDXCC] = true; + m_alu_setcc[OP3_SUBXCC] = true; + m_alu_setcc[OP3_TADDCC] = true; + m_alu_setcc[OP3_TSUBCC] = true; + m_alu_setcc[OP3_TADDCCTV] = true; + m_alu_setcc[OP3_TSUBCCTV] = true; + m_alu_setcc[OP3_MULSCC] = true; + + memset(m_alu_op3_assigned, 0, 64 * sizeof(bool)); + m_alu_op3_assigned[OP3_ADD] = true; + m_alu_op3_assigned[OP3_AND] = true; + m_alu_op3_assigned[OP3_OR] = true; + m_alu_op3_assigned[OP3_XOR] = true; + m_alu_op3_assigned[OP3_SUB] = true; + m_alu_op3_assigned[OP3_ANDN] = true; + m_alu_op3_assigned[OP3_ORN] = true; + m_alu_op3_assigned[OP3_XNOR] = true; + m_alu_op3_assigned[OP3_ADDX] = true; + m_alu_op3_assigned[OP3_SUBX] = true; + m_alu_op3_assigned[OP3_ADDCC] = true; + m_alu_op3_assigned[OP3_ANDCC] = true; + m_alu_op3_assigned[OP3_ORCC] = true; + m_alu_op3_assigned[OP3_XORCC] = true; + m_alu_op3_assigned[OP3_SUBCC] = true; + m_alu_op3_assigned[OP3_ANDNCC] = true; + m_alu_op3_assigned[OP3_ORNCC] = true; + m_alu_op3_assigned[OP3_XNORCC] = true; + m_alu_op3_assigned[OP3_ADDXCC] = true; + m_alu_op3_assigned[OP3_SUBXCC] = true; + m_alu_op3_assigned[OP3_TADDCC] = true; + m_alu_op3_assigned[OP3_TSUBCC] = true; + m_alu_op3_assigned[OP3_TADDCCTV] = true; + m_alu_op3_assigned[OP3_TSUBCCTV] = true; + m_alu_op3_assigned[OP3_MULSCC] = true; + m_alu_op3_assigned[OP3_SLL] = true; + m_alu_op3_assigned[OP3_SRL] = true; + m_alu_op3_assigned[OP3_SRA] = true; + m_alu_op3_assigned[OP3_RDASR] = true; + m_alu_op3_assigned[OP3_RDPSR] = true; + m_alu_op3_assigned[OP3_RDWIM] = true; + m_alu_op3_assigned[OP3_RDTBR] = true; + m_alu_op3_assigned[OP3_WRASR] = true; + m_alu_op3_assigned[OP3_WRPSR] = true; + m_alu_op3_assigned[OP3_WRWIM] = true; + m_alu_op3_assigned[OP3_WRTBR] = true; + m_alu_op3_assigned[OP3_FPOP1] = true; + m_alu_op3_assigned[OP3_FPOP2] = true; + m_alu_op3_assigned[OP3_CPOP1] = true; + m_alu_op3_assigned[OP3_CPOP2] = true; + m_alu_op3_assigned[OP3_JMPL] = true; + m_alu_op3_assigned[OP3_RETT] = true; + m_alu_op3_assigned[OP3_TICC] = true; + m_alu_op3_assigned[OP3_IFLUSH] = true; + m_alu_op3_assigned[OP3_SAVE] = true; + m_alu_op3_assigned[OP3_RESTORE] = true; + + memset(m_ldst_op3_assigned, 0, 64 * sizeof(bool)); + m_ldst_op3_assigned[OP3_LD] = true; + m_ldst_op3_assigned[OP3_LDUB] = true; + m_ldst_op3_assigned[OP3_LDUH] = true; + m_ldst_op3_assigned[OP3_LDD] = true; + m_ldst_op3_assigned[OP3_ST] = true; + m_ldst_op3_assigned[OP3_STB] = true; + m_ldst_op3_assigned[OP3_STH] = true; + m_ldst_op3_assigned[OP3_STD] = true; + m_ldst_op3_assigned[OP3_LDSB] = true; + m_ldst_op3_assigned[OP3_LDSH] = true; + m_ldst_op3_assigned[OP3_LDSTUB] = true; + m_ldst_op3_assigned[OP3_LDA] = true; + m_ldst_op3_assigned[OP3_LDUBA] = true; + m_ldst_op3_assigned[OP3_LDUHA] = true; + m_ldst_op3_assigned[OP3_LDDA] = true; + m_ldst_op3_assigned[OP3_STA] = true; + m_ldst_op3_assigned[OP3_STBA] = true; + m_ldst_op3_assigned[OP3_STHA] = true; + m_ldst_op3_assigned[OP3_STDA] = true; + m_ldst_op3_assigned[OP3_LDSBA] = true; + m_ldst_op3_assigned[OP3_LDSHA] = true; + m_ldst_op3_assigned[OP3_LDSTUBA] = true; + m_ldst_op3_assigned[OP3_LDFPR] = true; + m_ldst_op3_assigned[OP3_LDFSR] = true; + m_ldst_op3_assigned[OP3_LDDFPR] = true; + m_ldst_op3_assigned[OP3_STFPR] = true; + m_ldst_op3_assigned[OP3_STFSR] = true; + m_ldst_op3_assigned[OP3_STDFQ] = true; + m_ldst_op3_assigned[OP3_STDFPR] = true; + + // register our state for the debugger + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "CURPC", m_pc).noshow(); + state_add(STATE_GENFLAGS, "GENFLAGS", m_psr).callimport().callexport().formatstr("%6s").noshow(); + state_add(SPARC_PC, "PC", m_pc).formatstr("%08X"); + state_add(SPARC_NPC, "nPC", m_npc).formatstr("%08X"); + state_add(SPARC_PSR, "PSR", m_psr).formatstr("%08X"); + state_add(SPARC_WIM, "WIM", m_wim).formatstr("%08X"); + state_add(SPARC_TBR, "TBR", m_tbr).formatstr("%08X"); + state_add(SPARC_Y, "Y", m_y).formatstr("%08X"); + state_add(SPARC_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"); + + for (int i = 0; i < 8; i++) + 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++) + state_add(SPARC_O0 + i, util::string_format("o%d", i).c_str(), m_dbgregs[i]).formatstr("%08X"); + + for (int i = 0; i < 8; 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++) + 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"); + state_add(SPARC_ET, "ET", m_et).formatstr("%1u"); + 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"); + + 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 < 120; 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)); + save_item(NAME(m_fsr)); + save_item(NAME(m_ftt)); + save_item(NAME(m_pc)); + save_item(NAME(m_npc)); + save_item(NAME(m_psr)); + save_item(NAME(m_wim)); + save_item(NAME(m_tbr)); + save_item(NAME(m_y)); + save_item(NAME(m_bp_reset_in)); + save_item(NAME(m_bp_irl)); + save_item(NAME(m_bp_fpu_present)); + save_item(NAME(m_bp_cp_present)); + save_item(NAME(m_pb_error)); + save_item(NAME(m_pb_block_ldst_byte)); + save_item(NAME(m_pb_block_ldst_word)); + save_item(NAME(m_irq_state)); + save_item(NAME(m_trap)); + save_item(NAME(m_tt)); + save_item(NAME(m_ticc_trap_type)); + save_item(NAME(m_interrupt_level)); + save_item(NAME(m_privileged_instruction)); + save_item(NAME(m_illegal_instruction)); + save_item(NAME(m_mem_address_not_aligned)); + save_item(NAME(m_fp_disabled)); + save_item(NAME(m_cp_disabled)); + save_item(NAME(m_fp_exception)); + save_item(NAME(m_cp_exception)); + save_item(NAME(m_instruction_access_exception)); + save_item(NAME(m_data_access_exception)); + save_item(NAME(m_trap_instruction)); + save_item(NAME(m_window_underflow)); + save_item(NAME(m_window_overflow)); + save_item(NAME(m_tag_overflow)); + save_item(NAME(m_reset_mode)); + save_item(NAME(m_reset_trap)); + save_item(NAME(m_execute_mode)); + save_item(NAME(m_error_mode)); + save_item(NAME(m_fpu_sequence_err)); + save_item(NAME(m_cp_sequence_err)); + save_item(NAME(m_impl)); + save_item(NAME(m_ver)); + save_item(NAME(m_icc)); + save_item(NAME(m_ec)); + save_item(NAME(m_ef)); + save_item(NAME(m_pil)); + save_item(NAME(m_s)); + save_item(NAME(m_ps)); + save_item(NAME(m_et)); + save_item(NAME(m_cwp)); + save_item(NAME(m_alu_op3_assigned)); + save_item(NAME(m_ldst_op3_assigned)); + save_item(NAME(m_alu_setcc)); + 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)); + +#if LOG_FCODES + save_item(NAME(m_ss1_next_pc)); + save_item(NAME(m_ss1_next_opcode)); + save_item(NAME(m_ss1_next_handler_base)); + save_item(NAME(m_ss1_next_entry_point)); + save_item(NAME(m_ss1_next_stack)); + save_item(NAME(m_log_fcodes)); +#endif + + // set our instruction counter + set_icountptr(m_icount); +} + + +void sparc_base_device::device_resolve_objects() +{ + m_mmu->set_host(this); +} + +void sparc_base_device::device_reset() +{ + m_trap = 0; + 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_fp_exception = 0; + m_fpu_sequence_err = 0; + m_cp_disabled = 0; + m_cp_exception = 0; + m_cp_sequence_err = 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_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); + + WIM = 0; + TBR = 0; + Y = 0; + + PSR = PSR_S_MASK | PSR_PS_MASK; + m_s = true; + m_data_space = 11; + + for (int i = 0; i < 8; i++) + { + m_regs[i] = m_r + i; + } + update_gpr_pointers(); + +#if LOG_FCODES + m_ss1_next_pc = ~0; + m_ss1_next_opcode = ~0; + m_ss1_next_handler_base = ~0; + m_ss1_next_entry_point = ~0; + m_ss1_next_stack = ~0; +#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 +//------------------------------------------------- + +void sparc_base_device::device_post_load() +{ + update_gpr_pointers(); +} + + +//------------------------------------------------- +// memory_space_config - return the configuration +// of the specified address space, or nullptr if +// the space doesn't exist +//------------------------------------------------- + +device_memory_interface::space_config_vector sparc_base_device::memory_space_config() const +{ + space_config_vector config_vector; + config_vector.push_back(std::make_pair(AS_PROGRAM, &m_default_config)); + return config_vector; +} + + +//------------------------------------------------- +// 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. +//------------------------------------------------- + +uint32_t sparc_base_device::read_sized_word(const uint8_t asi, const uint32_t address, const uint32_t mem_mask) +{ + 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); +} + + +//------------------------------------------------- +// 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 +//------------------------------------------------- + +void sparc_base_device::write_sized_word(const uint8_t asi, const uint32_t address, const uint32_t data, const uint32_t mem_mask) +{ + 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); +} + + +//------------------------------------------------- +// state_string_export - export state as a string +// for the debugger +//------------------------------------------------- + +void sparc_base_device::state_string_export(const device_state_entry &entry, std::string &str) const +{ + switch (entry.index()) + { + case STATE_GENFLAGS: + case SPARC_ANNUL: + str = string_format("%01u", m_no_annul ? 0 : 1); + break; + case SPARC_CWP: + str = string_format("%2u", PSR & PSR_CWP_MASK); + break; + case SPARC_EC: + str = string_format("%01u", PSR & PSR_EC_MASK ? 1 : 0); + break; + case SPARC_EF: + str = string_format("%01u", PSR & PSR_EF_MASK ? 1 : 0); + break; + case SPARC_ET: + str = string_format("%01u", PSR & PSR_ET_MASK ? 1 : 0); + break; + case SPARC_PS: + str = string_format("%01u", PSR & PSR_PS_MASK ? 1 : 0); + break; + case SPARC_S: + str = string_format("%01u", PSR & PSR_S_MASK ? 1 : 0); + break; + case SPARC_PIL: + str = string_format("%02u", (PSR & PSR_PIL_MASK) >> PSR_PIL_SHIFT); + break; + case SPARC_ICC: + str = string_format("%c%c%c%c", ICC_N_SET ? 'n' : ' ', ICC_Z_SET ? 'z' : ' ', ICC_V_SET ? 'v' : ' ', ICC_C_SET ? 'c' : ' '); + break; + case SPARC_O0: case SPARC_O1: case SPARC_O2: case SPARC_O3: case SPARC_O4: case SPARC_O5: case SPARC_O6: case SPARC_O7: + str = string_format("%08X", m_dbgregs[entry.index() - SPARC_O0]); + break; + case SPARC_L0: case SPARC_L1: case SPARC_L2: case SPARC_L3: case SPARC_L4: case SPARC_L5: case SPARC_L6: case SPARC_L7: + str = string_format("%08X", m_dbgregs[8 + (entry.index() - SPARC_L0)]); + break; + case SPARC_I0: case SPARC_I1: case SPARC_I2: case SPARC_I3: case SPARC_I4: case SPARC_I5: case SPARC_I6: case SPARC_I7: + str = string_format("%08X", m_dbgregs[16 + (entry.index() - SPARC_I0)]); + break; + } +} + + +//------------------------------------------------- +// disassemble - call the disassembly +// helper function +//------------------------------------------------- + +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), 7); + m_asi_desc_adder(dasm.get()); + return std::move(dasm); +} + + +//************************************************************************** +// CORE EXECUTION LOOP +//************************************************************************** + +//------------------------------------------------- +// execute_min_cycles - return minimum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +uint32_t sparc_base_device::execute_min_cycles() const noexcept +{ + return 1; +} + + +//------------------------------------------------- +// execute_max_cycles - return maximum number of +// cycles it takes for one instruction to execute +//------------------------------------------------- + +uint32_t sparc_base_device::execute_max_cycles() const noexcept +{ + return 4; +} + + +//------------------------------------------------- +// execute_input_lines - return the number of +// input/interrupt lines +//------------------------------------------------- + +uint32_t sparc_base_device::execute_input_lines() const noexcept +{ + return 16; +} + + +//------------------------------------------------- +// execute_set_input - set the state of an input +// line during execution +//------------------------------------------------- + +void sparc_base_device::execute_set_input(int inputnum, int state) +{ + switch (inputnum) + { + case SPARC_IRQ1: + case SPARC_IRQ2: + case SPARC_IRQ3: + case SPARC_IRQ4: + case SPARC_IRQ5: + case SPARC_IRQ6: + case SPARC_IRQ7: + case SPARC_IRQ8: + case SPARC_IRQ9: + case SPARC_IRQ10: + case SPARC_IRQ11: + case SPARC_IRQ12: + case SPARC_IRQ13: + case SPARC_IRQ14: + case SPARC_NMI: + { + int index = (inputnum - SPARC_IRQ1) + 1; + if (state) + { + m_irq_state |= 1 << index; + } + else + { + m_irq_state &= ~(1 << index); + } + + for(index = 15; index > 0; index--) + { + if (m_irq_state & (1 << index)) + { + break; + } + } + + m_bp_irl = index; + break; + } + + case SPARC_MAE: + m_mae = (state != 0) ? 1 : 0; + break; + + case SPARC_RESET: + m_bp_reset_in = (state != 0) ? 1 : 0; + break; + } +} + + +//------------------------------------------------- +// execute_add - execute an add-type opcode +//------------------------------------------------- + +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; + + 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; + + uint32_t result = 0; + if (ADD || ADDCC) + result = rs1 + operand2; + else if (ADDX || ADDXCC) + result = rs1 + operand2 + ICC_C; + + if (RDBITS) + RDREG = result; + + if (ADDCC || ADDXCC) + { + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= ((BIT31(rs1) && BIT31(operand2) && !BIT31(result)) || + (!BIT31(rs1) && !BIT31(operand2) && BIT31(result))) ? PSR_V_MASK : 0; + PSR |= ((BIT31(rs1) && BIT31(operand2)) || + (!BIT31(result) && (BIT31(rs1) || BIT31(operand2)))) ? PSR_C_MASK : 0; + } + + PC = nPC; + nPC = nPC + 4; +} + + +//------------------------------------------------- +// execute_taddcc - execute a tagged add-type +// opcode +//------------------------------------------------- + +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) + + 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; + ); + */ + uint32_t rs1 = RS1REG; + uint32_t operand2 = USEIMM ? SIMM13 : RS2REG; + + uint32_t result = rs1 + operand2; + + bool temp_v = (BIT31(rs1) && BIT31(operand2) && !BIT31(result)) || + (!BIT31(rs1) && !BIT31(operand2) && BIT31(result)) || + ((rs1 & 3) != 0 || (operand2 & 3) != 0) ? true : false; + + if (TADDCCTV && temp_v) + { + m_trap = 1; + m_tag_overflow = true; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= temp_v ? PSR_V_MASK : 0; + PSR |= ((BIT31(rs1) && BIT31(operand2)) || + (!BIT31(result) && (BIT31(rs1) || BIT31(operand2)))) ? PSR_C_MASK : 0; + + if (RDBITS) + RDREG = result; + + PC = nPC; + nPC = nPC + 4; +} + + +//------------------------------------------------- +// execute_sub - execute a subtraction-type +// opcode +//------------------------------------------------- + +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; + + 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; + + uint32_t result = 0; + if (SUB || SUBCC) + result = rs1 - operand2; + else if (SUBX || SUBXCC) + result = rs1 - operand2 - ICC_C; + + if (RDBITS) + RDREG = result; + + if (SUBCC || SUBXCC) + { + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= ((BIT31(rs1) && !BIT31(operand2) && !BIT31(result)) || + (!BIT31(rs1) && BIT31(operand2) && BIT31(result))) ? PSR_V_MASK : 0; + PSR |= ((!BIT31(rs1) && BIT31(operand2)) || + (BIT31(result) && (!BIT31(rs1) || BIT31(operand2)))) ? PSR_C_MASK : 0; + } + + PC = nPC; + nPC = nPC + 4; +} + + +//-------------------------------------------------- +// execute_tsubcc - execute a tagged subtract-type +// opcode +//-------------------------------------------------- + +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; + ); + */ + + uint32_t rs1 = RS1REG; + uint32_t operand2 = USEIMM ? SIMM13 : RS2REG; + + uint32_t result = rs1 - operand2; + + bool temp_v = (BIT31(rs1) && !BIT31(operand2) && !BIT31(result)) || + (!BIT31(rs1) && BIT31(operand2) && BIT31(result)) || + ((rs1 & 3) != 0 || (operand2 & 3) != 0) ? true : false; + + if (TSUBCCTV && temp_v) + { + m_trap = 1; + m_tag_overflow = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= temp_v ? PSR_V_MASK : 0; + PSR |= ((!BIT31(rs1) && BIT31(operand2)) || + (BIT31(result) && (!BIT31(rs1) || BIT31(operand2)))) ? PSR_C_MASK : 0; + + if (RDBITS) + RDREG = result; + + PC = nPC; + nPC = nPC + 4; +} + + +/* 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; + +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 <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; + if (SETCC) + { + CLEAR_ICC; + if (result & 0x80000000) + PSR |= PSR_N_MASK; + else if (!result) + PSR |= PSR_Z_MASK; + } + + PC = nPC; + nPC = nPC + 4; +} + +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; + if (SETCC) + { + CLEAR_ICC; + if (result & 0x80000000) + PSR |= PSR_N_MASK; + else if (!result) + PSR |= PSR_Z_MASK; + } + + PC = nPC; + nPC = nPC + 4; +} + +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; + if (SETCC) + { + CLEAR_ICC; + if (result & 0x80000000) + PSR |= PSR_N_MASK; + else if (!result) + PSR |= PSR_Z_MASK; + } + + PC = nPC; + nPC = nPC + 4; +} + +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; + if (SETCC) + { + CLEAR_ICC; + if (result & 0x80000000) + PSR |= PSR_N_MASK; + else if (!result) + PSR |= PSR_Z_MASK; + } + + PC = nPC; + nPC = nPC + 4; +} + +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; + if (SETCC) + { + CLEAR_ICC; + if (result & 0x80000000) + PSR |= PSR_N_MASK; + else if (!result) + PSR |= PSR_Z_MASK; + } + + PC = nPC; + nPC = nPC + 4; +} + +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; + if (SETCC) + { + CLEAR_ICC; + if (result & 0x80000000) + PSR |= PSR_N_MASK; + else if (!result) + PSR |= PSR_Z_MASK; + } + + PC = nPC; + nPC = nPC + 4; +} + +//------------------------------------------------- +// execute_shift - execute a shift-type opcode, +// sll/srl/sra +//------------------------------------------------- + +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; + + 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) + { + if (SLL) + RDREG = RS1REG << shift_count; + else if (SRL) + RDREG = uint32_t(RS1REG) >> shift_count; + else if (SRA) + RDREG = int32_t(RS1REG) >> shift_count; + } + + PC = nPC; + nPC = nPC + 4; +} + + +//-------------------------------------------------- +// execute_mulscc - execute a multiply step opcode +//-------------------------------------------------- + +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) + ); + + 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; + + uint32_t result = operand1 + operand2; + Y = ((RS1REG & 1) ? 0x80000000 : 0) | (Y >> 1); + + if (RDBITS) + RDREG = result; + + CLEAR_ICC; + PSR |= (BIT31(result)) ? PSR_N_MASK : 0; + PSR |= (result == 0) ? PSR_Z_MASK : 0; + PSR |= ((BIT31(operand1) && BIT31(operand2) && !BIT31(result)) || + (!BIT31(operand1) && !BIT31(operand2) && BIT31(result))) ? PSR_V_MASK : 0; + PSR |= ((BIT31(operand1) && BIT31(operand2)) || + (!BIT31(result) && (BIT31(operand1) || BIT31(operand2)))) ? PSR_C_MASK : 0; + + PC = nPC; + nPC = nPC + 4; +} + + +//------------------------------------------------- +// execute_rdsr - execute a status register read +// opcode +//------------------------------------------------- + +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) + + 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 (((WRPSR || WRWIM || WRTBR) || (WRASR && 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; + } + + if (RDBITS) + { + if (RDASR) + { + if (RS1 == 0) + { + RDREG = Y; + } + } + else if (RDPSR) + { + RDREG = PSR; + } + else if (RDWIM) + RDREG = WIM; + else if (RDTBR) + RDREG = TBR; + } + + PC = nPC; + nPC = nPC + 4; +} + + +//------------------------------------------------- +// execute_wrsr - execute a status register write +// opcode +//------------------------------------------------- + +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) + + 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 + ) + ); + */ + uint32_t operand2 = USEIMM ? SIMM13 : RS2REG; + + uint32_t result = RS1REG ^ operand2; + + if (WRASR && RD == 0) + { + Y = result; + PC = nPC; + nPC = nPC + 4; + } + else if (WRASR) + { + if (m_privileged_asr[RD] && IS_USER) + { + 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 + { + // SPARCv8 + PC = nPC; + nPC = nPC + 4; + } + } + else if (WRPSR) + { + if (IS_USER) + { + 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; + update_gpr_pointers(); + + m_et = PSR & PSR_ET_MASK; + m_pil = (PSR & PSR_PIL_MASK) >> PSR_PIL_SHIFT; + m_s = PSR & PSR_S_MASK; + if (m_s) + { + m_data_space = 11; + } + else + { + m_data_space = 10; + } + + PC = nPC; + nPC = nPC + 4; + } + else if (WRWIM) + { + if (IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + WIM = result & 0x7f; + PC = nPC; + nPC = nPC + 4; + } + else if (WRTBR) + { + if (IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + TBR = result & 0xfffff000; + PC = nPC; + nPC = nPC + 4; + } +} + + +//------------------------------------------------- +// execute_rett - execute a return-from-trap +// opcode +//------------------------------------------------- + +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) + + 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 + ) + */ + + uint8_t new_cwp = ((PSR & PSR_CWP_MASK) + 1) % NWINDOWS; + uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + if (m_et) + { + m_trap = 1; + if (IS_USER) + { + m_privileged_instruction = 1; + } + else + { + m_illegal_instruction = 1; + } + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + else if (IS_USER) + { + m_trap = 1; + m_privileged_instruction = 1; + 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) + { + m_trap = 1; + m_window_underflow = 1; + m_tt = 6; + m_execute_mode = 0; + m_error_mode = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + else if (address & 3) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + m_tt = 7; + m_execute_mode = 0; + m_error_mode = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + PSR |= PSR_ET_MASK; + m_et = true; + PC = nPC; + nPC = address; + + PSR &= ~PSR_CWP_MASK; + PSR |= new_cwp; + + if (PSR & PSR_PS_MASK) + { + PSR |= PSR_S_MASK; + m_s = true; + m_data_space = 11; + } + else + { + PSR &= ~PSR_S_MASK; + m_s = false; + m_data_space = 10; + } + + update_gpr_pointers(); +} + + + +//------------------------------------------------- +// execute_saverestore - execute a save or restore +// opcode +//------------------------------------------------- + +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) + + 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 } + */ + + uint32_t rs1 = RS1REG; + uint32_t operand2 = USEIMM ? SIMM13 : RS2REG; + + uint32_t result = 0; + if (SAVE) + { + uint8_t new_cwp = (((PSR & PSR_CWP_MASK) + NWINDOWS) - 1) % NWINDOWS; + if ((WIM & (1 << new_cwp)) != 0) + { + m_trap = 1; + m_window_overflow = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + result = rs1 + operand2; + PSR &= ~PSR_CWP_MASK; + PSR |= new_cwp; + } + else if (RESTORE) + { + uint8_t new_cwp = ((PSR & PSR_CWP_MASK) + 1) % NWINDOWS; + if ((WIM & (1 << new_cwp)) != 0) + { + m_trap = 1; + m_window_underflow = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + result = rs1 + operand2; + PSR &= ~PSR_CWP_MASK; + PSR |= new_cwp; + } + + update_gpr_pointers(); + + if (RDBITS) + RDREG = result; + + PC = nPC; + nPC = nPC + 4; +} + + +//------------------------------------------------- +// execute_jmpl - execute a jump and link opcode +//------------------------------------------------- + +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 + ) + */ + + uint32_t jump_address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (jump_address & 3) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + m_stashed_icount = m_icount; + m_icount = 0; + } + else + { + if (RDBITS) + RDREG = PC; + PC = nPC; + nPC = jump_address; + } +} + + +//------------------------------------------------- +// execute_group2 - execute an opcode in group 2, +// mostly ALU ops +//------------------------------------------------- + +inline void sparc_base_device::execute_group2(uint32_t op) +{ + switch (OP3) + { + case OP3_ADD: + case OP3_ADDX: + case OP3_ADDCC: + case OP3_ADDXCC: + execute_add(op); + break; + + case OP3_SUB: + case OP3_SUBX: + case OP3_SUBCC: + case OP3_SUBXCC: + execute_sub(op); + break; + + case OP3_TADDCC: + case OP3_TADDCCTV: + execute_taddcc(op); + break; + + case OP3_TSUBCC: + case OP3_TSUBCCTV: + execute_tsubcc(op); + break; + + case OP3_AND: + execute_and<NOCC>(op); + break; + case OP3_OR: + execute_or<NOCC>(op); + break; + case OP3_XOR: + execute_xor<NOCC>(op); + break; + case OP3_ANDN: + execute_andn<NOCC>(op); + break; + case OP3_ORN: + execute_orn<NOCC>(op); + break; + case OP3_XNOR: + execute_xnor<NOCC>(op); + break; + case OP3_ANDCC: + execute_and<USECC>(op); + break; + case OP3_ORCC: + execute_or<USECC>(op); + break; + case OP3_XORCC: + execute_xor<USECC>(op); + break; + case OP3_ANDNCC: + execute_andn<USECC>(op); + break; + case OP3_ORNCC: + execute_orn<USECC>(op); + break; + case OP3_XNORCC: + execute_xnor<USECC>(op); + break; + + case OP3_MULSCC: + execute_mulscc(op); + break; + + case OP3_SLL: + case OP3_SRL: + case OP3_SRA: + execute_shift(op); + break; + + case OP3_RDASR: + case OP3_RDPSR: + case OP3_RDWIM: + case OP3_RDTBR: + execute_rdsr(op); + break; + + case OP3_WRASR: + case OP3_WRPSR: + case OP3_WRWIM: + case OP3_WRTBR: + execute_wrsr(op); + break; + + case OP3_FPOP1: + case OP3_FPOP2: + if (!(PSR & PSR_EF_MASK) || !m_bp_fpu_present) + { + m_trap = 1; + m_fp_disabled = 1; + m_stashed_icount = m_icount; + m_icount = 0; + } + complete_fp_execution(op); + return; + + case OP3_JMPL: + execute_jmpl(op); + break; + + case OP3_RETT: + execute_rett(op); + break; + + case OP3_TICC: + execute_ticc(op); + break; + + case OP3_IFLUSH: + // Ignored + PC = nPC; + nPC = nPC + 4; + break; + + case OP3_SAVE: + case OP3_RESTORE: + execute_saverestore(op); + break; + + default: + if (!execute_extra_group2(op)) + { + 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; + } +} + + +//------------------------------------------------- +// update_extra_group2 - execute a group2 +// instruction belonging to a newer SPARC version +// than v7 +//------------------------------------------------- + +bool sparcv7_device::execute_extra_group2(uint32_t op) +{ + 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); + return true; + + case OP3_UDIV: + case OP3_SDIV: + case OP3_UDIVCC: + case OP3_SDIVCC: + execute_div(op); + return true; + + case OP3_CPOP1: + case OP3_CPOP2: + logerror("cpop @ %08x: %08x\n", PC, op); + m_trap = 1; + m_cp_disabled = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return true; + + default: + return false; + } +} + +//------------------------------------------------- +// update_gpr_pointers - cache pointers to +// the registers in our current window +//------------------------------------------------- + +void sparc_base_device::update_gpr_pointers() +{ + int cwp = PSR & PSR_CWP_MASK; + for (int i = 0; i < 8; i++) + { + m_regs[ 8 + i] = &m_r[8 + (( 0 + cwp * 16 + i) % (NWINDOWS * 16))]; + m_regs[16 + i] = &m_r[8 + (( 8 + cwp * 16 + i) % (NWINDOWS * 16))]; + m_regs[24 + i] = &m_r[8 + ((16 + cwp * 16 + i) % (NWINDOWS * 16))]; + } +} + + +//------------------------------------------------- +// execute_store - execute a store-type opcode +//------------------------------------------------- + +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 ( (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 + ) + ); + */ + + 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)) + { + m_trap = 1; + m_illegal_instruction = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + uint32_t address = 0; + uint8_t addr_space = 0; + if (STD || ST || STH || STB || STF || STDF || STFSR || STDFQ || STCSR || STC || STDC || STDCQ) + { + address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + addr_space = m_data_space; + } + else if (STDA || STA || STHA || STBA) + { + address = RS1REG + RS2REG; + addr_space = ASI; + } + if ((STF || STDF || STFSR || STDFQ) && (!(PSR & PSR_EF_MASK) || !m_bp_fpu_present)) + { + 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; + } + else if ((ST || STA || STF || STFSR || STC || STCSR) && ((address & 3) != 0)) + { + 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; + 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) + { + // 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; + //uint8_t byte_mask; + if (STF) + { + //byte_mask = 15; + data0 = FREG(RD); + } + else if (STC) + { + //byte_mask = 15; + data0 = 0; + } + else if (STDF) + { + //byte_mask = 15; + data0 = FREG(RD & 0x1e); + } + else if (STDC) + { + //byte_mask = 15; + data0 = 0; + } + else if (STD || STDA) + { + //byte_mask = 15; + data0 = REG(RD & 0x1e); + } + else if (STDFQ) + { + //byte_mask = 15; + data0 = 0; + } + else if (STDCQ) + { + //byte_mask = 15; + data0 = 0; + } + else if (STFSR) + { + // while ((FSR.qne = 1) and (trap = 0)) ( + // wait for pending floating-point instructions to complete + // ) + // next; + //byte_mask = 15; + data0 = FSR; + } + else if (STCSR) + { + // { implementation-dependent actions } + //byte_mask = 15; + data0 = 0; + } + else if (ST || STA) + { + //byte_mask = 15; + data0 = REG(RD); + } + else if (STH || STHA) + { + if ((address & 3) == 0) + { + //byte_mask = 12; + data0 = REG(RD) << 16; + } + else if ((address & 3) == 2) + { + //byte_mask = 3; + data0 = REG(RD); + } + } + else if (STB || STBA) + { + if ((address & 3) == 0) + { + //byte_mask = 8; + data0 = REG(RD) << 24; + } + else if ((address & 3) == 1) + { + //byte_mask = 4; + data0 = REG(RD) << 16; + } + else if ((address & 3) == 2) + { + //byte_mask = 2; + data0 = REG(RD) << 8; + } + else if ((address & 3) == 3) + { + //byte_mask = 1; + data0 = REG(RD); + } + } + + 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])); + 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); + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + } + + PC = nPC; + 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 sparc_base_device::execute_ldd(uint32_t op) +{ + 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; + } + + const uint32_t data = m_mmu->read_asi(m_data_space, address >> 2, 0xffffffff); + + 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); + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + REG(RD | 1) = word1; + + PC = nPC; + nPC = nPC + 4; +} + +inline void sparc_base_device::execute_ld(uint32_t op) +{ + const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (address & 3) + { + 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); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RDBITS) + RDREG = data; + + PC = nPC; + nPC = nPC + 4; +} + +inline void sparc_base_device::execute_ldsh(uint32_t op) +{ + const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (address & 1) + { + 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]); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RDBITS) + { + if ((address & 3) == 0) RDREG = (int32_t)data >> 16; + else if ((address & 3) == 2) RDREG = ((int32_t)data << 16) >> 16; + } + + PC = nPC; + nPC = nPC + 4; +} + +inline void sparc_base_device::execute_lduh(uint32_t op) +{ + const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (address & 1) + { + 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]); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RDBITS) + { + if ((address & 3) == 0) RDREG = data >> 16; + else if ((address & 3) == 2) RDREG = data & 0xffff; + } + + PC = nPC; + nPC = nPC + 4; +} + +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]); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RDBITS) + { + if ((address & 3) == 0) RDREG = (int32_t)data >> 24; + else if ((address & 3) == 1) RDREG = ((int32_t)data << 8) >> 24; + else if ((address & 3) == 2) RDREG = ((int32_t)data << 16) >> 24; + else if ((address & 3) == 3) RDREG = ((int32_t)data << 24) >> 24; + } + + PC = nPC; + nPC = nPC + 4; +} + +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]); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RDBITS) + { + static const int shifts[4] = { 24, 16, 8, 0 }; + RDREG = (uint8_t)(data >> shifts[byte_idx]); + } + + PC = nPC; + nPC = nPC + 4; +} + +inline void sparc_base_device::execute_lddfpr(uint32_t op) +{ + const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (!(PSR & PSR_EF_MASK) || m_bp_fpu_present == 0) + { + m_trap = 1; + m_fp_disabled = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (address & 7) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RD & 1) + { + m_trap = 1; + m_fp_exception = 1; + m_ftt = 0xff; + 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); + + if (m_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) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + FREG(RD | 1) = word1; + + PC = nPC; + nPC = nPC + 4; +} + +inline void sparc_base_device::execute_ldfpr(uint32_t op) +{ + const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (!(PSR & PSR_EF_MASK) || m_bp_fpu_present == 0) + { + m_trap = 1; + m_fp_disabled = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (address & 3) + { + 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); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + FDREG = data; + + PC = nPC; + nPC = nPC + 4; +} + +inline void sparc_base_device::execute_ldfsr(uint32_t op) +{ + const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (!(PSR & PSR_EF_MASK) || m_bp_fpu_present == 0) + { + m_trap = 1; + m_fp_disabled = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (address & 3) + { + 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); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + 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 sparc_base_device::execute_lddcpr(uint32_t op) +{ + const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (!(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 (address & 7) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (m_cp_sequence_err) + { + 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); + 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); + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + // implementation-dependent actions + + PC = nPC; + nPC = nPC + 4; +} + +inline void sparc_base_device::execute_ldcpr(uint32_t op) +{ + const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (!(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 (address & 3) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (m_cp_sequence_err) + { + 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); + + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + // implementation-dependent actions + + PC = nPC; + nPC = nPC + 4; +} + +inline void sparc_base_device::execute_ldcsr(uint32_t op) +{ + const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + + if (!(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 (address & 3) + { + m_trap = 1; + m_mem_address_not_aligned = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (m_cp_sequence_err) + { + 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); + + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + // implementation-dependent actions + + PC = nPC; + nPC = nPC + 4; +} + +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) + { + m_trap = 1; + m_illegal_instruction = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + const uint32_t address = RS1REG + RS2REG; + const uint32_t addr_space = ASI; + + 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(addr_space, address >> 2, 0xffffffff); + + 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); + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + REG(RD | 1) = word1; + + PC = nPC; + nPC = nPC + 4; +} + +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; + } + + const uint32_t address = RS1REG + RS2REG; + + if (address & 3) + { + 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); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RDBITS) + RDREG = data; + + PC = nPC; + nPC = nPC + 4; +} + +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; + } + + const uint32_t address = RS1REG + RS2REG; + + if (address & 1) + { + 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]); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RDBITS) + { + if ((address & 3) == 0) RDREG = (int32_t)data >> 16; + else if ((address & 3) == 2) RDREG = ((int32_t)data << 16) >> 16; + } + + PC = nPC; + nPC = nPC + 4; +} + +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; + } + + const uint32_t address = RS1REG + RS2REG; + if (address & 1) + { + 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]); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RDBITS) + { + if ((address & 3) == 0) RDREG = data >> 16; + else if ((address & 3) == 2) RDREG = data & 0xffff; + } + + PC = nPC; + nPC = nPC + 4; +} + +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]); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RDBITS) + { + if ((address & 3) == 0) RDREG = (int32_t)data >> 24; + else if ((address & 3) == 1) RDREG = ((int32_t)data << 8) >> 24; + else if ((address & 3) == 2) RDREG = ((int32_t)data << 16) >> 24; + else if ((address & 3) == 3) RDREG = ((int32_t)data << 24) >> 24; + } + + PC = nPC; + nPC = nPC + 4; +} + +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]); + + if (m_mae) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + if (RDBITS) + { + if ((address & 3) == 0) RDREG = data >> 24; + else if ((address & 3) == 1) RDREG = (data >> 16) & 0xff; + else if ((address & 3) == 2) RDREG = (data >> 8) & 0xff; + else if ((address & 3) == 3) RDREG = data & 0xff; + } + + PC = nPC; + nPC = nPC + 4; +} + + +//------------------------------------------------- +// execute_ldstub - execute an atomic load-store +// instruction +//------------------------------------------------- + +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) + + 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 + ) + ); + */ + + uint32_t address = 0; + uint8_t addr_space = 0; + if (LDSTUB) + { + address = RS1REG + (USEIMM ? SIMM13 : RS2REG); + addr_space = (IS_USER ? 10 : 11); + } + else if (LDSTUBA) + { + 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; + } + else + { + address = RS1REG + RS2REG; + addr_space = ASI; + return; + } + } + + uint32_t data(0); + //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]); + + 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]); + + m_pb_block_ldst_byte = 0; + + if (MAE) + { + m_trap = 1; + m_data_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + uint32_t word; + if ((address & 3) == 0) + { + word = (data >> 24) & 0xff; + } + else if ((address & 3) == 1) + { + word = (data >> 16) & 0xff; + } + else if ((address & 3) == 2) + { + word = (data >> 8) & 0xff; + } + else // if ((address & 3) == 3) + { + word = data & 0xff; + } + if (RDBITS) + RDREG = word; + + PC = nPC; + nPC = nPC + 4; +} + + +//------------------------------------------------- +// execute_group3 - execute an opcode in group 3 +// (load/store) +//------------------------------------------------- + +inline void sparc_base_device::execute_group3(uint32_t op) +{ + static const int ldst_cycles[64] = { + 1, 1, 1, 2, 2, 2, 2, 3, + 0, 1, 1, 0, 0, 3, 0, 0, + 1, 1, 1, 2, 2, 2, 2, 3, + 0, 1, 1, 0, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + + switch (OP3) + { + case OP3_LD: + execute_ld(op); + break; + case OP3_LDUB: + execute_ldub(op); + break; + case OP3_LDUH: + execute_lduh(op); + break; + case OP3_LDD: + execute_ldd(op); + break; + case OP3_LDSB: + execute_ldsb(op); + break; + case OP3_LDSH: + execute_ldsh(op); + break; + case OP3_LDA: + execute_lda(op); + break; + case OP3_LDUBA: + execute_lduba(op); + break; + case OP3_LDUHA: + execute_lduha(op); + break; + case OP3_LDDA: + execute_ldda(op); + break; + case OP3_LDSBA: + execute_ldsba(op); + break; + case OP3_LDSHA: + execute_ldsha(op); + break; + case OP3_LDFPR: + execute_ldfpr(op); + break; + case OP3_LDFSR: + execute_ldfsr(op); + break; + case OP3_LDDFPR: + execute_lddfpr(op); + break; + case OP3_LDCPR: + execute_ldcpr(op); + break; + case OP3_LDCSR: + execute_ldcsr(op); + break; + case OP3_LDDCPR: + execute_lddcpr(op); + break; + + case OP3_ST: + case OP3_STB: + case OP3_STH: + case OP3_STD: + case OP3_STA: + case OP3_STBA: + case OP3_STHA: + case OP3_STDA: + case OP3_STFPR: + case OP3_STFSR: + case OP3_STDFQ: + case OP3_STDFPR: + case OP3_STCPR: + case OP3_STCSR: + case OP3_STDCQ: + case OP3_STDCPR: + execute_store(op); + break; + + case OP3_LDSTUB: + case OP3_LDSTUBA: + execute_ldstub(op); + break; + + default: + if (!execute_extra_group3(op)) + { + 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; + } + + if (MAE /*|| HOLD_BUS*/) + 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); + return true; + + default: + return false; + } +} + + +//------------------------------------------------- +// 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 + { + nPC = nPC + 4; + if (ANNUL) + m_no_annul = false; + } +} + + +//------------------------------------------------- +// evaluate_condition - evaluate a given integer +// condition code +//------------------------------------------------- + +bool sparc_base_device::evaluate_condition(uint32_t op) +{ + // COND & 8 + // 0 8 + // bn ba + // bz bne + // ble bg + // bl bge + // bleu bgu + // bcs bcc + // bneg bpos + // bvs bvc + + switch(COND) + { + case 0: return false; + case 1: return ICC_Z_SET; + case 2: return ICC_Z_SET || (ICC_N != ICC_Z); + case 3: return (ICC_N != ICC_V); + case 4: return ICC_C_SET || ICC_Z_SET; + case 5: return ICC_C_SET; + case 6: return ICC_N_SET; + case 7: return ICC_V_SET; + + case 8: return true; + case 9: return ICC_Z_CLEAR; + case 10: return ICC_Z_CLEAR && ICC_N_CLEAR; + case 11: return (ICC_N == ICC_V); + case 12: return ICC_C_CLEAR && ICC_Z_CLEAR; + case 13: return ICC_C_CLEAR; + case 14: return ICC_N_CLEAR; + case 15: return ICC_V_CLEAR; + } + + return false; +} + + +//------------------------------------------------- +// execute_bicc - execute a branch opcode +//------------------------------------------------- + +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) + + 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 } + ) + */ + + bool branch_taken = evaluate_condition(op); + uint32_t pc = PC; + PC = nPC; + if (branch_taken) + { + nPC = pc + DISP22; + if (COND == COND_BA && ANNUL) + m_no_annul = false; + } + else + { + nPC = nPC + 4; + if (ANNUL) + m_no_annul = false; + } +} + + +//------------------------------------------------- +// execute_ticc - execute a conditional trap +//------------------------------------------------- + +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) + + 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; + ) + ); + */ + + bool trap_eval_icc = evaluate_condition(op); + + uint8_t trap_number = RS1REG + (USEIMM ? SIMM7 : RS2REG); + + if (COND) + { + if (trap_eval_icc) + { + m_trap = 1; + m_trap_instruction = 1; + m_ticc_trap_type = trap_number & 0x7f; + m_stashed_icount = m_icount; + m_icount = 0; + } + else + { + PC = nPC; + nPC = nPC + 4; + } + } +} + + + +//------------------------------------------------- +// select_trap - prioritize traps and perform any +// additional functions from taking them +//------------------------------------------------- + +void sparc_base_device::select_trap() +{ + if (!m_trap) + return; + + if (m_reset_trap) + { + m_trap = 0; + return; + } + else if (!m_et) + { + m_execute_mode = 0; + m_error_mode = 1; + m_stashed_icount = m_icount; + m_icount = 0; + } + 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_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_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; + else if (m_r_register_access_error) + m_tt = 0x20; + else 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_unimplemented_FLUSH) + m_tt = 0x25; + 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_error) + m_tt = 0x29; + else if (m_data_access_exception) + m_tt = 0x09; + else if (m_tag_overflow) + m_tt = 0x0a; + else if (m_division_by_zero) + m_tt = 0x2a; + else if (m_trap_instruction) + m_tt = 0x80 | m_ticc_trap_type; + else if (m_interrupt_level > 0) + m_tt = 0x10 | m_interrupt_level; + + 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; +} + + +//------------------------------------------------- +// execute_trap - prioritize and invoke traps +// that have been flagged by the previous +// instructions, if any. +//------------------------------------------------- + +void sparc_base_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; + ); + */ + + if (!m_trap) + { + return; + } + + select_trap(); + + if (!m_error_mode) + { + PSR &= ~PSR_ET_MASK; + m_et = false; + + if (IS_USER) + PSR &= ~PSR_PS_MASK; + else + PSR |= PSR_PS_MASK; + + PSR |= PSR_S_MASK; + m_s = true; + m_data_space = 11; + + int cwp = PSR & PSR_CWP_MASK; + int new_cwp = ((cwp + NWINDOWS) - 1) % NWINDOWS; + + PSR &= ~PSR_CWP_MASK; + PSR |= new_cwp; + + update_gpr_pointers(); + + if (m_no_annul) + { + REG(17) = PC; + REG(18) = nPC; + } + else + { + REG(17) = nPC; + REG(18) = nPC + 4; + m_no_annul = true; + } + + if (!m_reset_trap) + { + PC = TBR; + nPC = TBR + 4; + } + else + { + PC = 0; + nPC = 4; + m_reset_trap = 0; + } + } +} + + +//------------------------------------------------- +// dispatch_instruction - executes a +// 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 sparc_base_device::dispatch_instruction(uint32_t op) +{ + const uint8_t op_type = OP; + switch (op_type) + { + case OP_TYPE0: // Bicc, SETHI, FBfcc + switch (OP2) + { + case OP2_UNIMP: // unimp + logerror("unimp @ %x\n", PC); + break; + case OP2_BICC: // branch on integer condition codes + execute_bicc(op); + break; + case OP2_SETHI: // sethi + *m_regs[RD] = op << 10; + m_r[0] = 0; + PC = nPC; + nPC = nPC + 4; + break; + case OP2_FBFCC: // branch on floating-point condition codes + if (!(PSR & PSR_EF_MASK) || !m_bp_fpu_present) + { + m_trap = 1; + m_fp_disabled = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + execute_fbfcc(op); + break; + default: + if (!dispatch_extra_instruction(op)) + { + 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; + + case OP_CALL: + { + uint32_t pc = PC; + uint32_t callpc = PC + DISP30; + PC = nPC; + nPC = callpc; + + REG(15) = pc; + break; + } + + case OP_ALU: + execute_group2(op); + break; + + case OP_LDST: + execute_group3(op); + break; + } +} + +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; + m_stashed_icount = m_icount; + m_icount = 0; + 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_trap = 1; + m_fp_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + 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_trap = 1; + m_fp_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return true; + } + return false; +} + +bool sparc_base_device::set_fpr32(const uint32_t rd, const uint32_t data) +{ + if (softfloat_exceptionFlags && check_fp_exceptions()) + return true; + + m_fpr[rd] = data; + return false; +} + +bool sparc_base_device::set_fpr64(const uint32_t rd, const uint64_t data) +{ + if (softfloat_exceptionFlags && check_fp_exceptions()) + 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 sparc_base_device::complete_fp_execution(uint32_t op) +{ + softfloat_exceptionFlags = 0; + + const uint32_t fpop = (op >> 5) & 0x1ff; + switch (fpop) + { + case FPOP_FMOVS: + FDREG = FREG(RS2); + break; + case FPOP_FNEGS: + { + const float32_t fs2 = float32_t{ FREG(RS2) }; + if (set_fpr32(RD, f32_mul(fs2, i32_to_f32(-1)).v)) + return; + break; + } + case FPOP_FABSS: + { + const uint32_t rs2 = FREG(RS2); + const float32_t fs2 = float32_t{ rs2 }; + if (f32_lt(fs2, float32_t{0})) + { + if (set_fpr32(RD, f32_mul(fs2, i32_to_f32(-1)).v)) + { + return; + } + } + else if (set_fpr32(RD, rs2)) + { + return; + } + break; + } + case FPOP_FSQRTS: + { + const float32_t fs2 = float32_t{ FREG(RS2) }; + if (set_fpr32(RD, f32_sqrt(fs2).v)) + return; + break; + } + case FPOP_FSQRTD: + { + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr64(RD_D, f64_sqrt(fs2).v)) + return; + break; + } + case FPOP_FADDS: + { + const float32_t fs1 = float32_t{ FREG(RS1) }; + const float32_t fs2 = float32_t{ FREG(RS2) }; + if (set_fpr32(RD, f32_add(fs1, fs2).v)) + return; + break; + } + case FPOP_FADDD: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr64(RD_D, f64_add(fs1, fs2).v)) + return; + break; + } + case FPOP_FSUBS: + { + const float32_t fs1 = float32_t{ FREG(RS1) }; + const float32_t fs2 = float32_t{ FREG(RS2) }; + if (set_fpr32(RD, f32_sub(fs1, fs2).v)) + return; + break; + } + case FPOP_FSUBD: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr64(RD_D, f64_sub(fs1, fs2).v)) + return; + break; + } + case FPOP_FMULS: + { + const float32_t fs1 = float32_t{ FREG(RS1) }; + const float32_t fs2 = float32_t{ FREG(RS2) }; + if (set_fpr32(RD, f32_mul(fs1, fs2).v)) + return; + break; + } + case FPOP_FMULD: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr64(RD_D, f64_mul(fs1, fs2).v)) + return; + break; + } + case FPOP_FDIVS: + { + const uint32_t rs1 = FREG(RS1); + const uint32_t rs2 = FREG(RS2); + if (rs2 == 0) + { + check_fdiv_zero_exception(); + return; + } + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + if (set_fpr32(RD, f32_div(fs1, fs2).v)) + return; + break; + } + case FPOP_FDIVD: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + if (rs2 == 0) + { + check_fdiv_zero_exception(); + return; + } + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr64(RD_D, f64_div(fs1, fs2).v)) + return; + break; + } + case FPOP_FITOS: + { + const uint32_t rs2 = FREG(RS2); + if (set_fpr32(RD, i32_to_f32(int32_t(rs2)).v)) + return; + break; + } + case FPOP_FDTOS: + { + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr32(RD, f64_to_f32(fs2).v)) + return; + break; + } + case FPOP_FITOD: + { + const uint32_t rs2 = FREG(RS2); + if (set_fpr64(RD_D, i32_to_f64(int32_t(rs2)).v)) + return; + break; + } + case FPOP_FSTOD: + { + const uint32_t rs2 = FREG(RS2); + const float32_t fs = float32_t{ rs2 }; + if (set_fpr64(RD_D, f32_to_f64(fs).v)) + return; + break; + } + case FPOP_FSTOI: + { + const uint32_t rs2 = FREG(RS2); + const float32_t fs2 = float32_t{ rs2 }; + if (set_fpr32(RD, f32_to_i32(fs2, softfloat_roundingMode, true))) + return; + break; + } + case FPOP_FDTOI: + { + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr32(RD, f64_to_i32(fs2, softfloat_roundingMode, true))) + return; + break; + } + case FPOP_FCMPS: + { + const float32_t fs1 = float32_t{ FREG(RS1) }; + const float32_t fs2 = float32_t{ FREG(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: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + 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: + { + const float32_t fs1 = float32_t{ FREG(RS1) }; + const float32_t fs2 = float32_t{ FREG(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_trap = 1; + m_fp_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + 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: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + 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_trap = 1; + m_fp_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + 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_trap = 1; + m_fp_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + + 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) + + 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 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) + + 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 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) + + 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; + } + } +} + + +//------------------------------------------------- +// execute_step - perform one step in execute +// mode (versus error or reset modes) +//------------------------------------------------- + +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) + + 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 + ) + ) + ) + */ + + // write-state-register delay not yet implemented + + const uint32_t op = m_mmu->fetch_insn(m_s, PC >> 2); + +#if LOG_FCODES + //if (m_log_fcodes) + { + log_fcodes(); + } +#endif + + if (m_no_annul) + { + if (MAE) + { + m_trap = 1; + m_instruction_access_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + dispatch_instruction(op); + } + else + { + m_no_annul = true; + PC = nPC; + nPC = nPC + 4; + } +} + + +//------------------------------------------------- +// reset_step - step one cycle in reset mode +//------------------------------------------------- + +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; + ) + ); + */ + + 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; + } +} + + +//------------------------------------------------- +// error_step - step one cycle in error mode +//------------------------------------------------- + +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 + ) + ); + */ + + 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; + } +} + +template <bool CHECK_DEBUG, sparc_base_device::running_mode MODE> +void sparc_base_device::run_loop() +{ + do + { + /*if (HOLD_BUS) + { + m_icount--; + continue; + }*/ + + if (CHECK_DEBUG) + debugger_instruction_hook(PC); + + if (MODE == MODE_RESET) + { + reset_step(); + } + else if (MODE == MODE_ERROR) + { + error_step(); + } + else if (MODE == MODE_EXECUTE) + { + execute_step(); + } + + if (CHECK_DEBUG) + { + for (int i = 0; i < 8; i++) + { + m_dbgregs[i] = *m_regs[8 + i]; + m_dbgregs[8 + i] = *m_regs[16 + i]; + m_dbgregs[16 + i] = *m_regs[24 + i]; + } + } + --m_icount; + } while (m_icount >= 0); +} + +//------------------------------------------------- +// execute_run - execute a timeslice's worth of +// opcodes +//------------------------------------------------- + +void sparc_base_device::execute_run() +{ + bool debug = machine().debug_flags & DEBUG_FLAG_ENABLED; + + if (m_bp_reset_in) + { + m_execute_mode = 0; + m_error_mode = 0; + m_reset_mode = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + else if (m_et && (m_bp_irl == 15 || m_bp_irl > m_pil)) + { + m_trap = 1; + m_interrupt_level = m_bp_irl; + } + + do + { + if (m_trap) + { + execute_trap(); + } + + if (debug) + { + if (m_reset_mode) + run_loop<true, MODE_RESET>(); + else if (m_error_mode) + run_loop<true, MODE_ERROR>(); + else + run_loop<true, MODE_EXECUTE>(); + } + else + { + if (m_reset_mode) + run_loop<false, MODE_RESET>(); + else if (m_error_mode) + run_loop<false, MODE_ERROR>(); + else + run_loop<false, MODE_EXECUTE>(); + } + + if (m_stashed_icount >= 0) + { + m_icount = m_stashed_icount; + m_stashed_icount = -1; + } + } while (m_icount >= 0); +} + + +//------------------------------------------------- +// get_reg_r - get integer register value for +// disassembler +//------------------------------------------------- + +uint64_t sparc_base_device::get_reg_r(unsigned index) const +{ + return REG(index & 31); +} + + +//------------------------------------------------- +// get_reg_pc - get program counter value for +// disassembler +//------------------------------------------------- + +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; +} + + +//------------------------------------------------- +// get_icc - get integer condition codes for +// disassembler +//------------------------------------------------- + +uint8_t sparc_base_device::get_icc() const +{ + return (m_psr & PSR_ICC_MASK) >> PSR_ICC_SHIFT; +} + + +//------------------------------------------------- +// get_icc - get extended integer condition codes +// for disassembler +//------------------------------------------------- + +uint8_t sparc_base_device::get_xcc() const +{ + // not present before SPARCv9 + return 0; +} + + +//------------------------------------------------- +// get_icc - get extended integer condition codes +// for disassembler +//------------------------------------------------- + +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 deef7376957..67f1b339e0b 100644 --- a/src/devices/cpu/sparc/sparc.h +++ b/src/devices/cpu/sparc/sparc.h @@ -12,24 +12,22 @@ #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_post_load() override; virtual void device_resolve_objects() override; @@ -75,11 +73,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 +97,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 +115,21 @@ 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 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(); @@ -198,17 +200,11 @@ 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_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,8 +217,8 @@ 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_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 @@ -269,8 +265,48 @@ protected: std::function<void (sparc_disassembler *)> m_asi_desc_adder; }; +class sparcv7_device : public sparc_base_device +{ +public: + sparcv7_device(const machine_config &mconfig, 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); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + + 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; +}; + // device type definition -DECLARE_DEVICE_TYPE(MB86901, mb86901_device) +DECLARE_DEVICE_TYPE(SPARCV7, sparcv7_device) +DECLARE_DEVICE_TYPE(SPARCV8, sparcv8_device) enum { @@ -297,6 +333,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/sparcdefs.h b/src/devices/cpu/sparc/sparcdefs.h index f023da44679..82c48b2bf36 100644 --- a/src/devices/cpu/sparc/sparcdefs.h +++ b/src/devices/cpu/sparc/sparcdefs.h @@ -9,8 +9,8 @@ #pragma once -#ifndef __MB86901_DEFS_H__ -#define __MB86901_DEFS_H__ +#ifndef CPU_SPARC_SPARC_DEFS_H +#define CPU_SPARC_SPARC_DEFS_H #define PSR_CWP_MASK 0x0000001f #define PSR_ET_SHIFT 5 @@ -127,9 +127,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] @@ -386,4 +389,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 // CPU_SPARC_SPARC_DEFS_H diff --git a/src/devices/cpu/sparc/mb86901.cpp b/src/devices/cpu/sparc/sparcv7v8.cpp index 82575f57f2a..219fa7334b1 100644 --- a/src/devices/cpu/sparc/mb86901.cpp +++ b/src/devices/cpu/sparc/sparcv7v8.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. +// sparcv7v8.cpp - Emulation for the SPARCv7/v8 line of +// processors. // // Notes: // - The CPU core implementation has been simplified @@ -16,9 +13,8 @@ // ever be. // // To-Do: -// - Ops: FBFcc, LDF, STF // - Test: SPARCv8 ops are untested -// - FPU support +// - Extended-precision FPU support // - Coprocessor support // //================================================================ @@ -29,10 +25,11 @@ #include "debugger.h" +#include "softfloat3/source/include/softfloat.h" -DEFINE_DEVICE_TYPE(MB86901, mb86901_device, "mb86901", "Fujitsu MB86901") +DEFINE_DEVICE_TYPE(SPARCV7, sparcv7_device, "sparcv7", "Sun SPARC v7") -const int mb86901_device::NWINDOWS = 7; +const int sparcv7_device::NWINDOWS = 7; #if LOG_FCODES #include "ss1fcode.ipp" @@ -43,18 +40,18 @@ const int mb86901_device::NWINDOWS = 7; #endif //------------------------------------------------- -// mb86901_device - constructor +// sparcv7_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) +sparcv7_device::sparcv7_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : cpu_device(mconfig, SPARCV7, tag, owner, clock) , m_mmu(*this, finder_base::DUMMY_TAG) { m_default_config = address_space_config("program", ENDIANNESS_BIG, 32, 32); } -void mb86901_device::device_start() +void sparcv7_device::device_start() { #if LOG_FCODES m_ss1_fcode_table.clear(); @@ -139,7 +136,7 @@ void mb86901_device::device_start() #endif 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; @@ -289,31 +286,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 +305,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"); + + for (int i = 0; i < 32; i++) + state_add(SPARC_F0 + i, util::string_format("f%d", i).c_str(), m_fpr[i]); - 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"); - } + 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)); @@ -413,16 +397,16 @@ void mb86901_device::device_start() } -void mb86901_device::device_stop() +void sparcv7_device::device_stop() { } -void mb86901_device::device_resolve_objects() +void sparcv7_device::device_resolve_objects() { m_mmu->set_host(this); } -void mb86901_device::device_reset() +void sparcv7_device::device_reset() { m_trap = 0; m_tt = 0; @@ -487,7 +471,7 @@ void mb86901_device::device_reset() // after loading a savestate //------------------------------------------------- -void mb86901_device::device_post_load() +void sparcv7_device::device_post_load() { update_gpr_pointers(); } @@ -499,7 +483,7 @@ void mb86901_device::device_post_load() // the space doesn't exist //------------------------------------------------- -device_memory_interface::space_config_vector mb86901_device::memory_space_config() const +device_memory_interface::space_config_vector sparcv7_device::memory_space_config() const { space_config_vector config_vector; config_vector.push_back(std::make_pair(AS_PROGRAM, &m_default_config)); @@ -514,7 +498,7 @@ device_memory_interface::space_config_vector mb86901_device::memory_space_config // a 32-bit word in a big-endian system. //------------------------------------------------- -uint32_t mb86901_device::read_sized_word(const uint8_t asi, const uint32_t address, const uint32_t mem_mask) +uint32_t sparcv7_device::read_sized_word(const uint8_t asi, const uint32_t address, const uint32_t mem_mask) { 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); @@ -530,7 +514,7 @@ uint32_t mb86901_device::read_sized_word(const uint8_t asi, const uint32_t addre // size handlers //------------------------------------------------- -void mb86901_device::write_sized_word(const uint8_t asi, const uint32_t address, const uint32_t data, const uint32_t mem_mask) +void sparcv7_device::write_sized_word(const uint8_t asi, const uint32_t address, const uint32_t data, const uint32_t mem_mask) { 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); @@ -542,7 +526,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 sparcv7_device::state_string_export(const device_state_entry &entry, std::string &str) const { switch (entry.index()) { @@ -592,7 +576,7 @@ 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> sparcv7_device::create_disassembler() { auto dasm = std::make_unique<sparc_disassembler>(static_cast<sparc_disassembler::config const *>(this), 7); m_asi_desc_adder(dasm.get()); @@ -609,7 +593,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 noexcept +uint32_t sparcv7_device::execute_min_cycles() const noexcept { return 1; } @@ -620,7 +604,7 @@ uint32_t mb86901_device::execute_min_cycles() const noexcept // cycles it takes for one instruction to execute //------------------------------------------------- -uint32_t mb86901_device::execute_max_cycles() const noexcept +uint32_t sparcv7_device::execute_max_cycles() const noexcept { return 4; } @@ -631,7 +615,7 @@ uint32_t mb86901_device::execute_max_cycles() const noexcept // input/interrupt lines //------------------------------------------------- -uint32_t mb86901_device::execute_input_lines() const noexcept +uint32_t sparcv7_device::execute_input_lines() const noexcept { return 16; } @@ -642,7 +626,7 @@ uint32_t mb86901_device::execute_input_lines() const noexcept // line during execution //------------------------------------------------- -void mb86901_device::execute_set_input(int inputnum, int state) +void sparcv7_device::execute_set_input(int inputnum, int state) { switch (inputnum) { @@ -699,7 +683,7 @@ 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 sparcv7_device::execute_add(uint32_t op) { /* The SPARC Instruction Manual: Version 8, page 173, "Appendix C - ISP Descriptions - Add Instructions" (SPARCv8.pdf, pg. 170) @@ -756,7 +740,7 @@ void mb86901_device::execute_add(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_taddcc(uint32_t op) +void sparcv7_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) @@ -821,7 +805,7 @@ void mb86901_device::execute_taddcc(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_sub(uint32_t op) +void sparcv7_device::execute_sub(uint32_t op) { /* The SPARC Instruction Manual: Version 8, page 174, "Appendix C - ISP Descriptions - Subtract Instructions" (SPARCv8.pdf, pg. 171) @@ -878,7 +862,7 @@ void mb86901_device::execute_sub(uint32_t op) // opcode //-------------------------------------------------- -void mb86901_device::execute_tsubcc(uint32_t op) +void sparcv7_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) @@ -961,8 +945,8 @@ if (ANDcccc or ANDNcc or ORcc or ORNcc or XORcc or XNORcc) then ( ); */ -template <mb86901_device::set_cc SETCC> -void mb86901_device::execute_and(const uint32_t op) +template <sparcv7_device::set_cc SETCC> +void sparcv7_device::execute_and(const uint32_t op) { const uint32_t result = RS1REG & (USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -979,8 +963,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 <sparcv7_device::set_cc SETCC> +void sparcv7_device::execute_or(const uint32_t op) { const uint32_t result = RS1REG | (USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -997,8 +981,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 <sparcv7_device::set_cc SETCC> +void sparcv7_device::execute_xor(const uint32_t op) { const uint32_t result = RS1REG ^ (USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -1015,8 +999,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 <sparcv7_device::set_cc SETCC> +void sparcv7_device::execute_andn(const uint32_t op) { const uint32_t result = RS1REG & ~(USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -1033,8 +1017,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 <sparcv7_device::set_cc SETCC> +void sparcv7_device::execute_orn(const uint32_t op) { const uint32_t result = RS1REG | ~(USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -1051,8 +1035,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 <sparcv7_device::set_cc SETCC> +void sparcv7_device::execute_xnor(const uint32_t op) { const uint32_t result = RS1REG ^ ~(USEIMM ? SIMM13 : RS2REG); if (RDBITS) RDREG = result; @@ -1074,7 +1058,7 @@ void mb86901_device::execute_xnor(const uint32_t op) // sll/srl/sra //------------------------------------------------- -void mb86901_device::execute_shift(uint32_t op) +void sparcv7_device::execute_shift(uint32_t op) { /* The SPARC Instruction Manual: Version 8, page 172, "Appendix C - ISP Descriptions - Shift Instructions" (SPARCv8.pdf, pg. 169) @@ -1108,7 +1092,7 @@ void mb86901_device::execute_shift(uint32_t op) // execute_mulscc - execute a multiply step opcode //-------------------------------------------------- -void mb86901_device::execute_mulscc(uint32_t op) +void sparcv7_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) @@ -1161,7 +1145,7 @@ void mb86901_device::execute_mulscc(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_rdsr(uint32_t op) +void sparcv7_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) @@ -1227,7 +1211,7 @@ void mb86901_device::execute_rdsr(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_wrsr(uint32_t op) +void sparcv7_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) @@ -1382,7 +1366,7 @@ void mb86901_device::execute_wrsr(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_rett(uint32_t op) +void sparcv7_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) @@ -1502,7 +1486,7 @@ void mb86901_device::execute_rett(uint32_t op) // opcode //------------------------------------------------- -void mb86901_device::execute_saverestore(uint32_t op) +void sparcv7_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) @@ -1585,7 +1569,7 @@ 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 sparcv7_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) @@ -1620,12 +1604,14 @@ void mb86901_device::execute_jmpl(uint32_t op) } +execute_extra_group2 + //------------------------------------------------- // execute_group2 - execute an opcode in group 2, // mostly ALU ops //------------------------------------------------- -inline void mb86901_device::execute_group2(uint32_t op) +inline void sparcv7_device::execute_group2(uint32_t op) { switch (OP3) { @@ -1718,7 +1704,6 @@ 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; @@ -1776,11 +1761,14 @@ inline void mb86901_device::execute_group2(uint32_t op) #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; + if (!execute_extra_group2(op)) + { + 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; } } @@ -1792,7 +1780,7 @@ inline void mb86901_device::execute_group2(uint32_t op) // the registers in our current window //------------------------------------------------- -void mb86901_device::update_gpr_pointers() +void sparcv7_device::update_gpr_pointers() { int cwp = PSR & PSR_CWP_MASK; for (int i = 0; i < 8; i++) @@ -1808,7 +1796,7 @@ void mb86901_device::update_gpr_pointers() // execute_store - execute a store-type opcode //------------------------------------------------- -void mb86901_device::execute_store(uint32_t op) +void sparcv7_device::execute_store(uint32_t op) { /* The SPARC Instruction Manual: Version 8, page 165, "Appendix C - ISP Descriptions - Store Instructions" (SPARCv8.pdf, pg. 162) @@ -2275,7 +2263,7 @@ if (((trap = 0) and (LDD or LDDA or LDDF or LDDC)) then ( ); */ -inline void mb86901_device::execute_ldd(uint32_t op) +inline void sparcv7_device::execute_ldd(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2317,7 +2305,7 @@ inline void mb86901_device::execute_ldd(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ld(uint32_t op) +inline void sparcv7_device::execute_ld(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2348,7 +2336,7 @@ inline void mb86901_device::execute_ld(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldsh(uint32_t op) +inline void sparcv7_device::execute_ldsh(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2383,7 +2371,7 @@ inline void mb86901_device::execute_ldsh(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_lduh(uint32_t op) +inline void sparcv7_device::execute_lduh(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2418,7 +2406,7 @@ inline void mb86901_device::execute_lduh(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldsb(uint32_t op) +inline void sparcv7_device::execute_ldsb(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2446,7 +2434,7 @@ inline void mb86901_device::execute_ldsb(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldub(uint32_t op) +inline void sparcv7_device::execute_ldub(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2473,7 +2461,7 @@ inline void mb86901_device::execute_ldub(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_lddfpr(uint32_t op) +inline void sparcv7_device::execute_lddfpr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2544,7 +2532,7 @@ inline void mb86901_device::execute_lddfpr(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldfpr(uint32_t op) +inline void sparcv7_device::execute_ldfpr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2593,7 +2581,7 @@ inline void mb86901_device::execute_ldfpr(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldfsr(uint32_t op) +inline void sparcv7_device::execute_ldfsr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2636,13 +2624,21 @@ inline void mb86901_device::execute_ldfsr(uint32_t op) 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 sparcv7_device::execute_lddcpr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2702,7 +2698,7 @@ inline void mb86901_device::execute_lddcpr(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldcpr(uint32_t op) +inline void sparcv7_device::execute_ldcpr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2751,7 +2747,7 @@ inline void mb86901_device::execute_ldcpr(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldcsr(uint32_t op) +inline void sparcv7_device::execute_ldcsr(uint32_t op) { const uint32_t address = RS1REG + (USEIMM ? SIMM13 : RS2REG); @@ -2800,7 +2796,7 @@ inline void mb86901_device::execute_ldcsr(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldda(uint32_t op) +inline void sparcv7_device::execute_ldda(uint32_t op) { if (IS_USER) { @@ -2861,7 +2857,7 @@ inline void mb86901_device::execute_ldda(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_lda(uint32_t op) +inline void sparcv7_device::execute_lda(uint32_t op) { if (IS_USER) { @@ -2909,7 +2905,7 @@ inline void mb86901_device::execute_lda(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldsha(uint32_t op) +inline void sparcv7_device::execute_ldsha(uint32_t op) { if (IS_USER) { @@ -2961,7 +2957,7 @@ inline void mb86901_device::execute_ldsha(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_lduha(uint32_t op) +inline void sparcv7_device::execute_lduha(uint32_t op) { if (IS_USER) { @@ -3012,7 +3008,7 @@ inline void mb86901_device::execute_lduha(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_ldsba(uint32_t op) +inline void sparcv7_device::execute_ldsba(uint32_t op) { if (IS_USER) { @@ -3056,7 +3052,7 @@ inline void mb86901_device::execute_ldsba(uint32_t op) nPC = nPC + 4; } -inline void mb86901_device::execute_lduba(uint32_t op) +inline void sparcv7_device::execute_lduba(uint32_t op) { if (IS_USER) { @@ -3106,7 +3102,7 @@ inline void mb86901_device::execute_lduba(uint32_t op) // instruction //------------------------------------------------- -void mb86901_device::execute_ldstub(uint32_t op) +void sparcv7_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) @@ -3201,12 +3197,12 @@ void mb86901_device::execute_ldstub(uint32_t op) } 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; @@ -3265,7 +3261,7 @@ void mb86901_device::execute_ldstub(uint32_t op) // (load/store) //------------------------------------------------- -inline void mb86901_device::execute_group3(uint32_t op) +inline void sparcv7_device::execute_group3(uint32_t op) { static const int ldst_cycles[64] = { 1, 1, 1, 2, 2, 2, 2, 3, @@ -3367,6 +3363,7 @@ inline void mb86901_device::execute_group3(uint32_t op) #endif default: + if (!execute_extended_Op( logerror("illegal instruction at %08x: %08x\n", PC, op); m_trap = 1; m_illegal_instruction = 1; @@ -3383,11 +3380,84 @@ inline void mb86901_device::execute_group3(uint32_t op) //------------------------------------------------- +// evaluate_fp_condition - evaluate a given fp +// condition code +//------------------------------------------------- + +bool sparcv7_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 sparcv7_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 + { + nPC = nPC + 4; + if (ANNUL) + m_no_annul = false; + } +} + + +//------------------------------------------------- // evaluate_condition - evaluate a given integer // condition code //------------------------------------------------- -bool mb86901_device::evaluate_condition(uint32_t op) +bool sparcv7_device::evaluate_condition(uint32_t op) { // COND & 8 // 0 8 @@ -3429,7 +3499,7 @@ bool mb86901_device::evaluate_condition(uint32_t op) // execute_bicc - execute a branch opcode //------------------------------------------------- -void mb86901_device::execute_bicc(uint32_t op) +void sparcv7_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) @@ -3485,7 +3555,7 @@ void mb86901_device::execute_bicc(uint32_t op) // execute_ticc - execute a conditional trap //------------------------------------------------- -void mb86901_device::execute_ticc(uint32_t op) +void sparcv7_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) @@ -3551,7 +3621,7 @@ void mb86901_device::execute_ticc(uint32_t op) // additional functions from taking them //------------------------------------------------- -void mb86901_device::select_trap() +void sparcv7_device::select_trap() { if (!m_trap) return; @@ -3636,7 +3706,7 @@ void mb86901_device::select_trap() // instructions, if any. //------------------------------------------------- -void mb86901_device::execute_trap() +void sparcv7_device::execute_trap() { /* The SPARC Instruction Manual: Version 8, page 161, "Appendix C - C.8. Traps" (SPARCv8.pdf, pg. 158) @@ -3804,7 +3874,7 @@ if (trap = 0) then ( ); */ -inline void mb86901_device::dispatch_instruction(uint32_t op) +inline void sparcv7_device::dispatch_instruction(uint32_t op) { const uint8_t op_type = OP; switch (op_type) @@ -3819,7 +3889,6 @@ inline void mb86901_device::dispatch_instruction(uint32_t op) execute_bicc(op); break; case OP2_SETHI: // sethi - //SET_RDREG(IMM22); *m_regs[RD] = op << 10; m_r[0] = 0; PC = nPC; @@ -3828,13 +3897,13 @@ inline void mb86901_device::dispatch_instruction(uint32_t op) 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 @@ -3880,13 +3949,487 @@ inline void mb86901_device::dispatch_instruction(uint32_t op) } } +void sparcv7_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_trap = 1; + m_fp_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + m_fsr |= FSR_AEXC_DZA; +} + +bool sparcv7_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_trap = 1; + m_fp_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return true; + } + return false; +} + +bool sparcv7_device::set_fpr32(const uint32_t rd, const uint32_t data) +{ + if (softfloat_exceptionFlags && check_fp_exceptions()) + return true; + + m_fpr[rd] = data; + return false; +} + +bool sparcv7_device::set_fpr64(const uint32_t rd, const uint64_t data) +{ + if (softfloat_exceptionFlags && check_fp_exceptions()) + 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 sparcv7_device::complete_fp_execution(uint32_t op) { + softfloat_exceptionFlags = 0; + + const uint32_t fpop = (op >> 5) & 0x1ff; + switch (fpop) + { + case FPOP_FMOVS: + FDREG = FREG(RS2); + printf("FMOVs %08x\n", FDREG); + break; + case FPOP_FNEGS: + { + const uint32_t rs2 = FREG(RS2); + const float32_t fs2 = float32_t{ rs2 }; + if (set_fpr32(RD, f32_mul(fs2, i32_to_f32(-1)).v)) + { + printf("FNEGs %08x -> Exception\n", rs2); + return; + } + printf("FNEGs %08x = %08x\n", rs2, FDREG); + break; + } + case FPOP_FABSS: + { + const uint32_t rs2 = FREG(RS2); + const float32_t fs2 = float32_t{ rs2 }; + if (f32_lt(fs2, float32_t{0})) + { + if (set_fpr32(RD, f32_mul(fs2, i32_to_f32(-1)).v)) + { + printf("FABSs %08x -> Exception\n", rs2); + return; + } + } + else if (set_fpr32(RD, rs2)) + { + printf("FABSs %08x -> Exception\n", rs2); + return; + } + + printf("FABSs %08x = %08x\n", rs2, FDREG); + break; + } + case FPOP_FSQRTS: + { + const uint32_t rs2 = FREG(RS2); + const float32_t fs2 = float32_t{ rs2 }; + if (set_fpr32(RD, f32_sqrt(fs2).v)) + { + printf("FSQRTs %08x -> Exception\n", rs2); + return; + } + printf("FSQRTs %08x -> %08x\n", rs2, FDREG); + break; + } + case FPOP_FSQRTD: + { + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr64(RD_D, f64_sqrt(fs2).v)) + { + printf("FSQRTd %08x%08x -> Exception\n", (uint32_t)(rs2 >> 32), (uint32_t)rs2); + return; + } + printf("FSQRTd %08x%08x -> %08x%08x\n", (uint32_t)(rs2 >> 32), (uint32_t)rs2, FREG(RD_D), FREG(RD_D + 1)); + break; + } + case FPOP_FSQRTX: + fatalerror("Unimplemented FPop: FSQRTx\n"); + break; + case FPOP_FADDS: + { + const uint32_t rs1 = FREG(RS1); + const uint32_t rs2 = FREG(RS2); + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + if (set_fpr32(RD, f32_add(fs1, fs2).v)) + { + printf("FADDs %08x + %08x -> Exception\n", rs1, rs2); + return; + } + printf("FADDs %08x + %08x = %08x\n", rs1, rs2, FDREG); + break; + } + case FPOP_FADDD: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr64(RD_D, f64_add(fs1, fs2).v)) + { + printf("FADDd %08x%08x + %08x%08x -> Exception\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + return; + } + printf("FADDd %08x%08x + %08x%08x = %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2, FREG(RD_D), FREG(RD_D + 1)); + break; + } + case FPOP_FADDX: + fatalerror("Unimplemented FPop: FADDx\n"); + break; + case FPOP_FSUBS: + { + const uint32_t rs1 = FREG(RS1); + const uint32_t rs2 = FREG(RS2); + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + if (set_fpr32(RD, f32_sub(fs1, fs2).v)) + { + printf("FSUBs %08x - %08x -> Exception\n", rs1, rs2); + return; + } + printf("FSUBs %08x - %08x = %08x\n", rs1, rs2, FDREG); + break; + } + case FPOP_FSUBD: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr64(RD_D, f64_sub(fs1, fs2).v)) + { + printf("FSUBd %08x%08x - %08x%08x -> Exception\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + return; + } + printf("FSUBd %08x%08x - %08x%08x = %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2, FREG(RD_D), FREG(RD_D + 1)); + break; + } + case FPOP_FSUBX: + fatalerror("Unimplemented FPop: FSUBx\n"); + break; + case FPOP_FMULS: + { + const uint32_t rs1 = FREG(RS1); + const uint32_t rs2 = FREG(RS2); + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + if (set_fpr32(RD, f32_mul(fs1, fs2).v)) + { + printf("FMULs %08x * %08x -> Exception\n", rs1, rs2); + return; + } + printf("FMULs %08x * %08x = %08x\n", rs1, rs2, FDREG); + break; + } + case FPOP_FMULD: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr64(RD_D, f64_mul(fs1, fs2).v)) + { + printf("FMULd %08x%08x * %08x%08x -> Exception\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + return; + } + printf("FMULd %08x%08x * %08x%08x = %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2, FREG(RD_D), FREG(RD_D + 1)); + break; + } + case FPOP_FMULX: + fatalerror("Unimplemented FPop: FMULx\n"); + break; + case FPOP_FDIVS: + { + const uint32_t rs1 = FREG(RS1); + const uint32_t rs2 = FREG(RS2); + if (rs2 == 0) + { + check_fdiv_zero_exception(); + printf("FDIVs %08x / %08x -> divide by zero\n", rs1, rs2); + return; + } + const float32_t fs1 = float32_t{ rs1 }; + const float32_t fs2 = float32_t{ rs2 }; + if (set_fpr32(RD, f32_div(fs1, fs2).v)) + { + printf("FDIVs %08x / %08x -> Exception\n", rs1, rs2); + return; + } + printf("FDIVs %08x / %08x = %08x\n", rs1, rs2, FDREG); + break; + } + case FPOP_FDIVD: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + if (rs2 == 0) + { + check_fdiv_zero_exception(); + printf("FDIVd %08x%08x / %08x%08x -> divide by zero\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + return; + } + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr64(RD_D, f64_div(fs1, fs2).v)) + { + printf("FDIVd %08x%08x / %08x%08x -> Exception\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + return; + } + printf("FDIVd %08x%08x / %08x%08x = %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2, FREG(RD_D), FREG(RD_D + 1)); + break; + } + case FPOP_FDIVX: + fatalerror("Unimplemented FPop: FDIVx\n"); + break; + case FPOP_FITOS: + { + const uint32_t rs2 = FREG(RS2); + if (set_fpr32(RD, i32_to_f32(int32_t(rs2)).v)) + { + printf("FiTOs %08x -> Exception\n", rs2); + return; + } + printf("FiTOs %08x -> %08x\n", rs2, FDREG); + break; + } + case FPOP_FDTOS: + { + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr32(RD, f64_to_f32(fs2).v)) + { + printf("FdTOs %08x%08x -> Exception\n", (uint32_t)(rs2 >> 32), (uint32_t)rs2); + return; + } + printf("FdTOs %08x%08x -> %08x\n", (uint32_t)(rs2 >> 32), (uint32_t)rs2, FDREG); + break; + } + case FPOP_FXTOS: + fatalerror("Unimplemented FPop: FxTOs\n"); + break; + case FPOP_FITOD: + { + const uint32_t rs2 = FREG(RS2); + if (set_fpr64(RD_D, i32_to_f64(int32_t(rs2)).v)) + { + printf("FiTOd %08x -> Exception\n", rs2); + return; + } + printf("FiTOd %08x -> %08x%08x\n", rs2, FREG(RD_D), FREG(RD_D + 1)); + break; + } + case FPOP_FSTOD: + { + const uint32_t rs2 = FREG(RS2); + const float32_t fs = float32_t{ rs2 }; + if (set_fpr64(RD_D, f32_to_f64(fs).v)) + { + printf("FsTOd %08x -> Exception\n", rs2); + return; + } + printf("FsTOd %08x -> %08x%08x\n", rs2, FREG(RD_D), FREG(RD_D + 1)); + break; + } + case FPOP_FXTOD: + fatalerror("Unimplemented FPop: FxTOd\n"); + break; + case FPOP_FITOX: + fatalerror("Unimplemented FPop: FiTOx\n"); + break; + case FPOP_FSTOX: + fatalerror("Unimplemented FPop: FsTOx\n"); + break; + case FPOP_FDTOX: + fatalerror("Unimplemented FPop: FdTOx\n"); + break; + case FPOP_FSTOI: + { + const uint32_t rs2 = FREG(RS2); + const float32_t fs2 = float32_t{ rs2 }; + if (set_fpr32(RD, f32_to_i32(fs2, softfloat_roundingMode, true))) + { + printf("FsTOi %08x -> Exception\n", rs2); + return; + } + printf("FsTOi %08x -> %08x\n", rs2, FDREG); + break; + } + case FPOP_FDTOI: + { + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs2 = float64_t{ rs2 }; + if (set_fpr32(RD, f64_to_i32(fs2, softfloat_roundingMode, true))) + { + printf("FdTOi %08x%08x -> Exception\n", (uint32_t)(rs2 >> 32), (uint32_t)rs2); + return; + } + printf("FdTOi %08x%08x -> %08x\n", (uint32_t)(rs2 >> 32), (uint32_t)rs2, FDREG); + break; + } + case FPOP_FXTOI: + fatalerror("Unimplemented FPop: FxTOi\n"); + break; + case FPOP_FCMPS: + { + const uint32_t rs1 = FREG(RS1); + const uint32_t rs2 = FREG(RS2); + 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) + { + printf("FCMPs %08x ? %08x\n", rs1, rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_UO; + } + else if (equal) + { + printf("FCMPs %08x = %08x\n", rs1, rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_EQ; + } + else if (f32_lt(fs1, fs2)) + { + printf("FCMPs %08x < %08x\n", rs1, rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_LT; + } + else + { + printf("FCMPs %08x > %08x\n", rs1, rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_GT; + } + break; + } + case FPOP_FCMPD: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + bool equal = f64_eq(fs1, fs2); + if (softfloat_exceptionFlags & softfloat_flag_invalid) + { + printf("FCMPd %08x%08x ? %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_UO; + } + else if (equal) + { + printf("FCMPd %08x%08x = %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_EQ; + } + else if (f64_lt(fs1, fs2)) + { + printf("FCMPd %08x%08x < %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_LT; + } + else + { + printf("FCMPd %08x%08x > %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_GT; + } + break; + } + case FPOP_FCMPX: + fatalerror("Unimplemented FPop: FCMPx\n"); + break; + case FPOP_FCMPES: + fatalerror("Unimplemented FPop: FCMPEs\n"); + break; + case FPOP_FCMPED: + { + const uint64_t rs1 = ((uint64_t)FREG(RS1_D) << 32) | FREG(RS1_D + 1); + const uint64_t rs2 = ((uint64_t)FREG(RS2_D) << 32) | FREG(RS2_D + 1); + const float64_t fs1 = float64_t{ rs1 }; + const float64_t fs2 = float64_t{ rs2 }; + bool equal = f64_eq(fs1, fs2); + if (softfloat_exceptionFlags & softfloat_flag_invalid) + { + printf("FCMPEd %08x%08x ? %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + 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_trap = 1; + m_fp_exception = 1; + m_stashed_icount = m_icount; + m_icount = 0; + return; + } + m_fsr |= FSR_AEXC_NVA; + break; + } + else if (equal) + { + printf("FCMPEd %08x%08x = %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_EQ; + break; + } + else if (f64_lt(fs1, fs2)) + { + printf("FCMPEd %08x%08x < %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_LT; + break; + } + else + { + printf("FCMPEd %08x%08x > %08x%08x\n", (uint32_t)(rs1 >> 32), (uint32_t)rs1, (uint32_t)(rs2 >> 32), (uint32_t)rs2); + m_fsr = (m_fsr & ~FSR_FCC_MASK) | FSR_FCC_GT; + break; + } + break; + } + case FPOP_FCMPEX: + fatalerror("Unimplemented FPop: FCMPEx\n"); + break; + default: + fatalerror("Unknown FPop: %03x\n", fpop); + break; + } + + PC = nPC; + nPC = nPC + 4; } //------------------------------------------------- @@ -3894,7 +4437,7 @@ void mb86901_device::complete_fp_execution(uint32_t /*op*/) // mode (versus error or reset modes) //------------------------------------------------- -inline void mb86901_device::execute_step() +inline void sparcv7_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) @@ -3985,7 +4528,7 @@ inline void mb86901_device::execute_step() // reset_step - step one cycle in reset mode //------------------------------------------------- -void mb86901_device::reset_step() +void sparcv7_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) @@ -4015,7 +4558,7 @@ void mb86901_device::reset_step() // error_step - step one cycle in error mode //------------------------------------------------- -void mb86901_device::error_step() +void sparcv7_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) @@ -4038,8 +4581,8 @@ void mb86901_device::error_step() } } -template <bool CHECK_DEBUG, mb86901_device::running_mode MODE> -void mb86901_device::run_loop() +template <bool CHECK_DEBUG, sparcv7_device::running_mode MODE> +void sparcv7_device::run_loop() { do { @@ -4083,7 +4626,7 @@ void mb86901_device::run_loop() // opcodes //------------------------------------------------- -void mb86901_device::execute_run() +void sparcv7_device::execute_run() { bool debug = machine().debug_flags & DEBUG_FLAG_ENABLED; @@ -4142,7 +4685,7 @@ void mb86901_device::execute_run() // disassembler //------------------------------------------------- -uint64_t mb86901_device::get_reg_r(unsigned index) const +uint64_t sparcv7_device::get_reg_r(unsigned index) const { return REG(index & 31); } @@ -4153,7 +4696,7 @@ uint64_t mb86901_device::get_reg_r(unsigned index) const // disassembler //------------------------------------------------- -uint64_t mb86901_device::get_translated_pc() const +uint64_t sparcv7_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 +4708,7 @@ uint64_t mb86901_device::get_translated_pc() const // disassembler //------------------------------------------------- -uint8_t mb86901_device::get_icc() const +uint8_t sparcv7_device::get_icc() const { return (m_psr & PSR_ICC_MASK) >> PSR_ICC_SHIFT; } @@ -4176,7 +4719,7 @@ uint8_t mb86901_device::get_icc() const // for disassembler //------------------------------------------------- -uint8_t mb86901_device::get_xcc() const +uint8_t sparcv7_device::get_xcc() const { // not present before SPARCv9 return 0; @@ -4188,7 +4731,7 @@ uint8_t mb86901_device::get_xcc() const // for disassembler //------------------------------------------------- -uint8_t mb86901_device::get_fcc(unsigned index) const +uint8_t sparcv7_device::get_fcc(unsigned index) const { // only one fcc instance before SPARCv9 return (m_fsr >> 10) & 3; 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..331d8924d07 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; @@ -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) diff --git a/src/devices/machine/sun4c_mmu.cpp b/src/devices/machine/sun4c_mmu.cpp index 08fae7b4aec..9dd8f90c433 100644 --- a/src/devices/machine/sun4c_mmu.cpp +++ b/src/devices/machine/sun4c_mmu.cpp @@ -2,15 +2,21 @@ // copyright-holders:Ryan Holtz /*************************************************************************** - sun4c_mmu.cpp - Sun 4c MMU emulation + sun4c_mmu.cpp - Sun 4/4c MMU emulation ***************************************************************************/ #include "emu.h" #include "sun4c_mmu.h" + #include "cpu/sparc/sparc.h" -DEFINE_DEVICE_TYPE(SUN4C_MMU, sun4c_mmu_device, "sun4c_mmu", "Sun 4C MMU") +#include "debug/debugcon.h" +#include "debug/debugcmd.h" +#include "debugger.h" + +DEFINE_DEVICE_TYPE(SUN4_MMU, sun4_mmu_device, "sun4_mmu", "Sun 4 MMU") +DEFINE_DEVICE_TYPE(SUN4C_MMU, sun4c_mmu_device, "sun4c_mmu", "Sun 4c MMU") #define LOG_PAGE_MAP (1U << 0) #define LOG_SEGMENT_MAP (1U << 1) @@ -31,8 +37,8 @@ DEFINE_DEVICE_TYPE(SUN4C_MMU, sun4c_mmu_device, "sun4c_mmu", "Sun 4C MMU") #define VERBOSE (0) #include "logmacro.h" -sun4c_mmu_device::sun4c_mmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, SUN4C_MMU, tag, owner, clock) +sun4_mmu_base_device::sun4_mmu_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) , m_cpu(*this, finder_base::DUMMY_TAG) , m_ram(*this, finder_base::DUMMY_TAG) , m_rom(*this, finder_base::DUMMY_TAG) @@ -53,7 +59,17 @@ sun4c_mmu_device::sun4c_mmu_device(const machine_config &mconfig, const char *ta { } -void sun4c_mmu_device::device_start() +sun4_mmu_device::sun4_mmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : sun4_mmu_base_device(mconfig, SUN4_MMU, tag, owner, clock, 7, 0x7f, 0x7ff, 11, 0x1f, 0x7ffff, 0xfff) +{ +} + +sun4c_mmu_device::sun4c_mmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : sun4_mmu_base_device(mconfig, SUN4C_MMU, tag, owner, clock, 7, 0x7f, 0x3ff, 10, 0x3f, 0xffff, 0x3fff) +{ +} + +void sun4_mmu_base_device::device_start() { m_type1_r.resolve_safe(0xffffffff); m_type1_w.resolve_safe(); @@ -62,26 +78,29 @@ void sun4c_mmu_device::device_start() m_reset_timer = timer_alloc(TIMER_RESET); m_reset_timer->adjust(attotime::never); + m_segmap = std::make_unique<std::unique_ptr<uint8_t[]>[]>(16); + m_segmap_masked = std::make_unique<std::unique_ptr<uint32_t[]>[]>(16); + for (int i = 0; i < 16; i++) { - save_item(NAME(m_segmap[i]), i); - save_item(NAME(m_segmap_masked[i]), i); + m_segmap[i] = std::make_unique<uint8_t[]>(16384); + m_segmap_masked[i] = std::make_unique<uint32_t[]>(16384); + save_pointer(NAME(m_segmap[i]), 16384, i); + save_pointer(NAME(m_segmap_masked[i]), 16384, i); } - for (int i = 0; i < 16384; i++) - { - save_item(NAME(m_pagemap[i].valid), i); - save_item(NAME(m_pagemap[i].writable), i); - save_item(NAME(m_pagemap[i].supervisor), i); - save_item(NAME(m_pagemap[i].uncached), i); - save_item(NAME(m_pagemap[i].accessed), i); - save_item(NAME(m_pagemap[i].modified), i); - save_item(NAME(m_pagemap[i].page), i); - save_item(NAME(m_pagemap[i].type), i); - } + m_pagemap = std::make_unique<page_entry[]>(16384); + save_pointer(NAME(reinterpret_cast<uint8_t*>(m_pagemap.get())), sizeof(page_entry) * 16384); + + m_cachetags = std::make_unique<uint32_t[]>(16384); + save_pointer(NAME(m_cachetags), 16384); + + m_cachedata = std::make_unique<uint32_t[]>(16384); + save_pointer(NAME(m_cachedata), 16384); + + m_page_valid = std::make_unique<bool[]>(16384); + save_pointer(NAME(m_page_valid), 16384); - save_item(NAME(m_cachetags)); - save_item(NAME(m_cachedata)); save_item(NAME(m_ram_size)); save_item(NAME(m_ram_size_words)); save_item(NAME(m_context)); @@ -89,15 +108,25 @@ void sun4c_mmu_device::device_start() save_item(NAME(m_system_enable)); save_item(NAME(m_fetch_bootrom)); save_item(NAME(m_buserr)); - save_item(NAME(m_page_valid)); save_item(NAME(m_ctx_mask)); save_item(NAME(m_pmeg_mask)); + save_item(NAME(m_page_mask)); + save_item(NAME(m_seg_entry_shift)); + save_item(NAME(m_seg_entry_mask)); + save_item(NAME(m_page_entry_mask)); + save_item(NAME(m_cache_mask)); save_item(NAME(m_ram_set_mask)); save_item(NAME(m_ram_set_base)); save_item(NAME(m_populated_ram_words)); + + if (machine().debug_flags & DEBUG_FLAG_ENABLED) + { + using namespace std::placeholders; + machine().debugger().console().register_command("l2p", CMDFLAG_NONE, 0, 1, 1, std::bind(&sun4_mmu_base_device::l2p_command, this, _1, _2)); + } } -void sun4c_mmu_device::device_reset() +void sun4_mmu_base_device::device_reset() { m_rom_ptr = (uint32_t *)m_rom->base(); m_ram_ptr = (uint32_t *)m_ram->pointer(); @@ -129,19 +158,22 @@ void sun4c_mmu_device::device_reset() m_context = 0; m_context_masked = 0; - m_curr_segmap = m_segmap[0]; - m_curr_segmap_masked = m_segmap_masked[0]; + m_curr_segmap = &m_segmap[0][0]; + m_curr_segmap_masked = &m_segmap_masked[0][0]; m_system_enable = 0; m_fetch_bootrom = true; memset(m_buserr, 0, sizeof(uint32_t) * 4); - memset(m_segmap, 0, sizeof(uint8_t) * 16 * 4096); - memset(m_pagemap, 0, sizeof(page_entry_t) * 16384); - memset(m_cachetags, 0, sizeof(uint32_t) * 16384); - memset(m_cachedata, 0, sizeof(uint32_t) * 16384); + for (int i = 0; i < 16; i++) + { + memset(&m_segmap[i][0], 0, 4096); + } + memset(&m_pagemap[0], 0, sizeof(page_entry) * 16384); + memset(&m_cachetags[0], 0, sizeof(uint32_t) * 16384); + memset(&m_cachedata[0], 0, sizeof(uint32_t) * 16384); } -void sun4c_mmu_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +void sun4_mmu_base_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { if (id == TIMER_RESET) { @@ -150,7 +182,7 @@ void sun4c_mmu_device::device_timer(emu_timer &timer, device_timer_id id, int pa } } -uint32_t sun4c_mmu_device::fetch_insn(const bool supervisor, const uint32_t offset) +uint32_t sun4_mmu_base_device::fetch_insn(const bool supervisor, const uint32_t offset) { if (supervisor) return insn_data_r<SUPER_INSN>(offset, 0xffffffff); @@ -158,7 +190,7 @@ uint32_t sun4c_mmu_device::fetch_insn(const bool supervisor, const uint32_t offs return insn_data_r<USER_INSN>(offset, 0xffffffff); } -uint32_t sun4c_mmu_device::read_asi(uint8_t asi, uint32_t offset, uint32_t mem_mask) +uint32_t sun4_mmu_base_device::read_asi(uint8_t asi, uint32_t offset, uint32_t mem_mask) { LOGMASKED(LOG_ALL_ASI, "read_asi %d: %08x & %08x\n", asi, offset << 2, mem_mask); switch (asi) @@ -187,7 +219,7 @@ uint32_t sun4c_mmu_device::read_asi(uint8_t asi, uint32_t offset, uint32_t mem_m } } -void sun4c_mmu_device::write_asi(uint8_t asi, uint32_t offset, uint32_t data, uint32_t mem_mask) +void sun4_mmu_base_device::write_asi(uint8_t asi, uint32_t offset, uint32_t data, uint32_t mem_mask) { LOGMASKED(LOG_ALL_ASI, "write_asi %d: %08x = %08x & %08x\n", asi, offset << 2, data, mem_mask); switch (asi) @@ -223,18 +255,18 @@ void sun4c_mmu_device::write_asi(uint8_t asi, uint32_t offset, uint32_t data, ui } } -uint32_t sun4c_mmu_device::cache_flush_r() +uint32_t sun4_mmu_base_device::cache_flush_r() { // Do nothing for now return 0; } -void sun4c_mmu_device::cache_flush_w() +void sun4_mmu_base_device::cache_flush_w() { // Do nothing for now } -uint32_t sun4c_mmu_device::system_r(const uint32_t offset, const uint32_t mem_mask) +uint32_t sun4_mmu_base_device::system_r(const uint32_t offset, const uint32_t mem_mask) { LOGMASKED(LOG_SYSTEM, "%s: system_r: %08x & %08x\n", machine().describe_context(), offset << 2, mem_mask); switch (offset >> 26) @@ -264,11 +296,11 @@ uint32_t sun4c_mmu_device::system_r(const uint32_t offset, const uint32_t mem_ma case 8: // (d-)cache tags LOGMASKED(LOG_CACHE_TAGS, "sun4_mmu: read dcache tags @ %x, PC = %x\n", offset, m_cpu->pc()); - return m_cachetags[offset & 0x3fff]; + return m_cachetags[offset & m_cache_mask]; case 9: // (d-)cache data LOGMASKED(LOG_CACHE_DATA, "sun4c_mmu: read dcache data @ %x, PC = %x\n", offset, m_cpu->pc()); - return m_cachedata[offset & 0x3fff]; + return m_cachedata[offset & m_cache_mask]; case 0xf: // UART bypass switch (offset & 3) @@ -285,7 +317,7 @@ uint32_t sun4c_mmu_device::system_r(const uint32_t offset, const uint32_t mem_ma } } -void sun4c_mmu_device::system_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask) +void sun4_mmu_base_device::system_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask) { LOGMASKED(LOG_SYSTEM, "system_w: %08x = %08x & %08x\n", offset << 2, data, mem_mask); switch (offset >> 26) @@ -295,8 +327,8 @@ void sun4c_mmu_device::system_w(const uint32_t offset, const uint32_t data, cons m_context = data >> 24; m_context_masked = m_context & m_ctx_mask; m_cache_context = m_context & m_ctx_mask; - m_curr_segmap = m_segmap[m_context_masked]; - m_curr_segmap_masked = m_segmap_masked[m_context_masked]; + m_curr_segmap = &m_segmap[m_context_masked][0]; + m_curr_segmap_masked = &m_segmap_masked[m_context_masked][0]; return; case 4: // system enable reg @@ -336,12 +368,12 @@ void sun4c_mmu_device::system_w(const uint32_t offset, const uint32_t data, cons case 8: // cache tags LOGMASKED(LOG_CACHE_TAGS, "write cache tags %08x = %08x & %08x\n", offset << 2, data, mem_mask); - m_cachetags[offset&0x3fff] = data & 0x03f8fffc; + m_cachetags[offset & m_cache_mask] = data & 0x03f8fffc; return; case 9: // cache data LOGMASKED(LOG_CACHE_DATA, "write cache data %08x = %08x & %08x\n", offset << 2, data, mem_mask); - m_cachedata[offset&0x3fff] = data | (1 << 19); + m_cachedata[offset & m_cache_mask] = data | (1 << 19); return; case 0xf: // UART bypass @@ -359,7 +391,7 @@ void sun4c_mmu_device::system_w(const uint32_t offset, const uint32_t data, cons } } -uint32_t sun4c_mmu_device::segment_map_r(const uint32_t offset, const uint32_t mem_mask) +uint32_t sun4_mmu_base_device::segment_map_r(const uint32_t offset, const uint32_t mem_mask) { uint32_t ret = 0; if (mem_mask == 0xffff0000) @@ -374,7 +406,7 @@ uint32_t sun4c_mmu_device::segment_map_r(const uint32_t offset, const uint32_t m return ret; } -void sun4c_mmu_device::segment_map_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask) +void sun4_mmu_base_device::segment_map_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask) { LOGMASKED(LOG_SEGMENT_MAP, "write segment map %08x = %08x & %08x\n", offset << 2, data, mem_mask); @@ -389,23 +421,23 @@ void sun4c_mmu_device::segment_map_w(const uint32_t offset, const uint32_t data, m_curr_segmap_masked[seg] = (segdata & m_pmeg_mask) << 6; } -uint32_t sun4c_mmu_device::page_map_r(const uint32_t offset, const uint32_t mem_mask) +uint32_t sun4_mmu_base_device::page_map_r(const uint32_t offset, const uint32_t mem_mask) { - const uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> 10) & 0x3f); - const uint32_t ret = m_pagemap[page].to_uint(); + const uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> m_seg_entry_shift) & m_seg_entry_mask); + const uint32_t ret = page_entry_to_uint(page); LOGMASKED(LOG_PAGE_MAP, "read page map %08x & %08x (%x) = %08x\n", offset << 2, mem_mask, page, ret); return ret; } -void sun4c_mmu_device::page_map_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask) +void sun4_mmu_base_device::page_map_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask) { - uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> 10) & 0x3f); + uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> m_seg_entry_shift) & m_seg_entry_mask); LOGMASKED(LOG_PAGE_MAP, "write page map %08x (%x) = %08x & %08x\n", offset << 2, page, data, mem_mask); - m_pagemap[page].merge_uint(data, mem_mask); + merge_page_entry(page, data, mem_mask); m_page_valid[page] = m_pagemap[page].valid; } -void sun4c_mmu_device::type0_timeout_r(const uint32_t offset) +void sun4_mmu_base_device::type0_timeout_r(const uint32_t offset) { LOGMASKED(LOG_TYPE0_TIMEOUT, "type 0 read timeout %08x, PC=%08x\n", offset << 2, m_cpu->pc()); m_buserr[0] = 0x20; // read timeout @@ -413,7 +445,7 @@ void sun4c_mmu_device::type0_timeout_r(const uint32_t offset) m_host->set_mae(); } -void sun4c_mmu_device::type0_timeout_w(const uint32_t offset) +void sun4_mmu_base_device::type0_timeout_w(const uint32_t offset) { LOGMASKED(LOG_TYPE0_TIMEOUT, "type 0 write timeout %08x, PC=%08x\n", offset << 2, m_cpu->pc()); m_buserr[0] = 0x8020; // write timeout @@ -421,31 +453,33 @@ void sun4c_mmu_device::type0_timeout_w(const uint32_t offset) m_host->set_mae(); } -uint32_t sun4c_mmu_device::page_entry_t::to_uint() +uint32_t sun4_mmu_base_device::page_entry_to_uint(uint32_t index) { - return valid | writable | supervisor | uncached | (type << 26) | accessed | modified | (page >> 10); + const page_entry &pe = m_pagemap[index]; + return pe.valid | pe.writable | pe.supervisor | pe.uncached | (pe.type << 26) | pe.accessed | pe.modified | (pe.page >> m_seg_entry_shift); } -void sun4c_mmu_device::page_entry_t::merge_uint(uint32_t data, uint32_t mem_mask) +void sun4_mmu_base_device::merge_page_entry(uint32_t index, uint32_t data, uint32_t mem_mask) { - const uint32_t new_value = (to_uint() & ~mem_mask) | (data & mem_mask); - valid = new_value & PM_VALID; - writable = new_value & PM_WRITEMASK; - supervisor = new_value & PM_SYSMASK; - uncached = new_value & PM_CACHE; - type = (new_value & PM_TYPEMASK) >> 26; - accessed = new_value & PM_ACCESSED; - modified = new_value & PM_MODIFIED; - page = (new_value & 0xffff) << 10; + page_entry &pe = m_pagemap[index]; + const uint32_t new_value = (page_entry_to_uint(index) & ~mem_mask) | (data & mem_mask); + pe.valid = new_value & PM_VALID; + pe.writable = new_value & PM_WRITEMASK; + pe.supervisor = new_value & PM_SYSMASK; + pe.uncached = new_value & PM_CACHE; + pe.type = (new_value & PM_TYPEMASK) >> 26; + pe.accessed = new_value & PM_ACCESSED; + pe.modified = new_value & PM_MODIFIED; + pe.page = (new_value & m_page_entry_mask) << m_seg_entry_shift; } -template uint32_t sun4c_mmu_device::insn_data_r<sun4c_mmu_device::USER_INSN>(const uint32_t, const uint32_t); -template uint32_t sun4c_mmu_device::insn_data_r<sun4c_mmu_device::SUPER_INSN>(const uint32_t, const uint32_t); -template uint32_t sun4c_mmu_device::insn_data_r<sun4c_mmu_device::USER_DATA>(const uint32_t, const uint32_t); -template uint32_t sun4c_mmu_device::insn_data_r<sun4c_mmu_device::SUPER_DATA>(const uint32_t, const uint32_t); +template uint32_t sun4_mmu_base_device::insn_data_r<sun4_mmu_base_device::USER_INSN>(const uint32_t, const uint32_t); +template uint32_t sun4_mmu_base_device::insn_data_r<sun4_mmu_base_device::SUPER_INSN>(const uint32_t, const uint32_t); +template uint32_t sun4_mmu_base_device::insn_data_r<sun4_mmu_base_device::USER_DATA>(const uint32_t, const uint32_t); +template uint32_t sun4_mmu_base_device::insn_data_r<sun4_mmu_base_device::SUPER_DATA>(const uint32_t, const uint32_t); -template <sun4c_mmu_device::insn_data_mode MODE> -uint32_t sun4c_mmu_device::insn_data_r(const uint32_t offset, const uint32_t mem_mask) +template <sun4_mmu_base_device::insn_data_mode MODE> +uint32_t sun4_mmu_base_device::insn_data_r(const uint32_t offset, const uint32_t mem_mask) { // supervisor program fetches in boot state are special if (MODE == SUPER_INSN && m_fetch_bootrom) @@ -455,14 +489,14 @@ uint32_t sun4c_mmu_device::insn_data_r(const uint32_t offset, const uint32_t mem // it's translation time const uint32_t pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff];// & m_pmeg_mask; - const uint32_t entry_index = pmeg | ((offset >> 10) & 0x3f); + const uint32_t entry_index = pmeg | ((offset >> m_seg_entry_shift) & m_seg_entry_mask); if (m_page_valid[entry_index]) { - page_entry_t &entry = m_pagemap[entry_index]; + page_entry &entry = m_pagemap[entry_index]; entry.accessed = PM_ACCESSED; - const uint32_t tmp = entry.page | (offset & 0x3ff); + const uint32_t tmp = entry.page | (offset & m_page_mask); switch (entry.type) { @@ -495,7 +529,7 @@ uint32_t sun4c_mmu_device::insn_data_r(const uint32_t offset, const uint32_t mem { if (!machine().side_effects_disabled()) { - LOGMASKED(LOG_INVALID_PTE, "read invalid PTE %d (%08x), %08x & %08x, PC=%08x\n", entry_index, m_pagemap[entry_index].to_uint(), offset << 2, mem_mask, m_cpu->pc()); + LOGMASKED(LOG_INVALID_PTE, "read invalid PTE %d (%08x), %08x & %08x, PC=%08x\n", entry_index, page_entry_to_uint(entry_index), offset << 2, mem_mask, m_cpu->pc()); m_host->set_mae(); m_buserr[0] |= 0x80; // invalid PTE m_buserr[0] &= ~0x8000; // read @@ -520,24 +554,24 @@ uint32_t sun4c_mmu_device::insn_data_r(const uint32_t offset, const uint32_t mem } } -template void sun4c_mmu_device::insn_data_w<sun4c_mmu_device::USER_INSN>(const uint32_t, const uint32_t, const uint32_t); -template void sun4c_mmu_device::insn_data_w<sun4c_mmu_device::SUPER_INSN>(const uint32_t, const uint32_t, const uint32_t); -template void sun4c_mmu_device::insn_data_w<sun4c_mmu_device::USER_DATA>(const uint32_t, const uint32_t, const uint32_t); -template void sun4c_mmu_device::insn_data_w<sun4c_mmu_device::SUPER_DATA>(const uint32_t, const uint32_t, const uint32_t); +template void sun4_mmu_base_device::insn_data_w<sun4_mmu_base_device::USER_INSN>(const uint32_t, const uint32_t, const uint32_t); +template void sun4_mmu_base_device::insn_data_w<sun4_mmu_base_device::SUPER_INSN>(const uint32_t, const uint32_t, const uint32_t); +template void sun4_mmu_base_device::insn_data_w<sun4_mmu_base_device::USER_DATA>(const uint32_t, const uint32_t, const uint32_t); +template void sun4_mmu_base_device::insn_data_w<sun4_mmu_base_device::SUPER_DATA>(const uint32_t, const uint32_t, const uint32_t); -template <sun4c_mmu_device::insn_data_mode MODE> -void sun4c_mmu_device::insn_data_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask) +template <sun4_mmu_base_device::insn_data_mode MODE> +void sun4_mmu_base_device::insn_data_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask) { // it's translation time const uint32_t pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff];// & m_pmeg_mask; - const uint32_t entry_index = pmeg | ((offset >> 10) & 0x3f); + const uint32_t entry_index = pmeg | ((offset >> m_seg_entry_shift) & m_seg_entry_mask); if (m_page_valid[entry_index]) { - page_entry_t &entry = m_pagemap[entry_index]; + page_entry &entry = m_pagemap[entry_index]; if ((!entry.writable) || (entry.supervisor && MODE != SUPER_DATA && MODE != SUPER_INSN)) { - LOGMASKED(LOG_WRITE_PROTECT, "write protect error with PTE %d (%08x), %08x = %08x & %08x, PC=%08x\n", entry_index, m_pagemap[entry_index].to_uint(), offset << 2, data, mem_mask, m_cpu->pc()); + LOGMASKED(LOG_WRITE_PROTECT, "write protect error with PTE %d (%08x), %08x = %08x & %08x, PC=%08x\n", entry_index, page_entry_to_uint(entry_index), offset << 2, data, mem_mask, m_cpu->pc()); m_buserr[0] |= 0x8040; // write, protection error m_buserr[1] = offset << 2; m_host->set_mae(); @@ -547,7 +581,7 @@ void sun4c_mmu_device::insn_data_w(const uint32_t offset, const uint32_t data, c entry.accessed = PM_ACCESSED; entry.modified = PM_MODIFIED; - const uint32_t tmp = entry.page | (offset & 0x3ff); + const uint32_t tmp = entry.page | (offset & m_page_mask); switch (entry.type) { @@ -579,7 +613,7 @@ void sun4c_mmu_device::insn_data_w(const uint32_t offset, const uint32_t data, c } else { - LOGMASKED(LOG_INVALID_PTE, "write invalid PTE %d (%08x), %08x = %08x & %08x, PC=%08x\n", entry_index, m_pagemap[entry_index].to_uint(), offset << 2, data, mem_mask, m_cpu->pc()); + LOGMASKED(LOG_INVALID_PTE, "write invalid PTE %d (%08x), %08x = %08x & %08x, PC=%08x\n", entry_index, page_entry_to_uint(entry_index), offset << 2, data, mem_mask, m_cpu->pc()); m_host->set_mae(); m_buserr[0] |= 0x8080; // write cycle, invalid PTE m_buserr[1] = offset << 2; @@ -601,3 +635,30 @@ void sun4c_mmu_device::insn_data_w(const uint32_t offset, const uint32_t data, c } } +void sun4_mmu_base_device::l2p_command(int ref, const std::vector<std::string> ¶ms) +{ + uint64_t addr, offset; + + if (!machine().debugger().commands().validate_number_parameter(params[0], addr)) return; + + addr &= 0xffffffff; + offset = addr >> 2; + + uint8_t pmeg = 0; + uint32_t entry_index = 0, tmp = 0; + uint32_t entry_value = 0; + + pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff]; + entry_index = pmeg | ((offset >> m_seg_entry_shift) & m_seg_entry_mask); + tmp = m_pagemap[entry_index].page | (offset & m_page_mask); + entry_value = page_entry_to_uint(entry_index); + + if (m_page_valid[entry_index]) + { + machine().debugger().console().printf("logical %08x => phys %08x, type %d (pmeg %d, entry %d PTE %08x)\n", addr, tmp << 2, m_pagemap[entry_index].type, pmeg, entry_index, entry_value); + } + else + { + machine().debugger().console().printf("logical %08x points to an invalid PTE! (pmeg %d, entry %d PTE %08x)\n", addr, tmp << 2, pmeg, entry_index, entry_value); + } +} diff --git a/src/devices/machine/sun4c_mmu.h b/src/devices/machine/sun4c_mmu.h index b97ec362181..f3567e7631d 100644 --- a/src/devices/machine/sun4c_mmu.h +++ b/src/devices/machine/sun4c_mmu.h @@ -2,31 +2,36 @@ // copyright-holders:Ryan Holtz /*************************************************************************** - sun4c_mmu.h - Sun 4c MMU emulation + sun4c_mmu.h - Sun 4/4c MMU emulation ***************************************************************************/ -#ifndef MAME_MACHINE_SUN4C_MMU_H -#define MAME_MACHINE_SUN4C_MMU_H - #pragma once +#ifndef DEVICE_MACHINE_SUN4C_MMU_H +#define DEVICE_MACHINE_SUN4C_MMU_H + #include "cpu/sparc/sparc_intf.h" #include "machine/ram.h" #include "machine/z80scc.h" -class sun4c_mmu_device : public device_t, public sparc_mmu_interface +class sun4_mmu_base_device : public device_t, public sparc_mmu_interface { public: - sun4c_mmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, uint8_t ctx_mask, uint8_t pmeg_mask) - : sun4c_mmu_device(mconfig, tag, owner, clock) + sun4_mmu_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock + , uint8_t ctx_mask, uint8_t pmeg_mask, uint32_t page_mask, uint32_t seg_entry_shift, uint32_t seg_entry_mask + , uint32_t page_entry_mask, uint32_t cache_mask) + : sun4_mmu_base_device(mconfig, type, tag, owner, clock) { set_ctx_mask(ctx_mask); set_pmeg_mask(pmeg_mask); + set_page_mask(page_mask); + set_seg_entry_shift(seg_entry_shift); + set_seg_entry_mask(seg_entry_mask); + set_page_entry_mask(page_entry_mask); + set_cache_mask(cache_mask); } - sun4c_mmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - template <typename T> void set_cpu(T &&cpu_tag) { m_cpu.set_tag(std::forward<T>(cpu_tag)); } template <typename T> void set_ram(T &&ram_tag) { m_ram.set_tag(std::forward<T>(ram_tag)); } template <typename T> void set_rom(T &&rom_tag) { m_rom.set_tag(std::forward<T>(rom_tag)); } @@ -37,6 +42,11 @@ public: void set_ctx_mask(uint8_t ctx_mask) { m_ctx_mask = ctx_mask; } void set_pmeg_mask(uint8_t pmeg_mask) { m_pmeg_mask = pmeg_mask; } + void set_page_mask(uint32_t page_mask) { m_page_mask = page_mask; } + void set_seg_entry_shift(uint32_t seg_entry_shift) { m_seg_entry_shift = seg_entry_shift; } + void set_seg_entry_mask(uint32_t seg_entry_mask) { m_seg_entry_mask = seg_entry_mask; } + void set_page_entry_mask(uint32_t page_entry_mask) { m_page_entry_mask = page_entry_mask; } + void set_cache_mask(uint32_t cache_mask) { m_cache_mask = cache_mask; } enum insn_data_mode { @@ -56,12 +66,17 @@ public: void set_host(sparc_mmu_host_interface *host) override { m_host = host; } protected: + sun4_mmu_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + static const device_timer_id TIMER_RESET = 0; virtual void device_start() override; virtual void device_reset() override; virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + uint32_t page_entry_to_uint(uint32_t index); + void merge_page_entry(uint32_t index, uint32_t data, uint32_t mem_mask); + uint32_t cache_flush_r(); void cache_flush_w(); uint32_t system_r(const uint32_t offset, const uint32_t mem_mask); @@ -72,6 +87,7 @@ protected: void page_map_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask); void type0_timeout_r(const uint32_t offset); void type0_timeout_w(const uint32_t offset); + void l2p_command(int ref, const std::vector<std::string> ¶ms); enum { @@ -92,7 +108,7 @@ protected: PM_MODIFIED = 0x01000000 // modified flag }; - struct page_entry_t + struct page_entry { uint32_t valid; uint32_t writable; @@ -103,9 +119,6 @@ protected: uint32_t page; uint8_t type; uint8_t pad[3]; - - uint32_t to_uint(); - void merge_uint(uint32_t data, uint32_t mem_mask); }; required_device<cpu_device> m_cpu; @@ -120,10 +133,10 @@ protected: devcb_write32 m_type1_w; // Actual SRAM - uint8_t m_segmap[16][4096]; - page_entry_t m_pagemap[16384]; - uint32_t m_cachetags[16384]; - uint32_t m_cachedata[16384]; + std::unique_ptr<std::unique_ptr<uint8_t[]>[]> m_segmap; + std::unique_ptr<page_entry[]> m_pagemap; + std::unique_ptr<uint32_t[]> m_cachetags; + std::unique_ptr<uint32_t[]> m_cachedata; uint32_t *m_rom_ptr; uint32_t *m_ram_ptr; @@ -137,21 +150,38 @@ protected: uint32_t m_buserr[4]; // Pre-computed data for optimization purposes - uint32_t m_segmap_masked[16][4096]; + std::unique_ptr<std::unique_ptr<uint32_t[]>[]> m_segmap_masked; uint8_t *m_curr_segmap; uint32_t *m_curr_segmap_masked; - bool m_page_valid[16384]; + std::unique_ptr<bool[]> m_page_valid; // Internal MAME device state uint8_t m_ctx_mask; // SS2 is sun4c but has 16 contexts; most have 8 uint8_t m_pmeg_mask; // SS2 is sun4c but has 16384 PTEs; most have 8192 + uint32_t m_page_mask; + uint32_t m_seg_entry_shift; + uint32_t m_seg_entry_mask; + uint32_t m_page_entry_mask; + uint32_t m_cache_mask; uint32_t m_ram_set_mask[4]; // Used for mirroring within 4 megabyte sets uint32_t m_ram_set_base[4]; uint32_t m_populated_ram_words; emu_timer *m_reset_timer; }; +class sun4_mmu_device : public sun4_mmu_base_device +{ +public: + sun4_mmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; + +class sun4c_mmu_device : public sun4_mmu_base_device +{ +public: + sun4c_mmu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); +}; +DECLARE_DEVICE_TYPE(SUN4_MMU, sun4_mmu_device) DECLARE_DEVICE_TYPE(SUN4C_MMU, sun4c_mmu_device) -#endif // MAME_MACHINE_SUN4C_MMU_H +#endif // DEVICE_MACHINE_SUN4C_MMU_H diff --git a/src/devices/video/bt45x.cpp b/src/devices/video/bt45x.cpp index 5760e01711f..5f7dc2ae2e3 100644 --- a/src/devices/video/bt45x.cpp +++ b/src/devices/video/bt45x.cpp @@ -36,8 +36,8 @@ #include "emu.h" #include "bt45x.h" -#define LOG_GENERAL (1U << 0) -#define LOG_READS (1U << 1) +#define LOG_READS (1U << 0) +#define LOG_WRITES (1U << 1) #define VERBOSE (0) @@ -180,7 +180,7 @@ void bt45x_device_base::device_reset() READ8_MEMBER(bt45x_device_base::address_r) { - LOGMASKED(LOG_READS, "address_r 0x%02x\n", m_address & (m_palette_colors - 1)); + LOGMASKED(LOG_READS, "%s: address_r 0x%02x\n", machine().describe_context(), m_address & (m_palette_colors - 1)); if (!machine().side_effects_disabled()) m_address_rgb = 0; @@ -190,7 +190,8 @@ READ8_MEMBER(bt45x_device_base::address_r) WRITE8_MEMBER(bt45x_device_base::address_w) { - LOG("address_w 0x%02x\n", data); + LOGMASKED(LOG_WRITES, "%s: address_w 0x%02x\n", machine().describe_context(), data); + m_address_rgb = 0; m_address = data & (m_palette_colors - 1); @@ -230,7 +231,7 @@ READ8_MEMBER(bt45x_rgb_device_base::palette_r) increment_address(); - LOGMASKED(LOG_READS, "palette_r 0x%02x\n", data & get_mask()); + LOGMASKED(LOG_READS, "%s: palette_r 0x%02x\n", machine().describe_context(), data & get_mask()); return data & get_mask(); } @@ -244,7 +245,7 @@ READ8_MEMBER(bt45x_mono_device_base::palette_r) increment_address(); - LOGMASKED(LOG_READS, "palette_r 0x%02x\n", data & get_mask()); + LOGMASKED(LOG_READS, "%s: palette_r 0x%02x\n", machine().describe_context(), data & get_mask()); return data & get_mask(); } @@ -259,14 +260,14 @@ READ8_MEMBER(bt457_device::palette_r) increment_address(); - LOGMASKED(LOG_READS, "palette_r 0x%02x\n", data); + LOGMASKED(LOG_READS, "%s: palette_r 0x%02x\n", machine().describe_context(), data); return data; } WRITE8_MEMBER(bt45x_rgb_device_base::palette_w) { - LOG("palette_w 0x%02x\n", data); + LOGMASKED(LOG_WRITES, "%s: palette_w 0x%02x\n", machine().describe_context(), data); m_color_ram[m_address][m_address_rgb] = data & get_mask(); @@ -279,7 +280,7 @@ WRITE8_MEMBER(bt45x_rgb_device_base::palette_w) WRITE8_MEMBER(bt45x_mono_device_base::palette_w) { - LOG("palette_w 0x%02x\n", data); + LOGMASKED(LOG_WRITES, "%s: palette_w 0x%02x\n", machine().describe_context(), data); if (m_address_rgb == 1) m_color_ram[m_address] = data & get_mask(); @@ -289,7 +290,7 @@ WRITE8_MEMBER(bt45x_mono_device_base::palette_w) WRITE8_MEMBER(bt457_device::palette_w) { - LOG("palette_w 0x%02x\n", data); + LOGMASKED(LOG_WRITES, "%s: palette_w 0x%02x\n", machine().describe_context(), data); // device in normal mode, or rgb mode and selected if (!(m_control & RGB) || (m_control & RGB) == (1 << m_address_rgb)) @@ -300,7 +301,7 @@ WRITE8_MEMBER(bt457_device::palette_w) READ8_MEMBER(bt45x_device_base::register_r) { - LOGMASKED(LOG_READS, "register_r 0x%02x\n", m_address); + LOGMASKED(LOG_READS, "%s: register_r 0x%02x\n", machine().describe_context(), m_address); switch (m_address) { @@ -318,17 +319,18 @@ WRITE8_MEMBER(bt45x_device_base::register_w) switch (m_address) { case REG_READ_MASK: - LOG("read mask 0x%02x\n", data); + LOGMASKED(LOG_WRITES, "%s: register_w: read mask 0x%02x\n", machine().describe_context(), data); m_read_mask = data; break; case REG_BLINK_MASK: - LOG("blink mask 0x%02x\n", data); + LOGMASKED(LOG_WRITES, "%s: register_w: blink mask 0x%02x\n", machine().describe_context(), data); m_blink_mask = data; break; case REG_COMMAND: - LOG("command 0x%02x, %d:1 multiplexing, use %s, %s, OL1 %s blinking, OL0 %s blinking, OL1 display %s, OL0 display %s\n", + LOGMASKED(LOG_WRITES, "%s: register_w: command 0x%02x, %d:1 multiplexing, use %s, %s, OL1 %s blinking, OL0 %s blinking, OL1 display %s, OL0 display %s\n", + machine().describe_context(), data, (data & CR7) ? 5 : 4, (data & CR6) ? "color palette RAM" : "overlay color 0", @@ -344,7 +346,7 @@ WRITE8_MEMBER(bt45x_device_base::register_w) break; case REG_CONTROL: - LOG("control 0x%02x, %s nibble%s%s%s\n", + LOGMASKED(LOG_WRITES, "%s: register_w: control 0x%02x, %s nibble%s%s%s\n", data, (data & D3) ? "low" : "high", (data & D2) ? ", blue channel enable" : "", @@ -367,7 +369,7 @@ READ8_MEMBER(bt45x_rgb_device_base::overlay_r) increment_address(); - LOGMASKED(LOG_READS, "overlay_r 0x%02x\n", data & get_mask()); + LOGMASKED(LOG_READS, "%s: overlay_r 0x%02x\n", machine().describe_context(), data & get_mask()); return data & get_mask(); } @@ -384,7 +386,7 @@ READ8_MEMBER(bt45x_mono_device_base::overlay_r) increment_address(); - LOGMASKED(LOG_READS, "overlay_r 0x%02x\n", data & get_mask()); + LOGMASKED(LOG_READS, "%s: overlay_r 0x%02x\n", machine().describe_context(), data & get_mask()); return data & get_mask(); } @@ -402,14 +404,14 @@ READ8_MEMBER(bt457_device::overlay_r) increment_address(); - LOGMASKED(LOG_READS, "overlay_r 0x%02x\n", data); + LOGMASKED(LOG_READS, "%s: overlay_r 0x%02x\n", machine().describe_context(), data); return data; } WRITE8_MEMBER(bt45x_rgb_device_base::overlay_w) { - LOG("overlay_w 0x%02x\n", data); + LOGMASKED(LOG_WRITES, "%s: overlay_w 0x%02x\n", machine().describe_context(), data); // address is ignored for 1 bit overlay devices const u8 address = (m_overlay_colors == 1) ? 0 : m_address; @@ -431,7 +433,7 @@ WRITE8_MEMBER(bt45x_rgb_device_base::overlay_w) WRITE8_MEMBER(bt45x_mono_device_base::overlay_w) { - LOG("overlay_w 0x%02x\n", data); + LOGMASKED(LOG_WRITES, "%s: overlay_w 0x%02x\n", machine().describe_context(), data); // address is ignored for 1 bit overlay devices const u8 address = (m_overlay_colors == 1) ? 0 : m_address; @@ -444,7 +446,7 @@ WRITE8_MEMBER(bt45x_mono_device_base::overlay_w) WRITE8_MEMBER(bt457_device::overlay_w) { - LOG("overlay_w 0x%02x\n", data); + LOGMASKED(LOG_WRITES, "%s: overlay_w 0x%02x\n", machine().describe_context(), data); if (m_address < m_overlay_colors) { diff --git a/src/mame/drivers/sun4.cpp b/src/mame/drivers/sun4.cpp index 0c5fabe29c5..83c85edc821 100644 --- a/src/mame/drivers/sun4.cpp +++ b/src/mame/drivers/sun4.cpp @@ -519,17 +519,10 @@ const sparc_disassembler::asi_desc_map::value_type sun4c_asi_desc[] = { }; } -enum -{ - ARCH_SUN4 = 0, - ARCH_SUN4C, - ARCH_SUN4E -}; - -class sun4_state : public driver_device +class sun4_base_state : public driver_device { public: - sun4_state(const machine_config &mconfig, device_type type, const char *tag) + sun4_base_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_mmu(*this, "mmu") @@ -541,87 +534,26 @@ public: , m_lance(*this, LANCE_TAG) , m_scsibus(*this, "scsibus") , m_scsi(*this, "scsibus:7:ncr53c90a") - , m_sbus(*this, "sbus") - , m_sbus_slot(*this, "slot%u", 1U) - , m_type0space(*this, "type0") , m_type1space(*this, "type1") , m_ram(*this, RAM_TAG) , m_rom(*this, "user1") - , m_rom_ptr(nullptr) { } - void sun4c(machine_config &config); - void sun4_20(machine_config &config); - void sun4_40(machine_config &config); - void sun4_50(machine_config &config); - void sun4_60(machine_config &config); - void sun4_65(machine_config &config); - void sun4_75(machine_config &config); - void sun4(machine_config &config); - - void init_sun4(); - void init_sun4c(); + void sun4_base(machine_config &config); -private: +protected: virtual void machine_reset() override; virtual void machine_start() override; virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; static const device_timer_id TIMER_0 = 0; static const device_timer_id TIMER_1 = 1; - static const device_timer_id TIMER_RESET = 2; - enum insn_data_mode - { - USER_INSN, - SUPER_INSN, - USER_DATA, - SUPER_DATA - }; + DECLARE_READ32_MEMBER( debugger_r ); + DECLARE_WRITE32_MEMBER( debugger_w ); - enum - { - // system enable constants - ENA_NOTBOOT = 0x80, - ENA_SDVMA = 0x20, - ENA_CACHE = 0x10, - ENA_RESET = 0x04, - ENA_DIAG = 0x01, - - // page table entry constants - PM_VALID = 0x80000000, // page is valid - PM_WRITEMASK = 0x40000000, // writable? - PM_SYSMASK = 0x20000000, // system use only? - PM_CACHE = 0x10000000, // cachable? - PM_TYPEMASK = 0x0c000000, // type mask - PM_ACCESSED = 0x02000000, // accessed flag - PM_MODIFIED = 0x01000000 // modified flag - }; - - DECLARE_READ32_MEMBER( sun4_cache_flush_r ); - DECLARE_WRITE32_MEMBER( sun4_cache_flush_w ); - DECLARE_READ32_MEMBER( sun4_system_r ); - DECLARE_WRITE32_MEMBER( sun4_system_w ); - DECLARE_READ32_MEMBER( sun4_segment_map_r ); - DECLARE_WRITE32_MEMBER( sun4_segment_map_w ); - DECLARE_READ32_MEMBER( sun4_page_map_r ); - DECLARE_WRITE32_MEMBER( sun4_page_map_w ); - template <insn_data_mode MODE> DECLARE_READ32_MEMBER( sun4_insn_data_r ); - DECLARE_WRITE32_MEMBER( sun4_insn_data_w ); - - DECLARE_READ32_MEMBER( sun4c_debugger_r ); - DECLARE_WRITE32_MEMBER( sun4c_debugger_w ); - - DECLARE_READ32_MEMBER( sun4_mmu_r ); - DECLARE_WRITE32_MEMBER( sun4_mmu_w ); - DECLARE_READ32_MEMBER( sun4c_mmu_r ); - DECLARE_WRITE32_MEMBER( sun4c_mmu_w ); - DECLARE_READ32_MEMBER( ram_r ); - DECLARE_WRITE32_MEMBER( ram_w ); - DECLARE_READ32_MEMBER( timeout_r ); - DECLARE_WRITE32_MEMBER( timeout_w ); - DECLARE_READ32_MEMBER( ss1_sl0_id ); + DECLARE_READ32_MEMBER( sl0_id ); DECLARE_READ32_MEMBER( timer_r ); DECLARE_WRITE32_MEMBER( timer_w ); DECLARE_READ8_MEMBER( irq_r ); @@ -632,7 +564,6 @@ private: DECLARE_WRITE8_MEMBER( auxio_w ); DECLARE_READ32_MEMBER( dma_r ); DECLARE_WRITE32_MEMBER( dma_w ); - DECLARE_WRITE32_MEMBER( buserr_w ); DECLARE_WRITE_LINE_MEMBER( scsi_irq ); DECLARE_WRITE_LINE_MEMBER( scsi_drq ); @@ -646,29 +577,12 @@ private: void ncr53c90a(device_t *device); - void sun4_system_map(address_map &map); - void sun4_segment_map(address_map &map); - void sun4_page_map(address_map &map); - void sun4_insn_map(address_map &map); - void sun4_supervisor_insn_map(address_map &map); - void sun4_data_map(address_map &map); - void sun4_supervisor_data_map(address_map &map); - - void sun4c_debugger_map(address_map &map); + void debugger_map(address_map &map); - void type0space_map(address_map &map); - void type1space_map(address_map &map); - void type1space_sbus_map(address_map &map); - void type1space_s4_map(address_map &map); - - enum sun4_arch - { - SUN4 = 0, - SUN4C = 1 - }; + void type1space_base_map(address_map &map); - required_device<mb86901_device> m_maincpu; - required_device<sun4c_mmu_device> m_mmu; + required_device<sparc_base_device> m_maincpu; + required_device<sun4_mmu_base_device> m_mmu; required_device<m48t02_device> m_timekpr; @@ -681,65 +595,11 @@ private: required_device<nscsi_bus_device> m_scsibus; required_device<ncr53c90a_device> m_scsi; - optional_device<sbus_device> m_sbus; - optional_device_array<sbus_slot_device, 3> m_sbus_slot; - optional_device<address_map_bank_device> m_type0space; - optional_device<address_map_bank_device> m_type1space; + required_device<address_map_bank_device> m_type1space; memory_access_cache<2, 0, ENDIANNESS_BIG> *m_type1_cache; required_device<ram_device> m_ram; required_memory_region m_rom; - struct page_entry_t - { - uint32_t valid; - uint32_t writable; - uint32_t supervisor; - uint32_t uncached; - uint32_t accessed; - uint32_t modified; - uint32_t page; - uint8_t type; - uint8_t pad[3]; - - uint32_t to_uint() - { - return valid | writable | supervisor | uncached | (type << 26) | accessed | modified | (page >> 11); - } - - void merge_uint(uint32_t data, uint32_t mem_mask) - { - const uint32_t new_value = (to_uint() & ~mem_mask) | (data & mem_mask); - valid = new_value & PM_VALID; - writable = new_value & PM_WRITEMASK; - supervisor = new_value & PM_SYSMASK; - uncached = new_value & PM_CACHE; - type = (new_value & PM_TYPEMASK) >> 26; - accessed = new_value & PM_ACCESSED; - modified = new_value & PM_MODIFIED; - page = (new_value & 0x7ffff) << 11; - } - }; - - uint8_t m_segmap[16][4096]; - page_entry_t m_pagemap[16384]; - uint32_t m_cachetags[16384]; - uint32_t m_cachedata[16384]; - - uint32_t *m_rom_ptr; - uint32_t *m_ram_ptr; - uint32_t m_ram_size; - uint32_t m_ram_size_words; - uint32_t m_context; - uint32_t m_context_masked; - uint8_t m_system_enable; - bool m_fetch_bootrom; - uint32_t m_buserr[4]; - - uint32_t m_segmap_masked[16][4096]; - uint8_t *m_curr_segmap; - uint32_t *m_curr_segmap_masked; - bool m_page_valid[16384]; - uint8_t m_auxio; uint32_t m_counter[4]; uint32_t m_dma[4]; @@ -751,331 +611,75 @@ private: uint8_t m_irq_reg; // IRQ control uint8_t m_scc1_int, m_scc2_int; - uint8_t m_diag; - int m_arch; attotime m_c0_last_read_time; attotime m_c1_last_read_time; emu_timer *m_c0_timer; emu_timer *m_c1_timer; - emu_timer *m_reset_timer; void dma_check_interrupts(); void dma_transfer(); void dma_transfer_write(); void dma_transfer_read(); - void l2p_command(int ref, const std::vector<std::string> ¶ms); void fcodes_command(int ref, const std::vector<std::string> ¶ms); }; -READ32_MEMBER( sun4_state::sun4_system_r ) -{ - switch (offset >> 26) - { - case 3: // context reg - if (mem_mask == 0x00ff0000) return m_context<<16; - return m_context<<24; - - case 4: // system enable reg - return m_system_enable<<24; - - case 6: // bus error register - //printf("sun4: read buserror, PC=%x (mask %08x)\n", m_maincpu->pc(), mem_mask); - return 0; - - case 8: // (d-)cache tags - //logerror("sun4: read dcache tags @ %x, PC = %x\n", offset, m_maincpu->pc()); - return m_cachetags[offset&0xfff]; - - case 9: // (d-)cache data - //logerror("sun4: read dcache data @ %x, PC = %x\n", offset, m_maincpu->pc()); - return 0xffffffff; - - case 0xf: // UART bypass - //printf("read UART bypass @ %x mask %08x (PC=%x)\n", offset<<2, mem_mask, m_maincpu->pc()); - switch (offset & 3) - { - case 0: if (mem_mask == 0xff000000) return m_scc2->cb_r(offset)<<24; else return m_scc2->db_r(offset)<<8; break; - case 1: if (mem_mask == 0xff000000) return m_scc2->ca_r(offset)<<24; else return m_scc2->da_r(offset)<<8; break; - } - return 0xffffffff; - - case 0: - default: - //logerror("sun4: ASI 2 space unhandled read @ %x (PC=%x)\n", offset<<2, m_maincpu->pc()); - return 0; - } -} - -WRITE32_MEMBER( sun4_state::sun4_system_w ) +class sun4_state : public sun4_base_state { - switch (offset >> 26) +public: + sun4_state(const machine_config &mconfig, device_type type, const char *tag) + : sun4_base_state(mconfig, type, tag) { - case 3: // context reg - //printf("%08x to context, mask %08x, offset %x\n", data, mem_mask, offset); - m_context = data>>24; - return; - - case 4: // system enable reg - m_system_enable = data>>24; - - if (m_system_enable & ENA_RESET) - { - m_reset_timer->adjust(attotime::from_usec(1), 0); - m_maincpu->set_input_line(SPARC_RESET, ASSERT_LINE); - //logerror("%s: Asserting reset line\n", machine().describe_context()); - } - //printf("%08x to system enable, mask %08x\n", data, mem_mask); - if (m_system_enable & ENA_RESET) - { - m_system_enable = 0; - m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); - m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); - } - return; - - case 7: // diag reg - m_diag = data >> 24; - #if 1 - printf("sun4: CPU LEDs to %02x (PC=%x) => ", ((data>>24) & 0xff) ^ 0xff, m_maincpu->pc()); - for (int i = 0; i < 8; i++) - { - if (m_diag & (1<<i)) - { - printf("."); - } - else - { - printf("*"); - } - } - printf("\n"); - #endif - return; - - case 8: // cache tags - //logerror("sun4: %08x to cache tags @ %x, PC = %x\n", data, offset, m_maincpu->pc()); - m_cachetags[offset&0xfff] = data; - return; - - case 9: // cache data - //logerror("sun4: %08x to cache data @ %x, PC = %x\n", data, offset, m_maincpu->pc()); - return; - - case 0xf: // UART bypass - //printf("%08x to UART bypass @ %x, mask %08x\n", data, offset<<2, mem_mask); - switch (offset & 3) - { - case 0: if (mem_mask == 0xff000000) m_scc2->cb_w(offset, data>>24); else m_scc2->db_w(offset, data>>8); break; - case 1: if (mem_mask == 0xff000000) m_scc2->ca_w(offset, data>>24); else { m_scc2->da_w(offset, data>>8); printf("%c", data>>8); } break; - } - return; - - case 0: // IDPROM - default: - //logerror("sun4: ASI 2 space unhandled write %x @ %x (mask %08x, PC=%x)\n", data, offset<<2, mem_mask, m_maincpu->pc()); - return; } -} -READ32_MEMBER( sun4_state::sun4_segment_map_r ) -{ - //printf("sun4: read segment map @ %x (ctx %d entry %d, mem_mask %08x, PC=%x)\n", offset << 2, m_context, (offset>>16) & 0xfff, mem_mask, m_maincpu->pc()); - if (mem_mask == 0xffff0000) - return m_curr_segmap[(offset>>16) & 0xfff]<<16; - else if (mem_mask == 0xff000000) - return m_curr_segmap[(offset>>16) & 0xfff]<<24; - else if (mem_mask == 0xffffffff) - return m_curr_segmap[(offset>>16) & 0xfff]; - else - logerror("sun4: read segment map w/ unknown mask %08x\n", mem_mask); - return 0x0; -} - -WRITE32_MEMBER( sun4_state::sun4_segment_map_w ) -{ - uint8_t segdata = 0; - //printf("segment write, mask %08x, PC=%x\n", mem_mask, m_maincpu->pc()); - if (mem_mask == 0xffff0000) segdata = (data >> 16) & 0xff; - else if (mem_mask == 0xff000000) segdata = (data >> 24) & 0xff; - else logerror("sun4: writing segment map with unknown mask %08x, PC=%x\n", mem_mask, m_maincpu->pc()); - - //printf("sun4: %08x to segment map @ %x (ctx %d entry %d, mem_mask %08x, PC=%x)\n", segdata, offset << 2, m_context, (offset>>16) & 0xfff, mem_mask, m_maincpu->pc()); - m_curr_segmap[(offset>>16) & 0xfff] = segdata; - m_curr_segmap_masked[(offset>>16) & 0xfff] = segdata << 5; -} - -READ32_MEMBER( sun4_state::sun4_page_map_r ) -{ - uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> 11) & 0x1f); - //printf("sun4: read page map @ %x (entry %d, seg %d, PMEG %d, mem_mask %08x, PC=%x)\n", offset << 2, page, (offset >> 16) & 0xfff, m_segmap[m_context][(offset >> 16) & 0xfff] & m_pmeg_mask, mem_mask, m_maincpu->pc()); - return m_pagemap[page].to_uint(); -} - -WRITE32_MEMBER( sun4_state::sun4_page_map_w ) -{ - const uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> 11) & 0x1f); - //printf("sun4: %08x to page map @ %x (entry %d, mem_mask %08x, PC=%x)\n", data, offset << 2, page, mem_mask, m_maincpu->pc()); - m_pagemap[page].merge_uint(data, mem_mask); - m_page_valid[page] = m_pagemap[page].valid; -} - -READ32_MEMBER( sun4_state::sun4c_debugger_r ) -{ - return m_mmu->insn_data_r<sun4c_mmu_device::SUPER_INSN>(offset, mem_mask); -} + void sun4(machine_config &config); -WRITE32_MEMBER( sun4_state::sun4c_debugger_w ) -{ - m_mmu->insn_data_w<sun4c_mmu_device::SUPER_INSN>(offset, data, mem_mask); -} +private: + void type1space_map(address_map &map); +}; -template <sun4_state::insn_data_mode MODE> -READ32_MEMBER( sun4_state::sun4_insn_data_r ) +class sun4c_state : public sun4_base_state { - // supervisor program fetches in boot state are special - if (m_fetch_bootrom && MODE == SUPER_INSN) +public: + sun4c_state(const machine_config &mconfig, device_type type, const char *tag) + : sun4_base_state(mconfig, type, tag) + , m_sbus(*this, "sbus") + , m_sbus_slot(*this, "slot%u", 1U) { - return m_rom_ptr[offset & 0x1ffff]; } - // it's translation time - const uint32_t pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff]; - const uint32_t entry_index = pmeg | ((offset >> 11) & 0x1f); - - if (m_page_valid[entry_index]) - { - page_entry_t &entry = m_pagemap[entry_index]; - entry.accessed = PM_ACCESSED; - - const uint32_t tmp = entry.page | (offset & 0x7ff); + void sun4c(machine_config &config); + void sun4_20(machine_config &config); + void sun4_40(machine_config &config); + void sun4_50(machine_config &config); + void sun4_60(machine_config &config); + void sun4_65(machine_config &config); + void sun4_75(machine_config &config); - //printf("sun4: read translated vaddr %08x to phys %08x type %d, PTE %08x, PC=%x\n", offset<<2, tmp<<2, entry.type, entry.to_uint(), m_maincpu->pc()); +private: + virtual void machine_start() override; + virtual void machine_reset() override; - switch (entry.type) - { - case 0: // type 0 space - return m_type0space->read32(tmp, mem_mask); + template <int Line> DECLARE_WRITE_LINE_MEMBER(sbus_irq_w); - case 1: // type 1 space - // magic EPROM bypass - if ((tmp >= (0x6000000>>2)) && (tmp <= (0x6ffffff>>2))) - { - return m_rom_ptr[offset & 0x1ffff]; - } - //printf("Read type 1 @ VA %08x, phys %08x\n", offset<<2, tmp<<2); - return m_type1space->read32(tmp, mem_mask); + void type1space_map(address_map &map); - default: - //logerror("sun4: access to unhandled memory type\n"); - return 0; - } - } - else - { - if (!machine().side_effects_disabled()) - { - //logerror("sun4: INVALID PTE entry %d %08x accessed! vaddr=%x PC=%x\n", entry_index, m_pagemap[entry_index].to_uint(), offset <<2, m_maincpu->pc()); - m_maincpu->set_mae(); - m_buserr[0] |= 0x80; // invalid PTE - m_buserr[0] &= ~0x8000; // read - m_buserr[1] = offset<<2; - if (mem_mask != ~0 && mem_mask != 0xffff0000 && mem_mask != 0xff000000) - { - if (mem_mask == 0x0000ffff || mem_mask == 0x0000ff00) - { - m_buserr[1] |= 2; - } - else if (mem_mask == 0x00ff0000) - { - m_buserr[1] |= 1; - } - else if (mem_mask == 0x000000ff) - { - m_buserr[1] |= 3; - } - } - } - return 0; - } -} + required_device<sbus_device> m_sbus; + required_device_array<sbus_slot_device, 3> m_sbus_slot; +}; -WRITE32_MEMBER( sun4_state::sun4_insn_data_w ) +READ32_MEMBER( sun4_base_state::debugger_r ) { - // it's translation time - const uint32_t pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff]; - const uint32_t entry_index = pmeg | ((offset >> 11) & 0x1f); - - if (m_page_valid[entry_index]) - { - page_entry_t &entry = m_pagemap[entry_index]; - entry.accessed = PM_ACCESSED; - - uint32_t tmp = entry.page | (offset & 0x7ff); - - //printf("sun4: write translated vaddr %08x to phys %08x type %d, PTE %08x, PC=%x\n", offset<<2, tmp<<2, entry.type, entry.to_uint(), m_maincpu->pc()); - - switch (entry.type) - { - case 0: // type 0 - m_type0space->write32(tmp, data, mem_mask); - return; - - case 1: // type 1 - //printf("write device space @ %x\n", tmp<<1); - m_type1space->write32(tmp, data, mem_mask); - return; - - default: - //logerror("sun4: access to memory type not defined in sun4\n"); - return; - } - } - else - { - //logerror("sun4: INVALID PTE entry %d %08x accessed! data=%08x vaddr=%x PC=%x\n", entry_index, m_pagemap[entry_index].to_uint(), data, offset <<2, m_maincpu->pc()); - //m_maincpu->trap(SPARC_DATA_ACCESS_EXCEPTION); - //m_buserr[0] = 0x8; // invalid PTE - //m_buserr[1] = offset<<2; - } + return m_mmu->insn_data_r<sun4_mmu_base_device::SUPER_INSN>(offset, mem_mask); } -// make debugger fetches emulate supervisor program for best compatibility with boot PROM execution -//if (machine().side_effects_disabled()) asi = 9; - -void sun4_state::l2p_command(int ref, const std::vector<std::string> ¶ms) +WRITE32_MEMBER( sun4_base_state::debugger_w ) { - uint64_t addr, offset; - - if (!machine().debugger().commands().validate_number_parameter(params[0], addr)) return; - - addr &= 0xffffffff; - offset = addr >> 2; - - uint8_t pmeg = 0; - uint32_t entry_index = 0, tmp = 0; - uint32_t entry_value = 0; - - if (m_arch == ARCH_SUN4) - { - pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff]; - entry_index = pmeg | ((offset >> 11) & 0x1f); - tmp = m_pagemap[entry_index].page | (offset & 0x7ff); - entry_value = m_pagemap[entry_index].to_uint(); - } - - if (m_page_valid[entry_index]) - { - machine().debugger().console().printf("logical %08x => phys %08x, type %d (pmeg %d, entry %d PTE %08x)\n", addr, tmp << 2, m_pagemap[entry_index].type, pmeg, entry_index, entry_value); - } - else - { - machine().debugger().console().printf("logical %08x points to an invalid PTE! (pmeg %d, entry %d PTE %08x)\n", addr, tmp << 2, pmeg, entry_index, entry_value); - } + m_mmu->insn_data_w<sun4_mmu_base_device::SUPER_INSN>(offset, data, mem_mask); } -void sun4_state::fcodes_command(int ref, const std::vector<std::string> ¶ms) +void sun4_base_state::fcodes_command(int ref, const std::vector<std::string> ¶ms) { #if SUN4_LOG_FCODES if (params < 1) @@ -1096,118 +700,51 @@ void sun4_state::fcodes_command(int ref, const std::vector<std::string> ¶ms) #endif } -void sun4_state::sun4_system_map(address_map &map) -{ - map(0x00000000, 0xffffffff).rw(FUNC(sun4_state::sun4_system_r), FUNC(sun4_state::sun4_system_w)); -} - -void sun4_state::sun4_segment_map(address_map &map) -{ - map(0x00000000, 0xffffffff).rw(FUNC(sun4_state::sun4_segment_map_r), FUNC(sun4_state::sun4_segment_map_w)); -} - -void sun4_state::sun4_page_map(address_map &map) -{ - map(0x00000000, 0xffffffff).rw(FUNC(sun4_state::sun4_page_map_r), FUNC(sun4_state::sun4_page_map_w)); -} - -void sun4_state::sun4_supervisor_insn_map(address_map &map) -{ - map(0x00000000, 0xffffffff).rw(FUNC(sun4_state::sun4_insn_data_r<SUPER_INSN>), FUNC(sun4_state::sun4_insn_data_w)); -} - -void sun4_state::sun4_supervisor_data_map(address_map &map) -{ - map(0x00000000, 0xffffffff).rw(FUNC(sun4_state::sun4_insn_data_r<SUPER_DATA>), FUNC(sun4_state::sun4_insn_data_w)); -} - -void sun4_state::sun4_insn_map(address_map &map) -{ - map(0x00000000, 0xffffffff).rw(FUNC(sun4_state::sun4_insn_data_r<USER_INSN>), FUNC(sun4_state::sun4_insn_data_w)); -} - -void sun4_state::sun4_data_map(address_map &map) -{ - map(0x00000000, 0xffffffff).rw(FUNC(sun4_state::sun4_insn_data_r<USER_DATA>), FUNC(sun4_state::sun4_insn_data_w)); -} - -void sun4_state::sun4c_debugger_map(address_map &map) -{ - map(0x00000000, 0xffffffff).rw(FUNC(sun4_state::sun4c_debugger_r), FUNC(sun4_state::sun4c_debugger_w)); -} +// make debugger fetches emulate supervisor program for best compatibility with boot PROM execution -void sun4_state::type0space_map(address_map &map) +void sun4_base_state::debugger_map(address_map &map) { - map.unmap_value_high(); - map(0x00000000, 0x00ffffff).rw(FUNC(sun4_state::ram_r), FUNC(sun4_state::ram_w)); - map(0x04000000, 0x0fffffff).rw(FUNC(sun4_state::timeout_r), FUNC(sun4_state::timeout_w)); + map(0x00000000, 0xffffffff).rw(FUNC(sun4_base_state::debugger_r), FUNC(sun4_base_state::debugger_w)); } -void sun4_state::type1space_map(address_map &map) +void sun4_base_state::type1space_base_map(address_map &map) { map(0x00000000, 0x0000000f).rw(m_scc1, FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask32(0xff00ff00); map(0x01000000, 0x0100000f).rw(m_scc2, FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask32(0xff00ff00); map(0x02000000, 0x020007ff).rw(m_timekpr, FUNC(timekeeper_device::read), FUNC(timekeeper_device::write)); - map(0x03000000, 0x0300000f).rw(FUNC(sun4_state::timer_r), FUNC(sun4_state::timer_w)).mirror(0xfffff0); - map(0x05000000, 0x05000003).rw(FUNC(sun4_state::irq_r), FUNC(sun4_state::irq_w)); + map(0x03000000, 0x0300000f).rw(FUNC(sun4_base_state::timer_r), FUNC(sun4_base_state::timer_w)).mirror(0xfffff0); + map(0x05000000, 0x05000003).rw(FUNC(sun4_base_state::irq_r), FUNC(sun4_base_state::irq_w)); map(0x06000000, 0x0607ffff).rom().region("user1", 0); - map(0x07200000, 0x07200007).rw(FUNC(sun4_state::fdc_r), FUNC(sun4_state::fdc_w)); - map(0x07400003, 0x07400003).rw(FUNC(sun4_state::auxio_r), FUNC(sun4_state::auxio_w)); - map(0x08000000, 0x08000003).r(FUNC(sun4_state::ss1_sl0_id)); // slot 0 contains SCSI/DMA/Ethernet - map(0x08400000, 0x0840000f).rw(FUNC(sun4_state::dma_r), FUNC(sun4_state::dma_w)); + map(0x07200000, 0x07200007).rw(FUNC(sun4_base_state::fdc_r), FUNC(sun4_base_state::fdc_w)); + map(0x07400003, 0x07400003).rw(FUNC(sun4_base_state::auxio_r), FUNC(sun4_base_state::auxio_w)); + map(0x08000000, 0x08000003).r(FUNC(sun4_base_state::sl0_id)); // internal slot 0 contains SCSI/DMA/Ethernet + map(0x08400000, 0x0840000f).rw(FUNC(sun4_base_state::dma_r), FUNC(sun4_base_state::dma_w)); map(0x08800000, 0x0880002f).m(m_scsi, FUNC(ncr53c90a_device::map)).umask32(0xff000000); map(0x08c00000, 0x08c00003).rw(m_lance, FUNC(am79c90_device::regs_r), FUNC(am79c90_device::regs_w)); } -void sun4_state::type1space_sbus_map(address_map &map) +void sun4c_state::type1space_map(address_map &map) { - type1space_map(map); + type1space_base_map(map); map(0x0a000000, 0x0fffffff).rw(m_sbus, FUNC(sbus_device::read), FUNC(sbus_device::write)); } -void sun4_state::type1space_s4_map(address_map &map) +void sun4_state::type1space_map(address_map &map) { - map(0x00000000, 0x0000000f).rw(m_scc1, FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask32(0xff00ff00); - map(0x01000000, 0x0100000f).rw(m_scc2, FUNC(z80scc_device::ab_dc_r), FUNC(z80scc_device::ab_dc_w)).umask32(0xff00ff00); + type1space_base_map(map); } /* Input ports */ static INPUT_PORTS_START( sun4 ) INPUT_PORTS_END -void sun4_state::machine_reset() +void sun4_base_state::machine_start() { - m_auxio = 0xc0; - m_irq_reg = 0; - m_scc1_int = m_scc2_int = 0; - m_scsi_irq = 0; - m_fdc_irq = 0; - m_dma_irq = false; - m_dma_tc_read = false; - m_dma_pack_register = 0; - - m_c0_last_read_time = attotime::zero; - m_c1_last_read_time = attotime::zero; - m_counter[0] = 1 << 10; - m_counter[2] = 1 << 10; - - memset(m_counter, 0, sizeof(m_counter)); - memset(m_dma, 0, sizeof(m_dma)); -} - -void sun4_state::machine_start() -{ - m_rom_ptr = (uint32_t *)m_rom->base(); - m_ram_ptr = (uint32_t *)m_ram->pointer(); - m_ram_size = m_ram->size(); - m_ram_size_words = m_ram_size >> 2; - if (machine().debug_flags & DEBUG_FLAG_ENABLED) { using namespace std::placeholders; - machine().debugger().console().register_command("l2p", CMDFLAG_NONE, 0, 1, 1, std::bind(&sun4_state::l2p_command, this, _1, _2)); #if SUN4_LOG_FCODES - machine().debugger().console().register_command("fcodes", CMDFLAG_NONE, 0, 1, 1, std::bind(&sun4_state::fcodes_command, this, _1, _2)); + machine().debugger().console().register_command("fcodes", CMDFLAG_NONE, 0, 1, 1, std::bind(&sun4_base_state::fcodes_command, this, _1, _2)); #endif } @@ -1217,39 +754,6 @@ void sun4_state::machine_start() m_c0_timer->adjust(attotime::from_usec(1), 0, attotime::from_usec(1)); m_c1_timer->adjust(attotime::from_usec(1), 0, attotime::from_usec(1)); - // allocate timer for system reset - m_reset_timer = timer_alloc(TIMER_RESET); - m_reset_timer->adjust(attotime::never); - - for (int i = 0; i < 16; i++) - { - save_item(NAME(m_segmap[i]), i); - save_item(NAME(m_segmap_masked[i]), i); - } - - for (int i = 0; i < 16384; i++) - { - save_item(NAME(m_pagemap[i].valid), i); - save_item(NAME(m_pagemap[i].writable), i); - save_item(NAME(m_pagemap[i].supervisor), i); - save_item(NAME(m_pagemap[i].uncached), i); - save_item(NAME(m_pagemap[i].accessed), i); - save_item(NAME(m_pagemap[i].modified), i); - save_item(NAME(m_pagemap[i].page), i); - save_item(NAME(m_pagemap[i].type), i); - } - - save_item(NAME(m_cachetags)); - save_item(NAME(m_cachedata)); - save_item(NAME(m_ram_size)); - save_item(NAME(m_ram_size_words)); - save_item(NAME(m_context)); - save_item(NAME(m_context_masked)); - save_item(NAME(m_system_enable)); - save_item(NAME(m_fetch_bootrom)); - save_item(NAME(m_buserr)); - save_item(NAME(m_page_valid)); - save_item(NAME(m_auxio)); save_item(NAME(m_counter)); save_item(NAME(m_dma)); @@ -1262,93 +766,39 @@ void sun4_state::machine_start() save_item(NAME(m_irq_reg)); save_item(NAME(m_scc1_int)); save_item(NAME(m_scc2_int)); - save_item(NAME(m_diag)); - save_item(NAME(m_arch)); } -READ32_MEMBER( sun4_state::ram_r ) +void sun4c_state::machine_start() { - return m_ram_ptr[offset]; + sun4_base_state::machine_start(); } -WRITE32_MEMBER( sun4_state::ram_w ) +void sun4_base_state::machine_reset() { -#if 0 - // if writing bad parity is enabled - if (((m_parregs[0] & 0x20000000) == 0x20000000) && - (m_irqctrl & 0x01000000) && - !(m_bInBusErr)) - { - m_parregs[1] = offset<<2; - //printf("Generating parity error, mem_mask %08x\n", mem_mask); - switch (mem_mask) - { - case 0xff000000: - m_parregs[0] |= 0x08<<24; - break; - - case 0x00ff0000: - m_parregs[1] += 1; - m_parregs[0] |= 0x04<<24; - break; - - case 0x0000ff00: - m_parregs[1] += 2; - m_parregs[0] |= 0x02<<24; - break; - - case 0x000000ff: - m_parregs[1] += 3; - m_parregs[0] |= 0x01<<24; - break; - - case 0x0000ffff: - m_parregs[1] += 2; - m_parregs[0] |= 0x03<<24; - break; - - case 0xffff0000: - m_parregs[0] |= 0x0c<<24; - break; - - case 0xffffffff: // no address adjust, show all 4 lanes as problematic - m_parregs[0] |= 0x0f<<24; - break; - } - - // indicate parity interrupt - m_parregs[0] |= 0x80000000; - - // and can we take that now? - if (m_parregs[0] & 0x40000000) - { - } - } -#endif - - //printf("ram_w: %08x to %08x (mask %08x)\n", data, offset<<2, mem_mask); - - //if ((offset<<2) == 0xfb2000) printf("write %08x to %08x, mask %08x, PC=%x\n", data, offset<<2, mem_mask, m_maincpu->pc()); + m_auxio = 0xc0; + m_irq_reg = 0; + m_scc1_int = m_scc2_int = 0; + m_scsi_irq = 0; + m_fdc_irq = 0; + m_dma_irq = false; + m_dma_tc_read = false; + m_dma_pack_register = 0; - COMBINE_DATA(&m_ram_ptr[offset]); -} + m_c0_last_read_time = attotime::zero; + m_c1_last_read_time = attotime::zero; + m_counter[0] = 1 << 10; + m_counter[2] = 1 << 10; -READ32_MEMBER( sun4_state::timeout_r ) -{ - m_buserr[0] = 0x20; // read timeout - m_buserr[1] = 0x04000000 + (offset << 2); - m_maincpu->set_mae(); - return 0; + memset(m_counter, 0, sizeof(m_counter)); + memset(m_dma, 0, sizeof(m_dma)); } -WRITE32_MEMBER( sun4_state::timeout_w ) +void sun4c_state::machine_reset() { - m_buserr[0] = 0x8020; // write timeout - m_buserr[1] = 0x04000000 + (offset << 2); - m_maincpu->set_mae(); + sun4_base_state::machine_reset(); } -READ8_MEMBER( sun4_state::fdc_r ) +READ8_MEMBER( sun4_base_state::fdc_r ) { if (machine().side_effects_disabled()) return 0; @@ -1378,7 +828,7 @@ READ8_MEMBER( sun4_state::fdc_r ) return 0; } -WRITE8_MEMBER( sun4_state::fdc_w ) +WRITE8_MEMBER( sun4_base_state::fdc_w ) { switch(offset) { @@ -1401,13 +851,13 @@ WRITE8_MEMBER( sun4_state::fdc_w ) } } -READ8_MEMBER( sun4_state::auxio_r ) +READ8_MEMBER( sun4_base_state::auxio_r ) { //logerror("%s: auxio_r: %02x\n", machine().describe_context(), m_auxio); return m_auxio; } -WRITE8_MEMBER( sun4_state::auxio_w ) +WRITE8_MEMBER( sun4_base_state::auxio_w ) { //logerror("%s: auxio_w: %02x, drive_sel:%d tc:%d eject:%d LED:%d\n", machine().describe_context(), data, BIT(data, 3), BIT(data, 2), BIT(data, 1), BIT(data, 0)); m_auxio = (m_auxio & 0xf0) | (data & 0x0f); @@ -1422,13 +872,13 @@ WRITE8_MEMBER( sun4_state::auxio_w ) } } -READ8_MEMBER( sun4_state::irq_r ) +READ8_MEMBER( sun4_base_state::irq_r ) { //logerror("%02x from IRQ\n", m_irq_reg); return m_irq_reg; } -WRITE8_MEMBER( sun4_state::irq_w ) +WRITE8_MEMBER( sun4_base_state::irq_w ) { const uint8_t old_irq = m_irq_reg; m_irq_reg = data; @@ -1441,16 +891,17 @@ WRITE8_MEMBER( sun4_state::irq_w ) if (BIT(changed, 0)) { + int enabled_state = BIT(data, 0) ? ASSERT_LINE : CLEAR_LINE; if (BIT(m_irq_reg, 7) && BIT(m_counter[2] | m_counter[3], 31)) - m_maincpu->set_input_line(SPARC_IRQ14, BIT(data, 0) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(SPARC_IRQ14, enabled_state); if (BIT(m_irq_reg, 5) && BIT(m_counter[0] | m_counter[1], 31)) - m_maincpu->set_input_line(SPARC_IRQ10, BIT(data, 0) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(SPARC_IRQ10, enabled_state); if (BIT(m_irq_reg, 3)) - m_maincpu->set_input_line(SPARC_IRQ6, BIT(data, 0) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(SPARC_IRQ6, enabled_state); if (BIT(m_irq_reg, 2)) - m_maincpu->set_input_line(SPARC_IRQ4, BIT(data, 0) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(SPARC_IRQ4, enabled_state); if (BIT(m_irq_reg, 1)) - m_maincpu->set_input_line(SPARC_IRQ1, BIT(data, 0) ? ASSERT_LINE : CLEAR_LINE); + m_maincpu->set_input_line(SPARC_IRQ1, enabled_state); } else if (BIT(m_irq_reg, 0)) { @@ -1467,21 +918,21 @@ WRITE8_MEMBER( sun4_state::irq_w ) } } -WRITE_LINE_MEMBER( sun4_state::scc1_int ) +WRITE_LINE_MEMBER( sun4_base_state::scc1_int ) { m_scc1_int = state; m_maincpu->set_input_line(SPARC_IRQ12, ((m_scc1_int || m_scc2_int) && (m_irq_reg & 0x01)) ? ASSERT_LINE : CLEAR_LINE); } -WRITE_LINE_MEMBER( sun4_state::scc2_int ) +WRITE_LINE_MEMBER( sun4_base_state::scc2_int ) { m_scc2_int = state; m_maincpu->set_input_line(SPARC_IRQ12, ((m_scc1_int || m_scc2_int) && (m_irq_reg & 0x01)) ? ASSERT_LINE : CLEAR_LINE); } -void sun4_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +void sun4_base_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { switch (id) { @@ -1522,16 +973,10 @@ void sun4_state::device_timer(emu_timer &timer, device_timer_id id, int param, v } } break; - - case TIMER_RESET: - m_reset_timer->adjust(attotime::never); - m_maincpu->set_input_line(SPARC_RESET, CLEAR_LINE); - //printf("Clearing reset line\n"); - break; } } -READ32_MEMBER( sun4_state::timer_r ) +READ32_MEMBER( sun4_base_state::timer_r ) { const uint32_t ret = m_counter[offset]; @@ -1562,7 +1007,7 @@ READ32_MEMBER( sun4_state::timer_r ) return ret; } -WRITE32_MEMBER( sun4_state::timer_w ) +WRITE32_MEMBER( sun4_base_state::timer_w ) { COMBINE_DATA(&m_counter[offset]); @@ -1591,7 +1036,7 @@ WRITE32_MEMBER( sun4_state::timer_w ) } } -void sun4_state::dma_check_interrupts() +void sun4_base_state::dma_check_interrupts() { bool tc_interrupt = (m_dma[DMA_CTRL] & DMA_TC) != 0 && !m_dma_tc_read; bool scsi_interrupt = m_scsi_irq != 0; @@ -1611,7 +1056,7 @@ void sun4_state::dma_check_interrupts() } } -void sun4_state::dma_transfer_write() +void sun4_base_state::dma_transfer_write() { //logerror("DMAing from device to RAM\n"); @@ -1629,12 +1074,7 @@ void sun4_state::dma_transfer_write() pack_cnt++; if (pack_cnt == 4) { - //logerror("Writing pack register %08x to %08x\n", m_dma_pack_register, m_dma[DMA_ADDR]); - if (m_arch == ARCH_SUN4C) - m_mmu->insn_data_w<sun4c_mmu_device::SUPER_DATA>(m_dma[DMA_ADDR] >> 2, m_dma_pack_register, ~0); - //else - TODO - //sun4_insn_data_w(space, m_dma[DMA_ADDR] >> 2, m_dma_pack_register, ~0); - + m_mmu->insn_data_w<sun4c_mmu_device::SUPER_DATA>(m_dma[DMA_ADDR] >> 2, m_dma_pack_register, ~0); pack_cnt = 0; m_dma_pack_register = 0; m_dma[DMA_ADDR] += 4; @@ -1645,7 +1085,7 @@ void sun4_state::dma_transfer_write() m_dma[DMA_CTRL] |= pack_cnt << DMA_PACK_CNT_SHIFT; } -void sun4_state::dma_transfer_read() +void sun4_base_state::dma_transfer_read() { //logerror("DMAing from RAM to device\n"); @@ -1655,10 +1095,7 @@ void sun4_state::dma_transfer_read() { if (!word_cached) { - if (m_arch == ARCH_SUN4C) - current_word = m_mmu->insn_data_r<sun4c_mmu_device::SUPER_DATA>(m_dma[DMA_ADDR] >> 2, ~0); - //else - TODO - //current_word = sun4_insn_data_r<SUPER_DATA>(space, m_dma[DMA_ADDR] >> 2, ~0); + current_word = m_mmu->insn_data_r<sun4c_mmu_device::SUPER_DATA>(m_dma[DMA_ADDR] >> 2, ~0); word_cached = true; //logerror("Current word: %08x\n", current_word); } @@ -1677,7 +1114,7 @@ void sun4_state::dma_transfer_read() } } -void sun4_state::dma_transfer() +void sun4_base_state::dma_transfer() { if (m_dma[DMA_CTRL] & DMA_WRITE) dma_transfer_write(); @@ -1692,7 +1129,7 @@ void sun4_state::dma_transfer() } } -READ32_MEMBER( sun4_state::dma_r ) +READ32_MEMBER( sun4_base_state::dma_r ) { if (offset == DMA_CTRL && (m_dma[DMA_CTRL] & DMA_TC) != 0) { @@ -1702,7 +1139,7 @@ READ32_MEMBER( sun4_state::dma_r ) return m_dma[offset]; } -WRITE32_MEMBER( sun4_state::dma_w ) +WRITE32_MEMBER( sun4_base_state::dma_w ) { switch (offset) { @@ -1735,10 +1172,7 @@ WRITE32_MEMBER( sun4_state::dma_w ) const uint32_t bit_index = (3 - i) * 8; //const uint32_t value = m_dma_pack_register & (0xff << bit_index); //logerror("dma_w: draining %02x to RAM address %08x & %08x\n", value >> bit_index, m_dma[DMA_ADDR], 0xff << (24 - bit_index)); - if (m_arch == ARCH_SUN4C) - m_mmu->insn_data_w<sun4c_mmu_device::SUPER_DATA>(m_dma[DMA_ADDR] >> 2, m_dma_pack_register, 0xff << bit_index); - else - sun4_insn_data_w(space, m_dma[DMA_ADDR] >> 2, m_dma_pack_register, 0xff << bit_index); + m_mmu->insn_data_w<sun4c_mmu_device::SUPER_DATA>(m_dma[DMA_ADDR] >> 2, m_dma_pack_register, 0xff << bit_index); m_dma[DMA_ADDR]++; } m_dma_pack_register = 0; @@ -1766,7 +1200,7 @@ WRITE32_MEMBER( sun4_state::dma_w ) } } -WRITE_LINE_MEMBER( sun4_state::scsi_irq ) +WRITE_LINE_MEMBER( sun4_base_state::scsi_irq ) { int old_irq = m_scsi_irq; m_scsi_irq = state; @@ -1777,7 +1211,7 @@ WRITE_LINE_MEMBER( sun4_state::scsi_irq ) } } -WRITE_LINE_MEMBER( sun4_state::scsi_drq ) +WRITE_LINE_MEMBER( sun4_base_state::scsi_drq ) { //logerror("scsi_drq %d\n", state); m_dma[DMA_CTRL] &= ~DMA_REQ_PEND; @@ -1793,7 +1227,7 @@ WRITE_LINE_MEMBER( sun4_state::scsi_drq ) } } -WRITE_LINE_MEMBER( sun4_state::fdc_irq ) +WRITE_LINE_MEMBER( sun4_base_state::fdc_irq ) { int old_irq = m_fdc_irq; m_fdc_irq = state; @@ -1804,18 +1238,19 @@ WRITE_LINE_MEMBER( sun4_state::fdc_irq ) } } -WRITE32_MEMBER( sun4_state::buserr_w ) +// indicate on-board SCSI/DMA/Ethernet card exists +READ32_MEMBER( sun4_base_state::sl0_id ) { - COMBINE_DATA(&m_buserr[offset]); + return 0xfe810101; } -// indicate 4/60 SCSI/DMA/Ethernet card exists -READ32_MEMBER( sun4_state::ss1_sl0_id ) +template <int Line> +WRITE_LINE_MEMBER(sun4c_state::sbus_irq_w) { - return 0xfe810101; + m_maincpu->set_input_line(Line, state); } -FLOPPY_FORMATS_MEMBER( sun4_state::floppy_formats ) +FLOPPY_FORMATS_MEMBER( sun4_base_state::floppy_formats ) FLOPPY_PC_FORMAT FLOPPY_FORMATS_END @@ -1837,77 +1272,55 @@ static void sun_scsi_devices(device_slot_interface &device) device.set_option_machine_config("cdrom", sun4_cdrom); } -void sun4_state::ncr53c90a(device_t *device) +void sun4_base_state::ncr53c90a(device_t *device) { ncr53c90a_device &adapter = downcast<ncr53c90a_device &>(*device); adapter.set_clock(10000000); - adapter.irq_handler_cb().set(*this, FUNC(sun4_state::scsi_irq)); - adapter.drq_handler_cb().set(*this, FUNC(sun4_state::scsi_drq)); + adapter.irq_handler_cb().set(*this, FUNC(sun4_base_state::scsi_irq)); + adapter.drq_handler_cb().set(*this, FUNC(sun4_base_state::scsi_drq)); } -void sun4_state::sun4(machine_config &config) +void sun4_base_state::sun4_base(machine_config &config) { - /* basic machine hardware */ - MB86901(config, m_maincpu, 16'670'000); - m_maincpu->add_asi_desc([](sparc_disassembler *dasm) { dasm->add_asi_desc(sun4_asi_desc); }); - m_maincpu->set_addrmap(0, &sun4_state::sun4c_debugger_map); - - // TODO: MMU for sun4 hardware - SUN4C_MMU(config, m_mmu, 25'000'000, 7, 0x7f); - m_mmu->type1_r().set(m_type1space, FUNC(address_map_bank_device::read32)); - m_mmu->type1_w().set(m_type1space, FUNC(address_map_bank_device::write32)); - m_mmu->set_cpu(m_maincpu); - m_mmu->set_ram(m_ram); - m_mmu->set_rom("user1"); - m_mmu->set_scc(m_scc2); - m_maincpu->set_mmu(m_mmu); - - RAM(config, m_ram); - m_ram->set_default_size("16M"); - m_ram->set_default_value(0x00); + RAM(config, m_ram).set_default_size("16M").set_default_value(0x00); + m_ram->set_extra_options("4M,8M,12M,16M,20M,24M,28M,32M,36M,40M,48M,52M,64M"); M48T02(config, TIMEKEEPER_TAG, 0); - I82072(config, m_fdc, 24_MHz_XTAL); + N82077AA(config, m_fdc, 24_MHz_XTAL); m_fdc->set_ready_line_connected(false); - m_fdc->intrq_wr_callback().set(FUNC(sun4_state::fdc_irq)); - FLOPPY_CONNECTOR(config, m_floppy, sun_floppies, "35hd", sun4_state::floppy_formats); - - // MMU Type 0 device space - ADDRESS_MAP_BANK(config, m_type0space).set_map(&sun4_state::type0space_map).set_options(ENDIANNESS_BIG, 32, 32, 0x80000000); - - // MMU Type 1 device space - ADDRESS_MAP_BANK(config, m_type1space).set_map(&sun4_state::type1space_s4_map).set_options(ENDIANNESS_BIG, 32, 32, 0x80000000); + m_fdc->intrq_wr_callback().set(FUNC(sun4_base_state::fdc_irq)); + FLOPPY_CONNECTOR(config, m_floppy, sun_floppies, "35hd", sun4_base_state::floppy_formats); // Ethernet AM79C90(config, m_lance); - m_lance->dma_in().set([this](address_space &space, offs_t offset) + m_lance->dma_in().set([this](offs_t offset) { - u32 const data = sun4_insn_data_r<SUPER_DATA>(space, (0xff000000U | offset) >> 2); + u32 const data = m_mmu->insn_data_r<sun4c_mmu_device::SUPER_DATA>((0xff000000U | offset) >> 2, 0xffffffffU); return (offset & 2) ? u16(data) : u16(data >> 16); }); - m_lance->dma_out().set([this](address_space &space, offs_t offset, u16 data, u16 mem_mask) + m_lance->dma_out().set([this](offs_t offset, u16 data, u16 mem_mask) { if (offset & 2) - sun4_insn_data_w(space, (0xff000000U | offset) >> 2, data, mem_mask); + m_mmu->insn_data_w<sun4c_mmu_device::SUPER_DATA>((0xff000000U | offset) >> 2, data, mem_mask); else - sun4_insn_data_w(space, (0xff000000U | offset) >> 2, u32(data) << 16, u32(mem_mask) << 16); + m_mmu->insn_data_w<sun4c_mmu_device::SUPER_DATA>((0xff000000U | offset) >> 2, u32(data) << 16, u32(mem_mask) << 16); }); // Keyboard/mouse SCC85C30(config, m_scc1, 4.9152_MHz_XTAL); - m_scc1->out_int_callback().set(FUNC(sun4_state::scc1_int)); + m_scc1->out_int_callback().set(FUNC(sun4_base_state::scc1_int)); m_scc1->out_txda_callback().set(KEYBOARD_TAG, FUNC(sun_keyboard_port_device::write_txd)); - m_scc1->out_txdb_callback().set(MOUSE_TAG, FUNC(sun_mouse_port_device::write_txd)); + // no mouse TxD connection - replaced with soft power request input - SUNKBD_PORT(config, KEYBOARD_TAG, default_sun_keyboard_devices, "type4hle").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxa_w)); + SUNKBD_PORT(config, KEYBOARD_TAG, default_sun_keyboard_devices, "type5hle").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxa_w)); SUNMOUSE_PORT(config, MOUSE_TAG, default_sun_mouse_devices, "hle1200").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxb_w)); // RS232 serial ports SCC85C30(config, m_scc2, 4.9152_MHz_XTAL); - m_scc2->out_int_callback().set(FUNC(sun4_state::scc2_int)); + m_scc2->out_int_callback().set(FUNC(sun4_base_state::scc2_int)); m_scc2->out_txda_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_txd)); m_scc2->out_txdb_callback().set(RS232B_TAG, FUNC(rs232_port_device::write_txd)); @@ -1932,14 +1345,19 @@ void sun4_state::sun4(machine_config &config) NSCSI_CONNECTOR(config, "scsibus:7", sun_scsi_devices, "ncr53c90a", true).set_option_machine_config("ncr53c90a", [this] (device_t *device) { ncr53c90a(device); }); } -void sun4_state::sun4c(machine_config &config) +void sun4_state::sun4(machine_config &config) { /* basic machine hardware */ - MB86901(config, m_maincpu, 20'000'000); - m_maincpu->add_asi_desc([](sparc_disassembler *dasm) { dasm->add_asi_desc(sun4c_asi_desc); }); - m_maincpu->set_addrmap(0, &sun4_state::sun4c_debugger_map); + SPARCV7(config, m_maincpu, 16'670'000); + m_maincpu->add_asi_desc([](sparc_disassembler *dasm) { dasm->add_asi_desc(sun4_asi_desc); }); + m_maincpu->set_addrmap(0, &sun4_state::debugger_map); - SUN4C_MMU(config, m_mmu, 20'000'000, 7, 0x7f); + sun4_base(config); + + // MMU Type 1 device space + ADDRESS_MAP_BANK(config, m_type1space).set_map(&sun4_state::type1space_map).set_options(ENDIANNESS_BIG, 32, 32, 0x80000000); + + SUN4_MMU(config, m_mmu, 25'000'000); m_mmu->type1_r().set(m_type1space, FUNC(address_map_bank_device::read32)); m_mmu->type1_w().set(m_type1space, FUNC(address_map_bank_device::write32)); m_mmu->set_cpu(m_maincpu); @@ -1947,82 +1365,44 @@ void sun4_state::sun4c(machine_config &config) m_mmu->set_rom("user1"); m_mmu->set_scc(m_scc2); m_maincpu->set_mmu(m_mmu); +} - RAM(config, m_ram).set_default_size("16M").set_default_value(0x00); - m_ram->set_extra_options("4M,8M,12M,16M,20M,24M,28M,32M,36M,40M,48M,52M,64M"); - - M48T02(config, TIMEKEEPER_TAG, 0); - - N82077AA(config, m_fdc, 24_MHz_XTAL); - m_fdc->set_ready_line_connected(false); - m_fdc->intrq_wr_callback().set(FUNC(sun4_state::fdc_irq)); - FLOPPY_CONNECTOR(config, m_floppy, sun_floppies, "35hd", sun4_state::floppy_formats); +void sun4c_state::sun4c(machine_config &config) +{ + /* basic machine hardware */ + SPARCV7(config, m_maincpu, 20'000'000); + m_maincpu->add_asi_desc([](sparc_disassembler *dasm) { dasm->add_asi_desc(sun4c_asi_desc); }); + m_maincpu->set_addrmap(0, &sun4c_state::debugger_map); - // MMU Type 0 device space - ADDRESS_MAP_BANK(config, m_type0space).set_map(&sun4_state::type0space_map).set_options(ENDIANNESS_BIG, 32, 32, 0x80000000); + sun4_base(config); // MMU Type 1 device space - ADDRESS_MAP_BANK(config, m_type1space).set_map(&sun4_state::type1space_sbus_map).set_options(ENDIANNESS_BIG, 32, 32, 0x80000000); - - // Ethernet - AM79C90(config, m_lance); - m_lance->dma_in().set([this](offs_t offset) - { - u32 const data = m_mmu->insn_data_r<sun4c_mmu_device::SUPER_DATA>((0xff000000U | offset) >> 2, 0xffffffffU); - - return (offset & 2) ? u16(data) : u16(data >> 16); - }); - m_lance->dma_out().set([this](offs_t offset, u16 data, u16 mem_mask) - { - if (offset & 2) - m_mmu->insn_data_w<sun4c_mmu_device::SUPER_DATA>((0xff000000U | offset) >> 2, data, mem_mask); - else - m_mmu->insn_data_w<sun4c_mmu_device::SUPER_DATA>((0xff000000U | offset) >> 2, u32(data) << 16, u32(mem_mask) << 16); - }); - - // Keyboard/mouse - SCC85C30(config, m_scc1, 4.9152_MHz_XTAL); - m_scc1->out_int_callback().set(FUNC(sun4_state::scc1_int)); - m_scc1->out_txda_callback().set(KEYBOARD_TAG, FUNC(sun_keyboard_port_device::write_txd)); - // no mouse TxD connection - replaced with soft power request input - - SUNKBD_PORT(config, KEYBOARD_TAG, default_sun_keyboard_devices, "type5hle").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxa_w)); - SUNMOUSE_PORT(config, MOUSE_TAG, default_sun_mouse_devices, "hle1200").rxd_handler().set(m_scc1, FUNC(z80scc_device::rxb_w)); - - // RS232 serial ports - SCC85C30(config, m_scc2, 4.9152_MHz_XTAL); - m_scc2->out_int_callback().set(FUNC(sun4_state::scc2_int)); - m_scc2->out_txda_callback().set(RS232A_TAG, FUNC(rs232_port_device::write_txd)); - m_scc2->out_txdb_callback().set(RS232B_TAG, FUNC(rs232_port_device::write_txd)); + ADDRESS_MAP_BANK(config, m_type1space).set_map(&sun4c_state::type1space_map).set_options(ENDIANNESS_BIG, 32, 32, 0x80000000); - rs232_port_device &rs232a(RS232_PORT(config, RS232A_TAG, default_rs232_devices, nullptr)); - rs232a.rxd_handler().set(m_scc2, FUNC(z80scc_device::rxa_w)); - rs232a.dcd_handler().set(m_scc2, FUNC(z80scc_device::dcda_w)); - rs232a.cts_handler().set(m_scc2, FUNC(z80scc_device::ctsa_w)); - - rs232_port_device &rs232b(RS232_PORT(config, RS232B_TAG, default_rs232_devices, nullptr)); - rs232b.rxd_handler().set(m_scc2, FUNC(z80scc_device::rxb_w)); - rs232b.dcd_handler().set(m_scc2, FUNC(z80scc_device::dcdb_w)); - rs232b.cts_handler().set(m_scc2, FUNC(z80scc_device::ctsb_w)); - - NSCSI_BUS(config, "scsibus"); - NSCSI_CONNECTOR(config, "scsibus:0", sun_scsi_devices, "harddisk"); - NSCSI_CONNECTOR(config, "scsibus:1", sun_scsi_devices, nullptr); - NSCSI_CONNECTOR(config, "scsibus:2", sun_scsi_devices, nullptr); - NSCSI_CONNECTOR(config, "scsibus:3", sun_scsi_devices, nullptr); - NSCSI_CONNECTOR(config, "scsibus:4", sun_scsi_devices, nullptr); - NSCSI_CONNECTOR(config, "scsibus:5", sun_scsi_devices, nullptr); - NSCSI_CONNECTOR(config, "scsibus:6", sun_scsi_devices, "cdrom"); - NSCSI_CONNECTOR(config, "scsibus:7", sun_scsi_devices, "ncr53c90a", true).set_option_machine_config("ncr53c90a", [this] (device_t *device) { ncr53c90a(device); }); + SUN4C_MMU(config, m_mmu, 20'000'000); + m_mmu->type1_r().set(m_type1space, FUNC(address_map_bank_device::read32)); + m_mmu->type1_w().set(m_type1space, FUNC(address_map_bank_device::write32)); + m_mmu->set_cpu(m_maincpu); + m_mmu->set_ram(m_ram); + m_mmu->set_rom("user1"); + m_mmu->set_scc(m_scc2); + m_maincpu->set_mmu(m_mmu); // SBus SBUS(config, m_sbus, 20'000'000, "maincpu", "type1"); + m_sbus->irq<0>().set(FUNC(sun4c_state::sbus_irq_w<SPARC_IRQ1>)); + m_sbus->irq<1>().set(FUNC(sun4c_state::sbus_irq_w<SPARC_IRQ2>)); + m_sbus->irq<2>().set(FUNC(sun4c_state::sbus_irq_w<SPARC_IRQ3>)); + m_sbus->irq<3>().set(FUNC(sun4c_state::sbus_irq_w<SPARC_IRQ5>)); + m_sbus->irq<4>().set(FUNC(sun4c_state::sbus_irq_w<SPARC_IRQ7>)); + m_sbus->irq<5>().set(FUNC(sun4c_state::sbus_irq_w<SPARC_IRQ8>)); + m_sbus->irq<6>().set(FUNC(sun4c_state::sbus_irq_w<SPARC_IRQ9>)); SBUS_SLOT(config, m_sbus_slot[0], 20'000'000, m_sbus, 0, sbus_cards, nullptr); SBUS_SLOT(config, m_sbus_slot[1], 20'000'000, m_sbus, 1, sbus_cards, nullptr); SBUS_SLOT(config, m_sbus_slot[2], 20'000'000, m_sbus, 2, sbus_cards, nullptr); } -void sun4_state::sun4_20(machine_config &config) +void sun4c_state::sun4_20(machine_config &config) { sun4c(config); @@ -2034,7 +1414,7 @@ void sun4_state::sun4_20(machine_config &config) m_sbus_slot[2]->set_fixed(true); } -void sun4_state::sun4_40(machine_config &config) +void sun4c_state::sun4_40(machine_config &config) { sun4c(config); @@ -2051,7 +1431,7 @@ void sun4_state::sun4_40(machine_config &config) m_sbus_slot[2]->set_fixed(true); } -void sun4_state::sun4_50(machine_config &config) +void sun4c_state::sun4_50(machine_config &config) { sun4c(config); @@ -2069,12 +1449,12 @@ void sun4_state::sun4_50(machine_config &config) m_sbus_slot[2]->set_fixed(true); } -void sun4_state::sun4_60(machine_config &config) +void sun4c_state::sun4_60(machine_config &config) { sun4c(config); } -void sun4_state::sun4_65(machine_config &config) +void sun4c_state::sun4_65(machine_config &config) { sun4c(config); @@ -2088,7 +1468,7 @@ void sun4_state::sun4_65(machine_config &config) m_sbus_slot[2]->set_default_option("bwtwo"); } -void sun4_state::sun4_75(machine_config &config) +void sun4c_state::sun4_75(machine_config &config) { sun4c(config); @@ -2338,33 +1718,23 @@ ROM_START( sun_s20 ) ROMX_LOAD( "ss10-20_v2.25r.rom", 0x0000, 0x80000, CRC(105ba132) SHA1(58530e88369d1d26ab11475c7884205f2299d255), ROM_BIOS(1)) ROM_END -void sun4_state::init_sun4() -{ - m_arch = ARCH_SUN4; -} - -void sun4_state::init_sun4c() -{ - m_arch = ARCH_SUN4C; -} - /* Drivers */ -// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS // sun4 -COMP( 198?, sun4_110, 0, 0, sun4, sun4, sun4_state, init_sun4, "Sun Microsystems", "Sun 4/110", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -COMP( 1987, sun4_300, 0, 0, sun4, sun4, sun4_state, init_sun4, "Sun Microsystems", "Sun 4/3x0", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -COMP( 198?, sun4_400, 0, 0, sun4, sun4, sun4_state, init_sun4, "Sun Microsystems", "Sun 4/4x0", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +COMP( 198?, sun4_110, 0, 0, sun4, sun4, sun4_state, empty_init, "Sun Microsystems", "Sun 4/110", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +COMP( 1987, sun4_300, 0, 0, sun4, sun4, sun4_state, empty_init, "Sun Microsystems", "Sun 4/3x0", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +COMP( 198?, sun4_400, 0, 0, sun4, sun4, sun4_state, empty_init, "Sun Microsystems", "Sun 4/4x0", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // sun4c -COMP( 1990, sun4_40, sun4_300, 0, sun4_40, sun4, sun4_state, init_sun4c, "Sun Microsystems", "SPARCstation IPC (Sun 4/40)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE ) -COMP( 1991, sun4_50, sun4_300, 0, sun4_50, sun4, sun4_state, init_sun4c, "Sun Microsystems", "SPARCstation IPX (Sun 4/50)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -COMP( 199?, sun4_20, sun4_300, 0, sun4_20, sun4, sun4_state, init_sun4c, "Sun Microsystems", "SPARCstation SLC (Sun 4/20)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -COMP( 1989, sun4_60, sun4_300, 0, sun4_60, sun4, sun4_state, init_sun4c, "Sun Microsystems", "SPARCstation 1 (Sun 4/60)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE ) -COMP( 1990, sun4_65, sun4_300, 0, sun4_65, sun4, sun4_state, init_sun4c, "Sun Microsystems", "SPARCstation 1+ (Sun 4/65)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -COMP( 1990, sun4_75, sun4_300, 0, sun4_75, sun4, sun4_state, init_sun4c, "Sun Microsystems", "SPARCstation 2 (Sun 4/75)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +COMP( 1990, sun4_40, sun4_300, 0, sun4_40, sun4, sun4c_state, empty_init, "Sun Microsystems", "SPARCstation IPC (Sun 4/40)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE ) +COMP( 1991, sun4_50, sun4_300, 0, sun4_50, sun4, sun4c_state, empty_init, "Sun Microsystems", "SPARCstation IPX (Sun 4/50)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +COMP( 199?, sun4_20, sun4_300, 0, sun4_20, sun4, sun4c_state, empty_init, "Sun Microsystems", "SPARCstation SLC (Sun 4/20)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +COMP( 1989, sun4_60, sun4_300, 0, sun4_60, sun4, sun4c_state, empty_init, "Sun Microsystems", "SPARCstation 1 (Sun 4/60)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE ) +COMP( 1990, sun4_65, sun4_300, 0, sun4_65, sun4, sun4c_state, empty_init, "Sun Microsystems", "SPARCstation 1+ (Sun 4/65)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +COMP( 1990, sun4_75, sun4_300, 0, sun4_75, sun4, sun4c_state, empty_init, "Sun Microsystems", "SPARCstation 2 (Sun 4/75)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) // sun4m (using the SPARC "reference MMU", probably will go to a separate driver) -COMP( 1992, sun_s10, sun4_300, 0, sun4c, sun4, sun4_state, init_sun4c, "Sun Microsystems", "SPARCstation 10 (Sun S10)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) -COMP( 1994, sun_s20, sun4_300, 0, sun4c, sun4, sun4_state, init_sun4c, "Sun Microsystems", "SPARCstation 20", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +COMP( 1992, sun_s10, sun4_300, 0, sun4c, sun4, sun4c_state, empty_init, "Sun Microsystems", "SPARCstation 10 (Sun S10)", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) +COMP( 1994, sun_s20, sun4_300, 0, sun4c, sun4, sun4c_state, empty_init, "Sun Microsystems", "SPARCstation 20", MACHINE_NOT_WORKING | MACHINE_NO_SOUND ) |