lightrec: allow to switch to pcsx's interpreter anytime
[pcsx_rearmed.git] / libpcsxcore / misc.c
... / ...
CommitLineData
1/***************************************************************************
2 * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
18 ***************************************************************************/
19
20/*
21* Miscellaneous functions, including savestates and CD-ROM loading.
22*/
23
24#include <stddef.h>
25#include "misc.h"
26#include "cdrom.h"
27#include "mdec.h"
28#include "gpu.h"
29#include "ppf.h"
30#include "database.h"
31#include "lightrec/plugin.h"
32#include <zlib.h>
33
34char CdromId[10] = "";
35char CdromLabel[33] = "";
36
37// PSX Executable types
38#define PSX_EXE 1
39#define CPE_EXE 2
40#define COFF_EXE 3
41#define INVALID_EXE 4
42
43#define ISODCL(from, to) (to - from + 1)
44
45struct iso_directory_record {
46 char length [ISODCL (1, 1)]; /* 711 */
47 char ext_attr_length [ISODCL (2, 2)]; /* 711 */
48 char extent [ISODCL (3, 10)]; /* 733 */
49 char size [ISODCL (11, 18)]; /* 733 */
50 char date [ISODCL (19, 25)]; /* 7 by 711 */
51 char flags [ISODCL (26, 26)];
52 char file_unit_size [ISODCL (27, 27)]; /* 711 */
53 char interleave [ISODCL (28, 28)]; /* 711 */
54 char volume_sequence_number [ISODCL (29, 32)]; /* 723 */
55 unsigned char name_len [ISODCL (33, 33)]; /* 711 */
56 char name [1];
57};
58
59static void mmssdd( char *b, char *p )
60{
61 int m, s, d;
62 unsigned char *ub = (void *)b;
63 int block = (ub[3] << 24) | (ub[2] << 16) | (ub[1] << 8) | ub[0];
64
65 block += 150;
66 m = block / 4500; // minutes
67 block = block - m * 4500; // minutes rest
68 s = block / 75; // seconds
69 d = block - s * 75; // seconds rest
70
71 m = ((m / 10) << 4) | m % 10;
72 s = ((s / 10) << 4) | s % 10;
73 d = ((d / 10) << 4) | d % 10;
74
75 p[0] = m;
76 p[1] = s;
77 p[2] = d;
78}
79
80#define incTime() \
81 time[0] = btoi(time[0]); time[1] = btoi(time[1]); time[2] = btoi(time[2]); \
82 time[2]++; \
83 if(time[2] == 75) { \
84 time[2] = 0; \
85 time[1]++; \
86 if (time[1] == 60) { \
87 time[1] = 0; \
88 time[0]++; \
89 } \
90 } \
91 time[0] = itob(time[0]); time[1] = itob(time[1]); time[2] = itob(time[2]);
92
93#define READTRACK() \
94 if (!CDR_readTrack(time)) return -1; \
95 buf = (void *)CDR_getBuffer(); \
96 if (buf == NULL) return -1; \
97 else CheckPPFCache((u8 *)buf, time[0], time[1], time[2]);
98
99#define READDIR(_dir) \
100 READTRACK(); \
101 memcpy(_dir, buf + 12, 2048); \
102 \
103 incTime(); \
104 READTRACK(); \
105 memcpy(_dir + 2048, buf + 12, 2048);
106
107int GetCdromFile(u8 *mdir, u8 *time, char *filename) {
108 struct iso_directory_record *dir;
109 int retval = -1;
110 u8 ddir[4096];
111 u8 *buf;
112 int i;
113
114 // only try to scan if a filename is given
115 if (!strlen(filename)) return -1;
116
117 i = 0;
118 while (i < 4096) {
119 dir = (struct iso_directory_record*) &mdir[i];
120 if (dir->length[0] == 0) {
121 return -1;
122 }
123 i += (u8)dir->length[0];
124
125 if (dir->flags[0] & 0x2) { // it's a dir
126 if (!strnicmp((char *)&dir->name[0], filename, dir->name_len[0])) {
127 if (filename[dir->name_len[0]] != '\\') continue;
128
129 filename += dir->name_len[0] + 1;
130
131 mmssdd(dir->extent, (char *)time);
132 READDIR(ddir);
133 i = 0;
134 mdir = ddir;
135 }
136 } else {
137 if (!strnicmp((char *)&dir->name[0], filename, strlen(filename))) {
138 mmssdd(dir->extent, (char *)time);
139 retval = 0;
140 break;
141 }
142 }
143 }
144 return retval;
145}
146
147static const unsigned int gpu_ctl_def[] = {
148 0x00000000, 0x01000000, 0x03000000, 0x04000000,
149 0x05000800, 0x06c60260, 0x0703fc10, 0x08000027,
150};
151
152static const unsigned int gpu_data_def[] = {
153 0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
154 0xe5001000, 0xe6000000,
155 0x02000000, 0x00000000, 0x01ff03ff,
156};
157
158static void fake_bios_gpu_setup(void)
159{
160 int i;
161
162 for (i = 0; i < sizeof(gpu_ctl_def) / sizeof(gpu_ctl_def[0]); i++)
163 GPU_writeStatus(gpu_ctl_def[i]);
164
165 for (i = 0; i < sizeof(gpu_data_def) / sizeof(gpu_data_def[0]); i++)
166 GPU_writeData(gpu_data_def[i]);
167}
168
169int LoadCdrom() {
170 EXE_HEADER tmpHead;
171 struct iso_directory_record *dir;
172 u8 time[4], *buf;
173 u8 mdir[4096];
174 char exename[256];
175
176 // not the best place to do it, but since BIOS boot logo killer
177 // is just below, do it here
178 fake_bios_gpu_setup();
179
180 if (!Config.HLE && !Config.SlowBoot) {
181 // skip BIOS logos
182 psxRegs.pc = psxRegs.GPR.n.ra;
183 return 0;
184 }
185
186 time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
187
188 READTRACK();
189
190 // skip head and sub, and go to the root directory record
191 dir = (struct iso_directory_record*) &buf[12+156];
192
193 mmssdd(dir->extent, (char*)time);
194
195 READDIR(mdir);
196
197 // Load SYSTEM.CNF and scan for the main executable
198 if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") == -1) {
199 // if SYSTEM.CNF is missing, start an existing PSX.EXE
200 if (GetCdromFile(mdir, time, "PSX.EXE;1") == -1) return -1;
201
202 READTRACK();
203 }
204 else {
205 // read the SYSTEM.CNF
206 READTRACK();
207
208 sscanf((char *)buf + 12, "BOOT = cdrom:\\%255s", exename);
209 if (GetCdromFile(mdir, time, exename) == -1) {
210 sscanf((char *)buf + 12, "BOOT = cdrom:%255s", exename);
211 if (GetCdromFile(mdir, time, exename) == -1) {
212 char *ptr = strstr((char *)buf + 12, "cdrom:");
213 if (ptr != NULL) {
214 ptr += 6;
215 while (*ptr == '\\' || *ptr == '/') ptr++;
216 strncpy(exename, ptr, 255);
217 exename[255] = '\0';
218 ptr = exename;
219 while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') ptr++;
220 *ptr = '\0';
221 if (GetCdromFile(mdir, time, exename) == -1)
222 return -1;
223 } else
224 return -1;
225 }
226 }
227
228 // Read the EXE-Header
229 READTRACK();
230 }
231
232 memcpy(&tmpHead, buf + 12, sizeof(EXE_HEADER));
233
234 psxRegs.pc = SWAP32(tmpHead.pc0);
235 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
236 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
237 if (psxRegs.GPR.n.sp == 0) psxRegs.GPR.n.sp = 0x801fff00;
238
239 tmpHead.t_size = SWAP32(tmpHead.t_size);
240 tmpHead.t_addr = SWAP32(tmpHead.t_addr);
241
242 psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
243 psxCpu->Reset();
244
245 // Read the rest of the main executable
246 while (tmpHead.t_size & ~2047) {
247 void *ptr = (void *)PSXM(tmpHead.t_addr);
248
249 incTime();
250 READTRACK();
251
252 if (ptr != INVALID_PTR) memcpy(ptr, buf+12, 2048);
253
254 tmpHead.t_size -= 2048;
255 tmpHead.t_addr += 2048;
256 }
257
258 return 0;
259}
260
261int LoadCdromFile(const char *filename, EXE_HEADER *head) {
262 struct iso_directory_record *dir;
263 u8 time[4],*buf;
264 u8 mdir[4096];
265 char exename[256];
266 u32 size, addr;
267 void *mem;
268
269 sscanf(filename, "cdrom:\\%255s", exename);
270
271 time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
272
273 READTRACK();
274
275 // skip head and sub, and go to the root directory record
276 dir = (struct iso_directory_record *)&buf[12 + 156];
277
278 mmssdd(dir->extent, (char*)time);
279
280 READDIR(mdir);
281
282 if (GetCdromFile(mdir, time, exename) == -1) return -1;
283
284 READTRACK();
285
286 memcpy(head, buf + 12, sizeof(EXE_HEADER));
287 size = head->t_size;
288 addr = head->t_addr;
289
290 psxCpu->Clear(addr, size / 4);
291 psxCpu->Reset();
292
293 while (size & ~2047) {
294 incTime();
295 READTRACK();
296
297 mem = PSXM(addr);
298 if (mem != INVALID_PTR)
299 memcpy(mem, buf + 12, 2048);
300
301 size -= 2048;
302 addr += 2048;
303 }
304
305 return 0;
306}
307
308int CheckCdrom() {
309 struct iso_directory_record *dir;
310 unsigned char time[4];
311 char *buf;
312 unsigned char mdir[4096];
313 char exename[256];
314 int i, len, c;
315
316 FreePPFCache();
317
318 time[0] = itob(0);
319 time[1] = itob(2);
320 time[2] = itob(0x10);
321
322 READTRACK();
323
324 memset(CdromLabel, 0, sizeof(CdromLabel));
325 memset(CdromId, 0, sizeof(CdromId));
326 memset(exename, 0, sizeof(exename));
327
328 strncpy(CdromLabel, buf + 52, 32);
329
330 // skip head and sub, and go to the root directory record
331 dir = (struct iso_directory_record *)&buf[12 + 156];
332
333 mmssdd(dir->extent, (char *)time);
334
335 READDIR(mdir);
336
337 if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") != -1) {
338 READTRACK();
339
340 sscanf(buf + 12, "BOOT = cdrom:\\%255s", exename);
341 if (GetCdromFile(mdir, time, exename) == -1) {
342 sscanf(buf + 12, "BOOT = cdrom:%255s", exename);
343 if (GetCdromFile(mdir, time, exename) == -1) {
344 char *ptr = strstr(buf + 12, "cdrom:"); // possibly the executable is in some subdir
345 if (ptr != NULL) {
346 ptr += 6;
347 while (*ptr == '\\' || *ptr == '/') ptr++;
348 strncpy(exename, ptr, 255);
349 exename[255] = '\0';
350 ptr = exename;
351 while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') ptr++;
352 *ptr = '\0';
353 if (GetCdromFile(mdir, time, exename) == -1)
354 return -1; // main executable not found
355 } else
356 return -1;
357 }
358 }
359 /* Workaround for Wild Arms EU/US which has non-standard string causing incorrect region detection */
360 if (exename[0] == 'E' && exename[1] == 'X' && exename[2] == 'E' && exename[3] == '\\') {
361 size_t offset = 4;
362 size_t i, len = strlen(exename) - offset;
363 for (i = 0; i < len; i++)
364 exename[i] = exename[i + offset];
365 exename[i] = '\0';
366 }
367 } else if (GetCdromFile(mdir, time, "PSX.EXE;1") != -1) {
368 strcpy(exename, "PSX.EXE;1");
369 strcpy(CdromId, "SLUS99999");
370 } else
371 return -1; // SYSTEM.CNF and PSX.EXE not found
372
373 if (CdromId[0] == '\0') {
374 len = strlen(exename);
375 c = 0;
376 for (i = 0; i < len; ++i) {
377 if (exename[i] == ';' || c >= sizeof(CdromId) - 1)
378 break;
379 if (isalnum(exename[i]))
380 CdromId[c++] = exename[i];
381 }
382 }
383
384 if (CdromId[0] == '\0')
385 strcpy(CdromId, "SLUS99999");
386
387 if (Config.PsxAuto) { // autodetect system (pal or ntsc)
388 if (
389 /* Make sure Wild Arms SCUS-94608 is not detected as a PAL game. */
390 ((CdromId[0] == 's' || CdromId[0] == 'S') && (CdromId[2] == 'e' || CdromId[2] == 'E')) ||
391 !strncmp(CdromId, "DTLS3035", 8) ||
392 !strncmp(CdromId, "PBPX95001", 9) || // according to redump.org, these PAL
393 !strncmp(CdromId, "PBPX95007", 9) || // discs have a non-standard ID;
394 !strncmp(CdromId, "PBPX95008", 9)) // add more serials if they are discovered.
395 Config.PsxType = PSX_TYPE_PAL; // pal
396 else Config.PsxType = PSX_TYPE_NTSC; // ntsc
397 }
398
399 if (CdromLabel[0] == ' ') {
400 strncpy(CdromLabel, CdromId, 9);
401 }
402 SysPrintf(_("CD-ROM Label: %.32s\n"), CdromLabel);
403 SysPrintf(_("CD-ROM ID: %.9s\n"), CdromId);
404 SysPrintf(_("CD-ROM EXE Name: %.255s\n"), exename);
405
406 Apply_Hacks_Cdrom();
407
408 BuildPPFCache();
409
410 return 0;
411}
412
413static int PSXGetFileType(FILE *f) {
414 unsigned long current;
415 u8 mybuf[2048];
416 EXE_HEADER *exe_hdr;
417 FILHDR *coff_hdr;
418
419 current = ftell(f);
420 fseek(f, 0L, SEEK_SET);
421 if (fread(&mybuf, sizeof(mybuf), 1, f) != sizeof(mybuf))
422 goto io_fail;
423
424 fseek(f, current, SEEK_SET);
425
426 exe_hdr = (EXE_HEADER *)mybuf;
427 if (memcmp(exe_hdr->id, "PS-X EXE", 8) == 0)
428 return PSX_EXE;
429
430 if (mybuf[0] == 'C' && mybuf[1] == 'P' && mybuf[2] == 'E')
431 return CPE_EXE;
432
433 coff_hdr = (FILHDR *)mybuf;
434 if (SWAPu16(coff_hdr->f_magic) == 0x0162)
435 return COFF_EXE;
436
437 return INVALID_EXE;
438
439io_fail:
440#ifndef NDEBUG
441 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
442#endif
443 return INVALID_EXE;
444}
445
446// temporary pandora workaround..
447// FIXME: remove
448size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
449{
450 void *tmp;
451 size_t ret = 0;
452
453 tmp = malloc(size * nmemb);
454 if (tmp) {
455 ret = fread(tmp, size, nmemb, stream);
456 memcpy(ptr, tmp, size * nmemb);
457 free(tmp);
458 }
459 return ret;
460}
461
462int Load(const char *ExePath) {
463 FILE *tmpFile;
464 EXE_HEADER tmpHead;
465 int type;
466 int retval = 0;
467 u8 opcode;
468 u32 section_address, section_size;
469 void *mem;
470
471 strcpy(CdromId, "SLUS99999");
472 strcpy(CdromLabel, "SLUS_999.99");
473
474 tmpFile = fopen(ExePath, "rb");
475 if (tmpFile == NULL) {
476 SysPrintf(_("Error opening file: %s.\n"), ExePath);
477 retval = -1;
478 } else {
479 type = PSXGetFileType(tmpFile);
480 switch (type) {
481 case PSX_EXE:
482 if (fread(&tmpHead, sizeof(EXE_HEADER), 1, tmpFile) != sizeof(EXE_HEADER))
483 goto fail_io;
484 section_address = SWAP32(tmpHead.t_addr);
485 section_size = SWAP32(tmpHead.t_size);
486 mem = PSXM(section_address);
487 if (mem != INVALID_PTR) {
488 fseek(tmpFile, 0x800, SEEK_SET);
489 fread_to_ram(mem, section_size, 1, tmpFile);
490 psxCpu->Clear(section_address, section_size / 4);
491 }
492 psxRegs.pc = SWAP32(tmpHead.pc0);
493 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
494 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
495 if (psxRegs.GPR.n.sp == 0)
496 psxRegs.GPR.n.sp = 0x801fff00;
497 retval = 0;
498 break;
499 case CPE_EXE:
500 fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
501 do {
502 if (fread(&opcode, sizeof(opcode), 1, tmpFile) != sizeof(opcode))
503 goto fail_io;
504 switch (opcode) {
505 case 1: /* Section loading */
506 if (fread(&section_address, sizeof(section_address), 1, tmpFile) != sizeof(section_address))
507 goto fail_io;
508 if (fread(&section_size, sizeof(section_size), 1, tmpFile) != sizeof(section_size))
509 goto fail_io;
510 section_address = SWAPu32(section_address);
511 section_size = SWAPu32(section_size);
512#ifdef EMU_LOG
513 EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
514#endif
515 mem = PSXM(section_address);
516 if (mem != INVALID_PTR) {
517 fread_to_ram(mem, section_size, 1, tmpFile);
518 psxCpu->Clear(section_address, section_size / 4);
519 }
520 break;
521 case 3: /* register loading (PC only?) */
522 fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
523 if (fread(&psxRegs.pc, sizeof(psxRegs.pc), 1, tmpFile) != sizeof(psxRegs.pc))
524 goto fail_io;
525 psxRegs.pc = SWAPu32(psxRegs.pc);
526 break;
527 case 0: /* End of file */
528 break;
529 default:
530 SysPrintf(_("Unknown CPE opcode %02x at position %08x.\n"), opcode, ftell(tmpFile) - 1);
531 retval = -1;
532 break;
533 }
534 } while (opcode != 0 && retval == 0);
535 break;
536 case COFF_EXE:
537 SysPrintf(_("COFF files not supported.\n"));
538 retval = -1;
539 break;
540 case INVALID_EXE:
541 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
542 SysPrintf(_("(did you forget -cdfile ?)\n"));
543 retval = -1;
544 break;
545 }
546 }
547
548 if (retval != 0) {
549 CdromId[0] = '\0';
550 CdromLabel[0] = '\0';
551 }
552
553 fclose(tmpFile);
554 return retval;
555
556fail_io:
557#ifndef NDEBUG
558 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
559#endif
560 fclose(tmpFile);
561 return -1;
562}
563
564// STATES
565
566static void *zlib_open(const char *name, const char *mode)
567{
568 return gzopen(name, mode);
569}
570
571static int zlib_read(void *file, void *buf, u32 len)
572{
573 return gzread(file, buf, len);
574}
575
576static int zlib_write(void *file, const void *buf, u32 len)
577{
578 return gzwrite(file, buf, len);
579}
580
581static long zlib_seek(void *file, long offs, int whence)
582{
583 return gzseek(file, offs, whence);
584}
585
586static void zlib_close(void *file)
587{
588 gzclose(file);
589}
590
591struct PcsxSaveFuncs SaveFuncs = {
592 zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
593};
594
595static const char PcsxHeader[32] = "STv4 PCSX v" PCSX_VERSION;
596
597// Savestate Versioning!
598// If you make changes to the savestate version, please increment the value below.
599static const u32 SaveVersion = 0x8b410006;
600
601int SaveState(const char *file) {
602 void *f;
603 GPUFreeze_t *gpufP;
604 SPUFreeze_t *spufP;
605 int Size;
606 unsigned char *pMem;
607
608 f = SaveFuncs.open(file, "wb");
609 if (f == NULL) return -1;
610
611 new_dyna_before_save();
612
613 if (drc_is_lightrec() && Config.Cpu != CPU_INTERPRETER)
614 lightrec_plugin_sync_regs_to_pcsx();
615
616 SaveFuncs.write(f, (void *)PcsxHeader, 32);
617 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
618 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
619
620 pMem = (unsigned char *)malloc(128 * 96 * 3);
621 if (pMem == NULL) return -1;
622 GPU_getScreenPic(pMem);
623 SaveFuncs.write(f, pMem, 128 * 96 * 3);
624 free(pMem);
625
626 if (Config.HLE)
627 psxBiosFreeze(1);
628
629 SaveFuncs.write(f, psxM, 0x00200000);
630 SaveFuncs.write(f, psxR, 0x00080000);
631 SaveFuncs.write(f, psxH, 0x00010000);
632 // only partial save of psxRegisters to maintain savestate compat
633 SaveFuncs.write(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
634
635 // gpu
636 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
637 gpufP->ulFreezeVersion = 1;
638 GPU_freeze(1, gpufP);
639 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
640 free(gpufP);
641
642 // spu
643 spufP = (SPUFreeze_t *) malloc(16);
644 SPU_freeze(2, spufP, psxRegs.cycle);
645 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
646 free(spufP);
647 spufP = (SPUFreeze_t *) malloc(Size);
648 SPU_freeze(1, spufP, psxRegs.cycle);
649 SaveFuncs.write(f, spufP, Size);
650 free(spufP);
651
652 sioFreeze(f, 1);
653 cdrFreeze(f, 1);
654 psxHwFreeze(f, 1);
655 psxRcntFreeze(f, 1);
656 mdecFreeze(f, 1);
657 new_dyna_freeze(f, 1);
658
659 SaveFuncs.close(f);
660
661 new_dyna_after_save();
662
663 return 0;
664}
665
666int LoadState(const char *file) {
667 void *f;
668 GPUFreeze_t *gpufP;
669 SPUFreeze_t *spufP;
670 int Size;
671 char header[32];
672 u32 version;
673 boolean hle;
674
675 f = SaveFuncs.open(file, "rb");
676 if (f == NULL) return -1;
677
678 SaveFuncs.read(f, header, sizeof(header));
679 SaveFuncs.read(f, &version, sizeof(u32));
680 SaveFuncs.read(f, &hle, sizeof(boolean));
681
682 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
683 SaveFuncs.close(f);
684 return -1;
685 }
686 Config.HLE = hle;
687
688 if (Config.HLE)
689 psxBiosInit();
690
691 if (!drc_is_lightrec() || Config.Cpu == CPU_INTERPRETER)
692 psxCpu->Reset();
693 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
694
695 SaveFuncs.read(f, psxM, 0x00200000);
696 SaveFuncs.read(f, psxR, 0x00080000);
697 SaveFuncs.read(f, psxH, 0x00010000);
698 SaveFuncs.read(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
699 psxRegs.gteBusyCycle = psxRegs.cycle;
700
701 if (drc_is_lightrec() && Config.Cpu != CPU_INTERPRETER)
702 lightrec_plugin_sync_regs_from_pcsx();
703
704 if (Config.HLE)
705 psxBiosFreeze(0);
706
707 // gpu
708 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
709 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
710 GPU_freeze(0, gpufP);
711 free(gpufP);
712 if (HW_GPU_STATUS == 0)
713 HW_GPU_STATUS = SWAP32(GPU_readStatus());
714
715 // spu
716 SaveFuncs.read(f, &Size, 4);
717 spufP = (SPUFreeze_t *)malloc(Size);
718 SaveFuncs.read(f, spufP, Size);
719 SPU_freeze(0, spufP, psxRegs.cycle);
720 free(spufP);
721
722 sioFreeze(f, 0);
723 cdrFreeze(f, 0);
724 psxHwFreeze(f, 0);
725 psxRcntFreeze(f, 0);
726 mdecFreeze(f, 0);
727 new_dyna_freeze(f, 0);
728
729 SaveFuncs.close(f);
730
731 return 0;
732}
733
734int CheckState(const char *file) {
735 void *f;
736 char header[32];
737 u32 version;
738 boolean hle;
739
740 f = SaveFuncs.open(file, "rb");
741 if (f == NULL) return -1;
742
743 SaveFuncs.read(f, header, sizeof(header));
744 SaveFuncs.read(f, &version, sizeof(u32));
745 SaveFuncs.read(f, &hle, sizeof(boolean));
746
747 SaveFuncs.close(f);
748
749 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
750 return -1;
751
752 return 0;
753}
754
755// NET Function Helpers
756
757int SendPcsxInfo() {
758 if (NET_recvData == NULL || NET_sendData == NULL)
759 return 0;
760
761 boolean Sio_old = 0;
762 boolean SpuIrq_old = 0;
763 boolean RCntFix_old = 0;
764 NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
765 NET_sendData(&Sio_old, sizeof(Sio_old), PSE_NET_BLOCKING);
766 NET_sendData(&SpuIrq_old, sizeof(SpuIrq_old), PSE_NET_BLOCKING);
767 NET_sendData(&RCntFix_old, sizeof(RCntFix_old), PSE_NET_BLOCKING);
768 NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
769 NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
770
771 return 0;
772}
773
774int RecvPcsxInfo() {
775 int tmp;
776
777 if (NET_recvData == NULL || NET_sendData == NULL)
778 return 0;
779
780 boolean Sio_old = 0;
781 boolean SpuIrq_old = 0;
782 boolean RCntFix_old = 0;
783 NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
784 NET_recvData(&Sio_old, sizeof(Sio_old), PSE_NET_BLOCKING);
785 NET_recvData(&SpuIrq_old, sizeof(SpuIrq_old), PSE_NET_BLOCKING);
786 NET_recvData(&RCntFix_old, sizeof(RCntFix_old), PSE_NET_BLOCKING);
787 NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
788
789 SysUpdate();
790
791 tmp = Config.Cpu;
792 NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
793 if (tmp != Config.Cpu) {
794 psxCpu->Shutdown();
795#ifndef DRC_DISABLE
796 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
797 else psxCpu = &psxRec;
798#else
799 psxCpu = &psxInt;
800#endif
801 if (psxCpu->Init() == -1) {
802 SysClose(); return -1;
803 }
804 psxCpu->Reset();
805 }
806
807 return 0;
808}
809
810// remove the leading and trailing spaces in a string
811void trim(char *str) {
812 int pos = 0;
813 char *dest = str;
814
815 // skip leading blanks
816 while (str[pos] <= ' ' && str[pos] > 0)
817 pos++;
818
819 while (str[pos]) {
820 *(dest++) = str[pos];
821 pos++;
822 }
823
824 *(dest--) = '\0'; // store the null
825
826 // remove trailing blanks
827 while (dest >= str && *dest <= ' ' && *dest > 0)
828 *(dest--) = '\0';
829}
830
831// lookup table for crc calculation
832static unsigned short crctab[256] = {
833 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
834 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
835 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
836 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
837 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
838 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
839 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
840 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
841 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
842 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
843 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
844 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
845 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
846 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
847 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
848 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
849 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
850 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
851 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
852 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
853 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
854 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
855 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
856 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
857 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
858 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
859 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
860 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
861 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
862};
863
864u16 calcCrc(u8 *d, int len) {
865 u16 crc = 0;
866 int i;
867
868 for (i = 0; i < len; i++) {
869 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
870 }
871
872 return ~crc;
873}