summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author dxl <41547105+hp9k@users.noreply.github.com>2018-11-02 15:16:49 +0100
committer R. Belmont <rb6502@users.noreply.github.com>2018-11-02 10:16:49 -0400
commit56fb140e00319b6882d64e91d72e4469eeea340d (patch)
tree91783e63157c504b5653a46929e01acb59ec3835 /src
parentbc0a6560c4d82c16cb99810841649aab19002a70 (diff)
m68kmmu improvements (#4229)
* m68kmmu: PMMU improvements (nw) - handle RW bit in ATC cache properly - add page table walk that result in BUSERROR to ATC - fix ptest instruction - trap if PLOAD is called with MMU disabled on MC68851 - don't skip descriptor status update for page descriptors - set address in ptest to last descriptor address - add function code page table lookup - fix ptest level report in MMU SR - fix TT register matching (test RW bit, fix masking of bits) - decode fc field for pload instruction - fix decoding of pload instruction * m68kmmu: remove unused variable (nw) * m68kmmu: abort table search when WP is encountered * m68kmmu: various improvements * hp9k_3xx: call MMU buserror handler * m68kmmu: set M bit if root descriptor is of page type It seems like at least the 68030 sets the M bit in the MMU SR if the root descriptor is of PAGE type, so do a logical and between RW and the root type. * m68kmmu: fix comment * m68kmmu: rename descriptor types to more useful names * m68kmmu: set type for 8 byte table descriptors * m68kmmu: use iterative approach for table walking * style (nw) * fix ptest argument (nw) * hp9k_3xx: ignore buserror if it's caused by a page table walk (nw) * m68kmmu: initialize addr_out to 0 (nw) Otherwise we might return an arbitrary value if ptest can't find an entry. Shouldn't matter for the OS, but that change makes at least the compiler happy.
Diffstat (limited to 'src')
-rw-r--r--src/devices/cpu/m68000/m68000.h1
-rw-r--r--src/devices/cpu/m68000/m68kcpu.cpp32
-rw-r--r--src/devices/cpu/m68000/m68kmmu.h727
-rw-r--r--src/mame/drivers/hp9k_3xx.cpp3
4 files changed, 488 insertions, 275 deletions
diff --git a/src/devices/cpu/m68000/m68000.h b/src/devices/cpu/m68000/m68000.h
index 5d67e2a713f..fcceb9b5ac7 100644
--- a/src/devices/cpu/m68000/m68000.h
+++ b/src/devices/cpu/m68000/m68000.h
@@ -290,6 +290,7 @@ protected:
uint16_t m_mmu_tmp_buserror_rw; /* temporary hack: (first) bus error rw */
uint16_t m_mmu_tmp_buserror_sz; /* temporary hack: (first) bus error size` */
+ bool m_mmu_tablewalk; /* set when MMU walks page tables */
uint32_t m_ic_address[M68K_IC_SIZE]; /* instruction cache address data */
uint32_t m_ic_data[M68K_IC_SIZE]; /* instruction cache content data */
bool m_ic_valid[M68K_IC_SIZE]; /* instruction cache valid flags */
diff --git a/src/devices/cpu/m68000/m68kcpu.cpp b/src/devices/cpu/m68000/m68kcpu.cpp
index b0c26d00181..d57afa7acd7 100644
--- a/src/devices/cpu/m68000/m68kcpu.cpp
+++ b/src/devices/cpu/m68000/m68kcpu.cpp
@@ -725,7 +725,7 @@ bool m68000_base_device::memory_translate(int space, int intention, offs_t &addr
}
else
{
- address = pmmu_translate_addr_with_fc(address, mode, 1);
+ address = pmmu_translate_addr_with_fc<false, false>(address, mode, (intention & TRANSLATE_TYPE_MASK) == TRANSLATE_READ);
}
if ((m_mmu_tmp_sr & M68K_MMU_SR_INVALID) != 0) {
@@ -1280,7 +1280,7 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace)
m_readimm16 = [this, ocache](offs_t address) -> u16 {
if (m_pmmu_enabled) {
- address = pmmu_translate_addr(address);
+ address = pmmu_translate_addr(address, 1);
if (m_mmu_tmp_buserror_occurred)
return ~0;
}
@@ -1290,7 +1290,7 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace)
m_read8 = [this](offs_t address) -> u8 {
if (m_pmmu_enabled) {
- address = pmmu_translate_addr(address);
+ address = pmmu_translate_addr(address, 1);
if (m_mmu_tmp_buserror_occurred)
return ~0;
}
@@ -1299,12 +1299,12 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace)
m_read16 = [this](offs_t address) -> u16 {
if (m_pmmu_enabled) {
- u32 address0 = pmmu_translate_addr(address);
+ u32 address0 = pmmu_translate_addr(address, 1);
if (m_mmu_tmp_buserror_occurred)
return ~0;
if (WORD_ALIGNED(address))
return m_space->read_word(address0);
- u32 address1 = pmmu_translate_addr(address + 1);
+ u32 address1 = pmmu_translate_addr(address + 1, 1);
if (m_mmu_tmp_buserror_occurred)
return ~0;
u16 result = m_space->read_byte(address0) << 8;
@@ -1319,7 +1319,7 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace)
m_read32 = [this](offs_t address) -> u32 {
if (m_pmmu_enabled) {
- u32 address0 = pmmu_translate_addr(address);
+ u32 address0 = pmmu_translate_addr(address, 1);
if (m_mmu_tmp_buserror_occurred)
return ~0;
if ((address +3) & 0xfc)
@@ -1328,15 +1328,15 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace)
else if (DWORD_ALIGNED(address)) // 0
return m_space->read_dword(address0);
else {
- u32 address2 = pmmu_translate_addr(address+2);
+ u32 address2 = pmmu_translate_addr(address+2, 1);
if (m_mmu_tmp_buserror_occurred)
return ~0;
if (WORD_ALIGNED(address)) { // 2
u32 result = m_space->read_word(address0) << 16;
return result | m_space->read_word(address2);
}
- u32 address1 = pmmu_translate_addr(address+1);
- u32 address3 = pmmu_translate_addr(address+3);
+ u32 address1 = pmmu_translate_addr(address+1, 1);
+ u32 address3 = pmmu_translate_addr(address+3, 1);
if (m_mmu_tmp_buserror_occurred)
return ~0;
u32 result = m_space->read_byte(address0) << 24;
@@ -1357,7 +1357,7 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace)
m_write8 = [this](offs_t address, u8 data) {
if (m_pmmu_enabled) {
- address = pmmu_translate_addr(address);
+ address = pmmu_translate_addr(address, 0);
if (m_mmu_tmp_buserror_occurred)
return;
}
@@ -1366,14 +1366,14 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace)
m_write16 = [this](offs_t address, u16 data) {
if (m_pmmu_enabled) {
- u32 address0 = pmmu_translate_addr(address);
+ u32 address0 = pmmu_translate_addr(address, 0);
if (m_mmu_tmp_buserror_occurred)
return;
if (WORD_ALIGNED(address)) {
m_space->write_word(address0, data);
return;
}
- u32 address1 = pmmu_translate_addr(address + 1);
+ u32 address1 = pmmu_translate_addr(address + 1, 0);
if (m_mmu_tmp_buserror_occurred)
return;
m_space->write_byte(address0, data >> 8);
@@ -1391,7 +1391,7 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace)
m_write32 = [this](offs_t address, u32 data) {
if (m_pmmu_enabled) {
- u32 address0 = pmmu_translate_addr(address);
+ u32 address0 = pmmu_translate_addr(address, 0);
if (m_mmu_tmp_buserror_occurred)
return;
if ((address +3) & 0xfc) {
@@ -1401,7 +1401,7 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace)
m_space->write_dword(address0, data);
return;
} else {
- u32 address2 = pmmu_translate_addr(address+2);
+ u32 address2 = pmmu_translate_addr(address+2, 0);
if (m_mmu_tmp_buserror_occurred)
return;
if (WORD_ALIGNED(address)) { // 2
@@ -1409,8 +1409,8 @@ void m68000_base_device::init32mmu(address_space &space, address_space &ospace)
m_space->write_word(address2, data);
return;
}
- u32 address1 = pmmu_translate_addr(address+1);
- u32 address3 = pmmu_translate_addr(address+3);
+ u32 address1 = pmmu_translate_addr(address+1, 0);
+ u32 address3 = pmmu_translate_addr(address+3, 0);
if (m_mmu_tmp_buserror_occurred)
return;
m_space->write_byte(address0, data >> 24);
diff --git a/src/devices/cpu/m68000/m68kmmu.h b/src/devices/cpu/m68000/m68kmmu.h
index 60fda569f85..b519f63379f 100644
--- a/src/devices/cpu/m68000/m68kmmu.h
+++ b/src/devices/cpu/m68000/m68kmmu.h
@@ -1,14 +1,13 @@
// license:BSD-3-Clause
-// copyright-holders:R. Belmont, Hans Ostermeyer
-/*
- m68kmmu.h - PMMU implementation for 68851/68030/68040
- HMMU implementation for 68020 (II and LC variants)
+// copyright-holders:R. Belmont, Hans Ostermeyer, Sven Schnelle
- By R. Belmont and Hans Ostermeyer
-*/
+// m68kmmu.h - PMMU implementation for 68851/68030/68040
+// HMMU implementation for 68020 (II and LC variants)
-// MMU status register bit definitions
+// By R. Belmont and Hans Ostermeyer
+//
+// MMU status register bit definitions
#if 0
#define MMULOG logerror
@@ -16,42 +15,43 @@
#define MMULOG(...)
#endif
-static constexpr int M68K_MMU_SR_BUS_ERROR = 0x8000;
-static constexpr int M68K_MMU_SR_SUPERVISOR_ONLY = 0x2000;
-static constexpr int M68K_MMU_SR_WRITE_PROTECT = 0x0800;
-static constexpr int M68K_MMU_SR_INVALID = 0x0400;
-static constexpr int M68K_MMU_SR_MODIFIED = 0x0200;
-static constexpr int M68K_MMU_SR_LEVEL_0 = 0x0000;
-static constexpr int M68K_MMU_SR_LEVEL_1 = 0x0001;
-static constexpr int M68K_MMU_SR_LEVEL_2 = 0x0002;
-static constexpr int M68K_MMU_SR_LEVEL_3 = 0x0003;
+// MMU SR register fields
+static constexpr uint16_t M68K_MMU_SR_BUS_ERROR = 0x8000;
+static constexpr uint16_t M68K_MMU_SR_SUPERVISOR_ONLY = 0x2000;
+static constexpr uint16_t M68K_MMU_SR_WRITE_PROTECT = 0x0800;
+static constexpr uint16_t M68K_MMU_SR_INVALID = 0x0400;
+static constexpr uint16_t M68K_MMU_SR_MODIFIED = 0x0200;
+static constexpr uint16_t M68K_MMU_SR_TRANSPARENT = 0x0040;
// MMU translation table descriptor field definitions
-
-static constexpr int M68K_MMU_DF_DT = 0x0003;
-static constexpr int M68K_MMU_DF_DT0 = 0x0000;
-static constexpr int M68K_MMU_DF_DT1 = 0x0001;
-static constexpr int M68K_MMU_DF_DT2 = 0x0002;
-static constexpr int M68K_MMU_DF_DT3 = 0x0003;
-static constexpr int M68K_MMU_DF_WP = 0x0004;
-static constexpr int M68K_MMU_DF_USED = 0x0008;
-static constexpr int M68K_MMU_DF_MODIFIED = 0x0010;
-static constexpr int M68K_MMU_DF_CI = 0x0040;
-static constexpr int M68K_MMU_DF_SUPERVISOR = 0x0100;
+static constexpr uint32_t M68K_MMU_DF_DT = 0x00000003;
+static constexpr uint32_t M68K_MMU_DF_DT_INVALID = 0x00000000;
+static constexpr uint32_t M68K_MMU_DF_DT_PAGE = 0x00000001;
+static constexpr uint32_t M68K_MMU_DF_DT_TABLE_4BYTE = 0x00000002;
+static constexpr uint32_t M68K_MMU_DF_DT_TABLE_8BYTE = 0x00000003;
+static constexpr uint32_t M68K_MMU_DF_WP = 0x00000004;
+static constexpr uint32_t M68K_MMU_DF_USED = 0x00000008;
+static constexpr uint32_t M68K_MMU_DF_MODIFIED = 0x00000010;
+static constexpr uint32_t M68K_MMU_DF_CI = 0x00000040;
+static constexpr uint32_t M68K_MMU_DF_SUPERVISOR = 0000000100;
+static constexpr uint32_t M68K_MMU_DF_ADDR_MASK = 0xfffffff0;
+static constexpr uint32_t M68K_MMU_DF_IND_ADDR_MASK = 0xfffffffc;
// MMU ATC Fields
-
-static constexpr int M68K_MMU_ATC_BUSERROR = 0x08000000;
-static constexpr int M68K_MMU_ATC_CACHE_IN = 0x04000000;
-static constexpr int M68K_MMU_ATC_WRITE_PR = 0x02000000;
-static constexpr int M68K_MMU_ATC_MODIFIED = 0x01000000;
-static constexpr int M68K_MMU_ATC_MASK = 0x00ffffff;
-static constexpr int M68K_MMU_ATC_SHIFT = 8;
-static constexpr int M68K_MMU_ATC_VALID = 0x08000000;
+static constexpr uint32_t M68K_MMU_ATC_BUSERROR = 0x08000000;
+static constexpr uint32_t M68K_MMU_ATC_CACHE_IN = 0x04000000;
+static constexpr uint32_t M68K_MMU_ATC_WRITE_PR = 0x02000000;
+static constexpr uint32_t M68K_MMU_ATC_MODIFIED = 0x01000000;
+static constexpr uint32_t M68K_MMU_ATC_MASK = 0x00ffffff;
+static constexpr uint32_t M68K_MMU_ATC_SHIFT = 8;
+static constexpr uint32_t M68K_MMU_ATC_VALID = 0x08000000;
// MMU Translation Control register
-static constexpr int M68K_MMU_TC_SRE = 0x02000000;
+static constexpr uint32_t M68K_MMU_TC_SRE = 0x02000000;
+static constexpr uint32_t M68K_MMU_TC_FCL = 0x01000000;
+// TT register
+static constexpr uint16_t M68K_MMU_TT_ENABLE = 0x8000;
/* decodes the effective address */
uint32_t DECODE_EA_32(int ea)
{
@@ -120,15 +120,32 @@ void pmmu_set_buserror(uint32_t addr_in)
}
}
-/*
- pmmu_atc_add: adds this address to the ATC
-*/
-void pmmu_atc_add(uint32_t logical, uint32_t physical, int fc)
+
+// pmmu_atc_add: adds this address to the ATC
+void pmmu_atc_add(uint32_t logical, uint32_t physical, int fc, const int rw)
{
// get page size (i.e. # of bits to ignore); is 10 for Apollo
int ps = (m_mmu_tc >> 20) & 0xf;
// Note: exact emulation would use (logical >> ps) << (ps-8)
- uint32_t atc_tag = M68K_MMU_ATC_VALID | ((fc & 7) << 24)| logical >> ps;
+
+ uint32_t atc_tag = M68K_MMU_ATC_VALID | ((fc & 7) << 24) | logical >> ps;
+ uint32_t atc_data = (physical >> ps) << (ps - 8);
+
+
+ if (m_mmu_tmp_sr & (M68K_MMU_SR_BUS_ERROR|M68K_MMU_SR_INVALID|M68K_MMU_SR_SUPERVISOR_ONLY))
+ {
+ atc_data |= M68K_MMU_ATC_BUSERROR;
+ }
+
+ if (m_mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT)
+ {
+ atc_data |= M68K_MMU_ATC_WRITE_PR;
+ }
+
+ if (!rw && !(m_mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT))
+ {
+ atc_data |= M68K_MMU_ATC_MODIFIED;
+ }
// first see if this is already in the cache
for (int i = 0; i < MMU_ATC_ENTRIES; i++)
@@ -136,6 +153,8 @@ void pmmu_atc_add(uint32_t logical, uint32_t physical, int fc)
// if tag bits and function code match, don't add
if (m_mmu_atc_tag[i] == atc_tag)
{
+ MMULOG("%s: hit, old %08x new %08x\n", __func__, m_mmu_atc_data[i], atc_data);
+ m_mmu_atc_data[i] = atc_data;
return;
}
}
@@ -163,256 +182,383 @@ void pmmu_atc_add(uint32_t logical, uint32_t physical, int fc)
}
// add the entry
- MMULOG("ATC[%2d] add: log %08x -> phys %08x (fc=%d)\n", found, (logical >> ps) << ps, (physical >> ps) << ps, fc);
+ MMULOG("ATC[%2d] add: log %08x -> phys %08x (fc=%d) data=%08x\n",
+ found, (logical >> ps) << ps, (physical >> ps) << ps, fc, atc_data);
m_mmu_atc_tag[found] = atc_tag;
- m_mmu_atc_data[found] = (physical >> ps) << (ps - 8);
-
- if (m_mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT)
- {
- m_mmu_atc_data[found] |= M68K_MMU_ATC_WRITE_PR;
- }
+ m_mmu_atc_data[found] = atc_data;
}
-/*
- pmmu_atc_flush: flush entire ATC
- 7fff0003 001ffd10 80f05750 is what should load
-*/
+// pmmu_atc_flush: flush entire ATC
+// 7fff0003 001ffd10 80f05750 is what should load
void pmmu_atc_flush()
{
MMULOG("ATC flush: pc=%08x\n", m_ppc);
+ std::fill(std::begin(m_mmu_atc_tag), std::end(m_mmu_atc_tag), 0);
+ m_mmu_atc_rr = 0;
+}
+
+template<bool ptest>
+bool pmmu_atc_lookup(const uint32_t addr_in, const int fc, const bool rw,
+ uint32_t& addr_out)
+{
+ MMULOG("%s: LOOKUP addr_in=%08x, fc=%d, ptest=%d\n", __func__, addr_in, fc, ptest);
+ const int ps = (m_mmu_tc >> 20) & 0xf;
+ const uint32_t atc_tag = M68K_MMU_ATC_VALID | ((fc & 7) << 24) | (addr_in >> ps);
for (int i = 0; i < MMU_ATC_ENTRIES; i++)
{
- m_mmu_atc_tag[i] = 0;
- }
- m_mmu_atc_rr = 0;
-}
+ if (m_mmu_atc_tag[i] != atc_tag)
+ {
+ continue;
+ }
+ const uint32_t atc_data = m_mmu_atc_data[i];
-inline uint32_t get_dt2_table_entry(uint32_t tptr, uint8_t ptest, bool indirect)
-{
- uint32_t tbl_entry = m_program->read_dword(tptr);
- uint32_t dt = tbl_entry & M68K_MMU_DF_DT;
+ if (!ptest && !rw)
+ {
+ // According to MC86030UM:
+ // "If the M bit is clear and a write access to this logical
+ // address is attempted, the MC68030 aborts the access and initiates a table
+ // search, setting the M bit in the page descriptor, invalidating the old ATC
+ // entry, and creating a new entry with the M bit set.
+ if (!(atc_data & M68K_MMU_ATC_MODIFIED))
+ {
+ m_mmu_atc_tag[i] = 0;
+ continue;
+ }
+ }
- if (!indirect)
- m_mmu_tmp_sr |= tbl_entry & 0x0004 ? M68K_MMU_SR_WRITE_PROTECT : 0;
+ m_mmu_tmp_sr = 0;
+ if (atc_data & M68K_MMU_ATC_MODIFIED)
+ {
+ m_mmu_tmp_sr |= M68K_MMU_SR_MODIFIED;
+ }
- if (!ptest && !indirect && dt != M68K_MMU_DF_DT0)
- {
- if (dt == M68K_MMU_DF_DT1 && !m_mmu_tmp_rw && !(m_mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT))
+ if (atc_data & M68K_MMU_ATC_WRITE_PR)
{
- // set used and modified
- m_program->write_dword( tptr, tbl_entry | M68K_MMU_DF_USED | M68K_MMU_DF_MODIFIED);
+ m_mmu_tmp_sr |= M68K_MMU_SR_WRITE_PROTECT;
}
- else if (!(tbl_entry & M68K_MMU_DF_USED))
+
+ if (atc_data & M68K_MMU_ATC_BUSERROR)
{
- m_program->write_dword( tptr, tbl_entry | M68K_MMU_DF_USED);
+ m_mmu_tmp_sr |= M68K_MMU_SR_BUS_ERROR|M68K_MMU_SR_INVALID;
}
+ addr_out = (atc_data << 8) | (addr_in & ~(~0 << ps));
+ MMULOG("%s: addr_in=%08x, addr_out=%08x, MMU SR %04x\n",
+ __func__, addr_in, addr_out, m_mmu_tmp_sr);
+ return true;
+ }
+ MMULOG("%s: lookup failed\n", __func__);
+ if (ptest)
+ {
+ m_mmu_tmp_sr = M68K_MMU_SR_INVALID;
}
- return tbl_entry;
+ return false;
}
-inline uint32_t get_dt3_table_entry(uint32_t tptr, uint8_t fc, uint8_t ptest)
+bool pmmu_match_tt(const uint32_t addr_in, const int fc, const uint32_t tt, const bool rw)
{
- uint32_t tbl_entry2 = m_program->read_dword(tptr);
- uint32_t tbl_entry = m_program->read_dword(tptr + 4);
- uint32_t dt = tbl_entry2 & M68K_MMU_DF_DT;
+ if (!(tt & M68K_MMU_TT_ENABLE))
+ {
+ return false;
+ }
- m_mmu_tmp_sr |= ((tbl_entry2 & 0x0100) && !(fc & 4)) ? M68K_MMU_SR_SUPERVISOR_ONLY : 0;
- m_mmu_tmp_sr |= tbl_entry2 & 0x0004 ? M68K_MMU_SR_WRITE_PROTECT : 0;
+ // transparent translation enabled
+ const uint32_t address_base = tt & 0xff000000;
+ const uint32_t address_mask = ((tt << 8) & 0xff000000) ^ 0xff000000;
+ const uint32_t fcmask = (~tt) & 7;
+ const uint32_t fcbits = (tt >> 4) & 7;
+ const bool rwmask = (~tt & 0x100);
+ const bool rwbit = (tt & 0x200);
+
+ if ((addr_in & address_mask) != (address_base & address_mask))
+ {
+ return false;
+ }
- if (!ptest && dt != M68K_MMU_DF_DT0)
+ if ((fc & fcmask) != (fcbits & fcmask))
{
- if (dt == M68K_MMU_DF_DT1 && !m_mmu_tmp_rw && !(m_mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT))
- {
- // set modified
- m_program->write_dword( tptr, tbl_entry2 | M68K_MMU_DF_USED | M68K_MMU_DF_MODIFIED);
- }
- else if (!(tbl_entry2 & M68K_MMU_DF_USED))
- {
- m_program->write_dword( tptr, tbl_entry2 | M68K_MMU_DF_USED);
- }
+ return false;
}
- return (tbl_entry & ~M68K_MMU_DF_DT) | dt;
+ if ((rw & rwmask) != (rwbit & rwmask))
+ {
+ return false;
+ }
+
+ m_mmu_tmp_sr |= M68K_MMU_SR_TRANSPARENT;
+ return true;
}
-bool pmmu_atc_lookup(const uint32_t addr_in, const int fc, const int ptest, uint32_t& addr_out)
+void update_descriptor(const uint32_t tptr, const int type, const uint32_t entry, const bool rw)
{
- const int ps = (m_mmu_tc >> 20) & 0xf;
- const uint32_t atc_tag = M68K_MMU_ATC_VALID | ((fc & 7) << 24) | (addr_in >> ps);
-
- for (int i = 0; i < MMU_ATC_ENTRIES; i++)
+ if (type == M68K_MMU_DF_DT_PAGE && !rw &&
+ !(entry & M68K_MMU_DF_MODIFIED) &&
+ !(entry & M68K_MMU_DF_WP))
{
- if (m_mmu_atc_tag[i] != atc_tag)
- continue;
+ MMULOG("%s: set M+U at %08x\n", __func__, tptr);
+ m_program->write_dword(tptr, entry | M68K_MMU_DF_USED | M68K_MMU_DF_MODIFIED);
+ }
+ else if (type != M68K_MMU_DF_DT_INVALID && !(entry & M68K_MMU_DF_USED))
+ {
+ MMULOG("%s: set U at %08x\n", __func__, tptr);
+ m_program->write_dword(tptr, entry | M68K_MMU_DF_USED);
+ }
+}
- if (!m_mmu_tmp_rw && (m_mmu_atc_data[i] & M68K_MMU_ATC_WRITE_PR))
- continue;
- if (!m_mmu_tmp_rw && !(m_mmu_atc_data[i] & M68K_MMU_ATC_MODIFIED))
- continue;
+template<bool _long>
+void update_sr(const int type, const uint32_t tbl_entry)
+{
+ switch(type)
+ {
+ case M68K_MMU_DF_DT_INVALID:
+ // Invalid has no flags
+ break;
- // read access or write access and not write protected
- if (!ptest)
+ case M68K_MMU_DF_DT_PAGE:
+ if (tbl_entry & M68K_MMU_DF_MODIFIED)
{
- // FIXME: must set modified in PMMU tables as well
- m_mmu_atc_data[i] |= (!m_mmu_tmp_rw ? M68K_MMU_ATC_MODIFIED : 0);
+ m_mmu_tmp_sr |= M68K_MMU_SR_MODIFIED;
}
- else
- {
- uint16_t sr = 0;
+ // fall through
- if (m_mmu_atc_data[i] & M68K_MMU_ATC_MODIFIED)
- sr = M68K_MMU_SR_MODIFIED;
+ case M68K_MMU_DF_DT_TABLE_4BYTE:
+ // fall through
- if (m_mmu_atc_data[i] & M68K_MMU_ATC_WRITE_PR)
- sr |= M68K_MMU_SR_WRITE_PROTECT;
+ case M68K_MMU_DF_DT_TABLE_8BYTE:
- if (m_mmu_atc_data[i] & M68K_MMU_ATC_BUSERROR)
- sr |= M68K_MMU_SR_BUS_ERROR|M68K_MMU_SR_INVALID;
- m_mmu_tmp_sr = sr;
+ if (tbl_entry & M68K_MMU_DF_WP)
+ {
+ m_mmu_tmp_sr |= M68K_MMU_SR_WRITE_PROTECT;
}
- addr_out = (m_mmu_atc_data[i] << 8) | (addr_in & ~(~0 << ps));
- return true;
+
+ if (_long && (tbl_entry & M68K_MMU_DF_SUPERVISOR))
+ {
+ m_mmu_tmp_sr |= M68K_MMU_SR_SUPERVISOR_ONLY;
+ }
+ break;
+ default:
+ break;
}
- if (ptest)
- m_mmu_tmp_sr = M68K_MMU_SR_INVALID;
- return false;
}
-bool pmmu_match_tt(uint32_t addr_in, int fc, uint32_t tt)
+template<bool ptest>
+bool pmmu_walk_tables(uint32_t addr_in, int type, uint32_t table, const int fc,
+ const int limit, const bool rw, uint32_t &addr_out)
{
- if (!(tt & 0x8000))
- return false;
+ int level = 0;
+ const uint32_t bits = m_mmu_tc & 0xffff;
+ const int pagesize = (m_mmu_tc >> 20) & 0xf;
+ const int is = (m_mmu_tc >> 16) & 0xf;
+ int bitpos = 12;
+ int resolved = 0;
+ int pageshift = is;
- // transparent translation enabled
- uint32_t address_base = tt & 0xff000000;
- uint32_t address_mask = ((tt << 8) & 0xff000000) ^ 0xff000000;
- return (addr_in & address_mask) == address_base && (fc & ~tt) == ((tt >> 4) & 7);
-}
+ addr_in <<= is;
-bool pmmu_walk_table(uint32_t& tbl_entry, uint32_t addr_in, int shift, int bits, int nextbits, bool ptest, int fc, int level, uint32_t &addr_out)
-{
- // get table offset
- uint32_t tofs;
- uint32_t tptr = tbl_entry & 0xfffffff0;
- int ps = (m_mmu_tc >> 20) & 0xf;
- // get initial shift (# of top bits to ignore)
- int is = (m_mmu_tc >> 16) & 0xf;
-
- shift += is;
- tofs = (addr_in << shift) >> (32 - bits);
+ m_mmu_tablewalk = true;
- MMULOG("walk_table: addr_in %08x, tbl_entry %08x, tofs %08x shift %d, bits %d, nextbits %d\n", addr_in, tbl_entry, tofs, shift, bits, nextbits);
+ if (m_mmu_tc & M68K_MMU_TC_FCL)
+ {
+ bitpos = 16;
+ }
- switch (tbl_entry & M68K_MMU_DF_DT)
+ do
{
- case M68K_MMU_DF_DT0: // invalid, will cause MMU exception
- m_mmu_tmp_sr &= 0xfffffff0;
- m_mmu_tmp_sr |= M68K_MMU_SR_INVALID | level;
- addr_out = tbl_entry;
- MMULOG("PMMU: DT0 PC=%x (addr_in %08x -> %08x)\n", m_ppc, addr_in, addr_out);
- return true;
-
- case M68K_MMU_DF_DT1: // page descriptor, will cause direct mapping
- tbl_entry &= (~0 << ps);
- addr_out = ((addr_in << shift) >> shift) + tbl_entry;
- MMULOG("PMMU: DT1 PC=%x (addr_in %08x -> %08x)\n", m_ppc, addr_in, addr_out);
- return true;
-
- case M68K_MMU_DF_DT2: // valid 4 byte descriptors
- tofs *= 4;
-
- if (bits)
+ const int indexbits = (bits >> bitpos) & 0xf;
+ const int table_index = (bitpos == 16) ? fc : (addr_in >> (32 - indexbits));
+ bitpos -= 4;
+ const bool indirect = (!bitpos || !(bits >> bitpos)) && indexbits;
+ uint32_t tbl_entry, tbl_entry2;
+
+ MMULOG("%s: type %d, table %08x, addr_in %08x, indexbits %d, pageshift %d, indirect %d table_index %08x, rw=%d fc=%d\n",
+ __func__, type, table, addr_in, indexbits, pageshift, indirect, table_index, rw, fc);
+
+ switch(type)
+ {
+ case M68K_MMU_DF_DT_INVALID: // invalid, will cause MMU exception
+ m_mmu_tmp_sr = M68K_MMU_SR_INVALID;
+ MMULOG("PMMU: DT0 PC=%x (addr_in %08x -> %08x)\n", m_ppc, addr_in, addr_out);
+ resolved = 1;
+ break;
+
+ case M68K_MMU_DF_DT_PAGE: // page descriptor, will cause direct mapping
+ if (!ptest)
+ {
+ table &= ~0 << pagesize;
+ addr_out = table + (addr_in >> pageshift);
+ }
+ resolved = 1;
+ break;
+
+ case M68K_MMU_DF_DT_TABLE_4BYTE: // valid 4 byte descriptors
+ level++;
+ addr_out = table + (table_index << 2);
+ tbl_entry = m_program->read_dword(addr_out);
+ type = tbl_entry & M68K_MMU_DF_DT;
+
+ if (indirect && (type == 2 || type == 3))
+ {
+ level++;
+ MMULOG("SHORT INDIRECT DESC: %08x\n", tbl_entry);
+ addr_out = tbl_entry & M68K_MMU_DF_IND_ADDR_MASK;
+ tbl_entry = m_program->read_dword(addr_out);
+ type = tbl_entry & M68K_MMU_DF_DT;
+ }
+
+ MMULOG("SHORT DESC: %08x\n", tbl_entry);
+ table = tbl_entry & M68K_MMU_DF_ADDR_MASK;
+ update_sr<0>(type, tbl_entry);
+ if (!ptest)
+ {
+ update_descriptor(addr_out, type, tbl_entry, rw);
+ }
+ break;
+
+ case M68K_MMU_DF_DT_TABLE_8BYTE: // valid 8 byte descriptors
+ level++;
+ addr_out = table + (table_index << 3);
+ tbl_entry = m_program->read_dword(addr_out);
+ tbl_entry2 = m_program->read_dword(addr_out + 4);
+ type = tbl_entry & M68K_MMU_DF_DT;
+
+ if (indirect && (type == 2 || type == 3))
+ {
+ level++;
+ MMULOG("LONG INDIRECT DESC: %08x%08x\n", tbl_entry, tbl_entry2);
+ addr_out = tbl_entry2 & M68K_MMU_DF_IND_ADDR_MASK;
+ tbl_entry = m_program->read_dword(addr_out);
+ tbl_entry2 = m_program->read_dword(addr_out);
+ type = tbl_entry & M68K_MMU_DF_DT;
+ }
+
+ MMULOG("LONG DESC: %08x %08x\n", tbl_entry, tbl_entry2);
+ table = tbl_entry2 & M68K_MMU_DF_ADDR_MASK;
+ update_sr<1>(type, tbl_entry);
+ if (!ptest)
+ {
+ update_descriptor(addr_out, type, tbl_entry, rw);
+ }
+ break;
+ }
+
+ if (m_mmu_tmp_sr & M68K_MMU_SR_BUS_ERROR)
+ {
+ // Bus erorr during page table walking is always fatal
+ resolved = 1;
+ break;
+ }
+
+ if (!ptest)
+ {
+ if (!rw && (m_mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT))
{
- tbl_entry = get_dt2_table_entry(tptr + tofs, ptest, !nextbits);
- return false;
- } else
+ resolved = 1;
+ break;
+ }
+
+ if (!(fc & 4) && (m_mmu_tmp_sr & M68K_MMU_SR_SUPERVISOR_ONLY))
{
- tptr = tbl_entry & 0xfffffffc;
- tbl_entry = get_dt2_table_entry(tptr, ptest, 0);
- return false;
+ resolved = 1;
+ break;
}
- MMULOG("PMMU: %sDT2 read table entry at %08x: %08x\n", bits ? "" : "indirect ", tofs + tptr, tbl_entry);
- return false;
-
- case M68K_MMU_DF_DT3: // valid 8 byte descriptors
- tofs *= 8;
- tbl_entry = get_dt3_table_entry(tofs + tptr, fc, ptest);
- MMULOG("PMMU: DT3 read table A entries at %08x\n", tofs + tptr, tbl_entry);
- return false;
- }
- return true;
+
+ }
+ addr_in <<= indexbits;
+ pageshift += indexbits;
+ } while(level < limit && !resolved);
+
+
+ m_mmu_tmp_sr &= 0xfff0;
+ m_mmu_tmp_sr |= level;
+ MMULOG("MMU SR after walk: %04X\n", m_mmu_tmp_sr);
+ m_mmu_tablewalk = false;
+ return resolved;
}
-/*
- pmmu_translate_addr_with_fc: perform 68851/68030-style PMMU address translation
-*/
-uint32_t pmmu_translate_addr_with_fc(uint32_t addr_in, uint8_t fc, uint8_t ptest)
+// pmmu_translate_addr_with_fc: perform 68851/68030-style PMMU address translation
+template<bool ptest, bool pload>
+uint32_t pmmu_translate_addr_with_fc(uint32_t addr_in, uint8_t fc, bool rw, const int limit = 7)
{
- uint32_t addr_out, tbl_entry;
- uint32_t abits, bbits, cbits, dbits;
+ uint32_t addr_out = 0;
+
+ MMULOG("%s: addr_in=%08x, fc=%d, ptest=%d, rw=%d, limit=%d\n",
+ __func__, addr_in, fc, ptest, rw, limit);
m_mmu_tmp_sr = 0;
- if (fc == 7 ||
- pmmu_match_tt(addr_in, fc, m_mmu_tt0) ||
- pmmu_match_tt(addr_in, fc, m_mmu_tt1))
+ if (pmmu_match_tt(addr_in, fc, m_mmu_tt0, rw) ||
+ pmmu_match_tt(addr_in, fc, m_mmu_tt1, rw) ||
+ fc == 7)
{
return addr_in;
}
- if (pmmu_atc_lookup(addr_in, fc, ptest, addr_out))
+ if (ptest && limit == 0)
+ {
+ pmmu_atc_lookup<true>(addr_in, fc, rw, addr_out);
+ return addr_out;
+ }
+
+ if (!ptest && pmmu_atc_lookup<false>(addr_in, fc, rw, addr_out))
{
+ if (pload)
+ {
+ return addr_out;
+ }
+
+ if ((m_mmu_tmp_sr & M68K_MMU_SR_BUS_ERROR) || (!rw && (m_mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT)))
+ {
+ MMULOG("set atc hit buserror: addr_in=%08x, addr_out=%x, rw=%x, fc=%d, sz=%d\n",
+ addr_in, addr_out, m_mmu_tmp_rw, m_mmu_tmp_fc, m_mmu_tmp_sz);
+ pmmu_set_buserror(addr_in);
+ }
return addr_out;
}
+ int type;
+ uint32_t tbl_addr;
// if SRP is enabled and we're in supervisor mode, use it
if ((m_mmu_tc & M68K_MMU_TC_SRE) && (fc & 4))
{
- tbl_entry = (m_mmu_srp_aptr & 0xfffffff0) | (m_mmu_srp_limit & M68K_MMU_DF_DT);
+ tbl_addr = m_mmu_srp_aptr & M68K_MMU_DF_ADDR_MASK;
+ type = m_mmu_srp_limit & M68K_MMU_DF_DT;
}
else // else use the CRP
{
- tbl_entry = (m_mmu_crp_aptr & 0xfffffff0) | (m_mmu_crp_limit & M68K_MMU_DF_DT);
+ tbl_addr = m_mmu_crp_aptr & M68K_MMU_DF_ADDR_MASK;
+ type = m_mmu_crp_limit & M68K_MMU_DF_DT;
}
- m_mmu_tmp_sr = 0;
- abits = (m_mmu_tc >> 12) & 0xf;
- bbits = (m_mmu_tc >> 8) & 0xf;
- cbits = (m_mmu_tc >> 4) & 0xf;
- dbits = m_mmu_tc & 0x0f;
-
-
- if (!pmmu_walk_table(tbl_entry, addr_in, 0 , abits, bbits, ptest, fc, 0, addr_out) &&
- !pmmu_walk_table(tbl_entry, addr_in, abits , bbits, cbits, ptest, fc, 2, addr_out) &&
- !pmmu_walk_table(tbl_entry, addr_in, abits + bbits , cbits, dbits, ptest, fc, 3, addr_out) &&
- !pmmu_walk_table(tbl_entry, addr_in, abits + bbits + cbits , dbits, 0, ptest, fc, 4, addr_out) &&
- !pmmu_walk_table(tbl_entry, addr_in, abits + bbits + cbits + dbits, 0, 0, ptest, fc, 5, addr_out))
+ if (!pmmu_walk_tables<ptest>(addr_in, type, tbl_addr, fc, limit, rw, addr_out))
{
fatalerror("Table walk did not resolve\n");
}
- if (!ptest)
+ if (ptest)
{
- if ((m_mmu_tmp_sr & (M68K_MMU_SR_INVALID|M68K_MMU_SR_SUPERVISOR_ONLY)) ||
- ((m_mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT) && !m_mmu_tmp_rw))
- {
- pmmu_set_buserror(addr_in);
+ return addr_out;
+ }
- }
+ if ((m_mmu_tmp_sr & (M68K_MMU_SR_INVALID|M68K_MMU_SR_SUPERVISOR_ONLY)) ||
+ ((m_mmu_tmp_sr & M68K_MMU_SR_WRITE_PROTECT) && !rw))
+ {
- if (!m_mmu_tmp_buserror_occurred)
+ if (!pload)
{
- // we add only valid entries
- pmmu_atc_add(addr_in, addr_out, fc);
+ MMULOG("%s: set buserror (SR %04X)\n", __func__, m_mmu_tmp_sr);
+ pmmu_set_buserror(addr_in);
}
}
- MMULOG("PMMU: [%08x] => [%08x]\n", addr_in, addr_out);
+ // it seems like at least the 68030 sets the M bit in the MMU SR
+ // if the root descriptor is of PAGE type, so do a logical and
+ // between RW and the root type
+ pmmu_atc_add(addr_in, addr_out, fc, rw && type != 1);
+ MMULOG("PMMU: [%08x] => [%08x] (SR %04x)\n", addr_in, addr_out, m_mmu_tmp_sr);
return addr_out;
}
@@ -444,7 +590,7 @@ uint32_t pmmu_translate_addr_with_fc_040(uint32_t addr_in, uint8_t fc, uint8_t p
fatalerror("68040: function code %d is neither data nor program!\n", fc & 7);
}
- if (tt0 & 0x8000)
+ if (tt0 & M68K_MMU_TT_ENABLE)
{
static constexpr int fcmask[4] = { 4, 4, 0, 0 };
static constexpr int fcmatch[4] = { 0, 4, 0, 0 };
@@ -464,7 +610,7 @@ uint32_t pmmu_translate_addr_with_fc_040(uint32_t addr_in, uint8_t fc, uint8_t p
}
}
- if (tt1 & 0x8000)
+ if (tt1 & M68K_MMU_TT_ENABLE)
{
static int fcmask[4] = { 4, 4, 0, 0 };
static int fcmatch[4] = { 0, 4, 0, 0 };
@@ -662,10 +808,8 @@ uint32_t pmmu_translate_addr_with_fc_040(uint32_t addr_in, uint8_t fc, uint8_t p
return addr_out;
}
-/*
- pmmu_translate_addr: perform 68851/68030-style PMMU address translation
-*/
-uint32_t pmmu_translate_addr(uint32_t addr_in)
+// pmmu_translate_addr: perform 68851/68030-style PMMU address translation
+uint32_t pmmu_translate_addr(uint32_t addr_in, const bool rw)
{
uint32_t addr_out;
@@ -675,62 +819,96 @@ uint32_t pmmu_translate_addr(uint32_t addr_in)
}
else
{
- addr_out = pmmu_translate_addr_with_fc(addr_in, m_mmu_tmp_fc, 0);
+ addr_out = pmmu_translate_addr_with_fc<false, false>(addr_in, m_mmu_tmp_fc, rw);
}
-
-// if (m_mmu_tmp_buserror_occurred > 0)
-// {
-// MMULOG("PMMU: pc=%08x sp=%08x va=%08x pa=%08x - invalid Table mode for level=%d (buserror %d)\n",
-// m_ppc, REG_A()[7], addr_in, addr_out, m_mmu_tmp_sr & M68K_MMU_SR_LEVEL_3,
-// m_mmu_tmp_buserror_occurred);
-// }
-
return addr_out;
}
-/*
- m68851_mmu_ops: COP 0 MMU opcode handling
-*/
+// m68851_mmu_ops: COP 0 MMU opcode handling
+
+int fc_from_modes(const uint16_t modes)
+{
+ if ((modes & 0x1f) == 0)
+ {
+ return m_sfc;
+ }
+
+ if ((modes & 0x1f) == 1)
+ {
+ return m_dfc;
+ }
+
+ if (m_cpu_type & CPU_TYPE_030)
+ {
+ // 68030 has 3 bits fc, but 68851 4 bits
+ if (((modes >> 3) & 3) == 1)
+ {
+ return REG_D()[modes & 7] & 0x7;
+ }
+
+ if (((modes >> 3) & 3) == 2)
+ {
+ return modes & 7;
+ }
+ }
+ else
+ {
+ if (((modes >> 3) & 3) == 1)
+ {
+ return REG_D()[modes & 7] & 0xf;
+ }
+
+ if (modes & 0x10)
+ {
+ return modes & 0xf;
+ }
+ }
+
+
+ fatalerror("%s: unknown fc mode: 0x%02xn", __func__, modes & 0x1f);
+ return 0;
+}
void m68851_pload(const uint32_t ea, const uint16_t modes)
{
uint32_t ltmp = DECODE_EA_32(ea);
- uint32_t ptmp;
+ const int fc = fc_from_modes(modes);
+ bool rw = (modes & 0x200);
- ptmp = ltmp;
- if (m_pmmu_enabled)
+ MMULOG("%s: PLOAD%c addr=%08x, fc=%d\n", __func__, rw ? 'R' : 'W', ltmp, fc);
+
+ // MC68851 traps if MMU is not enabled, 030 not
+ if (m_pmmu_enabled || (m_cpu_type & CPU_TYPE_030))
{
if (CPU_TYPE_IS_040_PLUS())
{
- ptmp = pmmu_translate_addr_with_fc_040(ltmp, modes & 0x07, 0);
+ pmmu_translate_addr_with_fc_040(ltmp, fc, 0);
}
else
{
- ptmp = pmmu_translate_addr_with_fc(ltmp, modes & 0x07, 0);
+ pmmu_translate_addr_with_fc<false,true>(ltmp, fc, rw);
}
}
-
- MMULOG("680x0: PLOADing ATC with logical %08x => phys %08x\n", ltmp, ptmp);
- // FIXME: rw bit?
- pmmu_atc_add(ltmp, ptmp, modes & 0x07);
+ else
+ {
+ MMULOG("PLOAD with MMU disabled on MC68851\n");
+ m68ki_exception_trap(57);
+ return;
+ }
}
void m68851_ptest(const uint32_t ea, const uint16_t modes)
{
uint32_t v_addr = DECODE_EA_32(ea);
uint32_t p_addr;
- uint32_t fc = modes & 0x1f;
- switch (fc >> 3) {
- case 0:
- fc = fc == 0 ? m_sfc : m_dfc;
- break;
- case 1:
- fc = REG_D()[fc &7] &7;
- break;
- case 2:
- fc &=7;
- break;
- }
+
+ const int level = (modes >> 10) & 7;
+ const bool rw = (modes & 0x200);
+ const int fc = fc_from_modes(modes);
+
+ MMULOG("PMMU: PTEST%c (%04X) pc=%08x sp=%08x va=%08x fc=%x level=%x a=%d, areg=%d\n",
+ rw ? 'R' : 'W', modes, m_ppc, REG_A()[7], v_addr, fc, level,
+ (modes & 0x100) ? 1 : 0, (modes >> 5) & 7);
if (CPU_TYPE_IS_040_PLUS())
{
@@ -738,13 +916,12 @@ void m68851_ptest(const uint32_t ea, const uint16_t modes)
}
else
{
- p_addr = pmmu_translate_addr_with_fc(v_addr, fc, 1);
+ p_addr = pmmu_translate_addr_with_fc<true, false>(v_addr, fc, rw, level);
}
- m_mmu_sr = m_mmu_tmp_sr;
- MMULOG("PMMU: pc=%08x sp=%08x va=%08x pa=%08x PTEST fc=%x level=%x mmu_sr=%04x\n",
- m_ppc, REG_A()[7], v_addr, p_addr, fc, (modes >> 10) & 0x07, m_mmu_sr);
+ m_mmu_sr = m_mmu_tmp_sr;
+ MMULOG("PMMU: PTEST result: %04x pa=%08x\n", m_mmu_sr, p_addr);
if (modes & 0x100)
{
int areg = (modes >> 5) & 7;
@@ -781,8 +958,14 @@ void m68851_pmove_get(uint32_t ea, uint16_t modes)
default:
logerror("680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, m_pc);
- break;
+ return;
}
+
+ if (!(modes & 0x100)) // flush ATC on moves to TC, SRP, CRP, TT with FD bit clear
+ {
+ pmmu_atc_flush();
+ }
+
}
void m68851_pmove_put(uint32_t ea, uint16_t modes)
@@ -794,24 +977,29 @@ void m68851_pmove_put(uint32_t ea, uint16_t modes)
{
uint32_t temp = READ_EA_32(ea);
- if (((modes>>10) & 7) == 2)
+ if (((modes >> 10) & 7) == 2)
{
MMULOG("WRITE TT0 = 0x%08x\n", m_mmu_tt0);
m_mmu_tt0 = temp;
}
- else if (((modes>>10) & 7) == 3)
+ else if (((modes >> 10) & 7) == 3)
{
MMULOG("WRITE TT1 = 0x%08x\n", m_mmu_tt1);
m_mmu_tt1 = temp;
}
break;
+
+ if (!(modes & 0x100))
+ {
+ pmmu_atc_flush();
+ }
}
case 1:
logerror("680x0: unknown PMOVE case 1, PC %x\n", m_pc);
break;
case 2:
- switch ((modes>>10) & 7)
+ switch ((modes >> 10) & 7)
{
case 0: // translation control register
m_mmu_tc = READ_EA_32(ea);
@@ -820,11 +1008,13 @@ void m68851_pmove_put(uint32_t ea, uint16_t modes)
if (m_mmu_tc & 0x80000000)
{
int bits = 0;
- for(int shift = 20; shift >= 0; shift -= 4) {
+ for (int shift = 20; shift >= 0; shift -= 4)
+ {
bits += (m_mmu_tc >> shift) & 0x0f;
}
- if (bits != 32 || !((m_mmu_tc >> 23) & 1)) {
+ if (bits != 32 || !((m_mmu_tc >> 23) & 1))
+ {
logerror("MMU: TC invalid!\n");
m_mmu_tc &= ~0x80000000;
m68ki_exception_trap(EXCEPTION_MMU_CONFIGURATION);
@@ -847,11 +1037,12 @@ void m68851_pmove_put(uint32_t ea, uint16_t modes)
case 2: // supervisor root pointer
temp64 = READ_EA_64(ea);
- m_mmu_srp_limit = (temp64>>32) & 0xffffffff;
+ m_mmu_srp_limit = (temp64 >> 32) & 0xffffffff;
m_mmu_srp_aptr = temp64 & 0xffffffff;
MMULOG("PMMU: SRP limit = %08x aptr = %08x\n", m_mmu_srp_limit, m_mmu_srp_aptr);
// SRP type 0 is not allowed
- if ((m_mmu_srp_limit & 3) == 0) {
+ if ((m_mmu_srp_limit & 3) == 0)
+ {
m68ki_exception_trap(EXCEPTION_MMU_CONFIGURATION);
return;
}
@@ -864,16 +1055,16 @@ void m68851_pmove_put(uint32_t ea, uint16_t modes)
case 3: // CPU root pointer
temp64 = READ_EA_64(ea);
- m_mmu_crp_limit = (temp64>>32) & 0xffffffff;
+ m_mmu_crp_limit = (temp64 >> 32) & 0xffffffff;
m_mmu_crp_aptr = temp64 & 0xffffffff;
MMULOG("PMMU: CRP limit = %08x aptr = %08x\n", m_mmu_crp_limit, m_mmu_crp_aptr);
// CRP type 0 is not allowed
- if ((m_mmu_crp_limit & 3) == 0) {
+ if ((m_mmu_crp_limit & 3) == 0)
+ {
m68ki_exception_trap(EXCEPTION_MMU_CONFIGURATION);
return;
}
-
if (!(modes & 0x100))
{
pmmu_atc_flush();
@@ -926,11 +1117,13 @@ void m68851_pmove(uint32_t ea, uint16_t modes)
case 3: // MC68030 to/from status reg
if (modes & 0x200)
{
+ MMULOG("%s: read SR = %04x\n", __func__, m_mmu_sr);
WRITE_EA_16(ea, m_mmu_sr);
}
else
{
m_mmu_sr = READ_EA_16(ea);
+ MMULOG("%s: write SR = %04X\n", __func__, m_mmu_sr);
}
break;
@@ -977,6 +1170,10 @@ void m68851_mmu_ops()
}
else if ((modes & 0xe200) == 0x2000) // PFLUSH
{
+ if (((modes >> 10) & 7) != 1)
+ {
+ logerror("PFLUSH by fc/ea not supported\n");
+ }
pmmu_atc_flush();
return;
}
@@ -1050,3 +1247,15 @@ inline uint32_t hmmu_translate_addr(uint32_t addr_in)
return addr_out;
}
+
+public:
+int m68851_buserror()
+{
+ if (!m_mmu_tablewalk)
+ {
+ return false;
+ }
+ MMULOG("buserror during table walk\n");
+ m_mmu_tmp_sr |= M68K_MMU_SR_BUS_ERROR|M68K_MMU_SR_INVALID;
+ return true;
+}
diff --git a/src/mame/drivers/hp9k_3xx.cpp b/src/mame/drivers/hp9k_3xx.cpp
index 4c05ae2c237..cea948ebe22 100644
--- a/src/mame/drivers/hp9k_3xx.cpp
+++ b/src/mame/drivers/hp9k_3xx.cpp
@@ -285,6 +285,9 @@ void hp9k3xx_state::add_dio32_bus(machine_config &config)
void hp9k3xx_state::set_bus_error(uint32_t address, bool write, uint16_t mem_mask)
{
+ if (m_maincpu->m68851_buserror())
+ return;
+
if (m_bus_error)
return;