Skip to content

Instantly share code, notes, and snippets.

@simias
Created September 16, 2015 18:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simias/f2f96b9965675e4db5fc to your computer and use it in GitHub Desktop.
Save simias/f2f96b9965675e4db5fc to your computer and use it in GitHub Desktop.
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 &timestamp, 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 &timestamp, 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