mmu: dynamic switching with read/write mem function pointers

This commit is contained in:
Flyinghead 2019-03-17 22:59:18 +01:00
parent 34f46fb482
commit 73d50486d5
7 changed files with 127 additions and 81 deletions

View File

@ -46,10 +46,11 @@ void CCN_MMUCR_write(u32 addr, u32 value)
CCN_MMUCR_type temp;
temp.reg_data=value;
// if ((temp.AT!=CCN_MMUCR.AT) && (temp.AT==1))
// {
// printf("<*******>MMU Enabled , ONLY SQ remaps work<*******>\n");
// }
if (temp.AT != CCN_MMUCR.AT)
{
//printf("<*******>MMU Enabled , ONLY SQ remaps work<*******>\n");
mmu_set_state();
}
if (temp.TI != 0)
{

View File

@ -11,11 +11,13 @@
TLB_Entry UTLB[64];
TLB_Entry ITLB[4];
#if defined(NO_MMU)
//SQ fast remap , mainly hackish , assumes 1MB pages
//max 64MB can be remapped on SQ
// 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)
{
@ -38,6 +40,10 @@ void ITLB_Sync(u32 entry)
printf("ITLB MEM remap %d : 0x%X to 0x%X\n",entry,ITLB[entry].Address.VPN<<10,ITLB[entry].Data.PPN<<10);
}
void mmu_set_state()
{
}
void MMU_init()
{
@ -68,14 +74,23 @@ defining NO_MMU disables the full mmu emulation
#include "ccn.h"
#include "hw/sh4/sh4_interrupts.h"
#include "hw/sh4/sh4_if.h"
#include "hw/sh4/sh4_mem.h"
#include "hw/mem/_vmem.h"
#define printf_mmu(...)
#define printf_win32(...)
//SQ fast remap , mailny hackish , assumes 1 mb pages
//max 64 mb can be remapped on SQ
ReadMem8Func ReadMem8;
ReadMem16Func ReadMem16;
ReadMem16Func IReadMem16;
ReadMem32Func ReadMem32;
ReadMem64Func ReadMem64;
WriteMem8Func WriteMem8;
WriteMem16Func WriteMem16;
WriteMem32Func WriteMem32;
WriteMem64Func WriteMem64;
const u32 mmu_mask[4] =
{
@ -113,30 +128,22 @@ u32 ITLB_LRU_USE[64];
//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)
{
printf_mmu("UTLB MEM remap %d : 0x%X to 0x%X : %d\n", entry, UTLB[entry].Address.VPN << 10, UTLB[entry].Data.PPN << 10, UTLB[entry].Data.V);
printf_mmu("UTLB MEM remap %d : 0x%X to 0x%X : %d asid %d size %d\n", entry, UTLB[entry].Address.VPN << 10, UTLB[entry].Data.PPN << 10, UTLB[entry].Data.V,
UTLB[entry].Address.ASID, UTLB[entry].Data.SZ0 + UTLB[entry].Data.SZ1 * 2);
if (UTLB[entry].Data.V == 0)
return true;
if ((UTLB[entry].Address.VPN & (0xFC000000 >> 10)) == (0xE0000000 >> 10))
{
#ifdef NO_MMU
u32 vpn_sq = ((UTLB[entry].Address.VPN & (0x3FFFFFF >> 10)) >> 10) & 0x3F;//upper bits are allways known [0xE0/E1/E2/E3]
// Used when FullMMU is off
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;
log("SQ remap %d : 0x%X to 0x%X\n", entry, UTLB[entry].Address.VPN << 10, UTLB[entry].Data.PPN << 10);
#endif
return true;
}
else
{
#ifdef NO_MMU
if ((UTLB[entry].Address.VPN&(0x1FFFFFFF >> 10)) == (UTLB[entry].Data.PPN&(0x1FFFFFFF >> 10)))
{
log("Static remap %d : 0x%X to 0x%X\n", entry, UTLB[entry].Address.VPN << 10, UTLB[entry].Data.PPN << 10);
return true;
}
log("Dynamic remap %d : 0x%X to 0x%X\n", entry, UTLB[entry].Address.VPN << 10, UTLB[entry].Data.PPN << 10);
#endif
return false;//log("MEM remap %d : 0x%X to 0x%X\n",entry,UTLB[entry].Address.VPN<<10,UTLB[entry].Data.PPN<<10);
return false;
}
}
//sync mem mapping to mmu , suspend compiled blocks if needed.entry is a ITLB entry # , -1 is for full sync
@ -155,9 +162,9 @@ void RaiseException(u32 expEvnt, u32 callVect) {
}
u32 mmu_error_TT;
void mmu_raise_exeption(u32 mmu_error, u32 address, u32 am)
void mmu_raise_exception(u32 mmu_error, u32 address, u32 am)
{
printf_mmu("mmu_raise_exeption -> pc = 0x%X : ", next_pc);
printf_mmu("mmu_raise_exception -> pc = 0x%X : ", next_pc);
CCN_TEA = address;
CCN_PTEH.VPN = address >> 10;
@ -168,7 +175,7 @@ void mmu_raise_exeption(u32 mmu_error, u32 address, u32 am)
{
//No error
case MMU_ERROR_NONE:
printf("Error : mmu_raise_exeption(MMU_ERROR_NONE)\n");
printf("Error : mmu_raise_exception(MMU_ERROR_NONE)\n");
getc(stdin);
break;
@ -240,7 +247,7 @@ void mmu_raise_exeption(u32 mmu_error, u32 address, u32 am)
break;
}
__debugbreak();
die("Unknown mmu_error");
}
bool mmu_match(u32 va, CCN_PTEH_type Address, CCN_PTEL_type Data)
@ -512,6 +519,38 @@ retry_ITLB_Match:
return MMU_ERROR_NONE;
}
void mmu_set_state()
{
if (CCN_MMUCR.AT == 1 && settings.dreamcast.FullMMU)
{
printf("Enabling Full MMU support\n");
ReadMem8 = &mmu_ReadMem8;
ReadMem16 = &mmu_ReadMem16;
IReadMem16 = &mmu_IReadMem16;
ReadMem32 = &mmu_ReadMem32;
ReadMem64 = &mmu_ReadMem64;
WriteMem8 = &mmu_WriteMem8;
WriteMem16 = &mmu_WriteMem16;
WriteMem32 = &mmu_WriteMem32;
WriteMem64 = &mmu_WriteMem64;
}
else
{
ReadMem8 = &_vmem_ReadMem8;
ReadMem16 = &_vmem_ReadMem16;
IReadMem16 = &_vmem_ReadMem16;
ReadMem32 = &_vmem_ReadMem32;
ReadMem64 = &_vmem_ReadMem64;
WriteMem8 = &_vmem_WriteMem8;
WriteMem16 = &_vmem_WriteMem16;
WriteMem32 = &_vmem_WriteMem32;
WriteMem64 = &_vmem_WriteMem64;
}
}
void MMU_init()
{
memset(ITLB_LRU_USE, 0xFF, sizeof(ITLB_LRU_USE));
@ -528,6 +567,7 @@ void MMU_init()
}
}
}
mmu_set_state();
}
@ -535,6 +575,7 @@ void MMU_reset()
{
memset(UTLB, 0, sizeof(UTLB));
memset(ITLB, 0, sizeof(ITLB));
mmu_set_state();
}
void MMU_term()
@ -548,7 +589,7 @@ u8 DYNACALL mmu_ReadMem8(u32 adr)
if (tv == 0)
return _vmem_ReadMem8(addr);
else
mmu_raise_exeption(tv, adr, MMU_TT_DREAD);
mmu_raise_exception(tv, adr, MMU_TT_DREAD);
return 0;
}
@ -557,7 +598,7 @@ u16 DYNACALL mmu_ReadMem16(u32 adr)
{
if (adr & 1)
{
mmu_raise_exeption(MMU_ERROR_BADADDR, adr, MMU_TT_DREAD);
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DREAD);
return 0;
}
u32 addr;
@ -565,7 +606,7 @@ u16 DYNACALL mmu_ReadMem16(u32 adr)
if (tv == 0)
return _vmem_ReadMem16(addr);
else
mmu_raise_exeption(tv, adr, MMU_TT_DREAD);
mmu_raise_exception(tv, adr, MMU_TT_DREAD);
return 0;
}
@ -573,7 +614,7 @@ u16 DYNACALL mmu_IReadMem16(u32 adr)
{
if (adr & 1)
{
mmu_raise_exeption(MMU_ERROR_BADADDR, adr, MMU_TT_IREAD);
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_IREAD);
return 0;
}
u32 addr;
@ -581,7 +622,7 @@ u16 DYNACALL mmu_IReadMem16(u32 adr)
if (tv == 0)
return _vmem_ReadMem16(addr);
else
mmu_raise_exeption(tv, adr, MMU_TT_IREAD);
mmu_raise_exception(tv, adr, MMU_TT_IREAD);
return 0;
}
@ -590,7 +631,7 @@ u32 DYNACALL mmu_ReadMem32(u32 adr)
{
if (adr & 3)
{
mmu_raise_exeption(MMU_ERROR_BADADDR, adr, MMU_TT_DREAD);
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DREAD);
return 0;
}
u32 addr;
@ -598,7 +639,7 @@ u32 DYNACALL mmu_ReadMem32(u32 adr)
if (tv == 0)
return _vmem_ReadMem32(addr);
else
mmu_raise_exeption(tv, adr, MMU_TT_DREAD);
mmu_raise_exception(tv, adr, MMU_TT_DREAD);
return 0;
}
@ -606,7 +647,7 @@ u64 DYNACALL mmu_ReadMem64(u32 adr)
{
if (adr & 7)
{
mmu_raise_exeption(MMU_ERROR_BADADDR, adr, MMU_TT_DREAD);
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DREAD);
return 0;
}
u32 addr;
@ -616,7 +657,7 @@ u64 DYNACALL mmu_ReadMem64(u32 adr)
return _vmem_ReadMem64(addr);
}
else
mmu_raise_exeption(tv, adr, MMU_TT_DREAD);
mmu_raise_exception(tv, adr, MMU_TT_DREAD);
return 0;
}
@ -631,14 +672,14 @@ void DYNACALL mmu_WriteMem8(u32 adr, u8 data)
return;
}
else
mmu_raise_exeption(tv, adr, MMU_TT_DWRITE);
mmu_raise_exception(tv, adr, MMU_TT_DWRITE);
}
void DYNACALL mmu_WriteMem16(u32 adr, u16 data)
{
if (adr & 1)
{
mmu_raise_exeption(MMU_ERROR_BADADDR, adr, MMU_TT_DWRITE);
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DWRITE);
return;
}
u32 addr;
@ -649,13 +690,13 @@ void DYNACALL mmu_WriteMem16(u32 adr, u16 data)
return;
}
else
mmu_raise_exeption(tv, adr, MMU_TT_DWRITE);
mmu_raise_exception(tv, adr, MMU_TT_DWRITE);
}
void DYNACALL mmu_WriteMem32(u32 adr, u32 data)
{
if (adr & 3)
{
mmu_raise_exeption(MMU_ERROR_BADADDR, adr, MMU_TT_DWRITE);
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DWRITE);
return;
}
u32 addr;
@ -666,13 +707,13 @@ void DYNACALL mmu_WriteMem32(u32 adr, u32 data)
return;
}
else
mmu_raise_exeption(tv, adr, MMU_TT_DWRITE);
mmu_raise_exception(tv, adr, MMU_TT_DWRITE);
}
void DYNACALL mmu_WriteMem64(u32 adr, u64 data)
{
if (adr & 7)
{
mmu_raise_exeption(MMU_ERROR_BADADDR, adr, MMU_TT_DWRITE);
mmu_raise_exception(MMU_ERROR_BADADDR, adr, MMU_TT_DWRITE);
return;
}
u32 addr;
@ -683,35 +724,31 @@ void DYNACALL mmu_WriteMem64(u32 adr, u64 data)
return;
}
else
mmu_raise_exeption(tv, adr, MMU_TT_DWRITE);
mmu_raise_exception(tv, adr, MMU_TT_DWRITE);
}
bool mmu_TranslateSQW(u32 adr, u32* out)
{
#ifndef NO_MMU
u32 addr;
u32 tv = mmu_full_SQ<MMU_TT_DREAD>(adr, addr);
if (tv != 0)
if (!settings.dreamcast.FullMMU)
{
mmu_raise_exeption(tv, adr, MMU_TT_DREAD);
return false;
}
//This will only work for 1 mb pages .. hopefully nothing else is used
//*FIXME* to work for all page sizes ?
*out = addr;
#else
//This will olny work for 1 mb pages .. hopefully nothing else is used
//*FIXME* to work for all page sizes ?
if (CCN_MMUCR.AT == 0)
{ //simple translation
*out = mmu_QACR_SQ(adr);
}
else
{ //remap table
*out = sq_remap[(adr >> 20) & 0x3F] | (adr & 0xFFFE0);
}
#endif
else
{
u32 addr;
u32 tv = mmu_full_SQ<MMU_TT_DREAD>(adr, addr);
if (tv != 0)
{
mmu_raise_exception(tv, adr, MMU_TT_DREAD);
return false;
}
*out = addr;
}
return true;
}
#endif

View File

@ -17,6 +17,7 @@ bool UTLB_Sync(u32 entry);
void ITLB_Sync(u32 entry);
bool mmu_match(u32 va, CCN_PTEH_type Address, CCN_PTEL_type Data);
void mmu_set_state();
#if defined(NO_MMU)
bool inline mmu_TranslateSQW(u32 addr, u32* mapped) {

View File

@ -19,14 +19,6 @@
//main system mem
VArray2 mem_b;
u8 DYNACALL ReadMem8_i(u32 addr);
u16 DYNACALL ReadMem16_i(u32 addr);
u32 DYNACALL ReadMem32_i(u32 addr);
void DYNACALL WriteMem8_i(u32 addr,u8 data);
void DYNACALL WriteMem16_i(u32 addr,u16 data);
void DYNACALL WriteMem32_i(u32 addr,u32 data);
void _vmem_init();
void _vmem_reset();
void _vmem_term();

View File

@ -21,20 +21,30 @@ extern VArray2 mem_b;
#define WriteMem64 _vmem_WriteMem64
//#define WriteMem64(addr,reg) { _vmem_WriteMem32(addr,((u32*)reg)[0]);_vmem_WriteMem32((addr)+4, ((u32*)reg)[1]); }
#else
#include "modules/mmu.h"
#define ReadMem8 mmu_ReadMem8
#define ReadMem16 mmu_ReadMem16
#define IReadMem16 mmu_IReadMem16
#define ReadMem32 mmu_ReadMem32
#define ReadMem64 mmu_ReadMem64
#define WriteMem8 mmu_WriteMem8
#define WriteMem16 mmu_WriteMem16
#define WriteMem32 mmu_WriteMem32
#define WriteMem64 mmu_WriteMem64
typedef u8 (*ReadMem8Func)(u32 addr);
typedef u16 (*ReadMem16Func)(u32 addr);
typedef u32 (*ReadMem32Func)(u32 addr);
typedef u64 (*ReadMem64Func)(u32 addr);
typedef void (*WriteMem8Func)(u32 addr, u8 data);
typedef void (*WriteMem16Func)(u32 addr, u16 data);
typedef void (*WriteMem32Func)(u32 addr, u32 data);
typedef void (*WriteMem64Func)(u32 addr, u64 data);
extern ReadMem8Func ReadMem8;
extern ReadMem16Func ReadMem16;
extern ReadMem16Func IReadMem16;
extern ReadMem32Func ReadMem32;
extern ReadMem64Func ReadMem64;
extern WriteMem8Func WriteMem8;
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
@ -90,4 +100,4 @@ u32 GetRamPageFromAddress(u32 RamAddress);
bool LoadRomFiles(const string& root);
void SaveRomFiles(const string& root);
bool LoadHle(const string& root);
bool LoadHle(const string& root);

View File

@ -454,6 +454,7 @@ void InitSettings()
settings.dreamcast.region = 3; // default
settings.dreamcast.broadcast = 4; // default
settings.dreamcast.language = 6; // default
settings.dreamcast.FullMMU = false;
settings.aica.LimitFPS = true;
settings.aica.NoBatch = false; // This also controls the DSP. Disabled by default
settings.aica.NoSound = false;
@ -527,6 +528,7 @@ void LoadSettings(bool game_specific)
settings.dreamcast.region = cfgLoadInt(config_section, "Dreamcast.Region", settings.dreamcast.region);
settings.dreamcast.broadcast = cfgLoadInt(config_section, "Dreamcast.Broadcast", settings.dreamcast.broadcast);
settings.dreamcast.language = cfgLoadInt(config_section, "Dreamcast.Language", settings.dreamcast.language);
settings.dreamcast.FullMMU = cfgLoadBool(config_section, "Dreamcast.FullMMU", settings.dreamcast.FullMMU);
settings.aica.LimitFPS = cfgLoadBool(config_section, "aica.LimitFPS", settings.aica.LimitFPS);
settings.aica.NoBatch = cfgLoadBool(config_section, "aica.NoBatch", settings.aica.NoBatch);
settings.aica.NoSound = cfgLoadBool(config_section, "aica.NoSound", settings.aica.NoSound);
@ -651,6 +653,7 @@ void SaveSettings()
cfgSaveInt("config", "Dreamcast.Cable", settings.dreamcast.cable);
cfgSaveInt("config", "Dreamcast.Region", settings.dreamcast.region);
cfgSaveInt("config", "Dreamcast.Broadcast", settings.dreamcast.broadcast);
cfgSaveBool("config", "Dreamcast.FullMMU", settings.dreamcast.FullMMU);
cfgSaveBool("config", "Dynarec.idleskip", settings.dynarec.idleskip);
cfgSaveBool("config", "Dynarec.unstable-opt", settings.dynarec.unstable_opt);
if (!safemode_game || !settings.dynarec.safemode)
@ -838,6 +841,7 @@ void dc_loadstate()
return;
}
mmu_set_state();
dsp.dyndirty = true;
sh4_sched_ffts();
CalculateSync();

View File

@ -751,6 +751,7 @@ struct settings_t
u32 broadcast; // 0 -> NTSC, 1 -> PAL, 2 -> PAL/M, 3 -> PAL/N, 4 -> default
u32 language; // 0 -> JP, 1 -> EN, 2 -> DE, 3 -> FR, 4 -> SP, 5 -> IT, 6 -> default
std::vector<std::string> ContentPath;
bool FullMMU;
} dreamcast;
struct