m68k: preliminary 68040 MMU implementation [R. Belmont]

This commit is contained in:
R. Belmont 2011-10-08 23:02:59 +00:00
parent ec6a340d1d
commit f8aba531d3
4 changed files with 318 additions and 60 deletions

View File

@ -6586,7 +6586,7 @@ M68KMAKE_OP(movec, 32, cr, .)
case 0x003: /* TC */ case 0x003: /* TC */
if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
{ {
/* TODO */ REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_tc;
return; return;
} }
m68ki_exception_illegal(mc68kcpu); m68ki_exception_illegal(mc68kcpu);
@ -6646,7 +6646,7 @@ M68KMAKE_OP(movec, 32, cr, .)
case 0x805: /* MMUSR */ case 0x805: /* MMUSR */
if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
{ {
/* TODO */ REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_sr_040;
return; return;
} }
m68ki_exception_illegal(mc68kcpu); m68ki_exception_illegal(mc68kcpu);
@ -6654,7 +6654,7 @@ M68KMAKE_OP(movec, 32, cr, .)
case 0x806: /* URP */ case 0x806: /* URP */
if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
{ {
/* TODO */ REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_urp_aptr;
return; return;
} }
m68ki_exception_illegal(mc68kcpu); m68ki_exception_illegal(mc68kcpu);
@ -6662,7 +6662,7 @@ M68KMAKE_OP(movec, 32, cr, .)
case 0x807: /* SRP */ case 0x807: /* SRP */
if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) if(CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
{ {
/* TODO */ REG_DA(mc68kcpu)[(word2 >> 12) & 15] = mc68kcpu->mmu_srp_aptr;
return; return;
} }
m68ki_exception_illegal(mc68kcpu); m68ki_exception_illegal(mc68kcpu);
@ -6831,7 +6831,16 @@ M68KMAKE_OP(movec, 32, rc, .)
case 0x003: /* TC */ case 0x003: /* TC */
if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) 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; return;
} }
m68ki_exception_illegal(mc68kcpu); m68ki_exception_illegal(mc68kcpu);
@ -6891,7 +6900,7 @@ M68KMAKE_OP(movec, 32, rc, .)
case 0x805: /* MMUSR */ case 0x805: /* MMUSR */
if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
{ {
/* TODO */ mc68kcpu->mmu_sr_040 = REG_DA(mc68kcpu)[(word2 >> 12) & 15];
return; return;
} }
m68ki_exception_illegal(mc68kcpu); m68ki_exception_illegal(mc68kcpu);
@ -6899,7 +6908,7 @@ M68KMAKE_OP(movec, 32, rc, .)
case 0x806: /* URP */ case 0x806: /* URP */
if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
{ {
/* TODO */ mc68kcpu->mmu_urp_aptr = REG_DA(mc68kcpu)[(word2 >> 12) & 15];
return; return;
} }
m68ki_exception_illegal(mc68kcpu); m68ki_exception_illegal(mc68kcpu);
@ -6907,7 +6916,7 @@ M68KMAKE_OP(movec, 32, rc, .)
case 0x807: /* SRP */ case 0x807: /* SRP */
if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type)) if (CPU_TYPE_IS_040_PLUS((mc68kcpu)->cpu_type))
{ {
/* TODO */ mc68kcpu->mmu_srp_aptr = REG_DA(mc68kcpu)[(word2 >> 12) & 15];
return; return;
} }
m68ki_exception_illegal(mc68kcpu); m68ki_exception_illegal(mc68kcpu);

View File

@ -735,20 +735,28 @@ static CPU_TRANSLATE( m68k )
/* only applies to the program address space and only does something if the MMU's enabled */ /* only applies to the program address space and only does something if the MMU's enabled */
if (m68k) 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 // FIXME: mmu_tmp_sr will be overwritten in pmmu_translate_addr_with_fc
UINT16 mmu_tmp_sr = m68k->mmu_tmp_sr; UINT16 mmu_tmp_sr = m68k->mmu_tmp_sr;
// UINT32 va=*address; // 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) { 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); // logerror("cpu_translate_m68k failed with mmu_sr=%04x va=%08x pa=%08x\n",m68k->mmu_tmp_sr,va ,*address);
*address = 0; *address = 0;
} }
m68k->mmu_tmp_sr= mmu_tmp_sr; m68k->mmu_tmp_sr = mmu_tmp_sr;
} }
} }
return TRUE; return TRUE;

View File

@ -692,8 +692,10 @@ public:
/* PMMU registers */ /* PMMU registers */
UINT32 mmu_crp_aptr, mmu_crp_limit; UINT32 mmu_crp_aptr, mmu_crp_limit;
UINT32 mmu_srp_aptr, mmu_srp_limit; UINT32 mmu_srp_aptr, mmu_srp_limit;
UINT32 mmu_urp_aptr; /* 040 only */
UINT32 mmu_tc; UINT32 mmu_tc;
UINT16 mmu_sr; UINT16 mmu_sr;
UINT32 mmu_sr_040;
UINT32 mmu_atc_tag[MMU_ATC_ENTRIES], mmu_atc_data[MMU_ATC_ENTRIES]; UINT32 mmu_atc_tag[MMU_ATC_ENTRIES], mmu_atc_data[MMU_ATC_ENTRIES];
UINT32 mmu_atc_rr; UINT32 mmu_atc_rr;
UINT32 mmu_tt0, mmu_tt1; UINT32 mmu_tt0, mmu_tt1;

View File

@ -2,7 +2,7 @@
m68kmmu.h - PMMU implementation for 68851/68030/68040 m68kmmu.h - PMMU implementation for 68851/68030/68040
HMMU implementation for 68020 (II and LC variants) HMMU implementation for 68020 (II and LC variants)
By R. Belmont By R. Belmont and Hans Ostermeyer
Copyright Nicola Salmoria and the MAME Team. Copyright Nicola Salmoria and the MAME Team.
Visit http://mamedev.org for licensing and usage restrictions. 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 // 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_tag[found] = atc_tag;
m68k->mmu_atc_data[found] = (physical >> ps) << (ps-8); 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) void pmmu_atc_flush(m68ki_cpu_core *m68k)
{ {
int i; 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++) 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; UINT32 address_mask = ((m68k->mmu_tt0 << 8) & 0xff000000) ^ 0xff000000;
if ((addr_in & address_mask) == address_base) 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; return addr_in;
} }
} }
// if ((++pmmu_access_count % 10000000) == 0) { // 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; // 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; m68k->mmu_tmp_sr = M68K_MMU_SR_MODIFIED;
} }
addr_out = (m68k->mmu_atc_data[i] << 8) | (addr_in & ~(~0 << ps)); 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++; // pmmu_atc_count++;
return addr_out; 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; bbits = (m68k->mmu_tc >> 8) & 0xf;
cbits = (m68k->mmu_tc >> 4) & 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 // get table A offset
tofs = (addr_in<<is)>>(32-abits); 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 case M68K_MMU_DF_DT1: // page descriptor, will cause direct mapping
addr_out = tptr + addr_in; 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; return addr_out;
case M68K_MMU_DF_DT2: // valid 4 byte descriptors case M68K_MMU_DF_DT2: // valid 4 byte descriptors
tofs *= 4; 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); tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest);
tamode = tbl_entry & M68K_MMU_DF_DT; 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; break;
case M68K_MMU_DF_DT3: // valid 8 byte descriptors case M68K_MMU_DF_DT3: // valid 8 byte descriptors
tofs *= 8; 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); tbl_entry = get_dt3_table_entry(m68k, tofs + tptr, fc, ptest);
tamode = tbl_entry & M68K_MMU_DF_DT; 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; 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 case M68K_MMU_DF_DT2: // 4-byte table B descriptor
tofs *= 4; 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); tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest);
tbmode = tbl_entry & M68K_MMU_DF_DT; 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; break;
case M68K_MMU_DF_DT3: // 8-byte table B descriptor case M68K_MMU_DF_DT3: // 8-byte table B descriptor
tofs *= 8; 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); tbl_entry = get_dt3_table_entry(m68k, tptr + tofs, fc, ptest);
tbmode = tbl_entry & M68K_MMU_DF_DT; tbmode = tbl_entry & M68K_MMU_DF_DT;
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; break;
case M68K_MMU_DF_DT1: // early termination descriptor 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 case M68K_MMU_DF_DT2: // 4-byte table C descriptor
tofs *= 4; 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); tbl_entry = get_dt2_table_entry(m68k, tptr + tofs, ptest);
tcmode = tbl_entry & M68K_MMU_DF_DT; 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; break;
case M68K_MMU_DF_DT3: // 8-byte table C descriptor case M68K_MMU_DF_DT3: // 8-byte table C descriptor
tofs *= 8; 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); tbl_entry = get_dt3_table_entry(m68k, tptr+ tofs, fc, ptest);
tcmode = tbl_entry & M68K_MMU_DF_DT; 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; break;
case M68K_MMU_DF_DT1: // termination descriptor 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; 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) /*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) { // 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, // 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); // 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) 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) // catch the 2 "weird" encodings up front (PBcc)
if ((m68k->ir & 0xffc0) == 0xf0c0) if ((m68k->ir & 0xffc0) == 0xf0c0)
{ {
logerror("680x0: unhandled PBcc\n"); printf("680x0: unhandled PBcc\n");
return; return;
} }
else if ((m68k->ir & 0xffc0) == 0xf080) else if ((m68k->ir & 0xffc0) == 0xf080)
{ {
logerror("680x0: unhandled PBcc\n"); printf("680x0: unhandled PBcc\n");
return; return;
} }
else // the rest are 1111000xxxXXXXXX where xxx is the instruction family 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; ptmp = ltmp;
if (m68k->pmmu_enabled) 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? // FIXME: rw bit?
pmmu_atc_add(m68k, ltmp, ptmp, modes & 0x07); pmmu_atc_add(m68k, ltmp, ptmp, modes & 0x07);
return; return;
@ -579,12 +811,12 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
} }
else if (modes == 0x2800) // PVALID (FORMAT 1) else if (modes == 0x2800) // PVALID (FORMAT 1)
{ {
logerror("680x0: unhandled PVALID1\n"); printf("680x0: unhandled PVALID1\n");
return; return;
} }
else if ((modes & 0xfff8) == 0x2c00) // PVALID (FORMAT 2) else if ((modes & 0xfff8) == 0x2c00) // PVALID (FORMAT 2)
{ {
logerror("680x0: unhandled PVALID2\n"); printf("680x0: unhandled PVALID2\n");
return; return;
} }
else if ((modes & 0xe000) == 0x8000) // PTEST else if ((modes & 0xe000) == 0x8000) // PTEST
@ -604,10 +836,17 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
break; 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; 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); // m68k->ppc, REG_A(m68k)[7], v_addr, p_addr, fc, (modes >> 10) & 0x07, m68k->mmu_sr);
if (modes & 0x100) if (modes & 0x100)
@ -629,29 +868,29 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
{ {
case 0x02: // transparent translation register 0 case 0x02: // transparent translation register 0
WRITE_EA_32(m68k, ea, m68k->mmu_tt0); 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; break;
case 0x03: // transparent translation register 1 case 0x03: // transparent translation register 1
WRITE_EA_32(m68k, ea, m68k->mmu_tt1); 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; break;
case 0x10: // translation control register case 0x10: // translation control register
WRITE_EA_32(m68k, ea, m68k->mmu_tc); 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; break;
case 0x12: // supervisor root pointer case 0x12: // supervisor root pointer
WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_srp_limit<<32 | (UINT64)m68k->mmu_srp_aptr); 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; break;
case 0x13: // CPU root pointer case 0x13: // CPU root pointer
WRITE_EA_64(m68k, ea, (UINT64)m68k->mmu_crp_limit<<32 | (UINT64)m68k->mmu_crp_aptr); 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; break;
default: 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; break;
} }
@ -676,7 +915,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
break; break;
case 1: 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; break;
case 2: case 2:
@ -684,17 +923,17 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
{ {
case 0: // translation control register case 0: // translation control register
m68k->mmu_tc = READ_EA_32(m68k, ea); 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) if (m68k->mmu_tc & 0x80000000)
{ {
m68k->pmmu_enabled = 1; m68k->pmmu_enabled = 1;
// logerror("PMMU enabled\n"); // printf("PMMU enabled\n");
} }
else else
{ {
m68k->pmmu_enabled = 0; 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 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); temp64 = READ_EA_64(m68k, ea);
m68k->mmu_srp_limit = (temp64>>32) & 0xffffffff; m68k->mmu_srp_limit = (temp64>>32) & 0xffffffff;
m68k->mmu_srp_aptr = temp64 & 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)) if (!(modes & 0x100))
{ {
pmmu_atc_flush(m68k); pmmu_atc_flush(m68k);
@ -718,7 +957,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
temp64 = READ_EA_64(m68k, ea); temp64 = READ_EA_64(m68k, ea);
m68k->mmu_crp_limit = (temp64>>32) & 0xffffffff; m68k->mmu_crp_limit = (temp64>>32) & 0xffffffff;
m68k->mmu_crp_aptr = temp64 & 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)) if (!(modes & 0x100))
{ {
pmmu_atc_flush(m68k); pmmu_atc_flush(m68k);
@ -726,7 +965,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
break; break;
default: 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;
} }
break; break;
@ -734,7 +973,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
case 3: // MMU status case 3: // MMU status
{ {
UINT32 temp = READ_EA_32(m68k, ea); 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; break;
} }
@ -753,7 +992,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
break; break;
default: 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; break;
} }
@ -761,7 +1000,7 @@ void m68881_mmu_ops(m68ki_cpu_core *m68k)
break; break;
default: 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; break;
} }
} }