Merge pull request #579 from gameblabla/pio_writes_sen_lib
[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);
952943a7 246 psxCpu->Reset();
ebe6ff2b 247
ef79bbde 248 // Read the rest of the main executable
ebe6ff2b 249 while (tmpHead.t_size & ~2047) {
ef79bbde
P
250 void *ptr = (void *)PSXM(tmpHead.t_addr);
251
252 incTime();
253 READTRACK();
254
255 if (ptr != NULL) memcpy(ptr, buf+12, 2048);
256
257 tmpHead.t_size -= 2048;
258 tmpHead.t_addr += 2048;
259 }
260
261 return 0;
262}
263
264int LoadCdromFile(const char *filename, EXE_HEADER *head) {
265 struct iso_directory_record *dir;
266 u8 time[4],*buf;
305c8c93 267 u8 mdir[4096];
268 char exename[256];
ef79bbde 269 u32 size, addr;
305c8c93 270 void *mem;
ef79bbde 271
9a9bcd78 272 sscanf(filename, "cdrom:\\%255s", exename);
ef79bbde
P
273
274 time[0] = itob(0); time[1] = itob(2); time[2] = itob(0x10);
275
276 READTRACK();
277
278 // skip head and sub, and go to the root directory record
3e42b115 279 dir = (struct iso_directory_record *)&buf[12 + 156];
ef79bbde
P
280
281 mmssdd(dir->extent, (char*)time);
282
283 READDIR(mdir);
284
285 if (GetCdromFile(mdir, time, exename) == -1) return -1;
286
287 READTRACK();
288
289 memcpy(head, buf + 12, sizeof(EXE_HEADER));
290 size = head->t_size;
291 addr = head->t_addr;
292
ebe6ff2b 293 psxCpu->Clear(addr, size / 4);
952943a7 294 psxCpu->Reset();
ebe6ff2b 295
296 while (size & ~2047) {
ef79bbde
P
297 incTime();
298 READTRACK();
299
305c8c93 300 mem = PSXM(addr);
301 if (mem)
302 memcpy(mem, buf + 12, 2048);
ef79bbde
P
303
304 size -= 2048;
305 addr += 2048;
306 }
307
308 return 0;
309}
310
311int CheckCdrom() {
312 struct iso_directory_record *dir;
305c8c93 313 unsigned char time[4];
314 char *buf;
ef79bbde
P
315 unsigned char mdir[4096];
316 char exename[256];
e06ee7f4 317 int i, len, c;
ef79bbde
P
318
319 FreePPFCache();
320
321 time[0] = itob(0);
322 time[1] = itob(2);
323 time[2] = itob(0x10);
324
325 READTRACK();
326
e06ee7f4 327 memset(CdromLabel, 0, sizeof(CdromLabel));
328 memset(CdromId, 0, sizeof(CdromId));
329 memset(exename, 0, sizeof(exename));
ef79bbde
P
330
331 strncpy(CdromLabel, buf + 52, 32);
332
333 // skip head and sub, and go to the root directory record
3e42b115 334 dir = (struct iso_directory_record *)&buf[12 + 156];
ef79bbde
P
335
336 mmssdd(dir->extent, (char *)time);
337
338 READDIR(mdir);
339
340 if (GetCdromFile(mdir, time, "SYSTEM.CNF;1") != -1) {
341 READTRACK();
342
9a9bcd78 343 sscanf(buf + 12, "BOOT = cdrom:\\%255s", exename);
ef79bbde 344 if (GetCdromFile(mdir, time, exename) == -1) {
9a9bcd78 345 sscanf(buf + 12, "BOOT = cdrom:%255s", exename);
ef79bbde
P
346 if (GetCdromFile(mdir, time, exename) == -1) {
347 char *ptr = strstr(buf + 12, "cdrom:"); // possibly the executable is in some subdir
348 if (ptr != NULL) {
349 ptr += 6;
350 while (*ptr == '\\' || *ptr == '/') ptr++;
351 strncpy(exename, ptr, 255);
352 exename[255] = '\0';
353 ptr = exename;
354 while (*ptr != '\0' && *ptr != '\r' && *ptr != '\n') ptr++;
355 *ptr = '\0';
356 if (GetCdromFile(mdir, time, exename) == -1)
357 return -1; // main executable not found
358 } else
359 return -1;
360 }
361 }
1893f408 362 /* Workaround for Wild Arms EU/US which has non-standard string causing incorrect region detection */
363 if (exename[0] == 'E' && exename[1] == 'X' && exename[2] == 'E' && exename[3] == '\\') {
364 size_t offset = 4;
365 size_t i, len = strlen(exename) - offset;
366 for (i = 0; i < len; i++)
367 exename[i] = exename[i + offset];
368 exename[i] = '\0';
369 }
ef79bbde
P
370 } else if (GetCdromFile(mdir, time, "PSX.EXE;1") != -1) {
371 strcpy(exename, "PSX.EXE;1");
372 strcpy(CdromId, "SLUS99999");
373 } else
374 return -1; // SYSTEM.CNF and PSX.EXE not found
375
376 if (CdromId[0] == '\0') {
e06ee7f4 377 len = strlen(exename);
378 c = 0;
379 for (i = 0; i < len; ++i) {
380 if (exename[i] == ';' || c >= sizeof(CdromId) - 1)
381 break;
382 if (isalnum(exename[i]))
383 CdromId[c++] = exename[i];
ef79bbde
P
384 }
385 }
386
0e2e3f49 387 if (CdromId[0] == '\0')
388 strcpy(CdromId, "SLUS99999");
389
ef79bbde 390 if (Config.PsxAuto) { // autodetect system (pal or ntsc)
a1dbab20 391 if (CdromId[2] == 'e' || CdromId[2] == 'E')
ef79bbde
P
392 Config.PsxType = PSX_TYPE_PAL; // pal
393 else Config.PsxType = PSX_TYPE_NTSC; // ntsc
394 }
395
396 if (CdromLabel[0] == ' ') {
4b7da20a 397 memcpy(CdromLabel, CdromId, 9);
ef79bbde
P
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);
ef79bbde
P
402
403 BuildPPFCache();
404
405 return 0;
406}
407
408static int PSXGetFileType(FILE *f) {
409 unsigned long current;
410 u8 mybuf[2048];
411 EXE_HEADER *exe_hdr;
412 FILHDR *coff_hdr;
413
414 current = ftell(f);
415 fseek(f, 0L, SEEK_SET);
9361a5aa
EC
416 if (fread(&mybuf, sizeof(mybuf), 1, f) != sizeof(mybuf))
417 goto io_fail;
418
ef79bbde
P
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;
9361a5aa
EC
433
434io_fail:
435#ifndef NDEBUG
436 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
437#endif
438 return INVALID_EXE;
ef79bbde
P
439}
440
96bef96f 441// temporary pandora workaround..
442// FIXME: remove
443size_t fread_to_ram(void *ptr, size_t size, size_t nmemb, FILE *stream)
444{
445 void *tmp;
446 size_t ret = 0;
3e42b115 447
96bef96f 448 tmp = malloc(size * nmemb);
449 if (tmp) {
450 ret = fread(tmp, size, nmemb, stream);
451 memcpy(ptr, tmp, size * nmemb);
452 free(tmp);
453 }
454 return ret;
455}
456
ef79bbde
P
457int Load(const char *ExePath) {
458 FILE *tmpFile;
459 EXE_HEADER tmpHead;
460 int type;
461 int retval = 0;
462 u8 opcode;
463 u32 section_address, section_size;
ebe6ff2b 464 void *mem;
ef79bbde 465
3e42b115 466 strcpy(CdromId, "SLUS99999");
467 strcpy(CdromLabel, "SLUS_999.99");
ef79bbde
P
468
469 tmpFile = fopen(ExePath, "rb");
470 if (tmpFile == NULL) {
471 SysPrintf(_("Error opening file: %s.\n"), ExePath);
472 retval = -1;
473 } else {
474 type = PSXGetFileType(tmpFile);
475 switch (type) {
476 case PSX_EXE:
9361a5aa
EC
477 if (fread(&tmpHead, sizeof(EXE_HEADER), 1, tmpFile) != sizeof(EXE_HEADER))
478 goto fail_io;
ebe6ff2b 479 section_address = SWAP32(tmpHead.t_addr);
480 section_size = SWAP32(tmpHead.t_size);
481 mem = PSXM(section_address);
482 if (mem != NULL) {
3e42b115 483 fseek(tmpFile, 0x800, SEEK_SET);
96bef96f 484 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 485 psxCpu->Clear(section_address, section_size / 4);
486 }
ef79bbde
P
487 psxRegs.pc = SWAP32(tmpHead.pc0);
488 psxRegs.GPR.n.gp = SWAP32(tmpHead.gp0);
3e42b115 489 psxRegs.GPR.n.sp = SWAP32(tmpHead.s_addr);
ef79bbde
P
490 if (psxRegs.GPR.n.sp == 0)
491 psxRegs.GPR.n.sp = 0x801fff00;
492 retval = 0;
493 break;
494 case CPE_EXE:
495 fseek(tmpFile, 6, SEEK_SET); /* Something tells me we should go to 4 and read the "08 00" here... */
496 do {
9361a5aa
EC
497 if (fread(&opcode, sizeof(opcode), 1, tmpFile) != sizeof(opcode))
498 goto fail_io;
ef79bbde
P
499 switch (opcode) {
500 case 1: /* Section loading */
9361a5aa
EC
501 if (fread(&section_address, sizeof(section_address), 1, tmpFile) != sizeof(section_address))
502 goto fail_io;
503 if (fread(&section_size, sizeof(section_size), 1, tmpFile) != sizeof(section_size))
504 goto fail_io;
ef79bbde
P
505 section_address = SWAPu32(section_address);
506 section_size = SWAPu32(section_size);
507#ifdef EMU_LOG
508 EMU_LOG("Loading %08X bytes from %08X to %08X\n", section_size, ftell(tmpFile), section_address);
509#endif
ebe6ff2b 510 mem = PSXM(section_address);
511 if (mem != NULL) {
96bef96f 512 fread_to_ram(mem, section_size, 1, tmpFile);
ebe6ff2b 513 psxCpu->Clear(section_address, section_size / 4);
514 }
ef79bbde
P
515 break;
516 case 3: /* register loading (PC only?) */
517 fseek(tmpFile, 2, SEEK_CUR); /* unknown field */
9361a5aa
EC
518 if (fread(&psxRegs.pc, sizeof(psxRegs.pc), 1, tmpFile) != sizeof(psxRegs.pc))
519 goto fail_io;
ef79bbde
P
520 psxRegs.pc = SWAPu32(psxRegs.pc);
521 break;
522 case 0: /* End of file */
523 break;
524 default:
525 SysPrintf(_("Unknown CPE opcode %02x at position %08x.\n"), opcode, ftell(tmpFile) - 1);
526 retval = -1;
527 break;
528 }
529 } while (opcode != 0 && retval == 0);
530 break;
531 case COFF_EXE:
532 SysPrintf(_("COFF files not supported.\n"));
533 retval = -1;
534 break;
535 case INVALID_EXE:
8f00f96c 536 SysPrintf(_("This file does not appear to be a valid PSX EXE file.\n"));
537 SysPrintf(_("(did you forget -cdfile ?)\n"));
ef79bbde
P
538 retval = -1;
539 break;
540 }
541 }
542
543 if (retval != 0) {
544 CdromId[0] = '\0';
545 CdromLabel[0] = '\0';
546 }
547
9361a5aa 548 fclose(tmpFile);
ef79bbde 549 return retval;
9361a5aa
EC
550
551fail_io:
552#ifndef NDEBUG
553 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
554#endif
555 fclose(tmpFile);
556 return -1;
ef79bbde
P
557}
558
559// STATES
560
496d88d4 561static void *zlib_open(const char *name, const char *mode)
562{
563 return gzopen(name, mode);
564}
565
566static int zlib_read(void *file, void *buf, u32 len)
567{
568 return gzread(file, buf, len);
569}
570
571static int zlib_write(void *file, const void *buf, u32 len)
572{
573 return gzwrite(file, buf, len);
574}
575
576static long zlib_seek(void *file, long offs, int whence)
577{
578 return gzseek(file, offs, whence);
579}
580
581static void zlib_close(void *file)
582{
583 gzclose(file);
584}
585
586struct PcsxSaveFuncs SaveFuncs = {
587 zlib_open, zlib_read, zlib_write, zlib_seek, zlib_close
588};
589
202b29d4 590static const char PcsxHeader[32] = "STv4 PCSX v" PCSX_VERSION;
ef79bbde
P
591
592// Savestate Versioning!
593// If you make changes to the savestate version, please increment the value below.
df656dde 594static const u32 SaveVersion = 0x8b410006;
ef79bbde
P
595
596int SaveState(const char *file) {
496d88d4 597 void *f;
ef79bbde
P
598 GPUFreeze_t *gpufP;
599 SPUFreeze_t *spufP;
600 int Size;
601 unsigned char *pMem;
602
496d88d4 603 f = SaveFuncs.open(file, "wb");
ef79bbde
P
604 if (f == NULL) return -1;
605
03f55e6b 606 new_dyna_before_save();
52082bc1 607
496d88d4 608 SaveFuncs.write(f, (void *)PcsxHeader, 32);
609 SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32));
610 SaveFuncs.write(f, (void *)&Config.HLE, sizeof(boolean));
ef79bbde
P
611
612 pMem = (unsigned char *)malloc(128 * 96 * 3);
613 if (pMem == NULL) return -1;
614 GPU_getScreenPic(pMem);
496d88d4 615 SaveFuncs.write(f, pMem, 128 * 96 * 3);
ef79bbde
P
616 free(pMem);
617
618 if (Config.HLE)
619 psxBiosFreeze(1);
620
496d88d4 621 SaveFuncs.write(f, psxM, 0x00200000);
622 SaveFuncs.write(f, psxR, 0x00080000);
623 SaveFuncs.write(f, psxH, 0x00010000);
624 SaveFuncs.write(f, (void *)&psxRegs, sizeof(psxRegs));
ef79bbde
P
625
626 // gpu
627 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
628 gpufP->ulFreezeVersion = 1;
629 GPU_freeze(1, gpufP);
496d88d4 630 SaveFuncs.write(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
631 free(gpufP);
632
633 // spu
634 spufP = (SPUFreeze_t *) malloc(16);
650adfd2 635 SPU_freeze(2, spufP, psxRegs.cycle);
496d88d4 636 Size = spufP->Size; SaveFuncs.write(f, &Size, 4);
ef79bbde
P
637 free(spufP);
638 spufP = (SPUFreeze_t *) malloc(Size);
650adfd2 639 SPU_freeze(1, spufP, psxRegs.cycle);
496d88d4 640 SaveFuncs.write(f, spufP, Size);
ef79bbde
P
641 free(spufP);
642
643 sioFreeze(f, 1);
644 cdrFreeze(f, 1);
645 psxHwFreeze(f, 1);
646 psxRcntFreeze(f, 1);
647 mdecFreeze(f, 1);
03f55e6b 648 new_dyna_freeze(f, 1);
ef79bbde 649
496d88d4 650 SaveFuncs.close(f);
ef79bbde 651
5b8c000f 652 new_dyna_after_save();
653
ef79bbde
P
654 return 0;
655}
656
657int LoadState(const char *file) {
496d88d4 658 void *f;
ef79bbde
P
659 GPUFreeze_t *gpufP;
660 SPUFreeze_t *spufP;
661 int Size;
662 char header[32];
663 u32 version;
664 boolean hle;
665
496d88d4 666 f = SaveFuncs.open(file, "rb");
ef79bbde
P
667 if (f == NULL) return -1;
668
496d88d4 669 SaveFuncs.read(f, header, sizeof(header));
670 SaveFuncs.read(f, &version, sizeof(u32));
671 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 672
33f56da1 673 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
496d88d4 674 SaveFuncs.close(f);
ef79bbde
P
675 return -1;
676 }
33f56da1 677 Config.HLE = hle;
678
679 if (Config.HLE)
680 psxBiosInit();
ef79bbde 681
8c9468f1
ZC
682#if defined(LIGHTREC)
683 if (Config.Cpu != CPU_INTERPRETER)
684 psxCpu->Clear(0, UINT32_MAX); //clear all
685 else
686#endif
ef79bbde 687 psxCpu->Reset();
496d88d4 688 SaveFuncs.seek(f, 128 * 96 * 3, SEEK_CUR);
ef79bbde 689
496d88d4 690 SaveFuncs.read(f, psxM, 0x00200000);
691 SaveFuncs.read(f, psxR, 0x00080000);
692 SaveFuncs.read(f, psxH, 0x00010000);
693 SaveFuncs.read(f, (void *)&psxRegs, sizeof(psxRegs));
ef79bbde
P
694
695 if (Config.HLE)
696 psxBiosFreeze(0);
697
698 // gpu
699 gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
496d88d4 700 SaveFuncs.read(f, gpufP, sizeof(GPUFreeze_t));
ef79bbde
P
701 GPU_freeze(0, gpufP);
702 free(gpufP);
ddbaf678 703 if (HW_GPU_STATUS == 0)
704 HW_GPU_STATUS = GPU_readStatus();
ef79bbde
P
705
706 // spu
496d88d4 707 SaveFuncs.read(f, &Size, 4);
ef79bbde 708 spufP = (SPUFreeze_t *)malloc(Size);
496d88d4 709 SaveFuncs.read(f, spufP, Size);
650adfd2 710 SPU_freeze(0, spufP, psxRegs.cycle);
ef79bbde
P
711 free(spufP);
712
713 sioFreeze(f, 0);
714 cdrFreeze(f, 0);
715 psxHwFreeze(f, 0);
716 psxRcntFreeze(f, 0);
717 mdecFreeze(f, 0);
03f55e6b 718 new_dyna_freeze(f, 0);
ef79bbde 719
496d88d4 720 SaveFuncs.close(f);
ef79bbde
P
721
722 return 0;
723}
724
725int CheckState(const char *file) {
496d88d4 726 void *f;
ef79bbde
P
727 char header[32];
728 u32 version;
729 boolean hle;
730
496d88d4 731 f = SaveFuncs.open(file, "rb");
ef79bbde
P
732 if (f == NULL) return -1;
733
496d88d4 734 SaveFuncs.read(f, header, sizeof(header));
735 SaveFuncs.read(f, &version, sizeof(u32));
736 SaveFuncs.read(f, &hle, sizeof(boolean));
ef79bbde 737
496d88d4 738 SaveFuncs.close(f);
ef79bbde 739
33f56da1 740 if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
ef79bbde
P
741 return -1;
742
743 return 0;
744}
745
746// NET Function Helpers
747
748int SendPcsxInfo() {
749 if (NET_recvData == NULL || NET_sendData == NULL)
750 return 0;
751
752 NET_sendData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
753 NET_sendData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
754 NET_sendData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
755 NET_sendData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
756 NET_sendData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
757 NET_sendData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
758
759 return 0;
760}
761
762int RecvPcsxInfo() {
763 int tmp;
764
765 if (NET_recvData == NULL || NET_sendData == NULL)
766 return 0;
767
768 NET_recvData(&Config.Xa, sizeof(Config.Xa), PSE_NET_BLOCKING);
769 NET_recvData(&Config.Sio, sizeof(Config.Sio), PSE_NET_BLOCKING);
770 NET_recvData(&Config.SpuIrq, sizeof(Config.SpuIrq), PSE_NET_BLOCKING);
771 NET_recvData(&Config.RCntFix, sizeof(Config.RCntFix), PSE_NET_BLOCKING);
772 NET_recvData(&Config.PsxType, sizeof(Config.PsxType), PSE_NET_BLOCKING);
773
774 SysUpdate();
775
776 tmp = Config.Cpu;
777 NET_recvData(&Config.Cpu, sizeof(Config.Cpu), PSE_NET_BLOCKING);
778 if (tmp != Config.Cpu) {
779 psxCpu->Shutdown();
87cc59de 780#if defined(NEW_DYNAREC) || defined(LIGHTREC)
ef79bbde
P
781 if (Config.Cpu == CPU_INTERPRETER) psxCpu = &psxInt;
782 else psxCpu = &psxRec;
783#else
784 psxCpu = &psxInt;
785#endif
786 if (psxCpu->Init() == -1) {
787 SysClose(); return -1;
788 }
789 psxCpu->Reset();
790 }
791
792 return 0;
793}
794
795// remove the leading and trailing spaces in a string
796void trim(char *str) {
797 int pos = 0;
798 char *dest = str;
799
800 // skip leading blanks
801 while (str[pos] <= ' ' && str[pos] > 0)
802 pos++;
803
804 while (str[pos]) {
805 *(dest++) = str[pos];
806 pos++;
807 }
808
809 *(dest--) = '\0'; // store the null
810
811 // remove trailing blanks
812 while (dest >= str && *dest <= ' ' && *dest > 0)
813 *(dest--) = '\0';
814}
815
816// lookup table for crc calculation
817static unsigned short crctab[256] = {
818 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
819 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
820 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
821 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
822 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
823 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
824 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
825 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
826 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
827 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
828 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
829 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
830 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
831 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
832 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
833 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
834 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
835 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
836 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
837 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
838 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
839 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
840 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
841 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
842 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
843 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
844 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
845 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
846 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
847};
848
849u16 calcCrc(u8 *d, int len) {
850 u16 crc = 0;
851 int i;
852
853 for (i = 0; i < len; i++) {
854 crc = crctab[(crc >> 8) ^ d[i]] ^ (crc << 8);
855 }
856
857 return ~crc;
858}