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