680x0: '030 MMU now emulates translation cache; fixed misinterpreted MMU opcodes [R. Belmont]

This commit is contained in:
R. Belmont 2010-09-27 16:39:18 +00:00
parent ac0b9c471a
commit 6bc248ae49
4 changed files with 495 additions and 45 deletions

View File

@ -33,6 +33,10 @@ enum
M68K_CPU_TYPE_SCC68070
};
/* HMMU enable types for use with m68k_set_hmmu_enable() */
#define M68K_HMMU_DISABLE 0 /* no translation */
#define M68K_HMMU_ENABLE_II 1 /* Mac II style fixed translation */
#define M68K_HMMU_ENABLE_LC 2 /* Mac LC style fixed translation */
/* Special interrupt acknowledge values.
* Use these as special returns from the interrupt acknowledge callback
@ -79,6 +83,7 @@ DECLARE_LEGACY_CPU_DEVICE(M68010, m68010);
DECLARE_LEGACY_CPU_DEVICE(M68EC020, m68ec020);
DECLARE_LEGACY_CPU_DEVICE(M68020, m68020);
DECLARE_LEGACY_CPU_DEVICE(M68020PMMU, m68020pmmu);
DECLARE_LEGACY_CPU_DEVICE(M68020HMMU, m68020hmmu);
DECLARE_LEGACY_CPU_DEVICE(M68EC030, m68ec030);
DECLARE_LEGACY_CPU_DEVICE(M68030, m68030);
DECLARE_LEGACY_CPU_DEVICE(M68EC040, m68ec040);
@ -89,6 +94,8 @@ DECLARE_LEGACY_CPU_DEVICE(SCC68070, scc68070);
void m68k_set_encrypted_opcode_range(running_device *device, offs_t start, offs_t end);
void m68k_set_hmmu_enable(running_device *device, int enable);
unsigned int m68k_disassemble_raw(char* str_buff, unsigned int pc, const unsigned char* opdata, const unsigned char* argdata, unsigned int cpu_type);
void m68k_set_reset_callback(running_device *device, m68k_reset_func callback);

View File

@ -571,6 +571,22 @@ static CPU_TRANSLATE( m68k )
return TRUE;
}
/* translate logical to physical addresses for Apple HMMU */
static CPU_TRANSLATE( m68khmmu )
{
m68ki_cpu_core *m68k = get_safe_token(device);
/* only applies to the program address space and only does something if the MMU's enabled */
if (m68k)
{
if ((space == ADDRESS_SPACE_PROGRAM) && (m68k->hmmu_enabled))
{
*address = hmmu_translate_addr(m68k, *address);
}
}
return TRUE;
}
/* Execute some instructions until we use up cycles clock cycles */
static CPU_EXECUTE( m68k )
{
@ -633,6 +649,12 @@ static CPU_INIT( m68k )
m68k->program = device->space(AS_PROGRAM);
m68k->int_ack_callback = irqcallback;
/* disable all MMUs */
m68k->has_pmmu = 0;
m68k->has_hmmu = 0;
m68k->pmmu_enabled = 0;
m68k->hmmu_enabled = 0;
/* The first call to this function initializes the opcode handler jump table */
if(!emulation_initialized)
{
@ -667,8 +689,9 @@ static CPU_RESET( m68k )
{
m68ki_cpu_core *m68k = get_safe_token(device);
/* Disable the PMMU on reset */
/* Disable the PMMU/HMMU on reset, if any */
m68k->pmmu_enabled = 0;
m68k->hmmu_enabled = 0;
/* Clear all stop levels and eat up all remaining cycles */
m68k->stopped = 0;
@ -702,6 +725,9 @@ static CPU_RESET( m68k )
m68k->run_mode = RUN_MODE_NORMAL;
m68k->reset_cycles = m68k->cyc_exception[EXCEPTION_RESET];
/* flush the MMU's cache */
pmmu_atc_flush(m68k);
}
static CPU_DISASSEMBLE( m68k )
@ -940,6 +966,13 @@ void m68k_set_encrypted_opcode_range(running_device *device, offs_t start, offs_
m68k->encrypted_end = end;
}
void m68k_set_hmmu_enable(running_device *device, int enable)
{
m68ki_cpu_core *m68k = get_safe_token(device);
m68k->hmmu_enabled = enable;
}
/****************************************************************************
* 8-bit data memory interface
****************************************************************************/
@ -1143,6 +1176,132 @@ void m68k_memory_interface::init32mmu(address_space &space)
}
/* interface for 32-bit data bus with PMMU (68EC020, 68020) */
UINT8 m68k_memory_interface::read_byte_32_hmmu(offs_t address)
{
if (m_cpustate->hmmu_enabled)
{
address = hmmu_translate_addr(m_cpustate, address);
}
return m_space->read_byte(address);
}
void m68k_memory_interface::write_byte_32_hmmu(offs_t address, UINT8 data)
{
if (m_cpustate->hmmu_enabled)
{
address = hmmu_translate_addr(m_cpustate, address);
}
m_space->write_byte(address, data);
}
UINT16 m68k_memory_interface::read_immediate_16_hmmu(offs_t address)
{
if (m_cpustate->hmmu_enabled)
{
address = hmmu_translate_addr(m_cpustate, address);
}
return m_direct->read_decrypted_word((address) ^ m_cpustate->memory.opcode_xor);
}
/* potentially misaligned 16-bit reads with a 32-bit data bus (and 24-bit address bus) */
UINT16 m68k_memory_interface::readword_d32_hmmu(offs_t address)
{
UINT16 result;
if (m_cpustate->hmmu_enabled)
{
address = hmmu_translate_addr(m_cpustate, address);
}
if (!(address & 1))
return m_space->read_word(address);
result = m_space->read_byte(address) << 8;
return result | m_space->read_byte(address + 1);
}
/* potentially misaligned 16-bit writes with a 32-bit data bus (and 24-bit address bus) */
void m68k_memory_interface::writeword_d32_hmmu(offs_t address, UINT16 data)
{
if (m_cpustate->hmmu_enabled)
{
address = hmmu_translate_addr(m_cpustate, address);
}
if (!(address & 1))
{
m_space->write_word(address, data);
return;
}
m_space->write_byte(address, data >> 8);
m_space->write_byte(address + 1, data);
}
/* potentially misaligned 32-bit reads with a 32-bit data bus (and 24-bit address bus) */
UINT32 m68k_memory_interface::readlong_d32_hmmu(offs_t address)
{
UINT32 result;
if (m_cpustate->hmmu_enabled)
{
address = hmmu_translate_addr(m_cpustate, address);
}
if (!(address & 3))
return m_space->read_dword(address);
else if (!(address & 1))
{
result = m_space->read_word(address) << 16;
return result | m_space->read_word(address + 2);
}
result = m_space->read_byte(address) << 24;
result |= m_space->read_word(address + 1) << 8;
return result | m_space->read_byte(address + 3);
}
/* potentially misaligned 32-bit writes with a 32-bit data bus (and 24-bit address bus) */
void m68k_memory_interface::writelong_d32_hmmu(offs_t address, UINT32 data)
{
if (m_cpustate->hmmu_enabled)
{
address = hmmu_translate_addr(m_cpustate, address);
}
if (!(address & 3))
{
m_space->write_dword(address, data);
return;
}
else if (!(address & 1))
{
m_space->write_word(address, data >> 16);
m_space->write_word(address + 2, data);
return;
}
m_space->write_byte(address, data >> 24);
m_space->write_word(address + 1, data >> 8);
m_space->write_byte(address + 3, data);
}
void m68k_memory_interface::init32hmmu(address_space &space)
{
m_space = &space;
m_direct = &space.direct();
m_cpustate = get_safe_token(&space.device());
opcode_xor = WORD_XOR_BE(0);
readimm16 = m68k_readimm16_delegate(m68k_readimm16_proto_delegate::create_member(m68k_memory_interface, read_immediate_16_hmmu), *this);
read8 = m68k_read8_delegate(m68k_read8_proto_delegate::create_member(m68k_memory_interface, read_byte_32_hmmu), *this);
read16 = m68k_read16_delegate(m68k_read16_proto_delegate::create_member(m68k_memory_interface, readword_d32_hmmu), *this);
read32 = m68k_read32_delegate(m68k_read32_proto_delegate::create_member(m68k_memory_interface, readlong_d32_hmmu), *this);
write8 = m68k_write8_delegate(m68k_write8_proto_delegate::create_member(m68k_memory_interface, write_byte_32_hmmu), *this);
write16 = m68k_write16_delegate(m68k_write16_proto_delegate::create_member(m68k_memory_interface, writeword_d32_hmmu), *this);
write32 = m68k_write32_delegate(m68k_write32_proto_delegate::create_member(m68k_memory_interface, writelong_d32_hmmu), *this);
}
void m68k_set_reset_callback(running_device *device, m68k_reset_func callback)
{
m68ki_cpu_core *m68k = get_safe_token(device);
@ -1253,6 +1412,7 @@ static CPU_INIT( m68000 )
m68k->cyc_shift = 1;
m68k->cyc_reset = 132;
m68k->has_pmmu = 0;
m68k->has_hmmu = 0;
define_state(device);
}
@ -1403,7 +1563,6 @@ static CPU_INIT( m68020 )
m68k->cyc_movem_l = 2;
m68k->cyc_shift = 0;
m68k->cyc_reset = 518;
m68k->has_pmmu = 0;
define_state(device);
}
@ -1459,6 +1618,36 @@ CPU_GET_INFO( m68020pmmu )
}
}
// 68020 with Apple HMMU
static CPU_INIT( m68020hmmu )
{
m68ki_cpu_core *m68k = get_safe_token(device);
CPU_INIT_CALL(m68020);
m68k->has_hmmu = 1;
// hack alert: we use placement new to ensure we are properly initialized
// because we live in the device state which is allocated as bytes
// remove me when we have a real C++ device
new(&m68k->memory) m68k_memory_interface;
m68k->memory.init32mmu(*m68k->program);
}
CPU_GET_INFO( m68020hmmu )
{
switch (state)
{
/* --- the following bits of info are returned as pointers to data or functions --- */
case CPUINFO_FCT_INIT: info->init = CPU_INIT_NAME(m68020hmmu); break;
case CPUINFO_FCT_TRANSLATE: info->translate = CPU_TRANSLATE_NAME(m68khmmu); break;
/* --- the following bits of info are returned as NULL-terminated strings --- */
case DEVINFO_STR_NAME: strcpy(info->s, "68020, Apple HMMU"); break;
default: CPU_GET_INFO_CALL(m68020); break;
}
}
/****************************************************************************
* M680EC20 section
****************************************************************************/
@ -1803,6 +1992,7 @@ DEFINE_LEGACY_CPU_DEVICE(M68010, m68010);
DEFINE_LEGACY_CPU_DEVICE(M68EC020, m68ec020);
DEFINE_LEGACY_CPU_DEVICE(M68020, m68020);
DEFINE_LEGACY_CPU_DEVICE(M68020PMMU, m68020pmmu);
DEFINE_LEGACY_CPU_DEVICE(M68020HMMU, m68020hmmu);
DEFINE_LEGACY_CPU_DEVICE(M68EC030, m68ec030);
DEFINE_LEGACY_CPU_DEVICE(M68030, m68030);
DEFINE_LEGACY_CPU_DEVICE(M68EC040, m68ec040);

View File

@ -100,6 +100,8 @@ typedef struct _m68ki_cpu_core m68ki_cpu_core;
#define RUN_MODE_NORMAL 0
#define RUN_MODE_BERR_AERR_RESET 1
/* MMU constants */
#define MMU_ATC_ENTRIES (22) // 68851 has 64, 030 has 22
/* ======================================================================== */
/* ================================ MACROS ================================ */
@ -558,6 +560,7 @@ public:
void init16(address_space &space);
void init32(address_space &space);
void init32mmu(address_space &space);
void init32hmmu(address_space &space);
offs_t opcode_xor; // Address Calculation
m68k_readimm16_delegate readimm16; // Immediate read 16 bit
@ -581,6 +584,14 @@ private:
UINT32 readlong_d32_mmu(offs_t address);
void writelong_d32_mmu(offs_t address, UINT32 data);
UINT8 read_byte_32_hmmu(offs_t address);
void write_byte_32_hmmu(offs_t address, UINT8 data);
UINT16 read_immediate_16_hmmu(offs_t address);
UINT16 readword_d32_hmmu(offs_t address);
void writeword_d32_hmmu(offs_t address, UINT16 data);
UINT32 readlong_d32_hmmu(offs_t address);
void writelong_d32_hmmu(offs_t address, UINT32 data);
address_space *m_space;
direct_read_data *m_direct;
m68ki_cpu_core *m_cpustate;
@ -622,7 +633,9 @@ struct _m68ki_cpu_core
UINT32 instr_mode; /* Stores whether we are in instruction mode or group 0/1 exception mode */
UINT32 run_mode; /* Stores whether we are processing a reset, bus error, address error, or something else */
int has_pmmu; /* Indicates if a PMMU available (yes on 030, 040, no on EC030) */
int has_hmmu; /* Indicates if an Apple HMMU is available in place of the 68851 (020 only) */
int pmmu_enabled; /* Indicates if the PMMU is enabled */
int hmmu_enabled; /* Indicates if the HMMU is enabled */
int fpu_just_reset; /* Indicates the FPU was just reset */
/* Clocks required for instructions / exceptions */
@ -683,6 +696,9 @@ struct _m68ki_cpu_core
UINT32 mmu_srp_aptr, mmu_srp_limit;
UINT32 mmu_tc;
UINT16 mmu_sr;
UINT32 mmu_atc_tag[MMU_ATC_ENTRIES], mmu_atc_data[MMU_ATC_ENTRIES];
UINT32 mmu_atc_rr;
UINT32 mmu_tt0, mmu_tt1;
};

View File

@ -1,5 +1,6 @@
/*
m68kmmu.h - PMMU implementation for 68851/68030/68040
HMMU implementation for 68020 (II and LC variants)
By R. Belmont
@ -7,6 +8,128 @@
Visit http://mamedev.org for licensing and usage restrictions.
*/
/* decodes the effective address */
static UINT32 DECODE_EA_32(m68ki_cpu_core *m68k, int ea)
{
int mode = (ea >> 3) & 0x7;
int reg = (ea & 0x7);
switch (mode)
{
case 2: // (An)
{
return REG_A[reg];
}
case 3: // (An)+
{
UINT32 ea = EA_AY_PI_32(m68k);
return ea;
}
case 5: // (d16, An)
{
UINT32 ea = EA_AY_DI_32(m68k);
return ea;
}
case 6: // (An) + (Xn) + d8
{
UINT32 ea = EA_AY_IX_32(m68k);
return ea;
}
case 7:
{
switch (reg)
{
case 0: // (xxx).W
{
UINT32 ea = (UINT32)OPER_I_16(m68k);
return ea;
}
case 1: // (xxx).L
{
UINT32 d1 = OPER_I_16(m68k);
UINT32 d2 = OPER_I_16(m68k);
UINT32 ea = (d1 << 16) | d2;
return ea;
}
case 2: // (d16, PC)
{
UINT32 ea = EA_PCDI_32(m68k);
return ea;
}
default: fatalerror("m68k: DECODE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
}
break;
}
default: fatalerror("m68k: DECODE_EA_32: unhandled mode %d, reg %d at %08X\n", mode, reg, REG_PC);
}
return 0;
}
/*
pmmu_atc_add: adds this address to the ATC
*/
void pmmu_atc_add(m68ki_cpu_core *m68k, UINT32 logical, UINT32 physical)
{
int i, found, curfc;
curfc = (m68ki_get_sr(m68k) & 0x2000) ? 4 : 0;
curfc |= 1; // program vs. data space is not implemented
// first see if this is already in the cache
for (i = 0; i < MMU_ATC_ENTRIES; i++)
{
// if tag bits and function code match, don't add
if (((m68k->mmu_atc_tag[i] & 0xffffff) == (logical>>8)) && (((m68k->mmu_atc_tag[i]>>24) & 7) == curfc))
{
return;
}
}
// find an open entry
found = -1;
for (i = 0; i < MMU_ATC_ENTRIES; i++)
{
if (!(m68k->mmu_atc_tag[i] & 0x80000000))
{
found = i;
break;
}
}
// did we find an entry? steal one by round-robin then
if (found == -1)
{
found = m68k->mmu_atc_rr++;
if (m68k->mmu_atc_rr >= MMU_ATC_ENTRIES)
{
m68k->mmu_atc_rr = 0;
}
}
// add the entry
// logerror("ATC[%d] add: log %08x -> phys %08x\n", found, logical, physical);
m68k->mmu_atc_tag[found] = (logical>>8) | (curfc<<24) | 0x80000000;
m68k->mmu_atc_data[found] = (physical>>8);
}
/*
pmmu_atc_flush: flush entire ATC
7fff0003 001ffd10 80f05750 is what should load
*/
void pmmu_atc_flush(m68ki_cpu_core *m68k)
{
int i;
for (i = 0; i < MMU_ATC_ENTRIES; i++)
{
m68k->mmu_atc_tag[i] = 0;
}
m68k->mmu_atc_rr = 0;
}
/*
pmmu_translate_addr: perform 68851/68030-style PMMU address translation
*/
@ -15,10 +138,29 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
UINT32 addr_out, tbl_entry = 0, tbl_entry2, tamode = 0, tbmode = 0, tcmode = 0;
UINT32 root_aptr, root_limit, tofs, is, abits, bbits, cbits;
UINT32 resolved, tptr, shift;
int curfc, i;
// int verbose = 0;
resolved = 0;
addr_out = addr_in;
curfc = (m68ki_get_sr(m68k) & 0x2000) ? 4 : 0;
curfc |= 1; // program vs. data space is not implemented
// first see if this is already in the ATC
for (i = 0; i < MMU_ATC_ENTRIES; i++)
{
// if tag bits and function code match, we've got it
if (((m68k->mmu_atc_tag[i] & 0xffffff) == (addr_in>>8)) && (((m68k->mmu_atc_tag[i]>>24) & 7) == curfc))
{
addr_out = (m68k->mmu_atc_data[i]<<8) | (addr_in & 0xff);
// logerror("ATC[%d] hit: log %08x -> phys %08x\n", i, addr_in, addr_out);
return addr_out;
}
}
// if (addr_in == 0x5fa04c) verbose = 1;
// if SRP is enabled and we're in supervisor mode, use it
if ((m68k->mmu_tc & 0x02000000) && (m68ki_get_sr(m68k) & 0x2000))
{
@ -47,24 +189,26 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
{
case 0: // invalid, should cause MMU exception
case 1: // page descriptor, should cause direct mapping
fatalerror("680x0 PMMU: Unhandled root mode\n");
logerror("680x0 PMMU: Unhandled root mode %d, not translating (addr_in %x)\n", root_limit & 3, addr_in);
logerror(" : aptr %08x limit %08x\n", root_aptr, root_limit);
return addr_in;
break;
case 2: // valid 4 byte descriptors
tofs *= 4;
// logerror("PMMU: reading table A entry at %08x\n", tofs + (root_aptr & 0xfffffffc));
// if (verbose) logerror("PMMU: reading table A entry at %08x\n", tofs + (root_aptr & 0xfffffffc));
tbl_entry = m68k->program->read_dword(tofs + (root_aptr & 0xfffffffc));
tamode = tbl_entry & 3;
// logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tamode, tofs);
// if (verbose) logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tamode, tofs);
break;
case 3: // valid 8 byte descriptors
tofs *= 8;
// logerror("PMMU: reading table A entries at %08x\n", tofs + (root_aptr & 0xfffffffc));
// if (verbose) logerror("PMMU: reading table A entries at %08x\n", tofs + (root_aptr & 0xfffffffc));
tbl_entry2 = m68k->program->read_dword(tofs + (root_aptr & 0xfffffffc));
tbl_entry = m68k->program->read_dword(tofs + (root_aptr & 0xfffffffc)+4);
tamode = tbl_entry2 & 3;
// logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs);
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs);
break;
}
@ -76,24 +220,24 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
switch (tamode)
{
case 0: // invalid, should cause MMU exception
fatalerror("680x0 PMMU: Unhandled Table A mode %d (addr_in %08x)\n", tamode, addr_in);
fatalerror("680x0 PMMU: Unhandled Table A mode %d (addr_in %08x PC %x)\n", tamode, addr_in, m68k->pc);
break;
case 2: // 4-byte table B descriptor
tofs *= 4;
// logerror("PMMU: reading table B entry at %08x\n", tofs + tptr);
// if (verbose) logerror("PMMU: reading table B entry at %08x\n", tofs + tptr);
tbl_entry = m68k->program->read_dword(tofs + tptr);
tbmode = tbl_entry & 3;
// logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
// if (verbose) logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
break;
case 3: // 8-byte table B descriptor
tofs *= 8;
// logerror("PMMU: reading table B entries at %08x\n", tofs + tptr);
// if (verbose) logerror("PMMU: reading table B entries at %08x\n", tofs + tptr);
tbl_entry2 = m68k->program->read_dword(tofs + tptr);
tbl_entry = m68k->program->read_dword(tofs + tptr + 4);
tbmode = tbl_entry2 & 3;
// logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
break;
case 1: // early termination descriptor
@ -120,19 +264,19 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
case 2: // 4-byte table C descriptor
tofs *= 4;
// logerror("PMMU: reading table C entry at %08x\n", tofs + tptr);
// if (verbose) logerror("PMMU: reading table C entry at %08x\n", tofs + tptr);
tbl_entry = m68k->program->read_dword(tofs + tptr);
tcmode = tbl_entry & 3;
// logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
// if (verbose) logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
break;
case 3: // 8-byte table C descriptor
tofs *= 8;
// logerror("PMMU: reading table C entries at %08x\n", tofs + tptr);
// if (verbose) logerror("PMMU: reading table C entries at %08x\n", tofs + tptr);
tbl_entry2 = m68k->program->read_dword(tofs + tptr);
tbl_entry = m68k->program->read_dword(tofs + tptr + 4);
tcmode = tbl_entry2 & 3;
// logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
break;
case 1: // termination descriptor
@ -150,9 +294,9 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
switch (tcmode)
{
case 0: // invalid, should cause MMU exception
case 2: // 4-byte ??? descriptor
case 3: // 8-byte ??? descriptor
fatalerror("680x0 PMMU: Unhandled Table B mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, m68k->pc);
case 2: // 4-byte table D descriptor
case 3: // 8-byte table D descriptor
fatalerror("680x0 PMMU: Unhandled Table C mode %d (addr_in %08x PC %x)\n", tbmode, addr_in, m68k->pc);
break;
case 1: // termination descriptor
@ -165,6 +309,7 @@ INLINE UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
}
}
pmmu_atc_add(m68k, addr_in, addr_out);
//logerror("PMMU: [%08x] => [%08x]\n", addr_in, addr_out);
@ -202,17 +347,28 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
if ((modes & 0xfde0) == 0x2000) // PLOAD
{
logerror("680x0: unhandled PLOAD\n");
UINT32 ltmp = DECODE_EA_32(m68k, ea);
UINT32 ptmp;
ptmp = ltmp;
if (m68k->pmmu_enabled)
{
ptmp = pmmu_translate_addr(m68k, ltmp);
}
// logerror("680x0: PLOADing ATC with logical %08x => phys %08x\n", ltmp, ptmp);
pmmu_atc_add(m68k, ltmp, ptmp);
return;
}
else if ((modes & 0xe200) == 0x2000) // PFLUSH
{
logerror("680x0: unhandled PFLUSH PC=%x\n", m68k->pc);
pmmu_atc_flush(m68k);
return;
}
else if (modes == 0xa000) // PFLUSHR
{
logerror("680x0: unhandled PFLUSHR\n");
pmmu_atc_flush(m68k);
return;
}
else if (modes == 0x2800) // PVALID (FORMAT 1)
@ -257,20 +413,50 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
break;
}
}
else
else // top 3 bits of modes: 010 for this, 011 for status, 000 for transparent translation regs
{
switch ((modes>>13) & 7)
{
case 0:
{
UINT32 temp = READ_EA_32(m68k, ea);
if (((modes>>10) & 7) == 2)
{
m68k->mmu_tt0 = temp;
}
else if (((modes>>10) & 7) == 3)
{
m68k->mmu_tt1 = temp;
}
}
break;
case 1:
logerror("680x0: unknown PMOVE case 1, PC %x\n", m68k->pc);
break;
case 2:
switch ((modes>>10) & 7)
{
case 0: // translation control register
m68k->mmu_tc = READ_EA_32(m68k, ea);
// logerror("PMMU: TC = %08x\n", m68k->mmu_tc);
if (m68k->mmu_tc & 0x80000000)
{
m68k->pmmu_enabled = 1;
// logerror("PMMU enabled\n");
}
else
{
m68k->pmmu_enabled = 0;
// logerror("PMMU disabled\n");
}
if (!(modes & 0x100)) // flush ATC on moves to TC, SRP, CRP with FD bit clear
{
pmmu_atc_flush(m68k);
}
break;
@ -278,18 +464,37 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
temp64 = READ_EA_64(m68k, ea);
m68k->mmu_srp_limit = (temp64>>32) & 0xffffffff;
m68k->mmu_srp_aptr = temp64 & 0xffffffff;
// logerror("PMMU: SRP limit = %08x aptr = %08x\n", m68k->mmu_srp_limit, m68k->mmu_srp_aptr);
if (!(modes & 0x100))
{
pmmu_atc_flush(m68k);
}
break;
case 3: // CPU root pointer
temp64 = READ_EA_64(m68k, ea);
m68k->mmu_crp_limit = (temp64>>32) & 0xffffffff;
m68k->mmu_crp_aptr = temp64 & 0xffffffff;
// logerror("PMMU: CRP limit = %08x aptr = %08x\n", m68k->mmu_crp_limit, m68k->mmu_crp_aptr);
if (!(modes & 0x100))
{
pmmu_atc_flush(m68k);
}
break;
default:
logerror("680x0: PMOVE to unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
break;
}
break;
case 3: // MMU status
{
UINT32 temp = READ_EA_32(m68k, ea);
logerror("680x0: unsupported PMOVE %x to MMU status, PC %x\n", temp, m68k->pc);
}
break;
}
}
break;
@ -307,6 +512,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
default:
logerror("680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, m68k->pc);
break;
}
}
break;
@ -318,3 +524,34 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
}
}
/* Apple HMMU translation is much simpler */
INLINE UINT32 hmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
{
UINT32 addr_out;
addr_out = addr_in;
// check if LC mode is enabled
if (m68k->hmmu_enabled == M68K_HMMU_ENABLE_LC)
{
addr_in &= 0xffffff;
addr_out &= 0xffffff;
if ((addr_in >= 0xa00000) && (addr_in <= 0xdfffff))
{
addr_out |= 0x40000000;
}
if ((addr_in >= 0xe00000) && (addr_in <= 0xefffff))
{
addr_out &= 0xfffff;
addr_out |= 0xfe000000;
}
else if (addr_in >= 0xf00000)
{
addr_out |= 0x50000000;
}
}
return addr_out;
}