mirror of
https://github.com/holub/mame
synced 2025-05-22 21:58:57 +03:00
680x0: '030 MMU now emulates translation cache; fixed misinterpreted MMU opcodes [R. Belmont]
This commit is contained in:
parent
ac0b9c471a
commit
6bc248ae49
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user