Merge pull request #649 from pcercuei/update-lightrec-20220425
[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
P
605
606int SaveState(const char *file) {
496d88d4 607 void *f;
ef79bbde
P
608 GPUFreeze_t *gpufP;
609 SPUFreeze_t *spufP;
610 int Size;
611 unsigned char *pMem;
612
496d88d4 613 f = SaveFuncs.open(file, "wb");
ef79bbde
P
614 if (f == NULL) return -1;
615
03f55e6b 616 new_dyna_before_save();
52082bc1 617
496d88d4 618 SaveFuncs.write(f, (void *)PcsxHeader, 32);
619 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
620 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
ef79bbde
P
621
622 pMem = (unsigned char *)malloc(128 * 96 * 3);
623 if (pMem == NULL) return -1;
624 GPU_getScreenPic(pMem);
496d88d4 625 SaveFuncs.write(f, pMem, 128 * 96 * 3);
ef79bbde
P
626 free(pMem);
627
628 if (Config.HLE)
629 psxBiosFreeze(1);
630
496d88d4 631 SaveFuncs.write(f, psxM, 0x00200000);
632 SaveFuncs.write(f, psxR, 0x00080000);
633 SaveFuncs.write(f, psxH, 0x00010000);
630b122b 634 // only partial save of psxRegisters to maintain savestate compat
635 SaveFuncs.write(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
ef79bbde
P
636
637 // gpu
638 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
639 gpufP->ulFreezeVersion = 1;
640 GPU_freeze(1, gpufP);
496d88d4 641 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
642 free(gpufP);
643
644 // spu
645 spufP = (SPUFreeze_t *) malloc(16);
650adfd2 646 SPU_freeze(2, spufP, psxRegs.cycle);
496d88d4 647 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
ef79bbde
P
648 free(spufP);
649 spufP = (SPUFreeze_t *) malloc(Size);
650adfd2 650 SPU_freeze(1, spufP, psxRegs.cycle);
496d88d4 651 SaveFuncs.write(f, spufP, Size);
ef79bbde
P
652 free(spufP);
653
654 sioFreeze(f, 1);
655 cdrFreeze(f, 1);
656 psxHwFreeze(f, 1);
657 psxRcntFreeze(f, 1);
658 mdecFreeze(f, 1);
03f55e6b 659 new_dyna_freeze(f, 1);
ef79bbde 660
496d88d4 661 SaveFuncs.close(f);
ef79bbde 662
5b8c000f 663 new_dyna_after_save();
664
ef79bbde
P
665 return 0;
666}
667
668int LoadState(const char *file) {
496d88d4 669 void *f;
ef79bbde
P
670 GPUFreeze_t *gpufP;
671 SPUFreeze_t *spufP;
672 int Size;
673 char header[32];
674 u32 version;
675 boolean hle;
676
496d88d4 677 f = SaveFuncs.open(file, "rb");
ef79bbde
P
678 if (f == NULL) return -1;
679
496d88d4 680 SaveFuncs.read(f, header, sizeof(header));
681 SaveFuncs.read(f, &version, sizeof(u32));
682 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 683
33f56da1 684 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
496d88d4 685 SaveFuncs.close(f);
ef79bbde
P
686 return -1;
687 }
33f56da1 688 Config.HLE = hle;
689
690 if (Config.HLE)
691 psxBiosInit();
ef79bbde 692
8c9468f1
ZC
693#if defined(LIGHTREC)
694 if (Config.Cpu != CPU_INTERPRETER)
695 psxCpu->Clear(0, UINT32_MAX); //clear all
696 else
697#endif
ef79bbde 698 psxCpu->Reset();
496d88d4 699 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
ef79bbde 700
496d88d4 701 SaveFuncs.read(f, psxM, 0x00200000);
702 SaveFuncs.read(f, psxR, 0x00080000);
703 SaveFuncs.read(f, psxH, 0x00010000);
630b122b 704 SaveFuncs.read(f, &psxRegs, offsetof(psxRegisters, gteBusyCycle));
705 psxRegs.gteBusyCycle = psxRegs.cycle;
ef79bbde
P
706
707 if (Config.HLE)
708 psxBiosFreeze(0);
709
710 // gpu
711 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
496d88d4 712 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
713 GPU_freeze(0, gpufP);
714 free(gpufP);
ddbaf678 715 if (HW_GPU_STATUS == 0)
716 HW_GPU_STATUS = GPU_readStatus();
ef79bbde
P
717
718 // spu
496d88d4 719 SaveFuncs.read(f, &Size, 4);
ef79bbde 720 spufP = (SPUFreeze_t *)malloc(Size);
496d88d4 721 SaveFuncs.read(f, spufP, Size);
650adfd2 722 SPU_freeze(0, spufP, psxRegs.cycle);
ef79bbde
P
723 free(spufP);
724
725 sioFreeze(f, 0);
726 cdrFreeze(f, 0);
727 psxHwFreeze(f, 0);
728 psxRcntFreeze(f, 0);
729 mdecFreeze(f, 0);
03f55e6b 730 new_dyna_freeze(f, 0);
ef79bbde 731
496d88d4 732 SaveFuncs.close(f);
ef79bbde
P
733
734 return 0;
735}
736
737int CheckState(const char *file) {
496d88d4 738 void *f;
ef79bbde
P
739 char header[32];
740 u32 version;
741 boolean hle;
742
496d88d4 743 f = SaveFuncs.open(file, "rb");
ef79bbde
P
744 if (f == NULL) return -1;
745
496d88d4 746 SaveFuncs.read(f, header, sizeof(header));
747 SaveFuncs.read(f, &version, sizeof(u32));
748 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 749
496d88d4 750 SaveFuncs.close(f);
ef79bbde 751
33f56da1 752 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
ef79bbde
P
753 return -1;
754
755 return 0;
756}
757
758// NET Function Helpers
759
760int SendPcsxInfo() {
761 if (NET_recvData == NULL || NET_sendData == NULL)
762 return 0;
763
764 NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
765 NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
766 NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
767 NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), 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 NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
781 NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
782 NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
783 NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
784 NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
785
786 SysUpdate();
787
788 tmp = Config.Cpu;
789 NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
790 if (tmp != Config.Cpu) {
791 psxCpu->Shutdown();
630b122b 792#ifndef DRC_DISABLE
ef79bbde
P
793 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
794 else psxCpu = &psxRec;
795#else
796 psxCpu = &psxInt;
797#endif
798 if (psxCpu->Init() == -1) {
799 SysClose(); return -1;
800 }
801 psxCpu->Reset();
802 }
803
804 return 0;
805}
806
807// remove the leading and trailing spaces in a string
808void trim(char *str) {
809 int pos = 0;
810 char *dest = str;
811
812 // skip leading blanks
813 while (str[pos] <= ' ' && str[pos] > 0)
814 pos++;
815
816 while (str[pos]) {
817 *(dest++) = str[pos];
818 pos++;
819 }
820
821 *(dest--) = '\0'; // store the null
822
823 // remove trailing blanks
824 while (dest >= str && *dest <= ' ' && *dest > 0)
825 *(dest--) = '\0';
826}
827
828// lookup table for crc calculation
829static unsigned short crctab[256] = {
830 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
831 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
832 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
833 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
834 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
835 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
836 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
837 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
838 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
839 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
840 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
841 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
842 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
843 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
844 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
845 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
846 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
847 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
848 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
849 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
850 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
851 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
852 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
853 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
854 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
855 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
856 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
857 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
858 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
859};
860
861u16 calcCrc(u8 *d, int len) {
862 u16 crc = 0;
863 int i;
864
865 for (i = 0; i < len; i++) {
866 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
867 }
868
869 return ~crc;
870}