1 /******************************************************************************/
2 /* Mednafen Sony PS1 Emulation Module */
3 /******************************************************************************/
4 /* psx.cpp:
5 ** Copyright (C) 2011-2017 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 #include "psx.h"
23 #include "mdec.h"
24 #include "frontio.h"
25 #include "timer.h"
26 #include "sio.h"
27 #include "cdc.h"
28 #include "spu.h"
29 #include <mednafen/FileStream.h>
30 #include <mednafen/mempatcher.h>
31 #include <mednafen/PSFLoader.h>
32 #include <mednafen/player.h>
33 #include <mednafen/hash/sha256.h>
34 #include <mednafen/cheat_formats/psx.h>
35
36 #include <zlib.h>
37
38 MDFN_HIDE extern MDFNGI EmulatedPSX;
39
40 namespace MDFN_IEN_PSX
41 {
42
43 #if PSX_DBGPRINT_ENABLE
44 static unsigned psx_dbg_level = 0;
45
PSX_DBG_BIOS_PUTC(uint8 c)46 void PSX_DBG_BIOS_PUTC(uint8 c) noexcept
47 {
48 if(psx_dbg_level >= PSX_DBG_BIOS_PRINT)
49 {
50 if(c == 0x1B)
51 return;
52
53 fputc(c, stdout);
54
55 //if(c == '\n')
56 //{
57 // fputc('%', stdout);
58 // fputc(' ', stdout);
59 //}
60 fflush(stdout);
61 }
62 }
63
PSX_DBG(unsigned level,const char * format,...)64 void PSX_DBG(unsigned level, const char *format, ...) noexcept
65 {
66 if(psx_dbg_level >= level)
67 {
68 va_list ap;
69
70 va_start(ap, format);
71
72 trio_vprintf(format, ap);
73
74 va_end(ap);
75 }
76 }
77 #else
78 static unsigned const psx_dbg_level = 0;
79 #endif
80
81
82 struct MDFN_PseudoRNG // Based off(but not the same as) public-domain "JKISS" PRNG.
83 {
MDFN_PseudoRNGMDFN_IEN_PSX::MDFN_PseudoRNG84 MDFN_COLD MDFN_PseudoRNG()
85 {
86 ResetState();
87 }
88
RandU32MDFN_IEN_PSX::MDFN_PseudoRNG89 uint32 RandU32(void)
90 {
91 uint64 t;
92
93 x = 314527869 * x + 1234567;
94 y ^= y << 5; y ^= y >> 7; y ^= y << 22;
95 t = 4294584393ULL * z + c; c = t >> 32; z = t;
96 lcgo = (19073486328125ULL * lcgo) + 1;
97
98 return (x + y + z) ^ (lcgo >> 16);
99 }
100
RandU32MDFN_IEN_PSX::MDFN_PseudoRNG101 uint32 RandU32(uint32 mina, uint32 maxa)
102 {
103 const uint32 range_m1 = maxa - mina;
104 uint32 range_mask;
105 uint32 tmp;
106
107 range_mask = range_m1;
108 range_mask |= range_mask >> 1;
109 range_mask |= range_mask >> 2;
110 range_mask |= range_mask >> 4;
111 range_mask |= range_mask >> 8;
112 range_mask |= range_mask >> 16;
113
114 do
115 {
116 tmp = RandU32() & range_mask;
117 } while(tmp > range_m1);
118
119 return(mina + tmp);
120 }
121
ResetStateMDFN_IEN_PSX::MDFN_PseudoRNG122 MDFN_COLD void ResetState(void) // Must always reset to the same state.
123 {
124 x = 123456789;
125 y = 987654321;
126 z = 43219876;
127 c = 6543217;
128 lcgo = 0xDEADBEEFCAFEBABEULL;
129 }
130
131 uint32 x,y,z,c;
132 uint64 lcgo;
133 };
134
135 static MDFN_PseudoRNG PSX_PRNG;
136
PSX_GetRandU32(uint32 mina,uint32 maxa)137 uint32 PSX_GetRandU32(uint32 mina, uint32 maxa)
138 {
139 return PSX_PRNG.RandU32(mina, maxa);
140 }
141
142
143 class PSF1Loader : public PSFLoader
144 {
145 public:
146
147 PSF1Loader(VirtualFS* vfs, const std::string& dir_path, Stream *fp) MDFN_COLD;
148 virtual ~PSF1Loader() override MDFN_COLD;
149
150 virtual void HandleEXE(Stream* fp, bool ignore_pcsp = false) override MDFN_COLD;
151
152 PSFTags tags;
153 };
154
155 enum
156 {
157 REGION_JP = 0,
158 REGION_NA = 1,
159 REGION_EU = 2,
160 };
161
162 static const MDFNSetting_EnumList Region_List[] =
163 {
164 { "jp", REGION_JP, gettext_noop("Japan") },
165 { "na", REGION_NA, gettext_noop("North America") },
166 { "eu", REGION_EU, gettext_noop("Europe") },
167 { NULL, 0 },
168 };
169
170 static const struct
171 {
172 const char* version;
173 char hwrev; // Ostensibly, not sure where this information originally came from or if it has any use(considering it doesn't reflect all hardware changes).
174 unsigned region;
175 bool bad;
176 sha256_digest sd;
177 } BIOS_DB[] =
178 {
179 // 1.0J, 2.2D, 4.1A(W):
180 // Tolerant with regards to ISO-9660 system-area contents
181 //
182
183 { "1.0J", 'A', REGION_JP, false, "cfc1fc38eb442f6f80781452119e931bcae28100c1c97e7e6c5f2725bbb0f8bb"_sha256 },
184
185 { "1.1J", 'B', REGION_JP, false, "5eb3aee495937558312b83b54323d76a4a015190decd4051214f1b6df06ac34b"_sha256 },
186
187 { "2.0A", 'X', REGION_NA, false, "42e4124be7623e2e28b1db0d8d426539646faee49d74b71166d8ba5bd7c472ed"_sha256 }, // DTL
188 { "2.0E", 'B', REGION_EU, false, "0af2be3468d30b6018b3c3b0d98b8b64347e255e16d874d55f0363648973dbf0"_sha256 },
189
190 { "2.1J", 'B', REGION_JP, false, "6f71ca1e716da761dc53187bd39e00c213f566e55090708fd3e2b4b425c8c989"_sha256 },
191 { "2.1A", 'X', REGION_NA, false, "6ad5521d105a6b86741f1af8da2e6ea1c732d34459940618c70305a105e8ec10"_sha256 }, // DTL
192 { "2.1E", 'B', REGION_EU, false, "1efb0cfc5db8a8751a884c5312e9c6265ca1bc580dc0c2663eb2dea3bde9fcf7"_sha256 },
193
194 { "2.2J", 'B', REGION_JP, false, "0c8359870cbac0ea091f1c87f188cd332dcc709753b91cafd9fd44a4a6188197"_sha256 },
195 { "2.2J", 'B', REGION_JP, true, "8e0383171e67b33e60d5df6394c58843f3b11c7a0b97f3bfcc4319ac2d1f9d18"_sha256 }, // BAD! ! ! !
196 { "2.2A", 'B', REGION_NA, false, "71af94d1e47a68c11e8fdb9f8368040601514a42a5a399cda48c7d3bff1e99d3"_sha256 },
197 { "2.2E", 'B', REGION_EU, false, "3d06d2c469313c2a2128d24fe2e0c71ff99bc2032be89a829a62337187f500b7"_sha256 },
198 { "2.2D", 'X', REGION_JP, false, "4018749b3698b8694387beebcbabfb48470513066840f9441459ee4c9f0f39bc"_sha256 }, // DTL
199
200 { "3.0J", 'C', REGION_JP, false, "9c0421858e217805f4abe18698afea8d5aa36ff0727eb8484944e00eb5e7eadb"_sha256 },
201 { "3.0A", 'C', REGION_NA, false, "11052b6499e466bbf0a709b1f9cb6834a9418e66680387912451e971cf8a1fef"_sha256 },
202 { "3.0E", 'C', REGION_EU, false, "1faaa18fa820a0225e488d9f086296b8e6c46df739666093987ff7d8fd352c09"_sha256 },
203 { "3.0E", 'C', REGION_EU, true, "9e1f8fb4fa356a5ac29d7c7209626dcc1b3038c0e5a85b0e99d1db96926647ca"_sha256 }, // BAD! ! ! !
204
205 { "4.0J", 'C', REGION_JP, false, "e900504d1755f021f861b82c8258c5e6658c7b592f800cccd91f5d32ea380d28"_sha256 },
206
207 { "4.1A(W)",'C',REGION_JP,false, "b3aa63cf30c81e0a40641740f4a43e25fda0b21b792fa9aaef60ce1675761479"_sha256 }, // Weird
208 { "4.1A", 'C', REGION_NA, false, "39dcc1a0717036c9b6ac52fefd1ee7a57d3808e8cfbc755879fa685a0a738278"_sha256 },
209 { "4.1E", 'C', REGION_EU, false, "5e84a94818cf5282f4217591fefd88be36b9b174b3cc7cb0bcd75199beb450f1"_sha256 },
210
211 { "4.3J", 'C', REGION_JP, false, "b29b4b5fcddef369bd6640acacda0865e0366fcf7ea54e40b2f1a8178004f89a"_sha256},
212
213 { "4.4E", 'C', REGION_EU, false, "5c0166da24e27deaa82246de8ff0108267fe4bb59f6df0fdec50e05e62448ca4"_sha256 },
214
215 { "4.5A", 'C', REGION_NA, false, "aca9cbfa974b933646baad6556a867eca9b81ce65d8af343a7843f7775b9ffc8"_sha256 },
216 { "4.5E", 'C', REGION_EU, false, "42244b0c650821519751b7e77ad1d3222a0125e75586df2b4e84ba693b9809dc"_sha256 },
217 };
218
219 static sha256_digest BIOS_SHA256; // SHA-256 hash of the currently-loaded BIOS; used for save state sanity checks.
220 static PSF1Loader *psf_loader = NULL;
221 static std::vector<CDInterface*> *cdifs = NULL;
222 static std::vector<const char *> cdifs_scex_ids;
223
224 static uint64 Memcard_PrevDC[8];
225 static int64 Memcard_SaveDelay[8];
226
227 PS_CPU *CPU = NULL;
228 PS_SPU *SPU = NULL;
229 PS_CDC *CDC = NULL;
230 static FrontIO *FIO = NULL;
231
232 static MultiAccessSizeMem<512 * 1024, false> *BIOSROM = NULL;
233 static MultiAccessSizeMem<65536, false> *PIOMem = NULL;
234
235 MultiAccessSizeMem<2048 * 1024, false> MainRAM;
236
237 static uint32 TextMem_Start;
238 static std::vector<uint8> TextMem;
239
240 static const uint32 SysControl_Mask[9] = { 0x00ffffff, 0x00ffffff, 0xffffffff, 0x2f1fffff,
241 0xffffffff, 0x2f1fffff, 0x2f1fffff, 0xffffffff,
242 0x0003ffff };
243
244 static const uint32 SysControl_OR[9] = { 0x1f000000, 0x1f000000, 0x00000000, 0x00000000,
245 0x00000000, 0x00000000, 0x00000000, 0x00000000,
246 0x00000000 };
247
248 static struct
249 {
250 union
251 {
252 struct
253 {
254 uint32 PIO_Base; // 0x1f801000 // BIOS Init: 0x1f000000, Writeable bits: 0x00ffffff(assumed, verify), FixedOR = 0x1f000000
255 uint32 Unknown0; // 0x1f801004 // BIOS Init: 0x1f802000, Writeable bits: 0x00ffffff, FixedOR = 0x1f000000
256 uint32 Unknown1; // 0x1f801008 // BIOS Init: 0x0013243f, ????
257 uint32 Unknown2; // 0x1f80100c // BIOS Init: 0x00003022, Writeable bits: 0x2f1fffff, FixedOR = 0x00000000
258
259 uint32 BIOS_Mapping; // 0x1f801010 // BIOS Init: 0x0013243f, ????
260 uint32 SPU_Delay; // 0x1f801014 // BIOS Init: 0x200931e1, Writeable bits: 0x2f1fffff, FixedOR = 0x00000000 - Affects bus timing on access to SPU
261 uint32 CDC_Delay; // 0x1f801018 // BIOS Init: 0x00020843, Writeable bits: 0x2f1fffff, FixedOR = 0x00000000
262 uint32 Unknown4; // 0x1f80101c // BIOS Init: 0x00070777, ????
263 uint32 Unknown5; // 0x1f801020 // BIOS Init: 0x00031125(but rewritten with other values often), Writeable bits: 0x0003ffff, FixedOR = 0x00000000 -- Possibly CDC related
264 };
265 uint32 Regs[9];
266 };
267 } SysControl;
268
269 static unsigned DMACycleSteal = 0; // Doesn't need to be saved in save states, since it's recalculated in the ForceEventUpdates() call chain.
270
PSX_SetDMACycleSteal(unsigned stealage)271 void PSX_SetDMACycleSteal(unsigned stealage)
272 {
273 if(stealage > 200) // Due to 8-bit limitations in the CPU core.
274 stealage = 200;
275
276 DMACycleSteal = stealage;
277 }
278
279
280 //
281 // Event stuff
282 //
283
284 static pscpu_timestamp_t Running; // Set to -1 when not desiring exit, and 0 when we are.
285
286 struct event_list_entry
287 {
288 uint32 which;
289 pscpu_timestamp_t event_time;
290 event_list_entry *prev;
291 event_list_entry *next;
292 };
293
294 static event_list_entry events[PSX_EVENT__COUNT];
295
EventReset(void)296 static void EventReset(void)
297 {
298 for(unsigned i = 0; i < PSX_EVENT__COUNT; i++)
299 {
300 events[i].which = i;
301
302 if(i == PSX_EVENT__SYNFIRST)
303 events[i].event_time = (int32)0x80000000;
304 else if(i == PSX_EVENT__SYNLAST)
305 events[i].event_time = 0x7FFFFFFF;
306 else
307 events[i].event_time = PSX_EVENT_MAXTS;
308
309 events[i].prev = (i > 0) ? &events[i - 1] : NULL;
310 events[i].next = (i < (PSX_EVENT__COUNT - 1)) ? &events[i + 1] : NULL;
311 }
312 }
313
314 //static void RemoveEvent(event_list_entry *e)
315 //{
316 // e->prev->next = e->next;
317 // e->next->prev = e->prev;
318 //}
319
RebaseTS(const pscpu_timestamp_t timestamp)320 static void RebaseTS(const pscpu_timestamp_t timestamp)
321 {
322 for(unsigned i = 0; i < PSX_EVENT__COUNT; i++)
323 {
324 if(i == PSX_EVENT__SYNFIRST || i == PSX_EVENT__SYNLAST)
325 continue;
326
327 assert(events[i].event_time > timestamp);
328 events[i].event_time -= timestamp;
329 }
330
331 CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time);
332 }
333
PSX_SetEventNT(const int type,const pscpu_timestamp_t next_timestamp)334 void PSX_SetEventNT(const int type, const pscpu_timestamp_t next_timestamp)
335 {
336 event_list_entry *e = &events[type];
337
338 if(next_timestamp < e->event_time)
339 {
340 event_list_entry *fe = e;
341
342 do
343 {
344 fe = fe->prev;
345 }
346 while(next_timestamp < fe->event_time);
347
348 // Remove this event from the list, temporarily of course.
349 e->prev->next = e->next;
350 e->next->prev = e->prev;
351
352 // Insert into the list, just after "fe".
353 e->prev = fe;
354 e->next = fe->next;
355 fe->next->prev = e;
356 fe->next = e;
357
358 e->event_time = next_timestamp;
359 }
360 else if(next_timestamp > e->event_time)
361 {
362 event_list_entry *fe = e;
363
364 do
365 {
366 fe = fe->next;
367 } while(next_timestamp > fe->event_time);
368
369 // Remove this event from the list, temporarily of course
370 e->prev->next = e->next;
371 e->next->prev = e->prev;
372
373 // Insert into the list, just BEFORE "fe".
374 e->prev = fe->prev;
375 e->next = fe;
376 fe->prev->next = e;
377 fe->prev = e;
378
379 e->event_time = next_timestamp;
380 }
381
382 CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time & Running);
383 }
384
385 // Called from debug.cpp too.
ForceEventUpdates(const pscpu_timestamp_t timestamp)386 void ForceEventUpdates(const pscpu_timestamp_t timestamp)
387 {
388 PSX_SetEventNT(PSX_EVENT_GPU, GPU_Update(timestamp));
389 PSX_SetEventNT(PSX_EVENT_CDC, CDC->Update(timestamp));
390
391 PSX_SetEventNT(PSX_EVENT_TIMER, TIMER_Update(timestamp));
392
393 PSX_SetEventNT(PSX_EVENT_DMA, DMA_Update(timestamp));
394
395 PSX_SetEventNT(PSX_EVENT_FIO, FIO->Update(timestamp));
396
397 CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time);
398 }
399
PSX_EventHandler(const pscpu_timestamp_t timestamp)400 bool MDFN_FASTCALL PSX_EventHandler(const pscpu_timestamp_t timestamp)
401 {
402 event_list_entry *e = events[PSX_EVENT__SYNFIRST].next;
403
404 while(timestamp >= e->event_time) // If Running = 0, PSX_EventHandler() may be called even if there isn't an event per-se, so while() instead of do { ... } while
405 {
406 event_list_entry *prev = e->prev;
407 pscpu_timestamp_t nt;
408
409 switch(e->which)
410 {
411 default: abort();
412
413 case PSX_EVENT_GPU:
414 nt = GPU_Update(e->event_time);
415 break;
416
417 case PSX_EVENT_CDC:
418 nt = CDC->Update(e->event_time);
419 break;
420
421 case PSX_EVENT_TIMER:
422 nt = TIMER_Update(e->event_time);
423 break;
424
425 case PSX_EVENT_DMA:
426 nt = DMA_Update(e->event_time);
427 break;
428
429 case PSX_EVENT_FIO:
430 nt = FIO->Update(e->event_time);
431 break;
432 }
433 #if PSX_EVENT_SYSTEM_CHECKS
434 assert(nt > e->event_time);
435 #endif
436
437 PSX_SetEventNT(e->which, nt);
438
439 // Order of events can change due to calling PSX_SetEventNT(), this prev business ensures we don't miss an event due to reordering.
440 e = prev->next;
441 }
442
443 return(Running);
444 }
445
446
PSX_RequestMLExit(void)447 void PSX_RequestMLExit(void)
448 {
449 Running = 0;
450 CPU->SetEventNT(0);
451 }
452
453
454 //
455 // End event stuff
456 //
457
458 // Remember to update MemPeek<>() and MemPoke<>() when we change address decoding in MemRW()
MemRW(pscpu_timestamp_t & timestamp,uint32 A,uint32 & V)459 template<typename T, bool IsWrite, bool Access24> static INLINE void MemRW(pscpu_timestamp_t ×tamp, uint32 A, uint32 &V)
460 {
461 #if 0
462 if(IsWrite)
463 printf("Write%d: %08x(orig=%08x), %08x\n", (int)(sizeof(T) * 8), A & mask[A >> 29], A, V);
464 else
465 printf("Read%d: %08x(orig=%08x)\n", (int)(sizeof(T) * 8), A & mask[A >> 29], A);
466 #endif
467
468 if(!IsWrite)
469 timestamp += DMACycleSteal;
470
471 if(A < 0x00800000)
472 {
473 if(IsWrite)
474 {
475 //timestamp++; // Best-case timing.
476 }
477 else
478 {
479 timestamp += 3;
480 }
481
482 if(Access24)
483 {
484 if(IsWrite)
485 MainRAM.WriteU24(A & 0x1FFFFF, V);
486 else
487 V = MainRAM.ReadU24(A & 0x1FFFFF);
488 }
489 else
490 {
491 if(IsWrite)
492 MainRAM.Write<T>(A & 0x1FFFFF, V);
493 else
494 V = MainRAM.Read<T>(A & 0x1FFFFF);
495 }
496
497 return;
498 }
499
500 if(A >= 0x1FC00000 && A <= 0x1FC7FFFF)
501 {
502 if(!IsWrite)
503 {
504 if(Access24)
505 V = BIOSROM->ReadU24(A & 0x7FFFF);
506 else
507 V = BIOSROM->Read<T>(A & 0x7FFFF);
508 }
509
510 return;
511 }
512
513 if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
514 PSX_EventHandler(timestamp);
515
516 if(A >= 0x1F801000 && A <= 0x1F802FFF)
517 {
518 //if(IsWrite)
519 // printf("HW Write%d: %08x %08x\n", (unsigned int)(sizeof(T)*8), (unsigned int)A, (unsigned int)V);
520 //else
521 // printf("HW Read%d: %08x\n", (unsigned int)(sizeof(T)*8), (unsigned int)A);
522
523 if(A >= 0x1F801C00 && A <= 0x1F801FFF) // SPU
524 {
525 if(sizeof(T) == 4 && !Access24)
526 {
527 if(IsWrite)
528 {
529 //timestamp += 15;
530
531 //if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
532 // PSX_EventHandler(timestamp);
533
534 SPU->Write(timestamp, A | 0, V);
535 SPU->Write(timestamp, A | 2, V >> 16);
536 }
537 else
538 {
539 timestamp += 36;
540
541 if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
542 PSX_EventHandler(timestamp);
543
544 V = SPU->Read(timestamp, A);
545 V |= SPU->Read(timestamp, A | 2) << 16;
546 }
547 }
548 else
549 {
550 if(IsWrite)
551 {
552 //timestamp += 8;
553
554 //if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
555 // PSX_EventHandler(timestamp);
556
557 SPU->Write(timestamp, A & ~1, V);
558 }
559 else
560 {
561 timestamp += 16; // Just a guess, need to test.
562
563 if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
564 PSX_EventHandler(timestamp);
565
566 V = SPU->Read(timestamp, A & ~1);
567 }
568 }
569 return;
570 } // End SPU
571
572
573 // CDC: TODO - 8-bit access.
574 if(A >= 0x1f801800 && A <= 0x1f80180F)
575 {
576 if(!IsWrite)
577 {
578 timestamp += 6 * sizeof(T); //24;
579 }
580
581 if(IsWrite)
582 CDC->Write(timestamp, A & 0x3, V);
583 else
584 V = CDC->Read(timestamp, A & 0x3);
585
586 return;
587 }
588
589 if(A >= 0x1F801810 && A <= 0x1F801817)
590 {
591 if(!IsWrite)
592 timestamp++;
593
594 if(IsWrite)
595 GPU_Write(timestamp, A, V);
596 else
597 V = GPU_Read(timestamp, A);
598
599 return;
600 }
601
602 if(A >= 0x1F801820 && A <= 0x1F801827)
603 {
604 if(!IsWrite)
605 timestamp++;
606
607 if(IsWrite)
608 MDEC_Write(timestamp, A, V);
609 else
610 V = MDEC_Read(timestamp, A);
611
612 return;
613 }
614
615 if(A >= 0x1F801000 && A <= 0x1F801023)
616 {
617 unsigned index = (A & 0x1F) >> 2;
618
619 if(!IsWrite)
620 timestamp++;
621
622 //if(A == 0x1F801014 && IsWrite)
623 // fprintf(stderr, "%08x %08x\n",A,V);
624
625 if(IsWrite)
626 {
627 V <<= (A & 3) * 8;
628 SysControl.Regs[index] = V & SysControl_Mask[index];
629 }
630 else
631 {
632 V = SysControl.Regs[index] | SysControl_OR[index];
633 V >>= (A & 3) * 8;
634 }
635 return;
636 }
637
638 if(A >= 0x1F801040 && A <= 0x1F80104F)
639 {
640 if(!IsWrite)
641 timestamp++;
642
643 if(IsWrite)
644 FIO->Write(timestamp, A, V);
645 else
646 V = FIO->Read(timestamp, A);
647 return;
648 }
649
650 if(A >= 0x1F801050 && A <= 0x1F80105F)
651 {
652 if(!IsWrite)
653 timestamp++;
654
655 #if 0
656 if(IsWrite)
657 {
658 PSX_WARNING("[SIO] Write: 0x%08x 0x%08x %u", A, V, (unsigned)sizeof(T));
659 }
660 else
661 {
662 PSX_WARNING("[SIO] Read: 0x%08x", A);
663 }
664 #endif
665
666 if(IsWrite)
667 SIO_Write(timestamp, A, V);
668 else
669 V = SIO_Read(timestamp, A);
670 return;
671 }
672
673 #if 0
674 if(A >= 0x1F801060 && A <= 0x1F801063)
675 {
676 if(IsWrite)
677 {
678
679 }
680 else
681 {
682
683 }
684
685 return;
686 }
687 #endif
688
689 if(A >= 0x1F801070 && A <= 0x1F801077) // IRQ
690 {
691 if(!IsWrite)
692 timestamp++;
693
694 if(IsWrite)
695 IRQ_Write(A, V);
696 else
697 V = IRQ_Read(A);
698 return;
699 }
700
701 if(A >= 0x1F801080 && A <= 0x1F8010FF) // DMA
702 {
703 if(!IsWrite)
704 timestamp++;
705
706 if(IsWrite)
707 DMA_Write(timestamp, A, V);
708 else
709 V = DMA_Read(timestamp, A);
710
711 return;
712 }
713
714 if(A >= 0x1F801100 && A <= 0x1F80113F) // Root counters
715 {
716 if(!IsWrite)
717 timestamp++;
718
719 if(IsWrite)
720 TIMER_Write(timestamp, A, V);
721 else
722 V = TIMER_Read(timestamp, A);
723
724 return;
725 }
726 }
727
728
729 if(A >= 0x1F000000 && A <= 0x1F7FFFFF)
730 {
731 if(!IsWrite)
732 {
733 //if((A & 0x7FFFFF) <= 0x84)
734 //PSX_WARNING("[PIO] Read%d from 0x%08x at time %d", (int)(sizeof(T) * 8), A, timestamp);
735
736 V = ~0U; // A game this affects: Tetris with Cardcaptor Sakura
737
738 if(PIOMem)
739 {
740 if((A & 0x7FFFFF) < 65536)
741 {
742 if(Access24)
743 V = PIOMem->ReadU24(A & 0x7FFFFF);
744 else
745 V = PIOMem->Read<T>(A & 0x7FFFFF);
746 }
747 else if((A & 0x7FFFFF) < (65536 + TextMem.size()))
748 {
749 if(Access24)
750 V = MDFN_de24lsb(&TextMem[(A & 0x7FFFFF) - 65536]);
751 else switch(sizeof(T))
752 {
753 case 1: V = TextMem[(A & 0x7FFFFF) - 65536]; break;
754 case 2: V = MDFN_de16lsb(&TextMem[(A & 0x7FFFFF) - 65536]); break;
755 case 4: V = MDFN_de32lsb(&TextMem[(A & 0x7FFFFF) - 65536]); break;
756 }
757 }
758 }
759 }
760 return;
761 }
762
763 if(A == 0xFFFE0130) // Per tests on PS1, ignores the access(sort of, on reads the value is forced to 0 if not aligned) if not aligned to 4-bytes.
764 {
765 if(!IsWrite)
766 V = CPU->GetBIU();
767 else
768 CPU->SetBIU(V);
769
770 return;
771 }
772
773 if(IsWrite)
774 {
775 PSX_WARNING("[MEM] Unknown write%d to %08x at time %d, =%08x(%d)", (int)(sizeof(T) * 8), A, timestamp, V, V);
776 }
777 else
778 {
779 V = 0;
780 PSX_WARNING("[MEM] Unknown read%d from %08x at time %d", (int)(sizeof(T) * 8), A, timestamp);
781 }
782 }
783
PSX_MemWrite8(pscpu_timestamp_t timestamp,uint32 A,uint32 V)784 void MDFN_FASTCALL PSX_MemWrite8(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
785 {
786 MemRW<uint8, true, false>(timestamp, A, V);
787 }
788
PSX_MemWrite16(pscpu_timestamp_t timestamp,uint32 A,uint32 V)789 void MDFN_FASTCALL PSX_MemWrite16(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
790 {
791 MemRW<uint16, true, false>(timestamp, A, V);
792 }
793
PSX_MemWrite24(pscpu_timestamp_t timestamp,uint32 A,uint32 V)794 void MDFN_FASTCALL PSX_MemWrite24(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
795 {
796 MemRW<uint32, true, true>(timestamp, A, V);
797 }
798
PSX_MemWrite32(pscpu_timestamp_t timestamp,uint32 A,uint32 V)799 void MDFN_FASTCALL PSX_MemWrite32(pscpu_timestamp_t timestamp, uint32 A, uint32 V)
800 {
801 MemRW<uint32, true, false>(timestamp, A, V);
802 }
803
PSX_MemRead8(pscpu_timestamp_t & timestamp,uint32 A)804 uint8 MDFN_FASTCALL PSX_MemRead8(pscpu_timestamp_t ×tamp, uint32 A)
805 {
806 uint32 V;
807
808 MemRW<uint8, false, false>(timestamp, A, V);
809
810 return(V);
811 }
812
PSX_MemRead16(pscpu_timestamp_t & timestamp,uint32 A)813 uint16 MDFN_FASTCALL PSX_MemRead16(pscpu_timestamp_t ×tamp, uint32 A)
814 {
815 uint32 V;
816
817 MemRW<uint16, false, false>(timestamp, A, V);
818
819 return(V);
820 }
821
PSX_MemRead24(pscpu_timestamp_t & timestamp,uint32 A)822 uint32 MDFN_FASTCALL PSX_MemRead24(pscpu_timestamp_t ×tamp, uint32 A)
823 {
824 uint32 V;
825
826 MemRW<uint32, false, true>(timestamp, A, V);
827
828 return(V);
829 }
830
PSX_MemRead32(pscpu_timestamp_t & timestamp,uint32 A)831 uint32 MDFN_FASTCALL PSX_MemRead32(pscpu_timestamp_t ×tamp, uint32 A)
832 {
833 uint32 V;
834
835 MemRW<uint32, false, false>(timestamp, A, V);
836
837 return(V);
838 }
839
MemPeek(pscpu_timestamp_t timestamp,uint32 A)840 template<typename T, bool Access24> static INLINE uint32 MemPeek(pscpu_timestamp_t timestamp, uint32 A)
841 {
842 if(A < 0x00800000)
843 {
844 if(Access24)
845 return(MainRAM.ReadU24(A & 0x1FFFFF));
846 else
847 return(MainRAM.Read<T>(A & 0x1FFFFF));
848 }
849
850 if(A >= 0x1FC00000 && A <= 0x1FC7FFFF)
851 {
852 if(Access24)
853 return(BIOSROM->ReadU24(A & 0x7FFFF));
854 else
855 return(BIOSROM->Read<T>(A & 0x7FFFF));
856 }
857
858 if(A >= 0x1F801000 && A <= 0x1F802FFF)
859 {
860 if(A >= 0x1F801C00 && A <= 0x1F801FFF) // SPU
861 {
862 // TODO
863
864 } // End SPU
865
866
867 // CDC: TODO - 8-bit access.
868 if(A >= 0x1f801800 && A <= 0x1f80180F)
869 {
870 // TODO
871
872 }
873
874 if(A >= 0x1F801810 && A <= 0x1F801817)
875 {
876 // TODO
877
878 }
879
880 if(A >= 0x1F801820 && A <= 0x1F801827)
881 {
882 // TODO
883
884 }
885
886 if(A >= 0x1F801000 && A <= 0x1F801023)
887 {
888 unsigned index = (A & 0x1F) >> 2;
889 return((SysControl.Regs[index] | SysControl_OR[index]) >> ((A & 3) * 8));
890 }
891
892 if(A >= 0x1F801040 && A <= 0x1F80104F)
893 {
894 // TODO
895
896 }
897
898 if(A >= 0x1F801050 && A <= 0x1F80105F)
899 {
900 // TODO
901
902 }
903
904
905 if(A >= 0x1F801070 && A <= 0x1F801077) // IRQ
906 {
907 // TODO
908
909 }
910
911 if(A >= 0x1F801080 && A <= 0x1F8010FF) // DMA
912 {
913 // TODO
914
915 }
916
917 if(A >= 0x1F801100 && A <= 0x1F80113F) // Root counters
918 {
919 // TODO
920
921 }
922 }
923
924
925 if(A >= 0x1F000000 && A <= 0x1F7FFFFF)
926 {
927 if(PIOMem)
928 {
929 if((A & 0x7FFFFF) < 65536)
930 {
931 if(Access24)
932 return(PIOMem->ReadU24(A & 0x7FFFFF));
933 else
934 return(PIOMem->Read<T>(A & 0x7FFFFF));
935 }
936 else if((A & 0x7FFFFF) < (65536 + TextMem.size()))
937 {
938 if(Access24)
939 return(MDFN_de24lsb(&TextMem[(A & 0x7FFFFF) - 65536]));
940 else switch(sizeof(T))
941 {
942 case 1: return(TextMem[(A & 0x7FFFFF) - 65536]); break;
943 case 2: return(MDFN_de16lsb(&TextMem[(A & 0x7FFFFF) - 65536])); break;
944 case 4: return(MDFN_de32lsb(&TextMem[(A & 0x7FFFFF) - 65536])); break;
945 }
946 }
947 }
948 return(~0U);
949 }
950
951 if(A == 0xFFFE0130)
952 return CPU->GetBIU();
953
954 return(0);
955 }
956
PSX_MemPeek8(uint32 A)957 uint8 PSX_MemPeek8(uint32 A)
958 {
959 return MemPeek<uint8, false>(0, A);
960 }
961
PSX_MemPeek16(uint32 A)962 uint16 PSX_MemPeek16(uint32 A)
963 {
964 return MemPeek<uint16, false>(0, A);
965 }
966
PSX_MemPeek32(uint32 A)967 uint32 PSX_MemPeek32(uint32 A)
968 {
969 return MemPeek<uint32, false>(0, A);
970 }
971
MemPoke(pscpu_timestamp_t timestamp,uint32 A,T V)972 template<typename T, bool Access24> static INLINE void MemPoke(pscpu_timestamp_t timestamp, uint32 A, T V)
973 {
974 if(A < 0x00800000)
975 {
976 if(Access24)
977 MainRAM.WriteU24(A & 0x1FFFFF, V);
978 else
979 MainRAM.Write<T>(A & 0x1FFFFF, V);
980
981 return;
982 }
983
984 if(A >= 0x1FC00000 && A <= 0x1FC7FFFF)
985 {
986 if(Access24)
987 BIOSROM->WriteU24(A & 0x7FFFF, V);
988 else
989 BIOSROM->Write<T>(A & 0x7FFFF, V);
990
991 return;
992 }
993
994 if(A >= 0x1F801000 && A <= 0x1F802FFF)
995 {
996 if(A >= 0x1F801000 && A <= 0x1F801023)
997 {
998 unsigned index = (A & 0x1F) >> 2;
999 SysControl.Regs[index] = (V << ((A & 3) * 8)) & SysControl_Mask[index];
1000 return;
1001 }
1002 }
1003
1004 if(A == 0xFFFE0130)
1005 {
1006 CPU->SetBIU(V);
1007 return;
1008 }
1009 }
1010
PSX_MemPoke8(uint32 A,uint8 V)1011 void PSX_MemPoke8(uint32 A, uint8 V)
1012 {
1013 MemPoke<uint8, false>(0, A, V);
1014 }
1015
PSX_MemPoke16(uint32 A,uint16 V)1016 void PSX_MemPoke16(uint32 A, uint16 V)
1017 {
1018 MemPoke<uint16, false>(0, A, V);
1019 }
1020
PSX_MemPoke32(uint32 A,uint32 V)1021 void PSX_MemPoke32(uint32 A, uint32 V)
1022 {
1023 MemPoke<uint32, false>(0, A, V);
1024 }
1025
1026
PSX_Reset(bool powering_up)1027 static void PSX_Reset(bool powering_up)
1028 {
1029 PSX_PRNG.ResetState(); // Should occur first!
1030
1031 memset(MainRAM.data8, 0, 2048 * 1024);
1032
1033 for(unsigned i = 0; i < 9; i++)
1034 SysControl.Regs[i] = 0;
1035
1036 CPU->Power();
1037
1038 EventReset();
1039
1040 TIMER_Power();
1041
1042 DMA_Power();
1043
1044 FIO->Reset(powering_up);
1045 SIO_Power();
1046
1047 MDEC_Power();
1048 CDC->Power();
1049 GPU_Power();
1050 //SPU->Power(); // Called from CDC->Power()
1051 IRQ_Power();
1052
1053 ForceEventUpdates(0);
1054 }
1055
1056
PSX_GPULineHook(const pscpu_timestamp_t timestamp,const pscpu_timestamp_t line_timestamp,bool vsync,uint32 * pixels,const MDFN_PixelFormat * const format,const unsigned width,const unsigned pix_clock_offset,const unsigned pix_clock,const unsigned pix_clock_divider)1057 void PSX_GPULineHook(const pscpu_timestamp_t timestamp, const pscpu_timestamp_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider)
1058 {
1059 FIO->GPULineHook(timestamp, line_timestamp, vsync, pixels, format, width, pix_clock_offset, pix_clock, pix_clock_divider);
1060 }
1061
1062 }
1063
1064 using namespace MDFN_IEN_PSX;
1065
1066
Emulate(EmulateSpecStruct * espec)1067 static void Emulate(EmulateSpecStruct *espec)
1068 {
1069 pscpu_timestamp_t timestamp = 0;
1070
1071 if(FIO->RequireNoFrameskip())
1072 {
1073 //puts("MEOW");
1074 espec->skip = false; //TODO: Save here, and restore at end of Emulate() ?
1075 }
1076
1077 MDFNGameInfo->mouse_sensitivity = MDFN_GetSettingF("psx.input.mouse_sensitivity");
1078
1079 MDFNMP_ApplyPeriodicCheats();
1080
1081
1082 espec->MasterCycles = 0;
1083 espec->SoundBufSize = 0;
1084
1085 FIO->UpdateInput();
1086 GPU_StartFrame(psf_loader ? NULL : espec);
1087 SPU->StartFrame(espec->SoundRate, MDFN_GetSettingUI("psx.spu.resamp_quality"));
1088
1089 Running = -1;
1090 timestamp = CPU->Run(timestamp, psf_loader == NULL && psx_dbg_level >= PSX_DBG_BIOS_PRINT, psf_loader != NULL);
1091
1092 assert(timestamp);
1093
1094 ForceEventUpdates(timestamp);
1095 if(GPU_GetScanlineNum() < 100)
1096 PSX_DBG(PSX_DBG_ERROR, "[BUUUUUUUG] Frame timing end glitch; scanline=%u, st=%u\n", GPU_GetScanlineNum(), timestamp);
1097
1098 //printf("scanline=%u, st=%u\n", GPU_GetScanlineNum(), timestamp);
1099
1100 espec->SoundBufSize = SPU->EndFrame(espec->SoundBuf, espec->NeedSoundReverse);
1101 espec->NeedSoundReverse = false;
1102
1103 CDC->ResetTS();
1104 TIMER_ResetTS();
1105 DMA_ResetTS();
1106 GPU_ResetTS();
1107 FIO->ResetTS();
1108
1109 RebaseTS(timestamp);
1110
1111 espec->MasterCycles = timestamp;
1112
1113 /*
1114 {
1115 static int frame_counter = -120;
1116 static uint64 cycle_counter = 0;
1117
1118 frame_counter++;
1119 if(frame_counter > 0)
1120 {
1121 cycle_counter += espec->MasterCycles;
1122 printf("moo: %f %f\n", EmulatedPSX.fps / 65536.0 / 256.0, (double)44100 * 768.0 * frame_counter / cycle_counter);
1123 }
1124 }
1125 */
1126
1127 if(psf_loader)
1128 {
1129 if(!espec->skip)
1130 {
1131 espec->LineWidths[0] = ~0;
1132 Player_Draw(espec->surface, &espec->DisplayRect, 0, espec->SoundBuf, espec->SoundBufSize);
1133 }
1134 }
1135
1136 FIO->UpdateOutput();
1137
1138 // Save memcards if dirty.
1139 if(!psf_loader)
1140 {
1141 for(int i = 0; i < 8; i++)
1142 {
1143 uint64 new_dc = FIO->GetMemcardDirtyCount(i);
1144
1145 if(new_dc > Memcard_PrevDC[i])
1146 {
1147 Memcard_PrevDC[i] = new_dc;
1148 Memcard_SaveDelay[i] = 0;
1149 }
1150
1151 if(Memcard_SaveDelay[i] >= 0)
1152 {
1153 Memcard_SaveDelay[i] += timestamp;
1154 if(Memcard_SaveDelay[i] >= (33868800 * 2)) // Wait until about 2 seconds of no new writes.
1155 {
1156 PSX_DBG(PSX_DBG_SPARSE, "Saving memcard %d...\n", i);
1157 try
1158 {
1159 char ext[64];
1160 trio_snprintf(ext, sizeof(ext), "%d.mcr", i);
1161 FIO->SaveMemcard(i, MDFN_MakeFName(MDFNMKF_SAV, 0, ext));
1162 Memcard_SaveDelay[i] = -1;
1163 Memcard_PrevDC[i] = 0;
1164 }
1165 catch(std::exception &e)
1166 {
1167 MDFN_Notify(MDFN_NOTICE_ERROR, _("Memcard %d save error: %s"), i, e.what());
1168 Memcard_SaveDelay[i] = 0; // Delay before trying to save again
1169 }
1170 }
1171 }
1172 }
1173 }
1174 }
1175
CalcRegion_By_SYSTEMCNF(CDInterface * c,unsigned * rr)1176 static bool CalcRegion_By_SYSTEMCNF(CDInterface *c, unsigned *rr)
1177 {
1178 try
1179 {
1180 uint8 pvd[2048];
1181 unsigned pvd_search_count = 0;
1182 std::unique_ptr<Stream> fp(c->MakeStream(0, ~0U));
1183
1184 fp->seek(0x8000, SEEK_SET);
1185
1186 do
1187 {
1188 if((pvd_search_count++) == 32)
1189 throw MDFN_Error(0, "PVD search count limit met.");
1190
1191 fp->read(pvd, 2048);
1192
1193 if(memcmp(&pvd[1], "CD001", 5))
1194 throw MDFN_Error(0, "Not ISO-9660");
1195
1196 if(pvd[0] == 0xFF)
1197 throw MDFN_Error(0, "Missing Primary Volume Descriptor");
1198 } while(pvd[0] != 0x01);
1199 //[156 ... 189], 34 bytes
1200 uint32 rdel = MDFN_de32lsb(&pvd[0x9E]);
1201 uint32 rdel_len = MDFN_de32lsb(&pvd[0xA6]);
1202
1203 if(rdel_len >= (1024 * 1024 * 10)) // Arbitrary sanity check.
1204 throw MDFN_Error(0, "Root directory table too large");
1205
1206 fp->seek((int64)rdel * 2048, SEEK_SET);
1207 //printf("%08x, %08x\n", rdel * 2048, rdel_len);
1208 while(fp->tell() < (((uint64)rdel * 2048) + rdel_len))
1209 {
1210 uint8 len_dr = fp->get_u8();
1211 uint8 dr[256 + 1];
1212
1213 memset(dr, 0xFF, sizeof(dr));
1214
1215 if(!len_dr)
1216 break;
1217
1218 memset(dr, 0, sizeof(dr));
1219 dr[0] = len_dr;
1220 fp->read(dr + 1, len_dr - 1);
1221
1222 uint8 len_fi = dr[0x20];
1223
1224 if(len_fi == 12 && !memcmp(&dr[0x21], "SYSTEM.CNF;1", 12))
1225 {
1226 uint32 file_lba = MDFN_de32lsb(&dr[0x02]);
1227 //uint32 file_len = MDFN_de32lsb(&dr[0x0A]);
1228 uint8 fb[2048 + 1];
1229 char *bootpos;
1230
1231 memset(fb, 0, sizeof(fb));
1232 fp->seek(file_lba * 2048, SEEK_SET);
1233 fp->read(fb, 2048);
1234
1235 if((bootpos = strstr((char*)fb, "BOOT")))
1236 {
1237 bootpos += 4;
1238 while(*bootpos == ' ' || *bootpos == '\t') bootpos++;
1239 if(*bootpos == '=')
1240 {
1241 bootpos++;
1242 while(*bootpos == ' ' || *bootpos == '\t') bootpos++;
1243 if(!MDFN_strazicmp(bootpos, "cdrom:", 6))
1244 {
1245 char* tmp;
1246
1247 bootpos += 6;
1248
1249 // strrchr() way will pick up Tekken 3, but only enable if needed due to possibility of regressions.
1250 //if((tmp = strrchr(bootpos, '\\')))
1251 // bootpos = tmp + 1;
1252 while(*bootpos == '\\')
1253 bootpos++;
1254
1255 if((tmp = strchr(bootpos, '_'))) *tmp = 0;
1256 if((tmp = strchr(bootpos, '.'))) *tmp = 0;
1257 if((tmp = strchr(bootpos, ';'))) *tmp = 0;
1258 //puts(bootpos);
1259
1260 if(strlen(bootpos) == 4 && MDFN_azupper(bootpos[0]) == 'S' && (MDFN_azupper(bootpos[1]) == 'C' || MDFN_azupper(bootpos[1]) == 'L' || MDFN_azupper(bootpos[1]) == 'I'))
1261 {
1262 switch(MDFN_azupper(bootpos[2]))
1263 {
1264 case 'E': *rr = REGION_EU;
1265 return(true);
1266
1267 case 'U': *rr = REGION_NA;
1268 return(true);
1269
1270 case 'K': // Korea?
1271 case 'B':
1272 case 'P': *rr = REGION_JP;
1273 return(true);
1274 }
1275 }
1276 }
1277 }
1278 }
1279 }
1280 }
1281 }
1282 catch(std::exception &e)
1283 {
1284 //puts(e.what());
1285 }
1286 catch(...)
1287 {
1288
1289 }
1290
1291 return(false);
1292 }
1293
CalcRegion_By_SA(const uint8 buf[2048* 8],unsigned * region)1294 static bool CalcRegion_By_SA(const uint8 buf[2048 * 8], unsigned* region)
1295 {
1296 uint8 fbuf[2048 + 1];
1297 unsigned ipos, opos;
1298
1299 memset(fbuf, 0, sizeof(fbuf));
1300
1301 for(ipos = 0, opos = 0; ipos < 0x48; ipos++)
1302 {
1303 if(buf[ipos] > 0x20 && buf[ipos] < 0x80)
1304 {
1305 fbuf[opos++] = MDFN_azlower(buf[ipos]);
1306 }
1307 }
1308
1309 fbuf[opos++] = 0;
1310
1311 PSX_DBG(PSX_DBG_SPARSE, "License string: %s\n", (char *)fbuf);
1312
1313 if(strstr((char *)fbuf, "licensedby") != NULL)
1314 {
1315 if(strstr((char *)fbuf, "america") != NULL)
1316 {
1317 *region = REGION_NA;
1318 return(true);
1319 }
1320 else if(strstr((char *)fbuf, "europe") != NULL)
1321 {
1322 *region = REGION_EU;
1323 return(true);
1324 }
1325 else if(strstr((char *)fbuf, "japan") != NULL)
1326 {
1327 *region = REGION_JP;
1328 return(true);
1329 }
1330 else if(strstr((char *)fbuf, "sonycomputerentertainmentinc.") != NULL)
1331 {
1332 *region = REGION_JP;
1333 return(true);
1334 }
1335 }
1336
1337 return(false);
1338 }
1339
1340
1341 //
1342 // Returns true if constraint applied(*region changed), false otherwise.
1343 //
ConstrainRegion_By_SA(const uint8 buf[2048* 8],unsigned * region)1344 static bool ConstrainRegion_By_SA(const uint8 buf[2048 * 8], unsigned* region)
1345 {
1346 //
1347 // If we're going with Japanese region,
1348 // make sure the licensed-by string is correct(Japanese BIOS is kinda strict).
1349 //
1350 if(*region == REGION_JP)
1351 {
1352 static const char tv[2][0x41] = {
1353 { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 76, 105, 99, 101, 110, 115,
1354 101, 100, 32, 32, 98, 121, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1355 83, 111, 110, 121, 32, 67, 111, 109, 112, 117, 116, 101, 114, 32, 69, 110,
1356 116, 101, 114, 116, 97, 105, 110, 109, 101, 110, 116, 32, 73, 110, 99, 46,
1357 0
1358 },
1359 { 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 76, 105, 99, 101, 110, 115,
1360 101, 100, 32, 32, 98, 121, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1361 83, 111, 110, 121, 32, 67, 111, 109, 112, 117, 116, 101, 114, 32, 69, 110,
1362 116, 101, 114, 116, 97, 105, 110, 109, 101, 110, 116, 32, 73, 110, 99, 46,
1363 10
1364 },
1365 };
1366 bool jp_incompatible = false;
1367
1368 if(memcmp(&buf[0], &tv[0][0], 0x41) && memcmp(&buf[0], &tv[1][0], 0x41))
1369 jp_incompatible = true;
1370
1371 if(crc32(0, &buf[0x800], 0x3278) != 0x0069c087)
1372 jp_incompatible = true;
1373
1374 if(jp_incompatible)
1375 {
1376 //
1377 // Doesn't match, so default to most similar region, NA.
1378 //
1379 *region = REGION_NA;
1380 return(true);
1381 }
1382 }
1383
1384 return(false);
1385 }
1386
Region_To_SCEx(const unsigned region)1387 static const char* Region_To_SCEx(const unsigned region)
1388 {
1389 switch(region)
1390 {
1391 default:
1392 abort();
1393
1394 case REGION_JP:
1395 return("SCEI");
1396
1397 case REGION_NA:
1398 return("SCEA");
1399
1400 case REGION_EU:
1401 return("SCEE");
1402 }
1403 }
1404
TestMagic(GameFile * gf)1405 static bool TestMagic(GameFile* gf)
1406 {
1407 if(PSFLoader::TestMagic(0x01, gf->stream))
1408 return(true);
1409
1410 gf->stream->rewind();
1411
1412 uint8 exe_header[0x800];
1413 if(gf->stream->read(exe_header, 0x800, false) == 0x800 && !memcmp(exe_header, "PS-X EXE", 8))
1414 return true;
1415
1416 return false;
1417 }
1418
TestMagicCD(std::vector<CDInterface * > * CDInterfaces)1419 static bool TestMagicCD(std::vector<CDInterface*> *CDInterfaces)
1420 {
1421 std::unique_ptr<uint8[]> buf(new uint8[2048 * 8]);
1422
1423 if((*CDInterfaces)[0]->ReadSectors(&buf[0], 4, 8) != 0x2)
1424 return(false);
1425
1426 if(strncmp((char *)&buf[10], "Licensed by", strlen("Licensed by")) && crc32(0, &buf[0x800], 0x3278) != 0x0069c087)
1427 return(false);
1428
1429 return(true);
1430 }
1431
1432
CalcDiscSCEx(void)1433 static unsigned CalcDiscSCEx(void)
1434 {
1435 const unsigned region_default = MDFN_GetSettingI("psx.region_default");
1436 bool found_ps1_disc = false;
1437 bool did_constraint = false;
1438 unsigned ret_region = region_default;
1439 unsigned region = region_default;
1440
1441 cdifs_scex_ids.clear();
1442
1443 for(unsigned i = 0; i < (cdifs ? cdifs->size() : 0); i++)
1444 {
1445 std::unique_ptr<uint8[]> buf(new uint8[2048 * 8]);
1446 bool is_ps1_disc = true;
1447
1448 //
1449 // Read the PS1 system area.
1450 //
1451 if((*cdifs)[i]->ReadSectors(buf.get(), 4, 8) == 0x2)
1452 {
1453 if(!CalcRegion_By_SYSTEMCNF((*cdifs)[i], ®ion))
1454 {
1455 if(!CalcRegion_By_SA(buf.get(), ®ion))
1456 {
1457 if(strncmp((char *)buf.get() + 10, "Licensed by", strlen("Licensed by")) && crc32(0, &buf[0x800], 0x3278) != 0x0069c087)
1458 {
1459 //
1460 // Last-ditch effort before deciding the disc isn't a PS1 disc.
1461 //
1462 uint8 pvd[2048];
1463
1464 if((*cdifs)[i]->ReadSectors(pvd, 16, 1) != 0x2 || memcmp(&pvd[0], "\x01" "CD001", 6) || memcmp(&pvd[8], "PLAYSTATION", 11))
1465 is_ps1_disc = false;
1466 }
1467 }
1468 }
1469 }
1470 else
1471 is_ps1_disc = false;
1472
1473 //
1474 // If PS1 disc, apply any constraints and change the region as necessary(e.g. Japanese PS1 BIOS is strict about the structure of the system area);
1475 // especially necessary for homebrew that failed automatic region detection above.
1476 //
1477 if(is_ps1_disc)
1478 {
1479 if(!found_ps1_disc || did_constraint)
1480 {
1481 if(ConstrainRegion_By_SA(buf.get(), ®ion))
1482 did_constraint = true;
1483 }
1484 }
1485
1486 //
1487 // Determine what sort of PS1 to emulate based on the first PS1 disc in the set.
1488 //
1489 if(!found_ps1_disc)
1490 ret_region = region;
1491
1492 found_ps1_disc |= is_ps1_disc;
1493 cdifs_scex_ids.push_back(is_ps1_disc ? Region_To_SCEx(region) : NULL);
1494 }
1495
1496 if(cdifs_scex_ids.size())
1497 {
1498 MDFN_printf(_("Emulated Disc SCEx IDs:\n"));
1499 {
1500 MDFN_AutoIndent aind(1);
1501
1502 for(size_t x = 0; x < cdifs_scex_ids.size(); x++)
1503 {
1504 MDFN_printf(_("Disc %zu: %s\n"), x + 1, (cdifs_scex_ids[x] ? cdifs_scex_ids[x] : _("(Not recognized as a PS1 disc)")));
1505 }
1506 }
1507 }
1508
1509 return ret_region;
1510 }
1511
DiscSanityChecks(void)1512 static void DiscSanityChecks(void)
1513 {
1514 if(!cdifs)
1515 return;
1516
1517 assert(cdifs->size() == cdifs_scex_ids.size());
1518
1519 for(size_t i = 0; i < cdifs_scex_ids.size(); i++)
1520 {
1521 //
1522 // Sanity check to ensure Q subchannel timing data relative to mode1/mode2 header timing data is as we expect it to be for a PS1 disc.
1523 //
1524 if(cdifs_scex_ids[i])
1525 {
1526 bool did_check = false;
1527
1528 for(int32 lba = -8; lba < 16; lba++)
1529 {
1530 uint8 rawbuf[2352 + 96];
1531
1532 if((*cdifs)[i]->ReadRawSector(rawbuf, lba))
1533 {
1534 uint8 qbuf[12];
1535
1536 CDUtility::subq_deinterleave(rawbuf + 2352, qbuf);
1537 if(CDUtility::subq_check_checksum(qbuf) && (qbuf[0] & 0xF) == CDUtility::ADR_CURPOS)
1538 {
1539 uint8 qm = qbuf[7];
1540 uint8 qs = qbuf[8];
1541 uint8 qf = qbuf[9];
1542
1543 uint8 hm = rawbuf[12];
1544 uint8 hs = rawbuf[13];
1545 uint8 hf = rawbuf[14];
1546
1547 uint8 lm, ls, lf;
1548
1549 CDUtility::LBA_to_AMSF(lba, &lm, &ls, &lf);
1550 lm = CDUtility::U8_to_BCD(lm);
1551 ls = CDUtility::U8_to_BCD(ls);
1552 lf = CDUtility::U8_to_BCD(lf);
1553
1554 if(qm != hm || qs != hs || qf != hf)
1555 {
1556 throw MDFN_Error(0, _("Disc %zu of %zu: Q-subchannel versus sector header absolute time mismatch at lba=%d; Q subchannel: %02x:%02x:%02x, Sector header: %02x:%02x:%02x"),
1557 i + 1, cdifs->size(),
1558 lba,
1559 qm, qs, qf,
1560 hm, hs, hf);
1561 }
1562
1563 if(lm != hm || ls != hs || lf != hf)
1564 {
1565 throw MDFN_Error(0, _("Disc %zu of %zu: Sector header absolute time broken at lba=%d(%02x:%02x:%02x); Sector header: %02x:%02x:%02x"),
1566 i + 1, cdifs->size(),
1567 lba,
1568 lm, ls, lf,
1569 hm, hs, hf);
1570 }
1571
1572 if(lba >= 0)
1573 did_check = true;
1574 }
1575 }
1576 }
1577
1578 if(!did_check)
1579 {
1580 throw MDFN_Error(0, _("Disc %zu of %zu: No valid Q subchannel ADR_CURPOS data present at lba 0-15?!"), i + 1, cdifs->size());
1581 }
1582 }
1583 }
1584 }
1585
InitCommon(std::vector<CDInterface * > * CDInterfaces,const bool IsPSF=false,const bool WantPIOMem=false)1586 static MDFN_COLD void InitCommon(std::vector<CDInterface*> *CDInterfaces, const bool IsPSF = false, const bool WantPIOMem = false)
1587 {
1588 unsigned region;
1589 int sls, sle;
1590 bool correct_aspect;
1591
1592 #if PSX_DBGPRINT_ENABLE
1593 psx_dbg_level = MDFN_GetSettingUI("psx.dbg_level");
1594 #endif
1595
1596 cdifs = CDInterfaces;
1597 region = CalcDiscSCEx();
1598 if(MDFN_GetSettingB("psx.cd_sanity"))
1599 DiscSanityChecks();
1600 else
1601 MDFN_printf(_("WARNING: CD (image) sanity checks disabled."));
1602
1603 if(!MDFN_GetSettingB("psx.region_autodetect"))
1604 region = MDFN_GetSettingI("psx.region_default");
1605
1606 MDFN_printf("\n");
1607
1608 for(auto const* rle = Region_List; rle->string; rle++)
1609 {
1610 if((unsigned)rle->number == region)
1611 {
1612 MDFN_printf(_("Region: %s\n"), rle->description);
1613 break;
1614 }
1615 }
1616
1617 sls = MDFN_GetSettingI((region == REGION_EU) ? "psx.slstartp" : "psx.slstart");
1618 sle = MDFN_GetSettingI((region == REGION_EU) ? "psx.slendp" : "psx.slend");
1619 correct_aspect = MDFN_GetSettingB("psx.correct_aspect");
1620
1621 if(sls > sle)
1622 {
1623 int tmp = sls;
1624 sls = sle;
1625 sle = tmp;
1626 }
1627
1628 CPU = new PS_CPU();
1629 SPU = new PS_SPU();
1630 GPU_Init(region == REGION_EU);
1631 CDC = new PS_CDC();
1632 FIO = new FrontIO();
1633
1634 MDFN_printf("\n");
1635 for(unsigned pp = 0; pp < 2; pp++)
1636 {
1637 char buf[64];
1638 bool sv;
1639
1640 trio_snprintf(buf, sizeof(buf), "psx.input.pport%u.multitap", pp + 1);
1641 sv = MDFN_GetSettingB(buf);
1642 FIO->SetMultitap(pp, sv);
1643
1644 MDFN_printf(_("Multitap on PSX Port %u: %s\n"), pp + 1, sv ? _("Enabled") : _("Disabled"));
1645 }
1646
1647 FIO->SetAMCT(MDFN_GetSettingB("psx.input.analog_mode_ct"), MDFN_GetSettingUI("psx.input.analog_mode_ct.compare"));
1648 for(unsigned i = 0; i < 8; i++)
1649 {
1650 char buf[64];
1651
1652 trio_snprintf(buf, sizeof(buf), "psx.input.port%u.gun_chairs", i + 1);
1653 FIO->SetCrosshairsColor(i, MDFN_GetSettingUI(buf));
1654
1655 {
1656 bool mcsv;
1657
1658 trio_snprintf(buf, sizeof(buf), "psx.input.port%u.memcard", i + 1);
1659 mcsv = !IsPSF && MDFN_GetSettingB(buf);
1660 FIO->SetMemcard(i, mcsv);
1661
1662 //MDFN_printf(_("Memcard on Virtual Port %u: %s\n"), i + 1, mcsv ? _("Enabled") : _("Disabled"));
1663 }
1664 }
1665
1666 DMA_Init();
1667
1668 GPU_SetGetVideoParams(&EmulatedPSX, correct_aspect, sls, sle, MDFN_GetSettingB("psx.h_overscan"));
1669
1670 CDC->SetDisc(true, NULL, NULL);
1671
1672 BIOSROM = new MultiAccessSizeMem<512 * 1024, false>();
1673
1674 if(WantPIOMem)
1675 PIOMem = new MultiAccessSizeMem<65536, false>();
1676 else
1677 PIOMem = NULL;
1678
1679 for(uint32 ma = 0x00000000; ma < 0x00800000; ma += 2048 * 1024)
1680 {
1681 CPU->SetFastMap(MainRAM.data8, 0x00000000 + ma, 2048 * 1024);
1682 CPU->SetFastMap(MainRAM.data8, 0x80000000 + ma, 2048 * 1024);
1683 CPU->SetFastMap(MainRAM.data8, 0xA0000000 + ma, 2048 * 1024);
1684 }
1685
1686 CPU->SetFastMap(BIOSROM->data8, 0x1FC00000, 512 * 1024);
1687 CPU->SetFastMap(BIOSROM->data8, 0x9FC00000, 512 * 1024);
1688 CPU->SetFastMap(BIOSROM->data8, 0xBFC00000, 512 * 1024);
1689
1690 if(PIOMem)
1691 {
1692 CPU->SetFastMap(PIOMem->data8, 0x1F000000, 65536);
1693 CPU->SetFastMap(PIOMem->data8, 0x9F000000, 65536);
1694 CPU->SetFastMap(PIOMem->data8, 0xBF000000, 65536);
1695 }
1696
1697
1698 MDFNMP_Init(1024, ((uint64)1 << 29) / 1024);
1699 MDFNMP_AddRAM(2048 * 1024, 0x00000000, MainRAM.data8);
1700 //MDFNMP_AddRAM(1024, 0x1F800000, ScratchRAM.data8);
1701
1702 //
1703 //
1704 //
1705 const char *biospath_sname;
1706
1707 if(region == REGION_JP)
1708 biospath_sname = "psx.bios_jp";
1709 else if(region == REGION_EU)
1710 biospath_sname = "psx.bios_eu";
1711 else if(region == REGION_NA)
1712 biospath_sname = "psx.bios_na";
1713 else
1714 abort();
1715
1716 {
1717 std::string biospath = MDFN_MakeFName(MDFNMKF_FIRMWARE, 0, MDFN_GetSettingS(biospath_sname));
1718 FileStream BIOSFile(biospath, FileStream::MODE_READ);
1719
1720 if(BIOSFile.size() != 524288)
1721 throw MDFN_Error(0, _("BIOS file \"%s\" is of an incorrect size."), biospath.c_str());
1722
1723 BIOSFile.read(BIOSROM->data8, 512 * 1024);
1724 BIOS_SHA256 = sha256(BIOSROM->data8, 512 * 1024);
1725
1726 if(MDFN_GetSettingB("psx.bios_sanity"))
1727 {
1728 bool bios_recognized = false;
1729
1730 for(auto const& dbe : BIOS_DB)
1731 {
1732 if(BIOS_SHA256 == dbe.sd)
1733 {
1734 if(dbe.bad)
1735 throw MDFN_Error(0, _("BIOS file \"%s\" is a known bad dump."), biospath.c_str());
1736
1737 if(dbe.region != region)
1738 throw MDFN_Error(0, _("BIOS file \"%s\" is not the proper BIOS for the region of PS1 being emulated."), biospath.c_str());
1739
1740 bios_recognized = true;
1741 break;
1742 }
1743 }
1744
1745 if(!bios_recognized)
1746 MDFN_printf(_("Warning: Unrecognized BIOS.\n"));
1747 }
1748 else
1749 MDFN_printf(_("WARNING: BIOS ROM sanity checks disabled.\n"));
1750 }
1751
1752 if(!IsPSF)
1753 {
1754 for(int i = 0; i < 8; i++)
1755 {
1756 char ext[64];
1757 trio_snprintf(ext, sizeof(ext), "%d.mcr", i);
1758 MDFN_BackupSavFile(5, ext);
1759 FIO->LoadMemcard(i, MDFN_MakeFName(MDFNMKF_SAV, 0, ext));
1760 }
1761
1762 for(int i = 0; i < 8; i++)
1763 {
1764 Memcard_PrevDC[i] = FIO->GetMemcardDirtyCount(i);
1765 Memcard_SaveDelay[i] = -1;
1766 }
1767 }
1768
1769 #ifdef WANT_DEBUGGER
1770 DBG_Init();
1771 #endif
1772
1773 PSX_Reset(true);
1774 }
1775
LoadEXE(Stream * fp,bool ignore_pcsp=false)1776 static MDFN_COLD void LoadEXE(Stream* fp, bool ignore_pcsp = false)
1777 {
1778 uint8 raw_header[0x800];
1779 uint32 PC;
1780 uint32 SP;
1781 uint32 TextStart;
1782 uint32 TextSize;
1783
1784 fp->read(raw_header, sizeof(raw_header));
1785
1786 PC = MDFN_de32lsb(&raw_header[0x10]);
1787 SP = MDFN_de32lsb(&raw_header[0x30]);
1788 TextStart = MDFN_de32lsb(&raw_header[0x18]);
1789 TextSize = MDFN_de32lsb(&raw_header[0x1C]);
1790
1791 if(ignore_pcsp)
1792 MDFN_printf("TextStart=0x%08x\nTextSize=0x%08x\n", TextStart, TextSize);
1793 else
1794 MDFN_printf("PC=0x%08x\nSP=0x%08x\nTextStart=0x%08x\nTextSize=0x%08x\n", PC, SP, TextStart, TextSize);
1795
1796 TextStart &= 0x1FFFFF;
1797
1798 if(TextSize > 2048 * 1024)
1799 {
1800 throw(MDFN_Error(0, "Text section too large"));
1801 }
1802
1803 //if(TextSize > (size - 0x800))
1804 // throw(MDFN_Error(0, "Text section recorded size is larger than data available in file. Header=0x%08x, Available=0x%08x", TextSize, size - 0x800));
1805
1806 //if(TextSize < (size - 0x800))
1807 // throw(MDFN_Error(0, "Text section recorded size is smaller than data available in file. Header=0x%08x, Available=0x%08x", TextSize, size - 0x800));
1808
1809 if(!TextMem.size())
1810 {
1811 TextMem_Start = TextStart;
1812 TextMem.resize(TextSize);
1813 }
1814
1815 if(TextStart < TextMem_Start)
1816 {
1817 uint32 old_size = TextMem.size();
1818
1819 //printf("RESIZE: 0x%08x\n", TextMem_Start - TextStart);
1820
1821 TextMem.resize(old_size + TextMem_Start - TextStart);
1822 memmove(&TextMem[TextMem_Start - TextStart], &TextMem[0], old_size);
1823
1824 TextMem_Start = TextStart;
1825 }
1826
1827 if(TextMem.size() < (TextStart - TextMem_Start + TextSize))
1828 TextMem.resize(TextStart - TextMem_Start + TextSize);
1829
1830 fp->read(&TextMem[TextStart - TextMem_Start], TextSize);
1831
1832 {
1833 uint64 extra_data = fp->read_discard();
1834
1835 if(extra_data > 0)
1836 throw MDFN_Error(0, _("0x%08llx bytes of extra data after EXE text section."), (unsigned long long)extra_data);
1837 }
1838
1839 //
1840 //
1841 //
1842
1843 // BIOS patch
1844 BIOSROM->WriteU32(0x6990, (3 << 26) | ((0xBF001000 >> 2) & ((1 << 26) - 1)));
1845 // BIOSROM->WriteU32(0x691C, (3 << 26) | ((0xBF001000 >> 2) & ((1 << 26) - 1)));
1846
1847 // printf("INSN: 0x%08x\n", BIOSROM->ReadU32(0x6990));
1848 // exit(1);
1849 uint8 *po;
1850
1851 po = &PIOMem->data8[0x0800];
1852
1853 MDFN_en32lsb(po, (0x0 << 26) | (31 << 21) | (0x8 << 0)); // JR
1854 po += 4;
1855 MDFN_en32lsb(po, 0); // NOP(kinda)
1856 po += 4;
1857
1858 po = &PIOMem->data8[0x1000];
1859
1860 // Load cacheable-region target PC into r2
1861 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (0x9F001010 >> 16)); // LUI
1862 po += 4;
1863 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (2 << 16) | (0x9F001010 & 0xFFFF)); // ORI
1864 po += 4;
1865
1866 // Jump to r2
1867 MDFN_en32lsb(po, (0x0 << 26) | (2 << 21) | (0x8 << 0)); // JR
1868 po += 4;
1869 MDFN_en32lsb(po, 0); // NOP(kinda)
1870 po += 4;
1871
1872 //
1873 // 0x9F001010:
1874 //
1875
1876 // Load source address into r8
1877 uint32 sa = 0x9F000000 + 65536;
1878 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (sa >> 16)); // LUI
1879 po += 4;
1880 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (8 << 16) | (sa & 0xFFFF)); // ORI
1881 po += 4;
1882
1883 // Load dest address into r9
1884 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (TextMem_Start >> 16)); // LUI
1885 po += 4;
1886 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (9 << 16) | (TextMem_Start & 0xFFFF)); // ORI
1887 po += 4;
1888
1889 // Load size into r10
1890 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (TextMem.size() >> 16)); // LUI
1891 po += 4;
1892 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (10 << 16) | (TextMem.size() & 0xFFFF)); // ORI
1893 po += 4;
1894
1895 //
1896 // Loop begin
1897 //
1898
1899 MDFN_en32lsb(po, (0x24 << 26) | (8 << 21) | (1 << 16)); // LBU to r1
1900 po += 4;
1901
1902 MDFN_en32lsb(po, (0x08 << 26) | (10 << 21) | (10 << 16) | 0xFFFF); // Decrement size
1903 po += 4;
1904
1905 MDFN_en32lsb(po, (0x28 << 26) | (9 << 21) | (1 << 16)); // SB from r1
1906 po += 4;
1907
1908 MDFN_en32lsb(po, (0x08 << 26) | (8 << 21) | (8 << 16) | 0x0001); // Increment source addr
1909 po += 4;
1910
1911 MDFN_en32lsb(po, (0x05 << 26) | (0 << 21) | (10 << 16) | (-5 & 0xFFFF));
1912 po += 4;
1913 MDFN_en32lsb(po, (0x08 << 26) | (9 << 21) | (9 << 16) | 0x0001); // Increment dest addr
1914 po += 4;
1915
1916 //
1917 // Loop end
1918 //
1919
1920 // Load SP into r29
1921 if(ignore_pcsp)
1922 {
1923 po += 16;
1924 }
1925 else
1926 {
1927 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (SP >> 16)); // LUI
1928 po += 4;
1929 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (29 << 16) | (SP & 0xFFFF)); // ORI
1930 po += 4;
1931
1932 // Load PC into r2
1933 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | ((PC >> 16) | 0x8000)); // LUI
1934 po += 4;
1935 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (2 << 16) | (PC & 0xFFFF)); // ORI
1936 po += 4;
1937 }
1938
1939 // Half-assed instruction cache flush. ;)
1940 for(unsigned i = 0; i < 1024; i++)
1941 {
1942 MDFN_en32lsb(po, 0);
1943 po += 4;
1944 }
1945
1946
1947
1948 // Jump to r2
1949 MDFN_en32lsb(po, (0x0 << 26) | (2 << 21) | (0x8 << 0)); // JR
1950 po += 4;
1951 MDFN_en32lsb(po, 0); // NOP(kinda)
1952 po += 4;
1953 }
1954
PSF1Loader(VirtualFS * vfs,const std::string & dir_path,Stream * fp)1955 PSF1Loader::PSF1Loader(VirtualFS* vfs, const std::string& dir_path, Stream *fp)
1956 {
1957 tags = Load(0x01, 2033664, vfs, dir_path, fp);
1958 }
1959
~PSF1Loader()1960 PSF1Loader::~PSF1Loader()
1961 {
1962
1963 }
1964
HandleEXE(Stream * fp,bool ignore_pcsp)1965 void PSF1Loader::HandleEXE(Stream* fp, bool ignore_pcsp)
1966 {
1967 LoadEXE(fp, ignore_pcsp);
1968 }
1969
1970 static void Cleanup(void);
Load(GameFile * gf)1971 static MDFN_COLD void Load(GameFile* gf)
1972 {
1973 try
1974 {
1975 const bool IsPSF = PSFLoader::TestMagic(0x01, gf->stream);
1976
1977 if(!TestMagic(gf))
1978 throw MDFN_Error(0, _("File format is unknown to module \"%s\"."), MDFNGameInfo->shortname);
1979
1980 gf->stream->rewind();
1981
1982 if(MDFN_GetSettingS("psx.dbg_exe_cdpath") != "") // For testing/debug purposes.
1983 {
1984 RMD_Drive dr;
1985 RMD_DriveDefaults drdef;
1986
1987 dr.Name = std::string("Virtual CD Drive");
1988 dr.PossibleStates.push_back(RMD_State({"Tray Open", false, false, true}));
1989 dr.PossibleStates.push_back(RMD_State({"Tray Closed (Empty)", false, false, false}));
1990 dr.PossibleStates.push_back(RMD_State({"Tray Closed", true, true, false}));
1991 dr.CompatibleMedia.push_back(0);
1992 dr.MediaMtoPDelay = 2000;
1993
1994 drdef.State = 2; // Tray Closed
1995 drdef.Media = 0;
1996 drdef.Orientation = 0;
1997
1998 MDFNGameInfo->RMD->Drives.push_back(dr);
1999 MDFNGameInfo->RMD->DrivesDefaults.push_back(drdef);
2000 MDFNGameInfo->RMD->MediaTypes.push_back(RMD_MediaType({"CD"}));
2001 MDFNGameInfo->RMD->Media.push_back(RMD_Media({"Test CD", 0}));
2002
2003 static std::vector<CDInterface*> CDInterfaces;
2004 CDInterfaces.clear();
2005 CDInterfaces.push_back(CDInterface::Open(&NVFS, MDFN_GetSettingS("psx.dbg_exe_cdpath"), false, MDFN_GetSettingUI("affinity.cd")));
2006 InitCommon(&CDInterfaces, IsPSF, true);
2007 }
2008 else
2009 InitCommon(NULL, IsPSF, true);
2010
2011 TextMem.resize(0);
2012
2013 if(IsPSF)
2014 {
2015 psf_loader = new PSF1Loader(gf->vfs, gf->dir, gf->stream);
2016
2017 std::vector<std::string> SongNames;
2018
2019 SongNames.push_back(psf_loader->tags.GetTag("title"));
2020
2021 Player_Init(1, psf_loader->tags.GetTag("game"), psf_loader->tags.GetTag("artist"), psf_loader->tags.GetTag("copyright"), SongNames);
2022 }
2023 else
2024 LoadEXE(gf->stream);
2025 }
2026 catch(std::exception &e)
2027 {
2028 Cleanup();
2029 throw;
2030 }
2031 }
2032
LoadCD(std::vector<CDInterface * > * CDInterfaces)2033 static MDFN_COLD void LoadCD(std::vector<CDInterface*> *CDInterfaces)
2034 {
2035 try
2036 {
2037 InitCommon(CDInterfaces);
2038 }
2039 catch(std::exception &e)
2040 {
2041 Cleanup();
2042 throw;
2043 }
2044 }
2045
Cleanup(void)2046 static MDFN_COLD void Cleanup(void)
2047 {
2048 TextMem.resize(0);
2049
2050 if(psf_loader)
2051 {
2052 delete psf_loader;
2053 psf_loader = NULL;
2054 }
2055
2056 if(CDC)
2057 {
2058 delete CDC;
2059 CDC = NULL;
2060 }
2061
2062 if(SPU)
2063 {
2064 delete SPU;
2065 SPU = NULL;
2066 }
2067
2068 GPU_Kill();
2069
2070 if(CPU)
2071 {
2072 delete CPU;
2073 CPU = NULL;
2074 }
2075
2076 if(FIO)
2077 {
2078 delete FIO;
2079 FIO = NULL;
2080 }
2081
2082 DMA_Kill();
2083
2084 if(BIOSROM)
2085 {
2086 delete BIOSROM;
2087 BIOSROM = NULL;
2088 }
2089
2090 if(PIOMem)
2091 {
2092 delete PIOMem;
2093 PIOMem = NULL;
2094 }
2095
2096 cdifs = NULL;
2097 }
2098
CloseGame(void)2099 static MDFN_COLD void CloseGame(void)
2100 {
2101 if(!psf_loader)
2102 {
2103 for(int i = 0; i < 8; i++)
2104 {
2105 // If there's an error saving one memcard, don't skip trying to save the other, since it might succeed and
2106 // we can reduce potential data loss!
2107 try
2108 {
2109 char ext[64];
2110 trio_snprintf(ext, sizeof(ext), "%d.mcr", i);
2111
2112 FIO->SaveMemcard(i, MDFN_MakeFName(MDFNMKF_SAV, 0, ext));
2113 }
2114 catch(std::exception &e)
2115 {
2116 MDFND_OutputNotice(MDFN_NOTICE_ERROR, e.what());
2117 }
2118 }
2119 }
2120
2121 Cleanup();
2122 }
2123
2124
SetInput(unsigned port,const char * type,uint8 * ptr)2125 static void SetInput(unsigned port, const char *type, uint8 *ptr)
2126 {
2127 if(psf_loader)
2128 FIO->SetInput(port, "none", NULL);
2129 else
2130 FIO->SetInput(port, type, ptr);
2131 }
2132
TransformInput(void)2133 static void TransformInput(void)
2134 {
2135 FIO->TransformInput();
2136 }
2137
StateAction(StateMem * sm,const unsigned load,const bool data_only)2138 static void StateAction(StateMem *sm, const unsigned load, const bool data_only)
2139 {
2140 if(!data_only)
2141 {
2142 sha256_digest sr_dig = BIOS_SHA256;
2143
2144 SFORMAT SRDStateRegs[] =
2145 {
2146 SFPTR8(sr_dig.data(), sr_dig.size()),
2147 SFEND
2148 };
2149
2150 MDFNSS_StateAction(sm, load, data_only, SRDStateRegs, "BIOS_HASH", true);
2151
2152 if(load && sr_dig != BIOS_SHA256)
2153 throw MDFN_Error(0, _("BIOS hash mismatch(save state created under a different BIOS)!"));
2154 }
2155
2156
2157 SFORMAT StateRegs[] =
2158 {
2159 SFPTR8(MainRAM.data8, 1024 * 2048),
2160 SFPTR32(SysControl.Regs, 9),
2161
2162 SFVAR(PSX_PRNG.lcgo),
2163 SFVAR(PSX_PRNG.x),
2164 SFVAR(PSX_PRNG.y),
2165 SFVAR(PSX_PRNG.z),
2166 SFVAR(PSX_PRNG.c),
2167
2168 SFEND
2169 };
2170
2171 MDFNSS_StateAction(sm, load, data_only, StateRegs, "MAIN");
2172
2173 CPU->StateAction(sm, load, data_only);
2174 DMA_StateAction(sm, load, data_only);
2175 TIMER_StateAction(sm, load, data_only);
2176 SIO_StateAction(sm, load, data_only);
2177
2178 CDC->StateAction(sm, load, data_only);
2179 MDEC_StateAction(sm, load, data_only);
2180 GPU_StateAction(sm, load, data_only);
2181 SPU->StateAction(sm, load, data_only);
2182
2183 FIO->StateAction(sm, load, data_only);
2184
2185 IRQ_StateAction(sm, load, data_only); // Do it last.
2186
2187 if(load)
2188 {
2189 ForceEventUpdates(0); // FIXME to work with debugger step mode.
2190 }
2191 }
2192
SetMedia(uint32 drive_idx,uint32 state_idx,uint32 media_idx,uint32 orientation_idx)2193 static void SetMedia(uint32 drive_idx, uint32 state_idx, uint32 media_idx, uint32 orientation_idx)
2194 {
2195 const RMD_Layout* rmd = EmulatedPSX.RMD;
2196 const RMD_Drive* rd = &rmd->Drives[drive_idx];
2197 const RMD_State* rs = &rd->PossibleStates[state_idx];
2198
2199 //printf("%d %d %d %d\n", drive_idx, state_idx, media_idx, orientation_idx);
2200
2201 if(rs->MediaPresent && rs->MediaUsable)
2202 {
2203 CDC->SetDisc(false, (*cdifs)[media_idx], cdifs_scex_ids[media_idx]);
2204 }
2205 else
2206 {
2207 CDC->SetDisc(rs->MediaCanChange, NULL, NULL);
2208 }
2209 }
2210
DoSimpleCommand(int cmd)2211 static void DoSimpleCommand(int cmd)
2212 {
2213 switch(cmd)
2214 {
2215 case MDFN_MSC_RESET: PSX_Reset(false); break;
2216 case MDFN_MSC_POWER: PSX_Reset(true); break;
2217 }
2218 }
2219
2220 static const CheatInfoStruct CheatInfo =
2221 {
2222 NULL,
2223 NULL,
2224
2225 NULL,
2226 NULL,
2227
2228 CheatFormats_PSX
2229 };
2230
2231
2232 static const FileExtensionSpecStruct KnownExtensions[] =
2233 {
2234 { ".psf", -20, gettext_noop("PSF1 Rip") },
2235 { ".minipsf", -20, gettext_noop("MiniPSF1 Rip") },
2236 { ".psx", 0, gettext_noop("PS-X Executable") },
2237 { ".exe", -80, gettext_noop("PS-X Executable") },
2238 { NULL, 0, NULL }
2239 };
2240
2241 static const MDFNSetting PSXSettings[] =
2242 {
2243 { "psx.input.mouse_sensitivity", MDFNSF_NOFLAGS, gettext_noop("Emulated mouse sensitivity."), NULL, MDFNST_FLOAT, "1.00", NULL, NULL },
2244
2245 { "psx.input.analog_mode_ct", MDFNSF_NOFLAGS, gettext_noop("Enable analog mode combo-button alternate toggle."), gettext_noop("When enabled, instead of the configured Analog mode toggle button for the emulated DualShock, use a combination of buttons held down for one emulated second to toggle it instead. The specific combination is controlled via the \"psx.input.analog_mode_ct.compare\" setting, which by default is Select, Start, and all four shoulder buttons."), MDFNST_BOOL, "0", NULL, NULL },
2246 { "psx.input.analog_mode_ct.compare", MDFNSF_NOFLAGS, gettext_noop("Compare value for analog mode combo-button alternate toggle."), gettext_noop("0x0001=SELECT\n0x0002=L3\n0x0004=R3\n0x0008=START\n0x0010=D-Pad UP\n0x0020=D-Pad Right\n0x0040=D-Pad Down\n0x0080=D-Pad Left\n0x0100=L2\n0x0200=R2\n0x0400=L1\n0x0800=R1\n0x1000=△\n0x2000=○\n0x4000=x\n0x8000=□"), MDFNST_UINT, "0x0F09", "0x0000", "0xFFFF" },
2247
2248 { "psx.input.pport1.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable multitap on PSX port 1."), gettext_noop("Makes 3 more virtual ports available.\n\nNOTE: Enabling multitap in games that don't fully support it may cause deleterious effects."), MDFNST_BOOL, "0", NULL, NULL }, //MDFNST_ENUM, "auto", NULL, NULL, NULL, NULL, MultiTap_List },
2249 { "psx.input.pport2.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Enable multitap on PSX port 2."), gettext_noop("Makes 3 more virtual ports available.\n\nNOTE: Enabling multitap in games that don't fully support it may cause deleterious effects."), MDFNST_BOOL, "0", NULL, NULL },
2250
2251 { "psx.input.port1.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memory card on virtual port 1."), NULL, MDFNST_BOOL, "1", NULL, NULL, },
2252 { "psx.input.port2.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memory card on virtual port 2."), NULL, MDFNST_BOOL, "1", NULL, NULL, },
2253 { "psx.input.port3.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memory card on virtual port 3."), NULL, MDFNST_BOOL, "1", NULL, NULL, },
2254 { "psx.input.port4.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memory card on virtual port 4."), NULL, MDFNST_BOOL, "1", NULL, NULL, },
2255 { "psx.input.port5.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memory card on virtual port 5."), NULL, MDFNST_BOOL, "1", NULL, NULL, },
2256 { "psx.input.port6.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memory card on virtual port 6."), NULL, MDFNST_BOOL, "1", NULL, NULL, },
2257 { "psx.input.port7.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memory card on virtual port 7."), NULL, MDFNST_BOOL, "1", NULL, NULL, },
2258 { "psx.input.port8.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Emulate memory card on virtual port 8."), NULL, MDFNST_BOOL, "1", NULL, NULL, },
2259
2260
2261 { "psx.input.port1.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 1."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFF0000", "0x000000", "0x1000000" },
2262 { "psx.input.port2.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 2."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x00FF00", "0x000000", "0x1000000" },
2263 { "psx.input.port3.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 3."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFF00FF", "0x000000", "0x1000000" },
2264 { "psx.input.port4.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 4."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFF8000", "0x000000", "0x1000000" },
2265 { "psx.input.port5.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 5."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0xFFFF00", "0x000000", "0x1000000" },
2266 { "psx.input.port6.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 6."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x00FFFF", "0x000000", "0x1000000" },
2267 { "psx.input.port7.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 7."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x0080FF", "0x000000", "0x1000000" },
2268 { "psx.input.port8.gun_chairs", MDFNSF_NOFLAGS, gettext_noop("Crosshairs color for lightgun on virtual port 8."), gettext_noop("A value of 0x1000000 disables crosshair drawing."), MDFNST_UINT, "0x8000FF", "0x000000", "0x1000000" },
2269
2270 { "psx.region_autodetect", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Attempt to auto-detect region of game."), NULL, MDFNST_BOOL, "1" },
2271 { "psx.region_default", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, gettext_noop("Default region to use."), gettext_noop("Used if region autodetection fails or is disabled."), MDFNST_ENUM, "jp", NULL, NULL, NULL, NULL, Region_List },
2272
2273 { "psx.bios_jp", MDFNSF_EMU_STATE | MDFNSF_CAT_PATH, gettext_noop("Path to the Japan SCPH-5500/v3.0J ROM BIOS"), gettext_noop("SHA-256 9c0421858e217805f4abe18698afea8d5aa36ff0727eb8484944e00eb5e7eadb"), MDFNST_STRING, "scph5500.bin" },
2274 { "psx.bios_na", MDFNSF_EMU_STATE | MDFNSF_CAT_PATH, gettext_noop("Path to the North America SCPH-5501/v3.0A ROM BIOS"), gettext_noop("SHA-256 11052b6499e466bbf0a709b1f9cb6834a9418e66680387912451e971cf8a1fef"), MDFNST_STRING, "scph5501.bin" },
2275 { "psx.bios_eu", MDFNSF_EMU_STATE | MDFNSF_CAT_PATH, gettext_noop("Path to the Europe SCPH-5502/v3.0E ROM BIOS"), gettext_noop("SHA-256 1faaa18fa820a0225e488d9f086296b8e6c46df739666093987ff7d8fd352c09"), MDFNST_STRING, "scph5502.bin" },
2276
2277 { "psx.bios_sanity", MDFNSF_NOFLAGS, gettext_noop("Enable BIOS ROM image sanity checks."), gettext_noop("Enables blacklisting of known bad BIOS dumps and known BIOS versions that don't match the region of the hardware being emulated.") , MDFNST_BOOL, "1" },
2278 { "psx.cd_sanity", MDFNSF_NOFLAGS, gettext_noop("Enable CD (image) sanity checks."), gettext_noop("Sanity checks are only performed on discs detected(via heuristics) to be PS1 discs. The checks primarily consist of ensuring that Q subchannel data is as expected for a typical commercially-released PS1 disc."), MDFNST_BOOL, "1" },
2279
2280 { "psx.spu.resamp_quality", MDFNSF_NOFLAGS, gettext_noop("SPU output resampler quality."),
2281 gettext_noop("0 is lowest quality and CPU usage, 10 is highest quality and CPU usage. The resampler that this setting refers to is used for converting from 44.1KHz to the sampling rate of the host audio device Mednafen is using. Changing Mednafen's output rate, via the \"sound.rate\" setting, to \"44100\" may bypass the resampler, which can decrease CPU usage by Mednafen, and can increase or decrease audio quality, depending on various operating system and hardware factors."), MDFNST_UINT, "5", "0", "10" },
2282
2283 { "psx.correct_aspect", MDFNSF_NOFLAGS, gettext_noop("Correct aspect ratio."), gettext_noop("Disabling aspect ratio correction with this setting should be considered a hack.\n\nIf disabling it to allow for sharper pixels by also separately disabling interpolation(though using Mednafen's \"autoipsharper\" OpenGL shader is usually a better option), remember to use scale factors that are multiples of 2, or else games that use high-resolution and interlaced modes will have distorted pixels.\n\nDisabling aspect ratio correction with this setting will allow for the QuickTime movie recording feature to produce much smaller files using much less CPU time."), MDFNST_BOOL, "1" },
2284
2285 { "psx.slstart", MDFNSF_NOFLAGS, gettext_noop("First displayed scanline in NTSC mode."), NULL, MDFNST_INT, "0", "0", "239" },
2286 { "psx.slend", MDFNSF_NOFLAGS, gettext_noop("Last displayed scanline in NTSC mode."), NULL, MDFNST_INT, "239", "0", "239" },
2287
2288 { "psx.slstartp", MDFNSF_NOFLAGS, gettext_noop("First displayed scanline in PAL mode."), NULL, MDFNST_INT, "0", "0", "287" }, // 14
2289 { "psx.slendp", MDFNSF_NOFLAGS, gettext_noop("Last displayed scanline in PAL mode."), NULL, MDFNST_INT, "287", "0", "287" }, // 275
2290
2291 { "psx.h_overscan", MDFNSF_NOFLAGS, gettext_noop("Show horizontal overscan area."), NULL, MDFNST_BOOL, "1" },
2292
2293 #if PSX_DBGPRINT_ENABLE
2294 { "psx.dbg_level", MDFNSF_NOFLAGS, gettext_noop("Debug printf verbosity level."), NULL, MDFNST_UINT, "0", "0", "4" },
2295 #endif
2296
2297 { "psx.dbg_exe_cdpath", MDFNSF_SUPPRESS_DOC | MDFNSF_CAT_PATH, gettext_noop("CD image to use with .PSX/.EXE loading."), NULL, MDFNST_STRING, "" },
2298
2299 { NULL },
2300 };
2301
2302 // Note for the future: If we ever support PSX emulation with non-8-bit RGB color components, or add a new linear RGB colorspace to MDFN_PixelFormat, we'll need
2303 // to buffer the intermediate 24-bit non-linear RGB calculation into an array and pass that into the GPULineHook stuff, otherwise netplay could break when
2304 // an emulated GunCon is used.
2305 MDFNGI EmulatedPSX =
2306 {
2307 "psx",
2308 "Sony PlayStation",
2309 KnownExtensions,
2310 MODPRIO_INTERNAL_HIGH,
2311 #ifdef WANT_DEBUGGER
2312 &PSX_DBGInfo,
2313 #else
2314 NULL,
2315 #endif
2316 FIO_PortInfo,
2317 NULL,
2318 Load,
2319 TestMagic,
2320 LoadCD,
2321 TestMagicCD,
2322 CloseGame,
2323
2324 NULL, //ToggleLayer,
2325 "GPU\0", //"Background Scroll\0Foreground Scroll\0Sprites\0",
2326
2327 NULL,
2328 NULL,
2329
2330 NULL,
2331 0,
2332
2333 CheatInfo,
2334
2335 false,
2336 StateAction,
2337 Emulate,
2338 TransformInput,
2339 SetInput,
2340 SetMedia,
2341 DoSimpleCommand,
2342 NULL,
2343 PSXSettings,
2344 MDFN_MASTERCLOCK_FIXED(33868800),
2345 0,
2346
2347 true, // Multires possible?
2348
2349 //
2350 // Note: Following video settings will be overwritten during game load.
2351 //
2352 0, // lcm_width
2353 0, // lcm_height
2354 NULL, // Dummy
2355
2356 320, // Nominal width
2357 240, // Nominal height
2358
2359 0, // Framebuffer width
2360 0, // Framebuffer height
2361 //
2362 //
2363 //
2364
2365 2, // Number of output sound channels
2366
2367 };
2368