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