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 ×tamp, 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 ×tamp, 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 ×tamp, 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