diff options
Diffstat (limited to 'src/devices/machine/sun4c_mmu.cpp')
-rw-r--r-- | src/devices/machine/sun4c_mmu.cpp | 667 |
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> ¶ms) +{ + 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); + } +} + |