mmu: add address cache to mem slow path. better fastmmu hashtable.
mmu: add address cache to Read/WriteMemNoEx fastmmu: ignore 1k pages. optimize hashtable get rid of NO_MMU
This commit is contained in:
parent
23f483cd01
commit
1464c02903
|
@ -617,7 +617,6 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||
core/hw/sh4/modules/intc.cpp
|
||||
core/hw/sh4/modules/mmu.cpp
|
||||
core/hw/sh4/modules/mmu.h
|
||||
core/hw/sh4/modules/mmu_impl.h
|
||||
core/hw/sh4/modules/modules.h
|
||||
core/hw/sh4/modules/rtc.cpp
|
||||
core/hw/sh4/modules/serial.cpp
|
||||
|
|
|
@ -115,7 +115,6 @@
|
|||
|
||||
*/
|
||||
|
||||
//#define NO_MMU
|
||||
//#define STRICT_MODE
|
||||
#ifndef STRICT_MODE
|
||||
#define FAST_MMU
|
||||
|
|
|
@ -217,7 +217,6 @@ static u32 vmem32_paddr_to_offset(u32 address)
|
|||
|
||||
static u32 vmem32_map_mmu(u32 address, bool write)
|
||||
{
|
||||
#ifndef NO_MMU
|
||||
u32 pa;
|
||||
const TLB_Entry *entry;
|
||||
u32 rc = mmu_full_lookup<false>(address, &entry, pa);
|
||||
|
@ -307,9 +306,7 @@ static u32 vmem32_map_mmu(u32 address, bool write)
|
|||
|
||||
return MMU_ERROR_NONE;
|
||||
}
|
||||
#else
|
||||
u32 rc = MMU_ERROR_PROTECTED;
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -335,7 +332,7 @@ static u32 vmem32_map_address(u32 address, bool write)
|
|||
return VMEM32_ERROR_NOT_MAPPED;
|
||||
}
|
||||
|
||||
#if !defined(NO_MMU) && defined(HOST_64BIT_CPU)
|
||||
#if defined(HOST_64BIT_CPU)
|
||||
// returns:
|
||||
// 0 if the fault address isn't handled by the mmu
|
||||
// 1 if the fault was handled and the access should be reattempted
|
||||
|
|
|
@ -53,59 +53,53 @@ static DynarecCodeEntryPtr DYNACALL bm_GetCode(u32 addr)
|
|||
// This returns an executable address
|
||||
DynarecCodeEntryPtr DYNACALL bm_GetCodeByVAddr(u32 addr)
|
||||
{
|
||||
#ifndef NO_MMU
|
||||
if (!mmu_enabled())
|
||||
#endif
|
||||
return bm_GetCode(addr);
|
||||
#ifndef NO_MMU
|
||||
else
|
||||
|
||||
if (addr & 1)
|
||||
{
|
||||
if (addr & 1)
|
||||
switch (addr)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
#ifdef USE_WINCE_HACK
|
||||
case 0xfffffde7: // GetTickCount
|
||||
// This should make this syscall faster
|
||||
r[0] = sh4_sched_now64() * 1000 / SH4_MAIN_CLOCK;
|
||||
next_pc = pr;
|
||||
break;
|
||||
case 0xfffffde7: // GetTickCount
|
||||
// This should make this syscall faster
|
||||
r[0] = sh4_sched_now64() * 1000 / SH4_MAIN_CLOCK;
|
||||
next_pc = pr;
|
||||
break;
|
||||
|
||||
case 0xfffffd05: // QueryPerformanceCounter(u64 *)
|
||||
case 0xfffffd05: // QueryPerformanceCounter(u64 *)
|
||||
{
|
||||
u32 paddr;
|
||||
if (mmu_data_translation<MMU_TT_DWRITE, u64>(r[4], paddr) == MMU_ERROR_NONE)
|
||||
{
|
||||
u32 paddr;
|
||||
if (mmu_data_translation<MMU_TT_DWRITE, u64>(r[4], paddr) == MMU_ERROR_NONE)
|
||||
{
|
||||
_vmem_WriteMem64(paddr, sh4_sched_now64() >> 4);
|
||||
r[0] = 1;
|
||||
next_pc = pr;
|
||||
}
|
||||
else
|
||||
{
|
||||
Do_Exception(addr, 0xE0, 0x100);
|
||||
}
|
||||
_vmem_WriteMem64(paddr, sh4_sched_now64() >> 4);
|
||||
r[0] = 1;
|
||||
next_pc = pr;
|
||||
}
|
||||
else
|
||||
{
|
||||
Do_Exception(addr, 0xE0, 0x100);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
Do_Exception(addr, 0xE0, 0x100);
|
||||
break;
|
||||
}
|
||||
addr = next_pc;
|
||||
}
|
||||
|
||||
u32 paddr;
|
||||
u32 rv = mmu_instruction_translation(addr, paddr);
|
||||
if (rv != MMU_ERROR_NONE)
|
||||
{
|
||||
DoMMUException(addr, rv, MMU_TT_IREAD);
|
||||
mmu_instruction_translation(next_pc, paddr);
|
||||
}
|
||||
|
||||
return bm_GetCode(paddr);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
Do_Exception(addr, 0xE0, 0x100);
|
||||
break;
|
||||
}
|
||||
addr = next_pc;
|
||||
}
|
||||
|
||||
u32 paddr;
|
||||
u32 rv = mmu_instruction_translation(addr, paddr);
|
||||
if (rv != MMU_ERROR_NONE)
|
||||
{
|
||||
DoMMUException(addr, rv, MMU_TT_IREAD);
|
||||
mmu_instruction_translation(next_pc, paddr);
|
||||
}
|
||||
|
||||
return bm_GetCode(paddr);
|
||||
}
|
||||
|
||||
// addr must be a physical address
|
||||
|
@ -691,20 +685,16 @@ void print_blocks()
|
|||
{
|
||||
gcode=op->guest_offs;
|
||||
u32 rpc=blk->vaddr+gcode;
|
||||
#ifndef NO_MMU
|
||||
try {
|
||||
#endif
|
||||
u16 op=IReadMem16(rpc);
|
||||
|
||||
char temp[128];
|
||||
OpDesc[op]->Disassemble(temp,rpc,op);
|
||||
|
||||
fprintf(f,"//g: %04X %s\n", op, temp);
|
||||
#ifndef NO_MMU
|
||||
} catch (SH4ThrownException& ex) {
|
||||
fprintf(f,"//g: ???? (page fault)\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string s = op->dissasm();
|
||||
|
|
|
@ -169,18 +169,14 @@ bool RuntimeBlockInfo::Setup(u32 rpc,fpscr_t rfpu_cfg)
|
|||
|
||||
oplist.clear();
|
||||
|
||||
#if !defined(NO_MMU)
|
||||
try {
|
||||
#endif
|
||||
if (!dec_DecodeBlock(this, SH4_TIMESLICE / 2))
|
||||
return false;
|
||||
#if !defined(NO_MMU)
|
||||
}
|
||||
catch (SH4ThrownException& ex) {
|
||||
Do_Exception(rpc, ex.expEvn, ex.callVect);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
SetProtectedFlags();
|
||||
|
||||
AnalyseBlock(this);
|
||||
|
|
|
@ -46,11 +46,7 @@
|
|||
#include "oslib/host_context.h"
|
||||
|
||||
#define CODE_SIZE (10*1024*1024)
|
||||
#ifdef NO_MMU
|
||||
#define TEMP_CODE_SIZE (0)
|
||||
#else
|
||||
#define TEMP_CODE_SIZE (1024*1024)
|
||||
#endif
|
||||
|
||||
// When NO_RWX is enabled there's two address-spaces, one executable and
|
||||
// one writtable. The emitter and most of the code in rec-* will work with
|
||||
|
|
|
@ -47,9 +47,7 @@ static void Sh4_int_Run()
|
|||
try {
|
||||
do
|
||||
{
|
||||
#if !defined(NO_MMU)
|
||||
try {
|
||||
#endif
|
||||
do
|
||||
{
|
||||
u32 op = ReadNexOp();
|
||||
|
@ -58,13 +56,10 @@ static void Sh4_int_Run()
|
|||
} while (l > 0);
|
||||
l += SH4_TIMESLICE;
|
||||
UpdateSystem_INTC();
|
||||
#if !defined(NO_MMU)
|
||||
}
|
||||
catch (SH4ThrownException& ex) {
|
||||
} catch (const SH4ThrownException& ex) {
|
||||
Do_Exception(ex.epc, ex.expEvn, ex.callVect);
|
||||
l -= CPU_RATIO * 5; // an exception requires the instruction pipeline to drain, so approx 5 cycles
|
||||
}
|
||||
#endif
|
||||
} while (sh4_int_bCpuRun);
|
||||
} catch (const debugger::Stop& e) {
|
||||
}
|
||||
|
@ -83,18 +78,11 @@ static void Sh4_int_Step()
|
|||
|
||||
RestoreHostRoundingMode();
|
||||
try {
|
||||
#if !defined(NO_MMU)
|
||||
try {
|
||||
#endif
|
||||
u32 op = ReadNexOp();
|
||||
ExecuteOpcode(op);
|
||||
#if !defined(NO_MMU)
|
||||
}
|
||||
catch (SH4ThrownException& ex) {
|
||||
Do_Exception(ex.epc, ex.expEvn, ex.callVect);
|
||||
l -= CPU_RATIO * 5; // an exception requires the instruction pipeline to drain, so approx 5 cycles
|
||||
}
|
||||
#endif
|
||||
u32 op = ReadNexOp();
|
||||
ExecuteOpcode(op);
|
||||
} catch (const SH4ThrownException& ex) {
|
||||
Do_Exception(ex.epc, ex.expEvn, ex.callVect);
|
||||
l -= CPU_RATIO * 5; // an exception requires the instruction pipeline to drain, so approx 5 cycles
|
||||
} catch (const debugger::Stop& e) {
|
||||
}
|
||||
}
|
||||
|
@ -134,37 +122,26 @@ static bool Sh4_int_IsCpuRunning()
|
|||
//TODO : Check for valid delayslot instruction
|
||||
void ExecuteDelayslot()
|
||||
{
|
||||
#if !defined(NO_MMU)
|
||||
try {
|
||||
#endif
|
||||
u32 op = ReadNexOp();
|
||||
|
||||
ExecuteOpcode(op);
|
||||
#if !defined(NO_MMU)
|
||||
}
|
||||
catch (SH4ThrownException& ex) {
|
||||
} catch (SH4ThrownException& ex) {
|
||||
AdjustDelaySlotException(ex);
|
||||
throw ex;
|
||||
}
|
||||
catch (const debugger::Stop& e) {
|
||||
} catch (const debugger::Stop& e) {
|
||||
next_pc -= 2; // break on previous instruction
|
||||
throw e;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExecuteDelayslot_RTE()
|
||||
{
|
||||
#if !defined(NO_MMU)
|
||||
try {
|
||||
#endif
|
||||
ExecuteDelayslot();
|
||||
#if !defined(NO_MMU)
|
||||
}
|
||||
catch (SH4ThrownException& ex) {
|
||||
} catch (const SH4ThrownException& ex) {
|
||||
ERROR_LOG(INTERPRETER, "Exception in RTE delay slot");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// every SH4_TIMESLICE cycles
|
||||
|
|
|
@ -2018,18 +2018,11 @@ sh4op(i0100_nnnn_0000_1110)
|
|||
UpdateINTC();
|
||||
}
|
||||
|
||||
|
||||
//Not implt
|
||||
sh4op(iNotImplemented)
|
||||
{
|
||||
#ifndef NO_MMU
|
||||
INFO_LOG(INTERPRETER, "iNimp %04X", op);
|
||||
debugger::debugTrap(0x180);
|
||||
SH4ThrownException ex = { next_pc - 2, 0x180, 0x100 };
|
||||
SH4ThrownException ex { next_pc - 2, 0x180, 0x100 };
|
||||
throw ex;
|
||||
#else
|
||||
cpu_iNimp(op, "Unknown opcode");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
|
||||
#include "hw/mem/_vmem.h"
|
||||
|
||||
#include "mmu_impl.h"
|
||||
#include "ccn.h"
|
||||
#include "hw/sh4/sh4_mem.h"
|
||||
|
||||
|
@ -38,7 +37,7 @@ extern u32 sq_remap[64];
|
|||
|
||||
#include "wince.h"
|
||||
|
||||
const TLB_Entry *lru_entry = NULL;
|
||||
static TLB_Entry const *lru_entry;
|
||||
static u32 lru_mask;
|
||||
static u32 lru_address;
|
||||
|
||||
|
@ -46,22 +45,25 @@ struct TLB_LinkedEntry {
|
|||
TLB_Entry entry;
|
||||
TLB_LinkedEntry *next_entry;
|
||||
};
|
||||
#define NBUCKETS 65536
|
||||
#define NBUCKETS 4096
|
||||
static TLB_LinkedEntry full_table[65536];
|
||||
static u32 full_table_size;
|
||||
static TLB_LinkedEntry *entry_buckets[NBUCKETS];
|
||||
|
||||
static u16 bucket_index(u32 address, int size)
|
||||
static u16 bucket_index(u32 address, int size, u32 asid)
|
||||
{
|
||||
return ((address >> 16) ^ ((address & 0xFC00) | size)) & (NBUCKETS - 1);
|
||||
return ((address >> 20) ^ (address >> 12) ^ (address | asid | (size << 8))) & (NBUCKETS - 1);
|
||||
}
|
||||
|
||||
static void cache_entry(const TLB_Entry &entry)
|
||||
{
|
||||
if (entry.Data.SZ0 == 0 && entry.Data.SZ1 == 0)
|
||||
return;
|
||||
verify(full_table_size < ARRAY_SIZE(full_table));
|
||||
u16 bucket = bucket_index(entry.Address.VPN << 10, entry.Data.SZ1 * 2 + entry.Data.SZ0);
|
||||
|
||||
full_table[full_table_size].entry = entry;
|
||||
|
||||
u16 bucket = bucket_index(entry.Address.VPN << 10, entry.Data.SZ1 * 2 + entry.Data.SZ0, entry.Address.ASID);
|
||||
full_table[full_table_size].next_entry = entry_buckets[bucket];
|
||||
entry_buckets[bucket] = &full_table[full_table_size];
|
||||
full_table_size++;
|
||||
|
@ -80,7 +82,7 @@ bool find_entry_by_page_size(u32 address, const TLB_Entry **ret_entry)
|
|||
size == 2 ? 6 :
|
||||
size == 3 ? 10 : 0;
|
||||
u32 vpn = (address >> (10 + shift)) << shift;
|
||||
u16 bucket = bucket_index(vpn << 10, size);
|
||||
u16 bucket = bucket_index(vpn << 10, size, CCN_PTEH.ASID);
|
||||
TLB_LinkedEntry *pEntry = entry_buckets[bucket];
|
||||
while (pEntry != NULL)
|
||||
{
|
||||
|
@ -109,9 +111,6 @@ static bool find_entry(u32 address, const TLB_Entry **ret_entry)
|
|||
// 1m
|
||||
if (find_entry_by_page_size<3>(address, ret_entry))
|
||||
return true;
|
||||
// 1k
|
||||
if (find_entry_by_page_size<0>(address, ret_entry))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -184,11 +183,13 @@ bool UTLB_Sync(u32 entry)
|
|||
TLB_Entry& tlb_entry = UTLB[entry];
|
||||
u32 sz = tlb_entry.Data.SZ1 * 2 + tlb_entry.Data.SZ0;
|
||||
|
||||
tlb_entry.Address.VPN &= mmu_mask[sz] >> 10;
|
||||
tlb_entry.Data.PPN &= mmu_mask[sz] >> 10;
|
||||
|
||||
lru_entry = &tlb_entry;
|
||||
lru_mask = mmu_mask[sz];
|
||||
lru_address = (tlb_entry.Address.VPN << 10) & lru_mask;
|
||||
lru_address = tlb_entry.Address.VPN << 10;
|
||||
|
||||
tlb_entry.Address.VPN = lru_address >> 10;
|
||||
cache_entry(tlb_entry);
|
||||
|
||||
if (!mmu_enabled() && (tlb_entry.Address.VPN & (0xFC000000 >> 10)) == (0xE0000000 >> 10))
|
||||
|
@ -217,44 +218,47 @@ u32 mmu_full_lookup(u32 va, const TLB_Entry** tlb_entry_ret, u32& rv)
|
|||
/*|| (sr.MD == 1 && CCN_MMUCR.SV == 1)*/)) // SV=1 not handled
|
||||
{
|
||||
//VPN->PPN | low bits
|
||||
// TODO mask off PPN when updating TLB to avoid doing it at look up time
|
||||
rv = ((lru_entry->Data.PPN << 10) & lru_mask) | (va & (~lru_mask));
|
||||
*tlb_entry_ret = lru_entry;
|
||||
rv = (lru_entry->Data.PPN << 10) | (va & ~lru_mask);
|
||||
if (tlb_entry_ret != nullptr)
|
||||
*tlb_entry_ret = lru_entry;
|
||||
|
||||
return MMU_ERROR_NONE;
|
||||
}
|
||||
}
|
||||
const TLB_Entry *localEntry;
|
||||
if (tlb_entry_ret == nullptr)
|
||||
tlb_entry_ret = &localEntry;
|
||||
|
||||
if (find_entry(va, tlb_entry_ret))
|
||||
{
|
||||
u32 mask = mmu_mask[(*tlb_entry_ret)->Data.SZ1 * 2 + (*tlb_entry_ret)->Data.SZ0];
|
||||
rv = (((*tlb_entry_ret)->Data.PPN << 10) & mask) | (va & (~mask));
|
||||
rv = ((*tlb_entry_ret)->Data.PPN << 10) | (va & ~mask);
|
||||
lru_entry = *tlb_entry_ret;
|
||||
lru_mask = mask;
|
||||
lru_address = ((*tlb_entry_ret)->Address.VPN << 10);
|
||||
|
||||
return MMU_ERROR_NONE;
|
||||
}
|
||||
|
||||
#ifdef USE_WINCE_HACK
|
||||
// WinCE hack
|
||||
TLB_Entry entry;
|
||||
TLB_Entry& entry = UTLB[CCN_MMUCR.URC];
|
||||
if (wince_resolve_address(va, entry))
|
||||
{
|
||||
CCN_PTEL.reg_data = entry.Data.reg_data;
|
||||
CCN_PTEA.reg_data = entry.Assistance.reg_data;
|
||||
CCN_PTEH.reg_data = entry.Address.reg_data;
|
||||
UTLB[CCN_MMUCR.URC] = entry;
|
||||
|
||||
*tlb_entry_ret = &UTLB[CCN_MMUCR.URC];
|
||||
lru_entry = *tlb_entry_ret;
|
||||
lru_entry = *tlb_entry_ret = &entry;
|
||||
|
||||
u32 sz = lru_entry->Data.SZ1 * 2 + lru_entry->Data.SZ0;
|
||||
u32 sz = entry.Data.SZ1 * 2 + entry.Data.SZ0;
|
||||
lru_mask = mmu_mask[sz];
|
||||
lru_address = va & lru_mask;
|
||||
lru_address = va & mmu_mask[sz];
|
||||
entry.Data.PPN &= mmu_mask[sz] >> 10;
|
||||
|
||||
rv = ((lru_entry->Data.PPN << 10) & lru_mask) | (va & (~lru_mask));
|
||||
rv = (entry.Data.PPN << 10) | (va & ~mmu_mask[sz]);
|
||||
|
||||
cache_entry(*lru_entry);
|
||||
cache_entry(entry);
|
||||
|
||||
return MMU_ERROR_NONE;
|
||||
}
|
||||
|
@ -267,10 +271,7 @@ template u32 mmu_full_lookup<false>(u32 va, const TLB_Entry** tlb_entry_ret, u32
|
|||
template<u32 translation_type>
|
||||
u32 mmu_full_SQ(u32 va, u32& rv)
|
||||
{
|
||||
//Address=Dest&0xFFFFFFE0;
|
||||
|
||||
const TLB_Entry *entry;
|
||||
u32 lookup = mmu_full_lookup(va, &entry, rv);
|
||||
u32 lookup = mmu_full_lookup(va, nullptr, rv);
|
||||
|
||||
if (lookup != MMU_ERROR_NONE)
|
||||
return lookup;
|
||||
|
@ -285,18 +286,10 @@ template u32 mmu_full_SQ<MMU_TT_DWRITE>(u32 va, u32& rv);
|
|||
template<u32 translation_type, typename T>
|
||||
u32 mmu_data_translation(u32 va, u32& rv)
|
||||
{
|
||||
if (va & (sizeof(T) - 1))
|
||||
if (fast_reg_lut[va >> 29] != 0)
|
||||
{
|
||||
return MMU_ERROR_BADADDR;
|
||||
}
|
||||
|
||||
if (translation_type == MMU_TT_DWRITE)
|
||||
{
|
||||
if ((va & 0xFC000000) == 0xE0000000)
|
||||
{
|
||||
rv = va; //SQ writes are not translated, only write backs are.
|
||||
return MMU_ERROR_NONE;
|
||||
}
|
||||
rv = va;
|
||||
return MMU_ERROR_NONE;
|
||||
}
|
||||
|
||||
if ((va & 0xFC000000) == 0x7C000000)
|
||||
|
@ -306,14 +299,7 @@ u32 mmu_data_translation(u32 va, u32& rv)
|
|||
return MMU_ERROR_NONE;
|
||||
}
|
||||
|
||||
if (fast_reg_lut[va >> 29] != 0)
|
||||
{
|
||||
rv = va;
|
||||
return MMU_ERROR_NONE;
|
||||
}
|
||||
|
||||
const TLB_Entry *entry;
|
||||
u32 lookup = mmu_full_lookup(va, &entry, rv);
|
||||
u32 lookup = mmu_full_lookup(va, nullptr, rv);
|
||||
if (lookup == MMU_ERROR_NONE && (rv & 0x1C000000) == 0x1C000000)
|
||||
// map 1C000000-1FFFFFFF to P4 memory-mapped registers
|
||||
rv |= 0xF0000000;
|
||||
|
@ -342,7 +328,9 @@ template u32 mmu_data_translation<MMU_TT_DWRITE, u64>(u32 va, u32& rv);
|
|||
|
||||
void mmu_flush_table()
|
||||
{
|
||||
lru_entry = NULL;
|
||||
lru_entry = nullptr;
|
||||
flush_cache();
|
||||
lastVAddr[0] = 1;
|
||||
lastVAddr[1] = 1;
|
||||
}
|
||||
#endif // FAST_MMU
|
||||
|
|
|
@ -13,60 +13,14 @@ u32 ITLB_LRU_USE[64];
|
|||
// Used when FullMMU is off
|
||||
u32 sq_remap[64];
|
||||
|
||||
#if defined(NO_MMU)
|
||||
|
||||
//Sync memory mapping to MMU , suspend compiled blocks if needed.entry is a UTLB entry # , -1 is for full sync
|
||||
bool UTLB_Sync(u32 entry)
|
||||
{
|
||||
if ((UTLB[entry].Address.VPN & (0xFC000000 >> 10)) == (0xE0000000 >> 10))
|
||||
{
|
||||
u32 vpn_sq = ((UTLB[entry].Address.VPN & 0x7FFFF) >> 10) & 0x3F;//upper bits are always known [0xE0/E1/E2/E3]
|
||||
sq_remap[vpn_sq] = UTLB[entry].Data.PPN << 10;
|
||||
INFO_LOG(SH4, "SQ remap %d : 0x%X to 0x%X", entry, UTLB[entry].Address.VPN << 10, UTLB[entry].Data.PPN << 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
INFO_LOG(SH4, "MEM remap %d : 0x%X to 0x%X", entry, UTLB[entry].Address.VPN << 10, UTLB[entry].Data.PPN << 10);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
//Sync memory mapping to MMU, suspend compiled blocks if needed.entry is a ITLB entry # , -1 is for full sync
|
||||
void ITLB_Sync(u32 entry)
|
||||
{
|
||||
INFO_LOG(SH4, "ITLB MEM remap %d : 0x%X to 0x%X",entry,ITLB[entry].Address.VPN<<10,ITLB[entry].Data.PPN<<10);
|
||||
}
|
||||
|
||||
void mmu_set_state()
|
||||
{
|
||||
}
|
||||
|
||||
void MMU_init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void MMU_reset()
|
||||
{
|
||||
memset(UTLB,0,sizeof(UTLB));
|
||||
memset(ITLB,0,sizeof(ITLB));
|
||||
}
|
||||
|
||||
void MMU_term()
|
||||
{
|
||||
}
|
||||
#else
|
||||
/*
|
||||
MMU support code
|
||||
This is mostly hacked-on as the core was never meant to have mmu support
|
||||
|
||||
There are two modes, one with 'full' mmu emulation (for wince/bleem/wtfever)
|
||||
and a fast-hack mode for 1mb sqremaps (for katana)
|
||||
|
||||
defining NO_MMU disables the full mmu emulation
|
||||
*/
|
||||
#include "mmu.h"
|
||||
#include "mmu_impl.h"
|
||||
#include "hw/sh4/sh4_if.h"
|
||||
#include "ccn.h"
|
||||
#include "hw/sh4/sh4_interrupts.h"
|
||||
|
@ -75,9 +29,6 @@ defining NO_MMU disables the full mmu emulation
|
|||
|
||||
#include "hw/mem/_vmem.h"
|
||||
|
||||
template<bool internal = false>
|
||||
u32 mmu_full_lookup(u32 va, u32& idx, u32& rv);
|
||||
|
||||
//#define TRACE_WINCE_SYSCALLS
|
||||
|
||||
#ifdef TRACE_WINCE_SYSCALLS
|
||||
|
@ -88,31 +39,14 @@ u32 unresolved_unicode_string;
|
|||
|
||||
#define printf_mmu(...) DEBUG_LOG(SH4, __VA_ARGS__)
|
||||
|
||||
extern const u32 mmu_mask[4] =
|
||||
{
|
||||
((0xFFFFFFFF) >> 10) << 10, //1 kb page
|
||||
((0xFFFFFFFF) >> 12) << 12, //4 kb page
|
||||
((0xFFFFFFFF) >> 16) << 16, //64 kb page
|
||||
((0xFFFFFFFF) >> 20) << 20 //1 MB page
|
||||
};
|
||||
|
||||
extern const u32 fast_reg_lut[8] =
|
||||
{
|
||||
0, 0, 0, 0 //P0-U0
|
||||
, 1 //P1
|
||||
, 1 //P2
|
||||
, 0 //P3
|
||||
, 1 //P4
|
||||
};
|
||||
|
||||
const u32 ITLB_LRU_OR[4] =
|
||||
constexpr u32 ITLB_LRU_OR[4] =
|
||||
{
|
||||
0x00,//000xxx
|
||||
0x20,//1xx00x
|
||||
0x14,//x1x1x0
|
||||
0x0B,//xx1x11
|
||||
};
|
||||
const u32 ITLB_LRU_AND[4] =
|
||||
constexpr u32 ITLB_LRU_AND[4] =
|
||||
{
|
||||
0x07,//000xxx
|
||||
0x39,//1xx00x
|
||||
|
@ -120,6 +54,10 @@ const u32 ITLB_LRU_AND[4] =
|
|||
0x3F,//xx1x11
|
||||
};
|
||||
|
||||
u32 lastVAddr[2] { 1, 1 };
|
||||
u32 lastPAddr[2];
|
||||
u8 lastIdx;
|
||||
|
||||
#ifndef FAST_MMU
|
||||
//sync mem mapping to mmu , suspend compiled blocks if needed.entry is a UTLB entry # , -1 is for full sync
|
||||
bool UTLB_Sync(u32 entry)
|
||||
|
@ -149,19 +87,10 @@ void ITLB_Sync(u32 entry)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void RaiseException(u32 expEvnt, u32 callVect) {
|
||||
#if !defined(NO_MMU)
|
||||
debugger::debugTrap(expEvnt); // FIXME CCN_TEA and CCN_PTEH have been updated already
|
||||
SH4ThrownException ex = { next_pc - 2, expEvnt, callVect };
|
||||
throw ex;
|
||||
#else
|
||||
msgboxf("Can't raise exceptions yet", MBX_ICONERROR);
|
||||
#endif
|
||||
}
|
||||
|
||||
void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
|
||||
template<typename F>
|
||||
static void mmuException(u32 mmu_error, u32 address, u32 am, F raise)
|
||||
{
|
||||
printf_mmu("mmu_raise_exception -> pc = 0x%X : ", next_pc);
|
||||
printf_mmu("MMU exception -> pc = 0x%X : ", next_pc);
|
||||
CCN_TEA = address;
|
||||
CCN_PTEH.VPN = address >> 10;
|
||||
|
||||
|
@ -169,18 +98,18 @@ void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
|
|||
{
|
||||
//No error
|
||||
case MMU_ERROR_NONE:
|
||||
die("Error : mmu_raise_exception(MMU_ERROR_NONE)");
|
||||
break;
|
||||
die("Error: mmu_error == MMU_ERROR_NONE)");
|
||||
return;
|
||||
|
||||
//TLB miss
|
||||
case MMU_ERROR_TLB_MISS:
|
||||
printf_mmu("MMU_ERROR_UTLB_MISS 0x%X, handled", address);
|
||||
if (am == MMU_TT_DWRITE) //WTLBMISS - Write Data TLB Miss Exception
|
||||
RaiseException(0x60, 0x400);
|
||||
raise(0x60, 0x400);
|
||||
else if (am == MMU_TT_DREAD) //RTLBMISS - Read Data TLB Miss Exception
|
||||
RaiseException(0x40, 0x400);
|
||||
raise(0x40, 0x400);
|
||||
else //ITLBMISS - Instruction TLB Miss Exception
|
||||
RaiseException(0x40, 0x400);
|
||||
raise(0x40, 0x400);
|
||||
return;
|
||||
|
||||
//TLB Multihit
|
||||
|
@ -192,11 +121,11 @@ void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
|
|||
case MMU_ERROR_PROTECTED:
|
||||
printf_mmu("MMU_ERROR_PROTECTED 0x%X, handled", address);
|
||||
if (am == MMU_TT_DWRITE) //WRITEPROT - Write Data TLB Protection Violation Exception
|
||||
RaiseException(0xC0, 0x100);
|
||||
raise(0xC0, 0x100);
|
||||
else if (am == MMU_TT_DREAD) //READPROT - Data TLB Protection Violation Exception
|
||||
RaiseException(0xA0, 0x100);
|
||||
raise(0xA0, 0x100);
|
||||
else //READPROT - Instr TLB Protection Violation Exception
|
||||
RaiseException(0xA0, 0x100);
|
||||
raise(0xA0, 0x100);
|
||||
return;
|
||||
|
||||
//Mem is write protected , firstwrite
|
||||
|
@ -204,7 +133,7 @@ void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
|
|||
printf_mmu("MMU_ERROR_FIRSTWRITE");
|
||||
verify(am == MMU_TT_DWRITE);
|
||||
//FIRSTWRITE - Initial Page Write Exception
|
||||
RaiseException(0x80, 0x100);
|
||||
raise(0x80, 0x100);
|
||||
return;
|
||||
|
||||
//data read/write missasligned
|
||||
|
@ -212,12 +141,12 @@ void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
|
|||
if (am == MMU_TT_DWRITE) //WADDERR - Write Data Address Error
|
||||
{
|
||||
printf_mmu("MMU_ERROR_BADADDR(dw) 0x%X", address);
|
||||
RaiseException(0x100, 0x100);
|
||||
raise(0x100, 0x100);
|
||||
}
|
||||
else if (am == MMU_TT_DREAD) //RADDERR - Read Data Address Error
|
||||
{
|
||||
printf_mmu("MMU_ERROR_BADADDR(dr) 0x%X", address);
|
||||
RaiseException(0xE0, 0x100);
|
||||
raise(0xE0, 0x100);
|
||||
}
|
||||
else //IADDERR - Instruction Address Error
|
||||
{
|
||||
|
@ -225,7 +154,7 @@ void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
|
|||
if (!print_wince_syscall(address))
|
||||
#endif
|
||||
printf_mmu("MMU_ERROR_BADADDR(i) 0x%X", address);
|
||||
RaiseException(0xE0, 0x100);
|
||||
raise(0xE0, 0x100);
|
||||
}
|
||||
return;
|
||||
|
||||
|
@ -234,99 +163,28 @@ void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
|
|||
INFO_LOG(SH4, "MMU_ERROR_EXECPROT 0x%X", address);
|
||||
|
||||
//EXECPROT - Instruction TLB Protection Violation Exception
|
||||
RaiseException(0xA0, 0x100);
|
||||
raise(0xA0, 0x100);
|
||||
return;
|
||||
}
|
||||
|
||||
die("Unknown mmu_error");
|
||||
}
|
||||
|
||||
void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
|
||||
{
|
||||
mmuException(mmu_error, address, am, [](u32 event, u32 vector) {
|
||||
debugger::debugTrap(event); // FIXME CCN_TEA and CCN_PTEH have been updated already
|
||||
SH4ThrownException ex { next_pc - 2, event, vector };
|
||||
throw ex;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void DoMMUException(u32 address, u32 mmu_error, u32 access_type)
|
||||
{
|
||||
printf_mmu("DoMMUException -> pc = 0x%X : %d ", next_pc, access_type);
|
||||
CCN_TEA = address;
|
||||
CCN_PTEH.VPN = address >> 10;
|
||||
|
||||
switch (mmu_error)
|
||||
{
|
||||
//No error
|
||||
case MMU_ERROR_NONE:
|
||||
die("Error : mmu_raise_exception(MMU_ERROR_NONE)");
|
||||
break;
|
||||
|
||||
//TLB miss
|
||||
case MMU_ERROR_TLB_MISS:
|
||||
printf_mmu("MMU_ERROR_UTLB_MISS 0x%X, handled", address);
|
||||
if (access_type == MMU_TT_DWRITE) //WTLBMISS - Write Data TLB Miss Exception
|
||||
Do_Exception(next_pc, 0x60, 0x400);
|
||||
else if (access_type == MMU_TT_DREAD) //RTLBMISS - Read Data TLB Miss Exception
|
||||
Do_Exception(next_pc, 0x40, 0x400);
|
||||
else //ITLBMISS - Instruction TLB Miss Exception
|
||||
Do_Exception(next_pc, 0x40, 0x400);
|
||||
|
||||
return;
|
||||
break;
|
||||
|
||||
//TLB Multihit
|
||||
case MMU_ERROR_TLB_MHIT:
|
||||
INFO_LOG(SH4, "MMU_ERROR_TLB_MHIT @ 0x%X", address);
|
||||
break;
|
||||
|
||||
//Mem is read/write protected (depends on translation type)
|
||||
case MMU_ERROR_PROTECTED:
|
||||
printf_mmu("MMU_ERROR_PROTECTED 0x%X, handled", address);
|
||||
if (access_type == MMU_TT_DWRITE) //WRITEPROT - Write Data TLB Protection Violation Exception
|
||||
Do_Exception(next_pc, 0xC0, 0x100);
|
||||
else if (access_type == MMU_TT_DREAD) //READPROT - Data TLB Protection Violation Exception
|
||||
Do_Exception(next_pc, 0xA0, 0x100);
|
||||
else
|
||||
{
|
||||
verify(false);
|
||||
}
|
||||
return;
|
||||
break;
|
||||
|
||||
//Mem is write protected , firstwrite
|
||||
case MMU_ERROR_FIRSTWRITE:
|
||||
printf_mmu("MMU_ERROR_FIRSTWRITE");
|
||||
verify(access_type == MMU_TT_DWRITE);
|
||||
//FIRSTWRITE - Initial Page Write Exception
|
||||
Do_Exception(next_pc, 0x80, 0x100);
|
||||
|
||||
return;
|
||||
break;
|
||||
|
||||
//data read/write missasligned
|
||||
case MMU_ERROR_BADADDR:
|
||||
if (access_type == MMU_TT_DWRITE) //WADDERR - Write Data Address Error
|
||||
Do_Exception(next_pc, 0x100, 0x100);
|
||||
else if (access_type == MMU_TT_DREAD) //RADDERR - Read Data Address Error
|
||||
Do_Exception(next_pc, 0xE0, 0x100);
|
||||
else //IADDERR - Instruction Address Error
|
||||
{
|
||||
#ifdef TRACE_WINCE_SYSCALLS
|
||||
if (!print_wince_syscall(address))
|
||||
#endif
|
||||
printf_mmu("MMU_ERROR_BADADDR(i) 0x%X", address);
|
||||
Do_Exception(next_pc, 0xE0, 0x100);
|
||||
return;
|
||||
}
|
||||
printf_mmu("MMU_ERROR_BADADDR(d) 0x%X, handled", address);
|
||||
return;
|
||||
break;
|
||||
|
||||
//Can't Execute
|
||||
case MMU_ERROR_EXECPROT:
|
||||
INFO_LOG(SH4, "MMU_ERROR_EXECPROT 0x%X", address);
|
||||
|
||||
//EXECPROT - Instruction TLB Protection Violation Exception
|
||||
Do_Exception(next_pc, 0xA0, 0x100);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
die("Unknown mmu_error");
|
||||
mmuException(mmu_error, address, access_type, [](u32 event, u32 vector) {
|
||||
Do_Exception(next_pc, event, vector);
|
||||
});
|
||||
}
|
||||
|
||||
bool mmu_match(u32 va, CCN_PTEH_type Address, CCN_PTEL_type Data)
|
||||
|
@ -396,10 +254,9 @@ u32 mmu_full_lookup(u32 va, const TLB_Entry** tlb_entry_ret, u32& rv)
|
|||
|
||||
return MMU_ERROR_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
//Simple QACR translation for mmu (when AT is off)
|
||||
u32 mmu_QACR_SQ(u32 va)
|
||||
static u32 mmu_QACR_SQ(u32 va)
|
||||
{
|
||||
u32 QACR;
|
||||
|
||||
|
@ -412,7 +269,6 @@ u32 mmu_QACR_SQ(u32 va)
|
|||
return QACR + va;
|
||||
}
|
||||
|
||||
#ifndef FAST_MMU
|
||||
template<u32 translation_type>
|
||||
u32 mmu_full_SQ(u32 va, u32& rv)
|
||||
{
|
||||
|
@ -709,6 +565,8 @@ void mmu_flush_table()
|
|||
|
||||
for (u32 i = 0; i < 64; i++)
|
||||
UTLB[i].Data.V = 0;
|
||||
lastVAddr[0] = 1;
|
||||
lastVAddr[1] = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -773,4 +631,3 @@ bool mmu_TranslateSQW(u32 adr, u32* out)
|
|||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#define MMU_ERROR_PROTECTED 3
|
||||
//Mem is write protected , firstwrite
|
||||
#define MMU_ERROR_FIRSTWRITE 4
|
||||
//data-Opcode read/write missasligned
|
||||
//data-Opcode read/write misaligned
|
||||
#define MMU_ERROR_BADADDR 5
|
||||
//Can't Execute
|
||||
#define MMU_ERROR_EXECPROT 6
|
||||
|
@ -38,9 +38,24 @@ struct TLB_Entry
|
|||
extern TLB_Entry UTLB[64];
|
||||
extern TLB_Entry ITLB[4];
|
||||
extern u32 sq_remap[64];
|
||||
extern const u32 fast_reg_lut[8];
|
||||
|
||||
//These are working only for SQ remaps on ndce
|
||||
constexpr u32 fast_reg_lut[8] =
|
||||
{
|
||||
0, 0, 0, 0 //P0-U0
|
||||
, 1 //P1
|
||||
, 1 //P2
|
||||
, 0 //P3
|
||||
, 1 //P4
|
||||
};
|
||||
|
||||
constexpr u32 mmu_mask[4] =
|
||||
{
|
||||
((0xFFFFFFFF) >> 10) << 10, //1 kb page
|
||||
((0xFFFFFFFF) >> 12) << 12, //4 kb page
|
||||
((0xFFFFFFFF) >> 16) << 16, //64 kb page
|
||||
((0xFFFFFFFF) >> 20) << 20 //1 MB page
|
||||
};
|
||||
|
||||
bool UTLB_Sync(u32 entry);
|
||||
void ITLB_Sync(u32 entry);
|
||||
|
||||
|
@ -51,11 +66,7 @@ void mmu_raise_exception(u32 mmu_error, u32 address, u32 am);
|
|||
|
||||
static INLINE bool mmu_enabled()
|
||||
{
|
||||
#ifndef NO_MMU
|
||||
return config::FullMMU && CCN_MMUCR.AT == 1;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<bool internal = false>
|
||||
|
@ -75,83 +86,91 @@ static INLINE u32 mmu_instruction_translation(u32 va, u32& rv)
|
|||
return MMU_ERROR_NONE;
|
||||
}
|
||||
|
||||
const TLB_Entry *tlb_entry;
|
||||
return mmu_full_lookup(va, &tlb_entry, rv);
|
||||
return mmu_full_lookup(va, nullptr, rv);
|
||||
}
|
||||
#else
|
||||
u32 mmu_instruction_translation(u32 va, u32& rv);
|
||||
#endif
|
||||
|
||||
template<u32 translation_type, typename T>
|
||||
extern u32 mmu_data_translation(u32 va, u32& rv);
|
||||
u32 mmu_data_translation(u32 va, u32& rv);
|
||||
void DoMMUException(u32 addr, u32 mmu_error, u32 access_type);
|
||||
|
||||
template<u32 translation_type>
|
||||
bool mmu_is_translated(u32 va, u32 size)
|
||||
inline static bool mmu_is_translated(u32 va, u32 size)
|
||||
{
|
||||
#ifndef FAST_MMU
|
||||
if (va & (size - 1))
|
||||
return true;
|
||||
|
||||
if (translation_type == MMU_TT_DWRITE)
|
||||
{
|
||||
if ((va & 0xFC000000) == 0xE0000000)
|
||||
//SQ writes are not translated, only write backs are.
|
||||
return false;
|
||||
}
|
||||
if ((va & 0xFC000000) == 0x7C000000)
|
||||
// On-chip RAM area isn't translated
|
||||
return false;
|
||||
#endif
|
||||
|
||||
if (fast_reg_lut[va >> 29] != 0)
|
||||
return false;
|
||||
|
||||
if ((va & 0xFC000000) == 0x7C000000)
|
||||
// On-chip RAM area isn't translated
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(NO_MMU)
|
||||
bool inline mmu_TranslateSQW(u32 addr, u32* mapped) {
|
||||
*mapped = sq_remap[(addr>>20)&0x3F] | (addr & 0xFFFE0);
|
||||
return true;
|
||||
template<typename T> T DYNACALL mmu_ReadMem(u32 adr);
|
||||
u16 DYNACALL mmu_IReadMem16(u32 addr);
|
||||
|
||||
template<typename T> void DYNACALL mmu_WriteMem(u32 adr, T data);
|
||||
|
||||
bool mmu_TranslateSQW(u32 adr, u32* out);
|
||||
|
||||
extern u32 lastVAddr[2];
|
||||
extern u32 lastPAddr[2];
|
||||
extern u8 lastIdx;
|
||||
|
||||
template<typename T>
|
||||
std::pair<T, bool> DYNACALL mmu_ReadMemNoEx(u32 adr)
|
||||
{
|
||||
u32 addr;
|
||||
if (lastVAddr[0] == (adr & ~PAGE_MASK)) {
|
||||
addr = lastPAddr[0] | (adr & PAGE_MASK);
|
||||
}
|
||||
void inline mmu_flush_table() {}
|
||||
#else
|
||||
template<typename T> T DYNACALL mmu_ReadMem(u32 adr);
|
||||
u16 DYNACALL mmu_IReadMem16(u32 addr);
|
||||
|
||||
template<typename T> void DYNACALL mmu_WriteMem(u32 adr, T data);
|
||||
|
||||
bool mmu_TranslateSQW(u32 adr, u32* out);
|
||||
|
||||
template<typename T>
|
||||
T DYNACALL mmu_ReadMemNoEx(u32 adr, u32 *exception_occurred)
|
||||
else if (lastVAddr[1] == (adr & ~PAGE_MASK)) {
|
||||
addr = lastPAddr[1] | (adr & PAGE_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 addr;
|
||||
u32 rv = mmu_data_translation<MMU_TT_DREAD, T>(adr, addr);
|
||||
if (rv != MMU_ERROR_NONE)
|
||||
if (unlikely(rv != MMU_ERROR_NONE))
|
||||
{
|
||||
DoMMUException(adr, rv, MMU_TT_DREAD);
|
||||
*exception_occurred = 1;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
*exception_occurred = 0;
|
||||
return _vmem_readt<T, T>(addr);
|
||||
return std::make_pair(0, true);
|
||||
}
|
||||
lastVAddr[lastIdx] = adr & ~PAGE_MASK;
|
||||
lastPAddr[lastIdx] = addr & ~PAGE_MASK;
|
||||
lastIdx ^= 1;
|
||||
}
|
||||
return std::make_pair(_vmem_readt<T, T>(addr), false);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
u32 DYNACALL mmu_WriteMemNoEx(u32 adr, T data)
|
||||
template<typename T>
|
||||
u32 DYNACALL mmu_WriteMemNoEx(u32 adr, T data)
|
||||
{
|
||||
u32 addr;
|
||||
if (lastVAddr[0] == (adr & ~PAGE_MASK)) {
|
||||
addr = lastPAddr[0] | (adr & PAGE_MASK);
|
||||
}
|
||||
else if (lastVAddr[1] == (adr & ~PAGE_MASK)) {
|
||||
addr = lastPAddr[1] | (adr & PAGE_MASK);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 addr;
|
||||
u32 rv = mmu_data_translation<MMU_TT_DWRITE, T>(adr, addr);
|
||||
if (rv != MMU_ERROR_NONE)
|
||||
u32 rv = mmu_data_translation<MMU_TT_DREAD, T>(adr, addr);
|
||||
if (unlikely(rv != MMU_ERROR_NONE))
|
||||
{
|
||||
DoMMUException(adr, rv, MMU_TT_DWRITE);
|
||||
return 1;
|
||||
}
|
||||
_vmem_writet<T>(addr, data);
|
||||
return 0;
|
||||
lastVAddr[lastIdx] = adr & ~PAGE_MASK;
|
||||
lastPAddr[lastIdx] = addr & ~PAGE_MASK;
|
||||
lastIdx ^= 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
_vmem_writet<T>(addr, data);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
#include "types.h"
|
||||
#include "ccn.h"
|
||||
#include "mmu.h"
|
||||
|
||||
void MMU_Init();
|
||||
void MMU_Reset(bool Manual);
|
||||
void MMU_Term();
|
||||
|
||||
template<u32 translation_type> u32 mmu_full_SQ(u32 va, u32& rv);
|
|
@ -106,15 +106,11 @@ struct SH4ThrownException {
|
|||
|
||||
static INLINE void RaiseFPUDisableException()
|
||||
{
|
||||
#if !defined(NO_MMU)
|
||||
if (config::FullMMU)
|
||||
{
|
||||
SH4ThrownException ex = { next_pc - 2, 0x800, 0x100 };
|
||||
SH4ThrownException ex { next_pc - 2, 0x800, 0x100 };
|
||||
throw ex;
|
||||
}
|
||||
#else
|
||||
msgboxf("Full MMU support needed", MBX_ICONERROR);
|
||||
#endif
|
||||
}
|
||||
|
||||
static INLINE void AdjustDelaySlotException(SH4ThrownException& ex)
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
//main system mem
|
||||
VArray2 mem_b;
|
||||
|
||||
#ifndef NO_MMU
|
||||
// Memory handlers
|
||||
ReadMem8Func ReadMem8;
|
||||
ReadMem16Func ReadMem16;
|
||||
|
@ -29,7 +28,6 @@ WriteMem8Func WriteMem8;
|
|||
WriteMem16Func WriteMem16;
|
||||
WriteMem32Func WriteMem32;
|
||||
WriteMem64Func WriteMem64;
|
||||
#endif
|
||||
|
||||
//AREA 1
|
||||
static _vmem_handler area1_32b;
|
||||
|
@ -313,7 +311,6 @@ static bool interpreterRunning = false;
|
|||
|
||||
void SetMemoryHandlers()
|
||||
{
|
||||
#ifndef NO_MMU
|
||||
#ifdef STRICT_MODE
|
||||
if (config::DynarecEnabled && interpreterRunning)
|
||||
{
|
||||
|
@ -366,5 +363,4 @@ void SetMemoryHandlers()
|
|||
WriteMem32 = &_vmem_WriteMem32;
|
||||
WriteMem64 = &_vmem_WriteMem64;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -8,23 +8,6 @@ extern VArray2 mem_b;
|
|||
#include "hw/mem/_vmem.h"
|
||||
#include "modules/mmu.h"
|
||||
|
||||
#ifdef NO_MMU
|
||||
#define ReadMem8 _vmem_ReadMem8
|
||||
#define ReadMem16 _vmem_ReadMem16
|
||||
#define IReadMem16 ReadMem16
|
||||
#define ReadMem32 _vmem_ReadMem32
|
||||
#define ReadMem64 _vmem_ReadMem64
|
||||
|
||||
#define WriteMem8 _vmem_WriteMem8
|
||||
#define WriteMem16 _vmem_WriteMem16
|
||||
#define WriteMem32 _vmem_WriteMem32
|
||||
#define WriteMem64 _vmem_WriteMem64
|
||||
#ifdef STRICT_MODE
|
||||
#error Strict mode requires the MMU
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef _MSC_VER
|
||||
typedef u8 (DYNACALL *ReadMem8Func)(u32 addr);
|
||||
typedef u16 (DYNACALL *ReadMem16Func)(u32 addr);
|
||||
|
@ -58,8 +41,6 @@ extern WriteMem16Func WriteMem16;
|
|||
extern WriteMem32Func WriteMem32;
|
||||
extern WriteMem64Func WriteMem64;
|
||||
|
||||
#endif
|
||||
|
||||
#define ReadMem8_nommu _vmem_ReadMem8
|
||||
#define ReadMem16_nommu _vmem_ReadMem16
|
||||
#define IReadMem16_nommu _vmem_IReadMem16
|
||||
|
|
|
@ -315,16 +315,11 @@ void DYNACALL WriteMem_P4(u32 addr,T data)
|
|||
{
|
||||
if (addr&0x80)
|
||||
{
|
||||
#ifdef NO_MMU
|
||||
INFO_LOG(SH4, "Unhandled p4 Write [Unified TLB address array, Associative Write] 0x%x = %x", addr, data);
|
||||
#endif
|
||||
|
||||
CCN_PTEH_type t;
|
||||
t.reg_data=data;
|
||||
|
||||
u32 va=t.VPN<<10;
|
||||
|
||||
#ifndef NO_MMU
|
||||
for (int i=0;i<64;i++)
|
||||
{
|
||||
if (mmu_match(va,UTLB[i].Address,UTLB[i].Data))
|
||||
|
@ -344,7 +339,6 @@ void DYNACALL WriteMem_P4(u32 addr,T data)
|
|||
ITLB_Sync(i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -46,7 +46,7 @@ void sigill_handler(int sn, siginfo_t * si, void *segfault_ctx) {
|
|||
|
||||
void fault_handler (int sn, siginfo_t * si, void *segfault_ctx)
|
||||
{
|
||||
#if !defined(NO_MMU) && defined(HOST_64BIT_CPU)
|
||||
#if defined(HOST_64BIT_CPU)
|
||||
// WinCE virtual memory
|
||||
#if HOST_CPU == CPU_ARM64
|
||||
#define HOST_CTX_READY
|
||||
|
|
|
@ -113,31 +113,23 @@ void ngen_GetFeatures(ngen_features* dst)
|
|||
template<typename T>
|
||||
static T ReadMemNoEx(u32 addr, u32, u32 pc)
|
||||
{
|
||||
#ifndef NO_MMU
|
||||
u32 ex;
|
||||
T rv = mmu_ReadMemNoEx<T>(addr, &ex);
|
||||
if (ex)
|
||||
auto rv = mmu_ReadMemNoEx<T>(addr);
|
||||
if (rv.second)
|
||||
{
|
||||
spc = pc;
|
||||
handleException();
|
||||
}
|
||||
return rv;
|
||||
#else
|
||||
return (T)0; // not used
|
||||
#endif
|
||||
return rv.first;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void WriteMemNoEx(u32 addr, T data, u32 pc)
|
||||
{
|
||||
#ifndef NO_MMU
|
||||
u32 ex = mmu_WriteMemNoEx<T>(addr, data);
|
||||
if (ex)
|
||||
if (mmu_WriteMemNoEx<T>(addr, data))
|
||||
{
|
||||
spc = pc;
|
||||
handleException();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void interpreter_fallback(u16 op, OpCallFP *oph, u32 pc)
|
||||
|
@ -1648,9 +1640,9 @@ private:
|
|||
|
||||
u32 size = op.flags & 0x7f;
|
||||
u32 addr = op.rs1._imm;
|
||||
if (mmu_enabled() && mmu_is_translated<MMU_TT_DREAD>(addr, size))
|
||||
if (mmu_enabled() && mmu_is_translated(addr, size))
|
||||
{
|
||||
if ((addr >> 12) != (block->vaddr >> 12))
|
||||
if ((addr >> 12) != (block->vaddr >> 12) && ((addr >> 12) != ((block->vaddr + block->guest_opcodes * 2 - 1) >> 12)))
|
||||
// When full mmu is on, only consider addresses in the same 4k page
|
||||
return false;
|
||||
u32 paddr;
|
||||
|
@ -1859,7 +1851,7 @@ private:
|
|||
|
||||
u32 size = op.flags & 0x7f;
|
||||
u32 addr = op.rs1._imm;
|
||||
if (mmu_enabled() && mmu_is_translated<MMU_TT_DWRITE>(addr, size))
|
||||
if (mmu_enabled() && mmu_is_translated(addr, size))
|
||||
{
|
||||
if ((addr >> 12) != (block->vaddr >> 12) && ((addr >> 12) != ((block->vaddr + block->guest_opcodes * 2 - 1) >> 12)))
|
||||
// When full mmu is on, only consider addresses in the same 4k page
|
||||
|
|
|
@ -41,7 +41,6 @@ static void (*handleException)();
|
|||
u32 mem_writes, mem_reads;
|
||||
u32 mem_rewrites_w, mem_rewrites_r;
|
||||
|
||||
static u32 exception_raised;
|
||||
static u64 jmp_rsp;
|
||||
|
||||
namespace MemSize {
|
||||
|
@ -104,38 +103,28 @@ static void ngen_blockcheckfail(u32 pc) {
|
|||
rdv_BlockCheckFail(pc);
|
||||
}
|
||||
|
||||
static void handle_mem_exception(u32 exception_raised, u32 pc)
|
||||
static void handle_mem_exception(u32 pc)
|
||||
{
|
||||
if (exception_raised)
|
||||
{
|
||||
spc = pc;
|
||||
cycle_counter += 2; // probably more is needed but no easy way to find out
|
||||
handleException();
|
||||
}
|
||||
spc = pc;
|
||||
cycle_counter += 2; // probably more is needed but no easy way to find out
|
||||
handleException();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T ReadMemNoEx(u32 addr, u32 pc)
|
||||
{
|
||||
#ifndef NO_MMU
|
||||
T rv = mmu_ReadMemNoEx<T>(addr, &exception_raised);
|
||||
handle_mem_exception(exception_raised, pc);
|
||||
auto rv = mmu_ReadMemNoEx<T>(addr);
|
||||
if (unlikely(rv.second))
|
||||
handle_mem_exception(pc);
|
||||
|
||||
return rv;
|
||||
#else
|
||||
// not used
|
||||
return (T)0;
|
||||
#endif
|
||||
return rv.first;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static u32 WriteMemNoEx(u32 addr, T data, u32 pc)
|
||||
static void WriteMemNoEx(u32 addr, T data, u32 pc)
|
||||
{
|
||||
#ifndef NO_MMU
|
||||
u32 exception_raised = mmu_WriteMemNoEx<T>(addr, data);
|
||||
handle_mem_exception(exception_raised, pc);
|
||||
return exception_raised;
|
||||
#endif
|
||||
if (mmu_WriteMemNoEx<T>(addr, data))
|
||||
handle_mem_exception(pc);
|
||||
}
|
||||
|
||||
static void handle_sh4_exception(SH4ThrownException& ex, u32 pc)
|
||||
|
@ -810,9 +799,9 @@ private:
|
|||
return false;
|
||||
u32 size = op.flags & 0x7f;
|
||||
u32 addr = op.rs1._imm;
|
||||
if (mmu_enabled() && mmu_is_translated<MMU_TT_DREAD>(addr, size))
|
||||
if (mmu_enabled() && mmu_is_translated(addr, size))
|
||||
{
|
||||
if ((addr >> 12) != (block->vaddr >> 12))
|
||||
if ((addr >> 12) != (block->vaddr >> 12) && ((addr >> 12) != ((block->vaddr + block->guest_opcodes * 2 - 1) >> 12)))
|
||||
// When full mmu is on, only consider addresses in the same 4k page
|
||||
return false;
|
||||
|
||||
|
@ -949,9 +938,9 @@ private:
|
|||
return false;
|
||||
u32 size = op.flags & 0x7f;
|
||||
u32 addr = op.rs1._imm;
|
||||
if (mmu_enabled() && mmu_is_translated<MMU_TT_DWRITE>(addr, size))
|
||||
if (mmu_enabled() && mmu_is_translated(addr, size))
|
||||
{
|
||||
if ((addr >> 12) != (block->vaddr >> 12))
|
||||
if ((addr >> 12) != (block->vaddr >> 12) && ((addr >> 12) != ((block->vaddr + block->guest_opcodes * 2 - 1) >> 12)))
|
||||
// When full mmu is on, only consider addresses in the same 4k page
|
||||
return false;
|
||||
|
||||
|
|
13
core/types.h
13
core/types.h
|
@ -170,18 +170,9 @@ int darw_printf(const char* Text,...);
|
|||
|
||||
#include "log/Log.h"
|
||||
|
||||
#ifndef NO_MMU
|
||||
#define _X_x_X_MMU_VER_STR "/mmu"
|
||||
#else
|
||||
#define _X_x_X_MMU_VER_STR ""
|
||||
#endif
|
||||
|
||||
|
||||
#define VER_EMUNAME "Flycast"
|
||||
|
||||
#define VER_FULLNAME VER_EMUNAME " git" _X_x_X_MMU_VER_STR " (built " __DATE__ "@" __TIME__ ")"
|
||||
#define VER_SHORTNAME VER_EMUNAME " git" _X_x_X_MMU_VER_STR
|
||||
|
||||
#define VER_FULLNAME VER_EMUNAME " (built " __DATE__ "@" __TIME__ ")"
|
||||
#define VER_SHORTNAME VER_EMUNAME
|
||||
|
||||
void os_DebugBreak();
|
||||
#define dbgbreak os_DebugBreak()
|
||||
|
|
|
@ -1055,7 +1055,6 @@
|
|||
AEE6279522247C2B00EC7E89 /* keyboard_device.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = keyboard_device.cpp; sourceTree = "<group>"; };
|
||||
AEF25640227C441F00348550 /* vmem32.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vmem32.cpp; sourceTree = "<group>"; };
|
||||
AEF25641227C441F00348550 /* vmem32.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vmem32.h; sourceTree = "<group>"; };
|
||||
AEF25643227C442F00348550 /* mmu_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mmu_impl.h; sourceTree = "<group>"; };
|
||||
AEF25644227C442F00348550 /* fastmmu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = fastmmu.cpp; sourceTree = "<group>"; };
|
||||
AEF25645227C442F00348550 /* wince.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wince.h; sourceTree = "<group>"; };
|
||||
AEF2564722886A2E00348550 /* posix_vmem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = posix_vmem.cpp; sourceTree = "<group>"; };
|
||||
|
@ -1835,7 +1834,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
AEF25644227C442F00348550 /* fastmmu.cpp */,
|
||||
AEF25643227C442F00348550 /* mmu_impl.h */,
|
||||
AEF25645227C442F00348550 /* wince.h */,
|
||||
84B7BE221B72720100F9733F /* bsc.cpp */,
|
||||
84B7BE231B72720100F9733F /* ccn.cpp */,
|
||||
|
|
Loading…
Reference in New Issue