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 #if 0
28 #define EXP_ILL_CHECK(n) {n;}
29 #else
30 #define EXP_ILL_CHECK(n) {}
31 #endif
32
33 #define BIU_ENABLE_ICACHE_S1 0x00000800 // Enable I-cache, set 1
34 #define BIU_ICACHE_FSIZE_MASK 0x00000300 // I-cache fill size mask; 0x000 = 2 words, 0x100 = 4 words, 0x200 = 8 words, 0x300 = 16 words
35 #define BIU_ENABLE_DCACHE 0x00000080 // Enable D-cache
36 #define BIU_DCACHE_SCRATCHPAD 0x00000008 // Enable scratchpad RAM mode of D-cache
37 #define BIU_TAG_TEST_MODE 0x00000004 // Enable TAG test mode(IsC must be set to 1 as well presumably?)
38 #define BIU_INVALIDATE_MODE 0x00000002 // Enable Invalidate mode(IsC must be set to 1 as well presumably?)
39 #define BIU_LOCK_MODE 0x00000001 // Enable Lock mode(IsC must be set to 1 as well presumably?)
40
41
42
43 namespace MDFN_IEN_PSX
44 {
45
46
PS_CPU()47 PS_CPU::PS_CPU()
48 {
49 //printf("%zu\n", (size_t)((uintptr_t)ICache - (uintptr_t)this));
50
51 Halted = false;
52
53 memset(FastMap, 0, sizeof(FastMap));
54 memset(DummyPage, 0xFF, sizeof(DummyPage)); // 0xFF to trigger an illegal instruction exception, so we'll know what's up when debugging.
55
56 for(uint64 a = 0x00000000; a < (1ULL << 32); a += FAST_MAP_PSIZE)
57 SetFastMap(DummyPage, a, FAST_MAP_PSIZE);
58
59 CPUHook = NULL;
60 ADDBT = NULL;
61
62 GTE_Init();
63
64 for(unsigned i = 0; i < 24; i++)
65 {
66 uint8 v = 7;
67
68 if(i < 12)
69 v += 4;
70
71 if(i < 21)
72 v += 3;
73
74 MULT_Tab24[i] = v;
75 }
76 }
77
~PS_CPU()78 PS_CPU::~PS_CPU()
79 {
80
81
82 }
83
SetFastMap(void * region_mem,uint32 region_address,uint32 region_size)84 void PS_CPU::SetFastMap(void *region_mem, uint32 region_address, uint32 region_size)
85 {
86 // FAST_MAP_SHIFT
87 // FAST_MAP_PSIZE
88
89 for(uint64 A = region_address; A < (uint64)region_address + region_size; A += FAST_MAP_PSIZE)
90 {
91 FastMap[A >> FAST_MAP_SHIFT] = ((uintptr_t)region_mem - region_address);
92 }
93 }
94
RecalcIPCache(void)95 INLINE void PS_CPU::RecalcIPCache(void)
96 {
97 IPCache = 0;
98
99 if((CP0.SR & CP0.CAUSE & 0xFF00) && (CP0.SR & 1))
100 IPCache = 0x80;
101
102 if(Halted)
103 IPCache = 0x80;
104 }
105
SetHalt(bool status)106 void PS_CPU::SetHalt(bool status)
107 {
108 Halted = status;
109 RecalcIPCache();
110 }
111
Power(void)112 void PS_CPU::Power(void)
113 {
114 assert(sizeof(ICache) == sizeof(ICache_Bulk));
115
116 memset(GPR, 0, sizeof(GPR));
117 memset(&CP0, 0, sizeof(CP0));
118 LO = 0;
119 HI = 0;
120
121 gte_ts_done = 0;
122 muldiv_ts_done = 0;
123
124 BACKED_PC = 0xBFC00000;
125 BACKED_new_PC = BACKED_PC + 4;
126 BDBT = 0;
127
128 BACKED_LDWhich = 0x20;
129 BACKED_LDValue = 0;
130 LDAbsorb = 0;
131 memset(ReadAbsorb, 0, sizeof(ReadAbsorb));
132 ReadAbsorbWhich = 0;
133 ReadFudge = 0;
134
135 CP0.SR |= (1 << 22); // BEV
136 CP0.SR |= (1 << 21); // TS
137
138 CP0.PRID = 0x2;
139
140 RecalcIPCache();
141
142
143 BIU = 0;
144
145 memset(ScratchRAM.data8, 0, 1024);
146
147 // Not quite sure about these poweron/reset values:
148 for(unsigned i = 0; i < 1024; i++)
149 {
150 ICache[i].TV = 0x2 | ((BIU & 0x800) ? 0x0 : 0x1);
151 ICache[i].Data = 0;
152 }
153
154 GTE_Power();
155 }
156
StateAction(StateMem * sm,const unsigned load,const bool data_only)157 void PS_CPU::StateAction(StateMem *sm, const unsigned load, const bool data_only)
158 {
159 uint32 OPM = BDBT;
160
161 SFORMAT StateRegs[] =
162 {
163 SFPTR32(GPR, 32),
164 SFVAR(LO),
165 SFVAR(HI),
166 SFVAR(BACKED_PC),
167 SFVAR(BACKED_new_PC),
168 SFVARN(OPM, "BACKED_new_PC_mask"),
169
170 SFVAR(IPCache),
171 SFVAR(Halted),
172
173 SFVAR(BACKED_LDWhich),
174 SFVAR(BACKED_LDValue),
175 SFVAR(LDAbsorb),
176
177 SFVAR(next_event_ts),
178 SFVAR(gte_ts_done),
179 SFVAR(muldiv_ts_done),
180
181 SFVAR(BIU),
182 SFVAR(ICache_Bulk),
183
184 SFVAR(CP0.Regs),
185
186 SFPTR8(ReadAbsorb, 0x20),
187 SFVARN(ReadAbsorb[0x20], "ReadAbsorbDummy"),
188 SFVAR(ReadAbsorbWhich),
189 SFVAR(ReadFudge),
190
191 SFPTR8(ScratchRAM.data8, 1024),
192
193 SFEND
194 };
195 MDFNSS_StateAction(sm, load, data_only, StateRegs, "CPU");
196
197 GTE_StateAction(sm, load, data_only);
198
199 if(load)
200 {
201 if(load < 0x939)
202 {
203 //
204 // For compatibility with pre-0.9.39 save states.
205 //
206 uint32 NOPM = ~OPM;
207
208 //printf("Old: new_PC=0x%08x, new_PC_mask=0x%08x\n", BACKED_new_PC, OPM);
209
210 BDBT = ((NOPM << 1) | (NOPM >> 1)) & 0x3;
211
212 BACKED_new_PC = (BACKED_PC & OPM) + BACKED_new_PC;
213 }
214 else
215 BDBT = OPM;
216
217 ReadAbsorbWhich &= 0x1F;
218 BACKED_LDWhich %= 0x21;
219
220 //printf("PC=0x%08x, new_PC=0x%08x, BDBT=0x%02x\n", BACKED_PC, BACKED_new_PC, BDBT);
221 }
222 }
223
AssertIRQ(unsigned which,bool asserted)224 void PS_CPU::AssertIRQ(unsigned which, bool asserted)
225 {
226 assert(which <= 5);
227
228 CP0.CAUSE &= ~(1 << (10 + which));
229
230 if(asserted)
231 CP0.CAUSE |= 1 << (10 + which);
232
233 RecalcIPCache();
234 }
235
SetBIU(uint32 val)236 void PS_CPU::SetBIU(uint32 val)
237 {
238 const uint32 old_BIU = BIU;
239
240 BIU = val & ~(0x440);
241
242 if((BIU ^ old_BIU) & 0x800)
243 {
244 if(BIU & 0x800) // ICache enabled
245 {
246 for(unsigned i = 0; i < 1024; i++)
247 ICache[i].TV &= ~0x1;
248 }
249 else // ICache disabled
250 {
251 for(unsigned i = 0; i < 1024; i++)
252 ICache[i].TV |= 0x1;
253 }
254 }
255
256 PSX_DBG(PSX_DBG_SPARSE, "[CPU] Set BIU=0x%08x\n", BIU);
257 }
258
GetBIU(void)259 uint32 PS_CPU::GetBIU(void)
260 {
261 return BIU;
262 }
263
264 template<typename T>
PeekMemory(uint32 address)265 INLINE T PS_CPU::PeekMemory(uint32 address)
266 {
267 T ret;
268 address &= addr_mask[address >> 29];
269
270 if(address >= 0x1F800000 && address <= 0x1F8003FF)
271 return ScratchRAM.Read<T>(address & 0x3FF);
272
273 //assert(!(CP0.SR & 0x10000));
274
275 if(sizeof(T) == 1)
276 ret = PSX_MemPeek8(address);
277 else if(sizeof(T) == 2)
278 ret = PSX_MemPeek16(address);
279 else
280 ret = PSX_MemPeek32(address);
281
282 return(ret);
283 }
284
285 template<typename T>
PokeMemory(uint32 address,T value)286 void PS_CPU::PokeMemory(uint32 address, T value)
287 {
288 address &= addr_mask[address >> 29];
289
290 if(address >= 0x1F800000 && address <= 0x1F8003FF)
291 return ScratchRAM.Write<T>(address & 0x3FF, value);
292
293 if(sizeof(T) == 1)
294 PSX_MemPoke8(address, value);
295 else if(sizeof(T) == 2)
296 PSX_MemPoke16(address, value);
297 else
298 PSX_MemPoke32(address, value);
299 }
300
301 template<typename T>
ReadMemory(pscpu_timestamp_t & timestamp,uint32 address,bool DS24,bool LWC_timing)302 INLINE T PS_CPU::ReadMemory(pscpu_timestamp_t ×tamp, uint32 address, bool DS24, bool LWC_timing)
303 {
304 T ret;
305
306 ReadAbsorb[ReadAbsorbWhich] = 0;
307 ReadAbsorbWhich = 0;
308
309 #if 0
310 if(MDFN_UNLIKELY(CP0.SR & 0x10000))
311 {
312 uint32 tmp = 0; // TODO(someday): = open bus
313
314 LDAbsorb = 0;
315
316 if(BIU & (BIU_TAG_TEST_MODE | BIU_INVALIDATE_MODE | BIU_LOCK_MODE))
317 {
318 if(BIU & BIU_TAG_TEST_MODE)
319 {
320 const __ICache* const ICI = &ICache[((address & 0xFF0) >> 2)];
321
322 tmp &= ~0x3F; // bits 0-3 validity, bit 4 tag compare match, bit 5 forced to 0(lock bit apparently unimplemented in the PS1).
323
324 //
325 // Get validity bits.
326 //
327 for(unsigned i = 0; i < 4; i++)
328 tmp |= (!(ICI[i].TV & 0x02)) << i;
329
330 //
331 // Tag compare.
332 //
333 if(!((address ^ ICI[0].TV) & 0xFFFFF000))
334 tmp |= 0x10;
335 }
336 }
337 else
338 {
339 tmp = ICache[(address & 0xFFC) >> 2].Data;
340 }
341
342 return tmp >> ((address & 0x3) * 8);
343 }
344 #endif
345 //
346 //
347 //
348
349 address &= addr_mask[address >> 29];
350
351 if(address >= 0x1F800000 && address <= 0x1F8003FF)
352 {
353 LDAbsorb = 0;
354
355 if(DS24)
356 return ScratchRAM.ReadU24(address & 0x3FF);
357 else
358 return ScratchRAM.Read<T>(address & 0x3FF);
359 }
360
361 timestamp += (ReadFudge >> 4) & 2;
362
363 //assert(!(CP0.SR & 0x10000));
364
365 pscpu_timestamp_t lts = timestamp;
366
367 if(sizeof(T) == 1)
368 ret = PSX_MemRead8(lts, address);
369 else if(sizeof(T) == 2)
370 ret = PSX_MemRead16(lts, address);
371 else
372 {
373 if(DS24)
374 ret = PSX_MemRead24(lts, address) & 0xFFFFFF;
375 else
376 ret = PSX_MemRead32(lts, address);
377 }
378
379 if(LWC_timing)
380 lts += 1;
381 else
382 lts += 2;
383
384 LDAbsorb = (lts - timestamp);
385 timestamp = lts;
386
387 return(ret);
388 }
389
390 template<typename T>
WriteMemory(pscpu_timestamp_t & timestamp,uint32 address,uint32 value,bool DS24)391 INLINE void PS_CPU::WriteMemory(pscpu_timestamp_t ×tamp, uint32 address, uint32 value, bool DS24)
392 {
393 if(MDFN_LIKELY(!(CP0.SR & 0x10000)))
394 {
395 address &= addr_mask[address >> 29];
396
397 if(address >= 0x1F800000 && address <= 0x1F8003FF)
398 {
399 if(DS24)
400 ScratchRAM.WriteU24(address & 0x3FF, value);
401 else
402 ScratchRAM.Write<T>(address & 0x3FF, value);
403
404 return;
405 }
406
407 if(sizeof(T) == 1)
408 PSX_MemWrite8(timestamp, address, value);
409 else if(sizeof(T) == 2)
410 PSX_MemWrite16(timestamp, address, value);
411 else
412 {
413 if(DS24)
414 PSX_MemWrite24(timestamp, address, value);
415 else
416 PSX_MemWrite32(timestamp, address, value);
417 }
418 }
419 else
420 {
421 if(BIU & BIU_ENABLE_ICACHE_S1) // Instruction cache is enabled/active
422 {
423 if(BIU & (BIU_TAG_TEST_MODE | BIU_INVALIDATE_MODE | BIU_LOCK_MODE))
424 {
425 const uint8 valid_bits = (BIU & BIU_TAG_TEST_MODE) ? ((value << ((address & 0x3) * 8)) & 0x0F) : 0x00;
426 __ICache* const ICI = &ICache[((address & 0xFF0) >> 2)];
427
428 //
429 // Set validity bits and tag.
430 //
431 for(unsigned i = 0; i < 4; i++)
432 ICI[i].TV = ((valid_bits & (1U << i)) ? 0x00 : 0x02) | (address & 0xFFFFFFF0) | (i << 2);
433 }
434 else
435 {
436 ICache[(address & 0xFFC) >> 2].Data = value << ((address & 0x3) * 8);
437 }
438 }
439
440 if((BIU & 0x081) == 0x080) // Writes to the scratchpad(TODO test)
441 {
442 if(DS24)
443 ScratchRAM.WriteU24(address & 0x3FF, value);
444 else
445 ScratchRAM.Write<T>(address & 0x3FF, value);
446 }
447 //printf("IsC WRITE%d 0x%08x 0x%08x -- CP0.SR=0x%08x\n", (int)sizeof(T), address, value, CP0.SR);
448 }
449 }
450
451 //
452 // ICache emulation here is not very accurate. More accurate emulation had about a 6% performance penalty for simple
453 // code that just looped infinitely, with no tangible known benefit for commercially-released games.
454 //
455 // We do emulate the tag test mode functionality in regards to loading custom tag, valid bits, and instruction word data, as it could
456 // hypothetically be useful for homebrew. However, due to inaccuracies, it's possible to load a tag for an address in the non-cached
457 // 0xA0000000-0xBFFFFFFF range, jump to the address, and have it execute out of instruction cache, which is wrong and not possible on a PS1.
458 //
459 // The other major inaccuracy here is how the region 0x80000000-0x9FFFFFFF is handled. On a PS1, when fetching instruction word data
460 // from this region, the upper bit is forced to 0 before the tag compare(though the tag compare IS a full 20 bit compare),
461 // 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,
462 // so in addition to the tag test mode implications, a program that jumps from somewhere in 0x00000000-0x1FFFFFFF to the corresponding
463 // location in 0x80000000-0x9FFFFFFF will always cause a cache miss in Mednafen.
464 //
465 // 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
466 // 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
467 // addresses?) to cache when a cache miss occurs on an address that isn't aligned to a 4-word boundary.
468 // 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
469 // the valid bits(when the tag matches, of course), but is obviously not very efficient unless running code that's just endless branching.
470 //
ReadInstruction(pscpu_timestamp_t & timestamp,uint32 address)471 INLINE uint32 PS_CPU::ReadInstruction(pscpu_timestamp_t ×tamp, uint32 address)
472 {
473 uint32 instr;
474
475 instr = ICache[(address & 0xFFC) >> 2].Data;
476
477 if(ICache[(address & 0xFFC) >> 2].TV != address)
478 {
479 ReadAbsorb[ReadAbsorbWhich] = 0;
480 ReadAbsorbWhich = 0;
481
482 if(address >= 0xA0000000 || !(BIU & 0x800))
483 {
484 instr = MDFN_de32lsb<true>((uint8*)(FastMap[address >> FAST_MAP_SHIFT] + address));
485 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).
486 }
487 else
488 {
489 __ICache *ICI = &ICache[((address & 0xFF0) >> 2)];
490 const uint8 *FMP = (uint8*)(FastMap[(address & 0xFFFFFFF0) >> FAST_MAP_SHIFT] + (address & 0xFFFFFFF0));
491
492 // | 0x2 to simulate (in)validity bits.
493 ICI[0x00].TV = (address & 0xFFFFFFF0) | 0x0 | 0x2;
494 ICI[0x01].TV = (address & 0xFFFFFFF0) | 0x4 | 0x2;
495 ICI[0x02].TV = (address & 0xFFFFFFF0) | 0x8 | 0x2;
496 ICI[0x03].TV = (address & 0xFFFFFFF0) | 0xC | 0x2;
497
498 timestamp += 3;
499
500 switch(address & 0xC)
501 {
502 case 0x0:
503 timestamp++;
504 ICI[0x00].TV &= ~0x2;
505 ICI[0x00].Data = MDFN_de32lsb<true>(&FMP[0x0]);
506 case 0x4:
507 timestamp++;
508 ICI[0x01].TV &= ~0x2;
509 ICI[0x01].Data = MDFN_de32lsb<true>(&FMP[0x4]);
510 case 0x8:
511 timestamp++;
512 ICI[0x02].TV &= ~0x2;
513 ICI[0x02].Data = MDFN_de32lsb<true>(&FMP[0x8]);
514 case 0xC:
515 timestamp++;
516 ICI[0x03].TV &= ~0x2;
517 ICI[0x03].Data = MDFN_de32lsb<true>(&FMP[0xC]);
518 break;
519 }
520 instr = ICache[(address & 0xFFC) >> 2].Data;
521 }
522 }
523
524 return instr;
525 }
526
Exception(uint32 code,uint32 PC,const uint32 NP,const uint32 instr)527 uint32 NO_INLINE PS_CPU::Exception(uint32 code, uint32 PC, const uint32 NP, const uint32 instr)
528 {
529 uint32 handler = 0x80000080;
530
531 assert(code < 16);
532
533 if(code != EXCEPTION_INT && code != EXCEPTION_BP && code != EXCEPTION_SYSCALL)
534 {
535 static const char* exmne[16] =
536 {
537 "INT", "MOD", "TLBL", "TLBS", "ADEL", "ADES", "IBE", "DBE", "SYSCALL", "BP", "RI", "COPU", "OV", NULL, NULL, NULL
538 };
539
540 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",
541 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));
542 }
543
544 if(CP0.SR & (1 << 22)) // BEV
545 handler = 0xBFC00180;
546
547 CP0.EPC = PC;
548 if(BDBT & 2)
549 {
550 CP0.EPC -= 4;
551 CP0.TAR = NP;
552 }
553
554 if(ADDBT)
555 ADDBT(PC, handler, true);
556
557 // "Push" IEc and KUc(so that the new IEc and KUc are 0)
558 CP0.SR = (CP0.SR & ~0x3F) | ((CP0.SR << 2) & 0x3F);
559
560 // Setup cause register
561 CP0.CAUSE &= 0x0000FF00;
562 CP0.CAUSE |= code << 2;
563
564 CP0.CAUSE |= BDBT << 30;
565 CP0.CAUSE |= (instr << 2) & (0x3 << 28); // CE
566
567 //
568 //
569 //
570 RecalcIPCache();
571
572 BDBT = 0;
573
574 return(handler);
575 }
576
577 #define BACKING_TO_ACTIVE \
578 PC = BACKED_PC; \
579 new_PC = BACKED_new_PC; \
580 LDWhich = BACKED_LDWhich; \
581 LDValue = BACKED_LDValue;
582
583 #define ACTIVE_TO_BACKING \
584 BACKED_PC = PC; \
585 BACKED_new_PC = new_PC; \
586 BACKED_LDWhich = LDWhich; \
587 BACKED_LDValue = LDValue;
588
589 //
590 // Should come before DO_LDS() so the EXP_ILL_CHECK() emulator debugging macro in GPR_DEP() will work properly.
591 //
592 #define GPR_DEPRES_BEGIN { uint8 back = ReadAbsorb[0];
593 #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); }) }
594 #define GPR_RES(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; }
595 #define GPR_DEPRES_END ReadAbsorb[0] = back; }
596
597 template<bool DebugMode, bool BIOSPrintMode, bool ILHMode>
RunReal(pscpu_timestamp_t timestamp_in)598 pscpu_timestamp_t PS_CPU::RunReal(pscpu_timestamp_t timestamp_in)
599 {
600 pscpu_timestamp_t timestamp = timestamp_in;
601
602 uint32 PC;
603 uint32 new_PC;
604 uint32 LDWhich;
605 uint32 LDValue;
606
607 //printf("%d %d\n", gte_ts_done, muldiv_ts_done);
608
609 gte_ts_done += timestamp;
610 muldiv_ts_done += timestamp;
611
612 BACKING_TO_ACTIVE;
613
614 do
615 {
616 //printf("Running: %d %d\n", timestamp, next_event_ts);
617 while(MDFN_LIKELY(timestamp < next_event_ts))
618 {
619 uint32 instr;
620 uint32 opf;
621
622 // Zero must be zero...until the Master Plan is enacted.
623 GPR[0] = 0;
624
625 if(DebugMode && CPUHook)
626 {
627 ACTIVE_TO_BACKING;
628
629 // For save states in step mode.
630 gte_ts_done -= timestamp;
631 muldiv_ts_done -= timestamp;
632
633 CPUHook(timestamp, PC);
634
635 // For save states in step mode.
636 gte_ts_done += timestamp;
637 muldiv_ts_done += timestamp;
638
639 BACKING_TO_ACTIVE;
640 }
641
642 if(BIOSPrintMode)
643 {
644 if(PC == 0xB0)
645 {
646 if(MDFN_UNLIKELY(GPR[9] == 0x3D))
647 {
648 PSX_DBG_BIOS_PUTC(GPR[4]);
649 }
650 }
651 }
652
653 //
654 // Instruction fetch
655 //
656 if(MDFN_UNLIKELY(PC & 0x3))
657 {
658 // This will block interrupt processing, but since we're going more for keeping broken homebrew/hacks from working
659 // than super-duper-accurate pipeline emulation, it shouldn't be a problem.
660 CP0.BADA = PC;
661 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, 0);
662 goto OpDone;
663 }
664
665 instr = ReadInstruction(timestamp, PC);
666
667
668 //
669 // Instruction decode
670 //
671 opf = instr & 0x3F;
672
673 if(instr & (0x3F << 26))
674 opf = 0x40 | (instr >> 26);
675
676 opf |= IPCache;
677
678 if(ReadAbsorb[ReadAbsorbWhich])
679 ReadAbsorb[ReadAbsorbWhich]--;
680 else
681 timestamp++;
682
683 #define DO_LDS() { GPR[LDWhich] = LDValue; ReadAbsorb[LDWhich] = LDAbsorb; ReadFudge = LDWhich; ReadAbsorbWhich |= LDWhich & 0x1F; LDWhich = 0x20; }
684 #define BEGIN_OPF(name) { op_##name:
685 #define END_OPF goto OpDone; }
686
687 #define DO_BRANCH(arg_cond, arg_offset, arg_mask, arg_dolink, arg_linkreg)\
688 { \
689 const bool cond = (arg_cond); \
690 const uint32 offset = (arg_offset); \
691 const uint32 mask = (arg_mask); \
692 const uint32 old_PC = PC; \
693 \
694 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);}) \
695 \
696 PC = new_PC; \
697 new_PC += 4; \
698 BDBT = 2; \
699 \
700 if(arg_dolink) \
701 GPR[(arg_linkreg)] = new_PC; \
702 \
703 if(cond) \
704 { \
705 if(ILHMode) \
706 { \
707 if(old_PC == (((new_PC - 4) & mask) + offset)) \
708 { \
709 if(MDFN_densb<uint32, true>((uint8*)(FastMap[PC >> FAST_MAP_SHIFT] + PC)) == 0) \
710 { \
711 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. */ \
712 { \
713 timestamp = next_event_ts; \
714 } \
715 } \
716 } \
717 } \
718 \
719 new_PC = ((new_PC - 4) & mask) + offset; \
720 BDBT = 3; \
721 \
722 if(DebugMode && ADDBT) \
723 { \
724 ADDBT(PC, new_PC, false); \
725 } \
726 } \
727 \
728 goto SkipNPCStuff; \
729 }
730
731 #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);*/
732 #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);*/
733 #define JTYPE uint32 target = instr & ((1 << 26) - 1); /*printf(" target=(%08x) ", target);*/
734 #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]);*/
735
736 #if HAVE_COMPUTED_GOTO
737 #if 0
738 //
739 // 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
740 // 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).
741 //
742 #define CGBEGIN static const uint32 const op_goto_table[256] = {
743 #define CGE(l) (uint32)(uintptr_t)&&l,
744 #define CGEND }; goto *(void*)(uintptr_t)op_goto_table[opf];
745 #else
746 #define CGBEGIN static const void *const op_goto_table[256] = {
747 #define CGE(l) &&l,
748 #define CGEND }; goto *op_goto_table[opf];
749 #endif
750 #else
751 /* (uint8) cast for cheaper alternative to generated branch+compare bounds check instructions, but still more
752 expensive than computed goto which needs no masking nor bounds checking.
753 */
754 #define CGBEGIN { enum { CGESB = 1 + __COUNTER__ }; switch((uint8)opf) {
755 #define CGE(l) case __COUNTER__ - CGESB: goto l;
756 #define CGEND } }
757 #endif
758
759 CGBEGIN
760 CGE(op_SLL) CGE(op_ILL) CGE(op_SRL) CGE(op_SRA) CGE(op_SLLV) CGE(op_ILL) CGE(op_SRLV) CGE(op_SRAV)
761 CGE(op_JR) CGE(op_JALR) CGE(op_ILL) CGE(op_ILL) CGE(op_SYSCALL) CGE(op_BREAK) CGE(op_ILL) CGE(op_ILL)
762 CGE(op_MFHI) CGE(op_MTHI) CGE(op_MFLO) CGE(op_MTLO) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
763 CGE(op_MULT) CGE(op_MULTU) CGE(op_DIV) CGE(op_DIVU) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
764 CGE(op_ADD) CGE(op_ADDU) CGE(op_SUB) CGE(op_SUBU) CGE(op_AND) CGE(op_OR) CGE(op_XOR) CGE(op_NOR)
765 CGE(op_ILL) CGE(op_ILL) CGE(op_SLT) CGE(op_SLTU) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
766 CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
767 CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
768
769 CGE(op_ILL) CGE(op_BCOND) CGE(op_J) CGE(op_JAL) CGE(op_BEQ) CGE(op_BNE) CGE(op_BLEZ) CGE(op_BGTZ)
770 CGE(op_ADDI) CGE(op_ADDIU) CGE(op_SLTI) CGE(op_SLTIU) CGE(op_ANDI) CGE(op_ORI) CGE(op_XORI) CGE(op_LUI)
771 CGE(op_COP0) CGE(op_COP13) CGE(op_COP2) CGE(op_COP13) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
772 CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
773 CGE(op_LB) CGE(op_LH) CGE(op_LWL) CGE(op_LW) CGE(op_LBU) CGE(op_LHU) CGE(op_LWR) CGE(op_ILL)
774 CGE(op_SB) CGE(op_SH) CGE(op_SWL) CGE(op_SW) CGE(op_ILL) CGE(op_ILL) CGE(op_SWR) CGE(op_ILL)
775 CGE(op_LWC013) CGE(op_LWC013) CGE(op_LWC2) CGE(op_LWC013) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
776 CGE(op_SWC013) CGE(op_SWC013) CGE(op_SWC2) CGE(op_SWC013) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
777
778 // Interrupt portion of this table is constructed so that an interrupt won't be taken when the PC is pointing to a GTE instruction,
779 // to avoid problems caused by pipeline vs coprocessor nuances that aren't emulated.
780 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
781 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
782 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
783 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
784 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
785 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
786 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
787 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
788
789 CGE(op_ILL) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
790 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
791 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_COP2) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
792 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
793 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
794 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
795 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
796 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
797 CGEND
798
799 {
800 BEGIN_OPF(ILL);
801 DO_LDS();
802 new_PC = Exception(EXCEPTION_RI, PC, new_PC, instr);
803 END_OPF;
804
805 //
806 // ADD - Add Word
807 //
808 BEGIN_OPF(ADD);
809 RTYPE;
810
811 GPR_DEPRES_BEGIN
812 GPR_DEP(rs);
813 GPR_DEP(rt);
814 GPR_RES(rd);
815 GPR_DEPRES_END
816
817 uint32 result = GPR[rs] + GPR[rt];
818 bool ep = ((~(GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000;
819
820 DO_LDS();
821
822 if(MDFN_UNLIKELY(ep))
823 {
824 new_PC = Exception(EXCEPTION_OV, PC, new_PC, instr);
825 }
826 else
827 GPR[rd] = result;
828
829 END_OPF;
830
831 //
832 // ADDI - Add Immediate Word
833 //
834 BEGIN_OPF(ADDI);
835 ITYPE;
836
837 GPR_DEPRES_BEGIN
838 GPR_DEP(rs);
839 GPR_RES(rt);
840 GPR_DEPRES_END
841
842 uint32 result = GPR[rs] + immediate;
843 bool ep = ((~(GPR[rs] ^ immediate)) & (GPR[rs] ^ result)) & 0x80000000;
844
845 DO_LDS();
846
847 if(MDFN_UNLIKELY(ep))
848 {
849 new_PC = Exception(EXCEPTION_OV, PC, new_PC, instr);
850 }
851 else
852 GPR[rt] = result;
853
854 END_OPF;
855
856 //
857 // ADDIU - Add Immediate Unsigned Word
858 //
859 BEGIN_OPF(ADDIU);
860 ITYPE;
861
862 GPR_DEPRES_BEGIN
863 GPR_DEP(rs);
864 GPR_RES(rt);
865 GPR_DEPRES_END
866
867 uint32 result = GPR[rs] + immediate;
868
869 DO_LDS();
870
871 GPR[rt] = result;
872
873 END_OPF;
874
875 //
876 // ADDU - Add Unsigned Word
877 //
878 BEGIN_OPF(ADDU);
879 RTYPE;
880
881 GPR_DEPRES_BEGIN
882 GPR_DEP(rs);
883 GPR_DEP(rt);
884 GPR_RES(rd);
885 GPR_DEPRES_END
886
887 uint32 result = GPR[rs] + GPR[rt];
888
889 DO_LDS();
890
891 GPR[rd] = result;
892
893 END_OPF;
894
895 //
896 // AND - And
897 //
898 BEGIN_OPF(AND);
899 RTYPE;
900
901 GPR_DEPRES_BEGIN
902 GPR_DEP(rs);
903 GPR_DEP(rt);
904 GPR_RES(rd);
905 GPR_DEPRES_END
906
907 uint32 result = GPR[rs] & GPR[rt];
908
909 DO_LDS();
910
911 GPR[rd] = result;
912
913 END_OPF;
914
915 //
916 // ANDI - And Immediate
917 //
918 BEGIN_OPF(ANDI);
919 ITYPE_ZE;
920
921 GPR_DEPRES_BEGIN
922 GPR_DEP(rs);
923 GPR_RES(rt);
924 GPR_DEPRES_END
925
926 uint32 result = GPR[rs] & immediate;
927
928 DO_LDS();
929
930 GPR[rt] = result;
931
932 END_OPF;
933
934 //
935 // BEQ - Branch on Equal
936 //
937 BEGIN_OPF(BEQ);
938 ITYPE;
939
940 GPR_DEPRES_BEGIN
941 GPR_DEP(rs);
942 GPR_DEP(rt);
943 GPR_DEPRES_END
944
945 const bool result = (GPR[rs] == GPR[rt]);
946
947 DO_LDS();
948
949 DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
950 END_OPF;
951
952 // Bah, why does MIPS encoding have to be funky like this. :(
953 // Handles BGEZ, BGEZAL, BLTZ, BLTZAL
954 BEGIN_OPF(BCOND);
955 const uint32 tv = GPR[(instr >> 21) & 0x1F];
956 const uint32 riv = (instr >> 16) & 0x1F;
957 const uint32 immediate = (int32)(int16)(instr & 0xFFFF);
958 const bool result = (int32)(tv ^ (riv << 31)) < 0;
959 const uint32 link = ((riv & 0x1E) == 0x10) ? 31 : 0;
960
961 GPR_DEPRES_BEGIN
962 GPR_DEP((instr >> 21) & 0x1F);
963 GPR_RES(link);
964 GPR_DEPRES_END
965
966 DO_LDS();
967
968 DO_BRANCH(result, (immediate << 2), ~0U, true, link);
969 END_OPF;
970
971
972 //
973 // BGTZ - Branch on Greater than Zero
974 //
975 BEGIN_OPF(BGTZ);
976 ITYPE;
977
978 GPR_DEPRES_BEGIN
979 GPR_DEP(rs);
980 GPR_DEPRES_END
981
982 const bool result = (int32)GPR[rs] > 0;
983
984 DO_LDS();
985
986 DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
987 END_OPF;
988
989 //
990 // BLEZ - Branch on Less Than or Equal to Zero
991 //
992 BEGIN_OPF(BLEZ);
993 ITYPE;
994
995 GPR_DEPRES_BEGIN
996 GPR_DEP(rs);
997 GPR_DEPRES_END
998
999 const bool result = (int32)GPR[rs] <= 0;
1000
1001 DO_LDS();
1002
1003 DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1004 END_OPF;
1005
1006 //
1007 // BNE - Branch on Not Equal
1008 //
1009 BEGIN_OPF(BNE);
1010 ITYPE;
1011
1012 GPR_DEPRES_BEGIN
1013 GPR_DEP(rs);
1014 GPR_DEP(rt);
1015 GPR_DEPRES_END
1016
1017 const bool result = GPR[rs] != GPR[rt];
1018
1019 DO_LDS();
1020
1021 DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1022 END_OPF;
1023
1024 //
1025 // BREAK - Breakpoint
1026 //
1027 BEGIN_OPF(BREAK);
1028 DO_LDS();
1029 new_PC = Exception(EXCEPTION_BP, PC, new_PC, instr);
1030 END_OPF;
1031
1032 // Cop "instructions": CFCz(no CP0), COPz, CTCz(no CP0), LWCz(no CP0), MFCz, MTCz, SWCz(no CP0)
1033 //
1034 // COP0 instructions
1035 //
1036 BEGIN_OPF(COP0);
1037 const uint32 sub_op = (instr >> 21) & 0x1F;
1038 const uint32 rt = (instr >> 16) & 0x1F;
1039 const uint32 rd = (instr >> 11) & 0x1F;
1040 const uint32 val = GPR[rt];
1041
1042 switch(sub_op)
1043 {
1044 default:
1045 DO_LDS();
1046 break;
1047
1048 case 0x02:
1049 case 0x06:
1050 DO_LDS();
1051 new_PC = Exception(EXCEPTION_RI, PC, new_PC, instr);
1052 break;
1053
1054 case 0x00: // MFC0 - Move from Coprocessor
1055 switch(rd)
1056 {
1057 case 0x00:
1058 case 0x01:
1059 case 0x02:
1060 case 0x04:
1061 case 0x0A:
1062 DO_LDS();
1063 new_PC = Exception(EXCEPTION_RI, PC, new_PC, instr);
1064 break;
1065
1066 case 0x03:
1067 case 0x05:
1068 case 0x06:
1069 case 0x07:
1070 case 0x08:
1071 case 0x09:
1072 case 0x0B:
1073 case 0x0C:
1074 case 0x0D:
1075 case 0x0E:
1076 case 0x0F:
1077 if(MDFN_UNLIKELY(LDWhich == rt))
1078 LDWhich = 0;
1079
1080 DO_LDS();
1081
1082 LDAbsorb = 0;
1083 LDWhich = rt;
1084 LDValue = CP0.Regs[rd];
1085 break;
1086
1087 default:
1088 // Tested to be rather NOPish
1089 DO_LDS();
1090 PSX_DBG(PSX_DBG_WARNING, "[CPU] MFC0 from unmapped CP0 register %u.\n", rd);
1091 break;
1092 }
1093 break;
1094
1095 case 0x04: // MTC0 - Move to Coprocessor
1096 DO_LDS();
1097 switch(rd)
1098 {
1099 case 0x00:
1100 case 0x01:
1101 case 0x02:
1102 case 0x04:
1103 case 0x0A:
1104 new_PC = Exception(EXCEPTION_RI, PC, new_PC, instr);
1105 break;
1106
1107 case CP0REG_BPC:
1108 CP0.BPC = val;
1109 break;
1110
1111 case CP0REG_BDA:
1112 CP0.BDA = val;
1113 break;
1114
1115 case CP0REG_DCIC:
1116 if(val)
1117 {
1118 PSX_DBG(PSX_DBG_WARNING, "[CPU] Non-zero write to DCIC: 0x%08x\n", val);
1119 }
1120 CP0.DCIC = val & 0xFF80003F;
1121 break;
1122
1123 case CP0REG_BDAM:
1124 CP0.BDAM = val;
1125 break;
1126
1127 case CP0REG_BPCM:
1128 CP0.BPCM = val;
1129 break;
1130
1131 case CP0REG_CAUSE:
1132 CP0.CAUSE &= ~(0x3 << 8);
1133 CP0.CAUSE |= val & (0x3 << 8);
1134 RecalcIPCache();
1135 break;
1136
1137 case CP0REG_SR:
1138 CP0.SR = val & ~( (0x3 << 26) | (0x3 << 23) | (0x3 << 6));
1139 RecalcIPCache();
1140 break;
1141 }
1142 break;
1143
1144 case 0x08: // BC
1145 case 0x0C:
1146 DO_LDS();
1147 {
1148 const uint32 immediate = (int32)(int16)(instr & 0xFFFF);
1149 const bool result = (false == (bool)(instr & (1U << 16)));
1150
1151 PSX_DBG(PSX_DBG_WARNING, "[CPU] BC0x instruction(0x%08x) @ PC=0x%08x\n", instr, PC);
1152
1153 DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1154 }
1155 break;
1156
1157 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1158 case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1159 DO_LDS();
1160 {
1161 const uint32 cp0_op = instr & 0x1F; // Not 0x3F
1162
1163 if(MDFN_LIKELY(cp0_op == 0x10)) // RFE
1164 {
1165 // "Pop"
1166 CP0.SR = (CP0.SR & ~0x0F) | ((CP0.SR >> 2) & 0x0F);
1167 RecalcIPCache();
1168 }
1169 else if(cp0_op == 0x01 || cp0_op == 0x02 || cp0_op == 0x06 || cp0_op == 0x08) // TLBR, TLBWI, TLBWR, TLBP
1170 {
1171 new_PC = Exception(EXCEPTION_RI, PC, new_PC, instr);
1172 }
1173 }
1174 break;
1175 }
1176 END_OPF;
1177
1178 //
1179 // COP2
1180 //
1181 BEGIN_OPF(COP2);
1182 const uint32 sub_op = (instr >> 21) & 0x1F;
1183 const uint32 rt = (instr >> 16) & 0x1F;
1184 const uint32 rd = (instr >> 11) & 0x1F;
1185 const uint32 val = GPR[rt];
1186
1187 if(MDFN_UNLIKELY(!(CP0.SR & (1U << (28 + 2)))))
1188 {
1189 DO_LDS();
1190 new_PC = Exception(EXCEPTION_COPU, PC, new_PC, instr);
1191 }
1192 else switch(sub_op)
1193 {
1194 default:
1195 DO_LDS();
1196 break;
1197
1198 case 0x00: // MFC2 - Move from Coprocessor
1199 if(MDFN_UNLIKELY(LDWhich == rt))
1200 LDWhich = 0;
1201
1202 DO_LDS();
1203
1204 if(timestamp < gte_ts_done)
1205 {
1206 LDAbsorb = gte_ts_done - timestamp;
1207 timestamp = gte_ts_done;
1208 }
1209 else
1210 LDAbsorb = 0;
1211
1212 LDWhich = rt;
1213 LDValue = GTE_ReadDR(rd);
1214 break;
1215
1216 case 0x04: // MTC2 - Move to Coprocessor
1217 DO_LDS();
1218
1219 if(timestamp < gte_ts_done)
1220 timestamp = gte_ts_done;
1221
1222 GTE_WriteDR(rd, val);
1223 break;
1224
1225 case 0x02: // CFC2
1226 if(MDFN_UNLIKELY(LDWhich == rt))
1227 LDWhich = 0;
1228
1229 DO_LDS();
1230
1231 if(timestamp < gte_ts_done)
1232 {
1233 LDAbsorb = gte_ts_done - timestamp;
1234 timestamp = gte_ts_done;
1235 }
1236 else
1237 LDAbsorb = 0;
1238
1239 LDWhich = rt;
1240 LDValue = GTE_ReadCR(rd);
1241 break;
1242
1243 case 0x06: // CTC2
1244 DO_LDS();
1245
1246 if(timestamp < gte_ts_done)
1247 timestamp = gte_ts_done;
1248
1249 GTE_WriteCR(rd, val);
1250 break;
1251
1252 case 0x08:
1253 case 0x0C:
1254 DO_LDS();
1255 {
1256 const uint32 immediate = (int32)(int16)(instr & 0xFFFF);
1257 const bool result = (false == (bool)(instr & (1U << 16)));
1258
1259 PSX_DBG(PSX_DBG_WARNING, "[CPU] BC2x instruction(0x%08x) @ PC=0x%08x\n", instr, PC);
1260
1261 DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1262 }
1263 break;
1264
1265 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
1266 case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F:
1267 DO_LDS();
1268
1269 if(timestamp < gte_ts_done)
1270 timestamp = gte_ts_done;
1271 gte_ts_done = timestamp + GTE_Instruction(instr);
1272 break;
1273 }
1274 END_OPF;
1275
1276 //
1277 // COP1, COP3
1278 //
1279 BEGIN_OPF(COP13);
1280 DO_LDS();
1281
1282 if(!(CP0.SR & (1U << (28 + ((instr >> 26) & 0x3)))))
1283 {
1284 new_PC = Exception(EXCEPTION_COPU, PC, new_PC, instr);
1285 }
1286 else
1287 {
1288 const uint32 sub_op = (instr >> 21) & 0x1F;
1289
1290 PSX_DBG(PSX_DBG_WARNING, "[CPU] COP%u instruction(0x%08x) @ PC=0x%08x\n", (instr >> 26) & 0x3, instr, PC);
1291
1292 if(sub_op == 0x08 || sub_op == 0x0C)
1293 {
1294 const uint32 immediate = (int32)(int16)(instr & 0xFFFF);
1295 const bool result = (false == (bool)(instr & (1U << 16)));
1296
1297 DO_BRANCH(result, (immediate << 2), ~0U, false, 0);
1298 }
1299 }
1300 END_OPF;
1301
1302 //
1303 // LWC0, LWC1, LWC3
1304 //
1305 BEGIN_OPF(LWC013);
1306 ITYPE;
1307 const uint32 address = GPR[rs] + immediate;
1308
1309 DO_LDS();
1310
1311 if(!(CP0.SR & (1U << (28 + ((instr >> 26) & 0x3)))))
1312 {
1313 new_PC = Exception(EXCEPTION_COPU, PC, new_PC, instr);
1314 }
1315 else
1316 {
1317 if(MDFN_UNLIKELY(address & 3))
1318 {
1319 CP0.BADA = address;
1320 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, instr);
1321 }
1322 else
1323 {
1324 PSX_DBG(PSX_DBG_WARNING, "[CPU] LWC%u instruction(0x%08x) @ PC=0x%08x\n", (instr >> 26) & 0x3, instr, PC);
1325
1326 ReadMemory<uint32>(timestamp, address, false, true);
1327 }
1328 }
1329 END_OPF;
1330
1331 //
1332 // LWC2
1333 //
1334 BEGIN_OPF(LWC2);
1335 ITYPE;
1336 const uint32 address = GPR[rs] + immediate;
1337
1338 DO_LDS();
1339
1340 if(MDFN_UNLIKELY(address & 3))
1341 {
1342 CP0.BADA = address;
1343 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, instr);
1344 }
1345 else
1346 {
1347 if(timestamp < gte_ts_done)
1348 timestamp = gte_ts_done;
1349
1350 GTE_WriteDR(rt, ReadMemory<uint32>(timestamp, address, false, true));
1351 }
1352 // GTE stuff here
1353 END_OPF;
1354
1355 //
1356 // SWC0, SWC1, SCW3
1357 //
1358 BEGIN_OPF(SWC013);
1359 ITYPE;
1360 const uint32 address = GPR[rs] + immediate;
1361
1362 DO_LDS();
1363
1364 if(!(CP0.SR & (1U << (28 + ((instr >> 26) & 0x3)))))
1365 {
1366 new_PC = Exception(EXCEPTION_COPU, PC, new_PC, instr);
1367 }
1368 else
1369 {
1370 if(MDFN_UNLIKELY(address & 0x3))
1371 {
1372 CP0.BADA = address;
1373 new_PC = Exception(EXCEPTION_ADES, PC, new_PC, instr);
1374 }
1375 else
1376 {
1377 PSX_DBG(PSX_DBG_WARNING, "[CPU] SWC%u instruction(0x%08x) @ PC=0x%08x\n", (instr >> 26) & 0x3, instr, PC);
1378 //WriteMemory<uint32>(timestamp, address, SOMETHING);
1379 }
1380 }
1381 END_OPF;
1382
1383 //
1384 // SWC2
1385 //
1386 BEGIN_OPF(SWC2);
1387 ITYPE;
1388 const uint32 address = GPR[rs] + immediate;
1389
1390 if(MDFN_UNLIKELY(address & 0x3))
1391 {
1392 CP0.BADA = address;
1393 new_PC = Exception(EXCEPTION_ADES, PC, new_PC, instr);
1394 }
1395 else
1396 {
1397 if(timestamp < gte_ts_done)
1398 timestamp = gte_ts_done;
1399
1400 WriteMemory<uint32>(timestamp, address, GTE_ReadDR(rt));
1401 }
1402 DO_LDS();
1403 END_OPF;
1404
1405 //
1406 // DIV - Divide Word
1407 //
1408 BEGIN_OPF(DIV);
1409 RTYPE;
1410
1411 GPR_DEPRES_BEGIN
1412 GPR_DEP(rs);
1413 GPR_DEP(rt);
1414 GPR_DEPRES_END
1415
1416 if(!GPR[rt])
1417 {
1418 if(GPR[rs] & 0x80000000)
1419 LO = 1;
1420 else
1421 LO = 0xFFFFFFFF;
1422
1423 HI = GPR[rs];
1424 }
1425 else if(GPR[rs] == 0x80000000 && GPR[rt] == 0xFFFFFFFF)
1426 {
1427 LO = 0x80000000;
1428 HI = 0;
1429 }
1430 else
1431 {
1432 LO = (int32)GPR[rs] / (int32)GPR[rt];
1433 HI = (int32)GPR[rs] % (int32)GPR[rt];
1434 }
1435 muldiv_ts_done = timestamp + 37;
1436
1437 DO_LDS();
1438
1439 END_OPF;
1440
1441
1442 //
1443 // DIVU - Divide Unsigned Word
1444 //
1445 BEGIN_OPF(DIVU);
1446 RTYPE;
1447
1448 GPR_DEPRES_BEGIN
1449 GPR_DEP(rs);
1450 GPR_DEP(rt);
1451 GPR_DEPRES_END
1452
1453 if(!GPR[rt])
1454 {
1455 LO = 0xFFFFFFFF;
1456 HI = GPR[rs];
1457 }
1458 else
1459 {
1460 LO = GPR[rs] / GPR[rt];
1461 HI = GPR[rs] % GPR[rt];
1462 }
1463 muldiv_ts_done = timestamp + 37;
1464
1465 DO_LDS();
1466 END_OPF;
1467
1468 //
1469 // J - Jump
1470 //
1471 BEGIN_OPF(J);
1472 JTYPE;
1473
1474 DO_LDS();
1475
1476 DO_BRANCH(true, target << 2, 0xF0000000, false, 0);
1477 END_OPF;
1478
1479 //
1480 // JAL - Jump and Link
1481 //
1482 BEGIN_OPF(JAL);
1483 JTYPE;
1484
1485 //GPR_DEPRES_BEGIN
1486 GPR_RES(31);
1487 //GPR_DEPRES_END
1488
1489 DO_LDS();
1490
1491 DO_BRANCH(true, target << 2, 0xF0000000, true, 31);
1492 END_OPF;
1493
1494 //
1495 // JALR - Jump and Link Register
1496 //
1497 BEGIN_OPF(JALR);
1498 RTYPE;
1499
1500 GPR_DEPRES_BEGIN
1501 GPR_DEP(rs);
1502 GPR_RES(rd);
1503 GPR_DEPRES_END
1504
1505 uint32 tmp = GPR[rs];
1506
1507 DO_LDS();
1508
1509 DO_BRANCH(true, tmp, 0, true, rd);
1510 END_OPF;
1511
1512 //
1513 // JR - Jump Register
1514 //
1515 BEGIN_OPF(JR);
1516 RTYPE;
1517
1518 GPR_DEPRES_BEGIN
1519 GPR_DEP(rs);
1520 GPR_RES(rd);
1521 GPR_DEPRES_END
1522
1523 uint32 bt = GPR[rs];
1524
1525 DO_LDS();
1526
1527 DO_BRANCH(true, bt, 0, false, 0);
1528 END_OPF;
1529
1530 //
1531 // LUI - Load Upper Immediate
1532 //
1533 BEGIN_OPF(LUI);
1534 ITYPE_ZE; // Actually, probably would be sign-extending...if we were emulating a 64-bit MIPS chip :b
1535
1536 GPR_DEPRES_BEGIN
1537 GPR_RES(rt);
1538 GPR_DEPRES_END
1539
1540 DO_LDS();
1541
1542 GPR[rt] = immediate << 16;
1543
1544 END_OPF;
1545
1546 //
1547 // MFHI - Move from HI
1548 //
1549 BEGIN_OPF(MFHI);
1550 RTYPE;
1551
1552 GPR_DEPRES_BEGIN
1553 GPR_RES(rd);
1554 GPR_DEPRES_END
1555
1556 DO_LDS();
1557
1558 if(timestamp < muldiv_ts_done)
1559 {
1560 if(timestamp == muldiv_ts_done - 1)
1561 muldiv_ts_done--;
1562 else
1563 {
1564 do
1565 {
1566 if(ReadAbsorb[ReadAbsorbWhich])
1567 ReadAbsorb[ReadAbsorbWhich]--;
1568 timestamp++;
1569 } while(timestamp < muldiv_ts_done);
1570 }
1571 }
1572
1573 GPR[rd] = HI;
1574
1575 END_OPF;
1576
1577
1578 //
1579 // MFLO - Move from LO
1580 //
1581 BEGIN_OPF(MFLO);
1582 RTYPE;
1583
1584 GPR_DEPRES_BEGIN
1585 GPR_RES(rd);
1586 GPR_DEPRES_END
1587
1588 DO_LDS();
1589
1590 if(timestamp < muldiv_ts_done)
1591 {
1592 if(timestamp == muldiv_ts_done - 1)
1593 muldiv_ts_done--;
1594 else
1595 {
1596 do
1597 {
1598 if(ReadAbsorb[ReadAbsorbWhich])
1599 ReadAbsorb[ReadAbsorbWhich]--;
1600 timestamp++;
1601 } while(timestamp < muldiv_ts_done);
1602 }
1603 }
1604
1605 GPR[rd] = LO;
1606
1607 END_OPF;
1608
1609
1610 //
1611 // MTHI - Move to HI
1612 //
1613 BEGIN_OPF(MTHI);
1614 RTYPE;
1615
1616 GPR_DEPRES_BEGIN
1617 GPR_DEP(rs);
1618 GPR_DEPRES_END
1619
1620 HI = GPR[rs];
1621
1622 DO_LDS();
1623
1624 END_OPF;
1625
1626 //
1627 // MTLO - Move to LO
1628 //
1629 BEGIN_OPF(MTLO);
1630 RTYPE;
1631
1632 GPR_DEPRES_BEGIN
1633 GPR_DEP(rs);
1634 GPR_DEPRES_END
1635
1636 LO = GPR[rs];
1637
1638 DO_LDS();
1639
1640 END_OPF;
1641
1642
1643 //
1644 // MULT - Multiply Word
1645 //
1646 BEGIN_OPF(MULT);
1647 RTYPE;
1648
1649 GPR_DEPRES_BEGIN
1650 GPR_DEP(rs);
1651 GPR_DEP(rt);
1652 GPR_DEPRES_END
1653
1654 uint64 result;
1655
1656 result = (int64)(int32)GPR[rs] * (int32)GPR[rt];
1657 muldiv_ts_done = timestamp + MULT_Tab24[MDFN_lzcount32((GPR[rs] ^ ((int32)GPR[rs] >> 31)) | 0x400)];
1658 DO_LDS();
1659
1660 LO = result;
1661 HI = result >> 32;
1662
1663 END_OPF;
1664
1665 //
1666 // MULTU - Multiply Unsigned Word
1667 //
1668 BEGIN_OPF(MULTU);
1669 RTYPE;
1670
1671 GPR_DEPRES_BEGIN
1672 GPR_DEP(rs);
1673 GPR_DEP(rt);
1674 GPR_DEPRES_END
1675
1676 uint64 result;
1677
1678 result = (uint64)GPR[rs] * GPR[rt];
1679 muldiv_ts_done = timestamp + MULT_Tab24[MDFN_lzcount32(GPR[rs] | 0x400)];
1680 DO_LDS();
1681
1682 LO = result;
1683 HI = result >> 32;
1684
1685 END_OPF;
1686
1687
1688 //
1689 // NOR - NOR
1690 //
1691 BEGIN_OPF(NOR);
1692 RTYPE;
1693
1694 GPR_DEPRES_BEGIN
1695 GPR_DEP(rs);
1696 GPR_DEP(rt);
1697 GPR_RES(rd);
1698 GPR_DEPRES_END
1699
1700 uint32 result = ~(GPR[rs] | GPR[rt]);
1701
1702 DO_LDS();
1703
1704 GPR[rd] = result;
1705
1706 END_OPF;
1707
1708 //
1709 // OR - OR
1710 //
1711 BEGIN_OPF(OR);
1712 RTYPE;
1713
1714 GPR_DEPRES_BEGIN
1715 GPR_DEP(rs);
1716 GPR_DEP(rt);
1717 GPR_RES(rd);
1718 GPR_DEPRES_END
1719
1720 uint32 result = GPR[rs] | GPR[rt];
1721
1722 DO_LDS();
1723
1724 GPR[rd] = result;
1725
1726 END_OPF;
1727
1728
1729 //
1730 // ORI - OR Immediate
1731 //
1732 BEGIN_OPF(ORI);
1733 ITYPE_ZE;
1734
1735 GPR_DEPRES_BEGIN
1736 GPR_DEP(rs);
1737 GPR_RES(rt);
1738 GPR_DEPRES_END
1739
1740 uint32 result = GPR[rs] | immediate;
1741
1742 DO_LDS();
1743
1744 GPR[rt] = result;
1745
1746 END_OPF;
1747
1748
1749 //
1750 // SLL - Shift Word Left Logical
1751 //
1752 BEGIN_OPF(SLL); // SLL
1753 RTYPE;
1754
1755 GPR_DEPRES_BEGIN
1756 GPR_DEP(rt);
1757 GPR_RES(rd);
1758 GPR_DEPRES_END
1759
1760 uint32 result = GPR[rt] << shamt;
1761
1762 DO_LDS();
1763
1764 GPR[rd] = result;
1765
1766 END_OPF;
1767
1768
1769 //
1770 // SLLV - Shift Word Left Logical Variable
1771 //
1772 BEGIN_OPF(SLLV);
1773 RTYPE;
1774
1775 GPR_DEPRES_BEGIN
1776 GPR_DEP(rs);
1777 GPR_DEP(rt);
1778 GPR_RES(rd);
1779 GPR_DEPRES_END
1780
1781 uint32 result = GPR[rt] << (GPR[rs] & 0x1F);
1782
1783 DO_LDS();
1784
1785 GPR[rd] = result;
1786
1787 END_OPF;
1788
1789 //
1790 // SLT - Set on Less Than
1791 //
1792 BEGIN_OPF(SLT);
1793 RTYPE;
1794
1795 GPR_DEPRES_BEGIN
1796 GPR_DEP(rs);
1797 GPR_DEP(rt);
1798 GPR_RES(rd);
1799 GPR_DEPRES_END
1800
1801 uint32 result = (bool)((int32)GPR[rs] < (int32)GPR[rt]);
1802
1803 DO_LDS();
1804
1805 GPR[rd] = result;
1806
1807 END_OPF;
1808
1809
1810 //
1811 // SLTI - Set on Less Than Immediate
1812 //
1813 BEGIN_OPF(SLTI);
1814 ITYPE;
1815
1816 GPR_DEPRES_BEGIN
1817 GPR_DEP(rs);
1818 GPR_RES(rt);
1819 GPR_DEPRES_END
1820
1821 uint32 result = (bool)((int32)GPR[rs] < (int32)immediate);
1822
1823 DO_LDS();
1824
1825 GPR[rt] = result;
1826
1827 END_OPF;
1828
1829
1830 //
1831 // SLTIU - Set on Less Than Immediate, Unsigned
1832 //
1833 BEGIN_OPF(SLTIU);
1834 ITYPE;
1835
1836 GPR_DEPRES_BEGIN
1837 GPR_DEP(rs);
1838 GPR_RES(rt);
1839 GPR_DEPRES_END
1840
1841 uint32 result = (bool)(GPR[rs] < (uint32)immediate);
1842
1843 DO_LDS();
1844
1845 GPR[rt] = result;
1846
1847 END_OPF;
1848
1849
1850 //
1851 // SLTU - Set on Less Than, Unsigned
1852 //
1853 BEGIN_OPF(SLTU);
1854 RTYPE;
1855
1856 GPR_DEPRES_BEGIN
1857 GPR_DEP(rs);
1858 GPR_DEP(rt);
1859 GPR_RES(rd);
1860 GPR_DEPRES_END
1861
1862 uint32 result = (bool)(GPR[rs] < GPR[rt]);
1863
1864 DO_LDS();
1865
1866 GPR[rd] = result;
1867
1868 END_OPF;
1869
1870
1871 //
1872 // SRA - Shift Word Right Arithmetic
1873 //
1874 BEGIN_OPF(SRA);
1875 RTYPE;
1876
1877 GPR_DEPRES_BEGIN
1878 GPR_DEP(rt);
1879 GPR_RES(rd);
1880 GPR_DEPRES_END
1881
1882 uint32 result = ((int32)GPR[rt]) >> shamt;
1883
1884 DO_LDS();
1885
1886 GPR[rd] = result;
1887
1888 END_OPF;
1889
1890
1891 //
1892 // SRAV - Shift Word Right Arithmetic Variable
1893 //
1894 BEGIN_OPF(SRAV);
1895 RTYPE;
1896
1897 GPR_DEPRES_BEGIN
1898 GPR_DEP(rs);
1899 GPR_DEP(rt);
1900 GPR_RES(rd);
1901 GPR_DEPRES_END
1902
1903 uint32 result = ((int32)GPR[rt]) >> (GPR[rs] & 0x1F);
1904
1905 DO_LDS();
1906
1907 GPR[rd] = result;
1908
1909 END_OPF;
1910
1911
1912 //
1913 // SRL - Shift Word Right Logical
1914 //
1915 BEGIN_OPF(SRL);
1916 RTYPE;
1917
1918 GPR_DEPRES_BEGIN
1919 GPR_DEP(rt);
1920 GPR_RES(rd);
1921 GPR_DEPRES_END
1922
1923 uint32 result = GPR[rt] >> shamt;
1924
1925 DO_LDS();
1926
1927 GPR[rd] = result;
1928
1929 END_OPF;
1930
1931 //
1932 // SRLV - Shift Word Right Logical Variable
1933 //
1934 BEGIN_OPF(SRLV);
1935 RTYPE;
1936
1937 GPR_DEPRES_BEGIN
1938 GPR_DEP(rs);
1939 GPR_DEP(rt);
1940 GPR_RES(rd);
1941 GPR_DEPRES_END
1942
1943 uint32 result = GPR[rt] >> (GPR[rs] & 0x1F);
1944
1945 DO_LDS();
1946
1947 GPR[rd] = result;
1948
1949 END_OPF;
1950
1951
1952 //
1953 // SUB - Subtract Word
1954 //
1955 BEGIN_OPF(SUB);
1956 RTYPE;
1957
1958 GPR_DEPRES_BEGIN
1959 GPR_DEP(rs);
1960 GPR_DEP(rt);
1961 GPR_RES(rd);
1962 GPR_DEPRES_END
1963
1964 uint32 result = GPR[rs] - GPR[rt];
1965 bool ep = (((GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000;
1966
1967 DO_LDS();
1968
1969 if(MDFN_UNLIKELY(ep))
1970 {
1971 new_PC = Exception(EXCEPTION_OV, PC, new_PC, instr);
1972 }
1973 else
1974 GPR[rd] = result;
1975
1976 END_OPF;
1977
1978
1979 //
1980 // SUBU - Subtract Unsigned Word
1981 //
1982 BEGIN_OPF(SUBU);
1983 RTYPE;
1984
1985 GPR_DEPRES_BEGIN
1986 GPR_DEP(rs);
1987 GPR_DEP(rt);
1988 GPR_RES(rd);
1989 GPR_DEPRES_END
1990
1991 uint32 result = GPR[rs] - GPR[rt];
1992
1993 DO_LDS();
1994
1995 GPR[rd] = result;
1996
1997 END_OPF;
1998
1999
2000 //
2001 // SYSCALL
2002 //
2003 BEGIN_OPF(SYSCALL);
2004 DO_LDS();
2005
2006 new_PC = Exception(EXCEPTION_SYSCALL, PC, new_PC, instr);
2007 END_OPF;
2008
2009
2010 //
2011 // XOR
2012 //
2013 BEGIN_OPF(XOR);
2014 RTYPE;
2015
2016 GPR_DEPRES_BEGIN
2017 GPR_DEP(rs);
2018 GPR_DEP(rt);
2019 GPR_RES(rd);
2020 GPR_DEPRES_END
2021
2022 uint32 result = GPR[rs] ^ GPR[rt];
2023
2024 DO_LDS();
2025
2026 GPR[rd] = result;
2027
2028 END_OPF;
2029
2030 //
2031 // XORI - Exclusive OR Immediate
2032 //
2033 BEGIN_OPF(XORI);
2034 ITYPE_ZE;
2035
2036 GPR_DEPRES_BEGIN
2037 GPR_DEP(rs);
2038 GPR_RES(rt);
2039 GPR_DEPRES_END
2040
2041 uint32 result = GPR[rs] ^ immediate;
2042
2043 DO_LDS();
2044
2045 GPR[rt] = result;
2046 END_OPF;
2047
2048 //
2049 // Memory access instructions(besides the coprocessor ones) follow:
2050 //
2051
2052 //
2053 // LB - Load Byte
2054 //
2055 BEGIN_OPF(LB);
2056 ITYPE;
2057
2058 GPR_DEPRES_BEGIN
2059 GPR_DEP(rs);
2060 GPR_DEPRES_END
2061
2062 uint32 address = GPR[rs] + immediate;
2063
2064 if(MDFN_UNLIKELY(LDWhich == rt))
2065 LDWhich = 0;
2066
2067 DO_LDS();
2068
2069 LDWhich = rt;
2070 LDValue = (int32)ReadMemory<int8>(timestamp, address);
2071 END_OPF;
2072
2073 //
2074 // LBU - Load Byte Unsigned
2075 //
2076 BEGIN_OPF(LBU);
2077 ITYPE;
2078
2079 GPR_DEPRES_BEGIN
2080 GPR_DEP(rs);
2081 GPR_DEPRES_END
2082
2083 uint32 address = GPR[rs] + immediate;
2084
2085 if(MDFN_UNLIKELY(LDWhich == rt))
2086 LDWhich = 0;
2087
2088 DO_LDS();
2089
2090 LDWhich = rt;
2091 LDValue = ReadMemory<uint8>(timestamp, address);
2092 END_OPF;
2093
2094 //
2095 // LH - Load Halfword
2096 //
2097 BEGIN_OPF(LH);
2098 ITYPE;
2099
2100 GPR_DEPRES_BEGIN
2101 GPR_DEP(rs);
2102 GPR_DEPRES_END
2103
2104 uint32 address = GPR[rs] + immediate;
2105
2106 if(MDFN_UNLIKELY(address & 1))
2107 {
2108 DO_LDS();
2109
2110 CP0.BADA = address;
2111 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, instr);
2112 }
2113 else
2114 {
2115 if(MDFN_UNLIKELY(LDWhich == rt))
2116 LDWhich = 0;
2117
2118 DO_LDS();
2119
2120 LDWhich = rt;
2121 LDValue = (int32)ReadMemory<int16>(timestamp, address);
2122 }
2123 END_OPF;
2124
2125 //
2126 // LHU - Load Halfword Unsigned
2127 //
2128 BEGIN_OPF(LHU);
2129 ITYPE;
2130
2131 GPR_DEPRES_BEGIN
2132 GPR_DEP(rs);
2133 GPR_DEPRES_END
2134
2135 uint32 address = GPR[rs] + immediate;
2136
2137 if(MDFN_UNLIKELY(address & 1))
2138 {
2139 DO_LDS();
2140
2141 CP0.BADA = address;
2142 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, instr);
2143 }
2144 else
2145 {
2146 if(MDFN_UNLIKELY(LDWhich == rt))
2147 LDWhich = 0;
2148
2149 DO_LDS();
2150
2151 LDWhich = rt;
2152 LDValue = ReadMemory<uint16>(timestamp, address);
2153 }
2154 END_OPF;
2155
2156
2157 //
2158 // LW - Load Word
2159 //
2160 BEGIN_OPF(LW);
2161 ITYPE;
2162
2163 GPR_DEPRES_BEGIN
2164 GPR_DEP(rs);
2165 GPR_DEPRES_END
2166
2167 uint32 address = GPR[rs] + immediate;
2168
2169 if(MDFN_UNLIKELY(address & 3))
2170 {
2171 DO_LDS();
2172
2173 CP0.BADA = address;
2174 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC, instr);
2175 }
2176 else
2177 {
2178 if(MDFN_UNLIKELY(LDWhich == rt))
2179 LDWhich = 0;
2180
2181 DO_LDS();
2182
2183 LDWhich = rt;
2184 LDValue = ReadMemory<uint32>(timestamp, address);
2185 }
2186 END_OPF;
2187
2188 //
2189 // SB - Store Byte
2190 //
2191 BEGIN_OPF(SB);
2192 ITYPE;
2193
2194 GPR_DEPRES_BEGIN
2195 GPR_DEP(rs);
2196 GPR_DEP(rt);
2197 GPR_DEPRES_END
2198
2199 uint32 address = GPR[rs] + immediate;
2200
2201 WriteMemory<uint8>(timestamp, address, GPR[rt]);
2202
2203 DO_LDS();
2204 END_OPF;
2205
2206 //
2207 // SH - Store Halfword
2208 //
2209 BEGIN_OPF(SH);
2210 ITYPE;
2211
2212 GPR_DEPRES_BEGIN
2213 GPR_DEP(rs);
2214 GPR_DEP(rt);
2215 GPR_DEPRES_END
2216
2217 uint32 address = GPR[rs] + immediate;
2218
2219 if(MDFN_UNLIKELY(address & 0x1))
2220 {
2221 CP0.BADA = address;
2222 new_PC = Exception(EXCEPTION_ADES, PC, new_PC, instr);
2223 }
2224 else
2225 WriteMemory<uint16>(timestamp, address, GPR[rt]);
2226
2227 DO_LDS();
2228 END_OPF;
2229
2230 //
2231 // SW - Store Word
2232 //
2233 BEGIN_OPF(SW);
2234 ITYPE;
2235
2236 GPR_DEPRES_BEGIN
2237 GPR_DEP(rs);
2238 GPR_DEP(rt);
2239 GPR_DEPRES_END
2240
2241 uint32 address = GPR[rs] + immediate;
2242
2243 if(MDFN_UNLIKELY(address & 0x3))
2244 {
2245 CP0.BADA = address;
2246 new_PC = Exception(EXCEPTION_ADES, PC, new_PC, instr);
2247 }
2248 else
2249 WriteMemory<uint32>(timestamp, address, GPR[rt]);
2250
2251 DO_LDS();
2252 END_OPF;
2253
2254 // 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)
2255
2256 //
2257 // LWL - Load Word Left
2258 //
2259 BEGIN_OPF(LWL);
2260 ITYPE;
2261
2262 GPR_DEPRES_BEGIN
2263 GPR_DEP(rs);
2264 //GPR_DEP(rt);
2265 GPR_DEPRES_END
2266
2267 uint32 address = GPR[rs] + immediate;
2268 uint32 v = GPR[rt];
2269
2270 if(LDWhich == rt)
2271 {
2272 v = LDValue;
2273 ReadFudge = 0;
2274 }
2275 else
2276 {
2277 DO_LDS();
2278 }
2279
2280 LDWhich = rt;
2281 switch(address & 0x3)
2282 {
2283 case 0: LDValue = (v & ~(0xFF << 24)) | (ReadMemory<uint8>(timestamp, address & ~3) << 24);
2284 break;
2285
2286 case 1: LDValue = (v & ~(0xFFFF << 16)) | (ReadMemory<uint16>(timestamp, address & ~3) << 16);
2287 break;
2288
2289 case 2: LDValue = (v & ~(0xFFFFFF << 8)) | (ReadMemory<uint32>(timestamp, address & ~3, true) << 8);
2290 break;
2291
2292 case 3: LDValue = (v & ~(0xFFFFFFFF << 0)) | (ReadMemory<uint32>(timestamp, address & ~3) << 0);
2293 break;
2294 }
2295 END_OPF;
2296
2297 //
2298 // SWL - Store Word Left
2299 //
2300 BEGIN_OPF(SWL);
2301 ITYPE;
2302
2303 GPR_DEPRES_BEGIN
2304 GPR_DEP(rs);
2305 GPR_DEP(rt);
2306 GPR_DEPRES_END
2307
2308 uint32 address = GPR[rs] + immediate;
2309
2310 switch(address & 0x3)
2311 {
2312 case 0: WriteMemory<uint8>(timestamp, address & ~3, GPR[rt] >> 24);
2313 break;
2314
2315 case 1: WriteMemory<uint16>(timestamp, address & ~3, GPR[rt] >> 16);
2316 break;
2317
2318 case 2: WriteMemory<uint32>(timestamp, address & ~3, GPR[rt] >> 8, true);
2319 break;
2320
2321 case 3: WriteMemory<uint32>(timestamp, address & ~3, GPR[rt] >> 0);
2322 break;
2323 }
2324 DO_LDS();
2325
2326 END_OPF;
2327
2328 //
2329 // LWR - Load Word Right
2330 //
2331 BEGIN_OPF(LWR);
2332 ITYPE;
2333
2334 GPR_DEPRES_BEGIN
2335 GPR_DEP(rs);
2336 //GPR_DEP(rt);
2337 GPR_DEPRES_END
2338
2339 uint32 address = GPR[rs] + immediate;
2340 uint32 v = GPR[rt];
2341
2342 if(LDWhich == rt)
2343 {
2344 v = LDValue;
2345 ReadFudge = 0;
2346 }
2347 else
2348 {
2349 DO_LDS();
2350 }
2351
2352 LDWhich = rt;
2353 switch(address & 0x3)
2354 {
2355 case 0: LDValue = (v & ~(0xFFFFFFFF)) | ReadMemory<uint32>(timestamp, address);
2356 break;
2357
2358 case 1: LDValue = (v & ~(0xFFFFFF)) | ReadMemory<uint32>(timestamp, address, true);
2359 break;
2360
2361 case 2: LDValue = (v & ~(0xFFFF)) | ReadMemory<uint16>(timestamp, address);
2362 break;
2363
2364 case 3: LDValue = (v & ~(0xFF)) | ReadMemory<uint8>(timestamp, address);
2365 break;
2366 }
2367 END_OPF;
2368
2369 //
2370 // SWR - Store Word Right
2371 //
2372 BEGIN_OPF(SWR);
2373 ITYPE;
2374
2375 GPR_DEPRES_BEGIN
2376 GPR_DEP(rs);
2377 GPR_DEP(rt);
2378 GPR_DEPRES_END
2379
2380 uint32 address = GPR[rs] + immediate;
2381
2382 switch(address & 0x3)
2383 {
2384 case 0: WriteMemory<uint32>(timestamp, address, GPR[rt]);
2385 break;
2386
2387 case 1: WriteMemory<uint32>(timestamp, address, GPR[rt], true);
2388 break;
2389
2390 case 2: WriteMemory<uint16>(timestamp, address, GPR[rt]);
2391 break;
2392
2393 case 3: WriteMemory<uint8>(timestamp, address, GPR[rt]);
2394 break;
2395 }
2396
2397 DO_LDS();
2398
2399 END_OPF;
2400
2401 //
2402 // Mednafen special instruction
2403 //
2404 BEGIN_OPF(INTERRUPT);
2405 if(Halted)
2406 {
2407 goto SkipNPCStuff;
2408 }
2409 else
2410 {
2411 DO_LDS();
2412
2413 new_PC = Exception(EXCEPTION_INT, PC, new_PC, instr);
2414 }
2415 END_OPF;
2416 }
2417
2418 OpDone: ;
2419 PC = new_PC;
2420 new_PC = new_PC + 4;
2421 BDBT = 0;
2422
2423 SkipNPCStuff: ;
2424
2425 //printf("\n");
2426 }
2427 } while(MDFN_LIKELY(PSX_EventHandler(timestamp)));
2428
2429 if(gte_ts_done > 0)
2430 gte_ts_done -= timestamp;
2431
2432 if(muldiv_ts_done > 0)
2433 muldiv_ts_done -= timestamp;
2434
2435 ACTIVE_TO_BACKING;
2436
2437 return(timestamp);
2438 }
2439
Run(pscpu_timestamp_t timestamp_in,bool BIOSPrintMode,bool ILHMode)2440 pscpu_timestamp_t PS_CPU::Run(pscpu_timestamp_t timestamp_in, bool BIOSPrintMode, bool ILHMode)
2441 {
2442 if(CPUHook || ADDBT)
2443 return(RunReal<true, true, false>(timestamp_in));
2444 else
2445 {
2446 if(ILHMode)
2447 return(RunReal<false, false, true>(timestamp_in));
2448 else
2449 {
2450 if(BIOSPrintMode)
2451 return(RunReal<false, true, false>(timestamp_in));
2452 else
2453 return(RunReal<false, false, false>(timestamp_in));
2454 }
2455 }
2456 }
2457
SetCPUHook(void (* cpuh)(const pscpu_timestamp_t timestamp,uint32 pc),void (* addbt)(uint32 from,uint32 to,bool exception))2458 void PS_CPU::SetCPUHook(void (*cpuh)(const pscpu_timestamp_t timestamp, uint32 pc), void (*addbt)(uint32 from, uint32 to, bool exception))
2459 {
2460 ADDBT = addbt;
2461 CPUHook = cpuh;
2462 }
2463
GetRegister(unsigned int which,char * special,const uint32 special_len)2464 uint32 PS_CPU::GetRegister(unsigned int which, char *special, const uint32 special_len)
2465 {
2466 uint32 ret = 0;
2467
2468 if(which >= GSREG_GPR && which < (GSREG_GPR + 32))
2469 ret = GPR[which];
2470 else switch(which)
2471 {
2472 case GSREG_PC:
2473 ret = BACKED_PC;
2474 break;
2475
2476 case GSREG_PC_NEXT:
2477 ret = BACKED_new_PC;
2478 break;
2479
2480 case GSREG_IN_BD_SLOT:
2481 ret = BDBT;
2482 break;
2483
2484 case GSREG_LO:
2485 ret = LO;
2486 break;
2487
2488 case GSREG_HI:
2489 ret = HI;
2490 break;
2491
2492 case GSREG_BPC:
2493 ret = CP0.BPC;
2494 break;
2495
2496 case GSREG_BDA:
2497 ret = CP0.BDA;
2498 break;
2499
2500 case GSREG_TAR:
2501 ret = CP0.TAR;
2502 break;
2503
2504 case GSREG_DCIC:
2505 ret = CP0.DCIC;
2506 break;
2507
2508 case GSREG_BADA:
2509 ret = CP0.BADA;
2510 break;
2511
2512 case GSREG_BDAM:
2513 ret = CP0.BDAM;
2514 break;
2515
2516 case GSREG_BPCM:
2517 ret = CP0.BPCM;
2518 break;
2519
2520 case GSREG_SR:
2521 ret = CP0.SR;
2522 break;
2523
2524 case GSREG_CAUSE:
2525 ret = CP0.CAUSE;
2526 if(special)
2527 {
2528 trio_snprintf(special, special_len, "BD: %u, BT: %u, CE: %u, IP: 0x%02x, Sw: %u, ExcCode: 0x%01x",
2529 (ret >> 31) & 1, (ret >> 30) & 1, (ret >> 28) & 3, (ret >> 10) & 0x3F, (ret >> 8) & 3, (ret >> 2) & 0xF);
2530 }
2531 break;
2532
2533 case GSREG_EPC:
2534 ret = CP0.EPC;
2535 break;
2536
2537 }
2538
2539 return(ret);
2540 }
2541
SetRegister(unsigned int which,uint32 value)2542 void PS_CPU::SetRegister(unsigned int which, uint32 value)
2543 {
2544 if(which >= GSREG_GPR && which < (GSREG_GPR + 32))
2545 {
2546 if(which != (GSREG_GPR + 0))
2547 GPR[which] = value;
2548 }
2549 else switch(which)
2550 {
2551 case GSREG_PC:
2552 BACKED_PC = value;
2553 break;
2554
2555 case GSREG_PC_NEXT:
2556 BACKED_new_PC = value;
2557 break;
2558
2559 case GSREG_IN_BD_SLOT:
2560 BDBT = value & 0x3;
2561 break;
2562
2563 case GSREG_LO:
2564 LO = value;
2565 break;
2566
2567 case GSREG_HI:
2568 HI = value;
2569 break;
2570
2571 case GSREG_SR:
2572 CP0.SR = value; // TODO: mask
2573 break;
2574
2575 case GSREG_CAUSE:
2576 CP0.CAUSE = value;
2577 break;
2578
2579 case GSREG_EPC:
2580 CP0.EPC = value & ~0x3U;
2581 break;
2582
2583
2584 }
2585 }
2586
PeekCheckICache(uint32 PC,uint32 * iw)2587 bool PS_CPU::PeekCheckICache(uint32 PC, uint32 *iw)
2588 {
2589 if(ICache[(PC & 0xFFC) >> 2].TV == PC)
2590 {
2591 *iw = ICache[(PC & 0xFFC) >> 2].Data;
2592 return(true);
2593 }
2594
2595 return(false);
2596 }
2597
2598
PeekMem8(uint32 A)2599 uint8 PS_CPU::PeekMem8(uint32 A)
2600 {
2601 return PeekMemory<uint8>(A);
2602 }
2603
PeekMem16(uint32 A)2604 uint16 PS_CPU::PeekMem16(uint32 A)
2605 {
2606 return PeekMemory<uint16>(A);
2607 }
2608
PeekMem32(uint32 A)2609 uint32 PS_CPU::PeekMem32(uint32 A)
2610 {
2611 return PeekMemory<uint32>(A);
2612 }
2613
PokeMem8(uint32 A,uint8 V)2614 void PS_CPU::PokeMem8(uint32 A, uint8 V)
2615 {
2616 PokeMemory<uint8>(A, V);
2617 }
2618
PokeMem16(uint32 A,uint16 V)2619 void PS_CPU::PokeMem16(uint32 A, uint16 V)
2620 {
2621 PokeMemory<uint16>(A, V);
2622 }
2623
PokeMem32(uint32 A,uint32 V)2624 void PS_CPU::PokeMem32(uint32 A, uint32 V)
2625 {
2626 PokeMemory<uint32>(A, V);
2627 }
2628
2629 #undef BEGIN_OPF
2630 #undef END_OPF
2631 #undef MK_OPF
2632
2633 #define MK_OPF(op, funct) ((op) ? (0x40 | (op)) : (funct))
2634 #define BEGIN_OPF(op, funct) case MK_OPF(op, funct): {
2635 #define END_OPF } break;
2636
2637 // 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)2638 void PS_CPU::CheckBreakpoints(void (*callback)(bool write, uint32 address, unsigned int len), uint32 instr)
2639 {
2640 uint32 opf;
2641
2642 opf = instr & 0x3F;
2643
2644 if(instr & (0x3F << 26))
2645 opf = 0x40 | (instr >> 26);
2646
2647
2648 switch(opf)
2649 {
2650 default:
2651 break;
2652
2653 //
2654 // LB - Load Byte
2655 //
2656 BEGIN_OPF(0x20, 0);
2657 ITYPE;
2658 uint32 address = GPR[rs] + immediate;
2659
2660 callback(false, address, 1);
2661 END_OPF;
2662
2663 //
2664 // LBU - Load Byte Unsigned
2665 //
2666 BEGIN_OPF(0x24, 0);
2667 ITYPE;
2668 uint32 address = GPR[rs] + immediate;
2669
2670 callback(false, address, 1);
2671 END_OPF;
2672
2673 //
2674 // LH - Load Halfword
2675 //
2676 BEGIN_OPF(0x21, 0);
2677 ITYPE;
2678 uint32 address = GPR[rs] + immediate;
2679
2680 callback(false, address, 2);
2681 END_OPF;
2682
2683 //
2684 // LHU - Load Halfword Unsigned
2685 //
2686 BEGIN_OPF(0x25, 0);
2687 ITYPE;
2688 uint32 address = GPR[rs] + immediate;
2689
2690 callback(false, address, 2);
2691 END_OPF;
2692
2693
2694 //
2695 // LW - Load Word
2696 //
2697 BEGIN_OPF(0x23, 0);
2698 ITYPE;
2699 uint32 address = GPR[rs] + immediate;
2700
2701 callback(false, address, 4);
2702 END_OPF;
2703
2704 //
2705 // SB - Store Byte
2706 //
2707 BEGIN_OPF(0x28, 0);
2708 ITYPE;
2709 uint32 address = GPR[rs] + immediate;
2710
2711 callback(true, address, 1);
2712 END_OPF;
2713
2714 //
2715 // SH - Store Halfword
2716 //
2717 BEGIN_OPF(0x29, 0);
2718 ITYPE;
2719 uint32 address = GPR[rs] + immediate;
2720
2721 callback(true, address, 2);
2722 END_OPF;
2723
2724 //
2725 // SW - Store Word
2726 //
2727 BEGIN_OPF(0x2B, 0);
2728 ITYPE;
2729 uint32 address = GPR[rs] + immediate;
2730
2731 callback(true, address, 4);
2732 END_OPF;
2733
2734 //
2735 // LWL - Load Word Left
2736 //
2737 BEGIN_OPF(0x22, 0);
2738 ITYPE;
2739 uint32 address = GPR[rs] + immediate;
2740
2741 do
2742 {
2743 callback(false, address, 1);
2744 } while((address--) & 0x3);
2745
2746 END_OPF;
2747
2748 //
2749 // SWL - Store Word Left
2750 //
2751 BEGIN_OPF(0x2A, 0);
2752 ITYPE;
2753 uint32 address = GPR[rs] + immediate;
2754
2755 do
2756 {
2757 callback(true, address, 1);
2758 } while((address--) & 0x3);
2759
2760 END_OPF;
2761
2762 //
2763 // LWR - Load Word Right
2764 //
2765 BEGIN_OPF(0x26, 0);
2766 ITYPE;
2767 uint32 address = GPR[rs] + immediate;
2768
2769 do
2770 {
2771 callback(false, address, 1);
2772 } while((++address) & 0x3);
2773
2774 END_OPF;
2775
2776 //
2777 // SWR - Store Word Right
2778 //
2779 BEGIN_OPF(0x2E, 0);
2780 ITYPE;
2781 uint32 address = GPR[rs] + immediate;
2782
2783 do
2784 {
2785 callback(true, address, 1);
2786 } while((++address) & 0x3);
2787
2788 END_OPF;
2789
2790 //
2791 // LWC2
2792 //
2793 BEGIN_OPF(0x32, 0);
2794 ITYPE;
2795 uint32 address = GPR[rs] + immediate;
2796
2797 callback(false, address, 4);
2798 END_OPF;
2799
2800 //
2801 // SWC2
2802 //
2803 BEGIN_OPF(0x3A, 0);
2804 ITYPE;
2805 uint32 address = GPR[rs] + immediate;
2806
2807 callback(true, address, 4);
2808 END_OPF;
2809
2810 }
2811 }
2812
2813
2814 }
2815