summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/sun4c_mmu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/sun4c_mmu.cpp')
-rw-r--r--src/devices/machine/sun4c_mmu.cpp667
1 files changed, 384 insertions, 283 deletions
diff --git a/src/devices/machine/sun4c_mmu.cpp b/src/devices/machine/sun4c_mmu.cpp
index 08fae7b4aec..038a47e7158 100644
--- a/src/devices/machine/sun4c_mmu.cpp
+++ b/src/devices/machine/sun4c_mmu.cpp
@@ -2,43 +2,59 @@
// 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")
-
-#define LOG_PAGE_MAP (1U << 0)
-#define LOG_SEGMENT_MAP (1U << 1)
-#define LOG_INVALID_PTE (1U << 2)
-#define LOG_SYSTEM (1U << 3)
-#define LOG_CONTEXT (1U << 4)
-#define LOG_SYSTEM_ENABLE (1U << 5)
-#define LOG_BUSERROR (1U << 6)
-#define LOG_CACHE_TAGS (1U << 7)
-#define LOG_CACHE_DATA (1U << 8)
-#define LOG_UNKNOWN_SYSTEM (1U << 9)
-#define LOG_UNKNOWN_SEGMENT (1U << 10)
-#define LOG_TYPE0_TIMEOUT (1U << 11)
-#define LOG_UNKNOWN_SPACE (1U << 12)
-#define LOG_WRITE_PROTECT (1U << 13)
-#define LOG_ALL_ASI (1U << 14) // WARNING: Heavy!
-
-#define VERBOSE (0)
+#include "debug/debugcon.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 << 1)
+#define LOG_SEGMENT_MAP (1U << 2)
+#define LOG_CONTEXT (1U << 3)
+#define LOG_SYSTEM_ENABLE (1U << 4)
+#define LOG_UART (1U << 5)
+#define LOG_PARITY (1U << 6)
+#define LOG_SEGMENT_FLUSH (1U << 7)
+#define LOG_PAGE_FLUSH (1U << 8)
+#define LOG_CONTEXT_FLUSH (1U << 9)
+#define LOG_ALL_FLUSH (1U << 10)
+#define LOG_CACHE_TAGS (1U << 11)
+#define LOG_CACHE_DATA (1U << 12)
+#define LOG_INVALID_PTE (1U << 13)
+#define LOG_BUSERROR (1U << 14)
+#define LOG_TYPE0_TIMEOUT (1U << 15)
+#define LOG_TYPE1_TIMEOUT (1U << 16)
+#define LOG_UNKNOWN_SPACE (1U << 17)
+#define LOG_UNKNOWN_SEGMENT (1U << 18)
+#define LOG_WRITE_PROTECT (1U << 19)
+#define LOG_MMU (LOG_PAGE_MAP | LOG_SEGMENT_MAP | LOG_CONTEXT)
+#define LOG_MISC_HW (LOG_SYSTEM_ENABLE | LOG_UART | LOG_PARITY)
+#define LOG_FLUSHES (LOG_SEGMENT_FLUSH | LOG_PAGE_FLUSH | LOG_CONTEXT_FLUSH | LOG_ALL_FLUSH)
+#define LOG_CACHE (LOG_CACHE_TAGS | LOG_CACHE_DATA | LOG_FLUSHES)
+#define LOG_ERRORS (LOG_INVALID_PTE | LOG_BUSERROR | LOG_TYPE0_TIMEOUT | LOG_TIME1_TIMEOUT | LOG_UNKNOWN_SPACE | LOG_UNKNOWN_SEGMENT | LOG_WRITE_PROTECT)
+
+//#define VERBOSE (LOG_MMU | LOG_MISC_HW | LOG_FLUSHES | LOG_CACHE | LOG_ERRORS)
#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)
+#define PRINT_UART_DATA (0)
+
+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)
, m_scc(*this, finder_base::DUMMY_TAG)
, m_host(nullptr)
- , m_type1_r(*this)
+ , m_type1_r(*this, 0xffffffff)
, m_type1_w(*this)
, m_rom_ptr(nullptr)
, m_ram_ptr(nullptr)
@@ -53,35 +69,45 @@ 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)
{
- m_type1_r.resolve_safe(0xffffffff);
- m_type1_w.resolve_safe();
+}
+void sun4_mmu_base_device::device_start()
+{
// allocate timer for system reset
- m_reset_timer = timer_alloc(TIMER_RESET);
+ m_reset_timer = timer_alloc(FUNC(sun4_mmu_base_device::reset_off_tick), this);
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 +115,29 @@ 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_type1_offset));
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));
+ save_item(NAME(m_parity_err_reg));
+ save_item(NAME(m_memory_err_reg));
+ save_item(NAME(m_parity_err));
+
+ if (machine().debug_flags & DEBUG_FLAG_ENABLED)
+ {
+ using namespace std::placeholders;
+ machine().debugger().console().register_command("l2p", CMDFLAG_NONE, 1, 1, std::bind(&sun4_mmu_base_device::l2p_command, this, _1));
+ }
}
-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,28 +169,32 @@ 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;
+ m_type1_offset = 0;
+ m_parity_err_reg = 0;
+ m_memory_err_reg = 0;
+ m_parity_err = 0;
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)
+TIMER_CALLBACK_MEMBER(sun4_mmu_base_device::reset_off_tick)
{
- if (id == TIMER_RESET)
- {
- m_reset_timer->adjust(attotime::never);
- m_cpu->set_input_line(SPARC_RESET, CLEAR_LINE);
- }
+ m_reset_timer->adjust(attotime::never);
+ m_cpu->set_input_line(SPARC_RESET, CLEAR_LINE);
}
-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,294 +202,326 @@ 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)
+void sun4_mmu_base_device::segment_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_ALL_ASI, "read_asi %d: %08x & %08x\n", asi, offset << 2, mem_mask);
- switch (asi)
- {
- case 2:
- return system_r(offset, mem_mask);
- case 3:
- return segment_map_r(offset, mem_mask);
- case 4:
- return page_map_r(offset, mem_mask);
- case 8:
- return insn_data_r<USER_INSN>(offset, mem_mask);
- case 9:
- return insn_data_r<SUPER_INSN>(offset, mem_mask);
- case 10:
- return insn_data_r<USER_DATA>(offset, mem_mask);
- case 11:
- return insn_data_r<SUPER_DATA>(offset, mem_mask);
- case 12:
- case 13:
- case 14:
- cache_flush_r();
- return 0;
- default:
- return ~0;
- }
+ // Do nothing for now
+ LOGMASKED(LOG_SEGMENT_FLUSH, "%s: segment_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
-void sun4c_mmu_device::write_asi(uint8_t asi, uint32_t offset, uint32_t data, uint32_t mem_mask)
+void sun4_mmu_base_device::page_flush_w(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)
- {
- case 2:
- system_w(offset, data, mem_mask);
- return;
- case 3:
- segment_map_w(offset, data, mem_mask);
- return;
- case 4:
- page_map_w(offset, data, mem_mask);
- return;
- case 8:
- insn_data_w<USER_INSN>(offset, data, mem_mask);
- return;
- case 9:
- insn_data_w<SUPER_INSN>(offset, data, mem_mask);
- return;
- case 10:
- insn_data_w<USER_DATA>(offset, data, mem_mask);
- return;
- case 11:
- insn_data_w<SUPER_DATA>(offset, data, mem_mask);
- return;
- case 12:
- case 13:
- case 14:
- cache_flush_w();
- return;
- default:
- return;
- }
+ // Do nothing for now
+ LOGMASKED(LOG_PAGE_FLUSH, "%s: page_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
-uint32_t sun4c_mmu_device::cache_flush_r()
+void sun4_mmu_base_device::context_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
// Do nothing for now
- return 0;
+ LOGMASKED(LOG_CONTEXT_FLUSH, "%s: context_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
-void sun4c_mmu_device::cache_flush_w()
+void sun4_mmu_base_device::hw_segment_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
// Do nothing for now
+ LOGMASKED(LOG_SEGMENT_FLUSH, "%s: segment_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
}
-uint32_t sun4c_mmu_device::system_r(const uint32_t offset, const uint32_t mem_mask)
+void sun4_mmu_base_device::hw_page_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_SYSTEM, "%s: system_r: %08x & %08x\n", machine().describe_context(), offset << 2, mem_mask);
- switch (offset >> 26)
- {
- case 3: // context reg
- {
- if (mem_mask == 0x00ff0000)
- {
- LOGMASKED(LOG_CONTEXT, "sun4c_mmu: read context %08x & %08x = %08x\n", offset << 2, mem_mask, m_context<<16);
- return m_context<<16;
- }
- LOGMASKED(LOG_CONTEXT, "sun4c_mmu: read context %08x & %08x = %08x\n", offset << 2, mem_mask, m_context<<24);
- return m_context<<24;
- }
+ // Do nothing for now
+ LOGMASKED(LOG_PAGE_FLUSH, "%s: page_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+}
- case 4: // system enable reg
- LOGMASKED(LOG_SYSTEM_ENABLE, "sun4c_mmu: read system enable %08x & %08x = %08x\n", offset << 2, mem_mask, m_system_enable<<24);
- return m_system_enable<<24;
+void sun4_mmu_base_device::hw_context_flush_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+{
+ // Do nothing for now
+ LOGMASKED(LOG_CONTEXT_FLUSH, "%s: context_flush_w %08x & %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+}
- case 6: // bus error register
- {
- const uint32_t ret = m_buserr[offset & 0xf];
- LOGMASKED(LOG_BUSERROR, "sun4c_mmu: read buserror %08x & %08x = %08x, PC=%x\n", 0x60000000 | (offset << 2), mem_mask, ret, m_cpu->pc());
- m_buserr[offset & 0xf] = 0; // clear on reading
- return ret;
- }
+void sun4_mmu_base_device::hw_flush_all_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+{
+ // Do nothing for now
+ LOGMASKED(LOG_ALL_FLUSH, "%s: hw_flush_all_w %08x = %08x: %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+}
- 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];
+uint32_t sun4_mmu_base_device::context_reg_r(uint32_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_context << (mem_mask == 0x00ff0000 ? 16 : 24);
+ LOGMASKED(LOG_CONTEXT, "%s: context_reg_r %08x & %08x: %08x\n", machine().describe_context(), offset << 2, mem_mask, data);
+ return data;
+}
- 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];
+void sun4_mmu_base_device::context_reg_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_CONTEXT, "%s: context_reg_w: %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+ 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][0];
+ m_curr_segmap_masked = &m_segmap_masked[m_context_masked][0];
+}
- case 0xf: // UART bypass
- switch (offset & 3)
- {
- case 0: if (mem_mask == 0xff000000) return m_scc->cb_r(0)<<24; else return m_scc->db_r(0)<<8; break;
- case 1: if (mem_mask == 0xff000000) return m_scc->ca_r(0)<<24; else return m_scc->da_r(0)<<8; break;
- }
- return 0xffffffff;
+uint32_t sun4_mmu_base_device::system_enable_r(uint32_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_system_enable << 24;
+ LOGMASKED(LOG_SYSTEM_ENABLE, "%s: system_enable_r %08x & %08x: %08x\n", machine().describe_context(), offset << 2, mem_mask, data);
+ return data;
+}
- case 0: // IDPROM - SPARCstation-1 does not have an ID prom and a timeout should occur.
- default:
- LOGMASKED(LOG_UNKNOWN_SYSTEM, "read unhandled ASI 2 space %08x & %08x\n", offset << 2, mem_mask);
- return 0;
+void sun4_mmu_base_device::system_enable_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_SYSTEM_ENABLE, "%s: system_enable_w: %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+ m_system_enable = data >> 24;
+ m_fetch_bootrom = !(m_system_enable & ENA_NOTBOOT);
+
+ if (m_system_enable & ENA_RESET)
+ {
+ m_reset_timer->adjust(attotime::from_usec(1));
+ m_cpu->set_input_line(SPARC_RESET, ASSERT_LINE);
+ }
+ if (m_system_enable & ENA_RESET)
+ {
+ m_system_enable = 0;
+ m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
+ m_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
}
}
-void sun4c_mmu_device::system_w(const uint32_t offset, const uint32_t data, const uint32_t mem_mask)
+uint32_t sun4_mmu_base_device::bus_error_r(uint32_t offset, uint32_t mem_mask)
{
- LOGMASKED(LOG_SYSTEM, "system_w: %08x = %08x & %08x\n", offset << 2, data, mem_mask);
- switch (offset >> 26)
- {
- case 3: // context reg
- LOGMASKED(LOG_CONTEXT, "write context = %08x & %08x\n", data, mem_mask);
- 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];
- return;
+ const uint32_t data = m_buserr[offset & 0xf];
+ LOGMASKED(LOG_BUSERROR, "%s: bus_error_r %08x & %08x: %08x\n", machine().describe_context(), 0x60000000 | (offset << 2), mem_mask, data);
+ m_buserr[offset & 0xf] = 0; // clear on reading
+ return data;
+}
- case 4: // system enable reg
- {
- LOGMASKED(LOG_SYSTEM_ENABLE, "write system enable = %08x & %08x\n", data, mem_mask);
- m_system_enable = data >> 24;
- m_fetch_bootrom = !(m_system_enable & ENA_NOTBOOT);
+void sun4_mmu_base_device::bus_error_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+{
+ const uint32_t masked_offset = offset & 0xf;
+ LOGMASKED(LOG_BUSERROR, "%s: bus_error_w: %08x = %08x & %08x\n", machine().describe_context(), 0x60000000 | (offset << 2), data, mem_mask);
+ if (masked_offset == 0)
+ m_buserr[0] = (data & 0x000000ff) | 0x00008000;
+ else if (masked_offset == 1)
+ m_buserr[1] = data;
+ else if (masked_offset == 2)
+ m_buserr[2] = data & 0x000000b0;
+ else if (masked_offset == 3)
+ m_buserr[3] = (data & 0x3fffffff) | ((data & 0x20000000) << 1) | ((data & 0x20000000) << 2);
+}
- if (m_system_enable & ENA_RESET)
- {
- m_reset_timer->adjust(attotime::from_usec(1));
- m_cpu->set_input_line(SPARC_RESET, ASSERT_LINE);
- }
- if (m_system_enable & ENA_RESET)
- {
- m_system_enable = 0;
- m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
- m_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
- }
- return;
- }
+uint32_t sun4_mmu_base_device::cache_tag_r(uint32_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_cachetags[offset & m_cache_mask];
+ LOGMASKED(LOG_CACHE_TAGS, "%s: cache_tag_r %08x & %08x: %08x\n", machine().describe_context(), offset, mem_mask, data);
+ return data;
+}
- case 6: // bus error
- {
- const uint32_t masked_offset = offset & 0xf;
- LOGMASKED(LOG_BUSERROR, "write bus error %08x = %08x & %08x\n", offset << 2, data, mem_mask);
- if (masked_offset == 0)
- m_buserr[0] = (data & 0x000000ff) | 0x00008000;
- else if (masked_offset == 1)
- m_buserr[1] = data;
- else if (masked_offset == 2)
- m_buserr[2] = data & 0x000000b0;
- else if (masked_offset == 3)
- m_buserr[3] = (data & 0x3fffffff) | ((data & 0x20000000) << 1) | ((data & 0x20000000) << 2);
- return;
- }
+void sun4_mmu_base_device::cache_tag_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_CACHE_TAGS, "%s: cache_tag_w: %08x = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ m_cachetags[offset & m_cache_mask] = data & 0x03f8fffc;
+}
- 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;
- return;
+uint32_t sun4_mmu_base_device::cache_data_r(uint32_t offset, uint32_t mem_mask)
+{
+ const uint32_t data = m_cachedata[offset & m_cache_mask];
+ LOGMASKED(LOG_CACHE_DATA, "%s: cache_data_r %08x & %08x: %08x\n", machine().describe_context(), offset, mem_mask, data);
+ return data;
+}
- 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);
- return;
+void sun4_mmu_base_device::cache_data_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_CACHE_DATA, "%s: cache_data_w: %08x = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ m_cachedata[offset & m_cache_mask] = data | (1 << 19);
+}
+
+uint32_t sun4_mmu_base_device::uart_r(uint32_t offset, uint32_t mem_mask)
+{
+ uint32_t data = 0xffffffff;
+ switch (offset & 3)
+ {
+ case 0:
+ if (mem_mask == 0xff000000)
+ data = m_scc->cb_r(0) << 24;
+ else
+ data = m_scc->db_r(0) << 8;
+ break;
+ case 1:
+ if (mem_mask == 0xff000000)
+ data = m_scc->ca_r(0) << 24;
+ else
+ data = m_scc->da_r(0) << 8;
+ break;
+ }
+ LOGMASKED(LOG_UART, "%s: uart_r %08x & %08x: %08x\n", machine().describe_context(), offset, mem_mask, data);
+ return data;
+}
- case 0xf: // UART bypass
- switch (offset & 3)
+void sun4_mmu_base_device::uart_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+{
+ LOGMASKED(LOG_UART, "%s: uart_w: %08x = %08x & %08x\n", machine().describe_context(), offset, data, mem_mask);
+ switch (offset & 3)
+ {
+ case 0:
+ if (mem_mask == 0xff000000)
+ m_scc->cb_w(0, data >> 24);
+ else
+ m_scc->db_w(0, data >> 8);
+ return;
+ case 1:
+ if (mem_mask == 0xff000000)
+ m_scc->ca_w(0, data >> 24);
+ else
{
- case 0: if (mem_mask == 0xff000000) m_scc->cb_w(0, data>>24); else m_scc->db_w(0, data>>8); break;
- case 1: if (mem_mask == 0xff000000) m_scc->ca_w(0, data>>24); else { m_scc->da_w(0, data>>8); printf("%c", data>>8); } break;
+ m_scc->da_w(0, data >> 8);
+ if (PRINT_UART_DATA)
+ {
+ printf("%c", data >> 8);
+ }
}
return;
-
- case 0: // IDPROM
- default:
- LOGMASKED(LOG_UNKNOWN_SYSTEM, "write unhandled ASI 2 space %08x = %08x & %08x, PC=%08x\n", offset << 2, data, mem_mask, m_cpu->pc());
- return;
}
}
-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(uint32_t offset, uint32_t mem_mask)
{
- uint32_t ret = 0;
+ uint32_t data = 0;
if (mem_mask == 0xffff0000)
- ret = m_curr_segmap[(offset>>16) & 0xfff]<<16;
+ data = m_curr_segmap[(offset >> 16) & 0xfff] << 16;
else if (mem_mask == 0xff000000)
- ret = m_curr_segmap[(offset>>16) & 0xfff]<<24;
+ data = m_curr_segmap[(offset >> 16) & 0xfff] << 24;
else if (mem_mask == 0xffffffff)
- ret = m_curr_segmap[(offset>>16) & 0xfff];
+ data = m_curr_segmap[(offset >> 16) & 0xfff];
else
- LOGMASKED(LOG_UNKNOWN_SEGMENT, "read segment map w/ unknown mask %08x & %08x\n", offset << 2, mem_mask);
- LOGMASKED(LOG_SEGMENT_MAP, "read segment map %08x & %08x = %08x\n", offset << 2, mem_mask, ret);
- return ret;
+ LOGMASKED(LOG_UNKNOWN_SEGMENT, "%s: segment_map_r: %08x & %08x (unknown mask)\n", machine().describe_context(), offset << 2, mem_mask);
+ LOGMASKED(LOG_SEGMENT_MAP, "%s: segment_map_r: %08x & %08x: %08x\n", machine().describe_context(), offset << 2, mem_mask, data);
+ return data;
}
-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(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- LOGMASKED(LOG_SEGMENT_MAP, "write segment map %08x = %08x & %08x\n", offset << 2, data, mem_mask);
+ LOGMASKED(LOG_SEGMENT_MAP, "%s: segment_map_w: %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
uint8_t segdata = 0;
- if (mem_mask == 0xffff0000) segdata = (data >> 16) & 0xff;
- else if (mem_mask == 0xff000000) segdata = (data >> 24) & 0xff;
- else if (mem_mask == 0xffffffff) segdata = data & 0xff;
- else LOGMASKED(LOG_UNKNOWN_SEGMENT, "write segment map w/ unknown mask %08x = %08x & %08x, PC=%08x\n", offset << 2, data, mem_mask, m_cpu->pc());
+ if (mem_mask == 0xffff0000)
+ segdata = (data >> 16) & 0xff;
+ else if (mem_mask == 0xff000000)
+ segdata = (data >> 24) & 0xff;
+ else if (mem_mask == 0xffffffff)
+ segdata = data & 0xff;
+ else
+ LOGMASKED(LOG_UNKNOWN_SEGMENT, "%s: segment_map_w: %08x = %08x & %08x (unknown mask)\n", machine().describe_context(), offset << 2, data, mem_mask);
- const uint32_t seg = (offset>>16) & 0xfff;
+ const uint32_t seg = (offset >> 16) & 0xfff;
m_curr_segmap[seg] = segdata;
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(uint32_t offset, 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();
- LOGMASKED(LOG_PAGE_MAP, "read page map %08x & %08x (%x) = %08x\n", offset << 2, mem_mask, page, ret);
- return ret;
+ const uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> m_seg_entry_shift) & m_seg_entry_mask);
+ const uint32_t data = page_entry_to_uint(page);
+ LOGMASKED(LOG_PAGE_MAP, "%s: page_map_r: %08x (%x) & %08x: %08x\n", machine().describe_context(), offset << 2, page, mem_mask, data);
+ return data;
}
-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(uint32_t offset, uint32_t data, uint32_t mem_mask)
{
- uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> 10) & 0x3f);
- 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);
+ const uint32_t page = m_curr_segmap_masked[(offset >> 16) & 0xfff] | ((offset >> m_seg_entry_shift) & m_seg_entry_mask);
+ LOGMASKED(LOG_PAGE_MAP, "%s: page_map_w: %08x (%x) = %08x & %08x\n", machine().describe_context(), offset << 2, page, 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());
+ LOGMASKED(LOG_TYPE0_TIMEOUT, "%s: type0_timeout_r (%08x)\n", machine().describe_context(), offset << 2);
m_buserr[0] = 0x20; // read timeout
m_buserr[1] = 0x04000000 + (offset << 2);
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());
+ LOGMASKED(LOG_TYPE0_TIMEOUT, "%s: type0_timeout_w (%08x)\n", machine().describe_context(), offset << 2);
m_buserr[0] = 0x8020; // write timeout
m_buserr[1] = 0x04000000 + (offset << 2);
m_host->set_mae();
}
-uint32_t sun4c_mmu_device::page_entry_t::to_uint()
+uint32_t sun4_mmu_base_device::type1_timeout_r(uint32_t offset)
{
- return valid | writable | supervisor | uncached | (type << 26) | accessed | modified | (page >> 10);
+ LOGMASKED(LOG_TYPE1_TIMEOUT, "%s: type1_timeout_r (%08x)\n", machine().describe_context(), offset << 2);
+ m_buserr[2] = 0x20; // read timeout
+ m_buserr[3] = m_type1_offset << 2;
+ return 0;
}
-void sun4c_mmu_device::page_entry_t::merge_uint(uint32_t data, uint32_t mem_mask)
+void sun4_mmu_base_device::type1_timeout_w(uint32_t offset, uint32_t data)
{
- 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;
+ LOGMASKED(LOG_TYPE1_TIMEOUT, "%s: type1_timeout_w (%08x)\n", machine().describe_context(), offset << 2);
+ m_buserr[2] = 0x120; // write timeout
+ m_buserr[3] = m_type1_offset << 2;
}
-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);
+uint32_t sun4_mmu_base_device::parity_r(uint32_t offset, uint32_t mem_mask)
+{
+ uint32_t data = 0;
+ if (offset == 0)
+ {
+ data = m_parity_err_reg;
+ LOGMASKED(LOG_PARITY, "%s: parity_r (parity error register): %08x & %08x: %08x\n", machine().describe_context(), offset << 2, mem_mask, data);
+ m_parity_err_reg &= ~0xcf;
+ }
+ else if (offset == 1)
+ {
+ data = m_memory_err_reg;
+ LOGMASKED(LOG_PARITY, "%s: parity_r (memory error register): %08x & %08x: %08x\n", machine().describe_context(), offset << 2, mem_mask, data);
+ }
+ return data;
+}
-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)
+void sun4_mmu_base_device::parity_w(uint32_t offset, uint32_t data, uint32_t mem_mask)
+{
+ if (offset == 0)
+ {
+ LOGMASKED(LOG_PARITY, "%s: parity_w (parity error register): %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+ COMBINE_DATA(&m_parity_err_reg);
+ }
+ else
+ {
+ LOGMASKED(LOG_PARITY, "%s: parity_w (memory error register): %08x = %08x & %08x\n", machine().describe_context(), offset << 2, data, mem_mask);
+ COMBINE_DATA(&m_memory_err_reg);
+ }
+}
+
+uint32_t sun4_mmu_base_device::page_entry_to_uint(uint32_t index)
+{
+ 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 sun4_mmu_base_device::merge_page_entry(uint32_t index, uint32_t data, uint32_t mem_mask)
+{
+ 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 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 <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)
@@ -454,15 +530,15 @@ 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 pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff];
+ 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)
{
@@ -481,6 +557,7 @@ uint32_t sun4c_mmu_device::insn_data_r(const uint32_t offset, const uint32_t mem
return ~0;
case 1: // type 1 space
+ m_type1_offset = offset;
return m_type1_r(tmp, mem_mask);
default:
@@ -495,7 +572,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 +597,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 +624,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)
{
@@ -566,6 +643,7 @@ void sun4c_mmu_device::insn_data_w(const uint32_t offset, const uint32_t data, c
return;
case 1: // type 1
+ m_type1_offset = offset;
m_type1_w(tmp, data, mem_mask);
return;
@@ -579,7 +657,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 +679,26 @@ void sun4c_mmu_device::insn_data_w(const uint32_t offset, const uint32_t data, c
}
}
+void sun4_mmu_base_device::l2p_command(const std::vector<std::string_view> &params)
+{
+ uint64_t addr;
+ if (!machine().debugger().console().validate_number_parameter(params[0], addr)) return;
+
+ addr &= 0xffffffff;
+ uint64_t offset = addr >> 2;
+
+ const uint32_t pmeg = m_curr_segmap_masked[(offset >> 16) & 0xfff];
+ const uint32_t entry_index = pmeg | ((offset >> m_seg_entry_shift) & m_seg_entry_mask);
+ const uint32_t tmp = m_pagemap[entry_index].page | (offset & m_page_mask);
+ const uint32_t 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! (tmp %08x, pmeg %d, entry %d PTE %08x)\n", addr, tmp << 2, pmeg, entry_index, entry_value);
+ }
+}
+