Created
September 16, 2015 18:44
-
-
Save simias/f2f96b9965675e4db5fc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/psx/cpu.cpp b/src/psx/cpu.cpp | |
index 24300f3..5a51afd 100644 | |
--- a/src/psx/cpu.cpp | |
+++ b/src/psx/cpu.cpp | |
@@ -458,6 +458,55 @@ uint32 PS_CPU::Exception(uint32 code, uint32 PC, const uint32 NPM) | |
#define GPR_RES(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; } | |
#define GPR_DEPRES_END ReadAbsorb[0] = back; } | |
+ uint32 PS_CPU::cache_fetch(pscpu_timestamp_t ×tamp, uint32 PC) { | |
+ uint32 instr; | |
+ | |
+ ReadAbsorb[ReadAbsorbWhich] = 0; | |
+ ReadAbsorbWhich = 0; | |
+ | |
+ if(PC >= 0xA0000000 || !(BIU & 0x800)) | |
+ { | |
+ instr = MDFN_de32lsb<true>(&FastMap[PC >> FAST_MAP_SHIFT][PC]); | |
+ timestamp += 4; | |
+ } | |
+ else | |
+ { | |
+ __ICache *ICI = &ICache[((PC & 0xFF0) >> 2)]; | |
+ const uint8 *FMP = &FastMap[(PC &~ 0xF) >> FAST_MAP_SHIFT][PC &~ 0xF]; | |
+ | |
+ ICI[0x00].TV = (PC &~ 0xF) | 0x00 | 0x2; | |
+ ICI[0x01].TV = (PC &~ 0xF) | 0x04 | 0x2; | |
+ ICI[0x02].TV = (PC &~ 0xF) | 0x08 | 0x2; | |
+ ICI[0x03].TV = (PC &~ 0xF) | 0x0C | 0x2; | |
+ | |
+ timestamp += 3; | |
+ | |
+ switch(PC & 0xC) | |
+ { | |
+ case 0x0: | |
+ timestamp++; | |
+ ICI[0x00].TV &= ~0x2; | |
+ ICI[0x00].Data = MDFN_de32lsb<true>(&FMP[0x0]); | |
+ case 0x4: | |
+ timestamp++; | |
+ ICI[0x01].TV &= ~0x2; | |
+ ICI[0x01].Data = MDFN_de32lsb<true>(&FMP[0x4]); | |
+ case 0x8: | |
+ timestamp++; | |
+ ICI[0x02].TV &= ~0x2; | |
+ ICI[0x02].Data = MDFN_de32lsb<true>(&FMP[0x8]); | |
+ case 0xC: | |
+ timestamp++; | |
+ ICI[0x03].TV &= ~0x2; | |
+ ICI[0x03].Data = MDFN_de32lsb<true>(&FMP[0xC]); | |
+ break; | |
+ } | |
+ instr = ICache[(PC & 0xFFC) >> 2].Data; | |
+ } | |
+ | |
+ return instr; | |
+ } | |
+ | |
template<bool DebugMode, bool BIOSPrintMode, bool ILHMode> | |
pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
{ | |
@@ -468,7 +517,8 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
register uint32 new_PC_mask; | |
register uint32 LDWhich; | |
register uint32 LDValue; | |
- | |
+ uint32 instr = 0; | |
+ uint32 opf; | |
//printf("%d %d\n", gte_ts_done, muldiv_ts_done); | |
gte_ts_done += timestamp; | |
@@ -478,146 +528,9 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
do | |
{ | |
- //printf("Running: %d %d\n", timestamp, next_event_ts); | |
- while(MDFN_LIKELY(timestamp < next_event_ts)) | |
- { | |
- uint32 instr; | |
- uint32 opf; | |
- | |
- // Zero must be zero...until the Master Plan is enacted. | |
- GPR[0] = 0; | |
- | |
- if(DebugMode && CPUHook) | |
- { | |
- ACTIVE_TO_BACKING; | |
- | |
- // For save states in step mode. | |
- gte_ts_done -= timestamp; | |
- muldiv_ts_done -= timestamp; | |
- | |
- CPUHook(timestamp, PC); | |
- | |
- // For save states in step mode. | |
- gte_ts_done += timestamp; | |
- muldiv_ts_done += timestamp; | |
- | |
- BACKING_TO_ACTIVE; | |
- } | |
- | |
- if(BIOSPrintMode) | |
- { | |
- if(PC == 0xB0) | |
- { | |
- if(MDFN_UNLIKELY(GPR[9] == 0x3D)) | |
- { | |
- PSX_DBG_BIOS_PUTC(GPR[4]); | |
- } | |
- } | |
- } | |
- | |
- // We can't fold this into the ICache[] != PC handling, since the lower 2 bits of TV | |
- // are already used for cache management purposes and it assumes that the lower 2 bits of PC will be 0. | |
- if(MDFN_UNLIKELY(PC & 0x3)) | |
- { | |
- // This will block interrupt processing, but since we're going more for keeping broken homebrew/hacks from working | |
- // than super-duper-accurate pipeline emulation, it shouldn't be a problem. | |
- new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask); | |
- new_PC_mask = 0; | |
- goto OpDone; | |
- } | |
- | |
- instr = ICache[(PC & 0xFFC) >> 2].Data; | |
- | |
- if(ICache[(PC & 0xFFC) >> 2].TV != PC) | |
- { | |
- //WriteAbsorb = 0; | |
- //WriteAbsorbCount = 0; | |
- //WriteAbsorbMonkey = 0; | |
- ReadAbsorb[ReadAbsorbWhich] = 0; | |
- ReadAbsorbWhich = 0; | |
- | |
- // FIXME: Handle executing out of scratchpad. | |
- if(PC >= 0xA0000000 || !(BIU & 0x800)) | |
- { | |
- instr = MDFN_de32lsb<true>(&FastMap[PC >> FAST_MAP_SHIFT][PC]); | |
- timestamp += 4; // Approximate best-case cache-disabled time, per PS1 tests(executing out of 0xA0000000+); it can be 5 in *some* sequences of code(like a lot of sequential "nop"s, probably other simple instructions too). | |
- } | |
- else | |
- { | |
- __ICache *ICI = &ICache[((PC & 0xFF0) >> 2)]; | |
- const uint8 *FMP = &FastMap[(PC &~ 0xF) >> FAST_MAP_SHIFT][PC &~ 0xF]; | |
- | |
- // | 0x2 to simulate (in)validity bits. | |
- ICI[0x00].TV = (PC &~ 0xF) | 0x00 | 0x2; | |
- ICI[0x01].TV = (PC &~ 0xF) | 0x04 | 0x2; | |
- ICI[0x02].TV = (PC &~ 0xF) | 0x08 | 0x2; | |
- ICI[0x03].TV = (PC &~ 0xF) | 0x0C | 0x2; | |
- | |
- timestamp += 3; | |
- | |
- switch(PC & 0xC) | |
- { | |
- case 0x0: | |
- timestamp++; | |
- ICI[0x00].TV &= ~0x2; | |
- ICI[0x00].Data = MDFN_de32lsb<true>(&FMP[0x0]); | |
- case 0x4: | |
- timestamp++; | |
- ICI[0x01].TV &= ~0x2; | |
- ICI[0x01].Data = MDFN_de32lsb<true>(&FMP[0x4]); | |
- case 0x8: | |
- timestamp++; | |
- ICI[0x02].TV &= ~0x2; | |
- ICI[0x02].Data = MDFN_de32lsb<true>(&FMP[0x8]); | |
- case 0xC: | |
- timestamp++; | |
- ICI[0x03].TV &= ~0x2; | |
- ICI[0x03].Data = MDFN_de32lsb<true>(&FMP[0xC]); | |
- break; | |
- } | |
- instr = ICache[(PC & 0xFFC) >> 2].Data; | |
- } | |
- } | |
- | |
- //printf("PC=%08x, SP=%08x - op=0x%02x - funct=0x%02x - instr=0x%08x\n", PC, GPR[29], instr >> 26, instr & 0x3F, instr); | |
- //for(int i = 0; i < 32; i++) | |
- // printf("%02x : %08x\n", i, GPR[i]); | |
- //printf("\n"); | |
- | |
- opf = instr & 0x3F; | |
- | |
- if(instr & (0x3F << 26)) | |
- opf = 0x40 | (instr >> 26); | |
- | |
- opf |= IPCache; | |
- | |
-#if 0 | |
- { | |
- uint32 tmp = (ReadAbsorb[ReadAbsorbWhich] + 0x7FFFFFFF) >> 31; | |
- ReadAbsorb[ReadAbsorbWhich] -= tmp; | |
- timestamp = timestamp + 1 - tmp; | |
- } | |
-#else | |
- if(ReadAbsorb[ReadAbsorbWhich]) | |
- ReadAbsorb[ReadAbsorbWhich]--; | |
- //else if((uint8)WriteAbsorb) | |
- //{ | |
- // WriteAbsorb--; | |
- // if(!WriteAbsorb) | |
- // { | |
- // WriteAbsorbCount--; | |
- // if(WriteAbsorbMonkey) | |
- // WriteAbsorbMonkey--; | |
- // WriteAbsorb >>= 8; | |
- // } | |
- //} | |
- else | |
- timestamp++; | |
-#endif | |
#define DO_LDS() { GPR[LDWhich] = LDValue; ReadAbsorb[LDWhich] = LDAbsorb; ReadFudge = LDWhich; ReadAbsorbWhich |= LDWhich & 0x1F; LDWhich = 0x20; } | |
#define BEGIN_OPF(name, arg_op, arg_funct) { op_##name: /*assert( ((arg_op) ? (0x40 | (arg_op)) : (arg_funct)) == opf); */ | |
- #define END_OPF goto OpDone; } | |
#define DO_BRANCH(offset, mask) \ | |
{ \ | |
@@ -646,7 +559,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
{ \ | |
ADDBT(PC, (PC & new_PC_mask) + new_PC, false); \ | |
} \ | |
- goto SkipNPCStuff; \ | |
+ NEXT_INSTRUCTION(); \ | |
} | |
#define ITYPE uint32 rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32 rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32 immediate = (int32)(int16)(instr & 0xFFFF); /*printf(" rs=%02x(%08x), rt=%02x(%08x), immediate=(%08x) ", rs, GPR[rs], rt, GPR[rt], immediate);*/ | |
@@ -657,7 +570,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
#if HAVE_COMPUTED_GOTO | |
#define CGBEGIN static const void *const op_goto_table[256] = { | |
#define CGE(l) &&l, | |
- #define CGEND }; goto *op_goto_table[opf]; | |
+ #define CGEND }; | |
#else | |
/* (uint8) cast for cheaper alternative to generated branch+compare bounds check instructions, but still more | |
expensive than computed goto which needs no masking nor bounds checking. | |
@@ -667,6 +580,79 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
#define CGEND } } | |
#endif | |
+#define NEXT_INSTRUCTION() { \ | |
+ if (MDFN_LIKELY(timestamp < next_event_ts)) \ | |
+ { \ | |
+ \ | |
+ GPR[0] = 0; \ | |
+ \ | |
+ if(DebugMode && CPUHook) \ | |
+ { \ | |
+ ACTIVE_TO_BACKING; \ | |
+ \ | |
+ gte_ts_done -= timestamp; \ | |
+ muldiv_ts_done -= timestamp; \ | |
+ \ | |
+ CPUHook(timestamp, PC); \ | |
+ \ | |
+ gte_ts_done += timestamp; \ | |
+ muldiv_ts_done += timestamp; \ | |
+ \ | |
+ BACKING_TO_ACTIVE; \ | |
+ } \ | |
+ \ | |
+ if(BIOSPrintMode) \ | |
+ { \ | |
+ if(PC == 0xB0) \ | |
+ { \ | |
+ if(MDFN_UNLIKELY(GPR[9] == 0x3D)) \ | |
+ { \ | |
+ PSX_DBG_BIOS_PUTC(GPR[4]); \ | |
+ } \ | |
+ } \ | |
+ } \ | |
+ \ | |
+ if(MDFN_UNLIKELY(PC & 0x3)) \ | |
+ { \ | |
+ new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask); \ | |
+ new_PC_mask = 0; \ | |
+ assert(0); \ | |
+ } \ | |
+ \ | |
+ instr = ICache[(PC & 0xFFC) >> 2].Data; \ | |
+ \ | |
+ if(ICache[(PC & 0xFFC) >> 2].TV != PC) \ | |
+ { \ | |
+ instr = cache_fetch(timestamp, PC); \ | |
+ } \ | |
+ \ | |
+ opf = instr & 0x3F; \ | |
+ \ | |
+ if(instr & (0x3F << 26)) \ | |
+ opf = 0x40 | (instr >> 26); \ | |
+ \ | |
+ opf |= IPCache; \ | |
+ \ | |
+ if(ReadAbsorb[ReadAbsorbWhich]) \ | |
+ ReadAbsorb[ReadAbsorbWhich]--; \ | |
+ else \ | |
+ timestamp++; \ | |
+ goto *op_goto_table[opf]; \ | |
+ } else { \ | |
+ continue; \ | |
+ } \ | |
+ } | |
+ | |
+ | |
+#define END_OPF NPC(); NEXT_INSTRUCTION(); } | |
+ | |
+ | |
+#define NPC() do { \ | |
+ PC = (PC & new_PC_mask) + new_PC; \ | |
+ new_PC_mask = ~0U; \ | |
+ new_PC = 4; \ | |
+ } while (0) | |
+ | |
CGBEGIN | |
CGE(op_SLL) CGE(op_ILL) CGE(op_SRL) CGE(op_SRA) CGE(op_SLLV) CGE(op_ILL) CGE(op_SRLV) CGE(op_SRAV) | |
CGE(op_JR) CGE(op_JALR) CGE(op_ILL) CGE(op_ILL) CGE(op_SYSCALL) CGE(op_BREAK) CGE(op_ILL) CGE(op_ILL) | |
@@ -707,6 +693,8 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) | |
CGEND | |
+ NEXT_INSTRUCTION(); | |
+ | |
{ | |
BEGIN_OPF(ILL, 0, 0); | |
PSX_WARNING("[CPU] Unknown instruction @%08x = %08x, op=%02x, funct=%02x", PC, instr, instr >> 26, (instr & 0x3F)); | |
@@ -1140,7 +1128,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
LDValue = GTE_ReadCR(rd); | |
//printf("GTE ReadCR: %d %d\n", rd, GPR[rt]); | |
- } | |
+ } | |
break; | |
case 0x06: // CTC2 | |
@@ -1154,7 +1142,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
if(timestamp < gte_ts_done) | |
timestamp = gte_ts_done; | |
- GTE_WriteCR(rd, val); | |
+ GTE_WriteCR(rd, val); | |
DO_LDS(); | |
} | |
break; | |
@@ -2069,7 +2057,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
DO_LDS(); | |
END_OPF; | |
- // | |
+ // | |
// SH - Store Halfword | |
// | |
BEGIN_OPF(SH, 0x29, 0); | |
@@ -2093,7 +2081,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
DO_LDS(); | |
END_OPF; | |
- // | |
+ // | |
// SW - Store Word | |
// | |
BEGIN_OPF(SW, 0x2B, 0); | |
@@ -2270,7 +2258,7 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
BEGIN_OPF(INTERRUPT, 0x3F, 0); | |
if(Halted) | |
{ | |
- goto SkipNPCStuff; | |
+ NEXT_INSTRUCTION(); | |
} | |
else | |
{ | |
@@ -2282,16 +2270,8 @@ pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in) | |
END_OPF; | |
} | |
- OpDone: ; | |
- | |
- PC = (PC & new_PC_mask) + new_PC; | |
- new_PC_mask = ~0U; | |
- new_PC = 4; | |
- | |
- SkipNPCStuff: ; | |
- | |
//printf("\n"); | |
- } | |
+ | |
} while(MDFN_LIKELY(PSX_EventHandler(timestamp))); | |
if(gte_ts_done > 0) | |
@@ -2538,7 +2518,7 @@ void PS_CPU::CheckBreakpoints(void (*callback)(bool write, uint32 address, unsig | |
callback(true, address, 1); | |
END_OPF; | |
- // | |
+ // | |
// SH - Store Halfword | |
// | |
BEGIN_OPF(0x29, 0); | |
@@ -2548,7 +2528,7 @@ void PS_CPU::CheckBreakpoints(void (*callback)(bool write, uint32 address, unsig | |
callback(true, address, 2); | |
END_OPF; | |
- // | |
+ // | |
// SW - Store Word | |
// | |
BEGIN_OPF(0x2B, 0); | |
diff --git a/src/psx/cpu.h b/src/psx/cpu.h | |
index f6e3d4a..6312844 100644 | |
--- a/src/psx/cpu.h | |
+++ b/src/psx/cpu.h | |
@@ -211,6 +211,8 @@ class PS_CPU | |
uint32 Exception(uint32 code, uint32 PC, const uint32 NPM) MDFN_WARN_UNUSED_RESULT; | |
+ uint32 cache_fetch(pscpu_timestamp_t ×tamp, uint32 PC); | |
+ | |
template<bool DebugMode, bool BIOSPrintMode, bool ILHMode> pscpu_timestamp_t RunReal(pscpu_timestamp_t timestamp_in) NO_INLINE; | |
template<typename T> T PeekMemory(uint32 address) MDFN_COLD; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment