mirror of
https://github.com/holub/mame
synced 2025-05-28 16:43:04 +03:00
m68k: preliminary 68040 MMU implementation [R. Belmont]
This commit is contained in:
parent
ec6a340d1d
commit
f8aba531d3
@ -6586,7 +6586,7 @@ M68KMAKE_OP(movec, 32, cr, .)
|
||||
case 0x003: /* TC */
|
||||
if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
|
||||
{
|
||||
/* TODO */
|
||||
REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_tc;
|
||||
return;
|
||||
}
|
||||
m68ki_exception_illegal(mc68kcpu);
|
||||
@ -6646,7 +6646,7 @@ M68KMAKE_OP(movec, 32, cr, .)
|
||||
case 0x805: /* MMUSR */
|
||||
if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
|
||||
{
|
||||
/* TODO */
|
||||
REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_sr_040;
|
||||
return;
|
||||
}
|
||||
m68ki_exception_illegal(mc68kcpu);
|
||||
@ -6654,7 +6654,7 @@ M68KMAKE_OP(movec, 32, cr, .)
|
||||
case 0x806: /* URP */
|
||||
if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
|
||||
{
|
||||
/* TODO */
|
||||
REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_urp_aptr;
|
||||
return;
|
||||
}
|
||||
m68ki_exception_illegal(mc68kcpu);
|
||||
@ -6662,7 +6662,7 @@ M68KMAKE_OP(movec, 32, cr, .)
|
||||
case 0x807: /* SRP */
|
||||
if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
|
||||
{
|
||||
/* TODO */
|
||||
REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_srp_aptr;
|
||||
return;
|
||||
}
|
||||
m68ki_exception_illegal(mc68kcpu);
|
||||
@ -6831,7 +6831,16 @@ M68KMAKE_OP(movec, 32, rc, .)
|
||||
case 0x003: /* TC */
|
||||
if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
|
||||
{
|
||||
/* TODO */
|
||||
mc68kcpu->mmu_tc = REG_DA(mc68kcpu)[(word2 >> 12) & 15];
|
||||
|
||||
if (mc68kcpu->mmu_tc & 0x8000)
|
||||
{
|
||||
mc68kcpu->pmmu_enabled = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mc68kcpu->pmmu_enabled = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
m68ki_exception_illegal(mc68kcpu);
|
||||
@ -6891,7 +6900,7 @@ M68KMAKE_OP(movec, 32, rc, .)
|
||||
case 0x805: /* MMUSR */
|
||||
if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
|
||||
{
|
||||
/* TODO */
|
||||
mc68kcpu->mmu_sr_040 = REG_DA(mc68kcpu)[(word2 >> 12) & 15];
|
||||
return;
|
||||
}
|
||||
m68ki_exception_illegal(mc68kcpu);
|
||||
@ -6899,7 +6908,7 @@ M68KMAKE_OP(movec, 32, rc, .)
|
||||
case 0x806: /* URP */
|
||||
if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
|
||||
{
|
||||
/* TODO */
|
||||
mc68kcpu->mmu_urp_aptr = REG_DA(mc68kcpu)[(word2 >> 12) & 15];
|
||||
return;
|
||||
}
|
||||
m68ki_exception_illegal(mc68kcpu);
|
||||
@ -6907,7 +6916,7 @@ M68KMAKE_OP(movec, 32, rc, .)
|
||||
case 0x807: /* SRP */
|
||||
if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
|
||||
{
|
||||
/* TODO */
|
||||
mc68kcpu->mmu_srp_aptr = REG_DA(mc68kcpu)[(word2 >> 12) & 15];
|
||||
return;
|
||||
}
|
||||
m68ki_exception_illegal(mc68kcpu);
|
||||
|
@ -735,20 +735,28 @@ static CPU_TRANSLATE( m68k )
|
||||
/* only applies to the program address space and only does something if the MMU's enabled */
|
||||
if (m68k)
|
||||
{
|
||||
if ((space == AS_PROGRAM) && (m68k->pmmu_enabled))
|
||||
/* 68040 needs to call the MMU even when disabled so transparent translation works */
|
||||
if ((space == AS_PROGRAM) && ((m68k->pmmu_enabled) || (CPU_TYPE_IS_040_PLUS(m68k->cpu_type))))
|
||||
{
|
||||
// FIXME: mmu_tmp_sr will be overwritten in pmmu_translate_addr_with_fc
|
||||
UINT16 mmu_tmp_sr = m68k->mmu_tmp_sr;
|
||||
// UINT32 va=*address;
|
||||
|
||||
*address = pmmu_translate_addr_with_fc(m68k, *address, 4, 1);
|
||||
if (CPU_TYPE_IS_040_PLUS(m68k->cpu_type))
|
||||
{
|
||||
*address = pmmu_translate_addr_with_fc_040(m68k, *address, FUNCTION_CODE_SUPERVISOR_PROGRAM, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*address = pmmu_translate_addr_with_fc(m68k, *address, FUNCTION_CODE_SUPERVISOR_PROGRAM, 1);
|
||||
}
|
||||
|
||||
if ((m68k->mmu_tmp_sr & M68K_MMU_SR_INVALID) != 0) {
|
||||
// logerror("cpu_translate_m68k failed with mmu_sr=%04x va=%08x pa=%08x\n",m68k->mmu_tmp_sr,va ,*address);
|
||||
*address = 0;
|
||||
}
|
||||
|
||||
m68k->mmu_tmp_sr= mmu_tmp_sr;
|
||||
m68k->mmu_tmp_sr = mmu_tmp_sr;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
|
@ -692,8 +692,10 @@ public:
|
||||
/* PMMU registers */
|
||||
UINT32 mmu_crp_aptr, mmu_crp_limit;
|
||||
UINT32 mmu_srp_aptr, mmu_srp_limit;
|
||||
UINT32 mmu_urp_aptr; /* 040 only */
|
||||
UINT32 mmu_tc;
|
||||
UINT16 mmu_sr;
|
||||
UINT32 mmu_sr_040;
|
||||
UINT32 mmu_atc_tag[MMU_ATC_ENTRIES], mmu_atc_data[MMU_ATC_ENTRIES];
|
||||
UINT32 mmu_atc_rr;
|
||||
UINT32 mmu_tt0, mmu_tt1;
|
||||
|
@ -2,7 +2,7 @@
|
||||
m68kmmu.h - PMMU implementation for 68851/68030/68040
|
||||
HMMU implementation for 68020 (II and LC variants)
|
||||
|
||||
By R. Belmont
|
||||
By R. Belmont and Hans Ostermeyer
|
||||
|
||||
Copyright Nicola Salmoria and the MAME Team.
|
||||
Visit http://mamedev.org for licensing and usage restrictions.
|
||||
@ -148,7 +148,7 @@ void pmmu_atc_add(m68ki_cpu_core *m68k, UINT32 logical, UINT32 physical, int fc)
|
||||
}
|
||||
|
||||
// add the entry
|
||||
// logerror("ATC[%2d] add: log %08x -> phys %08x (fc=%d)\n", found, (logical>>ps) << ps, (physical >> ps) << ps, fc);
|
||||
// printf("ATC[%2d] add: log %08x -> phys %08x (fc=%d)\n", found, (logical>>ps) << ps, (physical >> ps) << ps, fc);
|
||||
m68k->mmu_atc_tag[found] = atc_tag;
|
||||
m68k->mmu_atc_data[found] = (physical >> ps) << (ps-8);
|
||||
|
||||
@ -166,7 +166,7 @@ void pmmu_atc_add(m68ki_cpu_core *m68k, UINT32 logical, UINT32 physical, int fc)
|
||||
void pmmu_atc_flush(m68ki_cpu_core *m68k)
|
||||
{
|
||||
int i;
|
||||
// logerror("ATC flush: pc=%08x\n", REG_PPC(m68k));
|
||||
// printf("ATC flush: pc=%08x\n", REG_PPC(m68k));
|
||||
|
||||
for (i = 0; i < MMU_ATC_ENTRIES; i++)
|
||||
{
|
||||
@ -255,13 +255,13 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 fc, U
|
||||
UINT32 address_mask = ((m68k->mmu_tt0 << 8) & 0xff000000) ^ 0xff000000;
|
||||
if ((addr_in & address_mask) == address_base)
|
||||
{
|
||||
// logerror("PMMU: pc=%x TT0 fc=%x addr_in=%08x address_mask=%08x address_base=%08x\n", m68k->ppc, fc, addr_in, address_mask, address_base);
|
||||
// printf("PMMU: pc=%x TT0 fc=%x addr_in=%08x address_mask=%08x address_base=%08x\n", m68k->ppc, fc, addr_in, address_mask, address_base);
|
||||
return addr_in;
|
||||
}
|
||||
}
|
||||
|
||||
// if ((++pmmu_access_count % 10000000) == 0) {
|
||||
// logerror("pmmu_translate_addr_with_fc: atc usage = %d%%\n", pmmu_atc_count*100/pmmu_access_count);
|
||||
// printf("pmmu_translate_addr_with_fc: atc usage = %d%%\n", pmmu_atc_count*100/pmmu_access_count);
|
||||
// pmmu_atc_count = pmmu_access_count = 0;
|
||||
// }
|
||||
|
||||
@ -298,7 +298,7 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 fc, U
|
||||
m68k->mmu_tmp_sr = M68K_MMU_SR_MODIFIED;
|
||||
}
|
||||
addr_out = (m68k->mmu_atc_data[i] << 8) | (addr_in & ~(~0 << ps));
|
||||
// logerror("ATC[%2d] hit: log %08x -> phys %08x pc=%08x fc=%d\n", i, addr_in, addr_out, REG_PPC(m68k), fc);
|
||||
// printf("ATC[%2d] hit: log %08x -> phys %08x pc=%08x fc=%d\n", i, addr_in, addr_out, REG_PPC(m68k), fc);
|
||||
// pmmu_atc_count++;
|
||||
return addr_out;
|
||||
}
|
||||
@ -323,7 +323,7 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 fc, U
|
||||
bbits = (m68k->mmu_tc >> 8) & 0xf;
|
||||
cbits = (m68k->mmu_tc >> 4) & 0xf;
|
||||
|
||||
// logerror("PMMU: tcr %08x limit %08x aptr %08x is %x abits %d bbits %d cbits %d\n", m68k->mmu_tc, root_limit, root_aptr, is, abits, bbits, cbits);
|
||||
// printf("PMMU: tcr %08x limit %08x aptr %08x is %x abits %d bbits %d cbits %d\n", m68k->mmu_tc, root_limit, root_aptr, is, abits, bbits, cbits);
|
||||
|
||||
// get table A offset
|
||||
tofs = (addr_in<<is)>>(32-abits);
|
||||
@ -338,23 +338,23 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 fc, U
|
||||
|
||||
case M68K_MMU_DF_DT1: // page descriptor, will cause direct mapping
|
||||
addr_out = tptr + addr_in;
|
||||
// logerror("PMMU: PC=%x root mode %d (addr_in %08x -> %08x)\n", m68k->ppc, M68K_MMU_DF_DT1, addr_in, addr_out);
|
||||
// printf("PMMU: PC=%x root mode %d (addr_in %08x -> %08x)\n", m68k->ppc, M68K_MMU_DF_DT1, addr_in, addr_out);
|
||||
return addr_out;
|
||||
|
||||
case M68K_MMU_DF_DT2: // valid 4 byte descriptors
|
||||
tofs *= 4;
|
||||
// if (verbose) logerror("PMMU: reading table A entry at %08x\n", tofs + tptr);
|
||||
// if (verbose) printf("PMMU: reading table A entry at %08x\n", tofs + tptr);
|
||||
tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest);
|
||||
tamode = tbl_entry & M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tamode, tofs);
|
||||
// if (verbose) printf("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tamode, tofs);
|
||||
break;
|
||||
|
||||
case M68K_MMU_DF_DT3: // valid 8 byte descriptors
|
||||
tofs *= 8;
|
||||
// if (verbose) logerror("PMMU: reading table A entries at %08x\n", tofs + tptr);
|
||||
// if (verbose) printf("PMMU: reading table A entries at %08x\n", tofs + tptr);
|
||||
tbl_entry = get_dt3_table_entry(m68k, tofs + tptr, fc, ptest);
|
||||
tamode = tbl_entry & M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs);
|
||||
// if (verbose) printf("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tamode, tofs);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -376,19 +376,19 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 fc, U
|
||||
|
||||
case M68K_MMU_DF_DT2: // 4-byte table B descriptor
|
||||
tofs *= 4;
|
||||
// if (verbose) logerror("PMMU: reading table B entry at %08x\n", tofs + tptr);
|
||||
// if (verbose) printf("PMMU: reading table B entry at %08x\n", tofs + tptr);
|
||||
tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest);
|
||||
tbmode = tbl_entry & M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
|
||||
// if (verbose) printf("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
|
||||
break;
|
||||
|
||||
case M68K_MMU_DF_DT3: // 8-byte table B descriptor
|
||||
tofs *= 8;
|
||||
// if (verbose) logerror("PMMU: reading table B entries at %08x\n", tofs + tptr);
|
||||
// if (verbose) printf("PMMU: reading table B entries at %08x\n", tofs + tptr);
|
||||
tbl_entry = get_dt3_table_entry(m68k, tptr + tofs, fc, ptest);
|
||||
tbmode = tbl_entry & M68K_MMU_DF_DT;
|
||||
tbl_entry &= ~M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
|
||||
// if (verbose) printf("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tbmode, tofs);
|
||||
break;
|
||||
|
||||
case M68K_MMU_DF_DT1: // early termination descriptor
|
||||
@ -420,18 +420,18 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 fc, U
|
||||
|
||||
case M68K_MMU_DF_DT2: // 4-byte table C descriptor
|
||||
tofs *= 4;
|
||||
// if (verbose) logerror("PMMU: reading table C entry at %08x\n", tofs + tptr);
|
||||
// if (verbose) printf("PMMU: reading table C entry at %08x\n", tofs + tptr);
|
||||
tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest);
|
||||
tcmode = tbl_entry & M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
|
||||
// if (verbose) printf("PMMU: addr %08x entry %08x mode %x tofs %x\n", addr_in, tbl_entry, tbmode, tofs);
|
||||
break;
|
||||
|
||||
case M68K_MMU_DF_DT3: // 8-byte table C descriptor
|
||||
tofs *= 8;
|
||||
// if (verbose) logerror("PMMU: reading table C entries at %08x\n", tofs + tptr);
|
||||
// if (verbose) printf("PMMU: reading table C entries at %08x\n", tofs + tptr);
|
||||
tbl_entry = get_dt3_table_entry(m68k, tptr+ tofs, fc, ptest);
|
||||
tcmode = tbl_entry & M68K_MMU_DF_DT;
|
||||
// if (verbose) logerror("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tcmode, tofs);
|
||||
// if (verbose) printf("PMMU: addr %08x entry %08x entry2 %08x mode %x tofs %x\n", addr_in, tbl_entry, tbl_entry2, tcmode, tofs);
|
||||
break;
|
||||
|
||||
case M68K_MMU_DF_DT1: // termination descriptor
|
||||
@ -500,7 +500,224 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 fc, U
|
||||
}
|
||||
}
|
||||
|
||||
//logerror("PMMU: [%08x] => [%08x]\n", addr_in, addr_out);
|
||||
//printf("PMMU: [%08x] => [%08x]\n", addr_in, addr_out);
|
||||
|
||||
return addr_out;
|
||||
}
|
||||
|
||||
|
||||
// FC bits: 2 = supervisor, 1 = program, 0 = data
|
||||
// the 68040 is a subset of the 68851 and 68030 PMMUs - the page table sizes are fixed, there is no early termination, etc, etc.
|
||||
/*INLINE*/ static UINT32 pmmu_translate_addr_with_fc_040(m68ki_cpu_core *m68k, UINT32 addr_in, UINT8 fc, UINT8 ptest)
|
||||
{
|
||||
UINT32 addr_out, tt0, tt1;
|
||||
|
||||
addr_out = addr_in;
|
||||
m68k->mmu_tmp_sr = 0;
|
||||
|
||||
// transparent translation registers are always in force even if the PMMU itself is disabled
|
||||
// they don't do much in emulation because we never write out of order, but the write-protect and cache control features
|
||||
// are emulatable, and apparently transparent translation regions skip the page table lookup.
|
||||
if (fc & 1) // data, use DTT0/DTT1
|
||||
{
|
||||
tt0 = m68k->mmu_dtt0;
|
||||
tt1 = m68k->mmu_dtt1;
|
||||
}
|
||||
else if (fc & 2) // program, use ITT0/ITT1
|
||||
{
|
||||
tt0 = m68k->mmu_itt0;
|
||||
tt1 = m68k->mmu_itt1;
|
||||
}
|
||||
else
|
||||
{
|
||||
fatalerror("68040: function code %d is neither data nor program!\n", fc&7);
|
||||
}
|
||||
|
||||
if (tt0 & 0x8000)
|
||||
{
|
||||
UINT32 mask = (tt0>>16) & 0xff;
|
||||
mask ^= 0xff;
|
||||
mask <<= 24;
|
||||
|
||||
if ((addr_in & mask) == (tt0 & mask))
|
||||
{
|
||||
// printf("TT0 match on address %08x (TT0 = %08x, mask = %08x)\n", addr_in, tt0, mask);
|
||||
if ((tt0 & 4) && !m68k->mmu_tmp_rw && !ptest) // write protect?
|
||||
{
|
||||
if (++m68k->mmu_tmp_buserror_occurred == 1)
|
||||
{
|
||||
m68k->mmu_tmp_buserror_address = addr_in;
|
||||
}
|
||||
}
|
||||
|
||||
return addr_in;
|
||||
}
|
||||
}
|
||||
|
||||
if (tt1 & 0x8000)
|
||||
{
|
||||
UINT32 mask = (tt1>>16) & 0xff;
|
||||
mask ^= 0xff;
|
||||
mask <<= 24;
|
||||
|
||||
if ((addr_in & mask) == (tt1 & mask))
|
||||
{
|
||||
// printf("TT1 match on address %08x (TT0 = %08x, mask = %08x)\n", addr_in, tt1, mask);
|
||||
if ((tt1 & 4) && !m68k->mmu_tmp_rw && !ptest) // write protect?
|
||||
{
|
||||
if (++m68k->mmu_tmp_buserror_occurred == 1)
|
||||
{
|
||||
m68k->mmu_tmp_buserror_address = addr_in;
|
||||
}
|
||||
}
|
||||
|
||||
return addr_in;
|
||||
}
|
||||
}
|
||||
|
||||
if (m68k->pmmu_enabled)
|
||||
{
|
||||
UINT32 root_idx = (addr_in>>25) & 0x7f;
|
||||
UINT32 ptr_idx = (addr_in>>18) & 0x7f;
|
||||
UINT32 page_idx, page;
|
||||
UINT32 root_ptr, pointer_ptr, page_ptr;
|
||||
UINT32 root_entry, pointer_entry, page_entry;
|
||||
|
||||
// select supervisor or user root pointer
|
||||
if (fc & 4)
|
||||
{
|
||||
root_ptr = m68k->mmu_srp_aptr + (root_idx<<2);
|
||||
}
|
||||
else
|
||||
{
|
||||
root_ptr = m68k->mmu_urp_aptr + (root_idx<<2);
|
||||
}
|
||||
|
||||
// get the root entry
|
||||
root_entry = m68k->program->read_dword(root_ptr);
|
||||
// printf("root entry = %08x\n", root_entry);
|
||||
|
||||
// is UDT marked valid?
|
||||
if (root_entry & 2)
|
||||
{
|
||||
pointer_ptr = (root_entry & ~0x1ff) + (ptr_idx<<2);
|
||||
pointer_entry = m68k->program->read_dword(pointer_ptr);
|
||||
|
||||
// printf("pointer entry = %08x\n", pointer_entry);
|
||||
|
||||
// write protected by the root or pointer entries?
|
||||
if ((((root_entry & 4) && !m68k->mmu_tmp_rw) || ((pointer_entry & 4) && !m68k->mmu_tmp_rw)) && !ptest)
|
||||
{
|
||||
if (++m68k->mmu_tmp_buserror_occurred == 1)
|
||||
{
|
||||
m68k->mmu_tmp_buserror_address = addr_in;
|
||||
}
|
||||
|
||||
return addr_in;
|
||||
}
|
||||
|
||||
// is UDT valid on the pointer entry?
|
||||
if (!(pointer_entry & 2) && !ptest)
|
||||
{
|
||||
// printf("Invalid pointer entry! PC=%x, addr=%x\n", m68k->ppc, addr_in);
|
||||
if (++m68k->mmu_tmp_buserror_occurred == 1)
|
||||
{
|
||||
m68k->mmu_tmp_buserror_address = addr_in;
|
||||
}
|
||||
|
||||
return addr_in;
|
||||
}
|
||||
|
||||
// (fall out of these ifs into the page lookup below)
|
||||
}
|
||||
else // throw an error
|
||||
{
|
||||
// printf("Invalid root entry! PC=%x, addr=%x\n", m68k->ppc, addr_in);
|
||||
if (!ptest)
|
||||
{
|
||||
if (++m68k->mmu_tmp_buserror_occurred == 1)
|
||||
{
|
||||
m68k->mmu_tmp_buserror_address = addr_in;
|
||||
}
|
||||
}
|
||||
|
||||
return addr_in;
|
||||
}
|
||||
|
||||
// now do the page lookup
|
||||
if (m68k->mmu_tc & 0x4000) // 8k pages?
|
||||
{
|
||||
page_idx = (addr_in >> 13) & 0x1f;
|
||||
page = addr_in & 0x1fff;
|
||||
pointer_entry &= ~0x7f;
|
||||
|
||||
// printf("8k pages: index %x page %x\n", page_idx, page);
|
||||
}
|
||||
else // 4k pages
|
||||
{
|
||||
page_idx = (addr_in >> 12) & 0x3f;
|
||||
page = addr_in & 0xfff;
|
||||
pointer_entry &= ~0xff;
|
||||
|
||||
// printf("4k pages: index %x page %x\n", page_idx, page);
|
||||
}
|
||||
|
||||
page_ptr = pointer_entry + (page_idx<<2);
|
||||
page_entry = m68k->program->read_dword(page_ptr);
|
||||
|
||||
// printf("page_entry = %08x\n", page_entry);
|
||||
|
||||
// resolve indirect page pointers
|
||||
while ((page_entry & 3) == 2)
|
||||
{
|
||||
page_entry = m68k->program->read_dword(page_entry & ~0x3);
|
||||
}
|
||||
|
||||
// is the page write protected or supervisor protected?
|
||||
if ((((page_entry & 4) && !m68k->mmu_tmp_rw) || ((page_entry & 0x80) && !(fc&4))) && !ptest)
|
||||
{
|
||||
if (++m68k->mmu_tmp_buserror_occurred == 1)
|
||||
{
|
||||
m68k->mmu_tmp_buserror_address = addr_in;
|
||||
}
|
||||
|
||||
return addr_in;
|
||||
}
|
||||
|
||||
switch (page_entry & 3)
|
||||
{
|
||||
case 0: // invalid
|
||||
// printf("Invalid page entry! PC=%x, addr=%x\n", m68k->ppc, addr_in);
|
||||
if (!ptest)
|
||||
{
|
||||
if (++m68k->mmu_tmp_buserror_occurred == 1)
|
||||
{
|
||||
m68k->mmu_tmp_buserror_address = addr_in;
|
||||
}
|
||||
}
|
||||
|
||||
return addr_in;
|
||||
|
||||
case 1:
|
||||
case 3: // normal
|
||||
if (m68k->mmu_tc & 0x4000) // 8k pages?
|
||||
{
|
||||
addr_out = (page_entry & ~0x1fff) | page;
|
||||
}
|
||||
else
|
||||
{
|
||||
addr_out = (page_entry & ~0xfff) | page;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case 2: // shouldn't happen
|
||||
fatalerror("68040: got indirect final page pointer, shouldn't be possible\n");
|
||||
break;
|
||||
}
|
||||
// if (addr_in != addr_out) printf("040MMU: [%08x] => [%08x]\n", addr_in, addr_out);
|
||||
}
|
||||
|
||||
return addr_out;
|
||||
}
|
||||
@ -510,10 +727,19 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 fc, U
|
||||
*/
|
||||
/*INLINE*/ static UINT32 pmmu_translate_addr(m68ki_cpu_core *m68k, UINT32 addr_in)
|
||||
{
|
||||
UINT32 addr_out = pmmu_translate_addr_with_fc(m68k, addr_in, m68k->mmu_tmp_fc, 0);
|
||||
UINT32 addr_out;
|
||||
|
||||
if (CPU_TYPE_IS_040_PLUS(m68k->cpu_type))
|
||||
{
|
||||
addr_out = pmmu_translate_addr_with_fc_040(m68k, addr_in, m68k->mmu_tmp_fc, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr_out = pmmu_translate_addr_with_fc(m68k, addr_in, m68k->mmu_tmp_fc, 0);
|
||||
}
|
||||
|
||||
// if (m68k->mmu_tmp_buserror_occurred > 0) {
|
||||
// logerror("PMMU: pc=%08x sp=%08x va=%08x pa=%08x - invalid Table mode for level=%d (buserror %d)\n",
|
||||
// printf("PMMU: pc=%08x sp=%08x va=%08x pa=%08x - invalid Table mode for level=%d (buserror %d)\n",
|
||||
// REG_PPC(m68k), REG_A(m68k)[7], addr_in, addr_out, m68k->mmu_tmp_sr & M68K_MMU_SR_LEVEL_3,
|
||||
// m68k->mmu_tmp_buserror_occurred);
|
||||
// }
|
||||
@ -522,8 +748,7 @@ INLINE UINT32 get_dt3_table_entry(m68ki_cpu_core *m68k, UINT32 tptr, UINT8 fc, U
|
||||
}
|
||||
|
||||
/*
|
||||
m68881_mmu_ops: COP 0 MMU opcode handling
|
||||
|
||||
m68851_mmu_ops: COP 0 MMU opcode handling
|
||||
*/
|
||||
|
||||
void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
@ -536,12 +761,12 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
// catch the 2 "weird" encodings up front (PBcc)
|
||||
if ((m68k->ir & 0xffc0) == 0xf0c0)
|
||||
{
|
||||
logerror("680x0: unhandled PBcc\n");
|
||||
printf("680x0: unhandled PBcc\n");
|
||||
return;
|
||||
}
|
||||
else if ((m68k->ir & 0xffc0) == 0xf080)
|
||||
{
|
||||
logerror("680x0: unhandled PBcc\n");
|
||||
printf("680x0: unhandled PBcc\n");
|
||||
return;
|
||||
}
|
||||
else // the rest are 1111000xxxXXXXXX where xxx is the instruction family
|
||||
@ -559,10 +784,17 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
ptmp = ltmp;
|
||||
if (m68k->pmmu_enabled)
|
||||
{
|
||||
ptmp = pmmu_translate_addr_with_fc(m68k, ltmp, modes & 0x07, 0);
|
||||
if (CPU_TYPE_IS_040_PLUS(m68k->cpu_type))
|
||||
{
|
||||
ptmp = pmmu_translate_addr_with_fc_040(m68k, ltmp, modes & 0x07, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ptmp = pmmu_translate_addr_with_fc(m68k, ltmp, modes & 0x07, 0);
|
||||
}
|
||||
}
|
||||
|
||||
logerror("680x0: PLOADing ATC with logical %08x => phys %08x\n", ltmp, ptmp);
|
||||
printf("680x0: PLOADing ATC with logical %08x => phys %08x\n", ltmp, ptmp);
|
||||
// FIXME: rw bit?
|
||||
pmmu_atc_add(m68k, ltmp, ptmp, modes & 0x07);
|
||||
return;
|
||||
@ -579,12 +811,12 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
}
|
||||
else if (modes == 0x2800) // PVALID (FORMAT 1)
|
||||
{
|
||||
logerror("680x0: unhandled PVALID1\n");
|
||||
printf("680x0: unhandled PVALID1\n");
|
||||
return;
|
||||
}
|
||||
else if ((modes & 0xfff8) == 0x2c00) // PVALID (FORMAT 2)
|
||||
{
|
||||
logerror("680x0: unhandled PVALID2\n");
|
||||
printf("680x0: unhandled PVALID2\n");
|
||||
return;
|
||||
}
|
||||
else if ((modes & 0xe000) == 0x8000) // PTEST
|
||||
@ -604,10 +836,17 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
break;
|
||||
}
|
||||
|
||||
p_addr = pmmu_translate_addr_with_fc(m68k, v_addr, fc, 1);
|
||||
if (CPU_TYPE_IS_040_PLUS(m68k->cpu_type))
|
||||
{
|
||||
p_addr = pmmu_translate_addr_with_fc_040(m68k, v_addr, fc, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
p_addr = pmmu_translate_addr_with_fc(m68k, v_addr, fc, 1);
|
||||
}
|
||||
m68k->mmu_sr = m68k->mmu_tmp_sr;
|
||||
|
||||
// logerror("PMMU: pc=%08x sp=%08x va=%08x pa=%08x PTEST fc=%x level=%x mmu_sr=%04x\n",
|
||||
// printf("PMMU: pc=%08x sp=%08x va=%08x pa=%08x PTEST fc=%x level=%x mmu_sr=%04x\n",
|
||||
// m68k->ppc, REG_A(m68k)[7], v_addr, p_addr, fc, (modes >> 10) & 0x07, m68k->mmu_sr);
|
||||
|
||||
if (modes & 0x100)
|
||||
@ -629,29 +868,29 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
{
|
||||
case 0x02: // transparent translation register 0
|
||||
WRITE_EA_32(m68k, ea, m68k->mmu_tt0);
|
||||
// logerror("PMMU: pc=%x PMOVE from mmu_tt0=%08x\n", m68k->ppc, m68k->mmu_tt0);
|
||||
// printf("PMMU: pc=%x PMOVE from mmu_tt0=%08x\n", m68k->ppc, m68k->mmu_tt0);
|
||||
break;
|
||||
case 0x03: // transparent translation register 1
|
||||
WRITE_EA_32(m68k, ea, m68k->mmu_tt1);
|
||||
// logerror("PMMU: pc=%x PMOVE from mmu_tt1=%08x\n", m68k->ppc, m68k->mmu_tt1);
|
||||
// printf("PMMU: pc=%x PMOVE from mmu_tt1=%08x\n", m68k->ppc, m68k->mmu_tt1);
|
||||
break;
|
||||
case 0x10: // translation control register
|
||||
WRITE_EA_32(m68k, ea, m68k->mmu_tc);
|
||||
// logerror("PMMU: pc=%x PMOVE from mmu_tc=%08x\n", m68k->ppc, m68k->mmu_tc);
|
||||
// printf("PMMU: pc=%x PMOVE from mmu_tc=%08x\n", m68k->ppc, m68k->mmu_tc);
|
||||
break;
|
||||
|
||||
case 0x12: // supervisor root pointer
|
||||
WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_srp_limit<<32 | (UINT64)m68k->mmu_srp_aptr);
|
||||
// logerror("PMMU: pc=%x PMOVE from SRP limit = %08x, aptr = %08x\n", REG_PPC(m68k), m68k->mmu_srp_limit, m68k->mmu_srp_aptr);
|
||||
// printf("PMMU: pc=%x PMOVE from SRP limit = %08x, aptr = %08x\n", REG_PPC(m68k), m68k->mmu_srp_limit, m68k->mmu_srp_aptr);
|
||||
break;
|
||||
|
||||
case 0x13: // CPU root pointer
|
||||
WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_crp_limit<<32 | (UINT64)m68k->mmu_crp_aptr);
|
||||
// logerror("PMMU: pc=%x PMOVE from CRP limit = %08x, aptr = %08x\n", REG_PPC(m68k), m68k->mmu_crp_limit, m68k->mmu_crp_aptr);
|
||||
// printf("PMMU: pc=%x PMOVE from CRP limit = %08x, aptr = %08x\n", REG_PPC(m68k), m68k->mmu_crp_limit, m68k->mmu_crp_aptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
|
||||
printf("680x0: PMOVE from unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -676,7 +915,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
break;
|
||||
|
||||
case 1:
|
||||
logerror("680x0: unknown PMOVE case 1, PC %x\n", m68k->pc);
|
||||
printf("680x0: unknown PMOVE case 1, PC %x\n", m68k->pc);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
@ -684,17 +923,17 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
{
|
||||
case 0: // translation control register
|
||||
m68k->mmu_tc = READ_EA_32(m68k, ea);
|
||||
// logerror("PMMU: TC = %08x\n", m68k->mmu_tc);
|
||||
// printf("PMMU: TC = %08x\n", m68k->mmu_tc);
|
||||
|
||||
if (m68k->mmu_tc & 0x80000000)
|
||||
{
|
||||
m68k->pmmu_enabled = 1;
|
||||
// logerror("PMMU enabled\n");
|
||||
// printf("PMMU enabled\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
m68k->pmmu_enabled = 0;
|
||||
// logerror("PMMU disabled\n");
|
||||
// printf("PMMU disabled\n");
|
||||
}
|
||||
|
||||
if (!(modes & 0x100)) // flush ATC on moves to TC, SRP, CRP with FD bit clear
|
||||
@ -707,7 +946,7 @@ 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);
|
||||
// printf("PMMU: SRP limit = %08x aptr = %08x\n", m68k->mmu_srp_limit, m68k->mmu_srp_aptr);
|
||||
if (!(modes & 0x100))
|
||||
{
|
||||
pmmu_atc_flush(m68k);
|
||||
@ -718,7 +957,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
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);
|
||||
// printf("PMMU: CRP limit = %08x aptr = %08x\n", m68k->mmu_crp_limit, m68k->mmu_crp_aptr);
|
||||
if (!(modes & 0x100))
|
||||
{
|
||||
pmmu_atc_flush(m68k);
|
||||
@ -726,7 +965,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("680x0: PMOVE to unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
|
||||
printf("680x0: PMOVE to unknown MMU register %x, PC %x\n", (modes>>10) & 7, m68k->pc);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -734,7 +973,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
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);
|
||||
printf("680x0: unsupported PMOVE %x to MMU status, PC %x\n", temp, m68k->pc);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -753,7 +992,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, m68k->pc);
|
||||
printf("680x0: unknown PMOVE mode %x (modes %04x) (PC %x)\n", (modes>>13) & 0x7, modes, m68k->pc);
|
||||
break;
|
||||
|
||||
}
|
||||
@ -761,7 +1000,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
|
||||
break;
|
||||
|
||||
default:
|
||||
logerror("680x0: unknown PMMU instruction group %d\n", (m68k->ir>>9) & 0x7);
|
||||
printf("680x0: unknown PMMU instruction group %d\n", (m68k->ir>>9) & 0x7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user