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