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