Merge pull request #536 from gameblabla/cdrom_fixes
[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);
414 fread(mybuf, 2048, 1, f);
415 fseek(f, current, SEEK_SET);
416
417 exe_hdr = (EXE_HEADER *)mybuf;
418 if (memcmp(exe_hdr->id, "PS-X EXE", 8) == 0)
419 return PSX_EXE;
420
421 if (mybuf[0] == 'C' && mybuf[1] == 'P' && mybuf[2] == 'E')
422 return CPE_EXE;
423
424 coff_hdr = (FILHDR *)mybuf;
425 if (SWAPu16(coff_hdr->f_magic) == 0x0162)
426 return COFF_EXE;
427
428 return INVALID_EXE;
429}
430
96bef96f 431// temporary pandora workaround..
432// FIXME: remove
433size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
434{
435 void *tmp;
436 size_t ret = 0;
3e42b115 437
96bef96f 438 tmp = malloc(size * nmemb);
439 if (tmp) {
440 ret = fread(tmp, size, nmemb, stream);
441 memcpy(ptr, tmp, size * nmemb);
442 free(tmp);
443 }
444 return ret;
445}
446
ef79bbde
P
447int Load(const char *ExePath) {
448 FILE *tmpFile;
449 EXE_HEADER tmpHead;
450 int type;
451 int retval = 0;
452 u8 opcode;
453 u32 section_address, section_size;
ebe6ff2b 454 void *mem;
ef79bbde 455
3e42b115 456 strcpy(CdromId, "SLUS99999");
457 strcpy(CdromLabel, "SLUS_999.99");
ef79bbde
P
458
459 tmpFile = fopen(ExePath, "rb");
460 if (tmpFile == NULL) {
461 SysPrintf(_("Error opening file: %s.\n"), ExePath);
462 retval = -1;
463 } else {
464 type = PSXGetFileType(tmpFile);
465 switch (type) {
466 case PSX_EXE:
467 fread(&tmpHead,sizeof(EXE_HEADER),1,tmpFile);
ebe6ff2b 468 section_address = SWAP32(tmpHead.t_addr);
469 section_size = SWAP32(tmpHead.t_size);
470 mem = PSXM(section_address);
471 if (mem != NULL) {
3e42b115 472 fseek(tmpFile, 0x800, SEEK_SET);
96bef96f 473 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 474 psxCpu->Clear(section_address, section_size / 4);
475 }
ef79bbde
P
476 fclose(tmpFile);
477 psxRegs.pc = SWAP32(tmpHead.pc0);
478 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
3e42b115 479 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
ef79bbde
P
480 if (psxRegs.GPR.n.sp == 0)
481 psxRegs.GPR.n.sp = 0x801fff00;
482 retval = 0;
483 break;
484 case CPE_EXE:
485 fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
486 do {
487 fread(&opcode, 1, 1, tmpFile);
488 switch (opcode) {
489 case 1: /* Section loading */
490 fread(&section_address, 4, 1, tmpFile);
491 fread(&section_size, 4, 1, tmpFile);
492 section_address = SWAPu32(section_address);
493 section_size = SWAPu32(section_size);
494#ifdef EMU_LOG
495 EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
496#endif
ebe6ff2b 497 mem = PSXM(section_address);
498 if (mem != NULL) {
96bef96f 499 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 500 psxCpu->Clear(section_address, section_size / 4);
501 }
ef79bbde
P
502 break;
503 case 3: /* register loading (PC only?) */
504 fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
505 fread(&psxRegs.pc, 4, 1, tmpFile);
506 psxRegs.pc = SWAPu32(psxRegs.pc);
507 break;
508 case 0: /* End of file */
509 break;
510 default:
511 SysPrintf(_("Unknown CPE opcode %02x at position %08x.\n"), opcode, ftell(tmpFile) - 1);
512 retval = -1;
513 break;
514 }
515 } while (opcode != 0 && retval == 0);
516 break;
517 case COFF_EXE:
518 SysPrintf(_("COFF files not supported.\n"));
519 retval = -1;
520 break;
521 case INVALID_EXE:
8f00f96c 522 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
523 SysPrintf(_("(did you forget -cdfile ?)\n"));
ef79bbde
P
524 retval = -1;
525 break;
526 }
527 }
528
529 if (retval != 0) {
530 CdromId[0] = '\0';
531 CdromLabel[0] = '\0';
532 }
533
534 return retval;
535}
536
537// STATES
538
496d88d4 539static void *zlib_open(const char *name, const char *mode)
540{
541 return gzopen(name, mode);
542}
543
544static int zlib_read(void *file, void *buf, u32 len)
545{
546 return gzread(file, buf, len);
547}
548
549static int zlib_write(void *file, const void *buf, u32 len)
550{
551 return gzwrite(file, buf, len);
552}
553
554static long zlib_seek(void *file, long offs, int whence)
555{
556 return gzseek(file, offs, whence);
557}
558
559static void zlib_close(void *file)
560{
561 gzclose(file);
562}
563
564struct PcsxSaveFuncs SaveFuncs = {
565 zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
566};
567
202b29d4 568static const char PcsxHeader[32] = "STv4 PCSX v" PCSX_VERSION;
ef79bbde
P
569
570// Savestate Versioning!
571// If you make changes to the savestate version, please increment the value below.
df656dde 572static const u32 SaveVersion = 0x8b410006;
ef79bbde
P
573
574int SaveState(const char *file) {
496d88d4 575 void *f;
ef79bbde
P
576 GPUFreeze_t *gpufP;
577 SPUFreeze_t *spufP;
578 int Size;
579 unsigned char *pMem;
580
496d88d4 581 f = SaveFuncs.open(file, "wb");
ef79bbde
P
582 if (f == NULL) return -1;
583
03f55e6b 584 new_dyna_before_save();
52082bc1 585
496d88d4 586 SaveFuncs.write(f, (void *)PcsxHeader, 32);
587 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
588 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
ef79bbde
P
589
590 pMem = (unsigned char *)malloc(128 * 96 * 3);
591 if (pMem == NULL) return -1;
592 GPU_getScreenPic(pMem);
496d88d4 593 SaveFuncs.write(f, pMem, 128 * 96 * 3);
ef79bbde
P
594 free(pMem);
595
596 if (Config.HLE)
597 psxBiosFreeze(1);
598
496d88d4 599 SaveFuncs.write(f, psxM, 0x00200000);
600 SaveFuncs.write(f, psxR, 0x00080000);
601 SaveFuncs.write(f, psxH, 0x00010000);
602 SaveFuncs.write(f, (void *)&psxRegs, sizeof(psxRegs));
ef79bbde
P
603
604 // gpu
605 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
606 gpufP->ulFreezeVersion = 1;
607 GPU_freeze(1, gpufP);
496d88d4 608 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
609 free(gpufP);
610
611 // spu
612 spufP = (SPUFreeze_t *) malloc(16);
650adfd2 613 SPU_freeze(2, spufP, psxRegs.cycle);
496d88d4 614 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
ef79bbde
P
615 free(spufP);
616 spufP = (SPUFreeze_t *) malloc(Size);
650adfd2 617 SPU_freeze(1, spufP, psxRegs.cycle);
496d88d4 618 SaveFuncs.write(f, spufP, Size);
ef79bbde
P
619 free(spufP);
620
621 sioFreeze(f, 1);
622 cdrFreeze(f, 1);
623 psxHwFreeze(f, 1);
624 psxRcntFreeze(f, 1);
625 mdecFreeze(f, 1);
03f55e6b 626 new_dyna_freeze(f, 1);
ef79bbde 627
496d88d4 628 SaveFuncs.close(f);
ef79bbde 629
5b8c000f 630 new_dyna_after_save();
631
ef79bbde
P
632 return 0;
633}
634
635int LoadState(const char *file) {
496d88d4 636 void *f;
ef79bbde
P
637 GPUFreeze_t *gpufP;
638 SPUFreeze_t *spufP;
639 int Size;
640 char header[32];
641 u32 version;
642 boolean hle;
643
496d88d4 644 f = SaveFuncs.open(file, "rb");
ef79bbde
P
645 if (f == NULL) return -1;
646
496d88d4 647 SaveFuncs.read(f, header, sizeof(header));
648 SaveFuncs.read(f, &version, sizeof(u32));
649 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 650
33f56da1 651 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
496d88d4 652 SaveFuncs.close(f);
ef79bbde
P
653 return -1;
654 }
33f56da1 655 Config.HLE = hle;
656
657 if (Config.HLE)
658 psxBiosInit();
ef79bbde 659
8c9468f1
ZC
660#if defined(LIGHTREC)
661 if (Config.Cpu != CPU_INTERPRETER)
662 psxCpu->Clear(0, UINT32_MAX); //clear all
663 else
664#endif
ef79bbde 665 psxCpu->Reset();
496d88d4 666 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
ef79bbde 667
496d88d4 668 SaveFuncs.read(f, psxM, 0x00200000);
669 SaveFuncs.read(f, psxR, 0x00080000);
670 SaveFuncs.read(f, psxH, 0x00010000);
671 SaveFuncs.read(f, (void *)&psxRegs, sizeof(psxRegs));
ef79bbde
P
672
673 if (Config.HLE)
674 psxBiosFreeze(0);
675
676 // gpu
677 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
496d88d4 678 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
679 GPU_freeze(0, gpufP);
680 free(gpufP);
ddbaf678 681 if (HW_GPU_STATUS == 0)
682 HW_GPU_STATUS = GPU_readStatus();
ef79bbde
P
683
684 // spu
496d88d4 685 SaveFuncs.read(f, &Size, 4);
ef79bbde 686 spufP = (SPUFreeze_t *)malloc(Size);
496d88d4 687 SaveFuncs.read(f, spufP, Size);
650adfd2 688 SPU_freeze(0, spufP, psxRegs.cycle);
ef79bbde
P
689 free(spufP);
690
691 sioFreeze(f, 0);
692 cdrFreeze(f, 0);
693 psxHwFreeze(f, 0);
694 psxRcntFreeze(f, 0);
695 mdecFreeze(f, 0);
03f55e6b 696 new_dyna_freeze(f, 0);
ef79bbde 697
496d88d4 698 SaveFuncs.close(f);
ef79bbde
P
699
700 return 0;
701}
702
703int CheckState(const char *file) {
496d88d4 704 void *f;
ef79bbde
P
705 char header[32];
706 u32 version;
707 boolean hle;
708
496d88d4 709 f = SaveFuncs.open(file, "rb");
ef79bbde
P
710 if (f == NULL) return -1;
711
496d88d4 712 SaveFuncs.read(f, header, sizeof(header));
713 SaveFuncs.read(f, &version, sizeof(u32));
714 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 715
496d88d4 716 SaveFuncs.close(f);
ef79bbde 717
33f56da1 718 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
ef79bbde
P
719 return -1;
720
721 return 0;
722}
723
724// NET Function Helpers
725
726int SendPcsxInfo() {
727 if (NET_recvData == NULL || NET_sendData == NULL)
728 return 0;
729
730 NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
731 NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
732 NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
733 NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
734 NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
735 NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
736
737 return 0;
738}
739
740int RecvPcsxInfo() {
741 int tmp;
742
743 if (NET_recvData == NULL || NET_sendData == NULL)
744 return 0;
745
746 NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
747 NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
748 NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
749 NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
750 NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
751
752 SysUpdate();
753
754 tmp = Config.Cpu;
755 NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
756 if (tmp != Config.Cpu) {
757 psxCpu->Shutdown();
87cc59de 758#if defined(NEW_DYNAREC) || defined(LIGHTREC)
ef79bbde
P
759 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
760 else psxCpu = &psxRec;
761#else
762 psxCpu = &psxInt;
763#endif
764 if (psxCpu->Init() == -1) {
765 SysClose(); return -1;
766 }
767 psxCpu->Reset();
768 }
769
770 return 0;
771}
772
773// remove the leading and trailing spaces in a string
774void trim(char *str) {
775 int pos = 0;
776 char *dest = str;
777
778 // skip leading blanks
779 while (str[pos] <= ' ' && str[pos] > 0)
780 pos++;
781
782 while (str[pos]) {
783 *(dest++) = str[pos];
784 pos++;
785 }
786
787 *(dest--) = '\0'; // store the null
788
789 // remove trailing blanks
790 while (dest >= str && *dest <= ' ' && *dest > 0)
791 *(dest--) = '\0';
792}
793
794// lookup table for crc calculation
795static unsigned short crctab[256] = {
796 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
797 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
798 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
799 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
800 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
801 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
802 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
803 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
804 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
805 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
806 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
807 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
808 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
809 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
810 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
811 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
812 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
813 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
814 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
815 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
816 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
817 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
818 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
819 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
820 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
821 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
822 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
823 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
824 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
825};
826
827u16 calcCrc(u8 *d, int len) {
828 u16 crc = 0;
829 int i;
830
831 for (i = 0; i < len; i++) {
832 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
833 }
834
835 return ~crc;
836}