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