1 /******************************************************************************/
2 /* Mednafen Sony PS1 Emulation Module                                         */
3 /******************************************************************************/
4 /* cpu.cpp:
5 **  Copyright (C) 2011-2016 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 #pragma GCC optimize ("unroll-loops")
23 
24 #include "psx.h"
25 #include "cpu.h"
26 
27 #include "../state_helpers.h"
28 #include "../math_ops.h"
29 #include "../mednafen.h"
30 #include "../mednafen-endian.h"
31 
32 // iCB: PGXP STUFF
33 #include "../pgxp/pgxp_cpu.h"
34 #include "../pgxp/pgxp_gte.h"
35 #include "../pgxp/pgxp_main.h"
36 int pgxpMode = PGXP_GetModes();
37 
38 #ifdef HAVE_LIGHTREC
39 #include <lightrec.h>
40 #include <unistd.h>
41 #include <signal.h>
42 
43 enum DYNAREC prev_dynarec;
44 bool prev_invalidate;
45 extern bool psx_dynarec_invalidate;
46 extern uint8 psx_mmap;
47 static struct lightrec_state *lightrec_state;
48 #endif
49 
50 extern bool psx_gte_overclock;
51 pscpu_timestamp_t PS_CPU::next_event_ts;
52 uint32 PS_CPU::IPCache;
53 uint32 PS_CPU::BIU;
54 bool PS_CPU::Halted;
55 struct PS_CPU::CP0 PS_CPU::CP0;
56 char PS_CPU::cache_buf[64 * 1024];
57 
58 #if 0
59  #define EXP_ILL_CHECK(n) {n;}
60 #else
61  #define EXP_ILL_CHECK(n) {}
62 #endif
63 
64 #define BIU_ENABLE_ICACHE_S1	0x00000800	// Enable I-cache, set 1
65 #define BIU_ICACHE_FSIZE_MASK	0x00000300      // I-cache fill size mask; 0x000 = 2 words, 0x100 = 4 words, 0x200 = 8 words, 0x300 = 16 words
66 #define BIU_ENABLE_DCACHE	0x00000080	// Enable D-cache
67 #define BIU_DCACHE_SCRATCHPAD	0x00000008	// Enable scratchpad RAM mode of D-cache
68 #define BIU_TAG_TEST_MODE	0x00000004	// Enable TAG test mode(IsC must be set to 1 as well presumably?)
69 #define BIU_INVALIDATE_MODE	0x00000002	// Enable Invalidate mode(IsC must be set to 1 as well presumably?)
70 #define BIU_LOCK_MODE		0x00000001	// Enable Lock mode(IsC must be set to 1 as well presumably?)
71 
72 
73 #if NOT_LIBRETRO
74 namespace MDFN_IEN_PSX
75 {
76 #endif
77 
78 
PS_CPU()79 PS_CPU::PS_CPU()
80 {
81  //printf("%zu\n", (size_t)((uintptr_t)ICache - (uintptr_t)this));
82 
83    addr_mask[0] = 0xFFFFFFFF;
84    addr_mask[1] = 0xFFFFFFFF;
85    addr_mask[2] = 0xFFFFFFFF;
86    addr_mask[3] = 0xFFFFFFFF;
87    addr_mask[4] = 0x7FFFFFFF;
88    addr_mask[5] = 0x1FFFFFFF;
89    addr_mask[6] = 0xFFFFFFFF;
90    addr_mask[7] = 0xFFFFFFFF;
91 
92  Halted = false;
93 
94  memset(FastMap, 0, sizeof(FastMap));
95  memset(DummyPage, 0xFF, sizeof(DummyPage));	// 0xFF to trigger an illegal instruction exception, so we'll know what's up when debugging.
96 
97  for(uint64 a = 0x00000000; a < (1ULL << 32); a += FAST_MAP_PSIZE)
98   SetFastMap(DummyPage, a, FAST_MAP_PSIZE);
99 
100  CPUHook = NULL;
101  ADDBT = NULL;
102 
103  GTE_Init();
104 
105  for(unsigned i = 0; i < 24; i++)
106  {
107   uint8 v = 7;
108 
109   if(i < 12)
110    v += 4;
111 
112   if(i < 21)
113    v += 3;
114 
115   MULT_Tab24[i] = v;
116  }
117 }
118 
~PS_CPU()119 PS_CPU::~PS_CPU()
120 {
121 #ifdef HAVE_LIGHTREC
122  if (lightrec_state)
123   lightrec_plugin_shutdown();
124 #endif
125 
126 }
127 
SetFastMap(void * region_mem,uint32 region_address,uint32 region_size)128 void PS_CPU::SetFastMap(void *region_mem, uint32 region_address, uint32 region_size)
129 {
130  // FAST_MAP_SHIFT
131  // FAST_MAP_PSIZE
132 
133  for(uint64 A = region_address; A < (uint64)region_address + region_size; A += FAST_MAP_PSIZE)
134  {
135   FastMap[A >> FAST_MAP_SHIFT] = ((uintptr_t)region_mem - region_address);
136  }
137 }
138 
RecalcIPCache(void)139 INLINE void PS_CPU::RecalcIPCache(void)
140 {
141  IPCache = 0;
142 
143  if((CP0.SR & CP0.CAUSE & 0xFF00) && (CP0.SR & 1))
144   IPCache = 0x80;
145 
146  if(Halted)
147   IPCache = 0x80;
148 }
149 
SetHalt(bool status)150 void PS_CPU::SetHalt(bool status)
151 {
152  Halted = status;
153  RecalcIPCache();
154 }
155 
156 const uint8_t *PSX_LoadExpansion1(void);
157 
Power(void)158 void PS_CPU::Power(void)
159 {
160  assert(sizeof(ICache) == sizeof(ICache_Bulk));
161 
162  memset(GPR, 0, sizeof(GPR));
163  memset(&CP0, 0, sizeof(CP0));
164  LO = 0;
165  HI = 0;
166 
167  gte_ts_done = 0;
168  muldiv_ts_done = 0;
169 
170  BACKED_PC = 0xBFC00000;
171  BACKED_new_PC = BACKED_PC + 4;
172  BDBT = 0;
173 
174  BACKED_LDWhich = 0x20;
175  BACKED_LDValue = 0;
176  LDAbsorb = 0;
177  memset(ReadAbsorb, 0, sizeof(ReadAbsorb));
178  ReadAbsorbWhich = 0;
179  ReadFudge = 0;
180 
181  CP0.SR |= (1 << 22);	// BEV
182  CP0.SR |= (1 << 21);	// TS
183 
184  CP0.PRID = 0x2;
185 
186  RecalcIPCache();
187 
188 
189  BIU = 0;
190 
191  memset(ScratchRAM->data8, 0, 1024);
192 
193  PGXP_Init();
194 
195 #ifdef HAVE_LIGHTREC
196  prev_dynarec = psx_dynarec;
197  prev_invalidate = psx_dynarec_invalidate;
198  pgxpMode = PGXP_GetModes();
199  if(psx_dynarec != DYNAREC_DISABLED)
200   lightrec_plugin_init();
201 #endif
202 
203  // Not quite sure about these poweron/reset values:
204  for(unsigned i = 0; i < 1024; i++)
205  {
206   ICache[i].TV = 0x2 | ((BIU & 0x800) ? 0x0 : 0x1);
207   ICache[i].Data = 0;
208  }
209 
210  GTE_Power();
211 }
212 
StateAction(StateMem * sm,const unsigned load,const bool data_only)213 int PS_CPU::StateAction(StateMem *sm, const unsigned load, const bool data_only)
214 {
215  uint32 OPM = BDBT;
216 
217  SFORMAT StateRegs[] =
218  {
219   SFARRAY32(GPR, 32),
220   SFVAR(LO),
221   SFVAR(HI),
222   SFVAR(BACKED_PC),
223   SFVAR(BACKED_new_PC),
224   SFVARN(OPM, "BACKED_new_PC_mask"),
225 
226   SFVAR(IPCache),
227   SFVAR(Halted),
228 
229   SFVAR(BACKED_LDWhich),
230   SFVAR(BACKED_LDValue),
231   SFVAR(LDAbsorb),
232 
233   SFVAR(next_event_ts),
234   SFVAR(gte_ts_done),
235   SFVAR(muldiv_ts_done),
236 
237   SFVAR(BIU),
238   SFVAR(ICache_Bulk),
239 
240   SFVAR(CP0.Regs),
241 
242   SFARRAY(ReadAbsorb, 0x20),
243   SFVARN(ReadAbsorb[0x20], "ReadAbsorbDummy"),
244   SFVAR(ReadAbsorbWhich),
245   SFVAR(ReadFudge),
246 
247   SFARRAYN(ScratchRAM->data8, 1024, "ScratchRAM.data8"),
248 
249   SFEND
250  };
251  int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "CPU");
252 
253  ret &= GTE_StateAction(sm, load, data_only);
254 
255  if(load)
256  {
257 #ifdef HAVE_LIGHTREC
258   if(psx_dynarec != DYNAREC_DISABLED) {
259    if(lightrec_state)
260     lightrec_invalidate_all(lightrec_state);
261    else
262     lightrec_plugin_init();
263   }
264 #endif
265   if(load < 0x939)
266   {
267    //
268    // For compatibility with pre-0.9.39 save states.
269    //
270    uint32 NOPM = ~OPM;
271 
272    //printf("Old: new_PC=0x%08x, new_PC_mask=0x%08x\n", BACKED_new_PC, OPM);
273 
274    BDBT = ((NOPM << 1) | (NOPM >> 1)) & 0x3;
275 
276    BACKED_new_PC = (BACKED_PC & OPM) + BACKED_new_PC;
277   }
278   else
279    BDBT = OPM;
280 
281   ReadAbsorbWhich &= 0x1F;
282   BACKED_LDWhich %= 0x21;
283 
284   //printf("PC=0x%08x, new_PC=0x%08x, BDBT=0x%02x\n", BACKED_PC, BACKED_new_PC, BDBT);
285  }
286  return ret;
287 }
288 
AssertIRQ(unsigned which,bool asserted)289 void PS_CPU::AssertIRQ(unsigned which, bool asserted)
290 {
291  assert(which <= 5);
292 
293  CP0.CAUSE &= ~(1 << (10 + which));
294 
295  if(asserted)
296   CP0.CAUSE |= 1 << (10 + which);
297 
298  RecalcIPCache();
299 }
300 
SetBIU(uint32 val)301 void PS_CPU::SetBIU(uint32 val)
302 {
303  const uint32 old_BIU = BIU;
304 
305  BIU = val & ~(0x440);
306 
307  if((BIU ^ old_BIU) & 0x800)
308  {
309   if(BIU & 0x800)	// ICache enabled
310   {
311    for(unsigned i = 0; i < 1024; i++)
312     ICache[i].TV &= ~0x1;
313   }
314   else			// ICache disabled
315   {
316    for(unsigned i = 0; i < 1024; i++)
317     ICache[i].TV |= 0x1;
318   }
319  }
320 
321  PSX_DBG(PSX_DBG_SPARSE, "[CPU] Set BIU=0x%08x\n", BIU);
322 }
323 
GetBIU(void)324 uint32 PS_CPU::GetBIU(void)
325 {
326  return BIU;
327 }
328 
329 template<typename T>
PeekMemory(uint32 address)330 INLINE T PS_CPU::PeekMemory(uint32 address)
331 {
332  T ret;
333  address &= addr_mask[address >> 29];
334 
335  if(address >= 0x1F800000 && address <= 0x1F8003FF)
336   return ScratchRAM->Read<T>(address & 0x3FF);
337 
338  //assert(!(CP0.SR & 0x10000));
339 
340  if(sizeof(T) == 1)
341   ret = PSX_MemPeek8(address);
342  else if(sizeof(T) == 2)
343   ret = PSX_MemPeek16(address);
344  else
345   ret = PSX_MemPeek32(address);
346 
347  return(ret);
348 }
349 
350 template<typename T>
PokeMemory(uint32 address,T value)351 void PS_CPU::PokeMemory(uint32 address, T value)
352 {
353  address &= addr_mask[address >> 29];
354 
355  if(address >= 0x1F800000 && address <= 0x1F8003FF)
356   return ScratchRAM->Write<T>(address & 0x3FF, value);
357 
358  if(sizeof(T) == 1)
359   PSX_MemPoke8(address, value);
360  else if(sizeof(T) == 2)
361   PSX_MemPoke16(address, value);
362  else
363   PSX_MemPoke32(address, value);
364 }
365 
366 template<typename T>
ReadMemory(pscpu_timestamp_t & timestamp,uint32 address,bool DS24,bool LWC_timing)367 INLINE T PS_CPU::ReadMemory(pscpu_timestamp_t &timestamp, uint32 address, bool DS24, bool LWC_timing)
368 {
369  T ret;
370 
371  ReadAbsorb[ReadAbsorbWhich] = 0;
372  ReadAbsorbWhich = 0;
373 
374 #if 0
375  if(MDFN_UNLIKELY(CP0.SR & 0x10000))
376  {
377   uint32 tmp = 0;	// TODO(someday): = open bus
378 
379   LDAbsorb = 0;
380 
381   if(BIU & (BIU_TAG_TEST_MODE | BIU_INVALIDATE_MODE | BIU_LOCK_MODE))
382   {
383    if(BIU & BIU_TAG_TEST_MODE)
384    {
385     const __ICache* const ICI = &ICache[((address & 0xFF0) >> 2)];
386 
387     tmp &= ~0x3F;	// bits 0-3 validity, bit 4 tag compare match, bit 5 forced to 0(lock bit apparently unimplemented in the PS1).
388 
389     //
390     // Get validity bits.
391     //
392     for(unsigned i = 0; i < 4; i++)
393      tmp |= (!(ICI[i].TV & 0x02)) << i;
394 
395     //
396     // Tag compare.
397     //
398     if(!((address ^ ICI[0].TV) & 0xFFFFF000))
399      tmp |= 0x10;
400    }
401   }
402   else
403   {
404    tmp = ICache[(address & 0xFFC) >> 2].Data;
405   }
406 
407   return tmp >> ((address & 0x3) * 8);
408  }
409 #endif
410  //
411  //
412  //
413 
414  address &= addr_mask[address >> 29];
415 
416  if(address >= 0x1F800000 && address <= 0x1F8003FF)
417  {
418   LDAbsorb = 0;
419 
420   if(DS24)
421    return ScratchRAM->ReadU24(address & 0x3FF);
422   else
423    return ScratchRAM->Read<T>(address & 0x3FF);
424  }
425 
426  timestamp += (ReadFudge >> 4) & 2;
427 
428  //assert(!(CP0.SR & 0x10000));
429 
430  pscpu_timestamp_t lts = timestamp;
431 
432  if(sizeof(T) == 1)
433   ret = PSX_MemRead8(lts, address);
434  else if(sizeof(T) == 2)
435   ret = PSX_MemRead16(lts, address);
436  else
437  {
438   if(DS24)
439    ret = PSX_MemRead24(lts, address) & 0xFFFFFF;
440   else
441    ret = PSX_MemRead32(lts, address);
442  }
443 
444  if(LWC_timing)
445   lts += 1;
446  else
447   lts += 2;
448 
449  LDAbsorb = (lts - timestamp);
450  timestamp = lts;
451 
452  return(ret);
453 }
454 
455 template<typename T>
WriteMemory(pscpu_timestamp_t & timestamp,uint32 address,uint32 value,bool DS24)456 INLINE void PS_CPU::WriteMemory(pscpu_timestamp_t &timestamp, uint32 address, uint32 value, bool DS24)
457 {
458  if(MDFN_LIKELY(!(CP0.SR & 0x10000)))
459  {
460   address &= addr_mask[address >> 29];
461 
462   if(address >= 0x1F800000 && address <= 0x1F8003FF)
463   {
464    if(DS24)
465     ScratchRAM->WriteU24(address & 0x3FF, value);
466    else
467     ScratchRAM->Write<T>(address & 0x3FF, value);
468 
469    return;
470   }
471 
472   if(sizeof(T) == 1)
473    PSX_MemWrite8(timestamp, address, value);
474   else if(sizeof(T) == 2)
475    PSX_MemWrite16(timestamp, address, value);
476   else
477   {
478    if(DS24)
479     PSX_MemWrite24(timestamp, address, value);
480    else
481     PSX_MemWrite32(timestamp, address, value);
482   }
483  }
484  else
485  {
486   if(BIU & BIU_ENABLE_ICACHE_S1)	// Instruction cache is enabled/active
487   {
488    if(BIU & (BIU_TAG_TEST_MODE | BIU_INVALIDATE_MODE | BIU_LOCK_MODE))
489    {
490     const uint8 valid_bits = (BIU & BIU_TAG_TEST_MODE) ? ((value << ((address & 0x3) * 8)) & 0x0F) : 0x00;
491     __ICache* const ICI = &ICache[((address & 0xFF0) >> 2)];
492 
493     //
494     // Set validity bits and tag.
495     //
496     for(unsigned i = 0; i < 4; i++)
497      ICI[i].TV = ((valid_bits & (1U << i)) ? 0x00 : 0x02) | (address & 0xFFFFFFF0) | (i << 2);
498    }
499    else
500    {
501     ICache[(address & 0xFFC) >> 2].Data = value << ((address & 0x3) * 8);
502    }
503   }
504 
505   if((BIU & 0x081) == 0x080)	// Writes to the scratchpad(TODO test)
506   {
507    if(DS24)
508     ScratchRAM->WriteU24(address & 0x3FF, value);
509    else
510     ScratchRAM->Write<T>(address & 0x3FF, value);
511   }
512   //printf("IsC WRITE%d 0x%08x 0x%08x -- CP0.SR=0x%08x\n", (int)sizeof(T), address, value, CP0.SR);
513  }
514 }
515 
516 //
517 // ICache emulation here is not very accurate.  More accurate emulation had about a 6% performance penalty for simple
518 // code that just looped infinitely, with no tangible known benefit for commercially-released games.
519 //
520 // We do emulate the tag test mode functionality in regards to loading custom tag, valid bits, and instruction word data, as it could
521 // hypothetically be useful for homebrew.  However, due to inaccuracies, it's possible to load a tag for an address in the non-cached
522 // 0xA0000000-0xBFFFFFFF range, jump to the address, and have it execute out of instruction cache, which is wrong and not possible on a PS1.
523 //
524 // The other major inaccuracy here is how the region 0x80000000-0x9FFFFFFF is handled.  On a PS1, when fetching instruction word data
525 // from this region, the upper bit is forced to 0 before the tag compare(though the tag compare IS a full 20 bit compare),
526 // and this address with the upper bit set to 0 is also written to the tag on cache miss.  We don't do the address masking here,
527 // so in addition to the tag test mode implications, a program that jumps from somewhere in 0x00000000-0x1FFFFFFF to the corresponding
528 // location in 0x80000000-0x9FFFFFFF will always cause a cache miss in Mednafen.
529 //
530 // On a PS1, icache miss fill size can be programmed to 2, 4, 8, or 16 words(though 4 words is the nominally-correct setting).  We always emulate the cache
531 // miss fill size as 4-words.  Fill size of 8-words and 16-words are buggy on a PS1, and will write the wrong instruction data values(or read from the wrong
532 // addresses?) to cache when a cache miss occurs on an address that isn't aligned to a 4-word boundary.
533 // Fill size of 2-words seems to work on a PS1, and even behaves as if the line size is 2 words in regards to clearing
534 // the valid bits(when the tag matches, of course), but is obviously not very efficient unless running code that's just endless branching.
535 //
ReadInstruction(pscpu_timestamp_t & timestamp,uint32 address)536 INLINE uint32 PS_CPU::ReadInstruction(pscpu_timestamp_t &timestamp, uint32 address)
537 {
538  uint32 instr;
539 
540  instr = ICache[(address & 0xFFC) >> 2].Data;
541 
542  if(ICache[(address & 0xFFC) >> 2].TV != address)
543  {
544   ReadAbsorb[ReadAbsorbWhich] = 0;
545   ReadAbsorbWhich = 0;
546 
547   if(address >= 0xA0000000 || !(BIU & 0x800))
548   {
549    instr = MDFN_de32lsb<true>((uint8*)(FastMap[address >> FAST_MAP_SHIFT] + address));
550 
551    if (!psx_gte_overclock) {
552       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).
553    }
554   }
555   else
556   {
557    __ICache *ICI = &ICache[((address & 0xFF0) >> 2)];
558    const uint8 *FMP = (uint8*)(FastMap[(address & 0xFFFFFFF0) >> FAST_MAP_SHIFT] + (address & 0xFFFFFFF0));
559 
560    // | 0x2 to simulate (in)validity bits.
561    ICI[0x00].TV = (address & 0xFFFFFFF0) | 0x0 | 0x2;
562    ICI[0x01].TV = (address & 0xFFFFFFF0) | 0x4 | 0x2;
563    ICI[0x02].TV = (address & 0xFFFFFFF0) | 0x8 | 0x2;
564    ICI[0x03].TV = (address & 0xFFFFFFF0) | 0xC | 0x2;
565 
566    if (!psx_gte_overclock) {
567       timestamp += 3;
568    }
569 
570    switch(address & 0xC)
571    {
572     case 0x0:
573         if (!psx_gte_overclock) {
574            timestamp++;
575         }
576         ICI[0x00].TV &= ~0x2;
577 	ICI[0x00].Data = MDFN_de32lsb<true>(&FMP[0x0]);
578     case 0x4:
579         if (!psx_gte_overclock) {
580            timestamp++;
581         }
582         ICI[0x01].TV &= ~0x2;
583 	ICI[0x01].Data = MDFN_de32lsb<true>(&FMP[0x4]);
584     case 0x8:
585         if (!psx_gte_overclock) {
586            timestamp++;
587         }
588         ICI[0x02].TV &= ~0x2;
589 	ICI[0x02].Data = MDFN_de32lsb<true>(&FMP[0x8]);
590     case 0xC:
591         if (!psx_gte_overclock) {
592            timestamp++;
593         }
594         ICI[0x03].TV &= ~0x2;
595 	ICI[0x03].Data = MDFN_de32lsb<true>(&FMP[0xC]);
596 	break;
597    }
598    instr = ICache[(address & 0xFFC) >> 2].Data;
599   }
600  }
601 
602  return instr;
603 }
604 
Exception(uint32 code,uint32 PC,const uint32 NP,const uint32 instr)605 uint32 NO_INLINE PS_CPU::Exception(uint32 code, uint32 PC, const uint32 NP, const uint32 instr)
606 {
607  uint32 handler = 0x80000080;
608 
609  assert(code < 16);
610 
611 #ifdef DEBUG
612  if(code != EXCEPTION_INT && code != EXCEPTION_BP && code != EXCEPTION_SYSCALL)
613  {
614   static const char* exmne[16] =
615   {
616    "INT", "MOD", "TLBL", "TLBS", "ADEL", "ADES", "IBE", "DBE", "SYSCALL", "BP", "RI", "COPU", "OV", NULL, NULL, NULL
617   };
618 
619   PSX_DBG(PSX_DBG_WARNING, "[CPU] Exception %s(0x%02x) @ PC=0x%08x(NP=0x%08x, BDBT=0x%02x), Instr=0x%08x, IPCache=0x%02x, CAUSE=0x%08x, SR=0x%08x, IRQC_Status=0x%04x, IRQC_Mask=0x%04x\n",
620 	exmne[code], code, PC, NP, BDBT, instr, IPCache, CP0.CAUSE, CP0.SR, IRQ_GetRegister(IRQ_GSREG_STATUS, NULL, 0), IRQ_GetRegister(IRQ_GSREG_MASK, NULL, 0));
621  }
622 #endif
623 
624  if(CP0.SR & (1 << 22))	// BEV
625   handler = 0xBFC00180;
626 
627  CP0.EPC = PC;
628  if(BDBT & 2)
629  {
630   CP0.EPC -= 4;
631   CP0.TAR = NP;
632  }
633 
634  if(ADDBT)
635   ADDBT(PC, handler, true);
636 
637  // "Push" IEc and KUc(so that the new IEc and KUc are 0)
638  CP0.SR = (CP0.SR & ~0x3F) | ((CP0.SR << 2) & 0x3F);
639 
640  // Setup cause register
641  CP0.CAUSE &= 0x0000FF00;
642  CP0.CAUSE |= code << 2;
643 
644  CP0.CAUSE |= BDBT << 30;
645  CP0.CAUSE |= (instr << 2) & (0x3 << 28);	// CE
646 
647  //
648  //
649  //
650  RecalcIPCache();
651 
652  BDBT = 0;
653 
654  return(handler);
655 }
656 
657 #define BACKING_TO_ACTIVE			\
658 	PC = BACKED_PC;				\
659 	new_PC = BACKED_new_PC;			\
660 	LDWhich = BACKED_LDWhich;		\
661 	LDValue = BACKED_LDValue;
662 
663 #define ACTIVE_TO_BACKING			\
664 	BACKED_PC = PC;				\
665 	BACKED_new_PC = new_PC;			\
666 	BACKED_LDWhich = LDWhich;		\
667 	BACKED_LDValue = LDValue;
668 
669 //
670 // Should come before DO_LDS() so the EXP_ILL_CHECK() emulator debugging macro in GPR_DEP() will work properly.
671 //
672 #define GPR_DEPRES_BEGIN { uint8 back = ReadAbsorb[0];
673 #define GPR_DEP(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; EXP_ILL_CHECK(if(LDWhich > 0 && LDWhich < 0x20 && LDWhich == tn) { PSX_DBG(PSX_DBG_WARNING, "[CPU] Instruction at PC=0x%08x in load delay slot has dependency on load target register(0x%02x): SR=0x%08x\n", PC, LDWhich, CP0.SR); }) }
674 #define GPR_RES(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; }
675 #define GPR_DEPRES_END ReadAbsorb[0] = back; }
676 
677 template<bool DebugMode, bool BIOSPrintMode, bool ILHMode>
RunReal(pscpu_timestamp_t timestamp_in)678 pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
679 {
680  pscpu_timestamp_t timestamp = timestamp_in;
681 
682  uint32 PC;
683  uint32 new_PC;
684  uint32 LDWhich;
685  uint32 LDValue;
686 
687  //printf("%d %d\n", gte_ts_done, muldiv_ts_done);
688 
689  gte_ts_done += timestamp;
690  muldiv_ts_done += timestamp;
691 
692  BACKING_TO_ACTIVE;
693 
694 #if defined(HAVE_LIGHTREC) && defined(LIGHTREC_DEBUG)
695  u32 oldpc = PC;
696 #endif
697 
698  do
699  {
700   //printf("Running: %d %d\n", timestamp, next_event_ts);
701   while(MDFN_LIKELY(timestamp < next_event_ts))
702   {
703    uint32 instr;
704    uint32 opf;
705 
706    // Zero must be zero...until the Master Plan is enacted.
707    GPR[0] = 0;
708 
709 #ifdef DEBUG
710    if(DebugMode && CPUHook)
711    {
712     ACTIVE_TO_BACKING;
713 
714     // For save states in step mode.
715     gte_ts_done -= timestamp;
716     muldiv_ts_done -= timestamp;
717 
718     CPUHook(timestamp, PC);
719 
720     // For save states in step mode.
721     gte_ts_done += timestamp;
722     muldiv_ts_done += timestamp;
723 
724     BACKING_TO_ACTIVE;
725    }
726 #endif
727 
728 #if NOT_LIBRETRO
729    if(BIOSPrintMode)
730    {
731     if(PC == 0xB0)
732     {
733      if(MDFN_UNLIKELY(GPR[9] == 0x3D))
734      {
735       PSX_DBG_BIOS_PUTC(GPR[4]);
736      }
737     }
738    }
739 #endif
740 
741    //
742    // Instruction fetch
743    //
744    if(MDFN_UNLIKELY(PC & 0x3))
745    {
746     // This will block interrupt processing, but since we're going more for keeping broken homebrew/hacks from working
747     // than super-duper-accurate pipeline emulation, it shouldn't be a problem.
748     CP0.BADA = PC;
749     new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, 0);
750     goto OpDone;
751    }
752 
753    instr = ReadInstruction(timestamp, PC);
754 
755 
756    //
757    // Instruction decode
758    //
759    opf = instr & 0x3F;
760 
761    if(instr & (0x3F << 26))
762     opf = 0x40 | (instr >> 26);
763 
764    opf |= IPCache;
765 
766    if(ReadAbsorb[ReadAbsorbWhich])
767     ReadAbsorb[ReadAbsorbWhich]--;
768    else
769     timestamp++;
770 
771    #define DO_LDS() { GPR[LDWhich] = LDValue; ReadAbsorb[LDWhich] = LDAbsorb; ReadFudge = LDWhich; ReadAbsorbWhich |= LDWhich & 0x1F; LDWhich = 0x20; }
772    #define BEGIN_OPF(name) { op_##name:
773    #define END_OPF goto OpDone; }
774 
775 #ifdef DEBUG
776 #define DEBUG_ADDBT() if(DebugMode && ADDBT) { ADDBT(PC, new_PC, false); }
777 #define DEBUG_ILH() \
778 	  if(ILHMode)						\
779 	  {							\
780 	   if(old_PC == (((new_PC - 4) & mask) + offset))	\
781 	   {							\
782 	    if(MDFN_densb<uint32, true>((uint8*)(FastMap[PC >> FAST_MAP_SHIFT] + PC)) == 0)	\
783 	    {							\
784 	     if(next_event_ts > timestamp) /* Necessary since next_event_ts might be set to something like "0" to force a call to the event handler. */		\
785 	     {							\
786 	      timestamp = next_event_ts;			\
787 	     }							\
788 	    }							\
789 	   }							\
790 	  }
791 #else
792 #define DEBUG_ADDBT()
793 #define DEBUG_ILH()
794 #endif
795 
796    #define DO_BRANCH(arg_cond, arg_offset, arg_mask, arg_dolink, arg_linkreg)\
797 	{							\
798 	 const bool cond = (arg_cond);				\
799 	 const uint32 offset = (arg_offset);			\
800 	 const uint32 mask = (arg_mask);			\
801 	 const uint32 old_PC = PC;				\
802 								\
803 	 EXP_ILL_CHECK(if(BDBT) { PSX_DBG(PSX_DBG_WARNING, "[CPU] Branch instruction at PC=0x%08x in branch delay slot: SR=0x%08x\n", PC, CP0.SR);}) 	\
804 								\
805 	 PC = new_PC;						\
806 	 new_PC += 4;						\
807 	 BDBT = 2;						\
808 								\
809 	 if(arg_dolink)						\
810 	  GPR[(arg_linkreg)] = new_PC;				\
811 								\
812 	 if(cond)						\
813 	 {							\
814      DEBUG_ILH() \
815 	  new_PC = ((new_PC - 4) & mask) + offset;		\
816 	  BDBT = 3;						\
817      DEBUG_ADDBT() \
818 	 }							\
819 								\
820 	 goto SkipNPCStuff;					\
821 	}
822 
823    #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);*/
824    #define ITYPE_ZE uint32 rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32 rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32 immediate = instr & 0xFFFF; /*printf(" rs=%02x(%08x), rt=%02x(%08x), immediate=(%08x) ", rs, GPR[rs], rt, GPR[rt], immediate);*/
825    #define JTYPE uint32 target = instr & ((1 << 26) - 1); /*printf(" target=(%08x) ", target);*/
826    #define RTYPE uint32 rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32 rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32 rd MDFN_NOWARN_UNUSED = (instr >> 11) & 0x1F; uint32 shamt MDFN_NOWARN_UNUSED = (instr >> 6) & 0x1F; /*printf(" rs=%02x(%08x), rt=%02x(%08x), rd=%02x(%08x) ", rs, GPR[rs], rt, GPR[rt], rd, GPR[rd]);*/
827 
828 #if HAVE_COMPUTED_GOTO
829    #if 0
830 	//
831 	// These truncated 32-bit table values apparently can't be calculated at compile/link time by gcc on x86_64, so gcc inserts initialization code, but
832 	// the compare for the initialization code path is placed sub-optimally(near where the table value is used instead of at the beginning of the function).
833 	//
834 	#define CGBEGIN static const uint32 const op_goto_table[256] = {
835 	#define CGE(l) (uint32)(uintptr_t)&&l,
836 	#define CGEND }; goto *(void*)(uintptr_t)op_goto_table[opf];
837    #else
838 	#define CGBEGIN static const void *const op_goto_table[256] = {
839 	#define CGE(l) &&l,
840 	#define CGEND }; goto *op_goto_table[opf];
841    #endif
842 #else
843    /* (uint8) cast for cheaper alternative to generated branch+compare bounds check instructions, but still more
844       expensive than computed goto which needs no masking nor bounds checking.
845    */
846    #define CGBEGIN { enum { CGESB = 1 + __COUNTER__ }; switch((uint8)opf) {
847    #define CGE(l) case __COUNTER__ - CGESB: goto l;
848    #define CGEND } }
849 #endif
850 
851    CGBEGIN
852     CGE(op_SLL)  CGE(op_ILL)   CGE(op_SRL)  CGE(op_SRA)   CGE(op_SLLV)    CGE(op_ILL)   CGE(op_SRLV) CGE(op_SRAV)
853     CGE(op_JR)   CGE(op_JALR)  CGE(op_ILL)  CGE(op_ILL)   CGE(op_SYSCALL) CGE(op_BREAK) CGE(op_ILL)  CGE(op_ILL)
854     CGE(op_MFHI) CGE(op_MTHI)  CGE(op_MFLO) CGE(op_MTLO)  CGE(op_ILL)     CGE(op_ILL)   CGE(op_ILL)  CGE(op_ILL)
855     CGE(op_MULT) CGE(op_MULTU) CGE(op_DIV)  CGE(op_DIVU)  CGE(op_ILL)     CGE(op_ILL)   CGE(op_ILL)  CGE(op_ILL)
856     CGE(op_ADD)  CGE(op_ADDU)  CGE(op_SUB)  CGE(op_SUBU)  CGE(op_AND)     CGE(op_OR)    CGE(op_XOR)  CGE(op_NOR)
857     CGE(op_ILL)  CGE(op_ILL)   CGE(op_SLT)  CGE(op_SLTU)  CGE(op_ILL)     CGE(op_ILL)   CGE(op_ILL)  CGE(op_ILL)
858     CGE(op_ILL)  CGE(op_ILL)   CGE(op_ILL)  CGE(op_ILL)   CGE(op_ILL)     CGE(op_ILL)   CGE(op_ILL)  CGE(op_ILL)
859     CGE(op_ILL)  CGE(op_ILL)   CGE(op_ILL)  CGE(op_ILL)   CGE(op_ILL)     CGE(op_ILL)   CGE(op_ILL)  CGE(op_ILL)
860 
861     CGE(op_ILL)  CGE(op_BCOND) CGE(op_J)    CGE(op_JAL)   CGE(op_BEQ)  CGE(op_BNE) CGE(op_BLEZ) CGE(op_BGTZ)
862     CGE(op_ADDI) CGE(op_ADDIU) CGE(op_SLTI) CGE(op_SLTIU) CGE(op_ANDI) CGE(op_ORI) CGE(op_XORI) CGE(op_LUI)
863     CGE(op_COP0) CGE(op_COP13) CGE(op_COP2) CGE(op_COP13) CGE(op_ILL)  CGE(op_ILL) CGE(op_ILL)  CGE(op_ILL)
864     CGE(op_ILL)  CGE(op_ILL)   CGE(op_ILL)  CGE(op_ILL)   CGE(op_ILL)  CGE(op_ILL) CGE(op_ILL)  CGE(op_ILL)
865     CGE(op_LB)   CGE(op_LH)    CGE(op_LWL)  CGE(op_LW)    CGE(op_LBU)  CGE(op_LHU) CGE(op_LWR)  CGE(op_ILL)
866     CGE(op_SB)   CGE(op_SH)    CGE(op_SWL)  CGE(op_SW)    CGE(op_ILL)  CGE(op_ILL) CGE(op_SWR)  CGE(op_ILL)
867     CGE(op_LWC013) CGE(op_LWC013)  CGE(op_LWC2) CGE(op_LWC013)  CGE(op_ILL)  CGE(op_ILL) CGE(op_ILL)  CGE(op_ILL)
868     CGE(op_SWC013) CGE(op_SWC013)  CGE(op_SWC2) CGE(op_SWC013)  CGE(op_ILL)  CGE(op_ILL) CGE(op_ILL)  CGE(op_ILL)
869 
870     // Interrupt portion of this table is constructed so that an interrupt won't be taken when the PC is pointing to a GTE instruction,
871     // to avoid problems caused by pipeline vs coprocessor nuances that aren't emulated.
872     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
873     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
874     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
875     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
876     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
877     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
878     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
879     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
880 
881     CGE(op_ILL)       CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
882     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
883     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_COP2)      CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
884     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
885     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
886     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
887     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
888     CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
889    CGEND
890 
891    {
892     BEGIN_OPF(ILL);
893 	     DO_LDS();
894 	     new_PC = Exception(EXCEPTION_RI, PC, new_PC, instr);
895     END_OPF;
896 
897     //
898     // ADD - Add Word
899     //
900     BEGIN_OPF(ADD);
901 	RTYPE;
902 
903 	GPR_DEPRES_BEGIN
904 	GPR_DEP(rs);
905 	GPR_DEP(rt);
906  	GPR_RES(rd);
907 	GPR_DEPRES_END
908 
909 	uint32 result = GPR[rs] + GPR[rt];
910 	bool ep = ((~(GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000;
911 
912 	if (PGXP_GetModes() & PGXP_MODE_CPU)
913 		PGXP_CPU_ADD(instr, result, GPR[rs], GPR[rt]);
914 
915 	DO_LDS();
916 
917 	if(MDFN_UNLIKELY(ep))
918 	{
919 	 new_PC = Exception(EXCEPTION_OV, PC, new_PC, instr);
920 	}
921 	else
922 	 GPR[rd] = result;
923 
924     END_OPF;
925 
926     //
927     // ADDI - Add Immediate Word
928     //
929     BEGIN_OPF(ADDI);
930 	ITYPE;
931 
932 	GPR_DEPRES_BEGIN
933 	GPR_DEP(rs);
934 	GPR_RES(rt);
935 	GPR_DEPRES_END
936 
937         uint32 result = GPR[rs] + immediate;
938 	bool ep = ((~(GPR[rs] ^ immediate)) & (GPR[rs] ^ result)) & 0x80000000;
939 
940 	if (PGXP_GetModes() & PGXP_MODE_CPU)
941 		PGXP_CPU_ADDI(instr, result, GPR[rs]);
942 
943 	DO_LDS();
944 
945         if(MDFN_UNLIKELY(ep))
946 	{
947 	 new_PC = Exception(EXCEPTION_OV, PC, new_PC, instr);
948 	}
949         else
950          GPR[rt] = result;
951 
952     END_OPF;
953 
954     //
955     // ADDIU - Add Immediate Unsigned Word
956     //
957     BEGIN_OPF(ADDIU);
958 	ITYPE;
959 
960 	GPR_DEPRES_BEGIN
961 	GPR_DEP(rs);
962 	GPR_RES(rt);
963 	GPR_DEPRES_END
964 
965 	uint32 result = GPR[rs] + immediate;
966 
967 	if (PGXP_GetModes() & PGXP_MODE_CPU)
968 		PGXP_CPU_ADDIU(instr, result, GPR[rs]);
969 
970 	DO_LDS();
971 
972 	GPR[rt] = result;
973 
974     END_OPF;
975 
976     //
977     // ADDU - Add Unsigned Word
978     //
979     BEGIN_OPF(ADDU);
980 	RTYPE;
981 
982 	GPR_DEPRES_BEGIN
983 	GPR_DEP(rs);
984 	GPR_DEP(rt);
985  	GPR_RES(rd);
986 	GPR_DEPRES_END
987 
988 	uint32 result = GPR[rs] + GPR[rt];
989 
990 	if (PGXP_GetModes() & PGXP_MODE_CPU)
991 		PGXP_CPU_ADDU(instr, result, GPR[rs], GPR[rt]);
992 
993 	DO_LDS();
994 
995 	GPR[rd] = result;
996 
997     END_OPF;
998 
999     //
1000     // AND - And
1001     //
1002     BEGIN_OPF(AND);
1003 	RTYPE;
1004 
1005 	GPR_DEPRES_BEGIN
1006 	GPR_DEP(rs);
1007 	GPR_DEP(rt);
1008  	GPR_RES(rd);
1009 	GPR_DEPRES_END
1010 
1011 	uint32 result = GPR[rs] & GPR[rt];
1012 
1013 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1014 		PGXP_CPU_AND(instr, result, GPR[rs], GPR[rt]);
1015 
1016 	DO_LDS();
1017 
1018 	GPR[rd] = result;
1019 
1020     END_OPF;
1021 
1022     //
1023     // ANDI - And Immediate
1024     //
1025     BEGIN_OPF(ANDI);
1026 	ITYPE_ZE;
1027 
1028 	GPR_DEPRES_BEGIN
1029 	GPR_DEP(rs);
1030 	GPR_RES(rt);
1031 	GPR_DEPRES_END
1032 
1033 	uint32 result = GPR[rs] & immediate;
1034 
1035 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1036 		PGXP_CPU_ANDI(instr, result, GPR[rs]);
1037 
1038 	DO_LDS();
1039 
1040 	GPR[rt] = result;
1041 
1042     END_OPF;
1043 
1044     //
1045     // BEQ - Branch on Equal
1046     //
1047     BEGIN_OPF(BEQ);
1048 	ITYPE;
1049 
1050 	GPR_DEPRES_BEGIN
1051 	GPR_DEP(rs);
1052 	GPR_DEP(rt);
1053 	GPR_DEPRES_END
1054 
1055 	const bool result = (GPR[rs] == GPR[rt]);
1056 
1057 	DO_LDS();
1058 
1059 	DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1060     END_OPF;
1061 
1062     // Bah, why does MIPS encoding have to be funky like this. :(
1063     // Handles BGEZ, BGEZAL, BLTZ, BLTZAL
1064     BEGIN_OPF(BCOND);
1065 	const uint32 tv = GPR[(instr >> 21) & 0x1F];
1066 	const uint32 riv = (instr >> 16) & 0x1F;
1067 	const uint32 immediate = (int32)(int16)(instr & 0xFFFF);
1068 	const bool result = (int32)(tv ^ (riv << 31)) < 0;
1069 	const uint32 link = ((riv & 0x1E) == 0x10) ? 31 : 0;
1070 
1071 	GPR_DEPRES_BEGIN
1072 	GPR_DEP((instr >> 21) & 0x1F);
1073 	GPR_RES(link);
1074 	GPR_DEPRES_END
1075 
1076 	DO_LDS();
1077 
1078 	DO_BRANCH(result, (immediate << 2), ~0U, true, link);
1079     END_OPF;
1080 
1081 
1082     //
1083     // BGTZ - Branch on Greater than Zero
1084     //
1085     BEGIN_OPF(BGTZ);
1086 	ITYPE;
1087 
1088 	GPR_DEPRES_BEGIN
1089 	GPR_DEP(rs);
1090 	GPR_DEPRES_END
1091 
1092 	const bool result = (int32)GPR[rs] > 0;
1093 
1094 	DO_LDS();
1095 
1096 	DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1097     END_OPF;
1098 
1099     //
1100     // BLEZ - Branch on Less Than or Equal to Zero
1101     //
1102     BEGIN_OPF(BLEZ);
1103 	ITYPE;
1104 
1105 	GPR_DEPRES_BEGIN
1106 	GPR_DEP(rs);
1107 	GPR_DEPRES_END
1108 
1109 	const bool result = (int32)GPR[rs] <= 0;
1110 
1111 	DO_LDS();
1112 
1113 	DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1114     END_OPF;
1115 
1116     //
1117     // BNE - Branch on Not Equal
1118     //
1119     BEGIN_OPF(BNE);
1120 	ITYPE;
1121 
1122 	GPR_DEPRES_BEGIN
1123 	GPR_DEP(rs);
1124 	GPR_DEP(rt);
1125 	GPR_DEPRES_END
1126 
1127 	const bool result = GPR[rs] != GPR[rt];
1128 
1129 	DO_LDS();
1130 
1131 	DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1132     END_OPF;
1133 
1134     //
1135     // BREAK - Breakpoint
1136     //
1137     BEGIN_OPF(BREAK);
1138 	DO_LDS();
1139 	new_PC = Exception(EXCEPTION_BP, PC, new_PC, instr);
1140     END_OPF;
1141 
1142     // Cop "instructions":	CFCz(no CP0), COPz, CTCz(no CP0), LWCz(no CP0), MFCz, MTCz, SWCz(no CP0)
1143     //
1144     // COP0 instructions
1145     //
1146     BEGIN_OPF(COP0);
1147 	const uint32 sub_op = (instr >> 21) & 0x1F;
1148 	const uint32 rt = (instr >> 16) & 0x1F;
1149 	const uint32 rd = (instr >> 11) & 0x1F;
1150 	const uint32 val = GPR[rt];
1151 
1152 	switch(sub_op)
1153 	{
1154 	 default:
1155 		DO_LDS();
1156 		break;
1157 
1158 	 case 0x02:
1159 	 case 0x06:
1160 		DO_LDS();
1161 		new_PC = Exception(EXCEPTION_RI, PC, new_PC, instr);
1162 		break;
1163 
1164 	 case 0x00:		// MFC0	- Move from Coprocessor
1165 		switch(rd)
1166 		{
1167 		 case 0x00:
1168 		 case 0x01:
1169 		 case 0x02:
1170 		 case 0x04:
1171 		 case 0x0A:
1172 			DO_LDS();
1173 		  	new_PC = Exception(EXCEPTION_RI, PC, new_PC, instr);
1174 			break;
1175 
1176 		 case 0x03:
1177 		 case 0x05:
1178 		 case 0x06:
1179 		 case 0x07:
1180 		 case 0x08:
1181 		 case 0x09:
1182 		 case 0x0B:
1183 		 case 0x0C:
1184 		 case 0x0D:
1185 		 case 0x0E:
1186 		 case 0x0F:
1187 			if(MDFN_UNLIKELY(LDWhich == rt))
1188 		 	 LDWhich = 0;
1189 
1190 			DO_LDS();
1191 
1192 			LDAbsorb = 0;
1193 			LDWhich = rt;
1194 			LDValue = CP0.Regs[rd];
1195 			break;
1196 
1197 		 default:
1198 			// Tested to be rather NOPish
1199 			DO_LDS();
1200 			PSX_DBG(PSX_DBG_WARNING, "[CPU] MFC0 from unmapped CP0 register %u.\n", rd);
1201 			break;
1202 		}
1203 		break;
1204 
1205 	 case 0x04:		// MTC0	- Move to Coprocessor
1206 		DO_LDS();
1207 		switch(rd)
1208 		{
1209 		 case 0x00:
1210 		 case 0x01:
1211 		 case 0x02:
1212 		 case 0x04:
1213 		 case 0x0A:
1214 			new_PC = Exception(EXCEPTION_RI, PC, new_PC, instr);
1215 			break;
1216 
1217 		 case CP0REG_BPC:
1218 			CP0.BPC = val;
1219 			break;
1220 
1221 		 case CP0REG_BDA:
1222 			CP0.BDA = val;
1223 			break;
1224 
1225 		 case CP0REG_DCIC:
1226 #ifdef DEBUG
1227 			if(val)
1228 			{
1229 			 PSX_DBG(PSX_DBG_WARNING, "[CPU] Non-zero write to DCIC: 0x%08x\n", val);
1230 			}
1231 #endif
1232 			CP0.DCIC = val & 0xFF80003F;
1233 			break;
1234 
1235   		 case CP0REG_BDAM:
1236 			CP0.BDAM = val;
1237 			break;
1238 
1239   		 case CP0REG_BPCM:
1240 			CP0.BPCM = val;
1241 			break;
1242 
1243 		 case CP0REG_CAUSE:
1244 			CP0.CAUSE &= ~(0x3 << 8);
1245 			CP0.CAUSE |= val & (0x3 << 8);
1246 			RecalcIPCache();
1247 			break;
1248 
1249 		 case CP0REG_SR:
1250 			CP0.SR = val & ~( (0x3 << 26) | (0x3 << 23) | (0x3 << 6));
1251 			RecalcIPCache();
1252 			break;
1253 		}
1254 		break;
1255 
1256 	 case 0x08:	// BC
1257 	 case 0x0C:
1258 		DO_LDS();
1259 		{
1260 		 const uint32 immediate = (int32)(int16)(instr & 0xFFFF);
1261 		 const bool result = (false == (bool)(instr & (1U << 16)));
1262 
1263 #ifdef DEBUG
1264 		 PSX_DBG(PSX_DBG_WARNING, "[CPU] BC0x instruction(0x%08x) @ PC=0x%08x\n", instr, PC);
1265 #endif
1266 
1267 		 DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1268 		}
1269 		break;
1270 
1271 	 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1272 	 case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1273 		DO_LDS();
1274 		{
1275 		 const uint32 cp0_op = instr & 0x1F;	// Not 0x3F
1276 
1277 		 if(MDFN_LIKELY(cp0_op == 0x10))	// RFE
1278 		 {
1279 		  // "Pop"
1280 		  CP0.SR = (CP0.SR & ~0x0F) | ((CP0.SR >> 2) & 0x0F);
1281 		  RecalcIPCache();
1282 		 }
1283 		 else if(cp0_op == 0x01 || cp0_op == 0x02 || cp0_op == 0x06 || cp0_op == 0x08)	// TLBR, TLBWI, TLBWR, TLBP
1284 		 {
1285 		  new_PC = Exception(EXCEPTION_RI, PC, new_PC, instr);
1286 		 }
1287 		}
1288 		break;
1289 	}
1290     END_OPF;
1291 
1292     //
1293     // COP2
1294     //
1295     BEGIN_OPF(COP2);
1296 	const uint32 sub_op = (instr >> 21) & 0x1F;
1297 	const uint32 rt = (instr >> 16) & 0x1F;
1298 	const uint32 rd = (instr >> 11) & 0x1F;
1299 	const uint32 val = GPR[rt];
1300 
1301 	if(MDFN_UNLIKELY(!(CP0.SR & (1U << (28 + 2)))))
1302 	{
1303 	 DO_LDS();
1304          new_PC = Exception(EXCEPTION_COPU, PC, new_PC, instr);
1305 	}
1306 	else switch(sub_op)
1307 	{
1308 	 default:
1309 		DO_LDS();
1310 		break;
1311 
1312 	 case 0x00:		// MFC2	- Move from Coprocessor
1313 		if(MDFN_UNLIKELY(LDWhich == rt))
1314 		 LDWhich = 0;
1315 
1316 		DO_LDS();
1317 
1318 	        if(timestamp < gte_ts_done)
1319 		{
1320 		 LDAbsorb = gte_ts_done - timestamp;
1321 	         timestamp = gte_ts_done;
1322 		}
1323 		else
1324 		 LDAbsorb = 0;
1325 
1326 		LDWhich = rt;
1327 		LDValue = GTE_ReadDR(rd);
1328 
1329                 if (PGXP_GetModes() & PGXP_MODE_GTE)
1330                    PGXP_GTE_MFC2(instr, LDValue, LDValue);
1331 
1332 		break;
1333 
1334 	 case 0x04:		// MTC2	- Move to Coprocessor
1335 		DO_LDS();
1336 
1337 	        if(timestamp < gte_ts_done)
1338 	         timestamp = gte_ts_done;
1339 
1340 		GTE_WriteDR(rd, val);
1341 
1342                 if (PGXP_GetModes() & PGXP_MODE_GTE)
1343                    PGXP_GTE_MTC2(instr, val, val);
1344 
1345 		break;
1346 
1347 	 case 0x02:		// CFC2
1348 		if(MDFN_UNLIKELY(LDWhich == rt))
1349 		 LDWhich = 0;
1350 
1351 		DO_LDS();
1352 
1353 	        if(timestamp < gte_ts_done)
1354 		{
1355 		 LDAbsorb = gte_ts_done - timestamp;
1356 	         timestamp = gte_ts_done;
1357 		}
1358 		else
1359 		 LDAbsorb = 0;
1360 
1361 		LDWhich = rt;
1362 		LDValue = GTE_ReadCR(rd);
1363 
1364                 if (PGXP_GetModes() & PGXP_MODE_GTE)
1365                    PGXP_GTE_CFC2(instr, LDValue, LDValue);
1366 
1367 		break;
1368 
1369 	 case 0x06:		// CTC2
1370 		DO_LDS();
1371 
1372  	        if(timestamp < gte_ts_done)
1373 	         timestamp = gte_ts_done;
1374 
1375 		GTE_WriteCR(rd, val);
1376 
1377                 if (PGXP_GetModes() & PGXP_MODE_GTE)
1378                    PGXP_GTE_CTC2(instr, val, val);
1379 
1380 		break;
1381 
1382 	 case 0x08:
1383 	 case 0x0C:
1384 		DO_LDS();
1385 		{
1386 		 const uint32 immediate = (int32)(int16)(instr & 0xFFFF);
1387 		 const bool result = (false == (bool)(instr & (1U << 16)));
1388 
1389 #ifdef DEBUG
1390 		 PSX_DBG(PSX_DBG_WARNING, "[CPU] BC2x instruction(0x%08x) @ PC=0x%08x\n", instr, PC);
1391 #endif
1392 
1393 		 DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1394 		}
1395 		break;
1396 
1397 	 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1398 	 case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1399 		DO_LDS();
1400 
1401 	        if(timestamp < gte_ts_done)
1402 	         timestamp = gte_ts_done;
1403 		gte_ts_done = timestamp + GTE_Instruction(instr);
1404 		break;
1405 	}
1406     END_OPF;
1407 
1408     //
1409     // COP1, COP3
1410     //
1411     BEGIN_OPF(COP13);
1412 	DO_LDS();
1413 
1414 	if(!(CP0.SR & (1U << (28 + ((instr >> 26) & 0x3)))))
1415 	{
1416          new_PC = Exception(EXCEPTION_COPU, PC, new_PC, instr);
1417 	}
1418 	else
1419 	{
1420 	 const uint32 sub_op = (instr >> 21) & 0x1F;
1421 
1422 #ifdef DEBUG
1423 	 PSX_DBG(PSX_DBG_WARNING, "[CPU] COP%u instruction(0x%08x) @ PC=0x%08x\n", (instr >> 26) & 0x3, instr, PC);
1424 #endif
1425 
1426 	 if(sub_op == 0x08 || sub_op == 0x0C)
1427 	 {
1428 	  const uint32 immediate = (int32)(int16)(instr & 0xFFFF);
1429 	  const bool result = (false == (bool)(instr & (1U << 16)));
1430 
1431 	  DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1432 	 }
1433 	}
1434     END_OPF;
1435 
1436     //
1437     // LWC0, LWC1, LWC3
1438     //
1439     BEGIN_OPF(LWC013);
1440         ITYPE;
1441 	const uint32 address = GPR[rs] + immediate;
1442 
1443 	DO_LDS();
1444 
1445 	if(!(CP0.SR & (1U << (28 + ((instr >> 26) & 0x3)))))
1446 	{
1447          new_PC = Exception(EXCEPTION_COPU, PC, new_PC, instr);
1448 	}
1449 	else
1450 	{
1451 	 if(MDFN_UNLIKELY(address & 3))
1452 	 {
1453 	  CP0.BADA = address;
1454           new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, instr);
1455 	 }
1456          else
1457 	 {
1458 #ifdef DEBUG
1459 	  PSX_DBG(PSX_DBG_WARNING, "[CPU] LWC%u instruction(0x%08x) @ PC=0x%08x\n", (instr >> 26) & 0x3, instr, PC);
1460 #endif
1461 
1462           ReadMemory<uint32>(timestamp, address, false, true);
1463 	 }
1464 	}
1465     END_OPF;
1466 
1467     //
1468     // LWC2
1469     //
1470     BEGIN_OPF(LWC2);
1471         ITYPE;
1472 	const uint32 address = GPR[rs] + immediate;
1473 
1474 	DO_LDS();
1475 
1476         if(MDFN_UNLIKELY(address & 3))
1477 	{
1478 	 CP0.BADA = address;
1479          new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, instr);
1480 	}
1481         else
1482 	{
1483          if(timestamp < gte_ts_done)
1484           timestamp = gte_ts_done;
1485 
1486          uint32_t value = ReadMemory<uint32>(timestamp, address, false, true);
1487          GTE_WriteDR(rt, value);
1488 
1489          if (PGXP_GetModes() & PGXP_MODE_GTE)
1490             PGXP_GTE_LWC2(instr, value, address);
1491 
1492 	}
1493 	// GTE stuff here
1494     END_OPF;
1495 
1496     //
1497     // SWC0, SWC1, SCW3
1498     //
1499     BEGIN_OPF(SWC013);
1500         ITYPE;
1501 	const uint32 address = GPR[rs] + immediate;
1502 
1503 	DO_LDS();
1504 
1505 	if(!(CP0.SR & (1U << (28 + ((instr >> 26) & 0x3)))))
1506 	{
1507          new_PC = Exception(EXCEPTION_COPU, PC, new_PC, instr);
1508 	}
1509 	else
1510 	{
1511 	 if(MDFN_UNLIKELY(address & 0x3))
1512 	 {
1513 	  CP0.BADA = address;
1514 	  new_PC = Exception(EXCEPTION_ADES, PC, new_PC, instr);
1515 	 }
1516 #ifdef DEBUG
1517 	 else
1518 	 {
1519 	  PSX_DBG(PSX_DBG_WARNING, "[CPU] SWC%u instruction(0x%08x) @ PC=0x%08x\n", (instr >> 26) & 0x3, instr, PC);
1520 	  //WriteMemory<uint32>(timestamp, address, SOMETHING);
1521 	 }
1522 #endif
1523 	}
1524     END_OPF;
1525 
1526     //
1527     // SWC2
1528     //
1529     BEGIN_OPF(SWC2);
1530         ITYPE;
1531 	const uint32 address = GPR[rs] + immediate;
1532 
1533 	if(MDFN_UNLIKELY(address & 0x3))
1534 	{
1535 	 CP0.BADA = address;
1536 	 new_PC = Exception(EXCEPTION_ADES, PC, new_PC, instr);
1537 	}
1538 	else
1539 	{
1540          if(timestamp < gte_ts_done)
1541           timestamp = gte_ts_done;
1542 
1543 	 WriteMemory<uint32>(timestamp, address, GTE_ReadDR(rt));
1544 
1545 	 if (PGXP_GetModes() & PGXP_MODE_GTE)
1546             PGXP_GTE_SWC2(instr, GTE_ReadDR(rt), address);
1547 	}
1548 	DO_LDS();
1549     END_OPF;
1550 
1551     //
1552     // DIV - Divide Word
1553     //
1554     BEGIN_OPF(DIV);
1555 	RTYPE;
1556 
1557 	GPR_DEPRES_BEGIN
1558 	GPR_DEP(rs);
1559 	GPR_DEP(rt);
1560 	GPR_DEPRES_END
1561 
1562         if(!GPR[rt])
1563         {
1564 	 if(GPR[rs] & 0x80000000)
1565 	  LO = 1;
1566 	 else
1567 	  LO = 0xFFFFFFFF;
1568 
1569 	 HI = GPR[rs];
1570         }
1571 	else if(GPR[rs] == 0x80000000 && GPR[rt] == 0xFFFFFFFF)
1572 	{
1573 	 LO = 0x80000000;
1574 	 HI = 0;
1575 	}
1576         else
1577         {
1578          LO = (int32)GPR[rs] / (int32)GPR[rt];
1579          HI = (int32)GPR[rs] % (int32)GPR[rt];
1580         }
1581 	muldiv_ts_done = timestamp + 37;
1582 
1583 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1584 		PGXP_CPU_DIV(instr, HI, LO, GPR[rs], GPR[rt]);
1585 	DO_LDS();
1586 
1587     END_OPF;
1588 
1589 
1590     //
1591     // DIVU - Divide Unsigned Word
1592     //
1593     BEGIN_OPF(DIVU);
1594 	RTYPE;
1595 
1596 	GPR_DEPRES_BEGIN
1597 	GPR_DEP(rs);
1598 	GPR_DEP(rt);
1599 	GPR_DEPRES_END
1600 
1601 	if(!GPR[rt])
1602 	{
1603 	 LO = 0xFFFFFFFF;
1604 	 HI = GPR[rs];
1605 	}
1606 	else
1607 	{
1608 	 LO = GPR[rs] / GPR[rt];
1609 	 HI = GPR[rs] % GPR[rt];
1610 	}
1611  	muldiv_ts_done = timestamp + 37;
1612 
1613 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1614 		PGXP_CPU_DIVU(instr, HI, LO, GPR[rs], GPR[rt]);
1615 
1616 	DO_LDS();
1617     END_OPF;
1618 
1619     //
1620     // J - Jump
1621     //
1622     BEGIN_OPF(J);
1623 	JTYPE;
1624 
1625 	DO_LDS();
1626 
1627 	DO_BRANCH(true, target << 2, 0xF0000000, false, 0);
1628     END_OPF;
1629 
1630     //
1631     // JAL - Jump and Link
1632     //
1633     BEGIN_OPF(JAL);
1634 	JTYPE;
1635 
1636 	//GPR_DEPRES_BEGIN
1637 	GPR_RES(31);
1638 	//GPR_DEPRES_END
1639 
1640 	DO_LDS();
1641 
1642 	DO_BRANCH(true, target << 2, 0xF0000000, true, 31);
1643     END_OPF;
1644 
1645     //
1646     // JALR - Jump and Link Register
1647     //
1648     BEGIN_OPF(JALR);
1649 	RTYPE;
1650 
1651 	GPR_DEPRES_BEGIN
1652 	GPR_DEP(rs);
1653  	GPR_RES(rd);
1654 	GPR_DEPRES_END
1655 
1656 	uint32 tmp = GPR[rs];
1657 
1658 	DO_LDS();
1659 
1660 	DO_BRANCH(true, tmp, 0, true, rd);
1661     END_OPF;
1662 
1663     //
1664     // JR - Jump Register
1665     //
1666     BEGIN_OPF(JR);
1667 	RTYPE;
1668 
1669 	GPR_DEPRES_BEGIN
1670 	GPR_DEP(rs);
1671  	GPR_RES(rd);
1672 	GPR_DEPRES_END
1673 
1674 	uint32 bt = GPR[rs];
1675 
1676 	DO_LDS();
1677 
1678 	DO_BRANCH(true, bt, 0, false, 0);
1679     END_OPF;
1680 
1681     //
1682     // LUI - Load Upper Immediate
1683     //
1684     BEGIN_OPF(LUI);
1685 	ITYPE_ZE;		// Actually, probably would be sign-extending...if we were emulating a 64-bit MIPS chip :b
1686 
1687 	GPR_DEPRES_BEGIN
1688 	GPR_RES(rt);
1689 	GPR_DEPRES_END
1690 
1691 	DO_LDS();
1692 
1693 	GPR[rt] = immediate << 16;
1694 
1695 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1696 		PGXP_CPU_LUI(instr, GPR[rt]);
1697 
1698     END_OPF;
1699 
1700     //
1701     // MFHI - Move from HI
1702     //
1703     BEGIN_OPF(MFHI);
1704 	RTYPE;
1705 
1706 	GPR_DEPRES_BEGIN
1707  	GPR_RES(rd);
1708 	GPR_DEPRES_END
1709 
1710 	DO_LDS();
1711 
1712 	if(timestamp < muldiv_ts_done)
1713 	{
1714 	 if(timestamp == muldiv_ts_done - 1)
1715 	  muldiv_ts_done--;
1716 	 else
1717 	 {
1718 	  do
1719 	  {
1720 	   if(ReadAbsorb[ReadAbsorbWhich])
1721 	    ReadAbsorb[ReadAbsorbWhich]--;
1722 	   timestamp++;
1723 	  } while(timestamp < muldiv_ts_done);
1724 	 }
1725 	}
1726 
1727 	GPR[rd] = HI;
1728 
1729 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1730 		PGXP_CPU_MFHI(instr, GPR[rd], HI);
1731 
1732     END_OPF;
1733 
1734 
1735     //
1736     // MFLO - Move from LO
1737     //
1738     BEGIN_OPF(MFLO);
1739 	RTYPE;
1740 
1741 	GPR_DEPRES_BEGIN
1742  	GPR_RES(rd);
1743 	GPR_DEPRES_END
1744 
1745 	DO_LDS();
1746 
1747 	if(timestamp < muldiv_ts_done)
1748 	{
1749 	 if(timestamp == muldiv_ts_done - 1)
1750 	  muldiv_ts_done--;
1751 	 else
1752 	 {
1753 	  do
1754 	  {
1755 	   if(ReadAbsorb[ReadAbsorbWhich])
1756 	    ReadAbsorb[ReadAbsorbWhich]--;
1757 	   timestamp++;
1758 	  } while(timestamp < muldiv_ts_done);
1759 	 }
1760 	}
1761 
1762 	GPR[rd] = LO;
1763 
1764 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1765 		PGXP_CPU_MFLO(instr, GPR[rd], LO);
1766 
1767     END_OPF;
1768 
1769 
1770     //
1771     // MTHI - Move to HI
1772     //
1773     BEGIN_OPF(MTHI);
1774 	RTYPE;
1775 
1776 	GPR_DEPRES_BEGIN
1777 	GPR_DEP(rs);
1778 	GPR_DEPRES_END
1779 
1780 	HI = GPR[rs];
1781 
1782 	DO_LDS();
1783 
1784 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1785 		PGXP_CPU_MTHI(instr, HI, GPR[rs]);
1786 
1787     END_OPF;
1788 
1789     //
1790     // MTLO - Move to LO
1791     //
1792     BEGIN_OPF(MTLO);
1793 	RTYPE;
1794 
1795 	GPR_DEPRES_BEGIN
1796 	GPR_DEP(rs);
1797 	GPR_DEPRES_END
1798 
1799 	LO = GPR[rs];
1800 
1801 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1802 		PGXP_CPU_MTLO(instr, LO, GPR[rs]);
1803 
1804 	DO_LDS();
1805 
1806     END_OPF;
1807 
1808 
1809     //
1810     // MULT - Multiply Word
1811     //
1812     BEGIN_OPF(MULT);
1813 	RTYPE;
1814 
1815 	GPR_DEPRES_BEGIN
1816 	GPR_DEP(rs);
1817 	GPR_DEP(rt);
1818 	GPR_DEPRES_END
1819 
1820 	uint64 result;
1821 
1822 	result = (int64)(int32)GPR[rs] * (int32)GPR[rt];
1823 	muldiv_ts_done = timestamp + MULT_Tab24[MDFN_lzcount32((GPR[rs] ^ ((int32)GPR[rs] >> 31)) | 0x400)];
1824 	DO_LDS();
1825 
1826 	LO = result;
1827 	HI = result >> 32;
1828 
1829 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1830 		PGXP_CPU_MULT(instr, HI, LO, GPR[rs], GPR[rt]);
1831 
1832     END_OPF;
1833 
1834     //
1835     // MULTU - Multiply Unsigned Word
1836     //
1837     BEGIN_OPF(MULTU);
1838 	RTYPE;
1839 
1840 	GPR_DEPRES_BEGIN
1841 	GPR_DEP(rs);
1842 	GPR_DEP(rt);
1843 	GPR_DEPRES_END
1844 
1845 	uint64 result;
1846 
1847 	result = (uint64)GPR[rs] * GPR[rt];
1848 	muldiv_ts_done = timestamp + MULT_Tab24[MDFN_lzcount32(GPR[rs] | 0x400)];
1849 	DO_LDS();
1850 
1851 	LO = result;
1852 	HI = result >> 32;
1853 
1854 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1855 		PGXP_CPU_MULTU(instr, HI, LO, GPR[rs], GPR[rt]);
1856 
1857     END_OPF;
1858 
1859 
1860     //
1861     // NOR - NOR
1862     //
1863     BEGIN_OPF(NOR);
1864 	RTYPE;
1865 
1866 	GPR_DEPRES_BEGIN
1867 	GPR_DEP(rs);
1868 	GPR_DEP(rt);
1869  	GPR_RES(rd);
1870 	GPR_DEPRES_END
1871 
1872 	uint32 result = ~(GPR[rs] | GPR[rt]);
1873 
1874 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1875 		PGXP_CPU_NOR(instr, result, GPR[rs], GPR[rt]);
1876 
1877 	DO_LDS();
1878 
1879 	GPR[rd] = result;
1880 
1881     END_OPF;
1882 
1883     //
1884     // OR - OR
1885     //
1886     BEGIN_OPF(OR);
1887 	RTYPE;
1888 
1889 	GPR_DEPRES_BEGIN
1890 	GPR_DEP(rs);
1891 	GPR_DEP(rt);
1892  	GPR_RES(rd);
1893 	GPR_DEPRES_END
1894 
1895 	uint32 result = GPR[rs] | GPR[rt];
1896 
1897 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1898 		PGXP_CPU_OR(instr, result, GPR[rs], GPR[rt]);
1899 
1900 	DO_LDS();
1901 
1902 	GPR[rd] = result;
1903 
1904     END_OPF;
1905 
1906 
1907     //
1908     // ORI - OR Immediate
1909     //
1910     BEGIN_OPF(ORI);
1911 	ITYPE_ZE;
1912 
1913 	GPR_DEPRES_BEGIN
1914 	GPR_DEP(rs);
1915 	GPR_RES(rt);
1916 	GPR_DEPRES_END
1917 
1918 	uint32 result = GPR[rs] | immediate;
1919 
1920 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1921 		PGXP_CPU_ORI(instr, result, GPR[rs]);
1922 
1923 	DO_LDS();
1924 
1925 	GPR[rt] = result;
1926 
1927     END_OPF;
1928 
1929 
1930     //
1931     // SLL - Shift Word Left Logical
1932     //
1933     BEGIN_OPF(SLL);	// SLL
1934 	RTYPE;
1935 
1936 	GPR_DEPRES_BEGIN
1937 	GPR_DEP(rt);
1938  	GPR_RES(rd);
1939 	GPR_DEPRES_END
1940 
1941 	uint32 result = GPR[rt] << shamt;
1942 
1943 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1944 		PGXP_CPU_SLL(instr, result, GPR[rt]);
1945 
1946 	DO_LDS();
1947 
1948 	GPR[rd] = result;
1949 
1950     END_OPF;
1951 
1952 
1953     //
1954     // SLLV - Shift Word Left Logical Variable
1955     //
1956     BEGIN_OPF(SLLV);
1957 	RTYPE;
1958 
1959 	GPR_DEPRES_BEGIN
1960 	GPR_DEP(rs);
1961 	GPR_DEP(rt);
1962  	GPR_RES(rd);
1963 	GPR_DEPRES_END
1964 
1965 	uint32 result = GPR[rt] << (GPR[rs] & 0x1F);
1966 
1967 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1968 		PGXP_CPU_SLLV(instr, result, GPR[rt], GPR[rs]);
1969 
1970 	DO_LDS();
1971 
1972 	GPR[rd] = result;
1973 
1974     END_OPF;
1975 
1976     //
1977     // SLT - Set on Less Than
1978     //
1979     BEGIN_OPF(SLT);
1980 	RTYPE;
1981 
1982 	GPR_DEPRES_BEGIN
1983 	GPR_DEP(rs);
1984 	GPR_DEP(rt);
1985  	GPR_RES(rd);
1986 	GPR_DEPRES_END
1987 
1988 	uint32 result = (bool)((int32)GPR[rs] < (int32)GPR[rt]);
1989 
1990 	if (PGXP_GetModes() & PGXP_MODE_CPU)
1991 		PGXP_CPU_SLT(instr, result, GPR[rs], GPR[rt]);
1992 
1993 	DO_LDS();
1994 
1995 	GPR[rd] = result;
1996 
1997     END_OPF;
1998 
1999 
2000     //
2001     // SLTI - Set on Less Than Immediate
2002     //
2003     BEGIN_OPF(SLTI);
2004 	ITYPE;
2005 
2006 	GPR_DEPRES_BEGIN
2007 	GPR_DEP(rs);
2008 	GPR_RES(rt);
2009 	GPR_DEPRES_END
2010 
2011 	uint32 result = (bool)((int32)GPR[rs] < (int32)immediate);
2012 
2013 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2014 		PGXP_CPU_SLTI(instr, result, GPR[rs]);
2015 
2016 	DO_LDS();
2017 
2018 	GPR[rt] = result;
2019 
2020     END_OPF;
2021 
2022 
2023     //
2024     // SLTIU - Set on Less Than Immediate, Unsigned
2025     //
2026     BEGIN_OPF(SLTIU);
2027 	ITYPE;
2028 
2029 	GPR_DEPRES_BEGIN
2030 	GPR_DEP(rs);
2031 	GPR_RES(rt);
2032 	GPR_DEPRES_END
2033 
2034 	uint32 result = (bool)(GPR[rs] < (uint32)immediate);
2035 
2036 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2037 		PGXP_CPU_SLTIU(instr, result, GPR[rs]);
2038 
2039 	DO_LDS();
2040 
2041 	GPR[rt] = result;
2042 
2043     END_OPF;
2044 
2045 
2046     //
2047     // SLTU - Set on Less Than, Unsigned
2048     //
2049     BEGIN_OPF(SLTU);
2050 	RTYPE;
2051 
2052 	GPR_DEPRES_BEGIN
2053 	GPR_DEP(rs);
2054 	GPR_DEP(rt);
2055  	GPR_RES(rd);
2056 	GPR_DEPRES_END
2057 
2058 	uint32 result = (bool)(GPR[rs] < GPR[rt]);
2059 
2060 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2061 		PGXP_CPU_SLTU(instr, result, GPR[rs], GPR[rt]);
2062 
2063 	DO_LDS();
2064 
2065 	GPR[rd] = result;
2066 
2067     END_OPF;
2068 
2069 
2070     //
2071     // SRA - Shift Word Right Arithmetic
2072     //
2073     BEGIN_OPF(SRA);
2074 	RTYPE;
2075 
2076 	GPR_DEPRES_BEGIN
2077 	GPR_DEP(rt);
2078  	GPR_RES(rd);
2079 	GPR_DEPRES_END
2080 
2081 	uint32 result = ((int32)GPR[rt]) >> shamt;
2082 
2083 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2084 		PGXP_CPU_SRA(instr, result, GPR[rt]);
2085 
2086 	DO_LDS();
2087 
2088 	GPR[rd] = result;
2089 
2090     END_OPF;
2091 
2092 
2093     //
2094     // SRAV - Shift Word Right Arithmetic Variable
2095     //
2096     BEGIN_OPF(SRAV);
2097 	RTYPE;
2098 
2099 	GPR_DEPRES_BEGIN
2100 	GPR_DEP(rs);
2101 	GPR_DEP(rt);
2102  	GPR_RES(rd);
2103 	GPR_DEPRES_END
2104 
2105 	uint32 result = ((int32)GPR[rt]) >> (GPR[rs] & 0x1F);
2106 
2107 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2108 		PGXP_CPU_SRAV(instr, result, GPR[rt], GPR[rs]);
2109 
2110 	DO_LDS();
2111 
2112 	GPR[rd] = result;
2113 
2114     END_OPF;
2115 
2116 
2117     //
2118     // SRL - Shift Word Right Logical
2119     //
2120     BEGIN_OPF(SRL);
2121 	RTYPE;
2122 
2123 	GPR_DEPRES_BEGIN
2124 	GPR_DEP(rt);
2125  	GPR_RES(rd);
2126 	GPR_DEPRES_END
2127 
2128 	uint32 result = GPR[rt] >> shamt;
2129 
2130 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2131 		PGXP_CPU_SRL(instr, result, GPR[rt]);
2132 
2133 	DO_LDS();
2134 
2135 	GPR[rd] = result;
2136 
2137     END_OPF;
2138 
2139     //
2140     // SRLV - Shift Word Right Logical Variable
2141     //
2142     BEGIN_OPF(SRLV);
2143 	RTYPE;
2144 
2145 	GPR_DEPRES_BEGIN
2146 	GPR_DEP(rs);
2147 	GPR_DEP(rt);
2148  	GPR_RES(rd);
2149 	GPR_DEPRES_END
2150 
2151 	uint32 result = GPR[rt] >> (GPR[rs] & 0x1F);
2152 
2153 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2154 		PGXP_CPU_SRLV(instr, result, GPR[rt], GPR[rs]);
2155 
2156 	DO_LDS();
2157 
2158 	GPR[rd] = result;
2159 
2160     END_OPF;
2161 
2162 
2163     //
2164     // SUB - Subtract Word
2165     //
2166     BEGIN_OPF(SUB);
2167 	RTYPE;
2168 
2169 	GPR_DEPRES_BEGIN
2170 	GPR_DEP(rs);
2171 	GPR_DEP(rt);
2172  	GPR_RES(rd);
2173 	GPR_DEPRES_END
2174 
2175 	uint32 result = GPR[rs] - GPR[rt];
2176 	bool ep = (((GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000;
2177 
2178 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2179 		PGXP_CPU_SUB(instr, result, GPR[rs], GPR[rt]);
2180 
2181 	DO_LDS();
2182 
2183 	if(MDFN_UNLIKELY(ep))
2184 	{
2185 	 new_PC = Exception(EXCEPTION_OV, PC, new_PC, instr);
2186 	}
2187 	else
2188 	 GPR[rd] = result;
2189 
2190     END_OPF;
2191 
2192 
2193     //
2194     // SUBU - Subtract Unsigned Word
2195     //
2196     BEGIN_OPF(SUBU);
2197 	RTYPE;
2198 
2199 	GPR_DEPRES_BEGIN
2200 	GPR_DEP(rs);
2201 	GPR_DEP(rt);
2202  	GPR_RES(rd);
2203 	GPR_DEPRES_END
2204 
2205 	uint32 result = GPR[rs] - GPR[rt];
2206 
2207 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2208 		PGXP_CPU_SUBU(instr, result, GPR[rs], GPR[rt]);
2209 
2210 	DO_LDS();
2211 
2212 	GPR[rd] = result;
2213 
2214     END_OPF;
2215 
2216 
2217     //
2218     // SYSCALL
2219     //
2220     BEGIN_OPF(SYSCALL);
2221 	DO_LDS();
2222 
2223 	new_PC = Exception(EXCEPTION_SYSCALL, PC, new_PC, instr);
2224     END_OPF;
2225 
2226 
2227     //
2228     // XOR
2229     //
2230     BEGIN_OPF(XOR);
2231 	RTYPE;
2232 
2233 	GPR_DEPRES_BEGIN
2234 	GPR_DEP(rs);
2235 	GPR_DEP(rt);
2236  	GPR_RES(rd);
2237 	GPR_DEPRES_END
2238 
2239 	uint32 result = GPR[rs] ^ GPR[rt];
2240 
2241 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2242 		PGXP_CPU_XOR(instr, result, GPR[rs], GPR[rt]);
2243 
2244 	DO_LDS();
2245 
2246 	GPR[rd] = result;
2247 
2248     END_OPF;
2249 
2250     //
2251     // XORI - Exclusive OR Immediate
2252     //
2253     BEGIN_OPF(XORI);
2254 	ITYPE_ZE;
2255 
2256 	GPR_DEPRES_BEGIN
2257 	GPR_DEP(rs);
2258 	GPR_RES(rt);
2259 	GPR_DEPRES_END
2260 
2261 	uint32 result = GPR[rs] ^ immediate;
2262 
2263 	if (PGXP_GetModes() & PGXP_MODE_CPU)
2264 		PGXP_CPU_XORI(instr, result, GPR[rs]);
2265 
2266 	DO_LDS();
2267 
2268 	GPR[rt] = result;
2269     END_OPF;
2270 
2271     //
2272     // Memory access instructions(besides the coprocessor ones) follow:
2273     //
2274 
2275     //
2276     // LB - Load Byte
2277     //
2278     BEGIN_OPF(LB);
2279 	ITYPE;
2280 
2281 	GPR_DEPRES_BEGIN
2282 	GPR_DEP(rs);
2283 	GPR_DEPRES_END
2284 
2285 	uint32 address = GPR[rs] + immediate;
2286 
2287 	if(MDFN_UNLIKELY(LDWhich == rt))
2288 	 LDWhich = 0;
2289 
2290 	DO_LDS();
2291 
2292 	LDWhich = rt;
2293 	LDValue = (int32)ReadMemory<int8>(timestamp, address);
2294 
2295 	if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2296 		PGXP_CPU_LB(instr, LDValue, address);
2297     END_OPF;
2298 
2299     //
2300     // LBU - Load Byte Unsigned
2301     //
2302     BEGIN_OPF(LBU);
2303         ITYPE;
2304 
2305 	GPR_DEPRES_BEGIN
2306 	GPR_DEP(rs);
2307 	GPR_DEPRES_END
2308 
2309         uint32 address = GPR[rs] + immediate;
2310 
2311 	if(MDFN_UNLIKELY(LDWhich == rt))
2312 	 LDWhich = 0;
2313 
2314 	DO_LDS();
2315 
2316         LDWhich = rt;
2317 	LDValue = ReadMemory<uint8>(timestamp, address);
2318 
2319 	if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2320 		PGXP_CPU_LBU(instr, LDValue, address);
2321     END_OPF;
2322 
2323     //
2324     // LH - Load Halfword
2325     //
2326     BEGIN_OPF(LH);
2327         ITYPE;
2328 
2329 	GPR_DEPRES_BEGIN
2330 	GPR_DEP(rs);
2331 	GPR_DEPRES_END
2332 
2333         uint32 address = GPR[rs] + immediate;
2334 
2335 	if(MDFN_UNLIKELY(address & 1))
2336 	{
2337 	 DO_LDS();
2338 
2339 	 CP0.BADA = address;
2340 	 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, instr);
2341 	}
2342 	else
2343 	{
2344 	 if(MDFN_UNLIKELY(LDWhich == rt))
2345 	  LDWhich = 0;
2346 
2347 	 DO_LDS();
2348 
2349 	 LDWhich = rt;
2350          LDValue = (int32)ReadMemory<int16>(timestamp, address);
2351 	}
2352 	if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2353 		PGXP_CPU_LH(instr, LDValue, address);
2354     END_OPF;
2355 
2356     //
2357     // LHU - Load Halfword Unsigned
2358     //
2359     BEGIN_OPF(LHU);
2360         ITYPE;
2361 
2362 	GPR_DEPRES_BEGIN
2363 	GPR_DEP(rs);
2364 	GPR_DEPRES_END
2365 
2366         uint32 address = GPR[rs] + immediate;
2367 
2368         if(MDFN_UNLIKELY(address & 1))
2369 	{
2370 	 DO_LDS();
2371 
2372 	 CP0.BADA = address;
2373          new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, instr);
2374 	}
2375 	else
2376 	{
2377 	 if(MDFN_UNLIKELY(LDWhich == rt))
2378 	  LDWhich = 0;
2379 
2380 	 DO_LDS();
2381 
2382 	 LDWhich = rt;
2383          LDValue = ReadMemory<uint16>(timestamp, address);
2384 	}
2385 
2386 	if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2387 		PGXP_CPU_LHU(instr, LDValue, address);
2388     END_OPF;
2389 
2390 
2391     //
2392     // LW - Load Word
2393     //
2394     BEGIN_OPF(LW);
2395         ITYPE;
2396 
2397 	GPR_DEPRES_BEGIN
2398 	GPR_DEP(rs);
2399 	GPR_DEPRES_END
2400 
2401         uint32 address = GPR[rs] + immediate;
2402 
2403         if(MDFN_UNLIKELY(address & 3))
2404 	{
2405 	 DO_LDS();
2406 
2407 	 CP0.BADA = address;
2408          new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, instr);
2409 	}
2410         else
2411 	{
2412 	 if(MDFN_UNLIKELY(LDWhich == rt))
2413 	  LDWhich = 0;
2414 
2415 	 DO_LDS();
2416 
2417 	 LDWhich = rt;
2418          LDValue = ReadMemory<uint32>(timestamp, address);
2419 	}
2420 
2421 	if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2422 		PGXP_CPU_LW(instr, LDValue, address);
2423     END_OPF;
2424 
2425     //
2426     // SB - Store Byte
2427     //
2428     BEGIN_OPF(SB);
2429 	ITYPE;
2430 
2431 	GPR_DEPRES_BEGIN
2432 	GPR_DEP(rs);
2433 	GPR_DEP(rt);
2434 	GPR_DEPRES_END
2435 
2436 	uint32 address = GPR[rs] + immediate;
2437 
2438 	WriteMemory<uint8>(timestamp, address, GPR[rt]);
2439 
2440 	if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2441 		PGXP_CPU_SB(instr, GPR[rt], address);
2442 
2443 	DO_LDS();
2444     END_OPF;
2445 
2446     //
2447     // SH - Store Halfword
2448     //
2449     BEGIN_OPF(SH);
2450         ITYPE;
2451 
2452 	GPR_DEPRES_BEGIN
2453 	GPR_DEP(rs);
2454 	GPR_DEP(rt);
2455 	GPR_DEPRES_END
2456 
2457         uint32 address = GPR[rs] + immediate;
2458 
2459 	if(MDFN_UNLIKELY(address & 0x1))
2460 	{
2461 	 CP0.BADA = address;
2462 	 new_PC = Exception(EXCEPTION_ADES, PC, new_PC, instr);
2463 	}
2464 	else
2465 	 WriteMemory<uint16>(timestamp, address, GPR[rt]);
2466 
2467 	if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2468 		PGXP_CPU_SH(instr, GPR[rt], address);
2469 
2470 	DO_LDS();
2471     END_OPF;
2472 
2473     //
2474     // SW - Store Word
2475     //
2476     BEGIN_OPF(SW);
2477         ITYPE;
2478 
2479 	GPR_DEPRES_BEGIN
2480 	GPR_DEP(rs);
2481 	GPR_DEP(rt);
2482 	GPR_DEPRES_END
2483 
2484         uint32 address = GPR[rs] + immediate;
2485 
2486 	if(MDFN_UNLIKELY(address & 0x3))
2487 	{
2488 	 CP0.BADA = address;
2489 	 new_PC = Exception(EXCEPTION_ADES, PC, new_PC, instr);
2490 	}
2491 	else
2492 	 WriteMemory<uint32>(timestamp, address, GPR[rt]);
2493 
2494 	if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2495 		PGXP_CPU_SW(instr, GPR[rt], address);
2496 
2497 	DO_LDS();
2498     END_OPF;
2499 
2500     // LWL and LWR load delay slot tomfoolery appears to apply even to MFC0! (and probably MFCn and CFCn as well, though they weren't explicitly tested)
2501 
2502     //
2503     // LWL - Load Word Left
2504     //
2505     BEGIN_OPF(LWL);
2506 	ITYPE;
2507 
2508 	GPR_DEPRES_BEGIN
2509 	GPR_DEP(rs);
2510 	//GPR_DEP(rt);
2511 	GPR_DEPRES_END
2512 
2513 	uint32 address = GPR[rs] + immediate;
2514 	uint32 v = GPR[rt];
2515 
2516 	if(LDWhich == rt)
2517 	{
2518 	 v = LDValue;
2519 	 ReadFudge = 0;
2520 	}
2521 	else
2522 	{
2523 	 DO_LDS();
2524 	}
2525 
2526 	LDWhich = rt;
2527 	switch(address & 0x3)
2528 	{
2529 	 case 0: LDValue = (v & ~(0xFF << 24)) | (ReadMemory<uint8>(timestamp, address & ~3) << 24);
2530 		 break;
2531 
2532 	 case 1: LDValue = (v & ~(0xFFFF << 16)) | (ReadMemory<uint16>(timestamp, address & ~3) << 16);
2533 	         break;
2534 
2535 	 case 2: LDValue = (v & ~(0xFFFFFF << 8)) | (ReadMemory<uint32>(timestamp, address & ~3, true) << 8);
2536 		 break;
2537 
2538 	 case 3: LDValue = (v & ~(0xFFFFFFFF << 0)) | (ReadMemory<uint32>(timestamp, address & ~3) << 0);
2539 		 break;
2540 	}
2541 
2542         if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2543 	   PGXP_CPU_LWL(instr, LDValue, address);
2544 
2545     END_OPF;
2546 
2547     //
2548     // SWL - Store Word Left
2549     //
2550     BEGIN_OPF(SWL);
2551         ITYPE;
2552 
2553 	GPR_DEPRES_BEGIN
2554 	GPR_DEP(rs);
2555 	GPR_DEP(rt);
2556 	GPR_DEPRES_END
2557 
2558         uint32 address = GPR[rs] + immediate;
2559 
2560 	switch(address & 0x3)
2561 	{
2562 	 case 0: WriteMemory<uint8>(timestamp, address & ~3, GPR[rt] >> 24);
2563 		 break;
2564 
2565 	 case 1: WriteMemory<uint16>(timestamp, address & ~3, GPR[rt] >> 16);
2566 	         break;
2567 
2568 	 case 2: WriteMemory<uint32>(timestamp, address & ~3, GPR[rt] >> 8, true);
2569 		 break;
2570 
2571 	 case 3: WriteMemory<uint32>(timestamp, address & ~3, GPR[rt] >> 0);
2572 		 break;
2573 	}
2574         if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2575 	   PGXP_CPU_SWL(instr, GPR[rt], address);
2576 
2577 	DO_LDS();
2578 
2579     END_OPF;
2580 
2581     //
2582     // LWR - Load Word Right
2583     //
2584     BEGIN_OPF(LWR);
2585         ITYPE;
2586 
2587 	GPR_DEPRES_BEGIN
2588 	GPR_DEP(rs);
2589 	//GPR_DEP(rt);
2590 	GPR_DEPRES_END
2591 
2592         uint32 address = GPR[rs] + immediate;
2593 	uint32 v = GPR[rt];
2594 
2595 	if(LDWhich == rt)
2596 	{
2597 	 v = LDValue;
2598 	 ReadFudge = 0;
2599 	}
2600 	else
2601 	{
2602 	 DO_LDS();
2603 	}
2604 
2605 	LDWhich = rt;
2606 	switch(address & 0x3)
2607 	{
2608 	 case 0: LDValue = (v & ~(0xFFFFFFFF)) | ReadMemory<uint32>(timestamp, address);
2609 		 break;
2610 
2611 	 case 1: LDValue = (v & ~(0xFFFFFF)) | ReadMemory<uint32>(timestamp, address, true);
2612 		 break;
2613 
2614 	 case 2: LDValue = (v & ~(0xFFFF)) | ReadMemory<uint16>(timestamp, address);
2615 	         break;
2616 
2617 	 case 3: LDValue = (v & ~(0xFF)) | ReadMemory<uint8>(timestamp, address);
2618 		 break;
2619 	}
2620 
2621         if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2622 	   PGXP_CPU_LWR(instr, LDValue, address);
2623 
2624     END_OPF;
2625 
2626     //
2627     // SWR - Store Word Right
2628     //
2629     BEGIN_OPF(SWR);
2630         ITYPE;
2631 
2632 	GPR_DEPRES_BEGIN
2633 	GPR_DEP(rs);
2634 	GPR_DEP(rt);
2635 	GPR_DEPRES_END
2636 
2637         uint32 address = GPR[rs] + immediate;
2638 
2639 	switch(address & 0x3)
2640 	{
2641 	 case 0: WriteMemory<uint32>(timestamp, address, GPR[rt]);
2642 		 break;
2643 
2644 	 case 1: WriteMemory<uint32>(timestamp, address, GPR[rt], true);
2645 		 break;
2646 
2647 	 case 2: WriteMemory<uint16>(timestamp, address, GPR[rt]);
2648 	         break;
2649 
2650 	 case 3: WriteMemory<uint8>(timestamp, address, GPR[rt]);
2651 		 break;
2652 	}
2653 
2654         if (PGXP_GetModes() & PGXP_MODE_MEMORY)
2655 		PGXP_CPU_SWR(instr, GPR[rt], address);
2656 
2657 
2658 	DO_LDS();
2659 
2660     END_OPF;
2661 
2662     //
2663     // Mednafen special instruction
2664     //
2665     BEGIN_OPF(INTERRUPT);
2666 	if(Halted)
2667 	{
2668 	 goto SkipNPCStuff;
2669 	}
2670 	else
2671 	{
2672  	 DO_LDS();
2673 
2674 	 new_PC = Exception(EXCEPTION_INT, PC, new_PC, instr);
2675 	}
2676     END_OPF;
2677    }
2678 
2679    OpDone: ;
2680    PC = new_PC;
2681    new_PC = new_PC + 4;
2682    BDBT = 0;
2683 
2684    SkipNPCStuff:	;
2685 
2686    //printf("\n");
2687   }
2688 #if defined(HAVE_LIGHTREC) && defined(LIGHTREC_DEBUG)
2689   if (timestamp >= 0 && PC != oldpc)
2690      print_for_big_ass_debugger(timestamp, PC);
2691 #endif
2692  } while(MDFN_LIKELY(PSX_EventHandler(timestamp)));
2693 
2694  if(gte_ts_done > 0)
2695   gte_ts_done -= timestamp;
2696 
2697  if(muldiv_ts_done > 0)
2698   muldiv_ts_done -= timestamp;
2699 
2700  ACTIVE_TO_BACKING;
2701 
2702  return(timestamp);
2703 }
2704 
Run(pscpu_timestamp_t timestamp_in,bool BIOSPrintMode,bool ILHMode)2705 pscpu_timestamp_t PS_CPU::Run(pscpu_timestamp_t timestamp_in, bool BIOSPrintMode, bool ILHMode)
2706 {
2707 #ifdef HAVE_LIGHTREC
2708 //track options changing
2709  if(MDFN_UNLIKELY(psx_dynarec != prev_dynarec || pgxpMode != PGXP_GetModes()) ||
2710     prev_invalidate != psx_dynarec_invalidate)
2711  {
2712   //init lightrec when changing dynarec, invalidate, or PGXP option, cleans entire state if already running
2713   if(psx_dynarec != DYNAREC_DISABLED)
2714   {
2715    lightrec_plugin_init();
2716   }
2717   prev_dynarec = psx_dynarec;
2718   pgxpMode = PGXP_GetModes();
2719   prev_invalidate = psx_dynarec_invalidate;
2720  }
2721 
2722  if(psx_dynarec != DYNAREC_DISABLED)
2723   return(lightrec_plugin_execute(timestamp_in));
2724 #endif
2725  if(CPUHook || ADDBT)
2726   return(RunReal<true, true, false>(timestamp_in));
2727 #ifdef DEBUG
2728  if(ILHMode)
2729   return(RunReal<false, false, true>(timestamp_in));
2730  if(BIOSPrintMode)
2731   return(RunReal<false, true, false>(timestamp_in));
2732 #endif
2733  return(RunReal<false, false, false>(timestamp_in));
2734 }
2735 
SetCPUHook(void (* cpuh)(const pscpu_timestamp_t timestamp,uint32 pc),void (* addbt)(uint32 from,uint32 to,bool exception))2736 void PS_CPU::SetCPUHook(void (*cpuh)(const pscpu_timestamp_t timestamp, uint32 pc), void (*addbt)(uint32 from, uint32 to, bool exception))
2737 {
2738  ADDBT = addbt;
2739  CPUHook = cpuh;
2740 }
2741 
GetRegister(unsigned int which,char * special,const uint32 special_len)2742 uint32 PS_CPU::GetRegister(unsigned int which, char *special, const uint32 special_len)
2743 {
2744  uint32 ret = 0;
2745 
2746  if(which >= GSREG_GPR && which < (GSREG_GPR + 32))
2747   ret = GPR[which];
2748  else switch(which)
2749  {
2750   case GSREG_PC:
2751 	ret = BACKED_PC;
2752 	break;
2753 
2754   case GSREG_PC_NEXT:
2755 	ret = BACKED_new_PC;
2756 	break;
2757 
2758   case GSREG_IN_BD_SLOT:
2759 	ret = BDBT;
2760 	break;
2761 
2762   case GSREG_LO:
2763 	ret = LO;
2764 	break;
2765 
2766   case GSREG_HI:
2767 	ret = HI;
2768 	break;
2769 
2770   case GSREG_BPC:
2771 	ret = CP0.BPC;
2772 	break;
2773 
2774   case GSREG_BDA:
2775 	ret = CP0.BDA;
2776 	break;
2777 
2778   case GSREG_TAR:
2779 	ret = CP0.TAR;
2780 	break;
2781 
2782   case GSREG_DCIC:
2783 	ret = CP0.DCIC;
2784 	break;
2785 
2786   case GSREG_BADA:
2787 	ret = CP0.BADA;
2788 	break;
2789 
2790   case GSREG_BDAM:
2791 	ret = CP0.BDAM;
2792 	break;
2793 
2794   case GSREG_BPCM:
2795 	ret = CP0.BPCM;
2796 	break;
2797 
2798   case GSREG_SR:
2799 	ret = CP0.SR;
2800 	break;
2801 
2802   case GSREG_CAUSE:
2803 	ret = CP0.CAUSE;
2804 #ifdef NOT_LIBRETRO
2805 	if(special)
2806 	{
2807 	 trio_snprintf(special, special_len, "BD: %u, BT: %u, CE: %u, IP: 0x%02x, Sw: %u, ExcCode: 0x%01x",
2808 		(ret >> 31) & 1, (ret >> 30) & 1, (ret >> 28) & 3, (ret >> 10) & 0x3F, (ret >> 8) & 3, (ret >> 2) & 0xF);
2809 	}
2810 #endif
2811 	break;
2812 
2813   case GSREG_EPC:
2814 	ret = CP0.EPC;
2815 	break;
2816 
2817  }
2818 
2819  return(ret);
2820 }
2821 
SetRegister(unsigned int which,uint32 value)2822 void PS_CPU::SetRegister(unsigned int which, uint32 value)
2823 {
2824  if(which >= GSREG_GPR && which < (GSREG_GPR + 32))
2825  {
2826   if(which != (GSREG_GPR + 0))
2827    GPR[which] = value;
2828  }
2829  else switch(which)
2830  {
2831   case GSREG_PC:
2832         BACKED_PC = value;
2833         break;
2834 
2835   case GSREG_PC_NEXT:
2836 	BACKED_new_PC = value;
2837 	break;
2838 
2839   case GSREG_IN_BD_SLOT:
2840 	BDBT = value & 0x3;
2841 	break;
2842 
2843   case GSREG_LO:
2844         LO = value;
2845         break;
2846 
2847   case GSREG_HI:
2848         HI = value;
2849         break;
2850 
2851   case GSREG_SR:
2852         CP0.SR = value;		// TODO: mask
2853         break;
2854 
2855   case GSREG_CAUSE:
2856 	CP0.CAUSE = value;
2857 	break;
2858 
2859   case GSREG_EPC:
2860 	CP0.EPC = value & ~0x3U;
2861 	break;
2862 
2863 
2864  }
2865 }
2866 
PeekCheckICache(uint32 PC,uint32 * iw)2867 bool PS_CPU::PeekCheckICache(uint32 PC, uint32 *iw)
2868 {
2869  if(ICache[(PC & 0xFFC) >> 2].TV == PC)
2870  {
2871   *iw = ICache[(PC & 0xFFC) >> 2].Data;
2872   return(true);
2873  }
2874 
2875  return(false);
2876 }
2877 
2878 
PeekMem8(uint32 A)2879 uint8 PS_CPU::PeekMem8(uint32 A)
2880 {
2881  return PeekMemory<uint8>(A);
2882 }
2883 
PeekMem16(uint32 A)2884 uint16 PS_CPU::PeekMem16(uint32 A)
2885 {
2886  return PeekMemory<uint16>(A);
2887 }
2888 
PeekMem32(uint32 A)2889 uint32 PS_CPU::PeekMem32(uint32 A)
2890 {
2891  return PeekMemory<uint32>(A);
2892 }
2893 
PokeMem8(uint32 A,uint8 V)2894 void PS_CPU::PokeMem8(uint32 A, uint8 V)
2895 {
2896  PokeMemory<uint8>(A, V);
2897 }
2898 
PokeMem16(uint32 A,uint16 V)2899 void PS_CPU::PokeMem16(uint32 A, uint16 V)
2900 {
2901  PokeMemory<uint16>(A, V);
2902 }
2903 
PokeMem32(uint32 A,uint32 V)2904 void PS_CPU::PokeMem32(uint32 A, uint32 V)
2905 {
2906  PokeMemory<uint32>(A, V);
2907 }
2908 
2909 #undef BEGIN_OPF
2910 #undef END_OPF
2911 #undef MK_OPF
2912 
2913 #define MK_OPF(op, funct)	((op) ? (0x40 | (op)) : (funct))
2914 #define BEGIN_OPF(op, funct) case MK_OPF(op, funct): {
2915 #define END_OPF } break;
2916 
2917 // FIXME: should we breakpoint on an illegal address?  And with LWC2/SWC2 if CP2 isn't enabled?
CheckBreakpoints(void (* callback)(bool write,uint32 address,unsigned int len),uint32 instr)2918 void PS_CPU::CheckBreakpoints(void (*callback)(bool write, uint32 address, unsigned int len), uint32 instr)
2919 {
2920  uint32 opf;
2921 
2922  opf = instr & 0x3F;
2923 
2924  if(instr & (0x3F << 26))
2925   opf = 0x40 | (instr >> 26);
2926 
2927 
2928  switch(opf)
2929  {
2930   default:
2931 	break;
2932 
2933     //
2934     // LB - Load Byte
2935     //
2936     BEGIN_OPF(0x20, 0);
2937 	ITYPE;
2938 	uint32 address = GPR[rs] + immediate;
2939 
2940         callback(false, address, 1);
2941     END_OPF;
2942 
2943     //
2944     // LBU - Load Byte Unsigned
2945     //
2946     BEGIN_OPF(0x24, 0);
2947         ITYPE;
2948         uint32 address = GPR[rs] + immediate;
2949 
2950         callback(false, address, 1);
2951     END_OPF;
2952 
2953     //
2954     // LH - Load Halfword
2955     //
2956     BEGIN_OPF(0x21, 0);
2957         ITYPE;
2958         uint32 address = GPR[rs] + immediate;
2959 
2960         callback(false, address, 2);
2961     END_OPF;
2962 
2963     //
2964     // LHU - Load Halfword Unsigned
2965     //
2966     BEGIN_OPF(0x25, 0);
2967         ITYPE;
2968         uint32 address = GPR[rs] + immediate;
2969 
2970         callback(false, address, 2);
2971     END_OPF;
2972 
2973 
2974     //
2975     // LW - Load Word
2976     //
2977     BEGIN_OPF(0x23, 0);
2978         ITYPE;
2979         uint32 address = GPR[rs] + immediate;
2980 
2981         callback(false, address, 4);
2982     END_OPF;
2983 
2984     //
2985     // SB - Store Byte
2986     //
2987     BEGIN_OPF(0x28, 0);
2988 	ITYPE;
2989 	uint32 address = GPR[rs] + immediate;
2990 
2991         callback(true, address, 1);
2992     END_OPF;
2993 
2994     //
2995     // SH - Store Halfword
2996     //
2997     BEGIN_OPF(0x29, 0);
2998         ITYPE;
2999         uint32 address = GPR[rs] + immediate;
3000 
3001         callback(true, address, 2);
3002     END_OPF;
3003 
3004     //
3005     // SW - Store Word
3006     //
3007     BEGIN_OPF(0x2B, 0);
3008         ITYPE;
3009         uint32 address = GPR[rs] + immediate;
3010 
3011         callback(true, address, 4);
3012     END_OPF;
3013 
3014     //
3015     // LWL - Load Word Left
3016     //
3017     BEGIN_OPF(0x22, 0);
3018 	ITYPE;
3019 	uint32 address = GPR[rs] + immediate;
3020 
3021 	do
3022 	{
3023          callback(false, address, 1);
3024 	} while((address--) & 0x3);
3025 
3026     END_OPF;
3027 
3028     //
3029     // SWL - Store Word Left
3030     //
3031     BEGIN_OPF(0x2A, 0);
3032         ITYPE;
3033         uint32 address = GPR[rs] + immediate;
3034 
3035         do
3036         {
3037 	 callback(true, address, 1);
3038         } while((address--) & 0x3);
3039 
3040     END_OPF;
3041 
3042     //
3043     // LWR - Load Word Right
3044     //
3045     BEGIN_OPF(0x26, 0);
3046         ITYPE;
3047         uint32 address = GPR[rs] + immediate;
3048 
3049         do
3050         {
3051 	 callback(false, address, 1);
3052         } while((++address) & 0x3);
3053 
3054     END_OPF;
3055 
3056     //
3057     // SWR - Store Word Right
3058     //
3059     BEGIN_OPF(0x2E, 0);
3060         ITYPE;
3061         uint32 address = GPR[rs] + immediate;
3062 
3063         do
3064         {
3065 	 callback(true, address, 1);
3066         } while((++address) & 0x3);
3067 
3068     END_OPF;
3069 
3070     //
3071     // LWC2
3072     //
3073     BEGIN_OPF(0x32, 0);
3074         ITYPE;
3075         uint32 address = GPR[rs] + immediate;
3076 
3077 	callback(false, address, 4);
3078     END_OPF;
3079 
3080     //
3081     // SWC2
3082     //
3083     BEGIN_OPF(0x3A, 0);
3084         ITYPE;
3085         uint32 address = GPR[rs] + immediate;
3086 
3087 	callback(true, address, 4);
3088     END_OPF;
3089 
3090  }
3091 }
3092 
3093 #ifdef HAVE_LIGHTREC
3094 #define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
3095 
3096 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
3097 #	define LE32TOH(x)	__builtin_bswap32(x)
3098 #	define HTOLE32(x)	__builtin_bswap32(x)
3099 #	define LE16TOH(x)	__builtin_bswap16(x)
3100 #	define HTOLE16(x)	__builtin_bswap16(x)
3101 #else
3102 #	define LE32TOH(x)	(x)
3103 #	define HTOLE32(x)	(x)
3104 #	define LE16TOH(x)	(x)
3105 #	define HTOLE16(x)	(x)
3106 #endif
3107 
kunseg(u32 addr)3108 static inline u32 kunseg(u32 addr)
3109 {
3110 	if (MDFN_UNLIKELY(addr >= 0xa0000000))
3111 		return addr - 0xa0000000;
3112 	else
3113 		return addr &~ 0x80000000;
3114 }
3115 
3116 enum opcodes {
3117         OP_SPECIAL              = 0x00,
3118         OP_REGIMM               = 0x01,
3119         OP_J                    = 0x02,
3120         OP_JAL                  = 0x03,
3121         OP_BEQ                  = 0x04,
3122         OP_BNE                  = 0x05,
3123         OP_BLEZ                 = 0x06,
3124         OP_BGTZ                 = 0x07,
3125         OP_ADDI                 = 0x08,
3126         OP_ADDIU                = 0x09,
3127         OP_SLTI                 = 0x0a,
3128         OP_SLTIU                = 0x0b,
3129         OP_ANDI                 = 0x0c,
3130         OP_ORI                  = 0x0d,
3131         OP_XORI                 = 0x0e,
3132         OP_LUI                  = 0x0f,
3133         OP_CP0                  = 0x10,
3134         OP_CP2                  = 0x12,
3135         OP_LB                   = 0x20,
3136         OP_LH                   = 0x21,
3137         OP_LWL                  = 0x22,
3138         OP_LW                   = 0x23,
3139         OP_LBU                  = 0x24,
3140         OP_LHU                  = 0x25,
3141         OP_LWR                  = 0x26,
3142         OP_SB                   = 0x28,
3143         OP_SH                   = 0x29,
3144         OP_SWL                  = 0x2a,
3145         OP_SW                   = 0x2b,
3146         OP_SWR                  = 0x2e,
3147         OP_LWC2                 = 0x32,
3148         OP_SWC2                 = 0x3a,
3149 };
3150 
3151 static char *name = (char*) "beetle_psx_libretro";
3152 
3153 #ifdef LIGHTREC_DEBUG
3154 u32 lightrec_begin_cycles = 0;
3155 
hash_calculate(const void * buffer,u32 count)3156 u32 hash_calculate(const void *buffer, u32 count)
3157 {
3158 	unsigned int i;
3159 	u32 *data = (u32 *) buffer;
3160 	u32 hash = 0xffffffff;
3161 
3162 	count /= 4;
3163 	for(i = 0; i < count; ++i) {
3164 		hash += data[i];
3165 		hash += (hash << 10);
3166 		hash ^= (hash >> 6);
3167 	}
3168 
3169 	hash += (hash << 3);
3170 	hash ^= (hash >> 11);
3171 	hash += (hash << 15);
3172 	return hash;
3173 }
3174 
print_for_big_ass_debugger(int32_t timestamp,uint32_t PC)3175 void PS_CPU::print_for_big_ass_debugger(int32_t timestamp, uint32_t PC)
3176 {
3177 	uint8_t *psxM = (uint8_t *) MainRAM->data8;
3178 	uint8_t *psxR = (uint8_t *) BIOSROM->data8;
3179 	uint8_t *psxH = (uint8_t *) ScratchRAM->data8;
3180 
3181 	unsigned int i;
3182 
3183 	printf("CYCLE 0x%08x PC 0x%08x", timestamp, PC);
3184 
3185 #ifdef LIGHTREC_VERY_DEBUG
3186 	printf(" RAM 0x%08x SCRATCH 0x%08x",
3187 		hash_calculate(psxM, 0x200000),
3188 		hash_calculate(psxH, 0x400));
3189 #endif
3190 
3191 	printf(" CP0 0x%08x",
3192 		hash_calculate(&CP0.Regs,
3193 			sizeof(CP0.Regs)));
3194 
3195 #ifdef LIGHTREC_VERY_DEBUG
3196 	for (i = 0; i < 32; i++)
3197 		printf(" GPR[%i] 0x%08x", i, GPR[i]);
3198 	printf(" LO 0x%08x", LO);
3199 	printf(" HI 0x%08x", HI);
3200 #else
3201 	printf(" GPR 0x%08x", hash_calculate(&GPR, 32*sizeof(uint32_t)));
3202 #endif
3203 	printf("\n");
3204 }
3205 #endif /* LIGHTREC_DEBUG */
3206 
cop_mfc(struct lightrec_state * state,u32 op,u8 reg)3207 u32 PS_CPU::cop_mfc(struct lightrec_state *state, u32 op, u8 reg)
3208 {
3209 	return CP0.Regs[reg];
3210 }
3211 
cop_cfc(struct lightrec_state * state,u32 op,u8 reg)3212 u32 PS_CPU::cop_cfc(struct lightrec_state *state, u32 op, u8 reg)
3213 {
3214 	return CP0.Regs[reg];
3215 }
3216 
cop2_mfc(struct lightrec_state * state,u32 op,u8 reg)3217 u32 PS_CPU::cop2_mfc(struct lightrec_state *state, u32 op, u8 reg)
3218 {
3219 	return GTE_ReadDR(reg);
3220 }
3221 
pgxp_cop2_mfc(struct lightrec_state * state,u32 op,u8 reg)3222 u32 PS_CPU::pgxp_cop2_mfc(struct lightrec_state *state, u32 op, u8 reg)
3223 {
3224 	u32 r = GTE_ReadDR(reg);
3225 
3226 	if((op >> 26) == OP_CP2)
3227 		PGXP_GTE_MFC2(op, r, r);
3228 
3229 	return r;
3230 }
3231 
cop2_cfc(struct lightrec_state * state,u32 op,u8 reg)3232 u32 PS_CPU::cop2_cfc(struct lightrec_state *state, u32 op, u8 reg)
3233 {
3234 	return GTE_ReadCR(reg);
3235 }
3236 
pgxp_cop2_cfc(struct lightrec_state * state,u32 op,u8 reg)3237 u32 PS_CPU::pgxp_cop2_cfc(struct lightrec_state *state, u32 op, u8 reg)
3238 {
3239 	u32 r = GTE_ReadCR(reg);
3240 
3241 	PGXP_GTE_CFC2(op, r, r);
3242 
3243 	return r;
3244 }
3245 
cop_mtc_ctc(struct lightrec_state * state,u8 reg,u32 value)3246 void PS_CPU::cop_mtc_ctc(struct lightrec_state *state,
3247 		u8 reg, u32 value)
3248 {
3249 	switch (reg) {
3250 		case 1:
3251 		case 4:
3252 		case 8:
3253 		case 14:
3254 		case 15:
3255 			/* Those registers are read-only */
3256 			break;
3257 		case 12: /* Status */
3258 			if ((CP0.SR & ~value) & (1 << 16)) {
3259 				memcpy(MainRAM->data8, cache_buf, sizeof(cache_buf));
3260 				lightrec_invalidate_all(state);
3261 			} else if ((~CP0.SR & value) & (1 << 16)) {
3262 				memcpy(cache_buf, MainRAM->data8, sizeof(cache_buf));
3263 			}
3264 
3265 			CP0.SR = value & ~( (0x3 << 26) | (0x3 << 23) | (0x3 << 6));
3266 			RecalcIPCache();
3267 			lightrec_set_exit_flags(state,
3268 					LIGHTREC_EXIT_CHECK_INTERRUPT);
3269 			break;
3270 		case 13: /* Cause */
3271 			CP0.CAUSE &= ~0x0300;
3272 			CP0.CAUSE |= value & 0x0300;
3273 			RecalcIPCache();
3274 			lightrec_set_exit_flags(state,
3275 					LIGHTREC_EXIT_CHECK_INTERRUPT);
3276 			break;
3277 		default:
3278 			CP0.Regs[reg] = value;
3279 			break;
3280 	}
3281 }
3282 
cop_mtc(struct lightrec_state * state,u32 op,u8 reg,u32 value)3283 void PS_CPU::cop_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
3284 {
3285 	cop_mtc_ctc(state, reg, value);
3286 }
3287 
cop_ctc(struct lightrec_state * state,u32 op,u8 reg,u32 value)3288 void PS_CPU::cop_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
3289 {
3290 	cop_mtc_ctc(state, reg, value);
3291 }
3292 
cop2_mtc(struct lightrec_state * state,u32 op,u8 reg,u32 value)3293 void PS_CPU::cop2_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
3294 {
3295 	GTE_WriteDR(reg, value);
3296 }
3297 
pgxp_cop2_mtc(struct lightrec_state * state,u32 op,u8 reg,u32 value)3298 void PS_CPU::pgxp_cop2_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
3299 {
3300 	GTE_WriteDR(reg, value);
3301 	if((op >> 26) == OP_CP2)
3302 		PGXP_GTE_MTC2(op, value, value);
3303 }
3304 
cop2_ctc(struct lightrec_state * state,u32 op,u8 reg,u32 value)3305 void PS_CPU::cop2_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
3306 {
3307 	GTE_WriteCR(reg, value);
3308 }
3309 
pgxp_cop2_ctc(struct lightrec_state * state,u32 op,u8 reg,u32 value)3310 void PS_CPU::pgxp_cop2_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
3311 {
3312 	GTE_WriteCR(reg, value);
3313 	PGXP_GTE_CTC2(op, value, value);
3314 }
3315 
3316 static bool cp2_ops[0x40] = {0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,
3317                              1,1,1,1,1,0,1,0,0,0,0,1,1,0,1,0,
3318                              1,0,0,0,0,0,0,0,1,1,1,0,0,1,1,0,
3319                              1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1};
3320 
cop_op(struct lightrec_state * state,u32 func)3321 static void cop_op(struct lightrec_state *state, u32 func)
3322 {
3323    MDFND_DispMessage(3, RETRO_LOG_WARN,
3324          RETRO_MESSAGE_TARGET_LOG, RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,
3325          "Access to invalid co-processor 0");
3326 }
3327 
cop2_op(struct lightrec_state * state,u32 func)3328 static void cop2_op(struct lightrec_state *state, u32 func)
3329 {
3330    if (MDFN_UNLIKELY(!cp2_ops[func & 0x3f]))
3331    {
3332       MDFN_DispMessage(3, RETRO_LOG_WARN,
3333             RETRO_MESSAGE_TARGET_LOG, RETRO_MESSAGE_TYPE_NOTIFICATION_ALT,
3334             "Invalid CP2 function %u\n", func);
3335    }
3336    else
3337       GTE_Instruction(func);
3338 }
3339 
reset_target_cycle_count(struct lightrec_state * state,pscpu_timestamp_t timestamp)3340 void PS_CPU::reset_target_cycle_count(struct lightrec_state *state, pscpu_timestamp_t timestamp){
3341 	if (timestamp >= next_event_ts)
3342 		lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
3343 }
3344 
hw_write_byte(struct lightrec_state * state,u32 opcode,void * host,u32 mem,u8 val)3345 void PS_CPU::hw_write_byte(struct lightrec_state *state,
3346 		u32 opcode, void *host,	u32 mem, u8 val)
3347 {
3348 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3349 
3350 	PSX_MemWrite8(timestamp, mem, val);
3351 
3352 	reset_target_cycle_count(state, timestamp);
3353 }
3354 
pgxp_nonhw_write_byte(struct lightrec_state * state,u32 opcode,void * host,u32 mem,u8 val)3355 void PS_CPU::pgxp_nonhw_write_byte(struct lightrec_state *state,
3356 		u32 opcode, void *host,	u32 mem, u8 val)
3357 {
3358 	*(u8 *)host = val;
3359 	PGXP_CPU_SB(opcode, val, mem);
3360 
3361 	if (!psx_dynarec_invalidate)
3362 		lightrec_invalidate(state, mem, 1);
3363 }
3364 
pgxp_hw_write_byte(struct lightrec_state * state,u32 opcode,void * host,u32 mem,u8 val)3365 void PS_CPU::pgxp_hw_write_byte(struct lightrec_state *state,
3366 		u32 opcode, void *host,	u32 mem, u8 val)
3367 {
3368 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3369 
3370 	u32 kmem = kunseg(mem);
3371 
3372 	PSX_MemWrite8(timestamp, kmem, val);
3373 
3374 	PGXP_CPU_SB(opcode, val, mem);
3375 
3376 	reset_target_cycle_count(state, timestamp);
3377 }
3378 
hw_write_half(struct lightrec_state * state,u32 opcode,void * host,u32 mem,u16 val)3379 void PS_CPU::hw_write_half(struct lightrec_state *state,
3380 		u32 opcode, void *host, u32 mem, u16 val)
3381 {
3382 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3383 
3384 	PSX_MemWrite16(timestamp, mem, val);
3385 
3386 	reset_target_cycle_count(state, timestamp);
3387 }
3388 
pgxp_nonhw_write_half(struct lightrec_state * state,u32 opcode,void * host,u32 mem,u16 val)3389 void PS_CPU::pgxp_nonhw_write_half(struct lightrec_state *state,
3390 		u32 opcode, void *host, u32 mem, u16 val)
3391 {
3392 	*(u16 *)host = HTOLE16(val);
3393 	PGXP_CPU_SH(opcode, val, mem);
3394 
3395 	if (!psx_dynarec_invalidate)
3396 		lightrec_invalidate(state, mem, 2);
3397 }
3398 
pgxp_hw_write_half(struct lightrec_state * state,u32 opcode,void * host,u32 mem,u16 val)3399 void PS_CPU::pgxp_hw_write_half(struct lightrec_state *state,
3400 		u32 opcode, void *host, u32 mem, u16 val)
3401 {
3402 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3403 
3404 	u32 kmem = kunseg(mem);
3405 
3406 	PSX_MemWrite16(timestamp, kmem, val);
3407 
3408 	PGXP_CPU_SH(opcode, val, mem);
3409 
3410 	reset_target_cycle_count(state, timestamp);
3411 }
3412 
hw_write_word(struct lightrec_state * state,u32 opcode,void * host,u32 mem,u32 val)3413 void PS_CPU::hw_write_word(struct lightrec_state *state,
3414 		u32 opcode, void *host, u32 mem, u32 val)
3415 {
3416 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3417 
3418 	PSX_MemWrite32(timestamp, mem, val);
3419 
3420 	reset_target_cycle_count(state, timestamp);
3421 }
3422 
pgxp_nonhw_write_word(struct lightrec_state * state,u32 opcode,void * host,u32 mem,u32 val)3423 void PS_CPU::pgxp_nonhw_write_word(struct lightrec_state *state,
3424 		u32 opcode, void *host, u32 mem, u32 val)
3425 {
3426 	*(u32 *)host = HTOLE32(val);
3427 
3428 	switch (opcode >> 26){
3429 		case 0x2A:
3430 			PGXP_CPU_SWL(opcode, val, mem + (opcode & 0x3));
3431 			break;
3432 		case 0x2B:
3433 			PGXP_CPU_SW(opcode, val, mem);
3434 			break;
3435 		case 0x2E:
3436 			PGXP_CPU_SWR(opcode, val, mem + (opcode & 0x3));
3437 			break;
3438 		case 0x3A:
3439 			PGXP_GTE_SWC2(opcode, val, mem);
3440 			break;
3441 		default:
3442 			break;
3443 	}
3444 
3445 	if (!psx_dynarec_invalidate)
3446 		lightrec_invalidate(state, mem, 4);
3447 }
3448 
pgxp_hw_write_word(struct lightrec_state * state,u32 opcode,void * host,u32 mem,u32 val)3449 void PS_CPU::pgxp_hw_write_word(struct lightrec_state *state,
3450 		u32 opcode, void *host, u32 mem, u32 val)
3451 {
3452 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3453 
3454 	u32 kmem = kunseg(mem);
3455 
3456 	PSX_MemWrite32(timestamp, kmem, val);
3457 
3458 	switch (opcode >> 26){
3459 		case OP_SWL:
3460 			PGXP_CPU_SWL(opcode, val, mem + (opcode & 0x3));
3461 			break;
3462 		case OP_SW:
3463 			PGXP_CPU_SW(opcode, val, mem);
3464 			break;
3465 		case OP_SWR:
3466 			PGXP_CPU_SWR(opcode, val, mem + (opcode & 0x3));
3467 			break;
3468 		case OP_SWC2:
3469 			PGXP_GTE_SWC2(opcode, val, mem);
3470 			break;
3471 		default:
3472 			break;
3473 	}
3474 
3475 	reset_target_cycle_count(state, timestamp);
3476 }
3477 
hw_read_byte(struct lightrec_state * state,u32 opcode,void * host,u32 mem)3478 u8 PS_CPU::hw_read_byte(struct lightrec_state *state,
3479 		u32 opcode, void *host, u32 mem)
3480 {
3481 	u8 val;
3482 
3483 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3484 
3485 	val = PSX_MemRead8(timestamp, mem);
3486 
3487 	/* Calling PSX_MemRead* might update timestamp - Make sure
3488 	 * here that state->current_cycle stays in sync. */
3489 	lightrec_reset_cycle_count(lightrec_state, timestamp);
3490 
3491 	reset_target_cycle_count(state, timestamp);
3492 
3493 	return val;
3494 }
3495 
pgxp_nonhw_read_byte(struct lightrec_state * state,u32 opcode,void * host,u32 mem)3496 u8 PS_CPU::pgxp_nonhw_read_byte(struct lightrec_state *state,
3497 		u32 opcode, void *host, u32 mem)
3498 {
3499 	u8 val = *(u8 *)host;
3500 
3501 	if((opcode >> 26) == OP_LB)
3502 		PGXP_CPU_LB(opcode, val, mem);
3503 	else
3504 		PGXP_CPU_LBU(opcode, val, mem);
3505 
3506 	return val;
3507 }
3508 
pgxp_hw_read_byte(struct lightrec_state * state,u32 opcode,void * host,u32 mem)3509 u8 PS_CPU::pgxp_hw_read_byte(struct lightrec_state *state,
3510 		u32 opcode, void *host, u32 mem)
3511 {
3512 	u8 val;
3513 
3514 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3515 
3516 	u32 kmem = kunseg(mem);
3517 
3518 	val = PSX_MemRead8(timestamp, kmem);
3519 
3520 	if((opcode >> 26) == OP_LB)
3521 		PGXP_CPU_LB(opcode, val, mem);
3522 	else
3523 		PGXP_CPU_LBU(opcode, val, mem);
3524 
3525 	/* Calling PSX_MemRead* might update timestamp - Make sure
3526 	 * here that state->current_cycle stays in sync. */
3527 	lightrec_reset_cycle_count(lightrec_state, timestamp);
3528 
3529 	reset_target_cycle_count(state, timestamp);
3530 
3531 	return val;
3532 }
3533 
hw_read_half(struct lightrec_state * state,u32 opcode,void * host,u32 mem)3534 u16 PS_CPU::hw_read_half(struct lightrec_state *state,
3535 		u32 opcode, void *host, u32 mem)
3536 {
3537 	u16 val;
3538 
3539 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3540 
3541 	val = PSX_MemRead16(timestamp, mem);
3542 
3543 	/* Calling PSX_MemRead* might update timestamp - Make sure
3544 	 * here that state->current_cycle stays in sync. */
3545 	lightrec_reset_cycle_count(lightrec_state, timestamp);
3546 
3547 	reset_target_cycle_count(state, timestamp);
3548 
3549 	return val;
3550 }
3551 
pgxp_nonhw_read_half(struct lightrec_state * state,u32 opcode,void * host,u32 mem)3552 u16 PS_CPU::pgxp_nonhw_read_half(struct lightrec_state *state,
3553 		u32 opcode, void *host, u32 mem)
3554 {
3555 	u16 val = LE16TOH(*(u16 *)host);
3556 
3557 	if((opcode >> 26) == OP_LH)
3558 		PGXP_CPU_LH(opcode, val, mem);
3559 	else
3560 		PGXP_CPU_LHU(opcode, val, mem);
3561 
3562 	return val;
3563 }
3564 
pgxp_hw_read_half(struct lightrec_state * state,u32 opcode,void * host,u32 mem)3565 u16 PS_CPU::pgxp_hw_read_half(struct lightrec_state *state,
3566 		u32 opcode, void *host, u32 mem)
3567 {
3568 	u16 val;
3569 
3570 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3571 
3572 	u32 kmem = kunseg(mem);
3573 
3574 	val = PSX_MemRead16(timestamp, kmem);
3575 
3576 	if((opcode >> 26) == OP_LH)
3577 		PGXP_CPU_LH(opcode, val, mem);
3578 	else
3579 		PGXP_CPU_LHU(opcode, val, mem);
3580 
3581 	/* Calling PSX_MemRead* might update timestamp - Make sure
3582 	 * here that state->current_cycle stays in sync. */
3583 	lightrec_reset_cycle_count(lightrec_state, timestamp);
3584 
3585 	reset_target_cycle_count(state, timestamp);
3586 
3587 	return val;
3588 }
3589 
hw_read_word(struct lightrec_state * state,u32 opcode,void * host,u32 mem)3590 u32 PS_CPU::hw_read_word(struct lightrec_state *state,
3591 		u32 opcode, void *host, u32 mem)
3592 {
3593 	u32 val;
3594 
3595 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3596 
3597 	val = PSX_MemRead32(timestamp, mem);
3598 
3599 	/* Calling PSX_MemRead* might update timestamp - Make sure
3600 	 * here that state->current_cycle stays in sync. */
3601 	lightrec_reset_cycle_count(lightrec_state, timestamp);
3602 
3603 	reset_target_cycle_count(state, timestamp);
3604 
3605 	return val;
3606 }
3607 
pgxp_nonhw_read_word(struct lightrec_state * state,u32 opcode,void * host,u32 mem)3608 u32 PS_CPU::pgxp_nonhw_read_word(struct lightrec_state *state,
3609 		u32 opcode, void *host, u32 mem)
3610 {
3611 	u32 val = LE32TOH(*(u32 *)host);
3612 
3613 	switch (opcode >> 26){
3614 		case OP_LWL:
3615 			//TODO: OR with masked register
3616 			PGXP_CPU_LWL(opcode, val << (24-(opcode & 0x3)*8), mem + (opcode & 0x3));
3617 			break;
3618 		case OP_LW:
3619 			PGXP_CPU_LW(opcode, val, mem);
3620 			break;
3621 		case OP_LWR:
3622 			//TODO: OR with masked register
3623 			PGXP_CPU_LWR(opcode, val >> ((opcode & 0x3)*8), mem + (opcode & 0x3));
3624 			break;
3625 		case OP_LWC2:
3626 			PGXP_GTE_LWC2(opcode, val, mem);
3627 			break;
3628 		default:
3629 			break;
3630 	}
3631 
3632 	return val;
3633 }
3634 
pgxp_hw_read_word(struct lightrec_state * state,u32 opcode,void * host,u32 mem)3635 u32 PS_CPU::pgxp_hw_read_word(struct lightrec_state *state,
3636 		u32 opcode, void *host, u32 mem)
3637 {
3638 	u32 val;
3639 
3640 	pscpu_timestamp_t timestamp = lightrec_current_cycle_count(state);
3641 
3642 	u32 kmem = kunseg(mem);
3643 
3644 	val = PSX_MemRead32(timestamp, kmem);
3645 
3646 	switch (opcode >> 26){
3647 		case OP_LWL:
3648 			//TODO: OR with masked register
3649 			PGXP_CPU_LWL(opcode, val << (24-(opcode & 0x3)*8), mem + (opcode & 0x3));
3650 			break;
3651 		case OP_LW:
3652 			PGXP_CPU_LW(opcode, val, mem);
3653 			break;
3654 		case OP_LWR:
3655 			//TODO: OR with masked register
3656 			PGXP_CPU_LWR(opcode, val >> ((opcode & 0x3)*8), mem + (opcode & 0x3));
3657 			break;
3658 		case OP_LWC2:
3659 			PGXP_GTE_LWC2(opcode, val, mem);
3660 			break;
3661 		default:
3662 			break;
3663 	}
3664 
3665 	/* Calling PSX_MemRead* might update timestamp - Make sure
3666 	 * here that state->current_cycle stays in sync. */
3667 	lightrec_reset_cycle_count(lightrec_state, timestamp);
3668 
3669 	reset_target_cycle_count(state, timestamp);
3670 
3671 	return val;
3672 }
3673 
3674 struct lightrec_mem_map_ops PS_CPU::pgxp_nonhw_regs_ops = {
3675 	.sb = pgxp_nonhw_write_byte,
3676 	.sh = pgxp_nonhw_write_half,
3677 	.sw = pgxp_nonhw_write_word,
3678 	.lb = pgxp_nonhw_read_byte,
3679 	.lh = pgxp_nonhw_read_half,
3680 	.lw = pgxp_nonhw_read_word,
3681 };
3682 
3683 struct lightrec_mem_map_ops PS_CPU::pgxp_hw_regs_ops = {
3684 	.sb = pgxp_hw_write_byte,
3685 	.sh = pgxp_hw_write_half,
3686 	.sw = pgxp_hw_write_word,
3687 	.lb = pgxp_hw_read_byte,
3688 	.lh = pgxp_hw_read_half,
3689 	.lw = pgxp_hw_read_word,
3690 };
3691 
3692 struct lightrec_mem_map_ops PS_CPU::hw_regs_ops = {
3693 	.sb = hw_write_byte,
3694 	.sh = hw_write_half,
3695 	.sw = hw_write_word,
3696 	.lb = hw_read_byte,
3697 	.lh = hw_read_half,
3698 	.lw = hw_read_word,
3699 };
3700 
cache_ctrl_read_word(struct lightrec_state * state,u32 opcode,void * host,u32 mem)3701 u32 PS_CPU::cache_ctrl_read_word(struct lightrec_state *state,
3702 		u32 opcode, void *host, u32 mem)
3703 {
3704 	if (PGXP_GetModes() & PGXP_MODE_MEMORY)
3705 		PGXP_CPU_LW(opcode, BIU, mem);
3706 
3707 	return BIU;
3708 }
3709 
cache_ctrl_write_word(struct lightrec_state * state,u32 opcode,void * host,u32 mem,u32 val)3710 void PS_CPU::cache_ctrl_write_word(struct lightrec_state *state,
3711 		u32 opcode, void *host, u32 mem, u32 val)
3712 {
3713 	BIU = val;
3714 
3715 	if (PGXP_GetModes() & PGXP_MODE_MEMORY)
3716 		PGXP_CPU_SW(opcode, BIU, mem);
3717 }
3718 
3719 struct lightrec_mem_map_ops PS_CPU::cache_ctrl_ops = {
3720 	.sb = NULL,
3721 	.sh = NULL,
3722 	.sw = cache_ctrl_write_word,
3723 	.lb = NULL,
3724 	.lh = NULL,
3725 	.lw = cache_ctrl_read_word,
3726 };
3727 
3728 struct lightrec_mem_map PS_CPU::lightrec_map[] = {
3729 	[PSX_MAP_KERNEL_USER_RAM] = {
3730 		/* Kernel and user memory */
3731 		.pc = 0x00000000,
3732 		.length = 0x200000,
3733 	},
3734 	[PSX_MAP_BIOS] = {
3735 		/* BIOS */
3736 		.pc = 0x1fc00000,
3737 		.length = 0x80000,
3738 	},
3739 	[PSX_MAP_SCRATCH_PAD] = {
3740 		/* Scratch pad */
3741 		.pc = 0x1f800000,
3742 		.length = 0x400,
3743 	},
3744 	[PSX_MAP_PARALLEL_PORT] = {
3745 		/* Parallel port */
3746 		.pc = 0x1f000000,
3747 		.length = 0x800000,
3748 	},
3749 	[PSX_MAP_HW_REGISTERS] = {
3750 		/* Hardware registers */
3751 		.pc = 0x1f801000,
3752 		.length = 0x2000,
3753 	},
3754 	[PSX_MAP_CACHE_CONTROL] = {
3755 		/* Cache control */
3756 		.pc = 0x5ffe0130,
3757 		.length = 4,
3758 		.address = NULL,
3759 		.ops = &cache_ctrl_ops,
3760 	},
3761 
3762 	/* Mirrors of the kernel/user memory */
3763 	{
3764 		.pc = 0x00200000,
3765 		.length = 0x200000,
3766 		.address = NULL,
3767 		.ops = NULL,
3768 		.mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
3769 	},
3770 	{
3771 		.pc = 0x00400000,
3772 		.length = 0x200000,
3773 		.address = NULL,
3774 		.ops = NULL,
3775 		.mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
3776 	},
3777 	{
3778 		.pc = 0x00600000,
3779 		.length = 0x200000,
3780 		.address = NULL,
3781 		.ops = NULL,
3782 		.mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
3783 	},
3784 };
3785 
3786 struct lightrec_ops PS_CPU::ops = {
3787 	.cop0_ops = {
3788 		.mfc = cop_mfc,
3789 		.cfc = cop_cfc,
3790 		.mtc = cop_mtc,
3791 		.ctc = cop_ctc,
3792 		.op = cop_op,
3793 	},
3794 	.cop2_ops = {
3795 		.mfc = cop2_mfc,
3796 		.cfc = cop2_cfc,
3797 		.mtc = cop2_mtc,
3798 		.ctc = cop2_ctc,
3799 		.op = cop2_op,
3800 	},
3801 };
3802 
3803 struct lightrec_ops PS_CPU::pgxp_ops = {
3804 	.cop0_ops = {
3805 		.mfc = cop_mfc,
3806 		.cfc = cop_cfc,
3807 		.mtc = cop_mtc,
3808 		.ctc = cop_ctc,
3809 		.op = cop_op,
3810 	},
3811 	.cop2_ops = {
3812 		.mfc = pgxp_cop2_mfc,
3813 		.cfc = pgxp_cop2_cfc,
3814 		.mtc = pgxp_cop2_mtc,
3815 		.ctc = pgxp_cop2_ctc,
3816 		.op = cop2_op,
3817 	},
3818 };
3819 
lightrec_plugin_init()3820 int PS_CPU::lightrec_plugin_init()
3821 {
3822 	struct lightrec_ops *cop_ops;
3823 	uint8_t *psxM = (uint8_t *) MainRAM->data8;
3824 	uint8_t *psxR = (uint8_t *) BIOSROM->data8;
3825 	uint8_t *psxH = (uint8_t *) ScratchRAM->data8;
3826 	uint8_t *psxP = (uint8_t *) PSX_LoadExpansion1();
3827 
3828 	if(lightrec_state)
3829 		lightrec_destroy(lightrec_state);
3830 	else{
3831 		log_cb(RETRO_LOG_INFO, "Lightrec map addresses: M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n",
3832 			(uintptr_t) psxM,
3833 			(uintptr_t) psxP,
3834 			(uintptr_t) psxR,
3835 			(uintptr_t) psxH);
3836 	}
3837 
3838 	lightrec_map[PSX_MAP_KERNEL_USER_RAM].address = psxM;
3839 
3840 	if(psx_mmap == 4){
3841 		lightrec_map[PSX_MAP_MIRROR1].address = psxM + 0x200000;
3842 		lightrec_map[PSX_MAP_MIRROR2].address = psxM + 0x400000;
3843 		lightrec_map[PSX_MAP_MIRROR3].address = psxM + 0x600000;
3844 	}
3845 
3846 	lightrec_map[PSX_MAP_BIOS].address = psxR;
3847 	lightrec_map[PSX_MAP_SCRATCH_PAD].address = psxH;
3848 	lightrec_map[PSX_MAP_PARALLEL_PORT].address = psxP;
3849 
3850 	if (PGXP_GetModes() & (PGXP_MODE_MEMORY | PGXP_MODE_GTE)){
3851 		lightrec_map[PSX_MAP_HW_REGISTERS].ops = &pgxp_hw_regs_ops;
3852 		lightrec_map[PSX_MAP_KERNEL_USER_RAM].ops = &pgxp_nonhw_regs_ops;
3853 		lightrec_map[PSX_MAP_BIOS].ops = &pgxp_nonhw_regs_ops;
3854 		lightrec_map[PSX_MAP_SCRATCH_PAD].ops = &pgxp_nonhw_regs_ops;
3855 
3856 		cop_ops = &pgxp_ops;
3857 	} else {
3858 		lightrec_map[PSX_MAP_HW_REGISTERS].ops = &hw_regs_ops;
3859 		lightrec_map[PSX_MAP_KERNEL_USER_RAM].ops = NULL;
3860 		lightrec_map[PSX_MAP_BIOS].ops = NULL;
3861 		lightrec_map[PSX_MAP_SCRATCH_PAD].ops = NULL;
3862 
3863 		cop_ops = &ops;
3864 	}
3865 
3866 	lightrec_state = lightrec_init(name,
3867 			lightrec_map, ARRAY_SIZE(lightrec_map), cop_ops);
3868 
3869 	lightrec_set_invalidate_mode(lightrec_state, psx_dynarec_invalidate);
3870 
3871 	return 0;
3872 }
3873 
lightrec_plugin_execute(int32_t timestamp)3874 int32_t PS_CPU::lightrec_plugin_execute(int32_t timestamp)
3875 {
3876 	uint32_t GPRL[34];
3877 
3878 	uint32_t PC;
3879 	uint32_t new_PC;
3880 	uint32_t new_PC_mask;
3881 	uint32_t LDWhich;
3882 	uint32_t LDValue;
3883 
3884 	BACKING_TO_ACTIVE;
3885 
3886 	u32 flags;
3887 
3888 	do {
3889 #ifdef LIGHTREC_DEBUG
3890 		u32 oldpc = PC;
3891 #endif
3892 		memcpy(&GPRL,&GPR,32*sizeof(uint32_t));
3893 		GPRL[32] = LO;
3894 		GPRL[33] = HI;
3895 		lightrec_restore_registers(lightrec_state, GPRL);
3896 		lightrec_reset_cycle_count(lightrec_state, timestamp);
3897 
3898 		if (psx_dynarec == DYNAREC_EXECUTE)
3899 			PC = lightrec_execute(lightrec_state, PC, next_event_ts);
3900 		else if (psx_dynarec == DYNAREC_EXECUTE_ONE)
3901 			PC = lightrec_execute_one(lightrec_state,PC);
3902 		else if (psx_dynarec == DYNAREC_RUN_INTERPRETER)
3903 			PC = lightrec_run_interpreter(lightrec_state,PC);
3904 
3905 		timestamp = lightrec_current_cycle_count(
3906 				lightrec_state);
3907 
3908 		lightrec_dump_registers(lightrec_state, GPRL);
3909 		memcpy(&GPR,&GPRL,32*sizeof(uint32_t));
3910 		LO = GPRL[32];
3911 		HI = GPRL[33];
3912 
3913 		flags = lightrec_exit_flags(lightrec_state);
3914 
3915 		if (flags & LIGHTREC_EXIT_SEGFAULT) {
3916 			log_cb(RETRO_LOG_ERROR, "Exiting at cycle 0x%08x\n",
3917 					timestamp);
3918 			exit(1);
3919 		}
3920 
3921 		if (flags & LIGHTREC_EXIT_SYSCALL)
3922 			PC = Exception(EXCEPTION_SYSCALL, PC, PC, 0);
3923 
3924 #ifdef LIGHTREC_DEBUG
3925 		if (timestamp >= lightrec_begin_cycles && PC != oldpc){
3926 			print_for_big_ass_debugger(timestamp, PC);
3927 		}
3928 #endif
3929 		if ((CP0.SR & CP0.CAUSE & 0xFF00) && (CP0.SR & 1)) {
3930 			/* Handle software interrupts */
3931 			PC = Exception(EXCEPTION_INT, PC, PC, 0);
3932 		}
3933 	} while(MDFN_LIKELY(PSX_EventHandler(timestamp)));
3934 
3935 	ACTIVE_TO_BACKING;
3936 
3937 	return timestamp;
3938 }
3939 
lightrec_plugin_clear(u32 addr,u32 size)3940 void PS_CPU::lightrec_plugin_clear(u32 addr, u32 size)
3941 {
3942 	if (lightrec_state)	/* size * 4: uses DMA units */
3943 		lightrec_invalidate(lightrec_state, addr, size * 4);
3944 }
3945 
lightrec_plugin_shutdown(void)3946 void PS_CPU::lightrec_plugin_shutdown(void)
3947 {
3948 	log_cb(RETRO_LOG_INFO,"Lightrec memory usage: %u KiB, average IPI: %.2f\n",
3949 		lightrec_get_total_mem_usage()/1024,
3950 		lightrec_get_average_ipi());
3951 	lightrec_destroy(lightrec_state);
3952 }
3953 
3954 #endif
3955 
3956 #if NOT_LIBRETRO
3957 }
3958 #endif
3959