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