Merge pull request #837 from reicast/wip/mmu-exceptions

sh4/mmu: C++ exception based sh4 exception support. Won't run wince yet.
This commit is contained in:
Stefanos Kornilios Mitsis Poiitidis 2015-09-29 03:34:48 +02:00
commit 915d6b26d6
10 changed files with 172 additions and 110 deletions

View File

@ -346,24 +346,28 @@ sh4op(i1111_nnnn_mmmm_1011)
u32 n = GetN(op); u32 n = GetN(op);
u32 m = GetM(op); u32 m = GetM(op);
r[n] -= 4; u32 addr = r[n] - 4;
WriteMemU32(r[n], fr_hex[m]); WriteMemU32(addr, fr_hex[m]);
r[n] = addr;
} }
else else
{ {
u32 n = GetN(op); u32 n = GetN(op);
u32 m = GetM(op)>>1; u32 m = GetM(op)>>1;
r[n] -= 8; u32 addr = r[n] - 8;
if (((op >> 4) & 0x1) == 0) if (((op >> 4) & 0x1) == 0)
{ {
WriteMemU64(r[n] , dr_hex[m]); WriteMemU64(addr, dr_hex[m]);
} }
else else
{ {
WriteMemU64(r[n] , xd_hex[m]); WriteMemU64(addr, xd_hex[m]);
} }
r[n] = addr;
} }
} }

View File

@ -44,16 +44,27 @@ void Sh4_int_Run()
for (int i=0; i<10000; i++) for (int i=0; i<10000; i++)
#endif #endif
{ {
#if !defined(NO_MMU)
try {
#endif
do do
{ {
u32 op=ReadMem16(next_pc); u32 addr = next_pc;
next_pc += 2; next_pc += 2;
u32 op = IReadMem16(addr);
OpPtr[op](op); OpPtr[op](op);
l -= CPU_RATIO; l -= CPU_RATIO;
} while (l > 0); } while (l > 0);
l += SH4_TIMESLICE; l += SH4_TIMESLICE;
UpdateSystem_INTC(); UpdateSystem_INTC();
#if !defined(NO_MMU)
}
catch (SH4ThrownException ex) {
Do_Exception(ex.epc, ex.expEvn, ex.callVect);
l -= CPU_RATIO * 5;
}
#endif
#if !defined(TARGET_BOUNDED_EXECUTION) #if !defined(TARGET_BOUNDED_EXECUTION)
} while(sh4_int_bCpuRun); } while(sh4_int_bCpuRun);
@ -134,17 +145,40 @@ bool Sh4_int_IsCpuRunning()
//TODO : Check for valid delayslot instruction //TODO : Check for valid delayslot instruction
void ExecuteDelayslot() void ExecuteDelayslot()
{ {
u32 op=IReadMem16(next_pc); #if !defined(NO_MMU)
try {
#endif
u32 addr = next_pc;
next_pc += 2; next_pc += 2;
u32 op = IReadMem16(addr);
if (op != 0) if (op != 0)
ExecuteOpcode(op); ExecuteOpcode(op);
#if !defined(NO_MMU)
}
catch (SH4ThrownException ex) {
ex.epc -= 2;
//printf("Delay slot exception\n");
throw ex;
}
#endif
} }
void ExecuteDelayslot_RTE() void ExecuteDelayslot_RTE()
{ {
u32 oldsr = sr.GetFull();
#if !defined(NO_MMU)
try {
#endif
sr.SetFull(ssr); sr.SetFull(ssr);
ExecuteDelayslot(); ExecuteDelayslot();
#if !defined(NO_MMU)
}
catch (SH4ThrownException ex) {
msgboxf("RTE Exception", MBX_ICONERROR);
}
#endif
} }
//General update //General update

View File

@ -277,24 +277,10 @@ sh4op(i0010_nnnn_mmmm_0100)
//iNimp("mov.b <REG_M>,@-<REG_N>"); //iNimp("mov.b <REG_M>,@-<REG_N>");
u32 n = GetN(op); u32 n = GetN(op);
u32 m = GetM(op); u32 m = GetM(op);
//r[n]--;
if (n==m) u32 addr = r[n] - 1;
{
//printf("Mov.b !!!m==n\n");
//return;
//
WriteMemBOU8(r[n], (u32)-1, r[m]); WriteMemBOU8(r[n], (u32)-1, r[m]);
r[n]--; r[n] = addr;
}
else
{
r[n]--;
WriteMemU8(r[n],r[m]);
}
//WriteMemoryB(r[n], R(m) & 0xFF);
} }
//mov.w <REG_M>,@-<REG_N> //mov.w <REG_M>,@-<REG_N>
@ -303,19 +289,10 @@ sh4op(i0010_nnnn_mmmm_0101)
//iNimp("mov.w <REG_M>,@-<REG_N>"); //iNimp("mov.w <REG_M>,@-<REG_N>");
u32 n = GetN(op); u32 n = GetN(op);
u32 m = GetM(op); u32 m = GetM(op);
//r[n] -= 2;
if (n==m) u32 addr = r[n] - 2;
{ WriteMemU16(addr, r[m]);
//printf("Mov.w !!!m==n\n"); r[n] = addr;
//return;
WriteMemBOU16(r[n],(u32)-2,r[m]);
r[n] -= 2;
}
else
{
r[n] -= 2;
WriteMemU16(r[n], r[m]);
}
} }
//mov.l <REG_M>,@-<REG_N> //mov.l <REG_M>,@-<REG_N>
@ -323,20 +300,10 @@ sh4op(i0010_nnnn_mmmm_0110)
{ {
u32 n = GetN(op); u32 n = GetN(op);
u32 m = GetM(op); u32 m = GetM(op);
//r[n] -= 4;
if (m==n) u32 addr = r[n] - 4;
{ WriteMemU32(addr, r[m]);
//iNimp(op,"Mov.l !!!m==n"); r[n] = addr;
//printf("mov.l <REG_M>,@-<REG_N> !!!m==n\n");
//return;
WriteMemBOU32(r[n],(u32)-4,r[m]);
r[n] -= 4;
}
else
{
r[n] -= 4;
WriteMemU32(r[n],r[m]);
}
} }
// //
@ -346,16 +313,20 @@ sh4op(i0100_nnnn_0101_0010)
{ {
//iNimp("sts.l FPUL,@-<REG_N>"); //iNimp("sts.l FPUL,@-<REG_N>");
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n], fpul); u32 addr = r[n] - 4;
WriteMemU32(addr, fpul);
r[n] = addr;
} }
//sts.l MACH,@-<REG_N> //sts.l MACH,@-<REG_N>
sh4op(i0100_nnnn_0000_0010) sh4op(i0100_nnnn_0000_0010)
{ {
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n], mac.h); u32 addr = r[n] - 4;
WriteMemU32(addr, mac.h);
r[n] = addr;
} }
@ -363,8 +334,10 @@ sh4op(i0100_nnnn_0000_0010)
sh4op(i0100_nnnn_0001_0010) sh4op(i0100_nnnn_0001_0010)
{ {
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n], mac.l); u32 addr = r[n] - 4;
WriteMemU32(addr, mac.l);
r[n] = addr;
} }
@ -372,16 +345,20 @@ sh4op(i0100_nnnn_0001_0010)
sh4op(i0100_nnnn_0010_0010) sh4op(i0100_nnnn_0010_0010)
{ {
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n],pr); u32 addr = r[n] - 4;
WriteMemU32(addr,pr);
r[n] = addr;
} }
//sts.l DBR,@-<REG_N> //sts.l DBR,@-<REG_N>
sh4op(i0100_nnnn_1111_0010) sh4op(i0100_nnnn_1111_0010)
{ {
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n],dbr); u32 addr = r[n] - 4;
WriteMemU32(addr,dbr);
r[n] = addr;
} }
//stc.l GBR,@-<REG_N> //stc.l GBR,@-<REG_N>
@ -389,8 +366,10 @@ sh4op(i0100_nnnn_0001_0011)
{ {
//iNimp("stc.l GBR,@-<REG_N>"); //iNimp("stc.l GBR,@-<REG_N>");
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n], gbr); u32 addr = r[n] - 4;
WriteMemU32(addr, gbr);
r[n] = addr;
} }
@ -399,8 +378,10 @@ sh4op(i0100_nnnn_0010_0011)
{ {
//iNimp("stc.l VBR,@-<REG_N>"); //iNimp("stc.l VBR,@-<REG_N>");
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n], vbr); u32 addr = r[n] - 4;
WriteMemU32(addr, vbr);
r[n] = addr;
} }
@ -409,16 +390,20 @@ sh4op(i0100_nnnn_0011_0011)
{ {
//iNimp("stc.l SSR,@-<REG_N>"); //iNimp("stc.l SSR,@-<REG_N>");
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n], ssr); u32 addr = r[n] - 4;
WriteMemU32(addr, ssr);
r[n] = addr;
} }
//stc.l SGR,@-<REG_N> //stc.l SGR,@-<REG_N>
sh4op(i0100_nnnn_0011_0010) sh4op(i0100_nnnn_0011_0010)
{ {
//iNimp("stc.l SGR,@-<REG_N>"); //iNimp("stc.l SGR,@-<REG_N>");
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n], sgr); u32 addr = r[n] - 4;
WriteMemU32(addr, sgr);
r[n] = addr;
} }
@ -427,8 +412,10 @@ sh4op(i0100_nnnn_0100_0011)
{ {
//iNimp("stc.l SPC,@-<REG_N>"); //iNimp("stc.l SPC,@-<REG_N>");
u32 n = GetN(op); u32 n = GetN(op);
r[n] -= 4;
WriteMemU32(r[n], spc); u32 addr = r[n] - 4;
WriteMemU32(addr, spc);
r[n] = addr;
} }
//stc RM_BANK,@-<REG_N> //stc RM_BANK,@-<REG_N>
@ -437,8 +424,10 @@ sh4op(i0100_nnnn_1mmm_0011)
//iNimp("stc RM_BANK,@-<REG_N>"); //iNimp("stc RM_BANK,@-<REG_N>");
u32 n = GetN(op); u32 n = GetN(op);
u32 m = GetM(op) & 0x07; u32 m = GetM(op) & 0x07;
r[n] -= 4;
WriteMemU32(r[n], r_bank[m]); u32 addr = r[n] - 4;
WriteMemU32(addr, r_bank[m]);
r[n] = addr;
} }
@ -923,10 +912,14 @@ sh4op(i0000_nnnn_0010_0011)
//bsrf <REG_N> //bsrf <REG_N>
sh4op(i0000_nnnn_0000_0011) sh4op(i0000_nnnn_0000_0011)
{ {
//TODO: Check pr setting vs real h/w
u32 n = GetN(op); u32 n = GetN(op);
u32 newpc = r[n] + next_pc +2; u32 newpc = r[n] + next_pc +2;
pr = next_pc + 2; //after delayslot u32 newpr = next_pc + 2;
ExecuteDelayslot(); //WARN : pr and r[n] can change here ExecuteDelayslot(); //WARN : pr and r[n] can change here
pr = newpr;
next_pc = newpc; next_pc = newpc;
} }
@ -1023,9 +1016,12 @@ sh4op(i1010_iiii_iiii_iiii)
// bsr <bdisp12> // bsr <bdisp12>
sh4op(i1011_iiii_iiii_iiii) sh4op(i1011_iiii_iiii_iiii)
{ {
pr = next_pc + 2; //return after delayslot //TODO: check pr vs real h/w
u32 newpr = next_pc + 2; //return after delayslot
u32 newpc = branch_target_s12(op); u32 newpc = branch_target_s12(op);
ExecuteDelayslot(); ExecuteDelayslot();
pr = newpr;
next_pc=newpc; next_pc=newpc;
} }
@ -1034,7 +1030,7 @@ sh4op(i1100_0011_iiii_iiii)
{ {
//printf("trapa 0x%X\n",(GetImm8(op) << 2)); //printf("trapa 0x%X\n",(GetImm8(op) << 2));
CCN_TRA = (GetImm8(op) << 2); CCN_TRA = (GetImm8(op) << 2);
Do_Exeption(next_pc,0x160,0x100); Do_Exception(next_pc,0x160,0x100);
} }
//jmp @<REG_N> //jmp @<REG_N>
@ -1052,9 +1048,12 @@ sh4op(i0100_nnnn_0000_1011)
{ {
u32 n = GetN(op); u32 n = GetN(op);
pr = next_pc + 2; //return after delayslot //TODO: check pr vs real h/w
u32 newpr = next_pc + 2; //return after delayslot
u32 newpc= r[n]; u32 newpc= r[n];
ExecuteDelayslot(); //r[n]/pr can change here ExecuteDelayslot(); //r[n]/pr can change here
pr = newpr;
next_pc=newpc; next_pc=newpc;
} }
@ -1227,7 +1226,7 @@ sh4op(i0000_0000_0000_1001)
//ldtlb //ldtlb
sh4op(i0000_0000_0011_1000) sh4op(i0000_0000_0011_1000)
{ {
printf("ldtlb %d/%d\n",CCN_MMUCR.URC,CCN_MMUCR.URB); //printf("ldtlb %d/%d\n",CCN_MMUCR.URC,CCN_MMUCR.URB);
UTLB[CCN_MMUCR.URC].Data=CCN_PTEL; UTLB[CCN_MMUCR.URC].Data=CCN_PTEL;
UTLB[CCN_MMUCR.URC].Address=CCN_PTEH; UTLB[CCN_MMUCR.URC].Address=CCN_PTEH;
@ -2210,6 +2209,13 @@ sh4op(i0100_nnnn_0000_1110)
//Not implt //Not implt
sh4op(iNotImplemented) sh4op(iNotImplemented)
{ {
#ifndef NO_MMU
printf("iNimp %04X\n", op);
SH4ThrownException ex = { next_pc - 2, 0x180, 0x100 };
throw ex;
#else
cpu_iNimp(op, "Unknown opcode"); cpu_iNimp(op, "Unknown opcode");
#endif
} }

View File

@ -71,8 +71,8 @@ defining NO_MMU disables the full mmu emulation
#include "hw/mem/_vmem.h" #include "hw/mem/_vmem.h"
#define printf_mmu #define printf_mmu(...)
#define printf_win32 log #define printf_win32(...)
//SQ fast remap , mailny hackish , assumes 1 mb pages //SQ fast remap , mailny hackish , assumes 1 mb pages
//max 64 mb can be remapped on SQ //max 64 mb can be remapped on SQ
@ -145,8 +145,13 @@ void ITLB_Sync(u32 entry)
printf_mmu("ITLB MEM remap %d : 0x%X to 0x%X : %d\n", entry, ITLB[entry].Address.VPN << 10, ITLB[entry].Data.PPN << 10, ITLB[entry].Data.V); printf_mmu("ITLB MEM remap %d : 0x%X to 0x%X : %d\n", entry, ITLB[entry].Address.VPN << 10, ITLB[entry].Data.PPN << 10, ITLB[entry].Data.V);
} }
void RaiseException(u32 a, u32 b) { void RaiseException(u32 expEvnt, u32 callVect) {
#if !defined(NO_MMU)
SH4ThrownException ex = { next_pc - 2, expEvnt, callVect };
throw ex;
#else
msgboxf("Can't raise exceptions yet", MBX_ICONERROR); msgboxf("Can't raise exceptions yet", MBX_ICONERROR);
#endif
} }
u32 mmu_error_TT; u32 mmu_error_TT;
@ -217,7 +222,7 @@ void mmu_raise_exeption(u32 mmu_error, u32 address, u32 am)
RaiseException(0xE0, 0x100); RaiseException(0xE0, 0x100);
else //IADDERR - Instruction Address Error else //IADDERR - Instruction Address Error
{ {
printf("MMU_ERROR_BADADDR(i) 0x%X\n", address); printf_mmu("MMU_ERROR_BADADDR(i) 0x%X\n", address);
RaiseException(0xE0, 0x100); RaiseException(0xE0, 0x100);
return; return;
} }

View File

@ -16,6 +16,8 @@ extern u32 sq_remap[64];
bool UTLB_Sync(u32 entry); bool UTLB_Sync(u32 entry);
void ITLB_Sync(u32 entry); void ITLB_Sync(u32 entry);
bool mmu_match(u32 va, CCN_PTEH_type Address, CCN_PTEL_type Data);
#if defined(NO_MMU) #if defined(NO_MMU)
bool inline mmu_TranslateSQW(u32 addr, u32* mapped) { bool inline mmu_TranslateSQW(u32 addr, u32* mapped) {
*mapped = sq_remap[(addr>>20)&0x3F] | (addr & 0xFFFE0); *mapped = sq_remap[(addr>>20)&0x3F] | (addr & 0xFFFE0);

View File

@ -101,4 +101,10 @@ void SetFloatStatusReg();
bool Do_Interrupt(u32 intEvn); bool Do_Interrupt(u32 intEvn);
bool Do_Exeption(u32 epc, u32 expEvn, u32 CallVect); bool Do_Exception(u32 epc, u32 expEvn, u32 CallVect);
struct SH4ThrownException {
u32 epc;
u32 expEvn;
u32 callVect;
};

View File

@ -49,7 +49,7 @@ DECL_ALIGN(64) u32 InterruptBit[32] = { 0 };
DECL_ALIGN(64) u32 InterruptLevelBit[16] = { 0 }; DECL_ALIGN(64) u32 InterruptLevelBit[16] = { 0 };
bool Do_Interrupt(u32 intEvn); bool Do_Interrupt(u32 intEvn);
bool Do_Exeption(u32 epc, u32 expEvn, u32 CallVect); bool Do_Exception(u32 epc, u32 expEvn, u32 CallVect);
u32 interrupt_vpend; // Vector of pending interrupts u32 interrupt_vpend; // Vector of pending interrupts
u32 interrupt_vmask; // Vector of masked interrupts (-1 inhibits all interrupts) u32 interrupt_vmask; // Vector of masked interrupts (-1 inhibits all interrupts)
@ -158,8 +158,9 @@ bool Do_Interrupt(u32 intEvn)
return true; return true;
} }
bool Do_Exeption(u32 epc, u32 expEvn, u32 CallVect) bool Do_Exception(u32 epc, u32 expEvn, u32 CallVect)
{ {
verify(sr.BL == 0);
CCN_EXPEVT = expEvn; CCN_EXPEVT = expEvn;
ssr = sr.GetFull(); ssr = sr.GetFull();
@ -172,7 +173,7 @@ bool Do_Exeption(u32 epc, u32 expEvn, u32 CallVect)
next_pc = vbr + CallVect; next_pc = vbr + CallVect;
printf("RaiseException: from %08X , pc errh %08X\n", spc, epc); //printf("RaiseException: from %08X , pc errh %08X, %08X vect\n", spc, epc, next_pc);
return true; return true;
} }

View File

@ -111,7 +111,7 @@ void ResetInterruptMask(InterruptID intr);
int UpdateINTC(); int UpdateINTC();
//extern u32 interrupt_pend; //nonzero if there are pending interrupts //extern u32 interrupt_pend; //nonzero if there are pending interrupts
bool Do_Exeption(u32 lvl, u32 expEvn, u32 CallVect); bool Do_Exception(u32 lvl, u32 expEvn, u32 CallVect);

View File

@ -345,7 +345,10 @@ void DYNACALL WriteMem_P4(u32 addr,T data)
{ {
if (addr&0x80) if (addr&0x80)
{ {
#ifdef NO_MMU
printf("Unhandled p4 Write [Unified TLB address array, Associative Write] 0x%x = %x\n",addr,data); printf("Unhandled p4 Write [Unified TLB address array, Associative Write] 0x%x = %x\n",addr,data);
#endif
CCN_PTEH_type t; CCN_PTEH_type t;
t.reg_data=data; t.reg_data=data;
@ -353,25 +356,26 @@ void DYNACALL WriteMem_P4(u32 addr,T data)
for (int i=0;i<64;i++) for (int i=0;i<64;i++)
{ {
/*if (mmu_match(va,UTLB[i].Address,UTLB[i].Data)) #ifndef NO_MMU
if (mmu_match(va,UTLB[i].Address,UTLB[i].Data))
{ {
UTLB[i].Data.V=((u32)data>>8)&1; UTLB[i].Data.V=((u32)data>>8)&1;
UTLB[i].Data.D=((u32)data>>9)&1; UTLB[i].Data.D=((u32)data>>9)&1;
UTLB_Sync(i); UTLB_Sync(i);
} }
*/ #endif
} }
for (int i=0;i<4;i++) for (int i=0;i<4;i++)
{ {
/* #ifndef NO_MMU
if (mmu_match(va,ITLB[i].Address,ITLB[i].Data)) if (mmu_match(va,ITLB[i].Address,ITLB[i].Data))
{ {
ITLB[i].Data.V=((u32)data>>8)&1; ITLB[i].Data.V=((u32)data>>8)&1;
ITLB[i].Data.D=((u32)data>>9)&1; ITLB[i].Data.D=((u32)data>>9)&1;
ITLB_Sync(i); ITLB_Sync(i);
} }
*/ #endif
} }
} }
else else