psxbios: experimental vsync HLE
[pcsx_rearmed.git] / libpcsxcore / sio.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 * SIO functions.
22 */
23
24 #include "misc.h"
25 #include "psxcounters.h"
26 #include "sio.h"
27 #include <sys/stat.h>
28
29 #ifdef USE_LIBRETRO_VFS
30 #include <streams/file_stream_transforms.h>
31 #endif
32
33 // Status Flags
34 #define TX_RDY          0x0001
35 #define RX_RDY          0x0002
36 #define TX_EMPTY        0x0004
37 #define PARITY_ERR      0x0008
38 #define RX_OVERRUN      0x0010
39 #define FRAMING_ERR     0x0020
40 #define SYNC_DETECT     0x0040
41 #define DSR                     0x0080
42 #define CTS                     0x0100
43 #define IRQ                     0x0200
44
45 // Control Flags
46 #define TX_PERM         0x0001
47 #define DTR                     0x0002
48 #define RX_PERM         0x0004
49 #define BREAK           0x0008
50 #define RESET_ERR       0x0010
51 #define RTS                     0x0020
52 #define SIO_RESET       0x0040
53
54 // *** FOR WORKS ON PADS AND MEMORY CARDS *****
55
56 static unsigned char buf[256];
57 static unsigned char cardh1[4] = { 0xff, 0x08, 0x5a, 0x5d };
58 static unsigned char cardh2[4] = { 0xff, 0x08, 0x5a, 0x5d };
59
60 // Transfer Ready and the Buffer is Empty
61 // static unsigned short StatReg = 0x002b;
62 static unsigned short StatReg = TX_RDY | TX_EMPTY;
63 static unsigned short ModeReg;
64 static unsigned short CtrlReg;
65 static unsigned short BaudReg;
66
67 static unsigned int bufcount;
68 static unsigned int parp;
69 static unsigned int mcdst, rdwr;
70 static unsigned char adrH, adrL;
71 static unsigned int padst;
72
73 char Mcd1Data[MCD_SIZE], Mcd2Data[MCD_SIZE];
74 char McdDisable[2];
75
76 #define SIO_INT(eCycle) { \
77         psxRegs.interrupt |= (1 << PSXINT_SIO); \
78         psxRegs.intCycle[PSXINT_SIO].cycle = eCycle; \
79         psxRegs.intCycle[PSXINT_SIO].sCycle = psxRegs.cycle; \
80         new_dyna_set_event(PSXINT_SIO, eCycle); \
81 }
82
83 // clk cycle byte
84 // 4us * 8bits = (PSXCLK / 1000000) * 32; (linuzappz)
85 // TODO: add SioModePrescaler and BaudReg
86 #define SIO_CYCLES              535
87
88 void sioWrite8(unsigned char value) {
89         int more_data = 0;
90 #if 0
91         s32 framec = psxRegs.cycle - rcnts[3].cycleStart;
92         printf("%d:%03d sio write8 %04x %02x\n", frame_counter,
93                 (s32)(framec / (PSXCLK / 60 / 263.0f)), CtrlReg, value);
94 #endif
95         switch (padst) {
96                 case 1:
97                         if ((value & 0x40) == 0x40) {
98                                 padst = 2; parp = 1;
99                                 switch (CtrlReg & 0x2002) {
100                                         case 0x0002:
101                                                 buf[parp] = PAD1_poll(value, &more_data);
102                                                 break;
103                                         case 0x2002:
104                                                 buf[parp] = PAD2_poll(value, &more_data);
105                                                 break;
106                                 }
107
108                                 if (more_data) {
109                                         bufcount = parp + 1;
110                                         SIO_INT(SIO_CYCLES);
111                                 }
112                         }
113                         else padst = 0;
114                         return;
115                 case 2:
116                         parp++;
117                         switch (CtrlReg & 0x2002) {
118                                 case 0x0002: buf[parp] = PAD1_poll(value, &more_data); break;
119                                 case 0x2002: buf[parp] = PAD2_poll(value, &more_data); break;
120                         }
121
122                         if (more_data) {
123                                 bufcount = parp + 1;
124                                 SIO_INT(SIO_CYCLES);
125                         }
126                         return;
127         }
128
129         switch (mcdst) {
130                 case 1:
131                         SIO_INT(SIO_CYCLES);
132                         if (rdwr) { parp++; return; }
133                         parp = 1;
134                         switch (value) {
135                                 case 0x52: rdwr = 1; break;
136                                 case 0x57: rdwr = 2; break;
137                                 default: mcdst = 0;
138                         }
139                         return;
140                 case 2: // address H
141                         SIO_INT(SIO_CYCLES);
142                         adrH = value;
143                         *buf = 0;
144                         parp = 0;
145                         bufcount = 1;
146                         mcdst = 3;
147                         return;
148                 case 3: // address L
149                         SIO_INT(SIO_CYCLES);
150                         adrL = value;
151                         *buf = adrH;
152                         parp = 0;
153                         bufcount = 1;
154                         mcdst = 4;
155                         return;
156                 case 4:
157                         SIO_INT(SIO_CYCLES);
158                         parp = 0;
159                         switch (rdwr) {
160                                 case 1: // read
161                                         buf[0] = 0x5c;
162                                         buf[1] = 0x5d;
163                                         buf[2] = adrH;
164                                         buf[3] = adrL;
165                                         switch (CtrlReg & 0x2002) {
166                                                 case 0x0002:
167                                                         memcpy(&buf[4], Mcd1Data + (adrL | (adrH << 8)) * 128, 128);
168                                                         break;
169                                                 case 0x2002:
170                                                         memcpy(&buf[4], Mcd2Data + (adrL | (adrH << 8)) * 128, 128);
171                                                         break;
172                                         }
173                                         {
174                                         char xor = 0;
175                                         int i;
176                                         for (i = 2; i < 128 + 4; i++)
177                                                 xor ^= buf[i];
178                                         buf[132] = xor;
179                                         }
180                                         buf[133] = 0x47;
181                                         bufcount = 133;
182                                         break;
183                                 case 2: // write
184                                         buf[0] = adrL;
185                                         buf[1] = value;
186                                         buf[129] = 0x5c;
187                                         buf[130] = 0x5d;
188                                         buf[131] = 0x47;
189                                         bufcount = 131;
190                                         break;
191                         }
192                         mcdst = 5;
193                         return;
194                 case 5:
195                         parp++;
196                         if ((rdwr == 1 && parp == 132) ||
197                             (rdwr == 2 && parp == 129)) {
198                                 // clear "new card" flags
199                                 if (CtrlReg & 0x2000)
200                                         cardh2[1] &= ~8;
201                                 else
202                                         cardh1[1] &= ~8;
203                         }
204                         if (rdwr == 2) {
205                                 if (parp < 128) buf[parp + 1] = value;
206                         }
207                         SIO_INT(SIO_CYCLES);
208                         return;
209         }
210
211         switch (value) {
212                 case 0x01: // start pad
213                         StatReg |= RX_RDY;              // Transfer is Ready
214
215                         switch (CtrlReg & 0x2002) {
216                                 case 0x0002: buf[0] = PAD1_startPoll(1); break;
217                                 case 0x2002: buf[0] = PAD2_startPoll(2); break;
218                         }
219                         bufcount = 1;
220                         parp = 0;
221                         padst = 1;
222                         SIO_INT(SIO_CYCLES);
223                         return;
224                 case 0x81: // start memcard
225                         if (CtrlReg & 0x2000)
226                         {
227                                 if (McdDisable[1])
228                                         goto no_device;
229                                 memcpy(buf, cardh2, 4);
230                         }
231                         else
232                         {
233                                 if (McdDisable[0])
234                                         goto no_device;
235                                 memcpy(buf, cardh1, 4);
236                         }
237                         StatReg |= RX_RDY;
238                         parp = 0;
239                         bufcount = 3;
240                         mcdst = 1;
241                         rdwr = 0;
242                         SIO_INT(SIO_CYCLES);
243                         return;
244                 default:
245                 no_device:
246                         StatReg |= RX_RDY;
247                         buf[0] = 0xff;
248                         parp = 0;
249                         bufcount = 0;
250                         return;
251         }
252 }
253
254 void sioWriteStat16(unsigned short value) {
255 }
256
257 void sioWriteMode16(unsigned short value) {
258         ModeReg = value;
259 }
260
261 void sioWriteCtrl16(unsigned short value) {
262         CtrlReg = value & ~RESET_ERR;
263         if (value & RESET_ERR) StatReg &= ~IRQ;
264         if ((CtrlReg & SIO_RESET) || !(CtrlReg & DTR)) {
265                 padst = 0; mcdst = 0; parp = 0;
266                 StatReg = TX_RDY | TX_EMPTY;
267                 psxRegs.interrupt &= ~(1 << PSXINT_SIO);
268         }
269 }
270
271 void sioWriteBaud16(unsigned short value) {
272         BaudReg = value;
273 }
274
275 unsigned char sioRead8() {
276         unsigned char ret = 0;
277
278         if ((StatReg & RX_RDY)/* && (CtrlReg & RX_PERM)*/) {
279 //              StatReg &= ~RX_OVERRUN;
280                 ret = buf[parp];
281                 if (parp == bufcount) {
282                         StatReg &= ~RX_RDY;             // Receive is not Ready now
283                         if (mcdst == 5) {
284                                 mcdst = 0;
285                                 if (rdwr == 2) {
286                                         switch (CtrlReg & 0x2002) {
287                                                 case 0x0002:
288                                                         memcpy(Mcd1Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
289                                                         SaveMcd(Config.Mcd1, Mcd1Data, (adrL | (adrH << 8)) * 128, 128);
290                                                         break;
291                                                 case 0x2002:
292                                                         memcpy(Mcd2Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
293                                                         SaveMcd(Config.Mcd2, Mcd2Data, (adrL | (adrH << 8)) * 128, 128);
294                                                         break;
295                                         }
296                                 }
297                         }
298                         if (padst == 2) padst = 0;
299                         if (mcdst == 1) {
300                                 mcdst = 2;
301                                 StatReg|= RX_RDY;
302                         }
303                 }
304         }
305
306 #if 0
307         s32 framec = psxRegs.cycle - rcnts[3].cycleStart;
308         printf("%d:%03d sio read8  %04x %02x\n", frame_counter,
309                 (s32)((float)framec / (PSXCLK / 60 / 263.0f)), CtrlReg, ret);
310 #endif
311         return ret;
312 }
313
314 unsigned short sioReadStat16() {
315         return StatReg;
316 }
317
318 unsigned short sioReadMode16() {
319         return ModeReg;
320 }
321
322 unsigned short sioReadCtrl16() {
323         return CtrlReg;
324 }
325
326 unsigned short sioReadBaud16() {
327         return BaudReg;
328 }
329
330 void sioInterrupt() {
331 #ifdef PAD_LOG
332         PAD_LOG("Sio Interrupt (CP0.Status = %x)\n", psxRegs.CP0.n.Status);
333 #endif
334 //      SysPrintf("Sio Interrupt\n");
335         if (!(StatReg & IRQ)) {
336                 StatReg |= IRQ;
337                 psxHu32ref(0x1070) |= SWAPu32(0x80);
338         }
339 }
340
341 void LoadMcd(int mcd, char *str) {
342         FILE *f;
343         char *data = NULL;
344
345         if (mcd != 1 && mcd != 2)
346                 return;
347
348         if (mcd == 1) {
349                 data = Mcd1Data;
350                 cardh1[1] |= 8; // mark as new
351         }
352         if (mcd == 2) {
353                 data = Mcd2Data;
354                 cardh2[1] |= 8;
355         }
356
357         McdDisable[mcd - 1] = 0;
358 #ifdef HAVE_LIBRETRO
359         // memcard1 is handled by libretro
360         if (mcd == 1)
361                 return;
362 #endif
363
364         if (str == NULL || strcmp(str, "none") == 0) {
365                 McdDisable[mcd - 1] = 1;
366                 return;
367         }
368         if (*str == 0)
369                 return;
370
371         f = fopen(str, "rb");
372         if (f == NULL) {
373                 SysPrintf(_("The memory card %s doesn't exist - creating it\n"), str);
374                 CreateMcd(str);
375                 f = fopen(str, "rb");
376                 if (f != NULL) {
377                         struct stat buf;
378
379                         if (stat(str, &buf) != -1) {
380                                 if (buf.st_size == MCD_SIZE + 64)
381                                         fseek(f, 64, SEEK_SET);
382                                 else if(buf.st_size == MCD_SIZE + 3904)
383                                         fseek(f, 3904, SEEK_SET);
384                         }
385                         if (fread(data, 1, MCD_SIZE, f) != MCD_SIZE) {
386 #ifndef NDEBUG
387                                 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
388 #endif
389                                 memset(data, 0x00, MCD_SIZE);
390                         }
391                         fclose(f);
392                 }
393                 else
394                         SysMessage(_("Memory card %s failed to load!\n"), str);
395         }
396         else {
397                 struct stat buf;
398                 SysPrintf(_("Loading memory card %s\n"), str);
399                 if (stat(str, &buf) != -1) {
400                         if (buf.st_size == MCD_SIZE + 64)
401                                 fseek(f, 64, SEEK_SET);
402                         else if(buf.st_size == MCD_SIZE + 3904)
403                                 fseek(f, 3904, SEEK_SET);
404                 }
405                 if (fread(data, 1, MCD_SIZE, f) != MCD_SIZE) {
406 #ifndef NDEBUG
407                         SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
408 #endif
409                         memset(data, 0x00, MCD_SIZE);
410                 }
411                 fclose(f);
412         }
413 }
414
415 void LoadMcds(char *mcd1, char *mcd2) {
416         LoadMcd(1, mcd1);
417         LoadMcd(2, mcd2);
418 }
419
420 void SaveMcd(char *mcd, char *data, uint32_t adr, int size) {
421         FILE *f;
422
423         if (mcd == NULL || *mcd == 0 || strcmp(mcd, "none") == 0)
424                 return;
425
426         f = fopen(mcd, "r+b");
427         if (f != NULL) {
428                 struct stat buf;
429
430                 if (stat(mcd, &buf) != -1) {
431                         if (buf.st_size == MCD_SIZE + 64)
432                                 fseek(f, adr + 64, SEEK_SET);
433                         else if (buf.st_size == MCD_SIZE + 3904)
434                                 fseek(f, adr + 3904, SEEK_SET);
435                         else
436                                 fseek(f, adr, SEEK_SET);
437                 } else
438                         fseek(f, adr, SEEK_SET);
439
440                 fwrite(data + adr, 1, size, f);
441                 fclose(f);
442                 return;
443         }
444
445 #if 0
446         // try to create it again if we can't open it
447         f = fopen(mcd, "wb");
448         if (f != NULL) {
449                 fwrite(data, 1, MCD_SIZE, f);
450                 fclose(f);
451         }
452 #endif
453
454         ConvertMcd(mcd, data);
455 }
456
457 void CreateMcd(char *mcd) {
458         FILE *f;
459         struct stat buf;
460         int s = MCD_SIZE;
461         int i = 0, j;
462
463         f = fopen(mcd, "wb");
464         if (f == NULL)
465                 return;
466
467         if (stat(mcd, &buf) != -1) {
468                 if ((buf.st_size == MCD_SIZE + 3904) || strstr(mcd, ".gme")) {
469                         s = s + 3904;
470                         fputc('1', f);
471                         s--;
472                         fputc('2', f);
473                         s--;
474                         fputc('3', f);
475                         s--;
476                         fputc('-', f);
477                         s--;
478                         fputc('4', f);
479                         s--;
480                         fputc('5', f);
481                         s--;
482                         fputc('6', f);
483                         s--;
484                         fputc('-', f);
485                         s--;
486                         fputc('S', f);
487                         s--;
488                         fputc('T', f);
489                         s--;
490                         fputc('D', f);
491                         s--;
492                         for (i = 0; i < 7; i++) {
493                                 fputc(0, f);
494                                 s--;
495                         }
496                         fputc(1, f);
497                         s--;
498                         fputc(0, f);
499                         s--;
500                         fputc(1, f);
501                         s--;
502                         fputc('M', f);
503                         s--;
504                         fputc('Q', f);
505                         s--;
506                         for (i = 0; i < 14; i++) {
507                                 fputc(0xa0, f);
508                                 s--;
509                         }
510                         fputc(0, f);
511                         s--;
512                         fputc(0xff, f);
513                         while (s-- > (MCD_SIZE + 1))
514                                 fputc(0, f);
515                 } else if ((buf.st_size == MCD_SIZE + 64) || strstr(mcd, ".mem") || strstr(mcd, ".vgs")) {
516                         s = s + 64;
517                         fputc('V', f);
518                         s--;
519                         fputc('g', f);
520                         s--;
521                         fputc('s', f);
522                         s--;
523                         fputc('M', f);
524                         s--;
525                         for (i = 0; i < 3; i++) {
526                                 fputc(1, f);
527                                 s--;
528                                 fputc(0, f);
529                                 s--;
530                                 fputc(0, f);
531                                 s--;
532                                 fputc(0, f);
533                                 s--;
534                         }
535                         fputc(0, f);
536                         s--;
537                         fputc(2, f);
538                         while (s-- > (MCD_SIZE + 1))
539                                 fputc(0, f);
540                 }
541         }
542         fputc('M', f);
543         s--;
544         fputc('C', f);
545         s--;
546         while (s-- > (MCD_SIZE - 127))
547                 fputc(0, f);
548         fputc(0xe, f);
549         s--;
550
551         for (i = 0; i < 15; i++) { // 15 blocks
552                 fputc(0xa0, f);
553                 s--;
554                 fputc(0x00, f);
555                 s--;
556                 fputc(0x00, f);
557                 s--;
558                 fputc(0x00, f);
559                 s--;
560                 fputc(0x00, f);
561                 s--;
562                 fputc(0x00, f);
563                 s--;
564                 fputc(0x00, f);
565                 s--;
566                 fputc(0x00, f);
567                 s--;
568                 fputc(0xff, f);
569                 s--;
570                 fputc(0xff, f);
571                 s--;
572                 for (j = 0; j < 117; j++) {
573                         fputc(0x00, f);
574                         s--;
575                 }
576                 fputc(0xa0, f);
577                 s--;
578         }
579
580         for (i = 0; i < 20; i++) {
581                 fputc(0xff, f);
582                 s--;
583                 fputc(0xff, f);
584                 s--;
585                 fputc(0xff, f);
586                 s--;
587                 fputc(0xff, f);
588                 s--;
589                 fputc(0x00, f);
590                 s--;
591                 fputc(0x00, f);
592                 s--;
593                 fputc(0x00, f);
594                 s--;
595                 fputc(0x00, f);
596                 s--;
597                 fputc(0xff, f);
598                 s--;
599                 fputc(0xff, f);
600                 s--;
601                 for (j = 0; j < 118; j++) {
602                         fputc(0x00, f);
603                         s--;
604                 }
605         }
606
607         while ((s--) >= 0)
608                 fputc(0, f);
609
610         fclose(f);
611 }
612
613 void ConvertMcd(char *mcd, char *data) {
614         FILE *f;
615         int i = 0;
616         int s = MCD_SIZE;
617
618         if (strstr(mcd, ".gme")) {
619                 f = fopen(mcd, "wb");
620                 if (f != NULL) {
621                         fwrite(data - 3904, 1, MCD_SIZE + 3904, f);
622                         fclose(f);
623                 }
624                 f = fopen(mcd, "r+");
625                 if (f == NULL) return;
626                 s = s + 3904;
627                 fputc('1', f); s--;
628                 fputc('2', f); s--;
629                 fputc('3', f); s--;
630                 fputc('-', f); s--;
631                 fputc('4', f); s--;
632                 fputc('5', f); s--;
633                 fputc('6', f); s--;
634                 fputc('-', f); s--;
635                 fputc('S', f); s--;
636                 fputc('T', f); s--;
637                 fputc('D', f); s--;
638                 for (i = 0; i < 7; i++) {
639                         fputc(0, f); s--;
640                 }
641                 fputc(1, f); s--;
642                 fputc(0, f); s--;
643                 fputc(1, f); s--;
644                 fputc('M', f); s--;
645                 fputc('Q', f); s--;
646                 for(i=0;i<14;i++) {
647                         fputc(0xa0, f); s--;
648                 }
649                 fputc(0, f); s--;
650                 fputc(0xff, f);
651                 while (s-- > (MCD_SIZE+1)) fputc(0, f);
652                 fclose(f);
653         } else if(strstr(mcd, ".mem") || strstr(mcd,".vgs")) {
654                 f = fopen(mcd, "wb");
655                 if (f != NULL) {
656                         fwrite(data-64, 1, MCD_SIZE+64, f);
657                         fclose(f);
658                 }
659                 f = fopen(mcd, "r+");
660                 if (f == NULL) return;
661                 s = s + 64;
662                 fputc('V', f); s--;
663                 fputc('g', f); s--;
664                 fputc('s', f); s--;
665                 fputc('M', f); s--;
666                 for(i=0;i<3;i++) {
667                         fputc(1, f); s--;
668                         fputc(0, f); s--;
669                         fputc(0, f); s--;
670                         fputc(0, f); s--;
671                 }
672                 fputc(0, f); s--;
673                 fputc(2, f);
674                 while (s-- > (MCD_SIZE+1)) fputc(0, f);
675                 fclose(f);
676         } else {
677                 f = fopen(mcd, "wb");
678                 if (f != NULL) {
679                         fwrite(data, 1, MCD_SIZE, f);
680                         fclose(f);
681                 }
682         }
683 }
684
685 void GetMcdBlockInfo(int mcd, int block, McdBlock *Info) {
686         char *data = NULL, *ptr, *str, *sstr;
687         unsigned short clut[16];
688         unsigned short c;
689         int i, x;
690
691         memset(Info, 0, sizeof(McdBlock));
692
693         if (mcd != 1 && mcd != 2)
694                 return;
695
696         if (McdDisable[mcd - 1])
697                 return;
698
699         if (mcd == 1) data = Mcd1Data;
700         if (mcd == 2) data = Mcd2Data;
701
702         ptr = data + block * 8192 + 2;
703
704         Info->IconCount = *ptr & 0x3;
705
706         ptr += 2;
707
708         x = 0;
709
710         str = Info->Title;
711         sstr = Info->sTitle;
712
713         for (i = 0; i < 48; i++) {
714                 c = *(ptr) << 8;
715                 c |= *(ptr + 1);
716                 if (!c) break;
717
718                 // Convert ASCII characters to half-width
719                 if (c >= 0x8281 && c <= 0x829A)
720                         c = (c - 0x8281) + 'a';
721                 else if (c >= 0x824F && c <= 0x827A)
722                         c = (c - 0x824F) + '0';
723                 else if (c == 0x8140) c = ' ';
724                 else if (c == 0x8143) c = ',';
725                 else if (c == 0x8144) c = '.';
726                 else if (c == 0x8146) c = ':';
727                 else if (c == 0x8147) c = ';';
728                 else if (c == 0x8148) c = '?';
729                 else if (c == 0x8149) c = '!';
730                 else if (c == 0x815E) c = '/';
731                 else if (c == 0x8168) c = '"';
732                 else if (c == 0x8169) c = '(';
733                 else if (c == 0x816A) c = ')';
734                 else if (c == 0x816D) c = '[';
735                 else if (c == 0x816E) c = ']';
736                 else if (c == 0x817C) c = '-';
737                 else {
738                         str[i] = ' ';
739                         sstr[x++] = *ptr++; sstr[x++] = *ptr++;
740                         continue;
741                 }
742
743                 str[i] = sstr[x++] = c;
744                 ptr += 2;
745         }
746
747         trim(str);
748         trim(sstr);
749
750         ptr = data + block * 8192 + 0x60; // icon palette data
751
752         for (i = 0; i < 16; i++) {
753                 clut[i] = *((unsigned short *)ptr);
754                 ptr += 2;
755         }
756
757         for (i = 0; i < Info->IconCount; i++) {
758                 short *icon = &Info->Icon[i * 16 * 16];
759
760                 ptr = data + block * 8192 + 128 + 128 * i; // icon data
761
762                 for (x = 0; x < 16 * 16; x++) {
763                         icon[x++] = clut[*ptr & 0xf];
764                         icon[x] = clut[*ptr >> 4];
765                         ptr++;
766                 }
767         }
768
769         ptr = data + block * 128;
770
771         Info->Flags = *ptr;
772
773         ptr += 0xa;
774         strncpy(Info->ID, ptr, 12);
775         ptr += 12;
776         strncpy(Info->Name, ptr, 16);
777 }
778
779 int sioFreeze(void *f, int Mode) {
780         gzfreeze(buf, sizeof(buf));
781         gzfreeze(&StatReg, sizeof(StatReg));
782         gzfreeze(&ModeReg, sizeof(ModeReg));
783         gzfreeze(&CtrlReg, sizeof(CtrlReg));
784         gzfreeze(&BaudReg, sizeof(BaudReg));
785         gzfreeze(&bufcount, sizeof(bufcount));
786         gzfreeze(&parp, sizeof(parp));
787         gzfreeze(&mcdst, sizeof(mcdst));
788         gzfreeze(&rdwr, sizeof(rdwr));
789         gzfreeze(&adrH, sizeof(adrH));
790         gzfreeze(&adrL, sizeof(adrL));
791         gzfreeze(&padst, sizeof(padst));
792
793         return 0;
794 }