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