frontend: omap: do centering on large resolutions
[pcsx_rearmed.git] / libpcsxcore / misc.c
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"
27 #include "gpu.h"
28 #include "ppf.h"
29
30 char CdromId[10] = "";
31 char 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
41 struct 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
55 void mmssdd( char *b, char *p )
56 {
57         int m, s, d;
58 #if defined(__arm__)
59         int block = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | b[0];
60 #elif defined(__BIGENDIAN__)
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
107 int 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
145 static const unsigned int gpu_ctl_def[] = {
146         0x00000000, 0x01000000, 0x03000000, 0x04000000,
147         0x05000800, 0x06c60260, 0x0703fc10, 0x08000027,
148 };
149
150 static const unsigned int gpu_data_def[] = {
151         0xe100360b, 0xe2000000, 0xe3000800, 0xe4077e7f,
152         0xe5001000, 0xe6000000,
153         0x02000000, 0x00000000, 0x01ff03ff,
154 };
155
156 static 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
167 int 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
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
178         if (!Config.HLE) {
179                 // skip BIOS logos
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
240         psxCpu->Clear(tmpHead.t_addr, tmpHead.t_size / 4);
241
242         // Read the rest of the main executable
243         while (tmpHead.t_size & ~2047) {
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
258 int 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
285         psxCpu->Clear(addr, size / 4);
286
287         while (size & ~2047) {
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
300 int 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)
368                 if (CdromId[2] == 'e' || CdromId[2] == 'E')
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
384 static 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
409 int 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;
416         void *mem;
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);
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                                 }
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
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                                                         }
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
500 static 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.
504 static const u32 SaveVersion = 0x8b410006;
505
506 int 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
516         new_dyna_save();
517
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
561         new_dyna_after_save();
562
563         return 0;
564 }
565
566 int 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
582         if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion) {
583                 gzclose(f);
584                 return -1;
585         }
586         Config.HLE = hle;
587
588         if (Config.HLE)
589                 psxBiosInit();
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);
607         if (HW_GPU_STATUS == 0)
608                 HW_GPU_STATUS = GPU_readStatus();
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);
624         new_dyna_restore();
625
626         return 0;
627 }
628
629 int 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
644         if (strncmp("STv4 PCSX", header, 9) != 0 || version != SaveVersion)
645                 return -1;
646
647         return 0;
648 }
649
650 // NET Function Helpers
651
652 int 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
666 int 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
700 void 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
721 static 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
753 u16 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 }