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 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
{
u32 n = GetN(op);
u32 m = GetM(op)>>1;
r[n] -= 8;
u32 addr = r[n] - 8;
if (((op >> 4) & 0x1) == 0)
{
WriteMemU64(r[n] , dr_hex[m]);
WriteMemU64(addr, dr_hex[m]);
}
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++)
#endif
{
do
{
u32 op=ReadMem16(next_pc);
next_pc+=2;
#if !defined(NO_MMU)
try {
#endif
do
{
u32 addr = next_pc;
next_pc += 2;
u32 op = IReadMem16(addr);
OpPtr[op](op);
l-=CPU_RATIO;
} while(l>0);
l+=SH4_TIMESLICE;
UpdateSystem_INTC();
OpPtr[op](op);
l -= CPU_RATIO;
} while (l > 0);
l += SH4_TIMESLICE;
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)
} while(sh4_int_bCpuRun);
@ -134,17 +145,40 @@ bool Sh4_int_IsCpuRunning()
//TODO : Check for valid delayslot instruction
void ExecuteDelayslot()
{
u32 op=IReadMem16(next_pc);
next_pc+=2;
if (op!=0)
ExecuteOpcode(op);
#if !defined(NO_MMU)
try {
#endif
u32 addr = next_pc;
next_pc += 2;
u32 op = IReadMem16(addr);
if (op != 0)
ExecuteOpcode(op);
#if !defined(NO_MMU)
}
catch (SH4ThrownException ex) {
ex.epc -= 2;
//printf("Delay slot exception\n");
throw ex;
}
#endif
}
void ExecuteDelayslot_RTE()
{
sr.SetFull(ssr);
u32 oldsr = sr.GetFull();
ExecuteDelayslot();
#if !defined(NO_MMU)
try {
#endif
sr.SetFull(ssr);
ExecuteDelayslot();
#if !defined(NO_MMU)
}
catch (SH4ThrownException ex) {
msgboxf("RTE Exception", MBX_ICONERROR);
}
#endif
}
//General update

View File

@ -277,24 +277,10 @@ sh4op(i0010_nnnn_mmmm_0100)
//iNimp("mov.b <REG_M>,@-<REG_N>");
u32 n = GetN(op);
u32 m = GetM(op);
//r[n]--;
if (n==m)
{
//printf("Mov.b !!!m==n\n");
//return;
//
WriteMemBOU8(r[n],(u32)-1,r[m]);
r[n]--;
}
else
{
r[n]--;
WriteMemU8(r[n],r[m]);
}
//WriteMemoryB(r[n], R(m) & 0xFF);
u32 addr = r[n] - 1;
WriteMemBOU8(r[n], (u32)-1, r[m]);
r[n] = addr;
}
//mov.w <REG_M>,@-<REG_N>
@ -303,19 +289,10 @@ sh4op(i0010_nnnn_mmmm_0101)
//iNimp("mov.w <REG_M>,@-<REG_N>");
u32 n = GetN(op);
u32 m = GetM(op);
//r[n] -= 2;
if (n==m)
{
//printf("Mov.w !!!m==n\n");
//return;
WriteMemBOU16(r[n],(u32)-2,r[m]);
r[n] -= 2;
}
else
{
r[n] -= 2;
WriteMemU16(r[n], r[m]);
}
u32 addr = r[n] - 2;
WriteMemU16(addr, r[m]);
r[n] = addr;
}
//mov.l <REG_M>,@-<REG_N>
@ -323,20 +300,10 @@ sh4op(i0010_nnnn_mmmm_0110)
{
u32 n = GetN(op);
u32 m = GetM(op);
//r[n] -= 4;
if (m==n)
{
//iNimp(op,"Mov.l !!!m==n");
//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]);
}
u32 addr = r[n] - 4;
WriteMemU32(addr, r[m]);
r[n] = addr;
}
//
@ -346,16 +313,20 @@ sh4op(i0100_nnnn_0101_0010)
{
//iNimp("sts.l FPUL,@-<REG_N>");
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>
sh4op(i0100_nnnn_0000_0010)
{
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)
{
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)
{
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>
sh4op(i0100_nnnn_1111_0010)
{
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>
@ -389,8 +366,10 @@ sh4op(i0100_nnnn_0001_0011)
{
//iNimp("stc.l GBR,@-<REG_N>");
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>");
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>");
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>
sh4op(i0100_nnnn_0011_0010)
{
//iNimp("stc.l SGR,@-<REG_N>");
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>");
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>
@ -437,8 +424,10 @@ sh4op(i0100_nnnn_1mmm_0011)
//iNimp("stc RM_BANK,@-<REG_N>");
u32 n = GetN(op);
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>
sh4op(i0000_nnnn_0000_0011)
{
//TODO: Check pr setting vs real h/w
u32 n = GetN(op);
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
pr = newpr;
next_pc = newpc;
}
@ -1023,9 +1016,12 @@ sh4op(i1010_iiii_iiii_iiii)
// bsr <bdisp12>
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);
ExecuteDelayslot();
pr = newpr;
next_pc=newpc;
}
@ -1034,7 +1030,7 @@ sh4op(i1100_0011_iiii_iiii)
{
//printf("trapa 0x%X\n",(GetImm8(op) << 2));
CCN_TRA = (GetImm8(op) << 2);
Do_Exeption(next_pc,0x160,0x100);
Do_Exception(next_pc,0x160,0x100);
}
//jmp @<REG_N>
@ -1052,9 +1048,12 @@ sh4op(i0100_nnnn_0000_1011)
{
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];
ExecuteDelayslot(); //r[n]/pr can change here
pr = newpr;
next_pc=newpc;
}
@ -1227,7 +1226,7 @@ sh4op(i0000_0000_0000_1001)
//ldtlb
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].Address=CCN_PTEH;
@ -2210,6 +2209,13 @@ sh4op(i0100_nnnn_0000_1110)
//Not implt
sh4op(iNotImplemented)
{
cpu_iNimp(op,"Unknown opcode");
#ifndef NO_MMU
printf("iNimp %04X\n", op);
SH4ThrownException ex = { next_pc - 2, 0x180, 0x100 };
throw ex;
#else
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"
#define printf_mmu
#define printf_win32 log
#define printf_mmu(...)
#define printf_win32(...)
//SQ fast remap , mailny hackish , assumes 1 mb pages
//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);
}
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);
#endif
}
u32 mmu_error_TT;
@ -217,7 +222,7 @@ void mmu_raise_exeption(u32 mmu_error, u32 address, u32 am)
RaiseException(0xE0, 0x100);
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);
return;
}

View File

@ -16,6 +16,8 @@ extern u32 sq_remap[64];
bool UTLB_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)
bool inline mmu_TranslateSQW(u32 addr, u32* mapped) {
*mapped = sq_remap[(addr>>20)&0x3F] | (addr & 0xFFFE0);

View File

@ -101,4 +101,10 @@ void SetFloatStatusReg();
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 };
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_vmask; // Vector of masked interrupts (-1 inhibits all interrupts)
@ -158,8 +158,9 @@ bool Do_Interrupt(u32 intEvn)
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;
ssr = sr.GetFull();
@ -172,7 +173,7 @@ bool Do_Exeption(u32 epc, u32 expEvn, u32 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;
}

View File

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