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