summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author mooglyguy <therealmogminer@gmail.com>2019-11-18 17:30:38 +0100
committer MooglyGuy <therealmogminer@gmail.com>2019-11-18 17:31:09 +0100
commitb54cb1804b4eff6f1e4be82a43e346c30d6755ab (patch)
treeba6ef819ed48a53cc0f194fafb5896f2ebb8b77b
parent0a0d0fd9b03b791767b1400f713d63aa1647fcba (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.lua11
-rw-r--r--scripts/target/mame/mess.lua2
-rw-r--r--src/devices/bus/sbus/cgsix.cpp107
-rw-r--r--src/devices/bus/sbus/cgsix.h35
-rw-r--r--src/devices/bus/sbus/sbus.h2
-rw-r--r--src/devices/cpu/sparc/sparc.cpp5046
-rw-r--r--src/devices/cpu/sparc/sparc.h86
-rw-r--r--src/devices/cpu/sparc/sparcdefs.h101
-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.ipp293
-rw-r--r--src/devices/cpu/sparc/ss1fcode.ipp6
-rw-r--r--src/devices/machine/sun4c_mmu.cpp231
-rw-r--r--src/devices/machine/sun4c_mmu.h70
-rw-r--r--src/devices/video/bt45x.cpp44
-rw-r--r--src/mame/drivers/sun4.cpp1004
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> &params)
+{
+ 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> &params);
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> &params);
void fcodes_command(int ref, const std::vector<std::string> &params);
};
-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> &params)
+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> &params)
+void sun4_base_state::fcodes_command(int ref, const std::vector<std::string> &params)
{
#if SUN4_LOG_FCODES
if (params < 1)
@@ -1096,118 +700,51 @@ void sun4_state::fcodes_command(int ref, const std::vector<std::string> &params)
#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 )